Migrate monorepo to Zod 4
This commit is contained in:
Generated
+2283
-2984
File diff suppressed because it is too large
Load Diff
@@ -109,7 +109,7 @@
|
|||||||
"react-native-worklets": "~0.8.3",
|
"react-native-worklets": "~0.8.3",
|
||||||
"tiny-invariant": "^1.3.3",
|
"tiny-invariant": "^1.3.3",
|
||||||
"use-sync-external-store": "^1.6.0",
|
"use-sync-external-store": "^1.6.0",
|
||||||
"zod": "^3.23.8",
|
"zod": "^4.4.3",
|
||||||
"zustand": "^5.0.9"
|
"zustand": "^5.0.9"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -18,13 +18,13 @@ export interface FavoriteModelRow {
|
|||||||
const providerPreferencesSchema = z.object({
|
const providerPreferencesSchema = z.object({
|
||||||
model: z.string().optional(),
|
model: z.string().optional(),
|
||||||
mode: z.string().optional(),
|
mode: z.string().optional(),
|
||||||
thinkingByModel: z.record(z.string()).optional(),
|
thinkingByModel: z.record(z.string(), z.string()).optional(),
|
||||||
featureValues: z.record(z.unknown()).optional(),
|
featureValues: z.record(z.string(), z.unknown()).optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const formPreferencesSchema = z.object({
|
const formPreferencesSchema = z.object({
|
||||||
provider: z.string().optional(),
|
provider: z.string().optional(),
|
||||||
providerPreferences: z.record(providerPreferencesSchema).optional(),
|
providerPreferences: z.record(z.string(), providerPreferencesSchema).optional(),
|
||||||
favoriteModels: z
|
favoriteModels: z
|
||||||
.array(
|
.array(
|
||||||
z.object({
|
z.object({
|
||||||
|
|||||||
@@ -37,7 +37,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@getpaseo/protocol": "0.1.97-beta.3",
|
"@getpaseo/protocol": "0.1.97-beta.3",
|
||||||
"@getpaseo/relay": "0.1.97-beta.3",
|
"@getpaseo/relay": "0.1.97-beta.3",
|
||||||
"zod": "^3.23.8"
|
"zod": "^4.4.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^20.9.0",
|
"@types/node": "^20.9.0",
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ function parseSentFrame(
|
|||||||
return z
|
return z
|
||||||
.object({
|
.object({
|
||||||
type: z.literal("session"),
|
type: z.literal("session"),
|
||||||
message: z.record(z.unknown()),
|
message: z.record(z.string(), z.unknown()),
|
||||||
})
|
})
|
||||||
.parse(JSON.parse(assertStr(data))).message;
|
.parse(JSON.parse(assertStr(data))).message;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
"electron-log": "^5.4.3",
|
"electron-log": "^5.4.3",
|
||||||
"electron-updater": "^6.6.2",
|
"electron-updater": "^6.6.2",
|
||||||
"ws": "^8.14.2",
|
"ws": "^8.14.2",
|
||||||
"zod": "^3.23.8"
|
"zod": "^4.4.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "24.6.0",
|
"@types/node": "24.6.0",
|
||||||
|
|||||||
+2582
-1785
File diff suppressed because it is too large
Load Diff
@@ -31,8 +31,9 @@
|
|||||||
"open:android": "open -a \"Android Studio\" examples/basic-usage/android"
|
"open:android": "open -a \"Android Studio\" examples/basic-usage/android"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/jest": "^29.5.14",
|
||||||
"@types/react": "^18.0.25",
|
"@types/react": "^18.0.25",
|
||||||
"expo-module-scripts": "^3.5.2",
|
"expo-module-scripts": "^5.0.8",
|
||||||
"expo-modules-core": "^2.0.4"
|
"expo-modules-core": "^2.0.4"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
|
|||||||
@@ -4,7 +4,12 @@
|
|||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"outDir": "./build",
|
"outDir": "./build",
|
||||||
"module": "esnext",
|
"module": "esnext",
|
||||||
"moduleResolution": "bundler"
|
"moduleResolution": "bundler",
|
||||||
|
"typeRoots": [
|
||||||
|
"./node_modules/expo-module-scripts/ts-declarations",
|
||||||
|
"./node_modules/@types",
|
||||||
|
"../../node_modules/@types"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"include": ["./src"],
|
"include": ["./src"],
|
||||||
"exclude": ["**/__mocks__/*", "**/__tests__/*"]
|
"exclude": ["**/__mocks__/*", "**/__tests__/*"]
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
"test": "vitest run"
|
"test": "vitest run"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"zod": "^3.23.8"
|
"zod": "^4.4.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^20.9.0",
|
"@types/node": "^20.9.0",
|
||||||
|
|||||||
@@ -199,7 +199,7 @@ const AgentSelectOptionSchema = z.object({
|
|||||||
label: z.string(),
|
label: z.string(),
|
||||||
description: z.string().optional(),
|
description: z.string().optional(),
|
||||||
isDefault: z.boolean().optional(),
|
isDefault: z.boolean().optional(),
|
||||||
metadata: z.record(z.unknown()).optional(),
|
metadata: z.record(z.string(), z.unknown()).optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const AgentFeatureToggleSchema = z.object({
|
export const AgentFeatureToggleSchema = z.object({
|
||||||
@@ -235,7 +235,7 @@ const AgentModelDefinitionSchema: z.ZodType<AgentModelDefinition> = z
|
|||||||
label: z.string(),
|
label: z.string(),
|
||||||
description: z.string().optional(),
|
description: z.string().optional(),
|
||||||
isDefault: z.boolean().optional(),
|
isDefault: z.boolean().optional(),
|
||||||
metadata: z.record(z.unknown()).optional(),
|
metadata: z.record(z.string(), z.unknown()).optional(),
|
||||||
thinkingOptions: z.array(AgentSelectOptionSchema).optional(),
|
thinkingOptions: z.array(AgentSelectOptionSchema).optional(),
|
||||||
defaultThinkingOptionId: z.string().optional(),
|
defaultThinkingOptionId: z.string().optional(),
|
||||||
})
|
})
|
||||||
@@ -285,21 +285,21 @@ const McpStdioServerConfigSchema = z.object({
|
|||||||
type: z.literal("stdio"),
|
type: z.literal("stdio"),
|
||||||
command: z.string(),
|
command: z.string(),
|
||||||
args: z.array(z.string()).optional(),
|
args: z.array(z.string()).optional(),
|
||||||
env: z.record(z.string()).optional(),
|
env: z.record(z.string(), z.string()).optional(),
|
||||||
alwaysLoad: z.boolean().optional(),
|
alwaysLoad: z.boolean().optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const McpHttpServerConfigSchema = z.object({
|
const McpHttpServerConfigSchema = z.object({
|
||||||
type: z.literal("http"),
|
type: z.literal("http"),
|
||||||
url: z.string(),
|
url: z.string(),
|
||||||
headers: z.record(z.string()).optional(),
|
headers: z.record(z.string(), z.string()).optional(),
|
||||||
alwaysLoad: z.boolean().optional(),
|
alwaysLoad: z.boolean().optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const McpSseServerConfigSchema = z.object({
|
const McpSseServerConfigSchema = z.object({
|
||||||
type: z.literal("sse"),
|
type: z.literal("sse"),
|
||||||
url: z.string(),
|
url: z.string(),
|
||||||
headers: z.record(z.string()).optional(),
|
headers: z.record(z.string(), z.string()).optional(),
|
||||||
alwaysLoad: z.boolean().optional(),
|
alwaysLoad: z.boolean().optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -315,7 +315,7 @@ const AgentSessionConfigSchema = z.object({
|
|||||||
modeId: z.string().optional(),
|
modeId: z.string().optional(),
|
||||||
model: z.string().optional(),
|
model: z.string().optional(),
|
||||||
thinkingOptionId: z.string().optional(),
|
thinkingOptionId: z.string().optional(),
|
||||||
featureValues: z.record(z.unknown()).optional(),
|
featureValues: z.record(z.string(), z.unknown()).optional(),
|
||||||
title: z.string().trim().min(1).max(MAX_EXPLICIT_AGENT_TITLE_CHARS).optional().nullable(),
|
title: z.string().trim().min(1).max(MAX_EXPLICIT_AGENT_TITLE_CHARS).optional().nullable(),
|
||||||
approvalPolicy: z.string().optional(),
|
approvalPolicy: z.string().optional(),
|
||||||
sandboxMode: z.string().optional(),
|
sandboxMode: z.string().optional(),
|
||||||
@@ -323,16 +323,16 @@ const AgentSessionConfigSchema = z.object({
|
|||||||
webSearch: z.boolean().optional(),
|
webSearch: z.boolean().optional(),
|
||||||
extra: z
|
extra: z
|
||||||
.object({
|
.object({
|
||||||
codex: z.record(z.unknown()).optional(),
|
codex: z.record(z.string(), z.unknown()).optional(),
|
||||||
claude: z.record(z.unknown()).optional(),
|
claude: z.record(z.string(), z.unknown()).optional(),
|
||||||
})
|
})
|
||||||
.partial()
|
.partial()
|
||||||
.optional(),
|
.optional(),
|
||||||
systemPrompt: z.string().optional(),
|
systemPrompt: z.string().optional(),
|
||||||
mcpServers: z.record(McpServerConfigSchema).optional(),
|
mcpServers: z.record(z.string(), McpServerConfigSchema).optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const AgentPermissionUpdateSchema = z.record(z.unknown());
|
const AgentPermissionUpdateSchema = z.record(z.string(), z.unknown());
|
||||||
const AgentPermissionActionSchema = z.object({
|
const AgentPermissionActionSchema = z.object({
|
||||||
id: z.string(),
|
id: z.string(),
|
||||||
label: z.string(),
|
label: z.string(),
|
||||||
@@ -345,7 +345,7 @@ export const AgentPermissionResponseSchema: z.ZodType<AgentPermissionResponse> =
|
|||||||
z.object({
|
z.object({
|
||||||
behavior: z.literal("allow"),
|
behavior: z.literal("allow"),
|
||||||
selectedActionId: z.string().optional(),
|
selectedActionId: z.string().optional(),
|
||||||
updatedInput: z.record(z.unknown()).optional(),
|
updatedInput: z.record(z.string(), z.unknown()).optional(),
|
||||||
updatedPermissions: z.array(AgentPermissionUpdateSchema).optional(),
|
updatedPermissions: z.array(AgentPermissionUpdateSchema).optional(),
|
||||||
}),
|
}),
|
||||||
z.object({
|
z.object({
|
||||||
@@ -356,23 +356,20 @@ export const AgentPermissionResponseSchema: z.ZodType<AgentPermissionResponse> =
|
|||||||
}),
|
}),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
export const AgentPermissionRequestPayloadSchema: z.ZodType<
|
export const AgentPermissionRequestPayloadSchema: z.ZodType<AgentPermissionRequest, unknown> =
|
||||||
AgentPermissionRequest,
|
z.object({
|
||||||
z.ZodTypeDef,
|
id: z.string(),
|
||||||
unknown
|
provider: AgentProviderSchema,
|
||||||
> = z.object({
|
name: z.string(),
|
||||||
id: z.string(),
|
kind: z.enum(["tool", "plan", "question", "mode", "other"]),
|
||||||
provider: AgentProviderSchema,
|
title: z.string().optional(),
|
||||||
name: z.string(),
|
description: z.string().optional(),
|
||||||
kind: z.enum(["tool", "plan", "question", "mode", "other"]),
|
input: z.record(z.string(), z.unknown()).optional(),
|
||||||
title: z.string().optional(),
|
detail: z.lazy(() => ToolCallDetailPayloadSchema).optional(),
|
||||||
description: z.string().optional(),
|
suggestions: z.array(AgentPermissionUpdateSchema).optional(),
|
||||||
input: z.record(z.unknown()).optional(),
|
actions: z.array(AgentPermissionActionSchema).optional(),
|
||||||
detail: z.lazy(() => ToolCallDetailPayloadSchema).optional(),
|
metadata: z.record(z.string(), z.unknown()).optional(),
|
||||||
suggestions: z.array(AgentPermissionUpdateSchema).optional(),
|
});
|
||||||
actions: z.array(AgentPermissionActionSchema).optional(),
|
|
||||||
metadata: z.record(z.unknown()).optional(),
|
|
||||||
});
|
|
||||||
|
|
||||||
const UnknownValueSchema = z.union([
|
const UnknownValueSchema = z.union([
|
||||||
z.null(),
|
z.null(),
|
||||||
@@ -410,8 +407,9 @@ const WorktreeSetupDetailPayloadSchema = z.object({
|
|||||||
truncated: z.boolean().optional(),
|
truncated: z.boolean().optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const ToolCallDetailPayloadSchema: z.ZodType<ToolCallDetail, z.ZodTypeDef, unknown> =
|
const ToolCallDetailPayloadSchema: z.ZodType<ToolCallDetail, unknown> = z.discriminatedUnion(
|
||||||
z.discriminatedUnion("type", [
|
"type",
|
||||||
|
[
|
||||||
WorktreeSetupDetailPayloadSchema,
|
WorktreeSetupDetailPayloadSchema,
|
||||||
z.object({
|
z.object({
|
||||||
type: z.literal("shell"),
|
type: z.literal("shell"),
|
||||||
@@ -505,7 +503,8 @@ const ToolCallDetailPayloadSchema: z.ZodType<ToolCallDetail, z.ZodTypeDef, unkno
|
|||||||
input: UnknownValueSchema,
|
input: UnknownValueSchema,
|
||||||
output: UnknownValueSchema,
|
output: UnknownValueSchema,
|
||||||
}),
|
}),
|
||||||
]);
|
],
|
||||||
|
);
|
||||||
|
|
||||||
const ToolCallBasePayloadSchema = z.object({
|
const ToolCallBasePayloadSchema = z.object({
|
||||||
type: z.literal("tool_call"),
|
type: z.literal("tool_call"),
|
||||||
@@ -535,51 +534,49 @@ const ToolCallCanceledPayloadSchema = ToolCallBasePayloadSchema.extend({
|
|||||||
error: z.null(),
|
error: z.null(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const ToolCallTimelineItemPayloadSchema: z.ZodType<ToolCallTimelineItem, z.ZodTypeDef, unknown> =
|
const ToolCallTimelineItemPayloadSchema: z.ZodType<ToolCallTimelineItem, unknown> = z.union([
|
||||||
z.union([
|
ToolCallRunningPayloadSchema,
|
||||||
ToolCallRunningPayloadSchema,
|
ToolCallCompletedPayloadSchema,
|
||||||
ToolCallCompletedPayloadSchema,
|
ToolCallFailedPayloadSchema,
|
||||||
ToolCallFailedPayloadSchema,
|
ToolCallCanceledPayloadSchema,
|
||||||
ToolCallCanceledPayloadSchema,
|
]);
|
||||||
]);
|
|
||||||
|
|
||||||
export const AgentTimelineItemPayloadSchema: z.ZodType<AgentTimelineItem, z.ZodTypeDef, unknown> =
|
export const AgentTimelineItemPayloadSchema: z.ZodType<AgentTimelineItem, unknown> = z.union([
|
||||||
z.union([
|
z.object({
|
||||||
z.object({
|
type: z.literal("user_message"),
|
||||||
type: z.literal("user_message"),
|
text: z.string(),
|
||||||
text: z.string(),
|
messageId: z.string().optional(),
|
||||||
messageId: z.string().optional(),
|
}),
|
||||||
}),
|
z.object({
|
||||||
z.object({
|
type: z.literal("assistant_message"),
|
||||||
type: z.literal("assistant_message"),
|
text: z.string(),
|
||||||
text: z.string(),
|
messageId: z.string().optional(),
|
||||||
messageId: z.string().optional(),
|
}),
|
||||||
}),
|
z.object({
|
||||||
z.object({
|
type: z.literal("reasoning"),
|
||||||
type: z.literal("reasoning"),
|
text: z.string(),
|
||||||
text: z.string(),
|
}),
|
||||||
}),
|
ToolCallTimelineItemPayloadSchema,
|
||||||
ToolCallTimelineItemPayloadSchema,
|
z.object({
|
||||||
z.object({
|
type: z.literal("todo"),
|
||||||
type: z.literal("todo"),
|
items: z.array(
|
||||||
items: z.array(
|
z.object({
|
||||||
z.object({
|
text: z.string(),
|
||||||
text: z.string(),
|
completed: z.boolean(),
|
||||||
completed: z.boolean(),
|
}),
|
||||||
}),
|
),
|
||||||
),
|
}),
|
||||||
}),
|
z.object({
|
||||||
z.object({
|
type: z.literal("error"),
|
||||||
type: z.literal("error"),
|
message: z.string(),
|
||||||
message: z.string(),
|
}),
|
||||||
}),
|
z.object({
|
||||||
z.object({
|
type: z.literal("compaction"),
|
||||||
type: z.literal("compaction"),
|
status: z.enum(["loading", "completed"]),
|
||||||
status: z.enum(["loading", "completed"]),
|
trigger: z.enum(["auto", "manual"]).optional(),
|
||||||
trigger: z.enum(["auto", "manual"]).optional(),
|
preTokens: z.number().optional(),
|
||||||
preTokens: z.number().optional(),
|
}),
|
||||||
}),
|
]);
|
||||||
]);
|
|
||||||
|
|
||||||
export const AgentStreamEventPayloadSchema = z.discriminatedUnion("type", [
|
export const AgentStreamEventPayloadSchema = z.discriminatedUnion("type", [
|
||||||
z.object({
|
z.object({
|
||||||
@@ -755,7 +752,7 @@ export const AudioPlayedMessageSchema = z.object({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const AgentDirectoryFilterSchema = z.object({
|
const AgentDirectoryFilterSchema = z.object({
|
||||||
labels: z.record(z.string()).optional(),
|
labels: z.record(z.string(), z.string()).optional(),
|
||||||
projectKeys: z.array(z.string()).optional(),
|
projectKeys: z.array(z.string()).optional(),
|
||||||
statuses: z.array(AgentStatusSchema).optional(),
|
statuses: z.array(AgentStatusSchema).optional(),
|
||||||
includeArchived: z.boolean().optional(),
|
includeArchived: z.boolean().optional(),
|
||||||
@@ -786,7 +783,7 @@ export const UpdateAgentRequestMessageSchema = z.object({
|
|||||||
type: z.literal("update_agent_request"),
|
type: z.literal("update_agent_request"),
|
||||||
agentId: z.string(),
|
agentId: z.string(),
|
||||||
name: z.string().optional(),
|
name: z.string().optional(),
|
||||||
labels: z.record(z.string()).optional(),
|
labels: z.record(z.string(), z.string()).optional(),
|
||||||
requestId: z.string(),
|
requestId: z.string(),
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1138,18 +1135,18 @@ export type CreateAgentWorktreeTarget = z.infer<typeof CreateAgentWorktreeTarget
|
|||||||
export const CreateAgentRequestMessageSchema = z.object({
|
export const CreateAgentRequestMessageSchema = z.object({
|
||||||
type: z.literal("create_agent_request"),
|
type: z.literal("create_agent_request"),
|
||||||
config: AgentSessionConfigSchema,
|
config: AgentSessionConfigSchema,
|
||||||
env: z.record(z.string()).optional(),
|
env: z.record(z.string(), z.string()).optional(),
|
||||||
workspaceId: z.string().optional(),
|
workspaceId: z.string().optional(),
|
||||||
worktreeName: z.string().optional(),
|
worktreeName: z.string().optional(),
|
||||||
initialPrompt: z.string().optional(),
|
initialPrompt: z.string().optional(),
|
||||||
clientMessageId: z.string().optional(),
|
clientMessageId: z.string().optional(),
|
||||||
outputSchema: z.record(z.unknown()).optional(),
|
outputSchema: z.record(z.string(), z.unknown()).optional(),
|
||||||
images: z.array(ImageAttachmentSchema).optional(),
|
images: z.array(ImageAttachmentSchema).optional(),
|
||||||
attachments: AgentAttachmentsSchema,
|
attachments: AgentAttachmentsSchema,
|
||||||
git: GitSetupOptionsSchema.optional(),
|
git: GitSetupOptionsSchema.optional(),
|
||||||
worktree: CreateAgentWorktreeTargetSchema.optional(),
|
worktree: CreateAgentWorktreeTargetSchema.optional(),
|
||||||
autoArchive: z.boolean().optional(),
|
autoArchive: z.boolean().optional(),
|
||||||
labels: z.record(z.string()).default({}),
|
labels: z.record(z.string(), z.string()).default({}),
|
||||||
requestId: z.string(),
|
requestId: z.string(),
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1205,7 +1202,7 @@ export const ImportAgentRequestMessageSchema = z.object({
|
|||||||
sessionId: z.string().optional(),
|
sessionId: z.string().optional(),
|
||||||
providerHandleId: z.string().optional(),
|
providerHandleId: z.string().optional(),
|
||||||
cwd: z.string().optional(),
|
cwd: z.string().optional(),
|
||||||
labels: z.record(z.string()).optional(),
|
labels: z.record(z.string(), z.string()).optional(),
|
||||||
requestId: z.string(),
|
requestId: z.string(),
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1832,7 +1829,7 @@ const ListCommandsDraftConfigSchema = z.object({
|
|||||||
modeId: z.string().optional(),
|
modeId: z.string().optional(),
|
||||||
model: z.string().optional(),
|
model: z.string().optional(),
|
||||||
thinkingOptionId: z.string().optional(),
|
thinkingOptionId: z.string().optional(),
|
||||||
featureValues: z.record(z.unknown()).optional(),
|
featureValues: z.record(z.string(), z.unknown()).optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const ListProviderFeaturesRequestMessageSchema = z.object({
|
export const ListProviderFeaturesRequestMessageSchema = z.object({
|
||||||
@@ -2094,7 +2091,7 @@ export const ActivityLogPayloadSchema = z.object({
|
|||||||
timestamp: z.coerce.date(),
|
timestamp: z.coerce.date(),
|
||||||
type: z.enum(["transcript", "assistant", "tool_call", "tool_result", "error", "system"]),
|
type: z.enum(["transcript", "assistant", "tool_call", "tool_result", "error", "system"]),
|
||||||
content: z.string(),
|
content: z.string(),
|
||||||
metadata: z.record(z.unknown()).optional(),
|
metadata: z.record(z.string(), z.unknown()).optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const ActivityLogMessageSchema = z.object({
|
export const ActivityLogMessageSchema = z.object({
|
||||||
@@ -2241,7 +2238,7 @@ export const ServerInfoStatusPayloadSchema = z
|
|||||||
serverId: z.string().trim().min(1),
|
serverId: z.string().trim().min(1),
|
||||||
hostname: ServerInfoHostnameSchema.optional(),
|
hostname: ServerInfoHostnameSchema.optional(),
|
||||||
version: ServerInfoVersionSchema.optional(),
|
version: ServerInfoVersionSchema.optional(),
|
||||||
capabilities: ServerCapabilitiesFromUnknownSchema,
|
capabilities: ServerCapabilitiesFromUnknownSchema.optional(),
|
||||||
// COMPAT(providersSnapshot): added in v0.1.48, remove gating when all clients use snapshot
|
// COMPAT(providersSnapshot): added in v0.1.48, remove gating when all clients use snapshot
|
||||||
features: z
|
features: z
|
||||||
.object({
|
.object({
|
||||||
@@ -3486,7 +3483,7 @@ export const PullRequestTimelineResponseSchema = z.object({
|
|||||||
githubFeaturesEnabled: z.boolean().optional().default(true),
|
githubFeaturesEnabled: z.boolean().optional().default(true),
|
||||||
})
|
})
|
||||||
.optional()
|
.optional()
|
||||||
.default({}),
|
.prefault({}),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const CheckoutSwitchBranchResponseSchema = z.object({
|
export const CheckoutSwitchBranchResponseSchema = z.object({
|
||||||
|
|||||||
@@ -33,6 +33,34 @@ describe("paseo config schema", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("normalizes partial worktree lifecycle config without dropping present commands", () => {
|
||||||
|
expect(
|
||||||
|
PaseoConfigSchema.parse({
|
||||||
|
worktree: {
|
||||||
|
setup: 'echo "setup ran" > setup.log',
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
).toEqual({
|
||||||
|
worktree: {
|
||||||
|
setup: ['echo "setup ran" > setup.log'],
|
||||||
|
teardown: [],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(
|
||||||
|
PaseoConfigSchema.parse({
|
||||||
|
worktree: {
|
||||||
|
teardown: ["npm run clean"],
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
).toEqual({
|
||||||
|
worktree: {
|
||||||
|
setup: [],
|
||||||
|
teardown: ["npm run clean"],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it("parses all metadata generation instruction entries", () => {
|
it("parses all metadata generation instruction entries", () => {
|
||||||
expect(
|
expect(
|
||||||
PaseoConfigSchema.parse({
|
PaseoConfigSchema.parse({
|
||||||
|
|||||||
@@ -58,8 +58,8 @@ export const PaseoConfigRawSchema = z
|
|||||||
.passthrough();
|
.passthrough();
|
||||||
|
|
||||||
export const WorktreeConfigSchema = PaseoWorktreeConfigRawSchema.extend({
|
export const WorktreeConfigSchema = PaseoWorktreeConfigRawSchema.extend({
|
||||||
setup: z.unknown().transform(normalizeLifecycleCommands),
|
setup: z.unknown().optional().transform(normalizeLifecycleCommands),
|
||||||
teardown: z.unknown().transform(normalizeLifecycleCommands),
|
teardown: z.unknown().optional().transform(normalizeLifecycleCommands),
|
||||||
})
|
})
|
||||||
.passthrough()
|
.passthrough()
|
||||||
.catch({ setup: [], teardown: [] });
|
.catch({ setup: [], teardown: [] });
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ export const ProviderCommandSchema = z.discriminatedUnion("mode", [
|
|||||||
|
|
||||||
export const ProviderRuntimeSettingsSchema = z.object({
|
export const ProviderRuntimeSettingsSchema = z.object({
|
||||||
command: ProviderCommandSchema.optional(),
|
command: ProviderCommandSchema.optional(),
|
||||||
env: z.record(z.string()).optional(),
|
env: z.record(z.string(), z.string()).optional(),
|
||||||
disallowedTools: z.array(z.string()).optional(),
|
disallowedTools: z.array(z.string()).optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -48,8 +48,8 @@ export const ProviderOverrideSchema = z.object({
|
|||||||
label: z.string().optional(),
|
label: z.string().optional(),
|
||||||
description: z.string().optional(),
|
description: z.string().optional(),
|
||||||
command: z.array(z.string().min(1)).min(1).optional(),
|
command: z.array(z.string().min(1)).min(1).optional(),
|
||||||
env: z.record(z.string()).optional(),
|
env: z.record(z.string(), z.string()).optional(),
|
||||||
params: z.record(z.unknown()).optional(),
|
params: z.record(z.string(), z.unknown()).optional(),
|
||||||
models: z.array(ProviderProfileModelSchema).optional(),
|
models: z.array(ProviderProfileModelSchema).optional(),
|
||||||
additionalModels: z.array(ProviderProfileModelSchema).optional(),
|
additionalModels: z.array(ProviderProfileModelSchema).optional(),
|
||||||
disallowedTools: z.array(z.string()).optional(),
|
disallowedTools: z.array(z.string()).optional(),
|
||||||
@@ -61,7 +61,7 @@ const BUILTIN_PROVIDER_IDS = ["claude", "codex", "copilot", "opencode", "pi", "o
|
|||||||
const PROVIDER_ID_PATTERN = /^[a-z][a-z0-9-]*$/;
|
const PROVIDER_ID_PATTERN = /^[a-z][a-z0-9-]*$/;
|
||||||
|
|
||||||
export const ProviderOverridesSchema = z
|
export const ProviderOverridesSchema = z
|
||||||
.record(ProviderOverrideSchema)
|
.record(z.string(), ProviderOverrideSchema)
|
||||||
.superRefine((providers, ctx) => {
|
.superRefine((providers, ctx) => {
|
||||||
const builtinProviderIdSet = new Set<string>(BUILTIN_PROVIDER_IDS);
|
const builtinProviderIdSet = new Set<string>(BUILTIN_PROVIDER_IDS);
|
||||||
const validExtendsValues = new Set<string>([...BUILTIN_PROVIDER_IDS, "acp"]);
|
const validExtendsValues = new Set<string>([...BUILTIN_PROVIDER_IDS, "acp"]);
|
||||||
@@ -111,7 +111,7 @@ export const ProviderOverridesSchema = z
|
|||||||
});
|
});
|
||||||
|
|
||||||
export const AgentProviderRuntimeSettingsMapSchema = z
|
export const AgentProviderRuntimeSettingsMapSchema = z
|
||||||
.record(ProviderRuntimeSettingsSchema)
|
.record(z.string(), ProviderRuntimeSettingsSchema)
|
||||||
.superRefine((providers, ctx) => {
|
.superRefine((providers, ctx) => {
|
||||||
for (const providerId of Object.keys(providers)) {
|
for (const providerId of Object.keys(providers)) {
|
||||||
const parsedProviderId = AgentProviderSchema.safeParse(providerId);
|
const parsedProviderId = AgentProviderSchema.safeParse(providerId);
|
||||||
|
|||||||
@@ -10,11 +10,11 @@ import {
|
|||||||
const ScheduleCreateTargetSchema = z.discriminatedUnion("type", [
|
const ScheduleCreateTargetSchema = z.discriminatedUnion("type", [
|
||||||
z.object({
|
z.object({
|
||||||
type: z.literal("self"),
|
type: z.literal("self"),
|
||||||
agentId: z.string().uuid(),
|
agentId: z.guid(),
|
||||||
}),
|
}),
|
||||||
z.object({
|
z.object({
|
||||||
type: z.literal("agent"),
|
type: z.literal("agent"),
|
||||||
agentId: z.string().uuid(),
|
agentId: z.guid(),
|
||||||
}),
|
}),
|
||||||
z.object({
|
z.object({
|
||||||
type: z.literal("new-agent"),
|
type: z.literal("new-agent"),
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ export type ScheduleCadence = z.infer<typeof ScheduleCadenceSchema>;
|
|||||||
export const ScheduleTargetSchema = z.discriminatedUnion("type", [
|
export const ScheduleTargetSchema = z.discriminatedUnion("type", [
|
||||||
z.object({
|
z.object({
|
||||||
type: z.literal("agent"),
|
type: z.literal("agent"),
|
||||||
agentId: z.string().uuid(),
|
agentId: z.guid(),
|
||||||
}),
|
}),
|
||||||
z.object({
|
z.object({
|
||||||
type: z.literal("new-agent"),
|
type: z.literal("new-agent"),
|
||||||
@@ -35,16 +35,16 @@ export const ScheduleTargetSchema = z.discriminatedUnion("type", [
|
|||||||
sandboxMode: z.string().trim().min(1).optional(),
|
sandboxMode: z.string().trim().min(1).optional(),
|
||||||
networkAccess: z.boolean().optional(),
|
networkAccess: z.boolean().optional(),
|
||||||
webSearch: z.boolean().optional(),
|
webSearch: z.boolean().optional(),
|
||||||
featureValues: z.record(z.unknown()).optional(),
|
featureValues: z.record(z.string(), z.unknown()).optional(),
|
||||||
extra: z
|
extra: z
|
||||||
.object({
|
.object({
|
||||||
codex: z.record(z.unknown()).optional(),
|
codex: z.record(z.string(), z.unknown()).optional(),
|
||||||
claude: z.record(z.unknown()).optional(),
|
claude: z.record(z.string(), z.unknown()).optional(),
|
||||||
})
|
})
|
||||||
.partial()
|
.partial()
|
||||||
.optional(),
|
.optional(),
|
||||||
systemPrompt: z.string().optional(),
|
systemPrompt: z.string().optional(),
|
||||||
mcpServers: z.record(z.unknown()).optional(),
|
mcpServers: z.record(z.string(), z.unknown()).optional(),
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
]);
|
]);
|
||||||
@@ -56,7 +56,7 @@ export const ScheduleRunSchema = z.object({
|
|||||||
startedAt: z.string(),
|
startedAt: z.string(),
|
||||||
endedAt: z.string().nullable(),
|
endedAt: z.string().nullable(),
|
||||||
status: z.enum(["running", "succeeded", "failed"]),
|
status: z.enum(["running", "succeeded", "failed"]),
|
||||||
agentId: z.string().uuid().nullable(),
|
agentId: z.guid().nullable(),
|
||||||
output: z.string().nullable(),
|
output: z.string().nullable(),
|
||||||
error: z.string().nullable(),
|
error: z.string().nullable(),
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -63,7 +63,8 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@agentclientprotocol/sdk": "^0.17.1",
|
"@agentclientprotocol/sdk": "^0.17.1",
|
||||||
"@anthropic-ai/claude-agent-sdk": "^0.2.133",
|
"@anthropic-ai/claude-agent-sdk": "^0.3.181",
|
||||||
|
"@anthropic-ai/sdk": "^0.104.2",
|
||||||
"@getpaseo/client": "0.1.97-beta.3",
|
"@getpaseo/client": "0.1.97-beta.3",
|
||||||
"@getpaseo/highlight": "0.1.97-beta.3",
|
"@getpaseo/highlight": "0.1.97-beta.3",
|
||||||
"@getpaseo/protocol": "0.1.97-beta.3",
|
"@getpaseo/protocol": "0.1.97-beta.3",
|
||||||
@@ -81,7 +82,7 @@
|
|||||||
"lru-cache": "^11.5.1",
|
"lru-cache": "^11.5.1",
|
||||||
"mnemonic-id": "^3.2.7",
|
"mnemonic-id": "^3.2.7",
|
||||||
"node-pty": "1.2.0-beta.11",
|
"node-pty": "1.2.0-beta.11",
|
||||||
"openai": "^4.20.0",
|
"openai": "^6.44.0",
|
||||||
"p-limit": "^7.3.0",
|
"p-limit": "^7.3.0",
|
||||||
"p-memoize": "^8.0.0",
|
"p-memoize": "^8.0.0",
|
||||||
"pino": "^10.2.0",
|
"pino": "^10.2.0",
|
||||||
@@ -94,8 +95,7 @@
|
|||||||
"uuid": "^9.0.1",
|
"uuid": "^9.0.1",
|
||||||
"which": "^5.0.0",
|
"which": "^5.0.0",
|
||||||
"ws": "^8.14.2",
|
"ws": "^8.14.2",
|
||||||
"zod": "^3.23.8",
|
"zod": "^4.4.3"
|
||||||
"zod-to-json-schema": "^3.25.1"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@playwright/test": "^1.56.1",
|
"@playwright/test": "^1.56.1",
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { fileURLToPath } from "node:url";
|
|||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import fs from "node:fs";
|
import fs from "node:fs";
|
||||||
|
|
||||||
import { zodToJsonSchema } from "zod-to-json-schema";
|
import { z } from "zod";
|
||||||
import { PersistedConfigSchema } from "../src/server/persisted-config.js";
|
import { PersistedConfigSchema } from "../src/server/persisted-config.js";
|
||||||
|
|
||||||
const __filename = fileURLToPath(import.meta.url);
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
@@ -13,9 +13,12 @@ function main() {
|
|||||||
const outPath = path.join(repoRoot, "packages/website/public/schemas/paseo.config.v1.json");
|
const outPath = path.join(repoRoot, "packages/website/public/schemas/paseo.config.v1.json");
|
||||||
fs.mkdirSync(path.dirname(outPath), { recursive: true });
|
fs.mkdirSync(path.dirname(outPath), { recursive: true });
|
||||||
|
|
||||||
const schema = zodToJsonSchema(PersistedConfigSchema, {
|
const schema = z.toJSONSchema(PersistedConfigSchema, {
|
||||||
name: "PaseoConfigV1",
|
target: "draft-07",
|
||||||
|
unrepresentable: "any",
|
||||||
|
io: "input",
|
||||||
});
|
});
|
||||||
|
schema.title = "PaseoConfigV1";
|
||||||
|
|
||||||
fs.writeFileSync(outPath, JSON.stringify(schema, null, 2) + "\n", "utf8");
|
fs.writeFileSync(outPath, JSON.stringify(schema, null, 2) + "\n", "utf8");
|
||||||
process.stdout.write(`Wrote ${outPath}\n`);
|
process.stdout.write(`Wrote ${outPath}\n`);
|
||||||
|
|||||||
@@ -370,7 +370,7 @@ interface SubscriptionRecord {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const BUSY_STATUSES: Set<AgentLifecycleStatus> = new Set(["initializing", "running"]);
|
const BUSY_STATUSES: Set<AgentLifecycleStatus> = new Set(["initializing", "running"]);
|
||||||
const AgentIdSchema = z.string().uuid();
|
const AgentIdSchema = z.guid();
|
||||||
|
|
||||||
function isAgentBusy(status: AgentLifecycleStatus): boolean {
|
function isAgentBusy(status: AgentLifecycleStatus): boolean {
|
||||||
return BUSY_STATUSES.has(status);
|
return BUSY_STATUSES.has(status);
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { zodToJsonSchema } from "zod-to-json-schema";
|
|
||||||
import Ajv, { type ErrorObject, type Options as AjvOptions } from "ajv";
|
import Ajv, { type ErrorObject, type Options as AjvOptions } from "ajv";
|
||||||
import type { AgentProvider, AgentSessionConfig } from "./agent-sdk-types.js";
|
import type { AgentProvider, AgentSessionConfig } from "./agent-sdk-types.js";
|
||||||
import type { AgentManager } from "./agent-manager.js";
|
import type { AgentManager } from "./agent-manager.js";
|
||||||
@@ -106,16 +105,19 @@ interface SchemaValidator<T> {
|
|||||||
validate: (value: unknown) => { ok: true; value: T } | { ok: false; errors: string[] };
|
validate: (value: unknown) => { ok: true; value: T } | { ok: false; errors: string[] };
|
||||||
}
|
}
|
||||||
|
|
||||||
function isZodSchema(value: unknown): value is z.ZodTypeAny {
|
function isZodSchema(value: unknown): value is z.ZodType {
|
||||||
return typeof (value as z.ZodTypeAny | undefined)?.safeParse === "function";
|
return typeof (value as z.ZodType | undefined)?.safeParse === "function";
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildZodValidator<T>(schema: z.ZodTypeAny, schemaName: string): SchemaValidator<T> {
|
function buildZodValidator<T>(schema: z.ZodType, schemaName: string): SchemaValidator<T> {
|
||||||
const zodToJsonSchemaAny = zodToJsonSchema as unknown as (
|
const jsonSchema = z.toJSONSchema(schema, {
|
||||||
input: z.ZodTypeAny,
|
target: "draft-07",
|
||||||
name?: string,
|
unrepresentable: "any",
|
||||||
) => JsonSchema;
|
io: "input",
|
||||||
const jsonSchema = zodToJsonSchemaAny(schema, schemaName);
|
}) as JsonSchema;
|
||||||
|
if (typeof jsonSchema.title !== "string") {
|
||||||
|
jsonSchema.title = schemaName;
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
jsonSchema,
|
jsonSchema,
|
||||||
validate: (value) => {
|
validate: (value) => {
|
||||||
|
|||||||
@@ -14,10 +14,10 @@ const SERIALIZABLE_CONFIG_SCHEMA = z
|
|||||||
modeId: z.string().nullable().optional(),
|
modeId: z.string().nullable().optional(),
|
||||||
model: z.string().nullable().optional(),
|
model: z.string().nullable().optional(),
|
||||||
thinkingOptionId: z.string().nullable().optional(),
|
thinkingOptionId: z.string().nullable().optional(),
|
||||||
featureValues: z.record(z.unknown()).nullable().optional(),
|
featureValues: z.record(z.string(), z.unknown()).nullable().optional(),
|
||||||
extra: z.record(z.any()).nullable().optional(),
|
extra: z.record(z.string(), z.any()).nullable().optional(),
|
||||||
systemPrompt: z.string().nullable().optional(),
|
systemPrompt: z.string().nullable().optional(),
|
||||||
mcpServers: z.record(z.any()).nullable().optional(),
|
mcpServers: z.record(z.string(), z.any()).nullable().optional(),
|
||||||
})
|
})
|
||||||
.nullable()
|
.nullable()
|
||||||
.optional();
|
.optional();
|
||||||
@@ -27,7 +27,7 @@ const PERSISTENCE_HANDLE_SCHEMA = z
|
|||||||
provider: z.string(),
|
provider: z.string(),
|
||||||
sessionId: z.string(),
|
sessionId: z.string(),
|
||||||
nativeHandle: z.any().optional(),
|
nativeHandle: z.any().optional(),
|
||||||
metadata: z.record(z.any()).optional(),
|
metadata: z.record(z.string(), z.any()).optional(),
|
||||||
})
|
})
|
||||||
.nullable()
|
.nullable()
|
||||||
.optional();
|
.optional();
|
||||||
@@ -42,7 +42,7 @@ const STORED_AGENT_SCHEMA = z.object({
|
|||||||
lastActivityAt: z.string().optional(),
|
lastActivityAt: z.string().optional(),
|
||||||
lastUserMessageAt: z.string().nullable().optional(),
|
lastUserMessageAt: z.string().nullable().optional(),
|
||||||
title: z.string().nullable().optional(),
|
title: z.string().nullable().optional(),
|
||||||
labels: z.record(z.string()).default({}),
|
labels: z.record(z.string(), z.string()).default({}),
|
||||||
lastStatus: AgentStatusSchema.default("closed"),
|
lastStatus: AgentStatusSchema.default("closed"),
|
||||||
lastModeId: z.string().nullable().optional(),
|
lastModeId: z.string().nullable().optional(),
|
||||||
config: SERIALIZABLE_CONFIG_SCHEMA,
|
config: SERIALIZABLE_CONFIG_SCHEMA,
|
||||||
@@ -53,7 +53,7 @@ const STORED_AGENT_SCHEMA = z.object({
|
|||||||
model: z.string().nullable().optional(),
|
model: z.string().nullable().optional(),
|
||||||
thinkingOptionId: z.string().nullable().optional(),
|
thinkingOptionId: z.string().nullable().optional(),
|
||||||
modeId: z.string().nullable().optional(),
|
modeId: z.string().nullable().optional(),
|
||||||
extra: z.record(z.unknown()).optional(),
|
extra: z.record(z.string(), z.unknown()).optional(),
|
||||||
})
|
})
|
||||||
.optional(),
|
.optional(),
|
||||||
features: z.array(AgentFeatureSchema).optional(),
|
features: z.array(AgentFeatureSchema).optional(),
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ import { z } from "zod";
|
|||||||
|
|
||||||
import { AGENT_WAIT_TIMEOUT_MS } from "./mcp-shared.js";
|
import { AGENT_WAIT_TIMEOUT_MS } from "./mcp-shared.js";
|
||||||
import { createTestPaseoDaemon, type TestPaseoDaemon } from "../test-utils/paseo-daemon.js";
|
import { createTestPaseoDaemon, type TestPaseoDaemon } from "../test-utils/paseo-daemon.js";
|
||||||
|
import { createTestAgentClients } from "../test-utils/fake-agent-client.js";
|
||||||
|
import type { AgentClient, AgentProvider, AgentSessionConfig } from "./agent-sdk-types.js";
|
||||||
import { PARENT_AGENT_ID_LABEL } from "@getpaseo/protocol/agent-labels";
|
import { PARENT_AGENT_ID_LABEL } from "@getpaseo/protocol/agent-labels";
|
||||||
|
|
||||||
interface StructuredContent {
|
interface StructuredContent {
|
||||||
@@ -31,7 +33,7 @@ function str(val: unknown): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function recordArr(val: unknown): StructuredContent[] {
|
function recordArr(val: unknown): StructuredContent[] {
|
||||||
return z.array(z.record(z.unknown())).parse(val);
|
return z.array(z.record(z.string(), z.unknown())).parse(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
function expectAgentFeatureValue(snapshot: StructuredContent, featureId: string, value: unknown) {
|
function expectAgentFeatureValue(snapshot: StructuredContent, featureId: string, value: unknown) {
|
||||||
@@ -142,6 +144,56 @@ let agentScopedClient: McpClient;
|
|||||||
let parentAgentId: string;
|
let parentAgentId: string;
|
||||||
let parentAgentCwd: string;
|
let parentAgentCwd: string;
|
||||||
let worktreeRepoCwd: string;
|
let worktreeRepoCwd: string;
|
||||||
|
let launchConfigsByProvider: Record<AgentProvider, AgentSessionConfig[]>;
|
||||||
|
|
||||||
|
function createRecordingAgentClients(): Record<AgentProvider, AgentClient> {
|
||||||
|
const baseClients = createTestAgentClients();
|
||||||
|
launchConfigsByProvider = {};
|
||||||
|
const wrappedClients: Record<AgentProvider, AgentClient> = {};
|
||||||
|
|
||||||
|
for (const [provider, client] of Object.entries(baseClients)) {
|
||||||
|
const launchConfigs: AgentSessionConfig[] = [];
|
||||||
|
launchConfigsByProvider[provider] = launchConfigs;
|
||||||
|
const wrappedClient: AgentClient = {
|
||||||
|
provider: client.provider,
|
||||||
|
capabilities: client.capabilities,
|
||||||
|
createSession: async (config, launchContext, options) => {
|
||||||
|
launchConfigs.push(config);
|
||||||
|
return await client.createSession(config, launchContext, options);
|
||||||
|
},
|
||||||
|
resumeSession: async (handle, overrides, launchContext) =>
|
||||||
|
await client.resumeSession(handle, overrides, launchContext),
|
||||||
|
listModels: async (options) => await client.listModels(options),
|
||||||
|
isAvailable: async () => await client.isAvailable(),
|
||||||
|
};
|
||||||
|
if (client.listModes) {
|
||||||
|
wrappedClient.listModes = async (options) => await client.listModes!(options);
|
||||||
|
}
|
||||||
|
if (client.resolveCreateConfig) {
|
||||||
|
wrappedClient.resolveCreateConfig = (input) => client.resolveCreateConfig!(input);
|
||||||
|
}
|
||||||
|
if (client.isCreateConfigUnattended) {
|
||||||
|
wrappedClient.isCreateConfigUnattended = (input) => client.isCreateConfigUnattended!(input);
|
||||||
|
}
|
||||||
|
if (client.listCommands) {
|
||||||
|
wrappedClient.listCommands = async (config) => await client.listCommands!(config);
|
||||||
|
}
|
||||||
|
if (client.listFeatures) {
|
||||||
|
wrappedClient.listFeatures = async (config) => await client.listFeatures!(config);
|
||||||
|
}
|
||||||
|
if (client.listImportableSessions) {
|
||||||
|
wrappedClient.listImportableSessions = async (options) =>
|
||||||
|
await client.listImportableSessions!(options);
|
||||||
|
}
|
||||||
|
if (client.importSession) {
|
||||||
|
wrappedClient.importSession = async (input, context) =>
|
||||||
|
await client.importSession!(input, context);
|
||||||
|
}
|
||||||
|
wrappedClients[provider] = wrappedClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
return wrappedClients;
|
||||||
|
}
|
||||||
|
|
||||||
async function makeCwd(prefix: string): Promise<string> {
|
async function makeCwd(prefix: string): Promise<string> {
|
||||||
return await mkdtemp(path.join(tempRoot, `${prefix}-`));
|
return await mkdtemp(path.join(tempRoot, `${prefix}-`));
|
||||||
@@ -232,7 +284,7 @@ beforeAll(async () => {
|
|||||||
parentAgentCwd = await makeCwd("parent-agent-cwd");
|
parentAgentCwd = await makeCwd("parent-agent-cwd");
|
||||||
worktreeRepoCwd = await makeCwd("worktree-repo");
|
worktreeRepoCwd = await makeCwd("worktree-repo");
|
||||||
|
|
||||||
daemonHandle = await createTestPaseoDaemon();
|
daemonHandle = await createTestPaseoDaemon({ agentClients: createRecordingAgentClients() });
|
||||||
topLevelClient = await createMcpClient(`http://127.0.0.1:${daemonHandle.port}/mcp/agents`);
|
topLevelClient = await createMcpClient(`http://127.0.0.1:${daemonHandle.port}/mcp/agents`);
|
||||||
|
|
||||||
const parentPayload = await callToolStructured(topLevelClient, "create_agent", {
|
const parentPayload = await callToolStructured(topLevelClient, "create_agent", {
|
||||||
@@ -302,10 +354,11 @@ describe("Suite A: Core Fixes", () => {
|
|||||||
try {
|
try {
|
||||||
const listenTarget = daemonHandle.daemon.getListenTarget();
|
const listenTarget = daemonHandle.daemon.getListenTarget();
|
||||||
expect(listenTarget?.type).toBe("tcp");
|
expect(listenTarget?.type).toBe("tcp");
|
||||||
|
const cwd = await makeCwd("manager-direct-agent-cwd");
|
||||||
|
|
||||||
const snapshot = await daemonHandle.daemon.agentManager.createAgent({
|
const snapshot = await daemonHandle.daemon.agentManager.createAgent({
|
||||||
provider: "claude",
|
provider: "claude",
|
||||||
cwd: await makeCwd("manager-direct-agent-cwd"),
|
cwd,
|
||||||
title: "Manager direct parity agent",
|
title: "Manager direct parity agent",
|
||||||
modeId: "bypassPermissions",
|
modeId: "bypassPermissions",
|
||||||
});
|
});
|
||||||
@@ -317,20 +370,19 @@ describe("Suite A: Core Fixes", () => {
|
|||||||
agentId,
|
agentId,
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(snapshot.config.mcpServers).toMatchObject({
|
const launchConfig = launchConfigsByProvider.claude
|
||||||
|
?.toReversed()
|
||||||
|
.find((config) => config.cwd === cwd);
|
||||||
|
expect(launchConfig?.mcpServers).toMatchObject({
|
||||||
paseo: {
|
paseo: {
|
||||||
type: "http",
|
type: "http",
|
||||||
url: expectedUrl,
|
url: expectedUrl,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
expect(snapshot.config.mcpServers?.paseo).toBeUndefined();
|
||||||
|
|
||||||
const liveAgent = daemonHandle.daemon.agentManager.getAgent(agentId);
|
const liveAgent = daemonHandle.daemon.agentManager.getAgent(agentId);
|
||||||
expect(liveAgent?.config.mcpServers).toMatchObject({
|
expect(liveAgent?.config.mcpServers?.paseo).toBeUndefined();
|
||||||
paseo: {
|
|
||||||
type: "http",
|
|
||||||
url: expectedUrl,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
} finally {
|
} finally {
|
||||||
await archiveAgentIfPresent(agentId);
|
await archiveAgentIfPresent(agentId);
|
||||||
}
|
}
|
||||||
@@ -355,7 +407,7 @@ describe("Suite A: Core Fixes", () => {
|
|||||||
expect(internalSnapshot?.config.featureValues).toEqual({ test_feature: true });
|
expect(internalSnapshot?.config.featureValues).toEqual({ test_feature: true });
|
||||||
|
|
||||||
const status = await callToolStructured(topLevelClient, "get_agent_status", { agentId });
|
const status = await callToolStructured(topLevelClient, "get_agent_status", { agentId });
|
||||||
const snapshot = z.record(z.unknown()).parse(status.snapshot);
|
const snapshot = z.record(z.string(), z.unknown()).parse(status.snapshot);
|
||||||
expectAgentFeatureValue(snapshot, "test_feature", true);
|
expectAgentFeatureValue(snapshot, "test_feature", true);
|
||||||
} finally {
|
} finally {
|
||||||
await archiveAgentIfPresent(agentId);
|
await archiveAgentIfPresent(agentId);
|
||||||
@@ -373,7 +425,7 @@ describe("Suite A: Core Fixes", () => {
|
|||||||
expect(internalSnapshot?.config.featureValues).toEqual({ test_feature: true });
|
expect(internalSnapshot?.config.featureValues).toEqual({ test_feature: true });
|
||||||
|
|
||||||
const status = await callToolStructured(topLevelClient, "get_agent_status", { agentId });
|
const status = await callToolStructured(topLevelClient, "get_agent_status", { agentId });
|
||||||
const snapshot = z.record(z.unknown()).parse(status.snapshot);
|
const snapshot = z.record(z.string(), z.unknown()).parse(status.snapshot);
|
||||||
expectAgentFeatureValue(snapshot, "test_feature", true);
|
expectAgentFeatureValue(snapshot, "test_feature", true);
|
||||||
} finally {
|
} finally {
|
||||||
await archiveAgentIfPresent(agentId);
|
await archiveAgentIfPresent(agentId);
|
||||||
@@ -393,7 +445,7 @@ describe("Suite A: Core Fixes", () => {
|
|||||||
expect(internalSnapshot?.config.featureValues).toEqual({ test_feature: true });
|
expect(internalSnapshot?.config.featureValues).toEqual({ test_feature: true });
|
||||||
|
|
||||||
const status = await callToolStructured(topLevelClient, "get_agent_status", { agentId });
|
const status = await callToolStructured(topLevelClient, "get_agent_status", { agentId });
|
||||||
const snapshot = z.record(z.unknown()).parse(status.snapshot);
|
const snapshot = z.record(z.string(), z.unknown()).parse(status.snapshot);
|
||||||
expectAgentFeatureValue(snapshot, "test_feature", true);
|
expectAgentFeatureValue(snapshot, "test_feature", true);
|
||||||
} finally {
|
} finally {
|
||||||
await archiveAgentIfPresent(agentId);
|
await archiveAgentIfPresent(agentId);
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import { join, resolve as resolvePath } from "node:path";
|
|||||||
import { tmpdir } from "node:os";
|
import { tmpdir } from "node:os";
|
||||||
import Ajv from "ajv";
|
import Ajv from "ajv";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { zodToJsonSchema } from "zod-to-json-schema";
|
|
||||||
|
|
||||||
import { createTestLogger } from "../../test-utils/test-logger.js";
|
import { createTestLogger } from "../../test-utils/test-logger.js";
|
||||||
import { createAgentMcpServer } from "./mcp-server.js";
|
import { createAgentMcpServer } from "./mcp-server.js";
|
||||||
@@ -114,7 +113,11 @@ async function invokeToolWithParsedInput(
|
|||||||
|
|
||||||
function expectOutputSchemaAccepts(tool: RegisteredMcpTool, data: unknown): void {
|
function expectOutputSchemaAccepts(tool: RegisteredMcpTool, data: unknown): void {
|
||||||
expect(tool.outputSchema).toBeDefined();
|
expect(tool.outputSchema).toBeDefined();
|
||||||
const jsonSchema = zodToJsonSchema(tool.outputSchema as z.ZodTypeAny);
|
const jsonSchema = z.toJSONSchema(tool.outputSchema as z.ZodType, {
|
||||||
|
target: "draft-07",
|
||||||
|
unrepresentable: "any",
|
||||||
|
io: "input",
|
||||||
|
});
|
||||||
const ajv = new Ajv({ allErrors: true, strict: false });
|
const ajv = new Ajv({ allErrors: true, strict: false });
|
||||||
const validate = ajv.compile(jsonSchema);
|
const validate = ajv.compile(jsonSchema);
|
||||||
expect(validate(data), JSON.stringify(validate.errors, null, 2)).toBe(true);
|
expect(validate(data), JSON.stringify(validate.errors, null, 2)).toBe(true);
|
||||||
@@ -123,7 +126,7 @@ function expectOutputSchemaAccepts(tool: RegisteredMcpTool, data: unknown): void
|
|||||||
function agentsOf(response: {
|
function agentsOf(response: {
|
||||||
structuredContent: LooseStructuredContent;
|
structuredContent: LooseStructuredContent;
|
||||||
}): Array<Record<string, unknown>> {
|
}): Array<Record<string, unknown>> {
|
||||||
return z.array(z.record(z.unknown())).parse(response.structuredContent.agents);
|
return z.array(z.record(z.string(), z.unknown())).parse(response.structuredContent.agents);
|
||||||
}
|
}
|
||||||
|
|
||||||
type AgentManagerSpies = ReturnType<typeof buildAgentManagerSpies>;
|
type AgentManagerSpies = ReturnType<typeof buildAgentManagerSpies>;
|
||||||
@@ -3363,7 +3366,7 @@ describe("agent snapshot MCP serialization", () => {
|
|||||||
const tool = registeredTool(server, "list_agents");
|
const tool = registeredTool(server, "list_agents");
|
||||||
const response = await tool.handler({});
|
const response = await tool.handler({});
|
||||||
const structured = z
|
const structured = z
|
||||||
.object({ agents: z.array(z.record(z.unknown())) })
|
.object({ agents: z.array(z.record(z.string(), z.unknown())) })
|
||||||
.parse(response.structuredContent);
|
.parse(response.structuredContent);
|
||||||
|
|
||||||
expect(structured).toEqual({
|
expect(structured).toEqual({
|
||||||
@@ -3485,7 +3488,7 @@ describe("agent snapshot MCP serialization", () => {
|
|||||||
});
|
});
|
||||||
const tool = registeredTool(server, "get_agent_status");
|
const tool = registeredTool(server, "get_agent_status");
|
||||||
const response = await tool.handler({ agentId: "full-detail-agent" });
|
const response = await tool.handler({ agentId: "full-detail-agent" });
|
||||||
const snapshot = z.record(z.unknown()).parse(response.structuredContent.snapshot);
|
const snapshot = z.record(z.string(), z.unknown()).parse(response.structuredContent.snapshot);
|
||||||
|
|
||||||
const parsed = AgentSnapshotPayloadSchema.safeParse(snapshot);
|
const parsed = AgentSnapshotPayloadSchema.safeParse(snapshot);
|
||||||
if (!parsed.success) {
|
if (!parsed.success) {
|
||||||
|
|||||||
@@ -169,9 +169,11 @@ function formatStructuredContentForModel(structuredContent: unknown): string {
|
|||||||
return summary.length > 0 ? `${summary.join("\n")}\n\n${json}` : json;
|
return summary.length > 0 ? `${summary.join("\n")}\n\n${json}` : json;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isZodSchema(value: unknown): value is z.ZodTypeAny {
|
function isZodSchema(value: unknown): value is z.ZodType {
|
||||||
return (
|
return (
|
||||||
typeof value === "object" && value !== null && "_def" in value && "safeParseAsync" in value
|
typeof value === "object" &&
|
||||||
|
value !== null &&
|
||||||
|
typeof (value as { safeParseAsync?: unknown }).safeParseAsync === "function"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -714,7 +716,7 @@ export async function createAgentMcpServer(options: AgentMcpServerOptions): Prom
|
|||||||
modeId: z.string().optional().describe("Session mode to configure before the first run."),
|
modeId: z.string().optional().describe("Session mode to configure before the first run."),
|
||||||
thinkingOptionId: z.string().optional().describe("Thinking option ID."),
|
thinkingOptionId: z.string().optional().describe("Thinking option ID."),
|
||||||
features: z
|
features: z
|
||||||
.record(z.unknown())
|
.record(z.string(), z.unknown())
|
||||||
.optional()
|
.optional()
|
||||||
.describe("Provider-specific feature values, for example { fast_mode: true } for Codex."),
|
.describe("Provider-specific feature values, for example { fast_mode: true } for Codex."),
|
||||||
})
|
})
|
||||||
@@ -729,7 +731,7 @@ export async function createAgentMcpServer(options: AgentMcpServerOptions): Prom
|
|||||||
.optional()
|
.optional()
|
||||||
.describe("Thinking option ID. Pass null to clear."),
|
.describe("Thinking option ID. Pass null to clear."),
|
||||||
features: z
|
features: z
|
||||||
.record(z.unknown())
|
.record(z.string(), z.unknown())
|
||||||
.optional()
|
.optional()
|
||||||
.describe("Provider-specific feature values, for example { fast_mode: true } for Codex."),
|
.describe("Provider-specific feature values, for example { fast_mode: true } for Codex."),
|
||||||
})
|
})
|
||||||
@@ -739,7 +741,10 @@ export async function createAgentMcpServer(options: AgentMcpServerOptions): Prom
|
|||||||
modeId: z.string().optional().describe("Draft session mode ID."),
|
modeId: z.string().optional().describe("Draft session mode ID."),
|
||||||
model: z.string().optional().describe("Draft model ID."),
|
model: z.string().optional().describe("Draft model ID."),
|
||||||
thinkingOptionId: z.string().optional().describe("Draft thinking option ID."),
|
thinkingOptionId: z.string().optional().describe("Draft thinking option ID."),
|
||||||
features: z.record(z.unknown()).optional().describe("Draft provider feature values."),
|
features: z
|
||||||
|
.record(z.string(), z.unknown())
|
||||||
|
.optional()
|
||||||
|
.describe("Draft provider feature values."),
|
||||||
})
|
})
|
||||||
.strict();
|
.strict();
|
||||||
const agentToAgentInputSchema = {
|
const agentToAgentInputSchema = {
|
||||||
|
|||||||
@@ -66,8 +66,8 @@ const cases: ParityCase[] = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "non-existent path (canonicalize fallback)",
|
label: "non-existent path (canonicalize fallback)",
|
||||||
// realpath will throw; canonicalize falls back to NFC of input. SDK does
|
// realpath will throw; canonicalize falls back to the SDK's
|
||||||
// the same, so paths should still match.
|
// platform-specific normalization of the input.
|
||||||
build: async () => join(workspaceRoot, "this-path-was-never-created-" + randomUUID()),
|
build: async () => join(workspaceRoot, "this-path-was-never-created-" + randomUUID()),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ import { join } from "node:path";
|
|||||||
// Verbatim port of the Claude Agent SDK's project-directory encoding so
|
// Verbatim port of the Claude Agent SDK's project-directory encoding so
|
||||||
// paseo computes the same `~/.claude/projects/<dir>` path the SDK does.
|
// paseo computes the same `~/.claude/projects/<dir>` path the SDK does.
|
||||||
// The SDK ships only as a precompiled bundle; grep the JS source at
|
// The SDK ships only as a precompiled bundle; grep the JS source at
|
||||||
// node_modules/@anthropic-ai/claude-agent-sdk/sdk.mjs for `function f1`,
|
// node_modules/@anthropic-ai/claude-agent-sdk/sdk.mjs for `function Ar`,
|
||||||
// `function i4`, `function tB`, `S0=200`.
|
// `function So`, `async function wn`, `function Dy`, `Ni=200`.
|
||||||
|
|
||||||
const PROJECT_DIR_LENGTH_CAP = 200;
|
const PROJECT_DIR_LENGTH_CAP = 200;
|
||||||
|
|
||||||
@@ -32,20 +32,24 @@ export function claudeProjectDirSync(cwd: string, options?: ClaudeProjectDirOpti
|
|||||||
|
|
||||||
async function canonicalize(input: string): Promise<string> {
|
async function canonicalize(input: string): Promise<string> {
|
||||||
try {
|
try {
|
||||||
return (await realpath(input)).normalize("NFC");
|
return normalizeProjectPath(await realpath(input));
|
||||||
} catch {
|
} catch {
|
||||||
return input.normalize("NFC");
|
return normalizeProjectPath(input);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function canonicalizeSync(input: string): string {
|
function canonicalizeSync(input: string): string {
|
||||||
try {
|
try {
|
||||||
return realpathSync.native(input).normalize("NFC");
|
return normalizeProjectPath(realpathSync.native(input));
|
||||||
} catch {
|
} catch {
|
||||||
return input.normalize("NFC");
|
return normalizeProjectPath(input);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function normalizeProjectPath(input: string): string {
|
||||||
|
return process.platform === "darwin" ? input.normalize("NFC") : input;
|
||||||
|
}
|
||||||
|
|
||||||
function encode(input: string): string {
|
function encode(input: string): string {
|
||||||
const replaced = input.replace(/[^a-zA-Z0-9]/g, "-");
|
const replaced = input.replace(/[^a-zA-Z0-9]/g, "-");
|
||||||
if (replaced.length <= PROJECT_DIR_LENGTH_CAP) {
|
if (replaced.length <= PROJECT_DIR_LENGTH_CAP) {
|
||||||
|
|||||||
@@ -11,6 +11,61 @@ import {
|
|||||||
|
|
||||||
export const CommandValueSchema = z.union([z.string(), z.array(z.string())]);
|
export const CommandValueSchema = z.union([z.string(), z.array(z.string())]);
|
||||||
|
|
||||||
|
type ToolDetailSchema = z.ZodType;
|
||||||
|
// Zod 4 loses the generic output type when these branch helpers constrain
|
||||||
|
// schemas through z.ZodType, so the paired shape/value interfaces preserve the
|
||||||
|
// transform callback types without changing runtime parsing.
|
||||||
|
interface ToolDetailNameShape<
|
||||||
|
Name extends string,
|
||||||
|
InputSchema extends ToolDetailSchema,
|
||||||
|
OutputSchema extends ToolDetailSchema,
|
||||||
|
> {
|
||||||
|
name: z.ZodLiteral<Name>;
|
||||||
|
input: z.ZodNullable<InputSchema>;
|
||||||
|
output: z.ZodNullable<OutputSchema>;
|
||||||
|
}
|
||||||
|
interface ToolDetailToolNameShape<
|
||||||
|
Name extends string,
|
||||||
|
InputSchema extends ToolDetailSchema,
|
||||||
|
OutputSchema extends ToolDetailSchema,
|
||||||
|
> {
|
||||||
|
toolName: z.ZodLiteral<Name>;
|
||||||
|
input: z.ZodNullable<InputSchema>;
|
||||||
|
output: z.ZodNullable<OutputSchema>;
|
||||||
|
}
|
||||||
|
interface ToolDetailNameWithCwdShape<
|
||||||
|
Name extends string,
|
||||||
|
InputSchema extends ToolDetailSchema,
|
||||||
|
OutputSchema extends ToolDetailSchema,
|
||||||
|
> extends ToolDetailNameShape<Name, InputSchema, OutputSchema> {
|
||||||
|
cwd: z.ZodNullable<z.ZodOptional<z.ZodString>>;
|
||||||
|
}
|
||||||
|
interface ToolDetailNameValue<
|
||||||
|
Name extends string,
|
||||||
|
InputSchema extends ToolDetailSchema,
|
||||||
|
OutputSchema extends ToolDetailSchema,
|
||||||
|
> {
|
||||||
|
name: Name;
|
||||||
|
input: z.output<InputSchema> | null;
|
||||||
|
output: z.output<OutputSchema> | null;
|
||||||
|
}
|
||||||
|
interface ToolDetailToolNameValue<
|
||||||
|
Name extends string,
|
||||||
|
InputSchema extends ToolDetailSchema,
|
||||||
|
OutputSchema extends ToolDetailSchema,
|
||||||
|
> {
|
||||||
|
toolName: Name;
|
||||||
|
input: z.output<InputSchema> | null;
|
||||||
|
output: z.output<OutputSchema> | null;
|
||||||
|
}
|
||||||
|
interface ToolDetailNameWithCwdValue<
|
||||||
|
Name extends string,
|
||||||
|
InputSchema extends ToolDetailSchema,
|
||||||
|
OutputSchema extends ToolDetailSchema,
|
||||||
|
> extends ToolDetailNameValue<Name, InputSchema, OutputSchema> {
|
||||||
|
cwd?: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
export const ToolShellInputSchema = z
|
export const ToolShellInputSchema = z
|
||||||
.union([
|
.union([
|
||||||
z
|
z
|
||||||
@@ -424,11 +479,13 @@ interface ToolReadOutputValue {
|
|||||||
content?: string;
|
content?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ToolReadOutputSchema: z.ZodType<ToolReadOutputValue, z.ZodTypeDef, unknown> =
|
export const ToolReadOutputSchema: z.ZodType<ToolReadOutputValue, unknown> =
|
||||||
ToolReadOutputContentSchema;
|
ToolReadOutputContentSchema;
|
||||||
|
|
||||||
export const ToolReadOutputWithPathSchema: z.ZodType<ToolReadOutputValue, z.ZodTypeDef, unknown> =
|
export const ToolReadOutputWithPathSchema: z.ZodType<ToolReadOutputValue, unknown> = z.union([
|
||||||
z.union([ToolReadOutputContentSchema, ToolReadOutputPathSchema]);
|
ToolReadOutputContentSchema,
|
||||||
|
ToolReadOutputPathSchema,
|
||||||
|
]);
|
||||||
|
|
||||||
export const ToolWriteContentSchema = z
|
export const ToolWriteContentSchema = z
|
||||||
.object({
|
.object({
|
||||||
@@ -918,8 +975,8 @@ export function toFetchToolDetail(
|
|||||||
|
|
||||||
export function toolDetailBranchByName<
|
export function toolDetailBranchByName<
|
||||||
Name extends string,
|
Name extends string,
|
||||||
InputSchema extends z.ZodTypeAny,
|
InputSchema extends ToolDetailSchema,
|
||||||
OutputSchema extends z.ZodTypeAny,
|
OutputSchema extends ToolDetailSchema,
|
||||||
>(
|
>(
|
||||||
name: Name,
|
name: Name,
|
||||||
inputSchema: InputSchema,
|
inputSchema: InputSchema,
|
||||||
@@ -929,20 +986,23 @@ export function toolDetailBranchByName<
|
|||||||
output: z.infer<OutputSchema> | null,
|
output: z.infer<OutputSchema> | null,
|
||||||
) => ToolCallDetail | undefined,
|
) => ToolCallDetail | undefined,
|
||||||
) {
|
) {
|
||||||
const schema = z.object({
|
const shape: ToolDetailNameShape<Name, InputSchema, OutputSchema> = {
|
||||||
name: z.literal(name),
|
name: z.literal(name),
|
||||||
input: inputSchema.nullable(),
|
input: z.nullable(inputSchema),
|
||||||
output: outputSchema.nullable(),
|
output: z.nullable(outputSchema),
|
||||||
});
|
};
|
||||||
|
const schema = z.object(shape);
|
||||||
return schema.transform((value: z.infer<typeof schema>) => {
|
return schema.transform((value: z.infer<typeof schema>) => {
|
||||||
return mapper(value.input, value.output);
|
// Zod v4 drops generic unknown-valued shape fields from object output inference here.
|
||||||
|
const parsedValue = value as ToolDetailNameValue<Name, InputSchema, OutputSchema>;
|
||||||
|
return mapper(parsedValue.input, parsedValue.output);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function toolDetailBranchByToolName<
|
export function toolDetailBranchByToolName<
|
||||||
Name extends string,
|
Name extends string,
|
||||||
InputSchema extends z.ZodTypeAny,
|
InputSchema extends ToolDetailSchema,
|
||||||
OutputSchema extends z.ZodTypeAny,
|
OutputSchema extends ToolDetailSchema,
|
||||||
>(
|
>(
|
||||||
toolName: Name,
|
toolName: Name,
|
||||||
inputSchema: InputSchema,
|
inputSchema: InputSchema,
|
||||||
@@ -952,20 +1012,22 @@ export function toolDetailBranchByToolName<
|
|||||||
output: z.infer<OutputSchema> | null,
|
output: z.infer<OutputSchema> | null,
|
||||||
) => ToolCallDetail | undefined,
|
) => ToolCallDetail | undefined,
|
||||||
) {
|
) {
|
||||||
const schema = z.object({
|
const shape: ToolDetailToolNameShape<Name, InputSchema, OutputSchema> = {
|
||||||
toolName: z.literal(toolName),
|
toolName: z.literal(toolName),
|
||||||
input: inputSchema.nullable(),
|
input: z.nullable(inputSchema),
|
||||||
output: outputSchema.nullable(),
|
output: z.nullable(outputSchema),
|
||||||
});
|
};
|
||||||
|
const schema = z.object(shape);
|
||||||
return schema.transform((value: z.infer<typeof schema>) => {
|
return schema.transform((value: z.infer<typeof schema>) => {
|
||||||
return mapper(value.input, value.output);
|
const parsedValue = value as ToolDetailToolNameValue<Name, InputSchema, OutputSchema>;
|
||||||
|
return mapper(parsedValue.input, parsedValue.output);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function toolDetailBranchByNameWithCwd<
|
export function toolDetailBranchByNameWithCwd<
|
||||||
Name extends string,
|
Name extends string,
|
||||||
InputSchema extends z.ZodTypeAny,
|
InputSchema extends ToolDetailSchema,
|
||||||
OutputSchema extends z.ZodTypeAny,
|
OutputSchema extends ToolDetailSchema,
|
||||||
>(
|
>(
|
||||||
name: Name,
|
name: Name,
|
||||||
inputSchema: InputSchema,
|
inputSchema: InputSchema,
|
||||||
@@ -976,13 +1038,15 @@ export function toolDetailBranchByNameWithCwd<
|
|||||||
cwd: string | null,
|
cwd: string | null,
|
||||||
) => ToolCallDetail | undefined,
|
) => ToolCallDetail | undefined,
|
||||||
) {
|
) {
|
||||||
const schema = z.object({
|
const shape: ToolDetailNameWithCwdShape<Name, InputSchema, OutputSchema> = {
|
||||||
name: z.literal(name),
|
name: z.literal(name),
|
||||||
input: inputSchema.nullable(),
|
input: z.nullable(inputSchema),
|
||||||
output: outputSchema.nullable(),
|
output: z.nullable(outputSchema),
|
||||||
cwd: z.string().optional().nullable(),
|
cwd: z.string().optional().nullable(),
|
||||||
});
|
};
|
||||||
|
const schema = z.object(shape);
|
||||||
return schema.transform((value: z.infer<typeof schema>) => {
|
return schema.transform((value: z.infer<typeof schema>) => {
|
||||||
return mapper(value.input, value.output, value.cwd ?? null);
|
const parsedValue = value as ToolDetailNameWithCwdValue<Name, InputSchema, OutputSchema>;
|
||||||
|
return mapper(parsedValue.input, parsedValue.output, parsedValue.cwd ?? null);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -249,7 +249,7 @@ export const PersistedConfigSchema = z
|
|||||||
// localhost service proxying remains always enabled.
|
// localhost service proxying remains always enabled.
|
||||||
enabled: z.boolean().optional(),
|
enabled: z.boolean().optional(),
|
||||||
listen: z.string().optional(),
|
listen: z.string().optional(),
|
||||||
publicBaseUrl: z.string().url().optional(),
|
publicBaseUrl: z.url().optional(),
|
||||||
})
|
})
|
||||||
.strict()
|
.strict()
|
||||||
.optional(),
|
.optional(),
|
||||||
|
|||||||
@@ -544,7 +544,7 @@ const MIN_STREAMING_SEGMENT_DURATION_MS = 1000;
|
|||||||
const MIN_STREAMING_SEGMENT_BYTES = Math.round(
|
const MIN_STREAMING_SEGMENT_BYTES = Math.round(
|
||||||
PCM_BYTES_PER_MS * MIN_STREAMING_SEGMENT_DURATION_MS,
|
PCM_BYTES_PER_MS * MIN_STREAMING_SEGMENT_DURATION_MS,
|
||||||
);
|
);
|
||||||
const AgentIdSchema = z.string().uuid();
|
const AgentIdSchema = z.guid();
|
||||||
interface VoiceModeBaseConfig {
|
interface VoiceModeBaseConfig {
|
||||||
systemPrompt?: string;
|
systemPrompt?: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,9 +45,13 @@ export interface LocalSpeechSttLanguageConfig {
|
|||||||
const NumberLikeSchema = z.union([z.number(), z.string().trim().min(1)]);
|
const NumberLikeSchema = z.union([z.number(), z.string().trim().min(1)]);
|
||||||
const LanguageSchema = z.string().trim().min(1).default(DEFAULT_STT_LANGUAGE);
|
const LanguageSchema = z.string().trim().min(1).default(DEFAULT_STT_LANGUAGE);
|
||||||
|
|
||||||
const OptionalFiniteNumberSchema = NumberLikeSchema.pipe(z.coerce.number().finite()).optional();
|
const OptionalFiniteNumberSchema = NumberLikeSchema.pipe(
|
||||||
|
z.coerce.number<string | number>().finite(),
|
||||||
|
).optional();
|
||||||
|
|
||||||
const OptionalIntegerSchema = NumberLikeSchema.pipe(z.coerce.number().int()).optional();
|
const OptionalIntegerSchema = NumberLikeSchema.pipe(
|
||||||
|
z.coerce.number<string | number>().int(),
|
||||||
|
).optional();
|
||||||
|
|
||||||
const LocalSpeechResolutionSchema = z.object({
|
const LocalSpeechResolutionSchema = z.object({
|
||||||
includeProviderConfig: z.boolean(),
|
includeProviderConfig: z.boolean(),
|
||||||
|
|||||||
@@ -85,9 +85,7 @@ function resolveDefaultModelId(role: DefaultModelRole): SherpaOnnxModelId {
|
|||||||
export const DEFAULT_LOCAL_STT_MODEL = resolveDefaultModelId("stt");
|
export const DEFAULT_LOCAL_STT_MODEL = resolveDefaultModelId("stt");
|
||||||
export const DEFAULT_LOCAL_TTS_MODEL = resolveDefaultModelId("tts");
|
export const DEFAULT_LOCAL_TTS_MODEL = resolveDefaultModelId("tts");
|
||||||
|
|
||||||
function createModelIdSchema<T extends string>(
|
function createModelIdSchema<T extends string>(modelIds: readonly T[]): z.ZodType<T, string> {
|
||||||
modelIds: readonly T[],
|
|
||||||
): z.ZodType<T, z.ZodTypeDef, string> {
|
|
||||||
const validIds = new Set<string>(modelIds);
|
const validIds = new Set<string>(modelIds);
|
||||||
return z
|
return z
|
||||||
.string()
|
.string()
|
||||||
|
|||||||
@@ -21,7 +21,9 @@ const OpenAiTtsModelSchema = z.enum(["tts-1", "tts-1-hd"]);
|
|||||||
|
|
||||||
const NumberLikeSchema = z.union([z.number(), z.string().trim().min(1)]);
|
const NumberLikeSchema = z.union([z.number(), z.string().trim().min(1)]);
|
||||||
|
|
||||||
const OptionalFiniteNumberSchema = NumberLikeSchema.pipe(z.coerce.number().finite()).optional();
|
const OptionalFiniteNumberSchema = NumberLikeSchema.pipe(
|
||||||
|
z.coerce.number<string | number>().finite(),
|
||||||
|
).optional();
|
||||||
|
|
||||||
const OptionalTrimmedStringSchema = z
|
const OptionalTrimmedStringSchema = z
|
||||||
.string()
|
.string()
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ type RegistryRecord = PersistedProjectRecord | PersistedWorkspaceRecord;
|
|||||||
class FileBackedRegistry<TRecord extends RegistryRecord> {
|
class FileBackedRegistry<TRecord extends RegistryRecord> {
|
||||||
private readonly filePath: string;
|
private readonly filePath: string;
|
||||||
private readonly logger: Logger;
|
private readonly logger: Logger;
|
||||||
private readonly schema: z.ZodType<TRecord, z.ZodTypeDef, unknown>;
|
private readonly schema: z.ZodType<TRecord, unknown>;
|
||||||
private readonly getId: (record: TRecord) => string;
|
private readonly getId: (record: TRecord) => string;
|
||||||
private loaded = false;
|
private loaded = false;
|
||||||
private readonly cache = new Map<string, TRecord>();
|
private readonly cache = new Map<string, TRecord>();
|
||||||
@@ -87,7 +87,7 @@ class FileBackedRegistry<TRecord extends RegistryRecord> {
|
|||||||
constructor(options: {
|
constructor(options: {
|
||||||
filePath: string;
|
filePath: string;
|
||||||
logger: Logger;
|
logger: Logger;
|
||||||
schema: z.ZodType<TRecord, z.ZodTypeDef, unknown>;
|
schema: z.ZodType<TRecord, unknown>;
|
||||||
getId: (record: TRecord) => string;
|
getId: (record: TRecord) => string;
|
||||||
component: string;
|
component: string;
|
||||||
}) {
|
}) {
|
||||||
|
|||||||
@@ -13,8 +13,8 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@cloudflare/vite-plugin": "^1.29.1",
|
"@cloudflare/vite-plugin": "^1.29.1",
|
||||||
"@cloudflare/workers-types": "^4.20260317.1",
|
"@cloudflare/workers-types": "^4.20260317.1",
|
||||||
"@tanstack/react-router": "^1.166.4",
|
"@tanstack/react-router": "^1.170.16",
|
||||||
"@tanstack/react-start": "^1.166.4",
|
"@tanstack/react-start": "^1.168.26",
|
||||||
"framer-motion": "^12.35.2",
|
"framer-motion": "^12.35.2",
|
||||||
"github-slugger": "^2.0.0",
|
"github-slugger": "^2.0.0",
|
||||||
"lucide-react": "^1.7.0",
|
"lucide-react": "^1.7.0",
|
||||||
|
|||||||
Reference in New Issue
Block a user