Skip to content

Commit d0112c7

Browse files
committed
Typecheck that AgentConfig matches DynamicAgentConfig. Fix up schema
1 parent 70513aa commit d0112c7

File tree

1 file changed

+47
-17
lines changed

1 file changed

+47
-17
lines changed

common/src/types/dynamic-agent-template.ts

Lines changed: 47 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { z } from 'zod'
22
import { ALLOWED_MODEL_PREFIXES, models } from '../constants'
33
import { toolNames } from '../constants/tools'
4+
import type { AgentConfig } from '../templates/agent-template'
45

56
// Filter models to only include those that begin with allowed prefixes
67
const filteredModels = Object.values(models).filter((model) =>
@@ -11,19 +12,42 @@ if (filteredModels.length === 0) {
1112
throw new Error('No valid models found with allowed prefixes')
1213
}
1314

14-
// JSON Schema for params - supports any valid JSON schema
15-
const JsonSchemaSchema = z.record(z.any()).refine(
16-
(schema) => {
17-
// Basic validation that it looks like a JSON schema
18-
return typeof schema === 'object' && schema !== null
19-
},
20-
{ message: 'Must be a valid JSON schema object' }
15+
// Simplified JSON Schema definition - supports object schemas with nested properties
16+
const JsonSchemaSchema: z.ZodType<any> = z.lazy(() =>
17+
z
18+
.object({
19+
type: z.literal('object'),
20+
description: z.string().optional(),
21+
properties: z
22+
.record(
23+
JsonSchemaSchema.or(
24+
z
25+
.object({
26+
type: z.enum([
27+
'string',
28+
'number',
29+
'integer',
30+
'boolean',
31+
'array',
32+
]),
33+
description: z.string().optional(),
34+
enum: z.array(z.any()).optional(),
35+
})
36+
.passthrough()
37+
)
38+
)
39+
.optional(),
40+
required: z.array(z.string()).optional(),
41+
})
42+
.passthrough()
2143
)
2244

2345
// Schema for the combined inputSchema object
2446
const InputSchemaObjectSchema = z
2547
.object({
26-
prompt: JsonSchemaSchema.optional(), // Optional JSON schema for prompt validation
48+
prompt: z
49+
.object({ type: z.literal('string'), description: z.string().optional() })
50+
.optional(), // Optional JSON schema for prompt validation
2751
params: JsonSchemaSchema.optional(), // Optional JSON schema for params validation
2852
})
2953
.optional()
@@ -38,7 +62,7 @@ export type PromptField = z.infer<typeof PromptFieldSchema>
3862
// Validates the Typescript template file.
3963
export const DynamicAgentConfigSchema = z.object({
4064
id: z.string(), // The unique identifier for this agent
41-
version: z.string(),
65+
version: z.string().optional(),
4266
override: z.literal(false).optional().default(false), // Must be false for new agents, defaults to false if missing
4367

4468
// Required fields for new agents
@@ -50,17 +74,20 @@ export const DynamicAgentConfigSchema = z.object({
5074
outputSchema: JsonSchemaSchema.optional(), // Optional JSON schema for output validation
5175
includeMessageHistory: z.boolean().default(true),
5276
toolNames: z
53-
.array(z.string())
54-
.default(['end_turn'])
77+
.array(z.enum(toolNames))
78+
.optional()
79+
.default([])
5580
.refine(
5681
(tools) => {
82+
if (!tools) return true
5783
const validToolNames = toolNames as readonly string[]
5884
const invalidTools = tools.filter(
5985
(tool) => !validToolNames.includes(tool)
6086
)
6187
return invalidTools.length === 0
6288
},
6389
(tools) => {
90+
if (!tools) return { message: 'Tools array is undefined' }
6491
const validToolNames = toolNames as readonly string[]
6592
const invalidTools = tools.filter(
6693
(tool) => !validToolNames.includes(tool)
@@ -70,34 +97,37 @@ export const DynamicAgentConfigSchema = z.object({
7097
}
7198
}
7299
),
73-
subagents: z.array(z.string()).default([]),
100+
subagents: z.array(z.string()).optional().default([]),
74101
inputSchema: InputSchemaObjectSchema,
75102
parentInstructions: z.record(z.string(), z.string()).optional(),
76103

77104
// Prompts
78105
parentPrompt: z.string().optional(),
79-
systemPrompt: PromptFieldSchema,
80-
instructionsPrompt: PromptFieldSchema,
81-
stepPrompt: PromptFieldSchema,
106+
systemPrompt: z.string().optional(),
107+
instructionsPrompt: z.string().optional(),
108+
stepPrompt: z.string(),
82109

83110
// Optional generator function for programmatic agents
84111
handleSteps: z
85112
.function(
86113
z.tuple([
87114
z.object({
88115
agentState: z.any(),
89-
prompt: z.string(),
116+
prompt: z.string().optional(),
90117
params: z.any(),
91118
}),
92119
]),
93120
z.any()
94121
)
95122
.optional(),
96123
})
97-
98124
export type DynamicAgentConfig = z.input<typeof DynamicAgentConfigSchema>
99125
export type DynamicAgentConfigParsed = z.infer<typeof DynamicAgentConfigSchema>
100126

127+
// Checks that the AgentConfig and DynamicAgentConfig types are compatible
128+
// NOTE TO LLM: Don't remove this line!
129+
const _typecheck: AgentConfig = {} as DynamicAgentConfig
130+
101131
export const DynamicAgentTemplateSchema = DynamicAgentConfigSchema.extend({
102132
systemPrompt: z.string(),
103133
instructionsPrompt: z.string(),

0 commit comments

Comments
 (0)