@circuitwall/jarela 0.14.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (164) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/app-path-routes-manifest.json +1 -1
  3. package/.next/standalone/.next/build-manifest.json +2 -2
  4. package/.next/standalone/.next/prerender-manifest.json +3 -3
  5. package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  6. package/.next/standalone/.next/server/app/_global-error.html +1 -1
  7. package/.next/standalone/.next/server/app/_global-error.rsc +1 -1
  8. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  9. package/.next/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  10. package/.next/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  11. package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  12. package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  13. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  14. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  15. package/.next/standalone/.next/server/app/_not-found.html +2 -2
  16. package/.next/standalone/.next/server/app/_not-found.rsc +2 -2
  17. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
  18. package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  19. package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
  20. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  21. package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  22. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  23. package/.next/standalone/.next/server/app/api/v1/agents/[id]/route.js +6 -1
  24. package/.next/standalone/.next/server/app/api/v1/agents/[id]/route.js.map +1 -1
  25. package/.next/standalone/.next/server/app/api/v1/agents/route.js +6 -1
  26. package/.next/standalone/.next/server/app/api/v1/agents/route.js.map +1 -1
  27. package/.next/standalone/.next/server/app/api/v1/bridges/[id]/route.js +9 -1
  28. package/.next/standalone/.next/server/app/api/v1/bridges/[id]/route.js.map +1 -1
  29. package/.next/standalone/.next/server/app/api/v1/bridges/route.js +9 -1
  30. package/.next/standalone/.next/server/app/api/v1/bridges/route.js.map +1 -1
  31. package/.next/standalone/.next/server/app/api/v1/builtin-tools/route.js +36 -29
  32. package/.next/standalone/.next/server/app/api/v1/builtin-tools/route.js.map +1 -1
  33. package/.next/standalone/.next/server/app/api/v1/events/route.js +7 -1
  34. package/.next/standalone/.next/server/app/api/v1/events/route.js.map +1 -1
  35. package/.next/standalone/.next/server/app/api/v1/extensions/route.js +3 -3
  36. package/.next/standalone/.next/server/app/api/v1/extensions/route.js.map +1 -1
  37. package/.next/standalone/.next/server/app/api/v1/extensions/tools/[name]/secrets/route.js +4 -4
  38. package/.next/standalone/.next/server/app/api/v1/extensions/tools/[name]/secrets/route.js.map +1 -1
  39. package/.next/standalone/.next/server/app/api/v1/health/route.js +7 -1
  40. package/.next/standalone/.next/server/app/api/v1/health/route.js.map +1 -1
  41. package/.next/standalone/.next/server/app/api/v1/mcp-servers/[name]/route.js +9 -1
  42. package/.next/standalone/.next/server/app/api/v1/mcp-servers/[name]/route.js.map +1 -1
  43. package/.next/standalone/.next/server/app/api/v1/mcp-servers/route.js +9 -1
  44. package/.next/standalone/.next/server/app/api/v1/mcp-servers/route.js.map +1 -1
  45. package/.next/standalone/.next/server/app/api/v1/models/route.js +6 -1
  46. package/.next/standalone/.next/server/app/api/v1/models/route.js.map +1 -1
  47. package/.next/standalone/.next/server/app/api/v1/page-capture/route.js +7 -1
  48. package/.next/standalone/.next/server/app/api/v1/page-capture/route.js.map +1 -1
  49. package/.next/standalone/.next/server/app/api/v1/pending-actions/[id]/approve/route.js +14 -7
  50. package/.next/standalone/.next/server/app/api/v1/pending-actions/[id]/approve/route.js.map +1 -1
  51. package/.next/standalone/.next/server/app/api/v1/providers/[provider]/models/route.js +28 -0
  52. package/.next/standalone/.next/server/app/api/v1/providers/[provider]/models/route.js.map +1 -1
  53. package/.next/standalone/.next/server/app/api/v1/providers/route.js +7 -1
  54. package/.next/standalone/.next/server/app/api/v1/providers/route.js.map +1 -1
  55. package/.next/standalone/.next/server/app/api/v1/threads/[thread_id]/route.js +16 -2
  56. package/.next/standalone/.next/server/app/api/v1/threads/[thread_id]/route.js.map +1 -1
  57. package/.next/standalone/.next/server/app/api/v1/threads/[thread_id]/run/route.js +8 -1
  58. package/.next/standalone/.next/server/app/api/v1/threads/[thread_id]/run/route.js.map +1 -1
  59. package/.next/standalone/.next/server/app/api/v1/threads/route.js +6 -1
  60. package/.next/standalone/.next/server/app/api/v1/threads/route.js.map +1 -1
  61. package/.next/standalone/.next/server/app/api/v1/tools/route.js +10 -3
  62. package/.next/standalone/.next/server/app/api/v1/tools/route.js.map +1 -1
  63. package/.next/standalone/.next/server/app/index.html +2 -2
  64. package/.next/standalone/.next/server/app/index.rsc +3 -3
  65. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  66. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +3 -3
  67. package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  68. package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +2 -2
  69. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  70. package/.next/standalone/.next/server/app/page.js +56 -0
  71. package/.next/standalone/.next/server/app/page.js.map +1 -1
  72. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  73. package/.next/standalone/.next/server/app/setup/page_client-reference-manifest.js +1 -1
  74. package/.next/standalone/.next/server/app/setup.html +1 -1
  75. package/.next/standalone/.next/server/app/setup.rsc +2 -2
  76. package/.next/standalone/.next/server/app/setup.segments/_full.segment.rsc +2 -2
  77. package/.next/standalone/.next/server/app/setup.segments/_head.segment.rsc +1 -1
  78. package/.next/standalone/.next/server/app/setup.segments/_index.segment.rsc +2 -2
  79. package/.next/standalone/.next/server/app/setup.segments/_tree.segment.rsc +2 -2
  80. package/.next/standalone/.next/server/app/setup.segments/setup/__PAGE__.segment.rsc +1 -1
  81. package/.next/standalone/.next/server/app/setup.segments/setup.segment.rsc +1 -1
  82. package/.next/standalone/.next/server/app-paths-manifest.json +1 -1
  83. package/.next/standalone/.next/server/chunks/1683.js +2 -2
  84. package/.next/standalone/.next/server/chunks/2082.js +122 -13
  85. package/.next/standalone/.next/server/chunks/2082.js.map +1 -1
  86. package/.next/standalone/.next/server/chunks/210.js +3 -3
  87. package/.next/standalone/.next/server/chunks/210.js.map +1 -1
  88. package/.next/standalone/.next/server/chunks/239.js +1902 -1487
  89. package/.next/standalone/.next/server/chunks/239.js.map +1 -1
  90. package/.next/standalone/.next/server/chunks/2447.js +9 -1
  91. package/.next/standalone/.next/server/chunks/2447.js.map +1 -1
  92. package/.next/standalone/.next/server/chunks/423.js +125 -16
  93. package/.next/standalone/.next/server/chunks/423.js.map +1 -1
  94. package/.next/standalone/.next/server/chunks/4631.js +36 -29
  95. package/.next/standalone/.next/server/chunks/4631.js.map +1 -1
  96. package/.next/standalone/.next/server/chunks/5937.js +3 -2
  97. package/.next/standalone/.next/server/chunks/5937.js.map +1 -1
  98. package/.next/standalone/.next/server/chunks/{947.js → 8866.js} +11321 -10883
  99. package/.next/standalone/.next/server/chunks/8866.js.map +1 -0
  100. package/.next/standalone/.next/server/chunks/9032.js +3 -3
  101. package/.next/standalone/.next/server/chunks/9032.js.map +1 -1
  102. package/.next/standalone/.next/server/middleware-build-manifest.js +2 -2
  103. package/.next/standalone/.next/server/middleware.js +122 -13
  104. package/.next/standalone/.next/server/pages/404.html +2 -2
  105. package/.next/standalone/.next/server/pages/500.html +1 -1
  106. package/.next/standalone/.next/server/proxy.js.map +1 -1
  107. package/.next/standalone/.next/server/server-reference-manifest.json +1 -1
  108. package/.next/standalone/.next/static/chunks/app/{page-473b39ec30c7f569.js → page-a7cae65f235e2942.js} +57 -1
  109. package/.next/standalone/.next/static/chunks/app/page-a7cae65f235e2942.js.map +1 -0
  110. package/.next/standalone/.next/static/css/{6f8b1a84bcbcd467.css → e57bdbbbb5a05779.css} +2 -2
  111. package/.next/standalone/.next/static/css/e57bdbbbb5a05779.css.map +1 -0
  112. package/.next/standalone/package.json +9 -1
  113. package/CHANGELOG.md +90 -0
  114. package/README.md +30 -2
  115. package/api/types.ts +8 -0
  116. package/app/api/v1/agents/[id]/route.ts +7 -0
  117. package/app/api/v1/agents/route.ts +7 -0
  118. package/app/api/v1/events/route.ts +8 -0
  119. package/app/api/v1/extensions/route.ts +2 -2
  120. package/app/api/v1/extensions/tools/[name]/secrets/route.ts +3 -3
  121. package/app/api/v1/health/route.ts +8 -0
  122. package/app/api/v1/models/route.ts +7 -0
  123. package/app/api/v1/page-capture/route.ts +8 -0
  124. package/app/api/v1/providers/route.ts +8 -0
  125. package/app/api/v1/threads/[thread_id]/route.ts +8 -0
  126. package/app/api/v1/threads/[thread_id]/run/route.ts +9 -0
  127. package/app/api/v1/threads/route.ts +7 -0
  128. package/app/api/v1/tools/route.ts +9 -0
  129. package/components/chat/ContextUsageBar.tsx +44 -0
  130. package/lib/agents/llm.ts +25 -2
  131. package/lib/agents/run-thread.ts +13 -1
  132. package/lib/agents/stream-collector.ts +9 -1
  133. package/lib/api/serializers.test.ts +15 -0
  134. package/lib/api/serializers.ts +8 -0
  135. package/lib/db/migrations.ts +15 -0
  136. package/lib/health/runner.test.ts +24 -2
  137. package/lib/mcp/registry.ts +14 -6
  138. package/lib/providers/anthropic.test.ts +95 -0
  139. package/lib/providers/anthropic.ts +106 -10
  140. package/lib/providers/jarela-chat-model.ts +9 -1
  141. package/lib/providers/known-context-windows.ts +21 -0
  142. package/lib/providers/types.ts +21 -1
  143. package/lib/stores/message-usage.test.ts +34 -0
  144. package/lib/stores/message-usage.ts +15 -3
  145. package/lib/stores/pricing.test.ts +52 -0
  146. package/lib/stores/pricing.ts +26 -1
  147. package/lib/tools/builtins.ts +4 -0
  148. package/lib/tools/extension-surfaces.test.ts +79 -0
  149. package/lib/tools/extension-surfaces.ts +153 -0
  150. package/lib/tools/index.ts +27 -8
  151. package/lib/tools/list-tools.test.ts +76 -0
  152. package/lib/tools/list-tools.ts +84 -0
  153. package/lib/tools/mcp-servers-info.test.ts +73 -0
  154. package/lib/tools/mcp-servers-info.ts +71 -0
  155. package/lib/tools/providers-info.test.ts +73 -0
  156. package/lib/tools/providers-info.ts +106 -0
  157. package/lib/tools/registry.ts +36 -25
  158. package/lib/tools/types.ts +13 -0
  159. package/package.json +9 -1
  160. package/.next/standalone/.next/server/chunks/947.js.map +0 -1
  161. package/.next/standalone/.next/static/chunks/app/page-473b39ec30c7f569.js.map +0 -1
  162. package/.next/standalone/.next/static/css/6f8b1a84bcbcd467.css.map +0 -1
  163. /package/.next/standalone/.next/static/{T0p2VVPsJPj44rwbmjaFb → d_vhp-lJqfdjRFpnLVIqZ}/_buildManifest.js +0 -0
  164. /package/.next/standalone/.next/static/{T0p2VVPsJPj44rwbmjaFb → d_vhp-lJqfdjRFpnLVIqZ}/_ssgManifest.js +0 -0
