mirror of
https://github.com/rowboatlabs/rowboat.git
synced 2026-06-12 19:55:19 +02:00
Move volatile current time and middle-pane data out of the system prompt and into a hidden userMessageContext stored on each user message. Reconstruct the LLM-facing message from this persisted context so older conversation turns remain stable across later requests while UI-facing content stays unchanged. Keep finite branch instructions such as voice, search, code mode, agent notes, and workdir behavior in the system prompt so each conversation can still benefit from reusable prompt-cache prefixes.
109 lines
3.1 KiB
TypeScript
109 lines
3.1 KiB
TypeScript
import { z } from "zod";
|
|
|
|
export const ProviderOptions = z.record(z.string(), z.record(z.string(), z.json()));
|
|
|
|
export const TextPart = z.object({
|
|
type: z.literal("text"),
|
|
text: z.string(),
|
|
providerOptions: ProviderOptions.optional(),
|
|
});
|
|
|
|
export const ReasoningPart = z.object({
|
|
type: z.literal("reasoning"),
|
|
text: z.string(),
|
|
providerOptions: ProviderOptions.optional(),
|
|
});
|
|
|
|
export const ToolCallPart = z.object({
|
|
type: z.literal("tool-call"),
|
|
toolCallId: z.string(),
|
|
toolName: z.string(),
|
|
arguments: z.any(),
|
|
providerOptions: ProviderOptions.optional(),
|
|
});
|
|
|
|
export const AssistantContentPart = z.union([
|
|
TextPart,
|
|
ReasoningPart,
|
|
ToolCallPart,
|
|
]);
|
|
|
|
// A piece of user-typed text within a content array
|
|
export const UserTextPart = z.object({
|
|
type: z.literal("text"),
|
|
text: z.string(),
|
|
});
|
|
|
|
// An attachment within a content array
|
|
export const UserAttachmentPart = z.object({
|
|
type: z.literal("attachment"),
|
|
path: z.string(), // absolute file path
|
|
filename: z.string(), // display name ("photo.png")
|
|
mimeType: z.string(), // MIME type ("image/png", "text/plain")
|
|
size: z.number().optional(), // bytes
|
|
lineNumber: z.number().int().min(1).optional(), // 1-indexed line in source file (for editor-context references)
|
|
});
|
|
|
|
// Any single part of a user message (text or attachment)
|
|
export const UserContentPart = z.union([UserTextPart, UserAttachmentPart]);
|
|
|
|
// Named type for user message content — used everywhere instead of repeating the union
|
|
export const UserMessageContent = z.union([z.string(), z.array(UserContentPart)]);
|
|
|
|
export const UserMessageContext = z.object({
|
|
currentDateTime: z.string().optional(),
|
|
middlePane: z.discriminatedUnion("kind", [
|
|
z.object({
|
|
kind: z.literal("empty"),
|
|
}),
|
|
z.object({
|
|
kind: z.literal("note"),
|
|
path: z.string(),
|
|
content: z.string(),
|
|
}),
|
|
z.object({
|
|
kind: z.literal("browser"),
|
|
url: z.string(),
|
|
title: z.string(),
|
|
}),
|
|
]).optional(),
|
|
});
|
|
|
|
export const UserMessage = z.object({
|
|
role: z.literal("user"),
|
|
content: UserMessageContent,
|
|
userMessageContext: UserMessageContext.optional(),
|
|
providerOptions: ProviderOptions.optional(),
|
|
});
|
|
|
|
export const AssistantMessage = z.object({
|
|
role: z.literal("assistant"),
|
|
content: z.union([
|
|
z.string(),
|
|
z.array(AssistantContentPart),
|
|
]),
|
|
providerOptions: ProviderOptions.optional(),
|
|
});
|
|
|
|
export const SystemMessage = z.object({
|
|
role: z.literal("system"),
|
|
content: z.string(),
|
|
providerOptions: ProviderOptions.optional(),
|
|
});
|
|
|
|
export const ToolMessage = z.object({
|
|
role: z.literal("tool"),
|
|
content: z.string(),
|
|
toolCallId: z.string(),
|
|
toolName: z.string(),
|
|
providerOptions: ProviderOptions.optional(),
|
|
});
|
|
|
|
export const Message = z.discriminatedUnion("role", [
|
|
AssistantMessage,
|
|
SystemMessage,
|
|
ToolMessage,
|
|
UserMessage,
|
|
]);
|
|
|
|
export const MessageList = z.array(Message);
|