feat(config): add councils schema and defaults
This commit is contained in:
+1
-1
@@ -1,3 +1,3 @@
|
||||
export { loadConfig, deepMerge } from './loader.js';
|
||||
export { persistConfig } from './persistence.js';
|
||||
export { configSchema, MODEL_PROVIDERS, type ModelProvider, type Config, type TelegramConfig, type ModelConfig, type CronJobConfig, type AgentsConfig, type CompactionConfig, type ToolProfile, type ToolOverrideConfig, type ToolsConfig, type SandboxConfig, type AgentConfigEntry, type RoutingConfig, type ServerConfig, type BackupConfig, type K8sConfig, type TtsConfig } from './schema.js';
|
||||
export { configSchema, MODEL_PROVIDERS, type ModelProvider, type Config, type TelegramConfig, type ModelConfig, type CronJobConfig, type AgentsConfig, type CompactionConfig, type ToolProfile, type ToolOverrideConfig, type ToolsConfig, type SandboxConfig, type AgentConfigEntry, type CouncilsConfig, type RoutingConfig, type ServerConfig, type BackupConfig, type K8sConfig, type TtsConfig } from './schema.js';
|
||||
|
||||
@@ -412,6 +412,71 @@ describe('configSchema — agent_configs', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('configSchema — councils', () => {
|
||||
const minimalConfig = {
|
||||
telegram: { bot_token: 'test', allowed_chat_ids: [1] },
|
||||
models: { default: { provider: 'anthropic', model: 'claude-3' } },
|
||||
};
|
||||
|
||||
it('defaults councils config with deterministic caps and group presets', () => {
|
||||
const result = configSchema.parse(minimalConfig);
|
||||
expect(result.councils.enabled).toBe(false);
|
||||
expect(result.councils.defaults.max_rounds).toBe(2);
|
||||
expect(result.councils.defaults.top_ideas_for_bridge).toBe(3);
|
||||
expect(result.councils.defaults.bridge_packet_max_chars).toBe(2500);
|
||||
expect(result.councils.groups.D.novelty_bias).toBe('low');
|
||||
expect(result.councils.groups.P.novelty_bias).toBe('high');
|
||||
expect(result.councils.meta_arbiter_agent).toBe('council_meta_arbiter');
|
||||
});
|
||||
|
||||
it('accepts explicit councils overrides', () => {
|
||||
const result = configSchema.parse({
|
||||
...minimalConfig,
|
||||
councils: {
|
||||
enabled: true,
|
||||
defaults: {
|
||||
max_rounds: 3,
|
||||
ideas_per_round: 5,
|
||||
top_ideas_for_bridge: 2,
|
||||
bridge_packet_max_chars: 1800,
|
||||
bridge_field_max_bullets: 4,
|
||||
bridge_entry_max_chars: 200,
|
||||
novelty_delta_threshold: 5,
|
||||
repetition_threshold: 80,
|
||||
},
|
||||
strict_grounding: true,
|
||||
strict_meta_validation: true,
|
||||
groups: {
|
||||
D: {
|
||||
arbiter_agent: 'd_arb',
|
||||
freethinker_agent: 'd_ft',
|
||||
group_prompt_prefix: 'd',
|
||||
novelty_bias: 'low',
|
||||
risk_tolerance: 'medium',
|
||||
forbidden_approaches: ['x'],
|
||||
},
|
||||
P: {
|
||||
arbiter_agent: 'p_arb',
|
||||
freethinker_agent: 'p_ft',
|
||||
group_prompt_prefix: 'p',
|
||||
novelty_bias: 'high',
|
||||
risk_tolerance: 'high',
|
||||
forbidden_approaches: ['y'],
|
||||
},
|
||||
},
|
||||
meta_arbiter_agent: 'meta',
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.councils.enabled).toBe(true);
|
||||
expect(result.councils.defaults.max_rounds).toBe(3);
|
||||
expect(result.councils.groups.D.arbiter_agent).toBe('d_arb');
|
||||
expect(result.councils.groups.P.freethinker_agent).toBe('p_ft');
|
||||
expect(result.councils.strict_grounding).toBe(true);
|
||||
expect(result.councils.meta_arbiter_agent).toBe('meta');
|
||||
});
|
||||
});
|
||||
|
||||
describe('configSchema — backends', () => {
|
||||
const minimalConfig = {
|
||||
telegram: { bot_token: 'test', allowed_chat_ids: [1] },
|
||||
|
||||
@@ -860,6 +860,58 @@ const agentConfigEntrySchema = z.object({
|
||||
|
||||
const agentConfigsSchema = z.record(z.string(), agentConfigEntrySchema).default({});
|
||||
|
||||
const councilsGroupConfigSchema = z.object({
|
||||
arbiter_agent: z.string().min(1),
|
||||
freethinker_agent: z.string().min(1),
|
||||
group_prompt_prefix: z.string().min(1),
|
||||
novelty_bias: z.enum(['low', 'medium', 'high']).default('medium'),
|
||||
risk_tolerance: z.enum(['low', 'medium', 'high']).default('medium'),
|
||||
forbidden_approaches: z.array(z.string().min(1)).default([]),
|
||||
});
|
||||
|
||||
const councilsSchema = z.object({
|
||||
enabled: z.boolean().default(false),
|
||||
defaults: z.object({
|
||||
max_rounds: z.number().int().min(1).max(6).default(2),
|
||||
ideas_per_round: z.number().int().min(1).max(20).default(6),
|
||||
top_ideas_for_bridge: z.number().int().min(1).max(10).default(3),
|
||||
bridge_packet_max_chars: z.number().int().min(500).max(20_000).default(2500),
|
||||
bridge_field_max_bullets: z.number().int().min(1).max(20).default(6),
|
||||
bridge_entry_max_chars: z.number().int().min(20).max(2000).default(300),
|
||||
novelty_delta_threshold: z.number().int().min(0).max(100).default(10),
|
||||
repetition_threshold: z.number().int().min(0).max(100).default(70),
|
||||
}).default({}),
|
||||
strict_grounding: z.boolean().default(false),
|
||||
strict_meta_validation: z.boolean().default(true),
|
||||
groups: z.object({
|
||||
D: councilsGroupConfigSchema.default({
|
||||
arbiter_agent: 'council_d_arbiter',
|
||||
freethinker_agent: 'council_d_freethinker',
|
||||
group_prompt_prefix: 'Optimize for feasibility and speed-to-test. Prefer boring-but-true.',
|
||||
novelty_bias: 'low',
|
||||
risk_tolerance: 'low',
|
||||
forbidden_approaches: [
|
||||
'moonshots',
|
||||
'handwavy AI claims',
|
||||
'unverified assumptions',
|
||||
],
|
||||
}),
|
||||
P: councilsGroupConfigSchema.default({
|
||||
arbiter_agent: 'council_p_arbiter',
|
||||
freethinker_agent: 'council_p_freethinker',
|
||||
group_prompt_prefix: 'Optimize for reframing and non-obvious leverage. Weird is fine; label speculation.',
|
||||
novelty_bias: 'high',
|
||||
risk_tolerance: 'high',
|
||||
forbidden_approaches: [
|
||||
'incremental tweaks',
|
||||
'obvious best practices',
|
||||
'purely conventional solutions',
|
||||
],
|
||||
}),
|
||||
}).default({}),
|
||||
meta_arbiter_agent: z.string().min(1).default('council_meta_arbiter'),
|
||||
}).default({});
|
||||
|
||||
const routingSchema = z.object({
|
||||
default_agent: z.string().optional(),
|
||||
channels: z.record(z.string(), z.string()).default({}),
|
||||
@@ -1005,6 +1057,7 @@ export const configSchema = z.object({
|
||||
tools: toolsSchema,
|
||||
sandbox: sandboxSchema,
|
||||
agent_configs: agentConfigsSchema,
|
||||
councils: councilsSchema,
|
||||
routing: routingSchema,
|
||||
intents: intentsSchema,
|
||||
routing_policy: routingPolicySchema,
|
||||
@@ -1046,6 +1099,7 @@ export type ToolOverrideConfig = z.infer<typeof toolOverrideSchema>;
|
||||
export type ToolsConfig = z.infer<typeof toolsSchema>;
|
||||
export type SandboxConfig = z.infer<typeof sandboxSchema>;
|
||||
export type AgentConfigEntry = z.infer<typeof agentConfigEntrySchema>;
|
||||
export type CouncilsConfig = z.infer<typeof councilsSchema>;
|
||||
export type RoutingConfig = z.infer<typeof routingSchema>;
|
||||
export type IntentTargetType = z.infer<typeof intentTargetTypeSchema>;
|
||||
export type IntentRuleConfig = z.infer<typeof intentRuleSchema>;
|
||||
|
||||
Reference in New Issue
Block a user