summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--packages/app/src/components/prompt-input.tsx8
-rw-r--r--packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx6
-rw-r--r--packages/opencode/src/session/prompt.ts20
-rw-r--r--packages/sdk/js/src/v2/gen/sdk.gen.ts10
-rw-r--r--packages/sdk/js/src/v2/gen/types.gen.ts8
-rw-r--r--packages/sdk/openapi.json32
6 files changed, 81 insertions, 3 deletions
diff --git a/packages/app/src/components/prompt-input.tsx b/packages/app/src/components/prompt-input.tsx
index 4a3a96d67..6965e8740 100644
--- a/packages/app/src/components/prompt-input.tsx
+++ b/packages/app/src/components/prompt-input.tsx
@@ -1111,6 +1111,13 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
agent,
model: `${model.providerID}/${model.modelID}`,
variant,
+ parts: images.map((attachment) => ({
+ id: Identifier.ascending("part"),
+ type: "file" as const,
+ mime: attachment.mime,
+ url: attachment.dataUrl,
+ filename: attachment.filename,
+ })),
})
.catch((err) => {
showToast({
@@ -1206,6 +1213,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
filename: attachment.filename,
}))
+
const messageID = Identifier.ascending("message")
const textPart = {
id: Identifier.ascending("part"),
diff --git a/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx b/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx
index 02863b4ca..4558914cb 100644
--- a/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx
+++ b/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx
@@ -559,6 +559,12 @@ export function Prompt(props: PromptProps) {
model: `${selectedModel.providerID}/${selectedModel.modelID}`,
messageID,
variant,
+ parts: nonTextParts
+ .filter((x) => x.type === "file")
+ .map((x) => ({
+ id: Identifier.ascending("part"),
+ ...x,
+ })),
})
} else {
sdk.client.session.prompt({
diff --git a/packages/opencode/src/session/prompt.ts b/packages/opencode/src/session/prompt.ts
index fd7f8aa72..87b53f526 100644
--- a/packages/opencode/src/session/prompt.ts
+++ b/packages/opencode/src/session/prompt.ts
@@ -1422,10 +1422,23 @@ export namespace SessionPrompt {
arguments: z.string(),
command: z.string(),
variant: z.string().optional(),
+ parts: z
+ .array(
+ z.discriminatedUnion("type", [
+ MessageV2.FilePart.omit({
+ messageID: true,
+ sessionID: true,
+ }).partial({
+ id: true,
+ }),
+ ]),
+ )
+ .optional(),
})
export type CommandInput = z.infer<typeof CommandInput>
const bashRegex = /!`([^`]+)`/g
- const argsRegex = /(?:[^\s"']+|"[^"]*"|'[^']*')+/g
+ // Match [Image N] as single token, quoted strings, or non-space sequences
+ const argsRegex = /(?:\[Image\s+\d+\]|"[^"]*"|'[^']*'|[^\s"']+)/gi
const placeholderRegex = /\$(\d+)/g
const quoteTrimRegex = /^["']|["']$/g
/**
@@ -1516,6 +1529,7 @@ export namespace SessionPrompt {
throw error
}
+ const templateParts = await resolvePromptParts(template)
const parts =
(agent.mode === "subagent" && command.subtask !== false) || command.subtask === true
? [
@@ -1525,10 +1539,10 @@ export namespace SessionPrompt {
description: command.description ?? "",
command: input.command,
// TODO: how can we make task tool accept a more complex input?
- prompt: await resolvePromptParts(template).then((x) => x.find((y) => y.type === "text")?.text ?? ""),
+ prompt: templateParts.find((y) => y.type === "text")?.text ?? "",
},
]
- : await resolvePromptParts(template)
+ : [...templateParts, ...(input.parts ?? [])]
const result = (await prompt({
sessionID: input.sessionID,
diff --git a/packages/sdk/js/src/v2/gen/sdk.gen.ts b/packages/sdk/js/src/v2/gen/sdk.gen.ts
index ac5ea1211..a26cefb17 100644
--- a/packages/sdk/js/src/v2/gen/sdk.gen.ts
+++ b/packages/sdk/js/src/v2/gen/sdk.gen.ts
@@ -24,6 +24,7 @@ import type {
ExperimentalResourceListResponses,
FileListResponses,
FilePartInput,
+ FilePartSource,
FileReadResponses,
FileStatusResponses,
FindFilesResponses,
@@ -1451,6 +1452,14 @@ export class Session extends HeyApiClient {
arguments?: string
command?: string
variant?: string
+ parts?: Array<{
+ id?: string
+ type: "file"
+ mime: string
+ filename?: string
+ url: string
+ source?: FilePartSource
+ }>
},
options?: Options<never, ThrowOnError>,
) {
@@ -1467,6 +1476,7 @@ export class Session extends HeyApiClient {
{ in: "body", key: "arguments" },
{ in: "body", key: "command" },
{ in: "body", key: "variant" },
+ { in: "body", key: "parts" },
],
},
],
diff --git a/packages/sdk/js/src/v2/gen/types.gen.ts b/packages/sdk/js/src/v2/gen/types.gen.ts
index 431135db3..596e52ad9 100644
--- a/packages/sdk/js/src/v2/gen/types.gen.ts
+++ b/packages/sdk/js/src/v2/gen/types.gen.ts
@@ -3292,6 +3292,14 @@ export type SessionCommandData = {
arguments: string
command: string
variant?: string
+ parts?: Array<{
+ id?: string
+ type: "file"
+ mime: string
+ filename?: string
+ url: string
+ source?: FilePartSource
+ }>
}
path: {
/**
diff --git a/packages/sdk/openapi.json b/packages/sdk/openapi.json
index 3e7bd5e08..a32be164c 100644
--- a/packages/sdk/openapi.json
+++ b/packages/sdk/openapi.json
@@ -2667,6 +2667,38 @@
},
"variant": {
"type": "string"
+ },
+ "parts": {
+ "type": "array",
+ "items": {
+ "anyOf": [
+ {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string"
+ },
+ "type": {
+ "type": "string",
+ "const": "file"
+ },
+ "mime": {
+ "type": "string"
+ },
+ "filename": {
+ "type": "string"
+ },
+ "url": {
+ "type": "string"
+ },
+ "source": {
+ "$ref": "#/components/schemas/FilePartSource"
+ }
+ },
+ "required": ["type", "mime", "url"]
+ }
+ ]
+ }
}
},
"required": ["arguments", "command"]