返回 DeepSeek-Reasonix
prepared_submission.go
根目录 / internal / control / prepared_submission.go
1 package control
2
3 import (
4 "context"
5 "errors"
6 "maps"
7 "slices"
8 "strings"
9
10 "reasonix/internal/imageinput"
11 "reasonix/internal/session"
12 )
13
14 // PreparedSubmission is a host-only immutable admission candidate. Its fields
15 // cannot be supplied over RPC; source paths are consumed only during preparation.
16 type PreparedSubmission struct {
17 owner *Controller
18 scope string
19 request SubmissionRequest
20 images preparedImageReferences
21 }
22
23 func (p *PreparedSubmission) HasImages() bool { return p != nil && len(p.images.inputs) > 0 }
24
25 func (c *Controller) PrepareSubmission(ctx context.Context, req SubmissionRequest) (*PreparedSubmission, error) {
26 ctx, cancel := c.NewAttachmentOperationContext(ctx)
27 defer cancel()
28 if len(req.ID) > 256 || strings.ContainsAny(req.ID, "\x00\r\n") {
29 return nil, errors.New("invalid submission identity")
30 }
31 req = cloneSubmissionRequest(req)
32 p := &PreparedSubmission{owner: c, scope: c.attachmentScope(), request: req}
33 if _, found, err := c.LookupSubmissionContext(ctx, req); found || err != nil {
34 return p, err
35 }
36 images, failures := c.prepareSubmissionImagesContext(ctx, req)
37 if len(failures) > 0 {
38 // A concurrent retry may have completed while this request read a now
39 // released draft. A durable receipt takes precedence over source access.
40 if _, found, err := c.LookupSubmissionContext(ctx, req); found || err != nil {
41 return p, err
42 }
43 return nil, ImageReferenceFailures(failures)
44 }
45 if err := ctx.Err(); err != nil {
46 return nil, err
47 }
48 if images.requiresImageUnderstanding && c.selection.ref != "" && !c.imageInputEnabled() {
49 svc := imageinput.New(imageinput.Config{Model: c.visionModel, Resolve: c.visionProviderResolver, Select: c.visionModelSelector})
50 if c.executor != nil && c.executor.ImageInput() != nil {
51 svc = c.executor.ImageInput()
52 }
53 if _, err := svc.SelectModel(c.selection.ref, nil); err != nil {
54 return nil, err
55 }
56 }
57 p.images = images
58 return p, nil
59 }
60
61 func cloneSubmissionRequest(req SubmissionRequest) SubmissionRequest {
62 req.Invocations = slices.Clone(req.Invocations)
63 req.DraftIDs = slices.Clone(req.DraftIDs)
64 req.AttachmentDigests = slices.Clone(req.AttachmentDigests)
65 req.Attachments = slices.Clone(req.Attachments)
66 for i := range req.Attachments {
67 if ref := req.Attachments[i].Reference; ref != nil {
68 copy := *ref
69 req.Attachments[i].Reference = &copy
70 }
71 }
72 req.frozenSources = maps.Clone(req.frozenSources)
73 req.inheritedSources = slices.Clone(req.inheritedSources)
74 return req
75 }
76
77 func (c *Controller) SubmitPreparedWithSetup(ctx context.Context, prepared *PreparedSubmission, setup func() error) (session.SubmissionReceipt, error) {
78 if prepared == nil || prepared.owner != c {
79 return session.SubmissionReceipt{}, errors.New("invalid prepared submission owner")
80 }
81 return c.acceptPreparedSubmission(ctx, prepared, setup, func(admission turnAdmission) {
82 c.submitIdentifiedRequestLocked(prepared.request, admission)
83 })
84 }
85
85 lines GO