feat: add sandbox, agent_configs, and routing config schemas
This commit is contained in:
+1
-1
@@ -1,2 +1,2 @@
|
|||||||
export { loadConfig } from './loader.js';
|
export { loadConfig } from './loader.js';
|
||||||
export { configSchema, type Config, type TelegramConfig, type ModelConfig, type CronJobConfig, type AgentsConfig, type CompactionConfig, type ToolProfile, type ToolOverrideConfig, type ToolsConfig } from './schema.js';
|
export { configSchema, type Config, type TelegramConfig, type ModelConfig, type CronJobConfig, type AgentsConfig, type CompactionConfig, type ToolProfile, type ToolOverrideConfig, type ToolsConfig, type SandboxConfig, type AgentConfigEntry, type RoutingConfig } from './schema.js';
|
||||||
|
|||||||
@@ -1,6 +1,94 @@
|
|||||||
import { describe, it, expect } from 'vitest';
|
import { describe, it, expect } from 'vitest';
|
||||||
import { configSchema } from './schema.js';
|
import { configSchema } from './schema.js';
|
||||||
|
|
||||||
|
describe('configSchema — sandbox', () => {
|
||||||
|
const minimalConfig = {
|
||||||
|
telegram: { bot_token: 'test', allowed_chat_ids: [1] },
|
||||||
|
models: { default: { provider: 'anthropic', model: 'claude-3' } },
|
||||||
|
};
|
||||||
|
|
||||||
|
it('defaults sandbox to disabled', () => {
|
||||||
|
const result = configSchema.parse(minimalConfig);
|
||||||
|
expect(result.sandbox.enabled).toBe(false);
|
||||||
|
expect(result.sandbox.image).toBe('node:22-slim');
|
||||||
|
expect(result.sandbox.network).toBe('none');
|
||||||
|
expect(result.sandbox.memory_limit).toBe('512m');
|
||||||
|
expect(result.sandbox.cpu_limit).toBe('1.0');
|
||||||
|
expect(result.sandbox.timeout_seconds).toBe(300);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('accepts sandbox config', () => {
|
||||||
|
const result = configSchema.parse({
|
||||||
|
...minimalConfig,
|
||||||
|
sandbox: { enabled: true, image: 'ubuntu:24.04', network: 'bridge' },
|
||||||
|
});
|
||||||
|
expect(result.sandbox.enabled).toBe(true);
|
||||||
|
expect(result.sandbox.image).toBe('ubuntu:24.04');
|
||||||
|
expect(result.sandbox.network).toBe('bridge');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('configSchema — agent_configs', () => {
|
||||||
|
const minimalConfig = {
|
||||||
|
telegram: { bot_token: 'test', allowed_chat_ids: [1] },
|
||||||
|
models: { default: { provider: 'anthropic', model: 'claude-3' } },
|
||||||
|
};
|
||||||
|
|
||||||
|
it('defaults agent_configs to empty', () => {
|
||||||
|
const result = configSchema.parse(minimalConfig);
|
||||||
|
expect(result.agent_configs).toEqual({});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('accepts named agent configs', () => {
|
||||||
|
const result = configSchema.parse({
|
||||||
|
...minimalConfig,
|
||||||
|
agent_configs: {
|
||||||
|
assistant: {
|
||||||
|
system_prompt: 'You are helpful.',
|
||||||
|
model_tier: 'default',
|
||||||
|
tool_profile: 'messaging',
|
||||||
|
},
|
||||||
|
coder: {
|
||||||
|
model_tier: 'complex',
|
||||||
|
tool_profile: 'coding',
|
||||||
|
sandbox: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(result.agent_configs.assistant.system_prompt).toBe('You are helpful.');
|
||||||
|
expect(result.agent_configs.assistant.tool_profile).toBe('messaging');
|
||||||
|
expect(result.agent_configs.coder.sandbox).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('configSchema — routing', () => {
|
||||||
|
const minimalConfig = {
|
||||||
|
telegram: { bot_token: 'test', allowed_chat_ids: [1] },
|
||||||
|
models: { default: { provider: 'anthropic', model: 'claude-3' } },
|
||||||
|
};
|
||||||
|
|
||||||
|
it('defaults routing to empty', () => {
|
||||||
|
const result = configSchema.parse(minimalConfig);
|
||||||
|
expect(result.routing.default_agent).toBeUndefined();
|
||||||
|
expect(result.routing.channels).toEqual({});
|
||||||
|
expect(result.routing.senders).toEqual({});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('accepts routing config', () => {
|
||||||
|
const result = configSchema.parse({
|
||||||
|
...minimalConfig,
|
||||||
|
routing: {
|
||||||
|
default_agent: 'assistant',
|
||||||
|
channels: { discord: 'coder' },
|
||||||
|
senders: { 'telegram:12345': 'coder' },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(result.routing.default_agent).toBe('assistant');
|
||||||
|
expect(result.routing.channels.discord).toBe('coder');
|
||||||
|
expect(result.routing.senders['telegram:12345']).toBe('coder');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('configSchema automation', () => {
|
describe('configSchema automation', () => {
|
||||||
const baseConfig = {
|
const baseConfig = {
|
||||||
telegram: { bot_token: 'test-token', allowed_chat_ids: [123] },
|
telegram: { bot_token: 'test-token', allowed_chat_ids: [123] },
|
||||||
|
|||||||
@@ -179,6 +179,38 @@ const toolsSchema = z.object({
|
|||||||
providers: z.record(z.string(), toolOverrideSchema).default({}),
|
providers: z.record(z.string(), toolOverrideSchema).default({}),
|
||||||
}).default({});
|
}).default({});
|
||||||
|
|
||||||
|
// ── Sandbox schemas ───────────────────────────────────────────────────
|
||||||
|
|
||||||
|
const sandboxSchema = z.object({
|
||||||
|
enabled: z.boolean().default(false),
|
||||||
|
image: z.string().default('node:22-slim'),
|
||||||
|
workspace_dir: z.string().default('/workspace'),
|
||||||
|
network: z.enum(['none', 'bridge', 'host']).default('none'),
|
||||||
|
memory_limit: z.string().default('512m'),
|
||||||
|
cpu_limit: z.string().default('1.0'),
|
||||||
|
timeout_seconds: z.number().min(10).max(3600).default(300),
|
||||||
|
}).default({});
|
||||||
|
|
||||||
|
// ── Agent config + routing schemas ────────────────────────────────────
|
||||||
|
|
||||||
|
const modelTierEnum = z.enum(['fast', 'default', 'complex', 'local']);
|
||||||
|
|
||||||
|
const agentConfigEntrySchema = z.object({
|
||||||
|
system_prompt: z.string().optional(),
|
||||||
|
model_tier: modelTierEnum.optional(),
|
||||||
|
tool_profile: toolProfileEnum.optional(),
|
||||||
|
tool_overrides: toolOverrideSchema.optional(),
|
||||||
|
sandbox: z.boolean().default(false),
|
||||||
|
});
|
||||||
|
|
||||||
|
const agentConfigsSchema = z.record(z.string(), agentConfigEntrySchema).default({});
|
||||||
|
|
||||||
|
const routingSchema = z.object({
|
||||||
|
default_agent: z.string().optional(),
|
||||||
|
channels: z.record(z.string(), z.string()).default({}),
|
||||||
|
senders: z.record(z.string(), z.string()).default({}),
|
||||||
|
}).default({});
|
||||||
|
|
||||||
const promptSchema = z.object({
|
const promptSchema = z.object({
|
||||||
/** Additional directories to search for prompt template files. */
|
/** Additional directories to search for prompt template files. */
|
||||||
search_dirs: z.array(z.string()).default([]),
|
search_dirs: z.array(z.string()).default([]),
|
||||||
@@ -209,6 +241,9 @@ export const configSchema = z.object({
|
|||||||
web_search: webSearchSchema,
|
web_search: webSearchSchema,
|
||||||
prompt: promptSchema,
|
prompt: promptSchema,
|
||||||
tools: toolsSchema,
|
tools: toolsSchema,
|
||||||
|
sandbox: sandboxSchema,
|
||||||
|
agent_configs: agentConfigsSchema,
|
||||||
|
routing: routingSchema,
|
||||||
});
|
});
|
||||||
|
|
||||||
export type Config = z.infer<typeof configSchema>;
|
export type Config = z.infer<typeof configSchema>;
|
||||||
@@ -228,3 +263,6 @@ export type PromptConfig = z.infer<typeof promptSchema>;
|
|||||||
export type ToolProfile = z.infer<typeof toolProfileEnum>;
|
export type ToolProfile = z.infer<typeof toolProfileEnum>;
|
||||||
export type ToolOverrideConfig = z.infer<typeof toolOverrideSchema>;
|
export type ToolOverrideConfig = z.infer<typeof toolOverrideSchema>;
|
||||||
export type ToolsConfig = z.infer<typeof toolsSchema>;
|
export type ToolsConfig = z.infer<typeof toolsSchema>;
|
||||||
|
export type SandboxConfig = z.infer<typeof sandboxSchema>;
|
||||||
|
export type AgentConfigEntry = z.infer<typeof agentConfigEntrySchema>;
|
||||||
|
export type RoutingConfig = z.infer<typeof routingSchema>;
|
||||||
|
|||||||
Reference in New Issue
Block a user