mirror of
https://github.com/getpaseo/paseo.git
synced 2026-10-24 10:12:44 +00:00
* fix(providers): apply configured options at session startup Treat provider options as one opaque record, with provider-owned validation and per-agent overrides over configured defaults. Keep agent overrides separate from defaults so configuration changes apply on the next launch or resume. * test(providers): verify provider-owned validation through Hub * fix(providers): preserve the complete wrapped session interface
1414 lines
40 KiB
TypeScript
1414 lines
40 KiB
TypeScript
import type { JsonValue } from "@getpaseo/protocol/agent-types";
|
|
import { z } from "zod";
|
|
|
|
export const PROVIDER_PROTOCOL_VERSION = 1 as const;
|
|
|
|
export const PROVIDER_CAPABILITIES = [
|
|
"prompt.message",
|
|
"prompt.command",
|
|
"prompt.image",
|
|
"prompt.output_schema",
|
|
"prompt.steer",
|
|
"session.archive",
|
|
"session.configure",
|
|
"session.list",
|
|
"session.persistence",
|
|
"session.revert.both",
|
|
"session.revert.conversation",
|
|
"session.revert.files",
|
|
"session.subsession",
|
|
"session.unarchive",
|
|
"permission",
|
|
"permission.tool_policy",
|
|
"timeline.plugin",
|
|
] as const;
|
|
|
|
export type ProviderCapability = (typeof PROVIDER_CAPABILITIES)[number];
|
|
|
|
export interface ProviderRegistration {
|
|
/** Equal keys share discovery within this provider. Include effective configuration and execution environment. */
|
|
getCatalogCacheKey?(options: ProviderCatalogOptions): Promise<string | undefined>;
|
|
/** Default executable and arguments; the daemon resolves overrides before status/connect. */
|
|
command?: readonly [string, ...string[]];
|
|
status?(request: ProviderStatusRequest): Promise<ProviderStatus>;
|
|
id: string;
|
|
label: string;
|
|
description?: string;
|
|
/** Plugin-directory-relative path to a self-contained SVG file. */
|
|
icon?: string;
|
|
connect(request: ProviderConnectRequest): Promise<ProviderConnection>;
|
|
}
|
|
|
|
export type ProviderCatalogOptions =
|
|
| { scope: "global"; force?: boolean; launch?: ProviderLaunch }
|
|
| { scope: "workspace"; cwd: string; force?: boolean; launch?: ProviderLaunch };
|
|
|
|
export const ProviderLaunchSchema = z
|
|
.object({
|
|
/** Resolved executable path. */
|
|
command: z.string().min(1),
|
|
args: z.array(z.string()),
|
|
/** Complete daemon-owned environment, including overrides and parent-session stripping. */
|
|
env: z.record(z.string(), z.string()),
|
|
})
|
|
.strip();
|
|
|
|
export type ProviderLaunch = z.infer<typeof ProviderLaunchSchema>;
|
|
|
|
export interface ProviderStatusRequest {
|
|
launch?: ProviderLaunch;
|
|
}
|
|
|
|
export const ProviderStatusSchema = z.discriminatedUnion("available", [
|
|
z.object({ available: z.literal(true), diagnostic: z.string().optional() }).strip(),
|
|
z.object({ available: z.literal(false), diagnostic: z.string().min(1) }).strip(),
|
|
]);
|
|
|
|
export type ProviderStatus = z.infer<typeof ProviderStatusSchema>;
|
|
|
|
export interface ProviderConnectRequest {
|
|
launch?: ProviderLaunch;
|
|
versions: readonly number[];
|
|
capabilities: readonly string[];
|
|
}
|
|
|
|
export interface ProviderConnection {
|
|
readonly version: number;
|
|
readonly capabilities: readonly string[];
|
|
send(input: ProviderInput): Promise<void>;
|
|
onEvent(listener: (event: ProviderEvent) => void): () => void;
|
|
close(): Promise<void>;
|
|
}
|
|
|
|
export interface ProviderPersistence {
|
|
version: number;
|
|
data: JsonValue;
|
|
}
|
|
|
|
export type ProviderMcpServerConfig =
|
|
| {
|
|
type: "stdio";
|
|
command: string;
|
|
args?: string[];
|
|
env?: Record<string, string>;
|
|
alwaysLoad?: boolean;
|
|
}
|
|
| {
|
|
type: "http" | "sse";
|
|
url: string;
|
|
headers?: Record<string, string>;
|
|
alwaysLoad?: boolean;
|
|
};
|
|
|
|
export interface ProviderToolPolicy {
|
|
preapproved: Array<{ kind: "mcp"; server: string; tool: string }>;
|
|
}
|
|
|
|
export interface ProviderSessionConfig {
|
|
cwd: string;
|
|
env: Readonly<Record<string, string>>;
|
|
systemPrompt?: string;
|
|
mcpServers: Readonly<Record<string, ProviderMcpServerConfig>>;
|
|
toolPolicy?: ProviderToolPolicy;
|
|
model?: string;
|
|
mode?: string;
|
|
thinkingOption?: string;
|
|
settings: Readonly<Record<string, JsonValue>>;
|
|
providerOptions?: Readonly<Record<string, unknown>>;
|
|
title?: string;
|
|
persist: boolean;
|
|
}
|
|
|
|
export interface ProviderConfigChanges {
|
|
model?: string | null;
|
|
mode?: string | null;
|
|
thinkingOption?: string | null;
|
|
settings?: Readonly<Record<string, JsonValue>>;
|
|
}
|
|
|
|
export interface ProviderPrompt {
|
|
clientMessageId: string;
|
|
delivery: "auto" | "steer";
|
|
input:
|
|
| { type: "message"; content: ProviderContent[] }
|
|
| { type: "command"; name: string; arguments: string };
|
|
outputSchema?: JsonValue;
|
|
clearPendingPermissions?: boolean;
|
|
}
|
|
|
|
interface ProviderForgeChangeRequestAttachment {
|
|
type: "forge_change_request";
|
|
mimeType: "application/paseo-forge-change-request";
|
|
forge?: string;
|
|
number: number;
|
|
title: string;
|
|
url: string;
|
|
body?: string | null;
|
|
projectPath?: string;
|
|
baseRefName?: string | null;
|
|
headRefName?: string | null;
|
|
}
|
|
|
|
interface ProviderForgeIssueAttachment {
|
|
type: "forge_issue";
|
|
mimeType: "application/paseo-forge-issue";
|
|
forge?: string;
|
|
number: number;
|
|
title: string;
|
|
url: string;
|
|
body?: string | null;
|
|
projectPath?: string;
|
|
}
|
|
|
|
interface ProviderGitHubPrAttachment {
|
|
type: "github_pr";
|
|
mimeType: "application/github-pr";
|
|
number: number;
|
|
title: string;
|
|
url: string;
|
|
body?: string | null;
|
|
baseRefName?: string | null;
|
|
headRefName?: string | null;
|
|
}
|
|
|
|
interface ProviderGitHubIssueAttachment {
|
|
type: "github_issue";
|
|
mimeType: "application/github-issue";
|
|
number: number;
|
|
title: string;
|
|
url: string;
|
|
body?: string | null;
|
|
}
|
|
|
|
interface ProviderTextAttachment {
|
|
type: "text";
|
|
mimeType: "text/plain";
|
|
contextKind?: string;
|
|
title?: string | null;
|
|
text: string;
|
|
externalResource?: {
|
|
provider: string;
|
|
providerLabel: string;
|
|
resourceType: string;
|
|
id: string;
|
|
identifier: string;
|
|
title: string;
|
|
url: string;
|
|
};
|
|
}
|
|
|
|
interface ProviderReviewAttachment {
|
|
type: "review";
|
|
mimeType: "application/paseo-review";
|
|
cwd: string;
|
|
mode: "uncommitted" | "base";
|
|
baseRef?: string | null;
|
|
comments: Array<{
|
|
filePath: string;
|
|
side: "old" | "new";
|
|
lineNumber: number;
|
|
body: string;
|
|
context: {
|
|
hunkHeader: string;
|
|
targetLine: ProviderReviewContextLine;
|
|
lines: ProviderReviewContextLine[];
|
|
};
|
|
}>;
|
|
}
|
|
|
|
interface ProviderReviewContextLine {
|
|
oldLineNumber: number | null;
|
|
newLineNumber: number | null;
|
|
type: "add" | "remove" | "context";
|
|
content: string;
|
|
}
|
|
|
|
export type ProviderContent =
|
|
| { type: "text"; text: string }
|
|
| { type: "image"; data: string; mimeType: string }
|
|
| ProviderForgeChangeRequestAttachment
|
|
| ProviderForgeIssueAttachment
|
|
| ProviderGitHubPrAttachment
|
|
| ProviderGitHubIssueAttachment
|
|
| ProviderTextAttachment
|
|
| ProviderReviewAttachment
|
|
| {
|
|
type: "uploaded_file";
|
|
id: string;
|
|
fileName: string;
|
|
mimeType: string;
|
|
size: number;
|
|
path: string;
|
|
};
|
|
|
|
export type ProviderInput =
|
|
| { type: "catalog"; requestId: string; cwd?: string }
|
|
| { type: "sessions"; requestId: string; query?: string; cwd?: string; limit?: number }
|
|
| {
|
|
type: "session.open";
|
|
requestId: string;
|
|
sessionId: string;
|
|
config: ProviderSessionConfig;
|
|
persistence?: ProviderPersistence;
|
|
history: "replay" | "skip";
|
|
}
|
|
| { type: "session.prompt"; sessionId: string; prompt: ProviderPrompt }
|
|
| { type: "session.interrupt"; requestId: string; sessionId: string }
|
|
| {
|
|
type: "session.permission";
|
|
sessionId: string;
|
|
permissionId: string;
|
|
response: ProviderPermissionResponse;
|
|
}
|
|
| {
|
|
type: "session.configure";
|
|
requestId: string;
|
|
sessionId: string;
|
|
changes: ProviderConfigChanges;
|
|
}
|
|
| {
|
|
type: "session.revert";
|
|
requestId: string;
|
|
sessionId: string;
|
|
token: JsonValue;
|
|
scope: "conversation" | "files" | "both";
|
|
}
|
|
| { type: "session.archive"; requestId: string; persistence: ProviderPersistence }
|
|
| { type: "session.unarchive"; requestId: string; persistence: ProviderPersistence }
|
|
| { type: "session.close"; requestId: string; sessionId: string };
|
|
|
|
export interface ProviderThinkingOption {
|
|
id: string;
|
|
label: string;
|
|
description?: string;
|
|
isDefault?: boolean;
|
|
metadata?: Readonly<Record<string, JsonValue>>;
|
|
}
|
|
|
|
export interface ProviderModel {
|
|
id: string;
|
|
aliases?: string[];
|
|
isSelectable?: boolean;
|
|
label: string;
|
|
description?: string;
|
|
isDefault?: boolean;
|
|
metadata?: Readonly<Record<string, JsonValue>>;
|
|
contextWindowMaxTokens?: number;
|
|
thinkingOptions?: ProviderThinkingOption[];
|
|
defaultThinkingOptionId?: string;
|
|
}
|
|
|
|
export interface ProviderMode {
|
|
id: string;
|
|
label: string;
|
|
description?: string;
|
|
icon?: string;
|
|
colorTier?: string;
|
|
isUnattended?: boolean;
|
|
}
|
|
|
|
export type ProviderSetting =
|
|
| {
|
|
type: "toggle";
|
|
id: string;
|
|
label: string;
|
|
description?: string;
|
|
value: boolean;
|
|
}
|
|
| {
|
|
type: "select";
|
|
id: string;
|
|
label: string;
|
|
description?: string;
|
|
value: string | null;
|
|
options: ReadonlyArray<{ label: string; value: string }>;
|
|
};
|
|
|
|
export interface ProviderConfigState {
|
|
model?: string;
|
|
mode?: string;
|
|
thinkingOption?: string;
|
|
models: readonly ProviderModel[];
|
|
modes: readonly ProviderMode[];
|
|
thinkingOptions: readonly ProviderThinkingOption[];
|
|
settings: readonly ProviderSetting[];
|
|
}
|
|
|
|
export interface ProviderCatalog {
|
|
models: readonly ProviderModel[];
|
|
modes: readonly ProviderMode[];
|
|
thinkingOptions?: readonly ProviderThinkingOption[];
|
|
defaultModel?: string;
|
|
defaultMode?: string;
|
|
defaultThinkingOption?: string;
|
|
}
|
|
|
|
export interface ProviderSessionSummary {
|
|
persistence: ProviderPersistence;
|
|
cwd: string;
|
|
title?: string;
|
|
description?: string;
|
|
updatedAt?: string;
|
|
}
|
|
|
|
export interface ProviderCommand {
|
|
name: string;
|
|
description: string;
|
|
argumentHint?: string;
|
|
}
|
|
|
|
export interface ProviderError {
|
|
message: string;
|
|
code?: string;
|
|
diagnostic?: string;
|
|
}
|
|
|
|
export interface ProviderNotice {
|
|
id: string;
|
|
severity: "info" | "warning" | "error";
|
|
title: string;
|
|
description?: string;
|
|
dismissed?: boolean;
|
|
}
|
|
|
|
export interface ProviderPermissionAction {
|
|
id: string;
|
|
label: string;
|
|
behavior: "allow" | "deny";
|
|
variant?: "primary" | "secondary" | "danger";
|
|
intent?: "implement" | "implement_resume" | "dismiss";
|
|
}
|
|
|
|
export interface ProviderPermissionRequest {
|
|
id: string;
|
|
name: string;
|
|
kind: "tool" | "plan" | "question" | "mode" | "other";
|
|
title?: string;
|
|
description?: string;
|
|
input?: Readonly<Record<string, JsonValue>>;
|
|
detail?: ProviderToolCallDetail;
|
|
suggestions?: Array<Record<string, JsonValue>>;
|
|
actions?: ProviderPermissionAction[];
|
|
metadata?: Readonly<Record<string, JsonValue>>;
|
|
}
|
|
|
|
export type ProviderPermissionResponse =
|
|
| {
|
|
behavior: "allow";
|
|
selectedActionId?: string;
|
|
updatedInput?: Record<string, JsonValue>;
|
|
updatedPermissions?: Array<Record<string, JsonValue>>;
|
|
}
|
|
| {
|
|
behavior: "deny";
|
|
selectedActionId?: string;
|
|
message?: string;
|
|
interrupt?: boolean;
|
|
};
|
|
|
|
export interface ProviderUsage {
|
|
inputTokens?: number;
|
|
cachedInputTokens?: number;
|
|
outputTokens?: number;
|
|
totalCostUsd?: number;
|
|
contextWindowMaxTokens?: number;
|
|
contextWindowUsedTokens?: number;
|
|
}
|
|
|
|
interface ProviderTimelineIdentity {
|
|
id: string;
|
|
revertToken?: JsonValue;
|
|
}
|
|
|
|
export type ProviderToolCallDetail =
|
|
| { type: "shell"; command: string; cwd?: string; output?: string; exitCode?: number | null }
|
|
| { type: "read"; filePath: string; content?: string; offset?: number; limit?: number }
|
|
| {
|
|
type: "edit";
|
|
filePath: string;
|
|
oldString?: string;
|
|
newString?: string;
|
|
unifiedDiff?: string;
|
|
}
|
|
| { type: "write"; filePath: string; content?: string }
|
|
| {
|
|
type: "search";
|
|
query: string;
|
|
toolName?: "search" | "grep" | "glob" | "web_search";
|
|
content?: string;
|
|
filePaths?: string[];
|
|
webResults?: Array<{ title: string; url: string }>;
|
|
annotations?: string[];
|
|
numFiles?: number;
|
|
numMatches?: number;
|
|
durationMs?: number;
|
|
durationSeconds?: number;
|
|
truncated?: boolean;
|
|
mode?: "content" | "files_with_matches" | "count";
|
|
}
|
|
| {
|
|
type: "fetch";
|
|
url: string;
|
|
prompt?: string;
|
|
result?: string;
|
|
code?: number;
|
|
codeText?: string;
|
|
bytes?: number;
|
|
durationMs?: number;
|
|
}
|
|
| {
|
|
type: "worktree_setup";
|
|
worktreePath: string;
|
|
branchName: string;
|
|
log: string;
|
|
commands: Array<{
|
|
index: number;
|
|
command: string;
|
|
cwd: string;
|
|
log: string;
|
|
status: "running" | "completed" | "failed";
|
|
exitCode: number | null;
|
|
durationMs?: number;
|
|
}>;
|
|
truncated?: boolean;
|
|
}
|
|
| {
|
|
type: "sub_agent";
|
|
subAgentType?: string;
|
|
description?: string;
|
|
childSessionId?: string;
|
|
log: string;
|
|
actions?: Array<{ index: number; toolName: string; summary?: string }>;
|
|
}
|
|
| {
|
|
type: "plain_text";
|
|
label?: string;
|
|
text?: string;
|
|
icon?:
|
|
| "wrench"
|
|
| "square_terminal"
|
|
| "eye"
|
|
| "pencil"
|
|
| "search"
|
|
| "bot"
|
|
| "sparkles"
|
|
| "brain"
|
|
| "mic_vocal";
|
|
}
|
|
| { type: "plan"; text: string }
|
|
| { type: "unknown"; input: JsonValue; output: JsonValue };
|
|
|
|
type ProviderToolCallItem = ProviderTimelineIdentity & {
|
|
type: "tool_call";
|
|
callId: string;
|
|
name: string;
|
|
detail: ProviderToolCallDetail;
|
|
metadata?: Readonly<Record<string, JsonValue>>;
|
|
} & (
|
|
| { status: "running" | "completed" | "canceled"; error: null }
|
|
| { status: "failed"; error: JsonValue }
|
|
);
|
|
|
|
export type ProviderTimelineItem =
|
|
| (ProviderTimelineIdentity & {
|
|
type: "user_message";
|
|
text: string;
|
|
messageId?: string;
|
|
clientMessageId?: string;
|
|
})
|
|
| (ProviderTimelineIdentity & { type: "assistant_message"; text: string; messageId?: string })
|
|
| (ProviderTimelineIdentity & { type: "reasoning"; text: string })
|
|
| ProviderToolCallItem
|
|
| (ProviderTimelineIdentity & {
|
|
type: "todo";
|
|
items: Array<{
|
|
text: string;
|
|
completed: boolean;
|
|
id?: string;
|
|
status?: "pending" | "in_progress" | "completed";
|
|
activeForm?: string;
|
|
}>;
|
|
})
|
|
| (ProviderTimelineIdentity & { type: "error"; message: string })
|
|
| (ProviderTimelineIdentity & {
|
|
type: "notification";
|
|
level: "info" | "warning" | "error";
|
|
message: string;
|
|
})
|
|
| (ProviderTimelineIdentity & {
|
|
type: "compaction";
|
|
status: "loading" | "completed";
|
|
trigger?: "auto" | "manual";
|
|
preTokens?: number;
|
|
})
|
|
| (ProviderTimelineIdentity & {
|
|
type: "plugin";
|
|
pluginId: string;
|
|
kind: string;
|
|
version: number;
|
|
data: JsonValue;
|
|
});
|
|
|
|
export type ProviderEvent =
|
|
| { type: "catalog"; requestId: string; catalog: ProviderCatalog }
|
|
| { type: "sessions"; requestId: string; sessions: ProviderSessionSummary[] }
|
|
| { type: "request.completed"; requestId: string }
|
|
| { type: "request.failed"; requestId: string; error: ProviderError }
|
|
| {
|
|
type: "session.opened";
|
|
requestId?: string;
|
|
sessionId: string;
|
|
/** Direct parent in the provider session ID namespace. */
|
|
parentSessionId?: string;
|
|
/** ID of the spawning tool call in the direct parent's timeline. */
|
|
toolCallId?: string;
|
|
capabilities: readonly string[];
|
|
restoration: "core" | "parent";
|
|
persistence?: ProviderPersistence;
|
|
title?: string;
|
|
description?: string;
|
|
cwd: string;
|
|
}
|
|
| { type: "session.ready"; requestId?: string; sessionId: string }
|
|
| { type: "session.closed"; sessionId: string; error?: ProviderError }
|
|
| { type: "session.runtime_failed"; sessionId: string; error: ProviderError }
|
|
| { type: "session.persistence"; sessionId: string; persistence: ProviderPersistence }
|
|
| {
|
|
type: "session.prompt_result";
|
|
sessionId: string;
|
|
clientMessageId: string;
|
|
result:
|
|
| { type: "turn"; turnId: string }
|
|
| { type: "steer"; turnId: string }
|
|
| { type: "completed" }
|
|
| { type: "failed"; error: ProviderError };
|
|
}
|
|
| {
|
|
type: "session.turn";
|
|
sessionId: string;
|
|
turnId: string;
|
|
state: "started" | "completed" | "failed" | "canceled";
|
|
error?: ProviderError;
|
|
}
|
|
| { type: "session.usage"; sessionId: string; turnId?: string; usage: ProviderUsage }
|
|
| { type: "session.config"; sessionId: string; config: ProviderConfigState }
|
|
| { type: "session.commands"; sessionId: string; commands: ProviderCommand[] }
|
|
| { type: "session.permission"; sessionId: string; request: ProviderPermissionRequest }
|
|
| { type: "session.permission_resolved"; sessionId: string; permissionId: string }
|
|
| { type: "session.notice"; sessionId: string; notice: ProviderNotice }
|
|
| { type: "timeline.item"; sessionId: string; item: ProviderTimelineItem; timestamp?: string };
|
|
|
|
export function negotiateProviderCapabilities(
|
|
offered: readonly string[],
|
|
supported: readonly string[],
|
|
): readonly ProviderCapability[] {
|
|
const known = new Set<string>(PROVIDER_CAPABILITIES);
|
|
const supportedCapabilities = new Set(supported.filter((capability) => known.has(capability)));
|
|
return offered.filter(
|
|
(capability, index): capability is ProviderCapability =>
|
|
isProviderCapability(capability) &&
|
|
supportedCapabilities.has(capability) &&
|
|
offered.indexOf(capability) === index,
|
|
);
|
|
}
|
|
|
|
export function isProviderCapability(capability: string): capability is ProviderCapability {
|
|
return new Set<string>(PROVIDER_CAPABILITIES).has(capability);
|
|
}
|
|
|
|
function requiredPromptCapabilities(prompt: ProviderPrompt): readonly ProviderCapability[] {
|
|
const capabilities: ProviderCapability[] = [];
|
|
if (prompt.delivery === "steer") capabilities.push("prompt.steer");
|
|
if (prompt.input.type === "command") capabilities.push("prompt.command");
|
|
else {
|
|
capabilities.push("prompt.message");
|
|
if (prompt.input.content.some((part) => part.type === "image")) {
|
|
capabilities.push("prompt.image");
|
|
}
|
|
}
|
|
if (prompt.outputSchema !== undefined) capabilities.push("prompt.output_schema");
|
|
return capabilities;
|
|
}
|
|
|
|
export function requiredProviderCapabilities(input: ProviderInput): readonly ProviderCapability[] {
|
|
switch (input.type) {
|
|
case "catalog":
|
|
case "session.interrupt":
|
|
case "session.close":
|
|
return [];
|
|
case "sessions":
|
|
return ["session.list"];
|
|
case "session.open": {
|
|
const capabilities: ProviderCapability[] = [];
|
|
if (input.persistence) capabilities.push("session.persistence");
|
|
if (input.config.toolPolicy) capabilities.push("permission.tool_policy");
|
|
return capabilities;
|
|
}
|
|
case "session.prompt":
|
|
return requiredPromptCapabilities(input.prompt);
|
|
case "session.permission":
|
|
return ["permission"];
|
|
case "session.configure":
|
|
return ["session.configure"];
|
|
case "session.revert":
|
|
return [`session.revert.${input.scope}`];
|
|
case "session.archive":
|
|
return ["session.archive"];
|
|
case "session.unarchive":
|
|
return ["session.unarchive"];
|
|
}
|
|
}
|
|
|
|
export function requireProviderCapabilities(
|
|
capabilities: readonly string[],
|
|
input: ProviderInput,
|
|
): void {
|
|
for (const capability of requiredProviderCapabilities(input)) {
|
|
if (!capabilities.includes(capability)) {
|
|
throw new Error(`Provider does not support ${capability}`);
|
|
}
|
|
}
|
|
}
|
|
|
|
const idSchema = z.string().min(1);
|
|
const jsonObjectSchema = z.record(z.string(), z.json());
|
|
const providerErrorSchema = z
|
|
.object({ message: z.string(), code: z.string().optional(), diagnostic: z.string().optional() })
|
|
.strip();
|
|
const persistenceSchema = z
|
|
.object({ version: z.number().int().nonnegative(), data: z.json() })
|
|
.strip();
|
|
const mcpServerSchema = z.discriminatedUnion("type", [
|
|
z
|
|
.object({
|
|
type: z.literal("stdio"),
|
|
command: z.string(),
|
|
args: z.array(z.string()).optional(),
|
|
env: z.record(z.string(), z.string()).optional(),
|
|
alwaysLoad: z.boolean().optional(),
|
|
})
|
|
.strict(),
|
|
z
|
|
.object({
|
|
type: z.literal("http"),
|
|
url: z.string(),
|
|
headers: z.record(z.string(), z.string()).optional(),
|
|
alwaysLoad: z.boolean().optional(),
|
|
})
|
|
.strict(),
|
|
z
|
|
.object({
|
|
type: z.literal("sse"),
|
|
url: z.string(),
|
|
headers: z.record(z.string(), z.string()).optional(),
|
|
alwaysLoad: z.boolean().optional(),
|
|
})
|
|
.strict(),
|
|
]);
|
|
const toolPolicySchema = z
|
|
.object({
|
|
preapproved: z.array(
|
|
z.object({ kind: z.literal("mcp"), server: idSchema, tool: idSchema }).strict(),
|
|
),
|
|
})
|
|
.strict();
|
|
const providerPermissionResponseSchema: z.ZodType<ProviderPermissionResponse> =
|
|
z.discriminatedUnion("behavior", [
|
|
z
|
|
.object({
|
|
behavior: z.literal("allow"),
|
|
selectedActionId: z.string().optional(),
|
|
updatedInput: jsonObjectSchema.optional(),
|
|
updatedPermissions: z.array(jsonObjectSchema).optional(),
|
|
})
|
|
.strip(),
|
|
z
|
|
.object({
|
|
behavior: z.literal("deny"),
|
|
selectedActionId: z.string().optional(),
|
|
message: z.string().optional(),
|
|
interrupt: z.boolean().optional(),
|
|
})
|
|
.strip(),
|
|
]);
|
|
const sessionConfigSchema = z
|
|
.object({
|
|
cwd: z.string(),
|
|
env: z.record(z.string(), z.string()),
|
|
systemPrompt: z.string().optional(),
|
|
mcpServers: z.record(z.string(), mcpServerSchema),
|
|
toolPolicy: toolPolicySchema.optional(),
|
|
model: z.string().optional(),
|
|
mode: z.string().optional(),
|
|
thinkingOption: z.string().optional(),
|
|
settings: jsonObjectSchema,
|
|
providerOptions: z.record(z.string(), z.unknown()).optional(),
|
|
title: z.string().optional(),
|
|
persist: z.boolean(),
|
|
})
|
|
.strict();
|
|
const externalResourceSchema = z
|
|
.object({
|
|
provider: z.string(),
|
|
providerLabel: z.string(),
|
|
resourceType: z.string(),
|
|
id: z.string(),
|
|
identifier: z.string(),
|
|
title: z.string(),
|
|
url: z.string(),
|
|
})
|
|
.strip();
|
|
const reviewContextLineSchema = z
|
|
.object({
|
|
oldLineNumber: z.number().int().positive().nullable(),
|
|
newLineNumber: z.number().int().positive().nullable(),
|
|
type: z.enum(["add", "remove", "context"]),
|
|
content: z.string(),
|
|
})
|
|
.strip();
|
|
const providerContentSchema: z.ZodType<ProviderContent> = z.union([
|
|
z.object({ type: z.literal("text"), text: z.string() }).strict(),
|
|
z.object({ type: z.literal("image"), data: z.string(), mimeType: z.string() }).strict(),
|
|
z
|
|
.object({
|
|
type: z.literal("forge_change_request"),
|
|
mimeType: z.literal("application/paseo-forge-change-request"),
|
|
forge: z.string().optional(),
|
|
number: z.number().int().positive(),
|
|
title: z.string(),
|
|
url: z.string(),
|
|
body: z.string().nullable().optional(),
|
|
projectPath: z.string().optional(),
|
|
baseRefName: z.string().nullable().optional(),
|
|
headRefName: z.string().nullable().optional(),
|
|
})
|
|
.strip(),
|
|
z
|
|
.object({
|
|
type: z.literal("forge_issue"),
|
|
mimeType: z.literal("application/paseo-forge-issue"),
|
|
forge: z.string().optional(),
|
|
number: z.number().int().positive(),
|
|
title: z.string(),
|
|
url: z.string(),
|
|
body: z.string().nullable().optional(),
|
|
projectPath: z.string().optional(),
|
|
})
|
|
.strip(),
|
|
z
|
|
.object({
|
|
type: z.literal("github_pr"),
|
|
mimeType: z.literal("application/github-pr"),
|
|
number: z.number().int().positive(),
|
|
title: z.string(),
|
|
url: z.string(),
|
|
body: z.string().nullable().optional(),
|
|
baseRefName: z.string().nullable().optional(),
|
|
headRefName: z.string().nullable().optional(),
|
|
})
|
|
.strip(),
|
|
z
|
|
.object({
|
|
type: z.literal("github_issue"),
|
|
mimeType: z.literal("application/github-issue"),
|
|
number: z.number().int().positive(),
|
|
title: z.string(),
|
|
url: z.string(),
|
|
body: z.string().nullable().optional(),
|
|
})
|
|
.strip(),
|
|
z
|
|
.object({
|
|
type: z.literal("text"),
|
|
mimeType: z.literal("text/plain"),
|
|
contextKind: z.string().optional(),
|
|
title: z.string().nullable().optional(),
|
|
text: z.string(),
|
|
externalResource: externalResourceSchema.optional(),
|
|
})
|
|
.strip(),
|
|
z
|
|
.object({
|
|
type: z.literal("review"),
|
|
mimeType: z.literal("application/paseo-review"),
|
|
cwd: z.string(),
|
|
mode: z.enum(["uncommitted", "base"]),
|
|
baseRef: z.string().nullable().optional(),
|
|
comments: z.array(
|
|
z
|
|
.object({
|
|
filePath: z.string(),
|
|
side: z.enum(["old", "new"]),
|
|
lineNumber: z.number().int().positive(),
|
|
body: z.string(),
|
|
context: z
|
|
.object({
|
|
hunkHeader: z.string(),
|
|
targetLine: reviewContextLineSchema,
|
|
lines: z.array(reviewContextLineSchema),
|
|
})
|
|
.strip(),
|
|
})
|
|
.strip(),
|
|
),
|
|
})
|
|
.strip(),
|
|
z
|
|
.object({
|
|
type: z.literal("uploaded_file"),
|
|
id: z.string(),
|
|
fileName: z.string(),
|
|
mimeType: z.string(),
|
|
size: z.number().int().nonnegative(),
|
|
path: z.string(),
|
|
})
|
|
.strip(),
|
|
]);
|
|
const promptSchema = z
|
|
.object({
|
|
clientMessageId: idSchema,
|
|
delivery: z.enum(["auto", "steer"]),
|
|
input: z.union([
|
|
z.object({ type: z.literal("message"), content: z.array(providerContentSchema) }).strict(),
|
|
z.object({ type: z.literal("command"), name: idSchema, arguments: z.string() }).strict(),
|
|
]),
|
|
outputSchema: z.json().optional(),
|
|
clearPendingPermissions: z.boolean().optional(),
|
|
})
|
|
.strict();
|
|
const configChangesSchema = z
|
|
.object({
|
|
model: z.string().nullable().optional(),
|
|
mode: z.string().nullable().optional(),
|
|
thinkingOption: z.string().nullable().optional(),
|
|
settings: jsonObjectSchema.optional(),
|
|
})
|
|
.strict();
|
|
|
|
export const ProviderInputSchema: z.ZodType<ProviderInput> = z.discriminatedUnion("type", [
|
|
z
|
|
.object({ type: z.literal("catalog"), requestId: idSchema, cwd: z.string().optional() })
|
|
.strict(),
|
|
z
|
|
.object({
|
|
type: z.literal("sessions"),
|
|
requestId: idSchema,
|
|
query: z.string().optional(),
|
|
cwd: z.string().optional(),
|
|
limit: z.number().int().positive().optional(),
|
|
})
|
|
.strict(),
|
|
z
|
|
.object({
|
|
type: z.literal("session.open"),
|
|
requestId: idSchema,
|
|
sessionId: idSchema,
|
|
config: sessionConfigSchema,
|
|
persistence: persistenceSchema.optional(),
|
|
history: z.enum(["replay", "skip"]),
|
|
})
|
|
.strict(),
|
|
z
|
|
.object({ type: z.literal("session.prompt"), sessionId: idSchema, prompt: promptSchema })
|
|
.strict(),
|
|
z
|
|
.object({ type: z.literal("session.interrupt"), requestId: idSchema, sessionId: idSchema })
|
|
.strict(),
|
|
z
|
|
.object({
|
|
type: z.literal("session.permission"),
|
|
sessionId: idSchema,
|
|
permissionId: idSchema,
|
|
response: providerPermissionResponseSchema,
|
|
})
|
|
.strict(),
|
|
z
|
|
.object({
|
|
type: z.literal("session.configure"),
|
|
requestId: idSchema,
|
|
sessionId: idSchema,
|
|
changes: configChangesSchema,
|
|
})
|
|
.strict(),
|
|
z
|
|
.object({
|
|
type: z.literal("session.revert"),
|
|
requestId: idSchema,
|
|
sessionId: idSchema,
|
|
token: z.json(),
|
|
scope: z.enum(["conversation", "files", "both"]),
|
|
})
|
|
.strict(),
|
|
z
|
|
.object({
|
|
type: z.literal("session.archive"),
|
|
requestId: idSchema,
|
|
persistence: persistenceSchema,
|
|
})
|
|
.strict(),
|
|
z
|
|
.object({
|
|
type: z.literal("session.unarchive"),
|
|
requestId: idSchema,
|
|
persistence: persistenceSchema,
|
|
})
|
|
.strict(),
|
|
z.object({ type: z.literal("session.close"), requestId: idSchema, sessionId: idSchema }).strict(),
|
|
]);
|
|
|
|
const modeSchema = z
|
|
.object({
|
|
id: idSchema,
|
|
label: z.string(),
|
|
description: z.string().optional(),
|
|
icon: z.string().optional(),
|
|
colorTier: z.string().optional(),
|
|
isUnattended: z.boolean().optional(),
|
|
})
|
|
.strip();
|
|
const selectOptionSchema = z
|
|
.object({
|
|
id: idSchema,
|
|
label: z.string(),
|
|
description: z.string().optional(),
|
|
isDefault: z.boolean().optional(),
|
|
metadata: jsonObjectSchema.optional(),
|
|
})
|
|
.strip();
|
|
const modelSchema = z
|
|
.object({
|
|
id: idSchema,
|
|
aliases: z.array(z.string()).optional(),
|
|
isSelectable: z.boolean().optional(),
|
|
label: z.string(),
|
|
description: z.string().optional(),
|
|
isDefault: z.boolean().optional(),
|
|
metadata: jsonObjectSchema.optional(),
|
|
contextWindowMaxTokens: z.number().optional(),
|
|
thinkingOptions: z.array(selectOptionSchema).optional(),
|
|
defaultThinkingOptionId: z.string().optional(),
|
|
})
|
|
.strip();
|
|
const settingSchema = z.discriminatedUnion("type", [
|
|
z
|
|
.object({
|
|
type: z.literal("toggle"),
|
|
id: idSchema,
|
|
label: z.string(),
|
|
description: z.string().optional(),
|
|
value: z.boolean(),
|
|
})
|
|
.strip(),
|
|
z
|
|
.object({
|
|
type: z.literal("select"),
|
|
id: idSchema,
|
|
label: z.string(),
|
|
description: z.string().optional(),
|
|
value: z.string().nullable(),
|
|
options: z.array(z.object({ label: z.string(), value: z.string() }).strip()),
|
|
})
|
|
.strip(),
|
|
]);
|
|
const configStateSchema = z
|
|
.object({
|
|
model: z.string().optional(),
|
|
mode: z.string().optional(),
|
|
thinkingOption: z.string().optional(),
|
|
models: z.array(modelSchema),
|
|
modes: z.array(modeSchema),
|
|
thinkingOptions: z.array(selectOptionSchema),
|
|
settings: z.array(settingSchema),
|
|
})
|
|
.strip();
|
|
const catalogSchema = z
|
|
.object({
|
|
models: z.array(modelSchema),
|
|
modes: z.array(modeSchema),
|
|
thinkingOptions: z.array(selectOptionSchema).optional(),
|
|
defaultModel: z.string().optional(),
|
|
defaultMode: z.string().optional(),
|
|
defaultThinkingOption: z.string().optional(),
|
|
})
|
|
.strip();
|
|
const noticeSchema = z
|
|
.object({
|
|
id: idSchema,
|
|
severity: z.enum(["info", "warning", "error"]),
|
|
title: z.string(),
|
|
description: z.string().optional(),
|
|
dismissed: z.boolean().optional(),
|
|
})
|
|
.strip();
|
|
const commandSchema = z
|
|
.object({ name: idSchema, description: z.string(), argumentHint: z.string().optional() })
|
|
.strip();
|
|
const usageSchema = z
|
|
.object({
|
|
inputTokens: z.number().optional(),
|
|
cachedInputTokens: z.number().optional(),
|
|
outputTokens: z.number().optional(),
|
|
totalCostUsd: z.number().optional(),
|
|
contextWindowMaxTokens: z.number().optional(),
|
|
contextWindowUsedTokens: z.number().optional(),
|
|
})
|
|
.strip();
|
|
const worktreeCommandSchema = z
|
|
.object({
|
|
index: z.number().int().positive(),
|
|
command: z.string(),
|
|
cwd: z.string(),
|
|
log: z.string(),
|
|
status: z.enum(["running", "completed", "failed"]),
|
|
exitCode: z.number().nullable(),
|
|
durationMs: z.number().nonnegative().optional(),
|
|
})
|
|
.strip();
|
|
const toolCallDetailSchema: z.ZodType<ProviderToolCallDetail> = z.discriminatedUnion("type", [
|
|
z
|
|
.object({
|
|
type: z.literal("shell"),
|
|
command: z.string(),
|
|
cwd: z.string().optional(),
|
|
output: z.string().optional(),
|
|
exitCode: z.number().nullable().optional(),
|
|
})
|
|
.strip(),
|
|
z
|
|
.object({
|
|
type: z.literal("read"),
|
|
filePath: z.string(),
|
|
content: z.string().optional(),
|
|
offset: z.number().optional(),
|
|
limit: z.number().optional(),
|
|
})
|
|
.strip(),
|
|
z
|
|
.object({
|
|
type: z.literal("edit"),
|
|
filePath: z.string(),
|
|
oldString: z.string().optional(),
|
|
newString: z.string().optional(),
|
|
unifiedDiff: z.string().optional(),
|
|
})
|
|
.strip(),
|
|
z
|
|
.object({ type: z.literal("write"), filePath: z.string(), content: z.string().optional() })
|
|
.strip(),
|
|
z
|
|
.object({
|
|
type: z.literal("search"),
|
|
query: z.string(),
|
|
toolName: z.enum(["search", "grep", "glob", "web_search"]).optional(),
|
|
content: z.string().optional(),
|
|
filePaths: z.array(z.string()).optional(),
|
|
webResults: z.array(z.object({ title: z.string(), url: z.string() }).strip()).optional(),
|
|
annotations: z.array(z.string()).optional(),
|
|
numFiles: z.number().optional(),
|
|
numMatches: z.number().optional(),
|
|
durationMs: z.number().optional(),
|
|
durationSeconds: z.number().optional(),
|
|
truncated: z.boolean().optional(),
|
|
mode: z.enum(["content", "files_with_matches", "count"]).optional(),
|
|
})
|
|
.strip(),
|
|
z
|
|
.object({
|
|
type: z.literal("fetch"),
|
|
url: z.string(),
|
|
prompt: z.string().optional(),
|
|
result: z.string().optional(),
|
|
code: z.number().optional(),
|
|
codeText: z.string().optional(),
|
|
bytes: z.number().optional(),
|
|
durationMs: z.number().optional(),
|
|
})
|
|
.strip(),
|
|
z
|
|
.object({
|
|
type: z.literal("worktree_setup"),
|
|
worktreePath: z.string(),
|
|
branchName: z.string(),
|
|
log: z.string(),
|
|
commands: z.array(worktreeCommandSchema),
|
|
truncated: z.boolean().optional(),
|
|
})
|
|
.strip(),
|
|
z
|
|
.object({
|
|
type: z.literal("sub_agent"),
|
|
subAgentType: z.string().optional(),
|
|
description: z.string().optional(),
|
|
childSessionId: z.string().optional(),
|
|
log: z.string(),
|
|
actions: z
|
|
.array(
|
|
z
|
|
.object({
|
|
index: z.number().int().positive(),
|
|
toolName: z.string(),
|
|
summary: z.string().optional(),
|
|
})
|
|
.strip(),
|
|
)
|
|
.optional(),
|
|
})
|
|
.strip(),
|
|
z
|
|
.object({
|
|
type: z.literal("plain_text"),
|
|
label: z.string().optional(),
|
|
text: z.string().optional(),
|
|
icon: z
|
|
.enum([
|
|
"wrench",
|
|
"square_terminal",
|
|
"eye",
|
|
"pencil",
|
|
"search",
|
|
"bot",
|
|
"sparkles",
|
|
"brain",
|
|
"mic_vocal",
|
|
])
|
|
.optional(),
|
|
})
|
|
.strip(),
|
|
z.object({ type: z.literal("plan"), text: z.string() }).strip(),
|
|
z.object({ type: z.literal("unknown"), input: z.json(), output: z.json() }).strip(),
|
|
]);
|
|
const timelineIdentityShape = { id: idSchema, revertToken: z.json().optional() };
|
|
const toolCallBaseShape = {
|
|
...timelineIdentityShape,
|
|
type: z.literal("tool_call"),
|
|
callId: idSchema,
|
|
name: z.string(),
|
|
detail: toolCallDetailSchema,
|
|
metadata: jsonObjectSchema.optional(),
|
|
};
|
|
const timelineItemSchema: z.ZodType<ProviderTimelineItem> = z.union([
|
|
z
|
|
.object({
|
|
...timelineIdentityShape,
|
|
type: z.literal("user_message"),
|
|
text: z.string(),
|
|
messageId: z.string().optional(),
|
|
clientMessageId: z.string().optional(),
|
|
})
|
|
.strip(),
|
|
z
|
|
.object({
|
|
...timelineIdentityShape,
|
|
type: z.literal("assistant_message"),
|
|
text: z.string(),
|
|
messageId: z.string().optional(),
|
|
})
|
|
.strip(),
|
|
z.object({ ...timelineIdentityShape, type: z.literal("reasoning"), text: z.string() }).strip(),
|
|
z.object({ ...toolCallBaseShape, status: z.literal("running"), error: z.null() }).strip(),
|
|
z.object({ ...toolCallBaseShape, status: z.literal("completed"), error: z.null() }).strip(),
|
|
z.object({ ...toolCallBaseShape, status: z.literal("failed"), error: z.json() }).strip(),
|
|
z.object({ ...toolCallBaseShape, status: z.literal("canceled"), error: z.null() }).strip(),
|
|
z
|
|
.object({
|
|
...timelineIdentityShape,
|
|
type: z.literal("todo"),
|
|
items: z.array(
|
|
z
|
|
.object({
|
|
text: z.string(),
|
|
completed: z.boolean(),
|
|
id: z.string().optional(),
|
|
status: z.enum(["pending", "in_progress", "completed"]).optional(),
|
|
activeForm: z.string().optional(),
|
|
})
|
|
.strip(),
|
|
),
|
|
})
|
|
.strip(),
|
|
z.object({ ...timelineIdentityShape, type: z.literal("error"), message: z.string() }).strip(),
|
|
z
|
|
.object({
|
|
...timelineIdentityShape,
|
|
type: z.literal("notification"),
|
|
level: z.enum(["info", "warning", "error"]),
|
|
message: z.string(),
|
|
})
|
|
.strip(),
|
|
z
|
|
.object({
|
|
...timelineIdentityShape,
|
|
type: z.literal("compaction"),
|
|
status: z.enum(["loading", "completed"]),
|
|
trigger: z.enum(["auto", "manual"]).optional(),
|
|
preTokens: z.number().optional(),
|
|
})
|
|
.strip(),
|
|
z
|
|
.object({
|
|
...timelineIdentityShape,
|
|
type: z.literal("plugin"),
|
|
pluginId: idSchema,
|
|
kind: z.string(),
|
|
version: z.number(),
|
|
data: z.json(),
|
|
})
|
|
.strip(),
|
|
]);
|
|
const permissionActionSchema = z
|
|
.object({
|
|
id: idSchema,
|
|
label: z.string(),
|
|
behavior: z.enum(["allow", "deny"]),
|
|
variant: z.enum(["primary", "secondary", "danger"]).optional(),
|
|
intent: z.enum(["implement", "implement_resume", "dismiss"]).optional(),
|
|
})
|
|
.strip();
|
|
const providerPermissionRequestSchema: z.ZodType<ProviderPermissionRequest> = z
|
|
.object({
|
|
id: idSchema,
|
|
name: z.string(),
|
|
kind: z.enum(["tool", "plan", "question", "mode", "other"]),
|
|
title: z.string().optional(),
|
|
description: z.string().optional(),
|
|
input: jsonObjectSchema.optional(),
|
|
detail: toolCallDetailSchema.optional(),
|
|
suggestions: z.array(jsonObjectSchema).optional(),
|
|
actions: z.array(permissionActionSchema).optional(),
|
|
metadata: jsonObjectSchema.optional(),
|
|
})
|
|
.strip();
|
|
|
|
export const ProviderEventSchema: z.ZodType<ProviderEvent> = z.discriminatedUnion("type", [
|
|
z.object({ type: z.literal("catalog"), requestId: idSchema, catalog: catalogSchema }).strip(),
|
|
z
|
|
.object({
|
|
type: z.literal("sessions"),
|
|
requestId: idSchema,
|
|
sessions: z.array(
|
|
z
|
|
.object({
|
|
persistence: persistenceSchema,
|
|
cwd: z.string(),
|
|
title: z.string().optional(),
|
|
description: z.string().optional(),
|
|
updatedAt: z.string().optional(),
|
|
})
|
|
.strip(),
|
|
),
|
|
})
|
|
.strip(),
|
|
z.object({ type: z.literal("request.completed"), requestId: idSchema }).strip(),
|
|
z
|
|
.object({ type: z.literal("request.failed"), requestId: idSchema, error: providerErrorSchema })
|
|
.strip(),
|
|
z
|
|
.object({
|
|
type: z.literal("session.opened"),
|
|
requestId: idSchema.optional(),
|
|
sessionId: idSchema,
|
|
parentSessionId: idSchema.optional(),
|
|
toolCallId: idSchema.optional(),
|
|
capabilities: z.array(z.string()),
|
|
restoration: z.enum(["core", "parent"]),
|
|
persistence: persistenceSchema.optional(),
|
|
title: z.string().optional(),
|
|
description: z.string().optional(),
|
|
cwd: z.string(),
|
|
})
|
|
.strip(),
|
|
z
|
|
.object({
|
|
type: z.literal("session.ready"),
|
|
requestId: idSchema.optional(),
|
|
sessionId: idSchema,
|
|
})
|
|
.strip(),
|
|
z
|
|
.object({
|
|
type: z.literal("session.closed"),
|
|
sessionId: idSchema,
|
|
error: providerErrorSchema.optional(),
|
|
})
|
|
.strip(),
|
|
z
|
|
.object({
|
|
type: z.literal("session.runtime_failed"),
|
|
sessionId: idSchema,
|
|
error: providerErrorSchema,
|
|
})
|
|
.strip(),
|
|
z
|
|
.object({
|
|
type: z.literal("session.persistence"),
|
|
sessionId: idSchema,
|
|
persistence: persistenceSchema,
|
|
})
|
|
.strip(),
|
|
z
|
|
.object({
|
|
type: z.literal("session.prompt_result"),
|
|
sessionId: idSchema,
|
|
clientMessageId: idSchema,
|
|
result: z.union([
|
|
z.object({ type: z.literal("turn"), turnId: idSchema }).strip(),
|
|
z.object({ type: z.literal("steer"), turnId: idSchema }).strip(),
|
|
z.object({ type: z.literal("completed") }).strip(),
|
|
z.object({ type: z.literal("failed"), error: providerErrorSchema }).strip(),
|
|
]),
|
|
})
|
|
.strip(),
|
|
z
|
|
.object({
|
|
type: z.literal("session.turn"),
|
|
sessionId: idSchema,
|
|
turnId: idSchema,
|
|
state: z.enum(["started", "completed", "failed", "canceled"]),
|
|
error: providerErrorSchema.optional(),
|
|
})
|
|
.strip(),
|
|
z
|
|
.object({
|
|
type: z.literal("session.usage"),
|
|
sessionId: idSchema,
|
|
turnId: idSchema.optional(),
|
|
usage: usageSchema,
|
|
})
|
|
.strip(),
|
|
z
|
|
.object({ type: z.literal("session.config"), sessionId: idSchema, config: configStateSchema })
|
|
.strip(),
|
|
z
|
|
.object({
|
|
type: z.literal("session.commands"),
|
|
sessionId: idSchema,
|
|
commands: z.array(commandSchema),
|
|
})
|
|
.strip(),
|
|
z
|
|
.object({
|
|
type: z.literal("session.permission"),
|
|
sessionId: idSchema,
|
|
request: providerPermissionRequestSchema,
|
|
})
|
|
.strip(),
|
|
z
|
|
.object({
|
|
type: z.literal("session.permission_resolved"),
|
|
sessionId: idSchema,
|
|
permissionId: idSchema,
|
|
})
|
|
.strip(),
|
|
z
|
|
.object({ type: z.literal("session.notice"), sessionId: idSchema, notice: noticeSchema })
|
|
.strip(),
|
|
z
|
|
.object({
|
|
type: z.literal("timeline.item"),
|
|
sessionId: idSchema,
|
|
item: timelineItemSchema,
|
|
timestamp: z.string().optional(),
|
|
})
|
|
.strip(),
|
|
]);
|