Skip to content

feat: support file upload in agent chat - #2429

Open
supreme-gg-gg wants to merge 5 commits into
kagent-dev:release/v0.10.xfrom
supreme-gg-gg:feat/file-parts
Open

feat: support file upload in agent chat#2429
supreme-gg-gg wants to merge 5 commits into
kagent-dev:release/v0.10.xfrom
supreme-gg-gg:feat/file-parts

Conversation

@supreme-gg-gg

@supreme-gg-gg supreme-gg-gg commented Aug 12, 2026

Copy link
Copy Markdown
Contributor
  • Forward non-image file parts through Go model adapters instead of silently dropping them
  • Add chat UI file attach (paperclip, drag/drop, history chips) for Go declarative agents only
  • Demo video is attached in a comment below

Current support matrix:

Provider Native images Native documents
OpenAI (CC / Azure / Foundry) image/* PDF only, text extracted from text files
OpenAI (Responses) image/* PDF, text, markdown, csv, html, json, word, pptx, etc.
Anthropic image/* PDF, text/plain, text/markdown
Bedrock png/jpeg/gif/webp pdf, txt, md, csv, html, doc/docx, xls/xlsx
Ollama image/* only

Signed-off-by: Jet Chiang <pokyuen.jetchiang-ext@solo.io>
Copilot AI lite review requested due to automatic review settings August 12, 2026 00:42

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@github-actions github-actions Bot added the enhancement New feature or request label Aug 12, 2026
@supreme-gg-gg

Copy link
Copy Markdown
Contributor Author
input.mp4

Signed-off-by: Jet Chiang <pokyuen.jetchiang-ext@solo.io>
@iplay88keys

Copy link
Copy Markdown
Contributor

Tested locally with a PDF and gpt-4.1-mini:
image

@github-actions github-actions Bot added enhancement New feature or request and removed enhancement New feature or request labels Aug 12, 2026
} = {},
) => {
if (!userMessageText.trim() || !selectedAgentName || !selectedNamespace) {
const filesToSend = pendingFiles;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

handleMcpAppSendMessage() also calls sendChatMessageText, so an MCP app's ui/message will send and clear any files the user has staged.


if (options.clearInput ?? true) {
setCurrentInputMessage("");
setPendingFiles([]);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the cross-tab guard below returns "blocked", then the staged files will be cleared without sending. We should only clear after the cross-tab guard succeeds.

Source: &types.ImageSourceMemberBytes{Value: part.InlineData.Data},
},
})
} else if docFmt := bedrockDocumentFormat(mime, name); docFmt != "" {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on the Bedrock Converse documentation, if a message contains a document content block, there must also be a text content block:

If you include a ContentBlock with a document field in the array, you must also include a ContentBlock with a text field.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can think of two ways to enforce this, either we allow the user to only send a document (which is the behaviour right now) and check in adapter if there is no text part, we will add a default message like "review this file", or we will require the user to always send a text part alongside any documents (excluding images, since bedrock only requires this for documents).

I'll go with the first approach since A2A allows FilePart without a TextPart in messages

} from "@/lib/chatSessionGuard";

/** Soft client cap so base64 A2A FileParts stay reasonable. */
const MAX_CHAT_FILE_BYTES = 10 * 1024 * 1024;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bedrock has a max size of: 3.75 MB for images and 4.5 MB for documents with a max of 20 images or 5 documents. We should make sure the count/size conform to provider limits before allowing sending.

  • You can include up to 20 images. Each image’s size, height, and width must be no more than 3.75 MB, 8000 px, and 8000 px, respectively.
  • You can include up to five documents. Each document’s size must be no more than 4.5 MB.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, I've added the checks and the above 2 UI review comments in 2e28e44

@github-actions github-actions Bot added enhancement New feature or request and removed enhancement New feature or request labels Aug 12, 2026
Signed-off-by: Jet Chiang <pokyuen.jetchiang-ext@solo.io>
Signed-off-by: Jet Chiang <pokyuen.jetchiang-ext@solo.io>
Signed-off-by: Jet Chiang <pokyuen.jetchiang-ext@solo.io>
@github-actions github-actions Bot added enhancement New feature or request and removed enhancement New feature or request labels Aug 12, 2026

@iplay88keys iplay88keys left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just some extra validation, but nothing blocking.

Comment on lines +566 to +570
if (file.size > maxBytes) {
const mb = (maxBytes / (1024 * 1024)).toFixed(2);
toast.error(`${file.name} exceeds the ${mb}MB ${isImage ? "image" : "file"} limit`);
continue;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bedrock supports images up to a max size of 8000 x 8000 px. Do we want to validate that here as well?

Comment on lines +217 to +241
func bedrockSafeDocName(name string) string {
if name == "" {
return "document"
}
var b strings.Builder
prevSpace := false
for _, r := range name {
switch {
case (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') || (r >= '0' && r <= '9') ||
r == '-' || r == '(' || r == ')' || r == '[' || r == ']':
b.WriteRune(r)
prevSpace = false
case r == ' ' || r == '_' || r == '.':
if !prevSpace && b.Len() > 0 {
b.WriteByte(' ')
prevSpace = true
}
}
}
out := strings.TrimSpace(b.String())
if out == "" {
return "document"
}
return out
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bedrock document names also have a max of 200 characters. It's also worth considering a neutral name for them, though we'd have to distinctly name each of the files.

From the docs:

A name for the document. The name can only contain the following characters:

  • Alphanumeric characters
  • Whitespace characters (no more than one in a row)
  • Hyphens
  • Parentheses
  • Square brackets

Note
This field is vulnerable to prompt injections, because the model might inadvertently interpret it as instructions. Therefore, we recommend that you specify a neutral name.

Constraints:

  • min: 1
  • max: 200

const handleAttachFiles = async (fileList: FileList | null) => {
if (!fileList || fileList.length === 0) return;
const next: PendingChatFile[] = [];
let slots = MAX_CHAT_FILES - pendingFiles.length;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Codex's review mentions:

pendingFiles.length is captured before the asynchronous file reads. Two overlapping picker/drop operations can both calculate the same available slots and ultimately append more than MAX_CHAT_FILES. Please reserve slots while reading or enforce the cap atomically in the state update.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants