Migrate workspace schemas to zod 4

This commit is contained in:
Mohamed Boudra
2026-06-08 13:59:44 +07:00
parent 99876d37f3
commit ed8a6fefad
60 changed files with 378 additions and 342 deletions
+1 -1
View File
@@ -26,7 +26,7 @@
"test": "vitest run"
},
"dependencies": {
"zod": "^3.23.8"
"zod": "^4.1.8"
},
"devDependencies": {
"@types/node": "^20.9.0",
+168 -167
View File
@@ -182,7 +182,7 @@ const AgentSelectOptionSchema = z.object({
label: z.string(),
description: z.string().optional(),
isDefault: z.boolean().optional(),
metadata: z.record(z.unknown()).optional(),
metadata: z.record(z.string(), z.unknown()).optional(),
});
export const AgentFeatureToggleSchema = z.object({
@@ -218,7 +218,7 @@ const AgentModelDefinitionSchema: z.ZodType<AgentModelDefinition> = z
label: z.string(),
description: z.string().optional(),
isDefault: z.boolean().optional(),
metadata: z.record(z.unknown()).optional(),
metadata: z.record(z.string(), z.unknown()).optional(),
thinkingOptions: z.array(AgentSelectOptionSchema).optional(),
defaultThinkingOptionId: z.string().optional(),
})
@@ -265,21 +265,21 @@ const McpStdioServerConfigSchema = z.object({
type: z.literal("stdio"),
command: z.string(),
args: z.array(z.string()).optional(),
env: z.record(z.string()).optional(),
env: z.record(z.string(), z.string()).optional(),
alwaysLoad: z.boolean().optional(),
});
const McpHttpServerConfigSchema = z.object({
type: z.literal("http"),
url: z.string(),
headers: z.record(z.string()).optional(),
headers: z.record(z.string(), z.string()).optional(),
alwaysLoad: z.boolean().optional(),
});
const McpSseServerConfigSchema = z.object({
type: z.literal("sse"),
url: z.string(),
headers: z.record(z.string()).optional(),
headers: z.record(z.string(), z.string()).optional(),
alwaysLoad: z.boolean().optional(),
});
@@ -295,7 +295,7 @@ const AgentSessionConfigSchema = z.object({
modeId: z.string().optional(),
model: 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(),
approvalPolicy: z.string().optional(),
sandboxMode: z.string().optional(),
@@ -303,16 +303,16 @@ const AgentSessionConfigSchema = z.object({
webSearch: z.boolean().optional(),
extra: z
.object({
codex: z.record(z.unknown()).optional(),
claude: z.record(z.unknown()).optional(),
codex: z.record(z.string(), z.unknown()).optional(),
claude: z.record(z.string(), z.unknown()).optional(),
})
.partial()
.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({
id: z.string(),
label: z.string(),
@@ -325,7 +325,7 @@ export const AgentPermissionResponseSchema: z.ZodType<AgentPermissionResponse> =
z.object({
behavior: z.literal("allow"),
selectedActionId: z.string().optional(),
updatedInput: z.record(z.unknown()).optional(),
updatedInput: z.record(z.string(), z.unknown()).optional(),
updatedPermissions: z.array(AgentPermissionUpdateSchema).optional(),
}),
z.object({
@@ -336,22 +336,18 @@ export const AgentPermissionResponseSchema: z.ZodType<AgentPermissionResponse> =
}),
]);
export const AgentPermissionRequestPayloadSchema: z.ZodType<
AgentPermissionRequest,
z.ZodTypeDef,
unknown
> = z.object({
export const AgentPermissionRequestPayloadSchema: z.ZodType<AgentPermissionRequest> = z.object({
id: z.string(),
provider: AgentProviderSchema,
name: z.string(),
kind: z.enum(["tool", "plan", "question", "mode", "other"]),
title: z.string().optional(),
description: z.string().optional(),
input: z.record(z.unknown()).optional(),
input: z.record(z.string(), z.unknown()).optional(),
detail: z.lazy(() => ToolCallDetailPayloadSchema).optional(),
suggestions: z.array(AgentPermissionUpdateSchema).optional(),
actions: z.array(AgentPermissionActionSchema).optional(),
metadata: z.record(z.unknown()).optional(),
metadata: z.record(z.string(), z.unknown()).optional(),
});
const UnknownValueSchema = z.union([
@@ -390,102 +386,101 @@ const WorktreeSetupDetailPayloadSchema = z.object({
truncated: z.boolean().optional(),
});
const ToolCallDetailPayloadSchema: z.ZodType<ToolCallDetail, z.ZodTypeDef, unknown> =
z.discriminatedUnion("type", [
WorktreeSetupDetailPayloadSchema,
z.object({
type: z.literal("shell"),
command: z.string(),
cwd: z.string().optional(),
output: z.string().optional(),
exitCode: z.number().nullable().optional(),
}),
z.object({
type: z.literal("read"),
filePath: z.string(),
content: z.string().optional(),
offset: z.number().optional(),
limit: z.number().optional(),
}),
z.object({
type: z.literal("edit"),
filePath: z.string(),
oldString: z.string().optional(),
newString: z.string().optional(),
unifiedDiff: z.string().optional(),
}),
z.object({
type: z.literal("write"),
filePath: z.string(),
content: z.string().optional(),
}),
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(),
}),
)
.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(),
}),
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(),
}),
z.object({
type: z.literal("sub_agent"),
subAgentType: z.string().optional(),
description: z.string().optional(),
childSessionId: z.string().optional(),
log: z.string(),
// Compat cruft for clients <= 0.1.65-beta.3 that required this field. Producers still
// emit `[]`; nothing reads it. Drop the field (and the `[]` emissions) once those
// clients are no longer in the field.
actions: z
.array(
z.object({
index: z.number().int().positive(),
toolName: z.string(),
summary: z.string().optional(),
}),
)
.optional(),
}),
z.object({
type: z.literal("plain_text"),
label: z.string().optional(),
text: z.string().optional(),
icon: z.enum(TOOL_CALL_ICON_NAMES).optional(),
}),
z.object({
type: z.literal("plan"),
text: z.string(),
}),
z.object({
type: z.literal("unknown"),
input: UnknownValueSchema,
output: UnknownValueSchema,
}),
]);
const ToolCallDetailPayloadSchema: z.ZodType<ToolCallDetail> = z.discriminatedUnion("type", [
WorktreeSetupDetailPayloadSchema,
z.object({
type: z.literal("shell"),
command: z.string(),
cwd: z.string().optional(),
output: z.string().optional(),
exitCode: z.number().nullable().optional(),
}),
z.object({
type: z.literal("read"),
filePath: z.string(),
content: z.string().optional(),
offset: z.number().optional(),
limit: z.number().optional(),
}),
z.object({
type: z.literal("edit"),
filePath: z.string(),
oldString: z.string().optional(),
newString: z.string().optional(),
unifiedDiff: z.string().optional(),
}),
z.object({
type: z.literal("write"),
filePath: z.string(),
content: z.string().optional(),
}),
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(),
}),
)
.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(),
}),
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(),
}),
z.object({
type: z.literal("sub_agent"),
subAgentType: z.string().optional(),
description: z.string().optional(),
childSessionId: z.string().optional(),
log: z.string(),
// Compat cruft for clients <= 0.1.65-beta.3 that required this field. Producers still
// emit `[]`; nothing reads it. Drop the field (and the `[]` emissions) once those
// clients are no longer in the field.
actions: z
.array(
z.object({
index: z.number().int().positive(),
toolName: z.string(),
summary: z.string().optional(),
}),
)
.optional(),
}),
z.object({
type: z.literal("plain_text"),
label: z.string().optional(),
text: z.string().optional(),
icon: z.enum(TOOL_CALL_ICON_NAMES).optional(),
}),
z.object({
type: z.literal("plan"),
text: z.string(),
}),
z.object({
type: z.literal("unknown"),
input: UnknownValueSchema,
output: UnknownValueSchema,
}),
]);
const ToolCallBasePayloadSchema = z.object({
type: z.literal("tool_call"),
@@ -515,51 +510,49 @@ const ToolCallCanceledPayloadSchema = ToolCallBasePayloadSchema.extend({
error: z.null(),
});
const ToolCallTimelineItemPayloadSchema: z.ZodType<ToolCallTimelineItem, z.ZodTypeDef, unknown> =
z.union([
ToolCallRunningPayloadSchema,
ToolCallCompletedPayloadSchema,
ToolCallFailedPayloadSchema,
ToolCallCanceledPayloadSchema,
]);
const ToolCallTimelineItemPayloadSchema: z.ZodType<ToolCallTimelineItem> = z.union([
ToolCallRunningPayloadSchema,
ToolCallCompletedPayloadSchema,
ToolCallFailedPayloadSchema,
ToolCallCanceledPayloadSchema,
]);
export const AgentTimelineItemPayloadSchema: z.ZodType<AgentTimelineItem, z.ZodTypeDef, unknown> =
z.union([
z.object({
type: z.literal("user_message"),
text: z.string(),
messageId: z.string().optional(),
}),
z.object({
type: z.literal("assistant_message"),
text: z.string(),
messageId: z.string().optional(),
}),
z.object({
type: z.literal("reasoning"),
text: z.string(),
}),
ToolCallTimelineItemPayloadSchema,
z.object({
type: z.literal("todo"),
items: z.array(
z.object({
text: z.string(),
completed: z.boolean(),
}),
),
}),
z.object({
type: z.literal("error"),
message: z.string(),
}),
z.object({
type: z.literal("compaction"),
status: z.enum(["loading", "completed"]),
trigger: z.enum(["auto", "manual"]).optional(),
preTokens: z.number().optional(),
}),
]);
export const AgentTimelineItemPayloadSchema: z.ZodType<AgentTimelineItem> = z.union([
z.object({
type: z.literal("user_message"),
text: z.string(),
messageId: z.string().optional(),
}),
z.object({
type: z.literal("assistant_message"),
text: z.string(),
messageId: z.string().optional(),
}),
z.object({
type: z.literal("reasoning"),
text: z.string(),
}),
ToolCallTimelineItemPayloadSchema,
z.object({
type: z.literal("todo"),
items: z.array(
z.object({
text: z.string(),
completed: z.boolean(),
}),
),
}),
z.object({
type: z.literal("error"),
message: z.string(),
}),
z.object({
type: z.literal("compaction"),
status: z.enum(["loading", "completed"]),
trigger: z.enum(["auto", "manual"]).optional(),
preTokens: z.number().optional(),
}),
]);
export const AgentStreamEventPayloadSchema = z.discriminatedUnion("type", [
z.object({
@@ -734,7 +727,7 @@ export const AudioPlayedMessageSchema = 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(),
statuses: z.array(AgentStatusSchema).optional(),
includeArchived: z.boolean().optional(),
@@ -765,7 +758,7 @@ export const UpdateAgentRequestMessageSchema = z.object({
type: z.literal("update_agent_request"),
agentId: z.string(),
name: z.string().optional(),
labels: z.record(z.string()).optional(),
labels: z.record(z.string(), z.string()).optional(),
requestId: z.string(),
});
@@ -1108,18 +1101,18 @@ export type CreateAgentWorktreeTarget = z.infer<typeof CreateAgentWorktreeTarget
export const CreateAgentRequestMessageSchema = z.object({
type: z.literal("create_agent_request"),
config: AgentSessionConfigSchema,
env: z.record(z.string()).optional(),
env: z.record(z.string(), z.string()).optional(),
workspaceId: z.string().optional(),
worktreeName: z.string().optional(),
initialPrompt: 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(),
attachments: AgentAttachmentsSchema,
git: GitSetupOptionsSchema.optional(),
worktree: CreateAgentWorktreeTargetSchema.optional(),
autoArchive: z.boolean().optional(),
labels: z.record(z.string()).default({}),
labels: z.record(z.string(), z.string()).default({}),
requestId: z.string(),
});
@@ -1175,7 +1168,7 @@ export const ImportAgentRequestMessageSchema = z.object({
sessionId: z.string().optional(),
providerHandleId: z.string().optional(),
cwd: z.string().optional(),
labels: z.record(z.string()).optional(),
labels: z.record(z.string(), z.string()).optional(),
requestId: z.string(),
});
@@ -1726,7 +1719,7 @@ const ListCommandsDraftConfigSchema = z.object({
modeId: z.string().optional(),
model: 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({
@@ -1981,7 +1974,7 @@ export const ActivityLogPayloadSchema = z.object({
timestamp: z.coerce.date(),
type: z.enum(["transcript", "assistant", "tool_call", "tool_result", "error", "system"]),
content: z.string(),
metadata: z.record(z.unknown()).optional(),
metadata: z.record(z.string(), z.unknown()).optional(),
});
export const ActivityLogMessageSchema = z.object({
@@ -3256,7 +3249,15 @@ export const PullRequestTimelineResponseSchema = z.object({
githubFeaturesEnabled: z.boolean().optional().default(true),
})
.optional()
.default({}),
.default({
cwd: "",
prNumber: null,
items: [],
truncated: false,
error: null,
requestId: "",
githubFeaturesEnabled: true,
}),
});
export const CheckoutSwitchBranchResponseSchema = z.object({
+4 -4
View File
@@ -24,7 +24,7 @@ export const ProviderCommandSchema = z.discriminatedUnion("mode", [
export const ProviderRuntimeSettingsSchema = z.object({
command: ProviderCommandSchema.optional(),
env: z.record(z.string()).optional(),
env: z.record(z.string(), z.string()).optional(),
disallowedTools: z.array(z.string()).optional(),
});
@@ -48,7 +48,7 @@ export const ProviderOverrideSchema = z.object({
label: z.string().optional(),
description: z.string().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(),
models: z.array(ProviderProfileModelSchema).optional(),
additionalModels: z.array(ProviderProfileModelSchema).optional(),
disallowedTools: z.array(z.string()).optional(),
@@ -60,7 +60,7 @@ const BUILTIN_PROVIDER_IDS = ["claude", "codex", "copilot", "opencode", "pi"] as
const PROVIDER_ID_PATTERN = /^[a-z][a-z0-9-]*$/;
export const ProviderOverridesSchema = z
.record(ProviderOverrideSchema)
.record(z.string(), ProviderOverrideSchema)
.superRefine((providers, ctx) => {
const builtinProviderIdSet = new Set<string>(BUILTIN_PROVIDER_IDS);
const validExtendsValues = new Set<string>([...BUILTIN_PROVIDER_IDS, "acp"]);
@@ -110,7 +110,7 @@ export const ProviderOverridesSchema = z
});
export const AgentProviderRuntimeSettingsMapSchema = z
.record(ProviderRuntimeSettingsSchema)
.record(z.string(), ProviderRuntimeSettingsSchema)
.superRefine((providers, ctx) => {
for (const providerId of Object.keys(providers)) {
const parsedProviderId = AgentProviderSchema.safeParse(providerId);
+4 -4
View File
@@ -35,16 +35,16 @@ export const ScheduleTargetSchema = z.discriminatedUnion("type", [
sandboxMode: z.string().trim().min(1).optional(),
networkAccess: z.boolean().optional(),
webSearch: z.boolean().optional(),
featureValues: z.record(z.unknown()).optional(),
featureValues: z.record(z.string(), z.unknown()).optional(),
extra: z
.object({
codex: z.record(z.unknown()).optional(),
claude: z.record(z.unknown()).optional(),
codex: z.record(z.string(), z.unknown()).optional(),
claude: z.record(z.string(), z.unknown()).optional(),
})
.partial()
.optional(),
systemPrompt: z.string().optional(),
mcpServers: z.record(z.unknown()).optional(),
mcpServers: z.record(z.string(), z.unknown()).optional(),
}),
}),
]);