MCPcopy
hub / github.com/docker/docker-agent / Run

Method Run

pkg/app/app.go:456–525  ·  view source on GitHub ↗

Run one agent loop

(ctx context.Context, cancel context.CancelFunc, message string, attachments []messages.Attachment)

Source from the content-addressed store, hash-verified

454
455// Run one agent loop
456func (a *App) Run(ctx context.Context, cancel context.CancelFunc, message string, attachments []messages.Attachment) {
457 a.cancel = cancel
458
459 // If this is the first message and no title exists, start local title generation
460 if a.session.Title == "" && a.titleGen != nil {
461 a.titleGenerating.Store(true)
462 go a.generateTitle(ctx, []string{message})
463 }
464
465 go func() {
466 if len(attachments) > 0 {
467 // Build a single text string with the user's message and inlined text files.
468 // Keeping everything in one text block ensures the model sees file content
469 // together with the message, rather than as separate content blocks.
470 var textBuilder strings.Builder
471 textBuilder.WriteString(message)
472
473 // binaryParts holds non-text file parts (images, PDFs, etc.)
474 var binaryParts []chat.MessagePart
475
476 for _, att := range attachments {
477 switch {
478 case att.FilePath != "":
479 // File-reference attachment: read and classify from disk.
480 // Only remember the path on the session when the file actually
481 // exists as a regular file — we don't want sub-agents to inherit
482 // dangling references to directories or missing paths. The editor
483 // resolves @-mentions to absolute paths before this point.
484 if a.processFileAttachment(ctx, att, &textBuilder, &binaryParts) {
485 a.session.AddAttachedFile(att.FilePath)
486 }
487 case att.Content != "":
488 // Inline content attachment (e.g. pasted text).
489 a.processInlineAttachment(att, &textBuilder)
490 default:
491 slog.DebugContext(ctx, "skipping attachment with no file path or content", "name", att.Name)
492 }
493 }
494
495 multiContent := []chat.MessagePart{
496 {Type: chat.MessagePartTypeText, Text: textBuilder.String()},
497 }
498 multiContent = append(multiContent, binaryParts...)
499
500 a.session.AddMessage(session.UserMessage(message, multiContent...))
501 } else {
502 a.session.AddMessage(session.UserMessage(message))
503 }
504 for event := range a.runtime.RunStream(ctx, a.session) {
505 // If context is cancelled, continue draining but don't forward events
506 // — except StreamStoppedEvent, which must always propagate so the
507 // supervisor can mark the session as no longer running.
508 if ctx.Err() != nil {
509 if _, ok := event.(*runtime.StreamStoppedEvent); ok {
510 // ctx is cancelled; detach cancellation but keep its trace
511 // context so the stop event still reaches subscribers.
512 a.sendEvent(context.WithoutCancel(ctx), event)
513 }

Callers

nothing calls this directly

Calls 11

generateTitleMethod · 0.95
processFileAttachmentMethod · 0.95
sendEventMethod · 0.95
UserMessageFunction · 0.92
AddAttachedFileMethod · 0.80
AddMessageMethod · 0.65
RunStreamMethod · 0.65
ErrMethod · 0.65
StoreMethod · 0.45
StringMethod · 0.45

Tested by

no test coverage detected