feat: add P2 features — retry policy, prompt templating, usage tracking, tech debt cleanup

- Extract shared splitMessage() into channels/utils.ts (dedup 4 adapters)
- Add Slack user name resolution with caching (users.info API)
- Add withRetry() with exponential backoff + jitter, isRetryable() filter
- Wire retry config into ModelRouter.chat() (non-streaming only)
- Add assembleSystemPrompt() multi-file template system (SOUL/AGENTS/IDENTITY/USER/TOOLS.md)
- Add usage tracking accumulators in NativeAgent + AgentOrchestrator
- Add estimateCost() with per-model pricing table
- Add /usage TUI command with full usage report formatting
- Add retrySchema and promptSchema to config schema

Tests: 569 passing, typecheck clean
This commit is contained in:
William Valentin
2026-02-06 15:12:35 -08:00
parent de68deb1b2
commit 4316dbd3be
24 changed files with 902 additions and 143 deletions
+22
View File
@@ -146,6 +146,14 @@ const processSchema = z.object({
buffer_size: z.number().min(1024).max(1048576).default(65536),
}).default({});
const retrySchema = z.object({
enabled: z.boolean().default(true),
max_retries: z.number().min(0).max(10).default(3),
initial_delay_ms: z.number().min(100).max(60000).default(1000),
backoff_multiplier: z.number().min(1).max(5).default(2),
max_delay_ms: z.number().min(1000).max(120000).default(30000),
}).default({});
const webSearchSchema = z.object({
provider: z.enum(['brave', 'searxng']).default('brave'),
api_key: z.string().optional(),
@@ -153,6 +161,16 @@ const webSearchSchema = z.object({
max_results: z.number().min(1).max(20).default(5),
}).default({});
const promptSchema = z.object({
/** Additional directories to search for prompt template files. */
search_dirs: z.array(z.string()).default([]),
/** Extra named sections to include in the system prompt. */
extra_sections: z.array(z.object({
name: z.string(),
content: z.string(),
})).default([]),
}).default({});
export const configSchema = z.object({
telegram: telegramSchema,
discord: discordSchema,
@@ -169,7 +187,9 @@ export const configSchema = z.object({
compaction: compactionSchema,
memory: memorySchema,
process: processSchema,
retry: retrySchema,
web_search: webSearchSchema,
prompt: promptSchema,
});
export type Config = z.infer<typeof configSchema>;
@@ -184,3 +204,5 @@ export type ProcessConfig = z.infer<typeof processSchema>;
export type DiscordConfig = z.infer<typeof discordSchema>;
export type SlackConfig = z.infer<typeof slackSchema>;
export type WhatsAppConfig = z.infer<typeof whatsappSchema>;
export type RetryPolicyConfig = z.infer<typeof retrySchema>;
export type PromptConfig = z.infer<typeof promptSchema>;