import { BusEvent } from "@/bus/bus-event"import z from "zod"import { NamedError } from "@synsci/util/error"import { APICallError, convertToModelMessages, LoadAPIKeyError, type ModelMessage, type UIMessage } from "ai"import { Identifier } from "../id/id"import { LSP } from "../lsp"import { Snapshot } from "@/snapshot"import { fn } from "@/util/fn"import { Storage } from "@/storage/storage"import { ProviderTransform } from "@/provider/transform"import { STATUS_CODES } from "http"import { iife } from "@/util/iife"import { type SystemError } from "bun"import type { Provider } from "@/provider/provider"import { correctImageMimeFromBase64 } from "@/util/image"import { Lock } from "@/util/lock" export namespace MessageV2 { export const OutputLengthError = NamedError.create("MessageOutputLengthError", z.object({})) export const AbortedError = NamedError.create("MessageAbortedError", z.object({ message: z.string() })) export const AuthError = NamedError.create( "ProviderAuthError", z.object({ providerID: z.string(), message: z.string(), }), ) export const APIError = NamedError.create( "APIError", z.object({ message: z.string(), statusCode: z.number().optional(), isRetryable: z.boolean(), responseHeaders: z.record(z.string(), z.string()).optional(), responseBody: z.string().optional(), metadata: z.record(z.string(), z.string()).optional(), }), ) export type APIError = z.infer<typeof APIError.Schema> const PartBase = z.object({ id: z.string(), sessionID: z.string(), messageID: z.string(), }) export const SnapshotPart = PartBase.extend({ type: z.literal("snapshot"), snapshot: z.string(), }).meta({ ref: "SnapshotPart", }) export type SnapshotPart = z.infer<typeof SnapshotPart> export const PatchPart = PartBase.extend({ type: z.literal("patch"), hash: z.string(), files: z.string().array(), }).meta({ ref: "PatchPart", }) export type PatchPart = z.infer<typeof PatchPart> export const TextPart = PartBase.extend({ type: z.literal("text"), text: z.string(), synthetic: z.boolean().optional(), ignored: z.boolean().optional(), time: z .object({ start: z.number(), end: z.number().optional(), }) .optional(), metadata: z.record(z.string(), z.any()).optional(), }).meta({ ref: "TextPart", }) export type TextPart = z.infer<typeof TextPart> export const ReasoningPart = PartBase.extend({ type: z.literal("reasoning"), text: z.string(), metadata: z.record(z.string(), z.any()).optional(), time: z.object({ start: z.number(), end: z.number().optional(), }), }).meta({ ref: "ReasoningPart", }) export type ReasoningPart = z.infer<typeof ReasoningPart> const FilePartSourceBase = z.object({ text: z .object({ value: z.string(), start: z.number().int(), end: z.number().int(), }) .meta({ ref: "FilePartSourceText", }), }) export const FileSource = FilePartSourceBase.extend({ type: z.literal("file"), path: z.string(), }).meta({ ref: "FileSource", }) export const SymbolSource = FilePartSourceBase.extend({ type: z.literal("symbol"), path: z.string(), range: LSP.Range, name: z.string(), kind: z.number().int(), }).meta({ ref: "SymbolSource", }) export const ResourceSource = FilePartSourceBase.extend({ type: z.literal("resource"), clientName: z.string(), uri: z.string(), }).meta({ ref: "ResourceSource", }) export const FilePartSource = z.discriminatedUnion("type", [FileSource, SymbolSource, ResourceSource]).meta({ ref: "FilePartSource", }) export const FilePart = PartBase.extend({ type: z.literal("file"), mime: z.string(), filename: z.string().optional(), url: z.string(), source: FilePartSource.optional(), }).meta({ ref: "FilePart", }) export type FilePart = z.infer<typeof FilePart> export const AgentPart = PartBase.extend({ type: z.literal("agent"), name: z.string(), source: z .object({ value: z.string(), start: z.number().int(), end: z.number().int(), }) .optional(), }).meta({ ref: "AgentPart", }) export type AgentPart = z.infer<typeof AgentPart> export const CompactionPart = PartBase.extend({ type: z.literal("compaction"), auto: z.boolean(), }).meta({ ref: "CompactionPart", }) export type CompactionPart = z.infer<typeof CompactionPart> export const SubtaskPart = PartBase.extend({ type: z.literal("subtask"), prompt: z.string(), description: z.string(), agent: z.string(), model: z .object({ providerID: z.string(), modelID: z.string(), }) .optional(), command: z.string().optional(), }).meta({ ref: "SubtaskPart", }) export type SubtaskPart = z.infer<typeof SubtaskPart> export const RetryPart = PartBase.extend({ type: z.literal("retry"), attempt: z.number(), error: APIError.Schema, time: z.object({ created: z.number(), }), }).meta({ ref: "RetryPart", }) export type RetryPart = z.infer<typeof RetryPart> export const StepStartPart = PartBase.extend({ type: z.literal("step-start"), snapshot: z.string().optional(), }).meta({ ref: "StepStartPart", }) export type StepStartPart = z.infer<typeof StepStartPart> export const StepFinishPart = PartBase.extend({ type: z.literal("step-finish"), reason: z.string(), snapshot: z.string().optional(), cost: z.number(), tokens: z.object({ input: z.number(), output: z.number(), reasoning: z.number(), cache: z.object({ read: z.number(), write: z.number(), }), }), }).meta({ ref: "StepFinishPart", }) export type StepFinishPart = z.infer<typeof StepFinishPart> export const ToolStatePending = z .object({ status: z.literal("pending"), input: z.record(z.string(), z.any()), raw: z.string(), }) .meta({ ref: "ToolStatePending", }) export type ToolStatePending = z.infer<typeof ToolStatePending> export const ToolStateRunning = z .object({ status: z.literal("running"), input: z.record(z.string(), z.any()), title: z.string().optional(), metadata: z.record(z.string(), z.any()).optional(), time: z.object({ start: z.number(), }), }) .meta({ ref: "ToolStateRunning", }) export type ToolStateRunning = z.infer<typeof ToolStateRunning> export const ToolStateCompleted = z .object({ status: z.literal("completed"), input: z.record(z.string(), z.any()), output: z.string(), title: z.string(), metadata: z.record(z.string(), z.any()), time: z.object({ start: z.number(), end: z.number(), compacted: z.number().optional(), }), attachments: FilePart.array().optional(), }) .meta({ ref: "ToolStateCompleted", }) export type ToolStateCompleted = z.infer<typeof ToolStateCompleted> export const ToolStateError = z .object({ status: z.literal("error"), input: z.record(z.string(), z.any()), error: z.string(), metadata: z.record(z.string(), z.any()).optional(), time: z.object({ start: z.number(), end: z.number(), }), }) .meta({ ref: "ToolStateError", }) export type ToolStateError = z.infer<typeof ToolStateError> export const ToolState = z .discriminatedUnion("status", [ToolStatePending, ToolStateRunning, ToolStateCompleted, ToolStateError]) .meta({ ref: "ToolState", }) export const ToolPart = PartBase.extend({ type: z.literal("tool"), callID: z.string(), tool: z.string(), state: ToolState, metadata: z.record(z.string(), z.any()).optional(), }).meta({ ref: "ToolPart", }) export type ToolPart = z.infer<typeof ToolPart> const Base = z.object({ id: z.string(), sessionID: z.string(), }) export const User = Base.extend({ role: z.literal("user"), time: z.object({ created: z.number(), }), summary: z .object({ title: z.string().optional(), body: z.string().optional(), diffs: Snapshot.FileDiff.array(), }) .optional(), agent: z.string(), model: z.object({ providerID: z.string(), modelID: z.string(), }), system: z.string().optional(), tools: z.record(z.string(), z.boolean()).optional(), variant: z.string().optional(), tier: z.enum(["fast", "pro", "ultra"]).optional(), // Real per-request "fast" API param — currently gpt-5.5 only, mapped to // OpenAI service_tier:"priority" in llm.ts. Distinct from `tier` (billing). fast: z.boolean().optional(), }).meta({ ref: "UserMessage", }) export type User = z.infer<typeof User> export const Part = z .discriminatedUnion("type", [ TextPart, SubtaskPart, ReasoningPart, FilePart, ToolPart, StepStartPart, StepFinishPart, SnapshotPart, PatchPart, AgentPart, RetryPart, CompactionPart, ]) .meta({ ref: "Part", }) export type Part = z.infer<typeof Part> export const Assistant = Base.extend({ role: z.literal("assistant"), time: z.object({ created: z.number(), completed: z.number().optional(), }), error: z .discriminatedUnion("name", [ AuthError.Schema, NamedError.Unknown.Schema, OutputLengthError.Schema, AbortedError.Schema, APIError.Schema, ]) .optional(), parentID: z.string(), modelID: z.string(), providerID: z.string(), /** * @deprecated */ mode: z.string(), agent: z.string(), path: z.object({ cwd: z.string(), root: z.string(), }), summary: z.boolean().optional(), cost: z.number(), tokens: z.object({ input: z.number(), output: z.number(), reasoning: z.number(), cache: z.object({ read: z.number(), write: z.number(), }), }), finish: z.string().optional(), }).meta({ ref: "AssistantMessage", }) export type Assistant = z.infer<typeof Assistant> export const Info = z.discriminatedUnion("role", [User, Assistant]).meta({ ref: "Message", }) export type Info = z.infer<typeof Info> export const Event = { Updated: BusEvent.define( "message.updated", z.object({ info: Info, }), ), Removed: BusEvent.define( "message.removed", z.object({ sessionID: z.string(), messageID: z.string(), }), ), PartUpdated: BusEvent.define( "message.part.updated", z.object({ part: Part, delta: z.string().optional(), }), ), PartRemoved: BusEvent.define( "message.part.removed", z.object({ sessionID: z.string(), messageID: z.string(), partID: z.string(), }), ), } export const WithParts = z.object({ info: Info, parts: z.array(Part), }) export type WithParts = z.infer<typeof WithParts> export function toModelMessages(input: WithParts[], model: Provider.Model): ModelMessage[] { const result: UIMessage[] = [] const toolNames = new Set<string>() const toModelOutput = (output: unknown) => { if (typeof output === "string") { return { type: "text", value: output } } if (typeof output === "object") { const outputObject = output as { text: string attachments?: Array<{ mime: string; url: string }> } const attachments = (outputObject.attachments ?? []).filter((attachment) => { return attachment.url.startsWith("data:") && attachment.url.includes(",") }) return { type: "content", value: [ { type: "text", text: outputObject.text }, ...attachments.map((attachment) => { const base64 = iife(() => { const commaIndex = attachment.url.indexOf(",") return commaIndex === -1 ? attachment.url : attachment.url.slice(commaIndex + 1) }) const mime = attachment.mime.startsWith("image/") ? correctImageMimeFromBase64(attachment.mime, base64) : attachment.mime return { type: "media", mediaType: mime, data: base64 } }), ], } } return { type: "json", value: output as never } } for (const msg of input) { if (msg.parts.length === 0) continue if (msg.info.role === "user") { const userMessage: UIMessage = { id: msg.info.id, role: "user", parts: [], } result.push(userMessage) for (const part of msg.parts) { if (part.type === "text" && !part.ignored) userMessage.parts.push({ type: "text", text: part.text, }) // text/plain and directory files are converted into text parts, ignore them if (part.type === "file" && part.mime !== "text/plain" && part.mime !== "application/x-directory") {Lines 1–500 of 842. Load more
import { BusEvent } from "@/bus/bus-event" import z from "zod" import { NamedError } from "@synsci/util/error" import { APICallError, convertToModelMessages, LoadAPIKeyError, type ModelMessage, type UIMessage } from "ai" import { Identifier } from "../id/id" import { LSP } from "../lsp" import { Snapshot } from "@/snapshot" import { fn } from "@/util/fn" import { Storage } from "@/storage/storage" import { ProviderTransform } from "@/provider/transform" import { STATUS_CODES } from "http" import { iife } from "@/util/iife" import { type SystemError } from "bun" import type { Provider } from "@/provider/provider" import { correctImageMimeFromBase64 } from "@/util/image" import { Lock } from "@/util/lock" export namespace MessageV2 { export const OutputLengthError = NamedError.create("MessageOutputLengthError", z.object({})) export const AbortedError = NamedError.create("MessageAbortedError", z.object({ message: z.string() })) export const AuthError = NamedError.create( "ProviderAuthError", z.object({ providerID: z.string(), message: z.string(), }), ) export const APIError = NamedError.create( "APIError", z.object({ message: z.string(), statusCode: z.number().optional(), isRetryable: z.boolean(), responseHeaders: z.record(z.string(), z.string()).optional(), responseBody: z.string().optional(), metadata: z.record(z.string(), z.string()).optional(), }), ) export type APIError = z.infer<typeof APIError.Schema> const PartBase = z.object({ id: z.string(), sessionID: z.string(), messageID: z.string(), }) export const SnapshotPart = PartBase.extend({ type: z.literal("snapshot"), snapshot: z.string(), }).meta({ ref: "SnapshotPart", }) export type SnapshotPart = z.infer<typeof SnapshotPart> export const PatchPart = PartBase.extend({ type: z.literal("patch"), hash: z.string(), files: z.string().array(), }).meta({ ref: "PatchPart", }) export type PatchPart = z.infer<typeof PatchPart> export const TextPart = PartBase.extend({ type: z.literal("text"), text: z.string(), synthetic: z.boolean().optional(), ignored: z.boolean().optional(), time: z .object({ start: z.number(), end: z.number().optional(), }) .optional(), metadata: z.record(z.string(), z.any()).optional(), }).meta({ ref: "TextPart", }) export type TextPart = z.infer<typeof TextPart> export const ReasoningPart = PartBase.extend({ type: z.literal("reasoning"), text: z.string(), metadata: z.record(z.string(), z.any()).optional(), time: z.object({ start: z.number(), end: z.number().optional(), }), }).meta({ ref: "ReasoningPart", }) export type ReasoningPart = z.infer<typeof ReasoningPart> const FilePartSourceBase = z.object({ text: z .object({ value: z.string(), start: z.number().int(), end: z.number().int(), }) .meta({ ref: "FilePartSourceText", }), }) export const FileSource = FilePartSourceBase.extend({ type: z.literal("file"), path: z.string(), }).meta({ ref: "FileSource", }) export const SymbolSource = FilePartSourceBase.extend({ type: z.literal("symbol"), path: z.string(), range: LSP.Range, name: z.string(), kind: z.number().int(), }).meta({ ref: "SymbolSource", }) export const ResourceSource = FilePartSourceBase.extend({ type: z.literal("resource"), clientName: z.string(), uri: z.string(), }).meta({ ref: "ResourceSource", }) export const FilePartSource = z.discriminatedUnion("type", [FileSource, SymbolSource, ResourceSource]).meta({ ref: "FilePartSource", }) export const FilePart = PartBase.extend({ type: z.literal("file"), mime: z.string(), filename: z.string().optional(), url: z.string(), source: FilePartSource.optional(), }).meta({ ref: "FilePart", }) export type FilePart = z.infer<typeof FilePart> export const AgentPart = PartBase.extend({ type: z.literal("agent"), name: z.string(), source: z .object({ value: z.string(), start: z.number().int(), end: z.number().int(), }) .optional(), }).meta({ ref: "AgentPart", }) export type AgentPart = z.infer<typeof AgentPart> export const CompactionPart = PartBase.extend({ type: z.literal("compaction"), auto: z.boolean(), }).meta({ ref: "CompactionPart", }) export type CompactionPart = z.infer<typeof CompactionPart> export const SubtaskPart = PartBase.extend({ type: z.literal("subtask"), prompt: z.string(), description: z.string(), agent: z.string(), model: z .object({ providerID: z.string(), modelID: z.string(), }) .optional(), command: z.string().optional(), }).meta({ ref: "SubtaskPart", }) export type SubtaskPart = z.infer<typeof SubtaskPart> export const RetryPart = PartBase.extend({ type: z.literal("retry"), attempt: z.number(), error: APIError.Schema, time: z.object({ created: z.number(), }), }).meta({ ref: "RetryPart", }) export type RetryPart = z.infer<typeof RetryPart> export const StepStartPart = PartBase.extend({ type: z.literal("step-start"), snapshot: z.string().optional(), }).meta({ ref: "StepStartPart", }) export type StepStartPart = z.infer<typeof StepStartPart> export const StepFinishPart = PartBase.extend({ type: z.literal("step-finish"), reason: z.string(), snapshot: z.string().optional(), cost: z.number(), tokens: z.object({ input: z.number(), output: z.number(), reasoning: z.number(), cache: z.object({ read: z.number(), write: z.number(), }), }), }).meta({ ref: "StepFinishPart", }) export type StepFinishPart = z.infer<typeof StepFinishPart> export const ToolStatePending = z .object({ status: z.literal("pending"), input: z.record(z.string(), z.any()), raw: z.string(), }) .meta({ ref: "ToolStatePending", }) export type ToolStatePending = z.infer<typeof ToolStatePending> export const ToolStateRunning = z .object({ status: z.literal("running"), input: z.record(z.string(), z.any()), title: z.string().optional(), metadata: z.record(z.string(), z.any()).optional(), time: z.object({ start: z.number(), }), }) .meta({ ref: "ToolStateRunning", }) export type ToolStateRunning = z.infer<typeof ToolStateRunning> export const ToolStateCompleted = z .object({ status: z.literal("completed"), input: z.record(z.string(), z.any()), output: z.string(), title: z.string(), metadata: z.record(z.string(), z.any()), time: z.object({ start: z.number(), end: z.number(), compacted: z.number().optional(), }), attachments: FilePart.array().optional(), }) .meta({ ref: "ToolStateCompleted", }) export type ToolStateCompleted = z.infer<typeof ToolStateCompleted> export const ToolStateError = z .object({ status: z.literal("error"), input: z.record(z.string(), z.any()), error: z.string(), metadata: z.record(z.string(), z.any()).optional(), time: z.object({ start: z.number(), end: z.number(), }), }) .meta({ ref: "ToolStateError", }) export type ToolStateError = z.infer<typeof ToolStateError> export const ToolState = z .discriminatedUnion("status", [ToolStatePending, ToolStateRunning, ToolStateCompleted, ToolStateError]) .meta({ ref: "ToolState", }) export const ToolPart = PartBase.extend({ type: z.literal("tool"), callID: z.string(), tool: z.string(), state: ToolState, metadata: z.record(z.string(), z.any()).optional(), }).meta({ ref: "ToolPart", }) export type ToolPart = z.infer<typeof ToolPart> const Base = z.object({ id: z.string(), sessionID: z.string(), }) export const User = Base.extend({ role: z.literal("user"), time: z.object({ created: z.number(), }), summary: z .object({ title: z.string().optional(), body: z.string().optional(), diffs: Snapshot.FileDiff.array(), }) .optional(), agent: z.string(), model: z.object({ providerID: z.string(), modelID: z.string(), }), system: z.string().optional(), tools: z.record(z.string(), z.boolean()).optional(), variant: z.string().optional(), tier: z.enum(["fast", "pro", "ultra"]).optional(), // Real per-request "fast" API param — currently gpt-5.5 only, mapped to // OpenAI service_tier:"priority" in llm.ts. Distinct from `tier` (billing). fast: z.boolean().optional(), }).meta({ ref: "UserMessage", }) export type User = z.infer<typeof User> export const Part = z .discriminatedUnion("type", [ TextPart, SubtaskPart, ReasoningPart, FilePart, ToolPart, StepStartPart, StepFinishPart, SnapshotPart, PatchPart, AgentPart, RetryPart, CompactionPart, ]) .meta({ ref: "Part", }) export type Part = z.infer<typeof Part> export const Assistant = Base.extend({ role: z.literal("assistant"), time: z.object({ created: z.number(), completed: z.number().optional(), }), error: z .discriminatedUnion("name", [ AuthError.Schema, NamedError.Unknown.Schema, OutputLengthError.Schema, AbortedError.Schema, APIError.Schema, ]) .optional(), parentID: z.string(), modelID: z.string(), providerID: z.string(), /** * @deprecated */ mode: z.string(), agent: z.string(), path: z.object({ cwd: z.string(), root: z.string(), }), summary: z.boolean().optional(), cost: z.number(), tokens: z.object({ input: z.number(), output: z.number(), reasoning: z.number(), cache: z.object({ read: z.number(), write: z.number(), }), }), finish: z.string().optional(), }).meta({ ref: "AssistantMessage", }) export type Assistant = z.infer<typeof Assistant> export const Info = z.discriminatedUnion("role", [User, Assistant]).meta({ ref: "Message", }) export type Info = z.infer<typeof Info> export const Event = { Updated: BusEvent.define( "message.updated", z.object({ info: Info, }), ), Removed: BusEvent.define( "message.removed", z.object({ sessionID: z.string(), messageID: z.string(), }), ), PartUpdated: BusEvent.define( "message.part.updated", z.object({ part: Part, delta: z.string().optional(), }), ), PartRemoved: BusEvent.define( "message.part.removed", z.object({ sessionID: z.string(), messageID: z.string(), partID: z.string(), }), ), } export const WithParts = z.object({ info: Info, parts: z.array(Part), }) export type WithParts = z.infer<typeof WithParts> export function toModelMessages(input: WithParts[], model: Provider.Model): ModelMessage[] { const result: UIMessage[] = [] const toolNames = new Set<string>() const toModelOutput = (output: unknown) => { if (typeof output === "string") { return { type: "text", value: output } } if (typeof output === "object") { const outputObject = output as { text: string attachments?: Array<{ mime: string; url: string }> } const attachments = (outputObject.attachments ?? []).filter((attachment) => { return attachment.url.startsWith("data:") && attachment.url.includes(",") }) return { type: "content", value: [ { type: "text", text: outputObject.text }, ...attachments.map((attachment) => { const base64 = iife(() => { const commaIndex = attachment.url.indexOf(",") return commaIndex === -1 ? attachment.url : attachment.url.slice(commaIndex + 1) }) const mime = attachment.mime.startsWith("image/") ? correctImageMimeFromBase64(attachment.mime, base64) : attachment.mime return { type: "media", mediaType: mime, data: base64 } }), ], } } return { type: "json", value: output as never } } for (const msg of input) { if (msg.parts.length === 0) continue if (msg.info.role === "user") { const userMessage: UIMessage = { id: msg.info.id, role: "user", parts: [], } result.push(userMessage) for (const part of msg.parts) { if (part.type === "text" && !part.ignored) userMessage.parts.push({ type: "text", text: part.text, }) // text/plain and directory files are converted into text parts, ignore them if (part.type === "file" && part.mime !== "text/plain" && part.mime !== "application/x-directory") {