mirror of
https://github.com/anomalyco/opencode.git
synced 2026-05-23 21:04:36 +00:00
refactor(session): align prompt input types with their schemas (#25178)
This commit is contained in:
@@ -269,7 +269,7 @@ export const sessionHandlers = HttpApiBuilder.group(InstanceHttpApi, "session",
|
||||
promptSvc.prompt({
|
||||
...ctx.payload,
|
||||
sessionID: ctx.params.sessionID,
|
||||
} as unknown as SessionPrompt.PromptInput),
|
||||
}),
|
||||
),
|
||||
),
|
||||
).pipe(
|
||||
@@ -288,7 +288,7 @@ export const sessionHandlers = HttpApiBuilder.group(InstanceHttpApi, "session",
|
||||
yield* Effect.sync(() => {
|
||||
bridge.fork(
|
||||
promptSvc
|
||||
.prompt({ ...ctx.payload, sessionID: ctx.params.sessionID } as unknown as SessionPrompt.PromptInput)
|
||||
.prompt({ ...ctx.payload, sessionID: ctx.params.sessionID })
|
||||
.pipe(
|
||||
Effect.catchCause((error) =>
|
||||
Effect.sync(() => {
|
||||
@@ -309,14 +309,14 @@ export const sessionHandlers = HttpApiBuilder.group(InstanceHttpApi, "session",
|
||||
params: { sessionID: SessionID }
|
||||
payload: typeof CommandPayload.Type
|
||||
}) {
|
||||
return yield* promptSvc.command({ ...ctx.payload, sessionID: ctx.params.sessionID } as SessionPrompt.CommandInput)
|
||||
return yield* promptSvc.command({ ...ctx.payload, sessionID: ctx.params.sessionID })
|
||||
})
|
||||
|
||||
const shell = Effect.fn("SessionHttpApi.shell")(function* (ctx: {
|
||||
params: { sessionID: SessionID }
|
||||
payload: typeof ShellPayload.Type
|
||||
}) {
|
||||
return yield* promptSvc.shell({ ...ctx.payload, sessionID: ctx.params.sessionID } as SessionPrompt.ShellInput)
|
||||
return yield* promptSvc.shell({ ...ctx.payload, sessionID: ctx.params.sessionID })
|
||||
})
|
||||
|
||||
const revert = Effect.fn("SessionHttpApi.revert")(function* (ctx: {
|
||||
|
||||
@@ -45,7 +45,7 @@ import { AppFileSystem } from "@opencode-ai/core/filesystem"
|
||||
import { Truncate } from "@/tool/truncate"
|
||||
import { decodeDataUrl } from "@/util/data-url"
|
||||
import { Process } from "@/util/process"
|
||||
import { Cause, Effect, Exit, Latch, Layer, Option, Scope, Context, Schema } from "effect"
|
||||
import { Cause, Effect, Exit, Latch, Layer, Option, Scope, Context, Schema, Types } from "effect"
|
||||
import { zod } from "@/util/effect-zod"
|
||||
import { withStatics } from "@/util/schema"
|
||||
import * as EffectLogger from "@opencode-ai/core/effect/logger"
|
||||
@@ -127,7 +127,7 @@ export const layer = Layer.effect(
|
||||
|
||||
const resolvePromptParts = Effect.fn("SessionPrompt.resolvePromptParts")(function* (template: string) {
|
||||
const ctx = yield* InstanceState.context
|
||||
const parts: PromptInput["parts"] = [{ type: "text", text: template }]
|
||||
const parts: Types.DeepMutable<PromptInput["parts"]> = [{ type: "text", text: template }]
|
||||
const files = ConfigMarkdown.files(template)
|
||||
const seen = new Set<string>()
|
||||
yield* Effect.forEach(
|
||||
@@ -1012,7 +1012,7 @@ NOTE: At any point in time through this workflow you should feel free to ask the
|
||||
case "file:": {
|
||||
log.info("file", { mime: part.mime })
|
||||
const filepath = fileURLToPath(part.url)
|
||||
if (yield* fsys.isDir(filepath)) part.mime = "application/x-directory"
|
||||
const mime = (yield* fsys.isDir(filepath)) ? "application/x-directory" : part.mime
|
||||
|
||||
const { read } = yield* registry.named()
|
||||
const execRead = (args: Parameters<typeof read.execute>[0], extra?: Tool.Context["extra"]) => {
|
||||
@@ -1031,7 +1031,7 @@ NOTE: At any point in time through this workflow you should feel free to ask the
|
||||
.pipe(Effect.onInterrupt(() => Effect.sync(() => controller.abort())))
|
||||
}
|
||||
|
||||
if (part.mime === "text/plain") {
|
||||
if (mime === "text/plain") {
|
||||
let offset: number | undefined
|
||||
let limit: number | undefined
|
||||
const range = { start: url.searchParams.get("start"), end: url.searchParams.get("end") }
|
||||
@@ -1089,7 +1089,7 @@ NOTE: At any point in time through this workflow you should feel free to ask the
|
||||
})),
|
||||
)
|
||||
} else {
|
||||
pieces.push({ ...part, messageID: info.id, sessionID: input.sessionID })
|
||||
pieces.push({ ...part, mime, messageID: info.id, sessionID: input.sessionID })
|
||||
}
|
||||
} else {
|
||||
const error = Cause.squash(exit.cause)
|
||||
@@ -1110,7 +1110,7 @@ NOTE: At any point in time through this workflow you should feel free to ask the
|
||||
return pieces
|
||||
}
|
||||
|
||||
if (part.mime === "application/x-directory") {
|
||||
if (mime === "application/x-directory") {
|
||||
const args = { filePath: filepath }
|
||||
const exit = yield* execRead(args).pipe(Effect.exit)
|
||||
if (Exit.isFailure(exit)) {
|
||||
@@ -1146,7 +1146,7 @@ NOTE: At any point in time through this workflow you should feel free to ask the
|
||||
synthetic: true,
|
||||
text: exit.value.output,
|
||||
},
|
||||
{ ...part, messageID: info.id, sessionID: input.sessionID },
|
||||
{ ...part, mime, messageID: info.id, sessionID: input.sessionID },
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1164,9 +1164,9 @@ NOTE: At any point in time through this workflow you should feel free to ask the
|
||||
sessionID: input.sessionID,
|
||||
type: "file",
|
||||
url:
|
||||
`data:${part.mime};base64,` +
|
||||
`data:${mime};base64,` +
|
||||
Buffer.from(yield* fsys.readFile(filepath).pipe(Effect.catch(Effect.die))).toString("base64"),
|
||||
mime: part.mime,
|
||||
mime,
|
||||
filename: part.filename!,
|
||||
source: part.source,
|
||||
},
|
||||
@@ -1700,18 +1700,7 @@ export const PromptInput = Schema.Struct({
|
||||
]).annotate({ discriminator: "type" }),
|
||||
),
|
||||
}).pipe(withStatics((s) => ({ zod: zod(s) })))
|
||||
// `z.discriminatedUnion` erases the discriminated members' shapes back to
|
||||
// `{}` when walked from the generic `z.ZodType` input. Restore the precise
|
||||
// `parts` type from the exported Schema input types so callers see a proper
|
||||
// tagged union.
|
||||
type PartInputUnion =
|
||||
| MessageV2.TextPartInput
|
||||
| MessageV2.FilePartInput
|
||||
| MessageV2.AgentPartInput
|
||||
| MessageV2.SubtaskPartInput
|
||||
export type PromptInput = Omit<Schema.Schema.Type<typeof PromptInput>, "parts"> & {
|
||||
parts: PartInputUnion[]
|
||||
}
|
||||
export type PromptInput = Schema.Schema.Type<typeof PromptInput>
|
||||
|
||||
export class LoopInput extends Schema.Class<LoopInput>("SessionPrompt.LoopInput")({
|
||||
sessionID: SessionID,
|
||||
|
||||
Reference in New Issue
Block a user