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

Function CreateUserMessageWithAttachment

pkg/cli/runner.go:437–504  ·  view source on GitHub ↗

CreateUserMessageWithAttachment creates a user message with optional file attachment. All attachment processing (MIME detection, image resize, text inlining) is delegated to [chat.ProcessAttachment], which runs once at message-assembly time. Returns the prepared session.Message and the absolute pat

(ctx context.Context, userContent, attachmentPath string)

Source from the content-addressed store, hash-verified

435// large to inline, etc.). Callers should record successful attachments via
436// session.Session.AddAttachedFile so sub-agents inherit the file context.
437func CreateUserMessageWithAttachment(ctx context.Context, userContent, attachmentPath string) (*session.Message, string) {
438 // noAttachment returns the message without any attachment.
439 noAttachment := func() (*session.Message, string) {
440 return session.UserMessage(userContent), ""
441 }
442
443 if attachmentPath == "" {
444 return noAttachment()
445 }
446
447 absPath, err := filepath.Abs(attachmentPath)
448 if err != nil {
449 slog.WarnContext(ctx, "Failed to get absolute path for attachment", "path", attachmentPath, "error", err)
450 return noAttachment()
451 }
452
453 fi, err := os.Stat(absPath)
454 if err != nil {
455 slog.WarnContext(ctx, "Attachment file not accessible", "path", absPath, "error", err)
456 return noAttachment()
457 }
458
459 // Ensure we have some text content when attaching a file.
460 textContent := cmp.Or(strings.TrimSpace(userContent), "Please analyze this attached file.")
461
462 multiContent := []chat.MessagePart{
463 {Type: chat.MessagePartTypeText, Text: textContent},
464 }
465
466 switch {
467 case chat.IsTextFile(absPath):
468 // Text files are inlined directly as text content.
469 if fi.Size() > chat.MaxInlineFileSize {
470 slog.WarnContext(ctx, "Attachment text file too large to inline", "path", absPath, "size", fi.Size())
471 return noAttachment()
472 }
473 content, err := chat.ReadFileForInline(absPath)
474 if err != nil {
475 slog.WarnContext(ctx, "Failed to read attachment file", "path", absPath, "error", err)
476 return noAttachment()
477 }
478 multiContent = append(multiContent, chat.MessagePart{
479 Type: chat.MessagePartTypeText,
480 Text: content,
481 })
482
483 default:
484 // Binary files (images, PDFs, etc.) — delegate to ProcessAttachment.
485 if !chat.IsSupportedMimeType(chat.DetectMimeType(absPath)) {
486 slog.WarnContext(ctx, "Unsupported attachment file type", "path", absPath)
487 return noAttachment()
488 }
489 doc, _, procErr := chat.ProcessAttachmentWithMetadata(chat.MessagePart{
490 Type: chat.MessagePartTypeFile,
491 File: &chat.MessageFile{Path: absPath},
492 })
493 if procErr != nil {
494 slog.WarnContext(ctx, "Failed to process attachment", "path", absPath, "error", procErr)

Callers 1

PrepareUserMessageFunction · 0.85

Calls 7

UserMessageFunction · 0.92
IsTextFileFunction · 0.92
ReadFileForInlineFunction · 0.92
IsSupportedMimeTypeFunction · 0.92
DetectMimeTypeFunction · 0.92
SizeMethod · 0.45

Tested by

no test coverage detected