@@ -468,6 +468,12 @@ function mcpServerToResponse(r) {
468
468
  * chat panel's `ContextUsageBar` consumes. Returns `null` for messages
469
469
  * that have no snapshot (user turns and legacy assistant rows recorded
470
470
  * before the per-turn snapshot landed in ADR-0041).
471
+ *
472
+ * Anthropic prompt-cache tokens (PR #181 + the cache-fidelity follow-up)
473
+ * are surfaced as additive fields so future UI work can render a
474
+ * "served from cache" badge without another wire change. Both are
475
+ * `null` for rows that predate cache plumbing or for providers that
476
+ * don't expose a cache breakdown.
471
477
  */ function messageUsageToResponse(u) {
472
478
  if (!u) return null;
473
479
  return {
@@ -480,7 +486,9 @@ function mcpServerToResponse(r) {
480
486
  hot_budget_tokens: u.hot_budget_tokens,
481
487
  warm_budget_tokens: u.warm_budget_tokens,
482
488
  facts_budget_tokens: u.facts_budget_tokens,
483
- context_window_tokens: u.context_window_tokens
489
+ context_window_tokens: u.context_window_tokens,
490
+ cache_creation_input_tokens: u.cache_creation_input_tokens,
491
+ cache_read_input_tokens: u.cache_read_input_tokens
484
492
  };
485
493
  }
486
494
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"2447.js","mappings":"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","sources":["webpack://@circuitwall/jarela/./app/api/v1/agents/payload.ts","webpack://@circuitwall/jarela/./lib/api/responses.ts","webpack://@circuitwall/jarela/./lib/stores/agent-configs.ts","webpack://@circuitwall/jarela/./lib/utils/json.ts","webpack://@circuitwall/jarela/./lib/api/serializers.ts"],"sourcesContent":["import type { MbtiType } from \"@/lib/agents/adaptive-persona-presets\";\nimport type { AgentConfigRow, UpsertAgentInput } from \"@/lib/stores/agent-configs\";\nimport type { AgentConfigIn } from \"@/api/types\";\nimport { parseJsonSafe } from \"@/lib/utils/json\";\n\nexport type AgentCreateBody = AgentConfigIn;\nexport type AgentUpdateBody = Partial<AgentConfigIn>;\n\nexport function toCreateAgentInput(id: string, body: AgentCreateBody): UpsertAgentInput {\n return {\n id,\n name: body.name.trim(),\n icon: body.icon ?? null,\n identity: body.identity ?? \"\",\n instructions: body.instructions ?? \"\",\n tools: body.tools ?? [],\n model_config_name: body.model_config_name ?? null,\n is_default: body.is_default,\n history_limit: body.history_limit,\n history_window_hours: body.history_window_hours,\n never_reply: body.never_reply,\n adaptive_persona_enabled: body.adaptive_persona_enabled,\n adaptive_persona_strength: body.adaptive_persona_strength,\n adaptive_empathy: body.adaptive_empathy,\n adaptive_expressiveness: body.adaptive_expressiveness,\n adaptive_verbosity: body.adaptive_verbosity,\n adaptive_mbti: body.adaptive_mbti as MbtiType | undefined,\n voice_enabled: body.voice_enabled,\n voice_model: body.voice_model,\n voice_name: body.voice_name,\n voice_stt_model: body.voice_stt_model,\n voice_auto_speak: body.voice_auto_speak,\n harness_id: body.harness_id,\n delegate_targets: body.delegate_targets,\n context_tier_proportions: body.context_tier_proportions,\n anti_hallucination_mode: body.anti_hallucination_mode,\n anti_hallucination_model_config: body.anti_hallucination_model_config,\n require_source_links: body.require_source_links,\n };\n}\n\nexport function toUpdateAgentInput(\n id: string,\n body: AgentUpdateBody,\n existing: AgentConfigRow,\n): UpsertAgentInput {\n return {\n id,\n name: body.name?.trim() ?? existing.name,\n icon: \"icon\" in body ? (body.icon ?? null) : existing.icon,\n identity: body.identity ?? existing.identity,\n instructions: body.instructions ?? existing.instructions,\n tools: body.tools ?? parseJsonSafe<string[]>(existing.tools, []),\n model_config_name: \"model_config_name\" in body ? (body.model_config_name ?? null) : existing.model_config_name,\n is_default: body.is_default,\n history_limit: body.history_limit,\n history_window_hours: body.history_window_hours,\n never_reply: body.never_reply,\n adaptive_persona_enabled: body.adaptive_persona_enabled,\n adaptive_persona_strength: body.adaptive_persona_strength,\n adaptive_empathy: body.adaptive_empathy,\n adaptive_expressiveness: body.adaptive_expressiveness,\n adaptive_verbosity: body.adaptive_verbosity,\n adaptive_mbti: body.adaptive_mbti as MbtiType | undefined,\n voice_enabled: body.voice_enabled,\n voice_model: body.voice_model,\n voice_name: body.voice_name,\n voice_stt_model: body.voice_stt_model,\n voice_auto_speak: body.voice_auto_speak,\n harness_id: \"harness_id\" in body ? body.harness_id : undefined,\n delegate_targets: \"delegate_targets\" in body ? body.delegate_targets : undefined,\n context_tier_proportions:\n \"context_tier_proportions\" in body ? body.context_tier_proportions : undefined,\n anti_hallucination_mode:\n \"anti_hallucination_mode\" in body ? body.anti_hallucination_mode : undefined,\n anti_hallucination_model_config:\n \"anti_hallucination_model_config\" in body ? body.anti_hallucination_model_config : undefined,\n require_source_links:\n \"require_source_links\" in body ? body.require_source_links : undefined,\n };\n}\n","// Shared HTTP response builders for app/api/v1/** route handlers.\n//\n// Goal: every error/success payload across the v1 surface has the same\n// shape. Before this lived inline, response bodies drifted —\n// `{error: \"x\"}` vs `{message: \"x\"}`, 400 vs 422 for the same condition,\n// some routes returned Zod's raw issue array, others stringified it.\n\nimport { NextResponse } from \"next/server\";\nimport type { z } from \"zod\";\nimport type { NextRequest } from \"next/server\";\n\nexport function errorResponse(message: string, status: number = 400): NextResponse {\n return NextResponse.json({ error: message }, { status });\n}\n\nexport function notFoundResponse(message: string = \"Not found\"): NextResponse {\n return errorResponse(message, 404);\n}\n\nexport function createdResponse<T>(data: T): NextResponse {\n return NextResponse.json(data, { status: 201 });\n}\n\n// Wrap a 200 JSON response with a private Cache-Control header. Use on safe\n// GET endpoints that serve user-scoped data the client refetches often (panel\n// mounts, navigation back/forward) but mutates rarely. The TTL is short\n// enough that explicit mutations — which patch the client-side ApiClient\n// cache in place — stay observably consistent without an extra roundtrip.\nexport function cachedJson<T>(data: T, maxAgeSeconds: number): NextResponse {\n return NextResponse.json(data, {\n headers: {\n \"Cache-Control\": `private, max-age=${maxAgeSeconds}`,\n },\n });\n}\n\n// Validate a JSON request body against a zod schema.\n// Returns either the parsed data or a 400 NextResponse explaining the issue.\n// Caller pattern:\n// const parsed = await validateBody(req, Schema);\n// if (parsed instanceof NextResponse) return parsed;\n// // use parsed.field\nexport async function validateBody<S extends z.ZodTypeAny>(\n req: NextRequest,\n schema: S,\n): Promise<z.infer<S> | NextResponse> {\n let raw: unknown;\n try {\n raw = await req.json();\n } catch {\n return errorResponse(\"Request body must be valid JSON\", 400);\n }\n const parsed = schema.safeParse(raw);\n if (!parsed.success) {\n return errorResponse(parsed.error.issues[0]?.message ?? \"invalid body\", 400);\n }\n return parsed.data;\n}\n","import { getDb } from \"@/lib/db\";\nimport { MBTI_PRESETS, type MbtiType } from \"@/lib/agents/adaptive-persona-presets\";\n\nconst now = () => new Date().toISOString();\n\nexport interface AgentConfigRow {\n id: string;\n name: string;\n icon: string | null;\n identity: string;\n instructions: string;\n tools: string; // JSON string[]\n model_config_name: string | null;\n is_default: number;\n history_limit: number; // 0 = unlimited\n history_window_hours: number; // 0 = no time bound\n never_reply: number; // 1 = run the agent but don't auto-send replies via bridges\n adaptive_persona_enabled: number; // 1 = use runtime mood/tone adaptation hints\n adaptive_persona_strength: number; // 0..100, how strongly to adapt to cues\n adaptive_empathy: number; // 0..100, baseline empathetic tone\n adaptive_expressiveness: number; // 0..100, restrained -> energetic\n adaptive_verbosity: number; // 0..100, concise -> detailed\n adaptive_mbti: string; // one of 16 MBTI types\n voice_enabled: number; // 1 = expose mic/play UI for this agent\n voice_model: string; // Gemini TTS model id\n voice_name: string; // Gemini prebuilt voice name (Kore, Puck, …)\n voice_stt_model: string; // Gemini multimodal model used for transcription\n voice_auto_speak: number; // 1 = auto-play reply when user sent voice\n display_filters: string | null; // JSON: Partial<DisplayFilters>; NULL = inherit defaults (ADR-0022)\n harness_id: string | null; // ADR-0033: per-agent harness override; NULL = inherit global default\n delegate_targets: string | null; // JSON string[] of agent ids this agent may delegate to; NULL/'[]' = none\n // ADR-0043. JSON-encoded `{ hot, warm, facts }` — any positive numbers; the\n // backend divides by sum so the UI can ship raw weights and never has to\n // reconcile to 100. NULL = inherit the model config's value.\n context_tier_proportions: string | null;\n // Per-agent override of the anti-hallucination classifier mode/model.\n // NULL on either column = inherit the global JARELA_HALLUCINATION_DETECTOR_*\n // env knob.\n anti_hallucination_mode: string | null; // \"off\" | \"report\" | \"enforce\"\n anti_hallucination_model_config: string | null; // saved model config name\n // When 1, the system prompt is augmented with a citation-link directive\n // and the assistant turn is post-checked by `anti_hallucination_model_config`\n // for {source link present, source previously visited in this thread}.\n // Independent of `anti_hallucination_mode` — stall detection and citation\n // enforcement can be on/off in any combination.\n require_source_links: number;\n created_at: string;\n updated_at: string;\n}\n\nexport interface AgentTierProportions {\n hot: number;\n warm: number;\n facts: number;\n}\n\n/**\n * Parse the JSON-encoded per-agent override of context tier proportions.\n * Returns `null` for NULL, blank, malformed JSON, or any payload that\n * doesn't have three finite non-negative numeric fields. Callers fall\n * back to the model config's value (or built-in defaults) on null.\n */\nexport function getAgentTierProportions(row: AgentConfigRow): AgentTierProportions | null {\n const raw = row.context_tier_proportions;\n if (!raw) return null;\n try {\n const parsed = JSON.parse(raw) as Partial<AgentTierProportions>;\n const hot = Number(parsed.hot);\n const warm = Number(parsed.warm);\n const facts = Number(parsed.facts);\n if (![hot, warm, facts].every((n) => Number.isFinite(n) && n >= 0)) return null;\n if (hot + warm + facts <= 0) return null;\n return { hot, warm, facts };\n } catch {\n return null;\n }\n}\n\nexport function listAgentConfigs(): AgentConfigRow[] {\n return getDb()\n .prepare(\"SELECT * FROM agent_configs ORDER BY is_default DESC, created_at ASC\")\n .all() as unknown as AgentConfigRow[];\n}\n\nexport function getDefaultAgentConfig(): AgentConfigRow | null {\n return (\n (getDb()\n .prepare(\"SELECT * FROM agent_configs WHERE is_default=1 LIMIT 1\")\n .get() as unknown as AgentConfigRow) ?? null\n );\n}\n\nexport function getAgentConfig(id: string): AgentConfigRow | null {\n return (\n (getDb()\n .prepare(\"SELECT * FROM agent_configs WHERE id=?\")\n .get(id) as unknown as AgentConfigRow) ?? null\n );\n}\n\nexport interface UpsertAgentInput {\n id: string;\n name: string;\n icon?: string | null;\n identity: string;\n instructions: string;\n tools: string[];\n model_config_name?: string | null;\n is_default?: boolean;\n history_limit?: number;\n history_window_hours?: number;\n never_reply?: boolean;\n adaptive_persona_enabled?: boolean;\n adaptive_persona_strength?: number;\n adaptive_empathy?: number;\n adaptive_expressiveness?: number;\n adaptive_verbosity?: number;\n adaptive_mbti?: MbtiType;\n voice_enabled?: boolean;\n voice_model?: string;\n voice_name?: string;\n voice_stt_model?: string;\n voice_auto_speak?: boolean;\n harness_id?: string | null;\n delegate_targets?: string[];\n // ADR-0043. Pass `null` to clear the override and inherit from the model.\n // Pass `undefined` to keep whatever's already on the row (PATCH semantics).\n context_tier_proportions?: AgentTierProportions | null;\n // Per-agent anti-hallucination classifier override. `null` = clear the\n // override (inherit env). `undefined` = keep existing.\n anti_hallucination_mode?: \"off\" | \"regex\" | \"model\" | null;\n anti_hallucination_model_config?: string | null;\n // Citation enforcement (independent of stall detector). `undefined` = keep\n // existing. `false` = disable.\n require_source_links?: boolean;\n}\n\n/**\n * Parse the JSON-encoded delegate whitelist into a deduped string[]. Returns\n * an empty array for NULL, blank, or malformed JSON (delegation is opt-in).\n */\n/**\n * Parse the agent's tool allowlist (`tools` column, stored as a JSON string).\n * Returns an empty array on NULL/blank/malformed JSON — same defensive shape\n * as parseDelegateTargets. Callers that previously did `JSON.parse(cfg.tools)`\n * inline should switch to this getter so the serialization contract stays\n * owned by this store.\n */\nexport function getAgentTools(cfg: Pick<AgentConfigRow, \"tools\"> | null | undefined): string[] {\n if (!cfg?.tools) return [];\n try {\n const parsed = JSON.parse(cfg.tools);\n if (!Array.isArray(parsed)) return [];\n return parsed.filter((x): x is string => typeof x === \"string\" && x.length > 0);\n } catch {\n return [];\n }\n}\n\nexport function parseDelegateTargets(raw: string | null | undefined): string[] {\n if (!raw) return [];\n try {\n const parsed = JSON.parse(raw);\n if (!Array.isArray(parsed)) return [];\n const ids = parsed.filter((x): x is string => typeof x === \"string\" && x.length > 0);\n return Array.from(new Set(ids));\n } catch {\n return [];\n }\n}\n\nexport function upsertAgentConfig(input: UpsertAgentInput): AgentConfigRow {\n const t = now();\n const db = getDb();\n const existing = getAgentConfig(input.id);\n const created_at = existing?.created_at ?? t;\n const mbti = input.adaptive_mbti ?? toMbti(existing?.adaptive_mbti) ?? \"INTJ\";\n const preset = MBTI_PRESETS[mbti];\n const strength = input.adaptive_persona_strength ?? preset.strength;\n const empathy = input.adaptive_empathy ?? preset.empathy;\n const expressiveness = input.adaptive_expressiveness ?? preset.expressiveness;\n const verbosity = input.adaptive_verbosity ?? preset.verbosity;\n if (input.is_default) db.prepare(\"UPDATE agent_configs SET is_default=0\").run();\n // harness_id: explicit `undefined` means \"keep existing\"; explicit `null`\n // means \"use the global default\". Empty string is normalised to null too,\n // matching how the AgentEditor sends \"\" for the inherit option.\n const harnessId =\n input.harness_id === undefined\n ? (existing?.harness_id ?? null)\n : (input.harness_id && input.harness_id.length > 0 ? input.harness_id : null);\n // delegate_targets: undefined = keep existing; explicit empty array clears.\n const delegateTargets = input.delegate_targets === undefined\n ? (existing?.delegate_targets ?? null)\n : JSON.stringify(Array.from(new Set(input.delegate_targets.filter((id) => id && id !== input.id))));\n // context_tier_proportions: undefined = keep existing; null = clear and\n // inherit from the model; object = serialise as JSON. Negative values are\n // clamped to 0 so the upsert can't poison the column with bad data.\n const tierProportions =\n input.context_tier_proportions === undefined\n ? (existing?.context_tier_proportions ?? null)\n : input.context_tier_proportions === null\n ? null\n : JSON.stringify({\n hot: Math.max(0, Number(input.context_tier_proportions.hot) || 0),\n warm: Math.max(0, Number(input.context_tier_proportions.warm) || 0),\n facts: Math.max(0, Number(input.context_tier_proportions.facts) || 0),\n });\n // Anti-hallucination override: `undefined` keeps existing; `null` clears\n // the override (inherits env). Empty-string model is normalised to null\n // so the editor can ship \"\" for the inherit option.\n const antiHallucMode =\n input.anti_hallucination_mode === undefined\n ? (existing?.anti_hallucination_mode ?? null)\n : input.anti_hallucination_mode === null\n ? null\n : (input.anti_hallucination_mode === \"off\" || input.anti_hallucination_mode === \"regex\" || input.anti_hallucination_mode === \"model\")\n ? input.anti_hallucination_mode\n : null;\n const antiHallucModel =\n input.anti_hallucination_model_config === undefined\n ? (existing?.anti_hallucination_model_config ?? null)\n : input.anti_hallucination_model_config && input.anti_hallucination_model_config.trim().length > 0\n ? input.anti_hallucination_model_config.trim()\n : null;\n const requireSourceLinks =\n input.require_source_links === undefined\n ? (existing?.require_source_links ?? 0)\n : (input.require_source_links ? 1 : 0);\n db.prepare(\n `INSERT OR REPLACE INTO agent_configs\n (id, name, icon, identity, instructions, tools, model_config_name, is_default,\n history_limit, history_window_hours, never_reply,\n adaptive_persona_enabled, adaptive_persona_strength, adaptive_empathy, adaptive_expressiveness, adaptive_verbosity, adaptive_mbti,\n voice_enabled, voice_model, voice_name, voice_stt_model, voice_auto_speak,\n harness_id, delegate_targets, context_tier_proportions,\n anti_hallucination_mode, anti_hallucination_model_config, require_source_links,\n created_at, updated_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`\n )\n .run(\n input.id,\n input.name,\n input.icon ?? null,\n input.identity,\n input.instructions,\n JSON.stringify(input.tools),\n input.model_config_name ?? null,\n input.is_default ? 1 : (existing?.is_default ?? 0),\n input.history_limit ?? existing?.history_limit ?? 50,\n input.history_window_hours ?? existing?.history_window_hours ?? 8,\n // never_reply is a boolean toggle — explicit `undefined` means \"keep existing\"\n // (important for PATCH-style updates that omit the field).\n input.never_reply === undefined\n ? (existing?.never_reply ?? 0)\n : (input.never_reply ? 1 : 0),\n input.adaptive_persona_enabled === undefined\n ? (existing?.adaptive_persona_enabled ?? 0)\n : (input.adaptive_persona_enabled ? 1 : 0),\n clampPercent(strength, existing?.adaptive_persona_strength ?? 50),\n clampPercent(empathy, existing?.adaptive_empathy ?? 50),\n clampPercent(expressiveness, existing?.adaptive_expressiveness ?? 50),\n clampPercent(verbosity, existing?.adaptive_verbosity ?? 50),\n mbti,\n input.voice_enabled === undefined\n ? (existing?.voice_enabled ?? 0)\n : (input.voice_enabled ? 1 : 0),\n (input.voice_model ?? existing?.voice_model ?? \"gemini-2.5-flash-preview-tts\").trim() ||\n \"gemini-2.5-flash-preview-tts\",\n (input.voice_name ?? existing?.voice_name ?? \"Kore\").trim() || \"Kore\",\n (input.voice_stt_model ?? existing?.voice_stt_model ?? \"gemini-2.5-flash\").trim() ||\n \"gemini-2.5-flash\",\n input.voice_auto_speak === undefined\n ? (existing?.voice_auto_speak ?? 1)\n : (input.voice_auto_speak ? 1 : 0),\n harnessId,\n delegateTargets,\n tierProportions,\n antiHallucMode,\n antiHallucModel,\n requireSourceLinks,\n created_at,\n t,\n );\n return getAgentConfig(input.id)!;\n}\n\nfunction clampPercent(next: number | undefined, fallback: number): number {\n const n = Number.isFinite(next) ? Number(next) : fallback;\n return Math.max(0, Math.min(100, Math.round(n)));\n}\n\nfunction toMbti(v: string | null | undefined): MbtiType | null {\n if (!v) return null;\n return (v in MBTI_PRESETS ? v : null) as MbtiType | null;\n}\n\nexport function deleteAgentConfig(id: string): boolean {\n return (\n (getDb().prepare(\"DELETE FROM agent_configs WHERE id=?\").run(id) as { changes: number }).changes > 0\n );\n}\n\nexport function generateAgentId(name: string): string {\n const slug = name\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .slice(0, 40);\n const suffix = Math.random().toString(36).slice(2, 6);\n return slug ? `${slug}-${suffix}` : `agent-${suffix}`;\n}\n\n// ── ADR-0022: per-agent message-channel display filters ─────────────────\n// Canonical channel keys mirrored in `hooks/useMessageFilters.ts`. Kept\n// in sync there by importing this constant — single source of truth.\nexport const DISPLAY_FILTER_KEYS = [\n \"scheduled_task\",\n \"watcher\",\n \"bridge\",\n \"synthetic\",\n \"tool_use\",\n \"thinking\",\n] as const;\nexport type DisplayFilterKey = (typeof DISPLAY_FILTER_KEYS)[number];\nexport type DisplayFilters = Record<DisplayFilterKey, boolean>;\n\nexport const DISPLAY_FILTER_DEFAULTS: DisplayFilters = {\n scheduled_task: true,\n watcher: true,\n bridge: true,\n synthetic: true,\n tool_use: true,\n thinking: true,\n};\n\nfunction parseDisplayFilters(raw: string | null | undefined): DisplayFilters {\n if (!raw) return { ...DISPLAY_FILTER_DEFAULTS };\n try {\n const parsed = JSON.parse(raw) as Partial<DisplayFilters>;\n // Merge over defaults so newly-added channels stay visible on old rows.\n return { ...DISPLAY_FILTER_DEFAULTS, ...parsed };\n } catch {\n return { ...DISPLAY_FILTER_DEFAULTS };\n }\n}\n\nexport function getAgentDisplayFilters(id: string): DisplayFilters | null {\n const row = getAgentConfig(id);\n if (!row) return null;\n return parseDisplayFilters(row.display_filters);\n}\n\n/**\n * Merge a partial filter map into the agent's stored prefs. Pass `null` to\n * reset to defaults (clears the column). Safe against concurrent toggles\n * from multiple browser tabs because the merge happens server-side.\n */\nexport function updateAgentDisplayFilters(\n id: string,\n patch: Partial<DisplayFilters> | null,\n): DisplayFilters | null {\n const row = getAgentConfig(id);\n if (!row) return null;\n if (patch === null) {\n getDb()\n .prepare(\"UPDATE agent_configs SET display_filters=NULL, updated_at=? WHERE id=?\")\n .run(now(), id);\n return { ...DISPLAY_FILTER_DEFAULTS };\n }\n const current = parseDisplayFilters(row.display_filters);\n const next: DisplayFilters = { ...current };\n for (const k of DISPLAY_FILTER_KEYS) {\n if (k in patch && typeof patch[k] === \"boolean\") next[k] = patch[k] as boolean;\n }\n getDb()\n .prepare(\"UPDATE agent_configs SET display_filters=?, updated_at=? WHERE id=?\")\n .run(JSON.stringify(next), now(), id);\n return next;\n}\n","// JSON.parse with a fallback value when the input is malformed (or empty).\n// Used everywhere we read responses from external APIs — they're contractually\n// JSON but a transient 502 / proxy interstitial occasionally returns HTML.\nexport function parseJsonSafe<T>(text: string, fallback: T): T;\nexport function parseJsonSafe<T>(text: string): T | undefined;\nexport function parseJsonSafe<T>(text: string, fallback?: T): T | undefined {\n try {\n return JSON.parse(text) as T;\n } catch {\n return fallback;\n }\n}\n","// Row → JSON-response serializers shared between list (`route.ts`) and\n// item (`[id]/route.ts`) handlers. Keeping these in one place stops the\n// list and item shapes from drifting (they were copy-pasted before).\n\nimport type { AgentConfigRow } from \"@/lib/stores/agent-configs\";\nimport { getAgentTierProportions, parseDelegateTargets } from \"@/lib/stores/agent-configs\";\nimport type { BridgeRow } from \"@/lib/stores/bridges\";\nimport type { McpServerRow } from \"@/lib/stores/mcp-servers\";\nimport type { MessageRow } from \"@/lib/stores/threads\";\nimport type { MessageUsageRow } from \"@/lib/stores/message-usage\";\nimport { parseJsonSafe } from \"@/lib/utils/json\";\n\nexport function agentToResponse(a: AgentConfigRow) {\n return {\n id: a.id,\n name: a.name,\n icon: a.icon,\n identity: a.identity,\n instructions: a.instructions,\n tools: parseJsonSafe<string[]>(a.tools, []),\n model_config_name: a.model_config_name,\n is_default: !!a.is_default,\n history_limit: a.history_limit,\n history_window_hours: a.history_window_hours,\n never_reply: !!a.never_reply,\n adaptive_persona_enabled: !!a.adaptive_persona_enabled,\n adaptive_persona_strength: a.adaptive_persona_strength,\n adaptive_empathy: a.adaptive_empathy,\n adaptive_expressiveness: a.adaptive_expressiveness,\n adaptive_verbosity: a.adaptive_verbosity,\n adaptive_mbti: a.adaptive_mbti,\n voice_enabled: !!a.voice_enabled,\n voice_model: a.voice_model,\n voice_name: a.voice_name,\n voice_stt_model: a.voice_stt_model,\n voice_auto_speak: !!a.voice_auto_speak,\n harness_id: a.harness_id,\n delegate_targets: parseDelegateTargets(a.delegate_targets),\n context_tier_proportions: getAgentTierProportions(a),\n anti_hallucination_mode: (a.anti_hallucination_mode === \"off\" || a.anti_hallucination_mode === \"regex\" || a.anti_hallucination_mode === \"model\")\n ? a.anti_hallucination_mode\n : null,\n anti_hallucination_model_config: a.anti_hallucination_model_config,\n require_source_links: !!a.require_source_links,\n created_at: a.created_at,\n updated_at: a.updated_at,\n };\n}\n\nexport function bridgeToResponse(r: BridgeRow) {\n return {\n id: r.id,\n kind: r.kind,\n name: r.name,\n status: r.status,\n last_error: r.last_error,\n paired_id: r.paired_id,\n enabled: r.enabled === 1,\n created_at: r.created_at,\n updated_at: r.updated_at,\n };\n}\n\nexport function mcpServerToResponse(r: McpServerRow) {\n return {\n name: r.name,\n transport: r.transport,\n spec: parseJsonSafe<unknown>(r.spec, null),\n enabled: r.enabled === 1,\n last_error: r.last_error,\n created_at: r.created_at,\n updated_at: r.updated_at,\n };\n}\n\n/**\n * Shape a `message_usage` row into the over-the-wire `usage` object the\n * chat panel's `ContextUsageBar` consumes. Returns `null` for messages\n * that have no snapshot (user turns and legacy assistant rows recorded\n * before the per-turn snapshot landed in ADR-0041).\n */\nexport function messageUsageToResponse(u: MessageUsageRow | undefined | null) {\n if (!u) return null;\n return {\n input_tokens: u.input_tokens,\n output_tokens: u.output_tokens,\n hot_tokens: u.hot_tokens,\n warm_tokens: u.warm_tokens,\n facts_tokens: u.facts_tokens,\n overhead_tokens: u.overhead_tokens,\n hot_budget_tokens: u.hot_budget_tokens,\n warm_budget_tokens: u.warm_budget_tokens,\n facts_budget_tokens: u.facts_budget_tokens,\n context_window_tokens: u.context_window_tokens,\n };\n}\n\n/**\n * Shape one message row into its over-the-wire form, attaching its\n * per-turn `usage` snapshot when one exists. Pure data-shaping helper\n * extracted from the threads GET route so the wire contract has unit\n * coverage.\n */\nexport function messageToResponse(\n m: MessageRow,\n usageById: ReadonlyMap<string, MessageUsageRow>,\n) {\n return {\n id: m.msg_id,\n role: m.role,\n content: m.content,\n created_at: m.created_at,\n tool_events: parseToolEventsForResponse(m.tool_events),\n category: m.category ?? null,\n usage: messageUsageToResponse(usageById.get(m.msg_id)),\n metadata: parseMessageMetadataForResponse(m.metadata),\n };\n}\n\n/** Tolerant `tool_events` JSON parser shared with the route. Bad JSON\n * and non-array payloads collapse to `undefined` so the wire shape\n * always matches the typed client expectation. */\nexport function parseToolEventsForResponse(raw: string | null | undefined): unknown[] | undefined {\n if (!raw) return undefined;\n try {\n const parsed = JSON.parse(raw);\n return Array.isArray(parsed) ? parsed : undefined;\n } catch {\n return undefined;\n }\n}\n\n/** Tolerant `metadata` JSON parser. Returns `null` for missing/blank/\n * malformed/non-object payloads so the wire shape stays a plain object\n * or null — readers can rely on `metadata?.citations?...` chaining. */\nexport function parseMessageMetadataForResponse(raw: string | null | undefined): Record<string, unknown> | null {\n if (!raw) return null;\n try {\n const parsed = JSON.parse(raw);\n if (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) return null;\n return parsed as Record<string, unknown>;\n } catch {\n return null;\n }\n}\n\n/**\n * Resolve the bar's 100% baseline. Per-row `context_window_tokens`\n * (snapshotted at run time) wins so the bar matches the cap the agent\n * actually applied; legacy rows fall back to the model-config value;\n * unconfigured agents fall back to the default. Centralised so the\n * route and the UI share the same precedence rule.\n */\nexport function resolveContextWindowTokens(\n modelConfiguredTokens: number | null | undefined,\n defaultTokens: number,\n): number {\n if (typeof modelConfiguredTokens === \"number\" && modelConfiguredTokens > 0) {\n return modelConfiguredTokens;\n }\n return defaultTokens;\n}\n"],"names":["parseJsonSafe","toCreateAgentInput","id","body","name","trim","icon","identity","instructions","tools","model_config_name","is_default","history_limit","history_window_hours","never_reply","adaptive_persona_enabled","adaptive_persona_strength","adaptive_empathy","adaptive_expressiveness","adaptive_verbosity","adaptive_mbti","voice_enabled","voice_model","voice_name","voice_stt_model","voice_auto_speak","harness_id","delegate_targets","context_tier_proportions","anti_hallucination_mode","anti_hallucination_model_config","require_source_links","toUpdateAgentInput","existing","undefined","NextResponse","errorResponse","message","status","json","error","notFoundResponse","createdResponse","data","cachedJson","maxAgeSeconds","headers","validateBody","req","schema","raw","parsed","safeParse","success","issues","getDb","MBTI_PRESETS","now","Date","toISOString","getAgentTierProportions","row","JSON","parse","hot","Number","warm","facts","every","n","isFinite","listAgentConfigs","prepare","all","getDefaultAgentConfig","get","getAgentConfig","getAgentTools","cfg","Array","isArray","filter","x","length","parseDelegateTargets","ids","from","Set","upsertAgentConfig","input","t","db","created_at","mbti","toMbti","preset","strength","empathy","expressiveness","verbosity","run","harnessId","delegateTargets","stringify","tierProportions","Math","max","antiHallucMode","antiHallucModel","requireSourceLinks","clampPercent","next","fallback","min","round","v","deleteAgentConfig","changes","generateAgentId","slug","toLowerCase","replace","slice","suffix","random","toString","DISPLAY_FILTER_KEYS","DISPLAY_FILTER_DEFAULTS","scheduled_task","watcher","bridge","synthetic","tool_use","thinking","parseDisplayFilters","getAgentDisplayFilters","display_filters","updateAgentDisplayFilters","patch","current","k","text","agentToResponse","a","updated_at","bridgeToResponse","r","kind","last_error","paired_id","enabled","mcpServerToResponse","transport","spec","messageUsageToResponse","u","input_tokens","output_tokens","hot_tokens","warm_tokens","facts_tokens","overhead_tokens","hot_budget_tokens","warm_budget_tokens","facts_budget_tokens","context_window_tokens","messageToResponse","m","usageById","msg_id","role","content","tool_events","parseToolEventsForResponse","category","usage","metadata","parseMessageMetadataForResponse","resolveContextWindowTokens","modelConfiguredTokens","defaultTokens"],"sourceRoot":"","ignoreList":[]}
1
+ {"version":3,"file":"2447.js","mappings":"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","sources":["webpack://@circuitwall/jarela/./app/api/v1/agents/payload.ts","webpack://@circuitwall/jarela/./lib/api/responses.ts","webpack://@circuitwall/jarela/./lib/stores/agent-configs.ts","webpack://@circuitwall/jarela/./lib/utils/json.ts","webpack://@circuitwall/jarela/./lib/api/serializers.ts"],"sourcesContent":["import type { MbtiType } from \"@/lib/agents/adaptive-persona-presets\";\nimport type { AgentConfigRow, UpsertAgentInput } from \"@/lib/stores/agent-configs\";\nimport type { AgentConfigIn } from \"@/api/types\";\nimport { parseJsonSafe } from \"@/lib/utils/json\";\n\nexport type AgentCreateBody = AgentConfigIn;\nexport type AgentUpdateBody = Partial<AgentConfigIn>;\n\nexport function toCreateAgentInput(id: string, body: AgentCreateBody): UpsertAgentInput {\n return {\n id,\n name: body.name.trim(),\n icon: body.icon ?? null,\n identity: body.identity ?? \"\",\n instructions: body.instructions ?? \"\",\n tools: body.tools ?? [],\n model_config_name: body.model_config_name ?? null,\n is_default: body.is_default,\n history_limit: body.history_limit,\n history_window_hours: body.history_window_hours,\n never_reply: body.never_reply,\n adaptive_persona_enabled: body.adaptive_persona_enabled,\n adaptive_persona_strength: body.adaptive_persona_strength,\n adaptive_empathy: body.adaptive_empathy,\n adaptive_expressiveness: body.adaptive_expressiveness,\n adaptive_verbosity: body.adaptive_verbosity,\n adaptive_mbti: body.adaptive_mbti as MbtiType | undefined,\n voice_enabled: body.voice_enabled,\n voice_model: body.voice_model,\n voice_name: body.voice_name,\n voice_stt_model: body.voice_stt_model,\n voice_auto_speak: body.voice_auto_speak,\n harness_id: body.harness_id,\n delegate_targets: body.delegate_targets,\n context_tier_proportions: body.context_tier_proportions,\n anti_hallucination_mode: body.anti_hallucination_mode,\n anti_hallucination_model_config: body.anti_hallucination_model_config,\n require_source_links: body.require_source_links,\n };\n}\n\nexport function toUpdateAgentInput(\n id: string,\n body: AgentUpdateBody,\n existing: AgentConfigRow,\n): UpsertAgentInput {\n return {\n id,\n name: body.name?.trim() ?? existing.name,\n icon: \"icon\" in body ? (body.icon ?? null) : existing.icon,\n identity: body.identity ?? existing.identity,\n instructions: body.instructions ?? existing.instructions,\n tools: body.tools ?? parseJsonSafe<string[]>(existing.tools, []),\n model_config_name: \"model_config_name\" in body ? (body.model_config_name ?? null) : existing.model_config_name,\n is_default: body.is_default,\n history_limit: body.history_limit,\n history_window_hours: body.history_window_hours,\n never_reply: body.never_reply,\n adaptive_persona_enabled: body.adaptive_persona_enabled,\n adaptive_persona_strength: body.adaptive_persona_strength,\n adaptive_empathy: body.adaptive_empathy,\n adaptive_expressiveness: body.adaptive_expressiveness,\n adaptive_verbosity: body.adaptive_verbosity,\n adaptive_mbti: body.adaptive_mbti as MbtiType | undefined,\n voice_enabled: body.voice_enabled,\n voice_model: body.voice_model,\n voice_name: body.voice_name,\n voice_stt_model: body.voice_stt_model,\n voice_auto_speak: body.voice_auto_speak,\n harness_id: \"harness_id\" in body ? body.harness_id : undefined,\n delegate_targets: \"delegate_targets\" in body ? body.delegate_targets : undefined,\n context_tier_proportions:\n \"context_tier_proportions\" in body ? body.context_tier_proportions : undefined,\n anti_hallucination_mode:\n \"anti_hallucination_mode\" in body ? body.anti_hallucination_mode : undefined,\n anti_hallucination_model_config:\n \"anti_hallucination_model_config\" in body ? body.anti_hallucination_model_config : undefined,\n require_source_links:\n \"require_source_links\" in body ? body.require_source_links : undefined,\n };\n}\n","// Shared HTTP response builders for app/api/v1/** route handlers.\n//\n// Goal: every error/success payload across the v1 surface has the same\n// shape. Before this lived inline, response bodies drifted —\n// `{error: \"x\"}` vs `{message: \"x\"}`, 400 vs 422 for the same condition,\n// some routes returned Zod's raw issue array, others stringified it.\n\nimport { NextResponse } from \"next/server\";\nimport type { z } from \"zod\";\nimport type { NextRequest } from \"next/server\";\n\nexport function errorResponse(message: string, status: number = 400): NextResponse {\n return NextResponse.json({ error: message }, { status });\n}\n\nexport function notFoundResponse(message: string = \"Not found\"): NextResponse {\n return errorResponse(message, 404);\n}\n\nexport function createdResponse<T>(data: T): NextResponse {\n return NextResponse.json(data, { status: 201 });\n}\n\n// Wrap a 200 JSON response with a private Cache-Control header. Use on safe\n// GET endpoints that serve user-scoped data the client refetches often (panel\n// mounts, navigation back/forward) but mutates rarely. The TTL is short\n// enough that explicit mutations — which patch the client-side ApiClient\n// cache in place — stay observably consistent without an extra roundtrip.\nexport function cachedJson<T>(data: T, maxAgeSeconds: number): NextResponse {\n return NextResponse.json(data, {\n headers: {\n \"Cache-Control\": `private, max-age=${maxAgeSeconds}`,\n },\n });\n}\n\n// Validate a JSON request body against a zod schema.\n// Returns either the parsed data or a 400 NextResponse explaining the issue.\n// Caller pattern:\n// const parsed = await validateBody(req, Schema);\n// if (parsed instanceof NextResponse) return parsed;\n// // use parsed.field\nexport async function validateBody<S extends z.ZodTypeAny>(\n req: NextRequest,\n schema: S,\n): Promise<z.infer<S> | NextResponse> {\n let raw: unknown;\n try {\n raw = await req.json();\n } catch {\n return errorResponse(\"Request body must be valid JSON\", 400);\n }\n const parsed = schema.safeParse(raw);\n if (!parsed.success) {\n return errorResponse(parsed.error.issues[0]?.message ?? \"invalid body\", 400);\n }\n return parsed.data;\n}\n","import { getDb } from \"@/lib/db\";\nimport { MBTI_PRESETS, type MbtiType } from \"@/lib/agents/adaptive-persona-presets\";\n\nconst now = () => new Date().toISOString();\n\nexport interface AgentConfigRow {\n id: string;\n name: string;\n icon: string | null;\n identity: string;\n instructions: string;\n tools: string; // JSON string[]\n model_config_name: string | null;\n is_default: number;\n history_limit: number; // 0 = unlimited\n history_window_hours: number; // 0 = no time bound\n never_reply: number; // 1 = run the agent but don't auto-send replies via bridges\n adaptive_persona_enabled: number; // 1 = use runtime mood/tone adaptation hints\n adaptive_persona_strength: number; // 0..100, how strongly to adapt to cues\n adaptive_empathy: number; // 0..100, baseline empathetic tone\n adaptive_expressiveness: number; // 0..100, restrained -> energetic\n adaptive_verbosity: number; // 0..100, concise -> detailed\n adaptive_mbti: string; // one of 16 MBTI types\n voice_enabled: number; // 1 = expose mic/play UI for this agent\n voice_model: string; // Gemini TTS model id\n voice_name: string; // Gemini prebuilt voice name (Kore, Puck, …)\n voice_stt_model: string; // Gemini multimodal model used for transcription\n voice_auto_speak: number; // 1 = auto-play reply when user sent voice\n display_filters: string | null; // JSON: Partial<DisplayFilters>; NULL = inherit defaults (ADR-0022)\n harness_id: string | null; // ADR-0033: per-agent harness override; NULL = inherit global default\n delegate_targets: string | null; // JSON string[] of agent ids this agent may delegate to; NULL/'[]' = none\n // ADR-0043. JSON-encoded `{ hot, warm, facts }` — any positive numbers; the\n // backend divides by sum so the UI can ship raw weights and never has to\n // reconcile to 100. NULL = inherit the model config's value.\n context_tier_proportions: string | null;\n // Per-agent override of the anti-hallucination classifier mode/model.\n // NULL on either column = inherit the global JARELA_HALLUCINATION_DETECTOR_*\n // env knob.\n anti_hallucination_mode: string | null; // \"off\" | \"report\" | \"enforce\"\n anti_hallucination_model_config: string | null; // saved model config name\n // When 1, the system prompt is augmented with a citation-link directive\n // and the assistant turn is post-checked by `anti_hallucination_model_config`\n // for {source link present, source previously visited in this thread}.\n // Independent of `anti_hallucination_mode` — stall detection and citation\n // enforcement can be on/off in any combination.\n require_source_links: number;\n created_at: string;\n updated_at: string;\n}\n\nexport interface AgentTierProportions {\n hot: number;\n warm: number;\n facts: number;\n}\n\n/**\n * Parse the JSON-encoded per-agent override of context tier proportions.\n * Returns `null` for NULL, blank, malformed JSON, or any payload that\n * doesn't have three finite non-negative numeric fields. Callers fall\n * back to the model config's value (or built-in defaults) on null.\n */\nexport function getAgentTierProportions(row: AgentConfigRow): AgentTierProportions | null {\n const raw = row.context_tier_proportions;\n if (!raw) return null;\n try {\n const parsed = JSON.parse(raw) as Partial<AgentTierProportions>;\n const hot = Number(parsed.hot);\n const warm = Number(parsed.warm);\n const facts = Number(parsed.facts);\n if (![hot, warm, facts].every((n) => Number.isFinite(n) && n >= 0)) return null;\n if (hot + warm + facts <= 0) return null;\n return { hot, warm, facts };\n } catch {\n return null;\n }\n}\n\nexport function listAgentConfigs(): AgentConfigRow[] {\n return getDb()\n .prepare(\"SELECT * FROM agent_configs ORDER BY is_default DESC, created_at ASC\")\n .all() as unknown as AgentConfigRow[];\n}\n\nexport function getDefaultAgentConfig(): AgentConfigRow | null {\n return (\n (getDb()\n .prepare(\"SELECT * FROM agent_configs WHERE is_default=1 LIMIT 1\")\n .get() as unknown as AgentConfigRow) ?? null\n );\n}\n\nexport function getAgentConfig(id: string): AgentConfigRow | null {\n return (\n (getDb()\n .prepare(\"SELECT * FROM agent_configs WHERE id=?\")\n .get(id) as unknown as AgentConfigRow) ?? null\n );\n}\n\nexport interface UpsertAgentInput {\n id: string;\n name: string;\n icon?: string | null;\n identity: string;\n instructions: string;\n tools: string[];\n model_config_name?: string | null;\n is_default?: boolean;\n history_limit?: number;\n history_window_hours?: number;\n never_reply?: boolean;\n adaptive_persona_enabled?: boolean;\n adaptive_persona_strength?: number;\n adaptive_empathy?: number;\n adaptive_expressiveness?: number;\n adaptive_verbosity?: number;\n adaptive_mbti?: MbtiType;\n voice_enabled?: boolean;\n voice_model?: string;\n voice_name?: string;\n voice_stt_model?: string;\n voice_auto_speak?: boolean;\n harness_id?: string | null;\n delegate_targets?: string[];\n // ADR-0043. Pass `null` to clear the override and inherit from the model.\n // Pass `undefined` to keep whatever's already on the row (PATCH semantics).\n context_tier_proportions?: AgentTierProportions | null;\n // Per-agent anti-hallucination classifier override. `null` = clear the\n // override (inherit env). `undefined` = keep existing.\n anti_hallucination_mode?: \"off\" | \"regex\" | \"model\" | null;\n anti_hallucination_model_config?: string | null;\n // Citation enforcement (independent of stall detector). `undefined` = keep\n // existing. `false` = disable.\n require_source_links?: boolean;\n}\n\n/**\n * Parse the JSON-encoded delegate whitelist into a deduped string[]. Returns\n * an empty array for NULL, blank, or malformed JSON (delegation is opt-in).\n */\n/**\n * Parse the agent's tool allowlist (`tools` column, stored as a JSON string).\n * Returns an empty array on NULL/blank/malformed JSON — same defensive shape\n * as parseDelegateTargets. Callers that previously did `JSON.parse(cfg.tools)`\n * inline should switch to this getter so the serialization contract stays\n * owned by this store.\n */\nexport function getAgentTools(cfg: Pick<AgentConfigRow, \"tools\"> | null | undefined): string[] {\n if (!cfg?.tools) return [];\n try {\n const parsed = JSON.parse(cfg.tools);\n if (!Array.isArray(parsed)) return [];\n return parsed.filter((x): x is string => typeof x === \"string\" && x.length > 0);\n } catch {\n return [];\n }\n}\n\nexport function parseDelegateTargets(raw: string | null | undefined): string[] {\n if (!raw) return [];\n try {\n const parsed = JSON.parse(raw);\n if (!Array.isArray(parsed)) return [];\n const ids = parsed.filter((x): x is string => typeof x === \"string\" && x.length > 0);\n return Array.from(new Set(ids));\n } catch {\n return [];\n }\n}\n\nexport function upsertAgentConfig(input: UpsertAgentInput): AgentConfigRow {\n const t = now();\n const db = getDb();\n const existing = getAgentConfig(input.id);\n const created_at = existing?.created_at ?? t;\n const mbti = input.adaptive_mbti ?? toMbti(existing?.adaptive_mbti) ?? \"INTJ\";\n const preset = MBTI_PRESETS[mbti];\n const strength = input.adaptive_persona_strength ?? preset.strength;\n const empathy = input.adaptive_empathy ?? preset.empathy;\n const expressiveness = input.adaptive_expressiveness ?? preset.expressiveness;\n const verbosity = input.adaptive_verbosity ?? preset.verbosity;\n if (input.is_default) db.prepare(\"UPDATE agent_configs SET is_default=0\").run();\n // harness_id: explicit `undefined` means \"keep existing\"; explicit `null`\n // means \"use the global default\". Empty string is normalised to null too,\n // matching how the AgentEditor sends \"\" for the inherit option.\n const harnessId =\n input.harness_id === undefined\n ? (existing?.harness_id ?? null)\n : (input.harness_id && input.harness_id.length > 0 ? input.harness_id : null);\n // delegate_targets: undefined = keep existing; explicit empty array clears.\n const delegateTargets = input.delegate_targets === undefined\n ? (existing?.delegate_targets ?? null)\n : JSON.stringify(Array.from(new Set(input.delegate_targets.filter((id) => id && id !== input.id))));\n // context_tier_proportions: undefined = keep existing; null = clear and\n // inherit from the model; object = serialise as JSON. Negative values are\n // clamped to 0 so the upsert can't poison the column with bad data.\n const tierProportions =\n input.context_tier_proportions === undefined\n ? (existing?.context_tier_proportions ?? null)\n : input.context_tier_proportions === null\n ? null\n : JSON.stringify({\n hot: Math.max(0, Number(input.context_tier_proportions.hot) || 0),\n warm: Math.max(0, Number(input.context_tier_proportions.warm) || 0),\n facts: Math.max(0, Number(input.context_tier_proportions.facts) || 0),\n });\n // Anti-hallucination override: `undefined` keeps existing; `null` clears\n // the override (inherits env). Empty-string model is normalised to null\n // so the editor can ship \"\" for the inherit option.\n const antiHallucMode =\n input.anti_hallucination_mode === undefined\n ? (existing?.anti_hallucination_mode ?? null)\n : input.anti_hallucination_mode === null\n ? null\n : (input.anti_hallucination_mode === \"off\" || input.anti_hallucination_mode === \"regex\" || input.anti_hallucination_mode === \"model\")\n ? input.anti_hallucination_mode\n : null;\n const antiHallucModel =\n input.anti_hallucination_model_config === undefined\n ? (existing?.anti_hallucination_model_config ?? null)\n : input.anti_hallucination_model_config && input.anti_hallucination_model_config.trim().length > 0\n ? input.anti_hallucination_model_config.trim()\n : null;\n const requireSourceLinks =\n input.require_source_links === undefined\n ? (existing?.require_source_links ?? 0)\n : (input.require_source_links ? 1 : 0);\n db.prepare(\n `INSERT OR REPLACE INTO agent_configs\n (id, name, icon, identity, instructions, tools, model_config_name, is_default,\n history_limit, history_window_hours, never_reply,\n adaptive_persona_enabled, adaptive_persona_strength, adaptive_empathy, adaptive_expressiveness, adaptive_verbosity, adaptive_mbti,\n voice_enabled, voice_model, voice_name, voice_stt_model, voice_auto_speak,\n harness_id, delegate_targets, context_tier_proportions,\n anti_hallucination_mode, anti_hallucination_model_config, require_source_links,\n created_at, updated_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`\n )\n .run(\n input.id,\n input.name,\n input.icon ?? null,\n input.identity,\n input.instructions,\n JSON.stringify(input.tools),\n input.model_config_name ?? null,\n input.is_default ? 1 : (existing?.is_default ?? 0),\n input.history_limit ?? existing?.history_limit ?? 50,\n input.history_window_hours ?? existing?.history_window_hours ?? 8,\n // never_reply is a boolean toggle — explicit `undefined` means \"keep existing\"\n // (important for PATCH-style updates that omit the field).\n input.never_reply === undefined\n ? (existing?.never_reply ?? 0)\n : (input.never_reply ? 1 : 0),\n input.adaptive_persona_enabled === undefined\n ? (existing?.adaptive_persona_enabled ?? 0)\n : (input.adaptive_persona_enabled ? 1 : 0),\n clampPercent(strength, existing?.adaptive_persona_strength ?? 50),\n clampPercent(empathy, existing?.adaptive_empathy ?? 50),\n clampPercent(expressiveness, existing?.adaptive_expressiveness ?? 50),\n clampPercent(verbosity, existing?.adaptive_verbosity ?? 50),\n mbti,\n input.voice_enabled === undefined\n ? (existing?.voice_enabled ?? 0)\n : (input.voice_enabled ? 1 : 0),\n (input.voice_model ?? existing?.voice_model ?? \"gemini-2.5-flash-preview-tts\").trim() ||\n \"gemini-2.5-flash-preview-tts\",\n (input.voice_name ?? existing?.voice_name ?? \"Kore\").trim() || \"Kore\",\n (input.voice_stt_model ?? existing?.voice_stt_model ?? \"gemini-2.5-flash\").trim() ||\n \"gemini-2.5-flash\",\n input.voice_auto_speak === undefined\n ? (existing?.voice_auto_speak ?? 1)\n : (input.voice_auto_speak ? 1 : 0),\n harnessId,\n delegateTargets,\n tierProportions,\n antiHallucMode,\n antiHallucModel,\n requireSourceLinks,\n created_at,\n t,\n );\n return getAgentConfig(input.id)!;\n}\n\nfunction clampPercent(next: number | undefined, fallback: number): number {\n const n = Number.isFinite(next) ? Number(next) : fallback;\n return Math.max(0, Math.min(100, Math.round(n)));\n}\n\nfunction toMbti(v: string | null | undefined): MbtiType | null {\n if (!v) return null;\n return (v in MBTI_PRESETS ? v : null) as MbtiType | null;\n}\n\nexport function deleteAgentConfig(id: string): boolean {\n return (\n (getDb().prepare(\"DELETE FROM agent_configs WHERE id=?\").run(id) as { changes: number }).changes > 0\n );\n}\n\nexport function generateAgentId(name: string): string {\n const slug = name\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .slice(0, 40);\n const suffix = Math.random().toString(36).slice(2, 6);\n return slug ? `${slug}-${suffix}` : `agent-${suffix}`;\n}\n\n// ── ADR-0022: per-agent message-channel display filters ─────────────────\n// Canonical channel keys mirrored in `hooks/useMessageFilters.ts`. Kept\n// in sync there by importing this constant — single source of truth.\nexport const DISPLAY_FILTER_KEYS = [\n \"scheduled_task\",\n \"watcher\",\n \"bridge\",\n \"synthetic\",\n \"tool_use\",\n \"thinking\",\n] as const;\nexport type DisplayFilterKey = (typeof DISPLAY_FILTER_KEYS)[number];\nexport type DisplayFilters = Record<DisplayFilterKey, boolean>;\n\nexport const DISPLAY_FILTER_DEFAULTS: DisplayFilters = {\n scheduled_task: true,\n watcher: true,\n bridge: true,\n synthetic: true,\n tool_use: true,\n thinking: true,\n};\n\nfunction parseDisplayFilters(raw: string | null | undefined): DisplayFilters {\n if (!raw) return { ...DISPLAY_FILTER_DEFAULTS };\n try {\n const parsed = JSON.parse(raw) as Partial<DisplayFilters>;\n // Merge over defaults so newly-added channels stay visible on old rows.\n return { ...DISPLAY_FILTER_DEFAULTS, ...parsed };\n } catch {\n return { ...DISPLAY_FILTER_DEFAULTS };\n }\n}\n\nexport function getAgentDisplayFilters(id: string): DisplayFilters | null {\n const row = getAgentConfig(id);\n if (!row) return null;\n return parseDisplayFilters(row.display_filters);\n}\n\n/**\n * Merge a partial filter map into the agent's stored prefs. Pass `null` to\n * reset to defaults (clears the column). Safe against concurrent toggles\n * from multiple browser tabs because the merge happens server-side.\n */\nexport function updateAgentDisplayFilters(\n id: string,\n patch: Partial<DisplayFilters> | null,\n): DisplayFilters | null {\n const row = getAgentConfig(id);\n if (!row) return null;\n if (patch === null) {\n getDb()\n .prepare(\"UPDATE agent_configs SET display_filters=NULL, updated_at=? WHERE id=?\")\n .run(now(), id);\n return { ...DISPLAY_FILTER_DEFAULTS };\n }\n const current = parseDisplayFilters(row.display_filters);\n const next: DisplayFilters = { ...current };\n for (const k of DISPLAY_FILTER_KEYS) {\n if (k in patch && typeof patch[k] === \"boolean\") next[k] = patch[k] as boolean;\n }\n getDb()\n .prepare(\"UPDATE agent_configs SET display_filters=?, updated_at=? WHERE id=?\")\n .run(JSON.stringify(next), now(), id);\n return next;\n}\n","// JSON.parse with a fallback value when the input is malformed (or empty).\n// Used everywhere we read responses from external APIs — they're contractually\n// JSON but a transient 502 / proxy interstitial occasionally returns HTML.\nexport function parseJsonSafe<T>(text: string, fallback: T): T;\nexport function parseJsonSafe<T>(text: string): T | undefined;\nexport function parseJsonSafe<T>(text: string, fallback?: T): T | undefined {\n try {\n return JSON.parse(text) as T;\n } catch {\n return fallback;\n }\n}\n","// Row → JSON-response serializers shared between list (`route.ts`) and\n// item (`[id]/route.ts`) handlers. Keeping these in one place stops the\n// list and item shapes from drifting (they were copy-pasted before).\n\nimport type { AgentConfigRow } from \"@/lib/stores/agent-configs\";\nimport { getAgentTierProportions, parseDelegateTargets } from \"@/lib/stores/agent-configs\";\nimport type { BridgeRow } from \"@/lib/stores/bridges\";\nimport type { McpServerRow } from \"@/lib/stores/mcp-servers\";\nimport type { MessageRow } from \"@/lib/stores/threads\";\nimport type { MessageUsageRow } from \"@/lib/stores/message-usage\";\nimport { parseJsonSafe } from \"@/lib/utils/json\";\n\nexport function agentToResponse(a: AgentConfigRow) {\n return {\n id: a.id,\n name: a.name,\n icon: a.icon,\n identity: a.identity,\n instructions: a.instructions,\n tools: parseJsonSafe<string[]>(a.tools, []),\n model_config_name: a.model_config_name,\n is_default: !!a.is_default,\n history_limit: a.history_limit,\n history_window_hours: a.history_window_hours,\n never_reply: !!a.never_reply,\n adaptive_persona_enabled: !!a.adaptive_persona_enabled,\n adaptive_persona_strength: a.adaptive_persona_strength,\n adaptive_empathy: a.adaptive_empathy,\n adaptive_expressiveness: a.adaptive_expressiveness,\n adaptive_verbosity: a.adaptive_verbosity,\n adaptive_mbti: a.adaptive_mbti,\n voice_enabled: !!a.voice_enabled,\n voice_model: a.voice_model,\n voice_name: a.voice_name,\n voice_stt_model: a.voice_stt_model,\n voice_auto_speak: !!a.voice_auto_speak,\n harness_id: a.harness_id,\n delegate_targets: parseDelegateTargets(a.delegate_targets),\n context_tier_proportions: getAgentTierProportions(a),\n anti_hallucination_mode: (a.anti_hallucination_mode === \"off\" || a.anti_hallucination_mode === \"regex\" || a.anti_hallucination_mode === \"model\")\n ? a.anti_hallucination_mode\n : null,\n anti_hallucination_model_config: a.anti_hallucination_model_config,\n require_source_links: !!a.require_source_links,\n created_at: a.created_at,\n updated_at: a.updated_at,\n };\n}\n\nexport function bridgeToResponse(r: BridgeRow) {\n return {\n id: r.id,\n kind: r.kind,\n name: r.name,\n status: r.status,\n last_error: r.last_error,\n paired_id: r.paired_id,\n enabled: r.enabled === 1,\n created_at: r.created_at,\n updated_at: r.updated_at,\n };\n}\n\nexport function mcpServerToResponse(r: McpServerRow) {\n return {\n name: r.name,\n transport: r.transport,\n spec: parseJsonSafe<unknown>(r.spec, null),\n enabled: r.enabled === 1,\n last_error: r.last_error,\n created_at: r.created_at,\n updated_at: r.updated_at,\n };\n}\n\n/**\n * Shape a `message_usage` row into the over-the-wire `usage` object the\n * chat panel's `ContextUsageBar` consumes. Returns `null` for messages\n * that have no snapshot (user turns and legacy assistant rows recorded\n * before the per-turn snapshot landed in ADR-0041).\n *\n * Anthropic prompt-cache tokens (PR #181 + the cache-fidelity follow-up)\n * are surfaced as additive fields so future UI work can render a\n * \"served from cache\" badge without another wire change. Both are\n * `null` for rows that predate cache plumbing or for providers that\n * don't expose a cache breakdown.\n */\nexport function messageUsageToResponse(u: MessageUsageRow | undefined | null) {\n if (!u) return null;\n return {\n input_tokens: u.input_tokens,\n output_tokens: u.output_tokens,\n hot_tokens: u.hot_tokens,\n warm_tokens: u.warm_tokens,\n facts_tokens: u.facts_tokens,\n overhead_tokens: u.overhead_tokens,\n hot_budget_tokens: u.hot_budget_tokens,\n warm_budget_tokens: u.warm_budget_tokens,\n facts_budget_tokens: u.facts_budget_tokens,\n context_window_tokens: u.context_window_tokens,\n cache_creation_input_tokens: u.cache_creation_input_tokens,\n cache_read_input_tokens: u.cache_read_input_tokens,\n };\n}\n\n/**\n * Shape one message row into its over-the-wire form, attaching its\n * per-turn `usage` snapshot when one exists. Pure data-shaping helper\n * extracted from the threads GET route so the wire contract has unit\n * coverage.\n */\nexport function messageToResponse(\n m: MessageRow,\n usageById: ReadonlyMap<string, MessageUsageRow>,\n) {\n return {\n id: m.msg_id,\n role: m.role,\n content: m.content,\n created_at: m.created_at,\n tool_events: parseToolEventsForResponse(m.tool_events),\n category: m.category ?? null,\n usage: messageUsageToResponse(usageById.get(m.msg_id)),\n metadata: parseMessageMetadataForResponse(m.metadata),\n };\n}\n\n/** Tolerant `tool_events` JSON parser shared with the route. Bad JSON\n * and non-array payloads collapse to `undefined` so the wire shape\n * always matches the typed client expectation. */\nexport function parseToolEventsForResponse(raw: string | null | undefined): unknown[] | undefined {\n if (!raw) return undefined;\n try {\n const parsed = JSON.parse(raw);\n return Array.isArray(parsed) ? parsed : undefined;\n } catch {\n return undefined;\n }\n}\n\n/** Tolerant `metadata` JSON parser. Returns `null` for missing/blank/\n * malformed/non-object payloads so the wire shape stays a plain object\n * or null — readers can rely on `metadata?.citations?...` chaining. */\nexport function parseMessageMetadataForResponse(raw: string | null | undefined): Record<string, unknown> | null {\n if (!raw) return null;\n try {\n const parsed = JSON.parse(raw);\n if (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) return null;\n return parsed as Record<string, unknown>;\n } catch {\n return null;\n }\n}\n\n/**\n * Resolve the bar's 100% baseline. Per-row `context_window_tokens`\n * (snapshotted at run time) wins so the bar matches the cap the agent\n * actually applied; legacy rows fall back to the model-config value;\n * unconfigured agents fall back to the default. Centralised so the\n * route and the UI share the same precedence rule.\n */\nexport function resolveContextWindowTokens(\n modelConfiguredTokens: number | null | undefined,\n defaultTokens: number,\n): number {\n if (typeof modelConfiguredTokens === \"number\" && modelConfiguredTokens > 0) {\n return modelConfiguredTokens;\n }\n return defaultTokens;\n}\n"],"names":["parseJsonSafe","toCreateAgentInput","id","body","name","trim","icon","identity","instructions","tools","model_config_name","is_default","history_limit","history_window_hours","never_reply","adaptive_persona_enabled","adaptive_persona_strength","adaptive_empathy","adaptive_expressiveness","adaptive_verbosity","adaptive_mbti","voice_enabled","voice_model","voice_name","voice_stt_model","voice_auto_speak","harness_id","delegate_targets","context_tier_proportions","anti_hallucination_mode","anti_hallucination_model_config","require_source_links","toUpdateAgentInput","existing","undefined","NextResponse","errorResponse","message","status","json","error","notFoundResponse","createdResponse","data","cachedJson","maxAgeSeconds","headers","validateBody","req","schema","raw","parsed","safeParse","success","issues","getDb","MBTI_PRESETS","now","Date","toISOString","getAgentTierProportions","row","JSON","parse","hot","Number","warm","facts","every","n","isFinite","listAgentConfigs","prepare","all","getDefaultAgentConfig","get","getAgentConfig","getAgentTools","cfg","Array","isArray","filter","x","length","parseDelegateTargets","ids","from","Set","upsertAgentConfig","input","t","db","created_at","mbti","toMbti","preset","strength","empathy","expressiveness","verbosity","run","harnessId","delegateTargets","stringify","tierProportions","Math","max","antiHallucMode","antiHallucModel","requireSourceLinks","clampPercent","next","fallback","min","round","v","deleteAgentConfig","changes","generateAgentId","slug","toLowerCase","replace","slice","suffix","random","toString","DISPLAY_FILTER_KEYS","DISPLAY_FILTER_DEFAULTS","scheduled_task","watcher","bridge","synthetic","tool_use","thinking","parseDisplayFilters","getAgentDisplayFilters","display_filters","updateAgentDisplayFilters","patch","current","k","text","agentToResponse","a","updated_at","bridgeToResponse","r","kind","last_error","paired_id","enabled","mcpServerToResponse","transport","spec","messageUsageToResponse","u","input_tokens","output_tokens","hot_tokens","warm_tokens","facts_tokens","overhead_tokens","hot_budget_tokens","warm_budget_tokens","facts_budget_tokens","context_window_tokens","cache_creation_input_tokens","cache_read_input_tokens","messageToResponse","m","usageById","msg_id","role","content","tool_events","parseToolEventsForResponse","category","usage","metadata","parseMessageMetadataForResponse","resolveContextWindowTokens","modelConfiguredTokens","defaultTokens"],"sourceRoot":"","ignoreList":[]}
@@ -108,11 +108,11 @@ function deleteMemory(namespace, key) {
108
108
 
109
109
  // EXPORTS
110
110
  __webpack_require__.d(__webpack_exports__, {
111
- sO: () => (/* binding */ getProvider)
111
+ X4: () => (/* binding */ BUILTIN_PROVIDER_NAMES),
112
+ sO: () => (/* binding */ getProvider),
113
+ Yb: () => (/* binding */ listProviderNames)
112
114
  });
113
115
 
114
- // UNUSED EXPORTS: BUILTIN_PROVIDER_NAMES, listProviderNames
115
-
116
116
  // EXTERNAL MODULE: ./node_modules/openai/index.mjs + 138 modules
117
117
  var openai = __webpack_require__(15989);
118
118
  ;// ./lib/providers/openai.ts
@@ -486,6 +486,87 @@ function appendServerTools(anthropicTools, params) {
486
486
  }
487
487
  return merged;
488
488
  }
489
+ // Anthropic prompt-caching breakpoints. Within a multi-tool ReAct turn the
490
+ // system prompt + tools are stable across every LLM call, and tool_results
491
+ // only grow at the tail — exactly the prefix Anthropic's ephemeral cache is
492
+ // built for. We mark three breakpoints (system, last tool, last tool_result)
493
+ // so calls 2..N read the prefix at ~10% the input rate. The prefix below the
494
+ // minimum cacheable size is silently ignored by the API at no extra cost,
495
+ // so it is safe to mark unconditionally.
496
+ const EPHEMERAL = {
497
+ type: "ephemeral"
498
+ };
499
+ function withSystemCacheControl(text) {
500
+ if (!text) return undefined;
501
+ return [
502
+ {
503
+ type: "text",
504
+ text,
505
+ cache_control: EPHEMERAL
506
+ }
507
+ ];
508
+ }
509
+ function withToolsCacheControl(tools) {
510
+ if (tools.length === 0) return tools;
511
+ const last = tools[tools.length - 1];
512
+ return [
513
+ ...tools.slice(0, -1),
514
+ {
515
+ ...last,
516
+ cache_control: EPHEMERAL
517
+ }
518
+ ];
519
+ }
520
+ function withLastToolResultCacheControl(messages) {
521
+ for(let i = messages.length - 1; i >= 0; i--){
522
+ const m = messages[i];
523
+ if (typeof m.content === "string") continue;
524
+ const blocks = m.content;
525
+ for(let j = blocks.length - 1; j >= 0; j--){
526
+ const b = blocks[j];
527
+ if (b.type === "tool_result") {
528
+ const newBlocks = [
529
+ ...blocks
530
+ ];
531
+ newBlocks[j] = {
532
+ ...b,
533
+ cache_control: EPHEMERAL
534
+ };
535
+ const next = [
536
+ ...messages
537
+ ];
538
+ next[i] = {
539
+ ...m,
540
+ content: newBlocks
541
+ };
542
+ return next;
543
+ }
544
+ }
545
+ }
546
+ return messages;
547
+ }
548
+ function usageEventFromStart(usage) {
549
+ if (!usage) return null;
550
+ return {
551
+ type: "usage",
552
+ input_tokens: usage.input_tokens ?? 0,
553
+ output_tokens: usage.output_tokens ?? 0,
554
+ cache_creation_input_tokens: usage.cache_creation_input_tokens ?? 0,
555
+ cache_read_input_tokens: usage.cache_read_input_tokens ?? 0
556
+ };
557
+ }
558
+ function usageEventFromDelta(usage) {
559
+ if (!usage) return null;
560
+ // message_delta only carries the *final* output_tokens; input/cache fields
561
+ // are already accounted for from message_start. Emitting just the output
562
+ // delta here keeps the agent loop's running total accurate without
563
+ // double-counting cache reads.
564
+ return {
565
+ type: "usage",
566
+ input_tokens: 0,
567
+ output_tokens: usage.output_tokens ?? 0
568
+ };
569
+ }
489
570
  const anthropicProvider = {
490
571
  name: "anthropic",
491
572
  async chat (model_id, messages, params) {
@@ -503,7 +584,7 @@ const anthropicProvider = {
503
584
  const stream = await client.messages.stream({
504
585
  model: model_id,
505
586
  max_tokens: params.max_tokens ?? 4096,
506
- system: systemText || undefined,
587
+ system: withSystemCacheControl(systemText),
507
588
  messages: userMessages
508
589
  });
509
590
  return {
@@ -523,12 +604,13 @@ const anthropicProvider = {
523
604
  defaultHeaders: params.extra_headers
524
605
  });
525
606
  const systemMsg = messages.find((m)=>m.role === "system");
526
- const msgList = toAnthropicMessages(messages.filter((m)=>m.role !== "system"));
527
- const anthropicTools = appendServerTools(toAnthropicTools(tools), params);
607
+ const systemText = typeof systemMsg?.content === "string" ? systemMsg.content : "";
608
+ const msgList = withLastToolResultCacheControl(toAnthropicMessages(messages.filter((m)=>m.role !== "system")));
609
+ const anthropicTools = withToolsCacheControl(appendServerTools(toAnthropicTools(tools), params));
528
610
  const resp = await client.messages.create({
529
611
  model: model_id,
530
612
  max_tokens: params.max_tokens ?? 4096,
531
- system: typeof systemMsg?.content === "string" ? systemMsg.content : undefined,
613
+ system: withSystemCacheControl(systemText),
532
614
  messages: msgList,
533
615
  tools: anthropicTools,
534
616
  ...params.thinking ? {
@@ -556,15 +638,17 @@ const anthropicProvider = {
556
638
  defaultHeaders: params.extra_headers
557
639
  });
558
640
  const systemMsg = messages.find((m)=>m.role === "system");
559
- const msgList = toAnthropicMessages(messages.filter((m)=>m.role !== "system"));
560
- const anthropicTools = appendServerTools(toAnthropicTools(tools), params);
641
+ const systemText = typeof systemMsg?.content === "string" ? systemMsg.content : "";
642
+ const msgList = withLastToolResultCacheControl(toAnthropicMessages(messages.filter((m)=>m.role !== "system")));
643
+ const anthropicTools = withToolsCacheControl(appendServerTools(toAnthropicTools(tools), params));
561
644
  const body = {
562
645
  model: model_id,
563
646
  max_tokens: params.max_tokens ?? 4096,
564
647
  messages: msgList,
565
648
  ...pickAnthropicOptions(params)
566
649
  };
567
- if (typeof systemMsg?.content === "string") body.system = systemMsg.content;
650
+ const systemParam = withSystemCacheControl(systemText);
651
+ if (systemParam) body.system = systemParam;
568
652
  if (anthropicTools.length > 0) body.tools = anthropicTools;
569
653
  if (params.thinking) {
570
654
  body.thinking = params.thinking;
@@ -573,6 +657,12 @@ const anthropicProvider = {
573
657
  const stream = client.messages.stream(body);
574
658
  const blockType = new Map();
575
659
  for await (const event of stream){
660
+ if (event.type === "message_start") {
661
+ const ev = event;
662
+ const u = usageEventFromStart(ev.message?.usage);
663
+ if (u) yield u;
664
+ continue;
665
+ }
576
666
  if (event.type === "content_block_start") {
577
667
  const cb = event.content_block;
578
668
  if (cb.type === "tool_use") {
@@ -607,12 +697,17 @@ const anthropicProvider = {
607
697
  args_delta: d.partial_json
608
698
  };
609
699
  }
610
- } else if (event.type === "message_delta" && event.delta?.stop_reason) {
611
- const reason = event.delta.stop_reason;
612
- yield {
613
- type: "stop",
614
- reason: reason === "tool_use" ? "tool_use" : reason === "max_tokens" ? "length" : "stop"
615
- };
700
+ } else if (event.type === "message_delta") {
701
+ const delta = event;
702
+ const u = usageEventFromDelta(delta.usage);
703
+ if (u) yield u;
704
+ if (event.delta?.stop_reason) {
705
+ const reason = event.delta.stop_reason;
706
+ yield {
707
+ type: "stop",
708
+ reason: reason === "tool_use" ? "tool_use" : reason === "max_tokens" ? "length" : "stop"
709
+ };
710
+ }
616
711
  }
617
712
  }
618
713
  }();
@@ -3228,6 +3323,7 @@ function runMigrations(db) {
3228
3323
  ensureScheduledTasksReactionKindColumns(db);
3229
3324
  ensureMessageUsageTable(db);
3230
3325
  ensureMessageUsageTierColumns(db);
3326
+ ensureMessageUsageCacheColumns(db);
3231
3327
  ensureThreadContextPinColumns(db);
3232
3328
  ensureThreadChannelSummariesTable(db);
3233
3329
  seedModelConfigs(db);
@@ -3638,6 +3734,19 @@ function ensureMessageUsageTierColumns(db) {
3638
3734
  if (!names.has("facts_budget_tokens")) db.exec("ALTER TABLE message_usage ADD COLUMN facts_budget_tokens INTEGER");
3639
3735
  if (!names.has("context_window_tokens")) db.exec("ALTER TABLE message_usage ADD COLUMN context_window_tokens INTEGER");
3640
3736
  }
3737
+ // PR #181 enabled Anthropic prompt caching, but the per-turn usage snapshot
3738
+ // only captured `input_tokens` / `output_tokens`. Anthropic returns cache
3739
+ // reads and writes as separate counts (priced at 0.1× and 1.25× the input
3740
+ // rate respectively), so without these columns the dashboard underreports
3741
+ // cost on cache-creating turns and *over*reports on cache-hitting turns.
3742
+ // Both columns are nullable: legacy rows and non-Anthropic providers leave
3743
+ // them NULL.
3744
+ function ensureMessageUsageCacheColumns(db) {
3745
+ const cols = db.prepare("PRAGMA table_info(message_usage)").all();
3746
+ const names = new Set(cols.map((c)=>c.name));
3747
+ if (!names.has("cache_creation_input_tokens")) db.exec("ALTER TABLE message_usage ADD COLUMN cache_creation_input_tokens INTEGER");
3748
+ if (!names.has("cache_read_input_tokens")) db.exec("ALTER TABLE message_usage ADD COLUMN cache_read_input_tokens INTEGER");
3749
+ }
3641
3750
  function seedAgentConfigs(db) {
3642
3751
  // Only seed on first run — once the user has any agents we must not
3643
3752
  // resurrect ones they've deleted (e.g. the legacy "echo" / "llm" defaults).