@cogenta/agents 0.2.0 → 0.4.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 (229) hide show
  1. package/dist/agents/builtins.d.ts +51 -0
  2. package/dist/agents/builtins.d.ts.map +1 -0
  3. package/dist/agents/builtins.js +190 -0
  4. package/dist/agents/builtins.js.map +1 -0
  5. package/dist/agents/orchestrator.d.ts +95 -0
  6. package/dist/agents/orchestrator.d.ts.map +1 -0
  7. package/dist/agents/orchestrator.js +285 -0
  8. package/dist/agents/orchestrator.js.map +1 -0
  9. package/dist/agents/store.d.ts +71 -0
  10. package/dist/agents/store.d.ts.map +1 -0
  11. package/dist/agents/store.js +211 -0
  12. package/dist/agents/store.js.map +1 -0
  13. package/dist/agents/types.d.ts +10 -0
  14. package/dist/agents/types.d.ts.map +1 -1
  15. package/dist/assist/agent-identity.d.ts +44 -0
  16. package/dist/assist/agent-identity.d.ts.map +1 -0
  17. package/dist/assist/agent-identity.js +136 -0
  18. package/dist/assist/agent-identity.js.map +1 -0
  19. package/dist/assist/chat.d.ts +2 -0
  20. package/dist/assist/chat.d.ts.map +1 -1
  21. package/dist/assist/chat.js +14 -5
  22. package/dist/assist/chat.js.map +1 -1
  23. package/dist/assist/classify.d.ts +3 -2
  24. package/dist/assist/classify.d.ts.map +1 -1
  25. package/dist/assist/classify.js +30 -11
  26. package/dist/assist/classify.js.map +1 -1
  27. package/dist/assist/faq.d.ts +3 -2
  28. package/dist/assist/faq.d.ts.map +1 -1
  29. package/dist/assist/faq.js +31 -13
  30. package/dist/assist/faq.js.map +1 -1
  31. package/dist/assist/runtime.d.ts +8 -2
  32. package/dist/assist/runtime.d.ts.map +1 -1
  33. package/dist/assist/runtime.js +2 -2
  34. package/dist/assist/runtime.js.map +1 -1
  35. package/dist/assist/toolset.d.ts +10 -0
  36. package/dist/assist/toolset.d.ts.map +1 -1
  37. package/dist/assist/toolset.js +36 -8
  38. package/dist/assist/toolset.js.map +1 -1
  39. package/dist/assist/usage.d.ts +58 -0
  40. package/dist/assist/usage.d.ts.map +1 -0
  41. package/dist/assist/usage.js +53 -0
  42. package/dist/assist/usage.js.map +1 -0
  43. package/dist/assist/writing.d.ts +10 -9
  44. package/dist/assist/writing.d.ts.map +1 -1
  45. package/dist/assist/writing.js +126 -58
  46. package/dist/assist/writing.js.map +1 -1
  47. package/dist/audit/with-audit.d.ts +13 -0
  48. package/dist/audit/with-audit.d.ts.map +1 -1
  49. package/dist/audit/with-audit.js +6 -0
  50. package/dist/audit/with-audit.js.map +1 -1
  51. package/dist/autonomy/levels.d.ts +37 -0
  52. package/dist/autonomy/levels.d.ts.map +1 -0
  53. package/dist/autonomy/levels.js +51 -0
  54. package/dist/autonomy/levels.js.map +1 -0
  55. package/dist/conversations/store.d.ts +62 -0
  56. package/dist/conversations/store.d.ts.map +1 -0
  57. package/dist/conversations/store.js +0 -0
  58. package/dist/conversations/store.js.map +1 -0
  59. package/dist/identity/context.d.ts +8 -0
  60. package/dist/identity/context.d.ts.map +1 -1
  61. package/dist/identity/context.js +19 -4
  62. package/dist/identity/context.js.map +1 -1
  63. package/dist/identity/markdown.d.ts +38 -0
  64. package/dist/identity/markdown.d.ts.map +1 -0
  65. package/dist/identity/markdown.js +85 -0
  66. package/dist/identity/markdown.js.map +1 -0
  67. package/dist/index.d.ts +56 -5
  68. package/dist/index.d.ts.map +1 -1
  69. package/dist/index.js +30 -3
  70. package/dist/index.js.map +1 -1
  71. package/dist/prompts/render.d.ts +23 -0
  72. package/dist/prompts/render.d.ts.map +1 -0
  73. package/dist/prompts/render.js +35 -0
  74. package/dist/prompts/render.js.map +1 -0
  75. package/dist/prompts/seeds.d.ts +34 -0
  76. package/dist/prompts/seeds.d.ts.map +1 -0
  77. package/dist/prompts/seeds.js +166 -0
  78. package/dist/prompts/seeds.js.map +1 -0
  79. package/dist/prompts/store.d.ts +8 -0
  80. package/dist/prompts/store.d.ts.map +1 -0
  81. package/dist/prompts/store.js +153 -0
  82. package/dist/prompts/store.js.map +1 -0
  83. package/dist/prompts/types.d.ts +51 -0
  84. package/dist/prompts/types.d.ts.map +1 -0
  85. package/dist/prompts/types.js +24 -0
  86. package/dist/prompts/types.js.map +1 -0
  87. package/dist/providers/anthropic.d.ts +21 -3
  88. package/dist/providers/anthropic.d.ts.map +1 -1
  89. package/dist/providers/anthropic.js +60 -12
  90. package/dist/providers/anthropic.js.map +1 -1
  91. package/dist/providers/catalog.d.ts +41 -0
  92. package/dist/providers/catalog.d.ts.map +1 -0
  93. package/dist/providers/catalog.js +85 -0
  94. package/dist/providers/catalog.js.map +1 -0
  95. package/dist/providers/content-parts.d.ts +12 -0
  96. package/dist/providers/content-parts.d.ts.map +1 -0
  97. package/dist/providers/content-parts.js +18 -0
  98. package/dist/providers/content-parts.js.map +1 -0
  99. package/dist/providers/defaults.d.ts +15 -0
  100. package/dist/providers/defaults.d.ts.map +1 -0
  101. package/dist/providers/defaults.js +15 -0
  102. package/dist/providers/defaults.js.map +1 -0
  103. package/dist/providers/google.d.ts +16 -3
  104. package/dist/providers/google.d.ts.map +1 -1
  105. package/dist/providers/google.js +54 -12
  106. package/dist/providers/google.js.map +1 -1
  107. package/dist/providers/openai.d.ts +32 -4
  108. package/dist/providers/openai.d.ts.map +1 -1
  109. package/dist/providers/openai.js +114 -21
  110. package/dist/providers/openai.js.map +1 -1
  111. package/dist/providers/registry.d.ts +31 -20
  112. package/dist/providers/registry.d.ts.map +1 -1
  113. package/dist/providers/registry.js +49 -7
  114. package/dist/providers/registry.js.map +1 -1
  115. package/dist/providers/request-signal.d.ts +23 -0
  116. package/dist/providers/request-signal.d.ts.map +1 -0
  117. package/dist/providers/request-signal.js +26 -0
  118. package/dist/providers/request-signal.js.map +1 -0
  119. package/dist/providers/resolve.d.ts +13 -0
  120. package/dist/providers/resolve.d.ts.map +1 -0
  121. package/dist/providers/resolve.js +30 -0
  122. package/dist/providers/resolve.js.map +1 -0
  123. package/dist/providers/store.d.ts +70 -0
  124. package/dist/providers/store.d.ts.map +1 -0
  125. package/dist/providers/store.js +308 -0
  126. package/dist/providers/store.js.map +1 -0
  127. package/dist/providers/tool-names.d.ts +9 -0
  128. package/dist/providers/tool-names.d.ts.map +1 -0
  129. package/dist/providers/tool-names.js +56 -0
  130. package/dist/providers/tool-names.js.map +1 -0
  131. package/dist/providers/types.d.ts +78 -3
  132. package/dist/providers/types.d.ts.map +1 -1
  133. package/dist/rag/reference-documents/ingest.d.ts +22 -0
  134. package/dist/rag/reference-documents/ingest.d.ts.map +1 -0
  135. package/dist/rag/reference-documents/ingest.js +69 -0
  136. package/dist/rag/reference-documents/ingest.js.map +1 -0
  137. package/dist/rag/reference-documents/store.d.ts +23 -0
  138. package/dist/rag/reference-documents/store.d.ts.map +1 -0
  139. package/dist/rag/reference-documents/store.js +140 -0
  140. package/dist/rag/reference-documents/store.js.map +1 -0
  141. package/dist/rag/reference-documents/types.d.ts +52 -0
  142. package/dist/rag/reference-documents/types.d.ts.map +1 -0
  143. package/dist/rag/reference-documents/types.js +32 -0
  144. package/dist/rag/reference-documents/types.js.map +1 -0
  145. package/dist/runtime/loop.d.ts +29 -7
  146. package/dist/runtime/loop.d.ts.map +1 -1
  147. package/dist/runtime/loop.js +200 -42
  148. package/dist/runtime/loop.js.map +1 -1
  149. package/dist/runtime/types.d.ts +4 -3
  150. package/dist/runtime/types.d.ts.map +1 -1
  151. package/dist/site-plan/analyse-brief.d.ts +8 -0
  152. package/dist/site-plan/analyse-brief.d.ts.map +1 -1
  153. package/dist/site-plan/analyse-brief.js +18 -7
  154. package/dist/site-plan/analyse-brief.js.map +1 -1
  155. package/dist/site-plan/approval.d.ts +2 -2
  156. package/dist/site-plan/approval.d.ts.map +1 -1
  157. package/dist/site-plan/approval.js +34 -4
  158. package/dist/site-plan/approval.js.map +1 -1
  159. package/dist/site-plan/content-model.d.ts +14 -0
  160. package/dist/site-plan/content-model.d.ts.map +1 -1
  161. package/dist/site-plan/content-model.js +52 -8
  162. package/dist/site-plan/content-model.js.map +1 -1
  163. package/dist/site-plan/demo-content.js +2 -3
  164. package/dist/site-plan/demo-content.js.map +1 -1
  165. package/dist/site-plan/propose-plan.d.ts +10 -0
  166. package/dist/site-plan/propose-plan.d.ts.map +1 -1
  167. package/dist/site-plan/propose-plan.js +25 -1
  168. package/dist/site-plan/propose-plan.js.map +1 -1
  169. package/dist/site-plan/site-context.d.ts +81 -0
  170. package/dist/site-plan/site-context.d.ts.map +1 -0
  171. package/dist/site-plan/site-context.js +76 -0
  172. package/dist/site-plan/site-context.js.map +1 -0
  173. package/dist/site-plan/skin-candidates.d.ts +7 -0
  174. package/dist/site-plan/skin-candidates.d.ts.map +1 -1
  175. package/dist/site-plan/skin-candidates.js +6 -0
  176. package/dist/site-plan/skin-candidates.js.map +1 -1
  177. package/dist/site-plan/structural-gaps.d.ts +32 -0
  178. package/dist/site-plan/structural-gaps.d.ts.map +1 -0
  179. package/dist/site-plan/structural-gaps.js +77 -0
  180. package/dist/site-plan/structural-gaps.js.map +1 -0
  181. package/dist/site-plan/types.d.ts +7 -0
  182. package/dist/site-plan/types.d.ts.map +1 -1
  183. package/dist/skills/frontmatter.d.ts +19 -1
  184. package/dist/skills/frontmatter.d.ts.map +1 -1
  185. package/dist/skills/frontmatter.js +29 -5
  186. package/dist/skills/frontmatter.js.map +1 -1
  187. package/dist/skills/library.d.ts +133 -0
  188. package/dist/skills/library.d.ts.map +1 -0
  189. package/dist/skills/library.js +332 -0
  190. package/dist/skills/library.js.map +1 -0
  191. package/dist/skills/types.d.ts +8 -1
  192. package/dist/skills/types.d.ts.map +1 -1
  193. package/dist/skin/generate.d.ts +10 -0
  194. package/dist/skin/generate.d.ts.map +1 -1
  195. package/dist/skin/generate.js +43 -4
  196. package/dist/skin/generate.js.map +1 -1
  197. package/dist/theme-creator/propose-theme.d.ts +77 -0
  198. package/dist/theme-creator/propose-theme.d.ts.map +1 -0
  199. package/dist/theme-creator/propose-theme.js +228 -0
  200. package/dist/theme-creator/propose-theme.js.map +1 -0
  201. package/dist/tools/core/agent-delegate.d.ts +8 -5
  202. package/dist/tools/core/agent-delegate.d.ts.map +1 -1
  203. package/dist/tools/core/agent-delegate.js +16 -6
  204. package/dist/tools/core/agent-delegate.js.map +1 -1
  205. package/dist/tools/core/content-browse.d.ts +74 -0
  206. package/dist/tools/core/content-browse.d.ts.map +1 -0
  207. package/dist/tools/core/content-browse.js +63 -0
  208. package/dist/tools/core/content-browse.js.map +1 -0
  209. package/dist/tools/core/content-schema.d.ts +86 -0
  210. package/dist/tools/core/content-schema.d.ts.map +1 -0
  211. package/dist/tools/core/content-schema.js +83 -0
  212. package/dist/tools/core/content-schema.js.map +1 -0
  213. package/dist/tools/core/deps-scan.d.ts +25 -0
  214. package/dist/tools/core/deps-scan.d.ts.map +1 -0
  215. package/dist/tools/core/deps-scan.js +85 -0
  216. package/dist/tools/core/deps-scan.js.map +1 -0
  217. package/dist/tools/core/media.d.ts +18 -2
  218. package/dist/tools/core/media.d.ts.map +1 -1
  219. package/dist/tools/core/media.js +8 -2
  220. package/dist/tools/core/media.js.map +1 -1
  221. package/dist/tools/core/not-found-log.d.ts +44 -0
  222. package/dist/tools/core/not-found-log.d.ts.map +1 -0
  223. package/dist/tools/core/not-found-log.js +32 -0
  224. package/dist/tools/core/not-found-log.js.map +1 -0
  225. package/dist/tools/core/redirects.d.ts +51 -0
  226. package/dist/tools/core/redirects.d.ts.map +1 -0
  227. package/dist/tools/core/redirects.js +50 -0
  228. package/dist/tools/core/redirects.js.map +1 -0
  229. package/package.json +6 -4
@@ -1 +1 @@
1
- {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/providers/registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAC5C,OAAO,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAA;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAChD,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAGhD,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,WAAW,EAAE,QAAQ,EAAE,QAAQ,CAAU,CAAA;AAaxE;;;;;GAKG;AACH,MAAM,UAAU,sBAAsB,CAAC,MAA8B;IAInE,MAAM,OAAO,GAAG,IAAI,GAAG,EAAgC,CAAA;IACvD,IAAI,MAAM,CAAC,SAAS,KAAK,SAAS;QAChC,OAAO,CAAC,GAAG,CAAC,WAAW,EAAE,qBAAqB,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAA;IACnE,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS;QAAE,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,kBAAkB,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAA;IACzF,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS;QAAE,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,kBAAkB,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAA;IAEzF,OAAO;QACL,GAAG,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;QAChC,GAAG,CAAC,IAAI;YACN,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;YAChC,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;gBACzB,MAAM,IAAI,YAAY,CAAC;oBACrB,IAAI,EAAE,kBAAkB;oBACxB,OAAO,EAAE,sBAAsB,IAAI,gCAAgC;oBACnE,IAAI,EAAE,sEAAsE;iBAC7E,CAAC,CAAA;YACJ,CAAC;YACD,OAAO,MAAM,CAAA;QACf,CAAC;KACF,CAAA;AACH,CAAC"}
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/providers/registry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Every default-`false` timeout: none of the three adapters ever bounded a
3
+ * model call on their own — `ChatOptions.signal` only cancels when a caller
4
+ * (the run loop's own cancellation, task 2) supplies one, and the run loop
5
+ * never does for a single chat turn triggered by `POST
6
+ * .../conversation/messages`. Reproduced live: a stalled DeepSeek response
7
+ * left that request (and the browser tab awaiting it) hung for minutes with
8
+ * no error, nothing in the server log, and no way to recover short of
9
+ * killing the process. This is the floor every adapter now falls back to
10
+ * when the caller supplies no signal of its own — a stalled vendor fails
11
+ * with a named error instead of hanging the caller forever.
12
+ */
13
+ export declare const DEFAULT_PROVIDER_REQUEST_TIMEOUT_MS = 180000;
14
+ /**
15
+ * The caller's own signal (if any) combined with a timeout floor, so a
16
+ * cancellation the run loop already wants (budget exceeded, kill switch)
17
+ * still works exactly as before, and an otherwise-uncancelled call still
18
+ * gives up eventually. `timeoutMs` defaults to the real floor above —
19
+ * overridable only so a test can prove the behaviour without a real
20
+ * two-minute wait.
21
+ */
22
+ export declare function requestSignalWithTimeout(callerSignal: AbortSignal | undefined, timeoutMs?: number): AbortSignal;
23
+ //# sourceMappingURL=request-signal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-signal.d.ts","sourceRoot":"","sources":["../../src/providers/request-signal.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,mCAAmC,SAAU,CAAA;AAE1D;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CACtC,YAAY,EAAE,WAAW,GAAG,SAAS,EACrC,SAAS,GAAE,MAA4C,GACtD,WAAW,CAGb"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Every default-`false` timeout: none of the three adapters ever bounded a
3
+ * model call on their own — `ChatOptions.signal` only cancels when a caller
4
+ * (the run loop's own cancellation, task 2) supplies one, and the run loop
5
+ * never does for a single chat turn triggered by `POST
6
+ * .../conversation/messages`. Reproduced live: a stalled DeepSeek response
7
+ * left that request (and the browser tab awaiting it) hung for minutes with
8
+ * no error, nothing in the server log, and no way to recover short of
9
+ * killing the process. This is the floor every adapter now falls back to
10
+ * when the caller supplies no signal of its own — a stalled vendor fails
11
+ * with a named error instead of hanging the caller forever.
12
+ */
13
+ export const DEFAULT_PROVIDER_REQUEST_TIMEOUT_MS = 180_000;
14
+ /**
15
+ * The caller's own signal (if any) combined with a timeout floor, so a
16
+ * cancellation the run loop already wants (budget exceeded, kill switch)
17
+ * still works exactly as before, and an otherwise-uncancelled call still
18
+ * gives up eventually. `timeoutMs` defaults to the real floor above —
19
+ * overridable only so a test can prove the behaviour without a real
20
+ * two-minute wait.
21
+ */
22
+ export function requestSignalWithTimeout(callerSignal, timeoutMs = DEFAULT_PROVIDER_REQUEST_TIMEOUT_MS) {
23
+ const timeoutSignal = AbortSignal.timeout(timeoutMs);
24
+ return callerSignal === undefined ? timeoutSignal : AbortSignal.any([callerSignal, timeoutSignal]);
25
+ }
26
+ //# sourceMappingURL=request-signal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-signal.js","sourceRoot":"","sources":["../../src/providers/request-signal.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,mCAAmC,GAAG,OAAO,CAAA;AAE1D;;;;;;;GAOG;AACH,MAAM,UAAU,wBAAwB,CACtC,YAAqC,EACrC,SAAS,GAAW,mCAAmC;IAEvD,MAAM,aAAa,GAAG,WAAW,CAAC,OAAO,CAAC,SAAS,CAAC,CAAA;IACpD,OAAO,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,YAAY,EAAE,aAAa,CAAC,CAAC,CAAA;AACpG,CAAC"}
@@ -0,0 +1,13 @@
1
+ import type { ProviderRegistryConfig } from './registry.js';
2
+ import type { ProviderConfigStore } from './store.js';
3
+ /**
4
+ * Turns the persisted, encrypted `ProviderConfigStore` into the plaintext
5
+ * shape `createProviderRegistry` needs — the one place a key is decrypted
6
+ * for actual use (R7: never logged, never returned from this function's
7
+ * caller over the wire). A provider with no saved key, or saved but
8
+ * disabled, is simply absent from the result — exactly R2's "no provider
9
+ * configured" state `createProviderRegistry`'s own doc comment already
10
+ * describes.
11
+ */
12
+ export declare function resolveProviderRegistryConfig(store: ProviderConfigStore): Promise<ProviderRegistryConfig>;
13
+ //# sourceMappingURL=resolve.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../src/providers/resolve.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAA;AAC3D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAA;AAErD;;;;;;;;GAQG;AACH,wBAAsB,6BAA6B,CACjD,KAAK,EAAE,mBAAmB,GACzB,OAAO,CAAC,sBAAsB,CAAC,CA4BjC"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Turns the persisted, encrypted `ProviderConfigStore` into the plaintext
3
+ * shape `createProviderRegistry` needs — the one place a key is decrypted
4
+ * for actual use (R7: never logged, never returned from this function's
5
+ * caller over the wire). A provider with no saved key, or saved but
6
+ * disabled, is simply absent from the result — exactly R2's "no provider
7
+ * configured" state `createProviderRegistry`'s own doc comment already
8
+ * describes.
9
+ */
10
+ export async function resolveProviderRegistryConfig(store) {
11
+ const configs = await store.list();
12
+ const config = {};
13
+ for (const entry of configs) {
14
+ if (!entry.enabled)
15
+ continue;
16
+ const apiKey = await store.decryptKey(entry.provider);
17
+ config[entry.provider] = {
18
+ apiKey,
19
+ model: entry.model,
20
+ ...(entry.baseUrl === undefined ? {} : { baseUrl: entry.baseUrl }),
21
+ ...(entry.maxOutputTokens === undefined ? {} : { maxOutputTokens: entry.maxOutputTokens }),
22
+ ...(entry.requestTimeoutMs === undefined ? {} : { requestTimeoutMs: entry.requestTimeoutMs }),
23
+ ...(entry.maxCorrectionAttempts === undefined
24
+ ? {}
25
+ : { maxCorrectionAttempts: entry.maxCorrectionAttempts }),
26
+ };
27
+ }
28
+ return config;
29
+ }
30
+ //# sourceMappingURL=resolve.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve.js","sourceRoot":"","sources":["../../src/providers/resolve.ts"],"names":[],"mappings":"AAGA;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,6BAA6B,CACjD,KAA0B;IAE1B,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC,IAAI,EAAE,CAAA;IAClC,MAAM,MAAM,GAUR,EAAE,CAAA;IACN,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,CAAC,KAAK,CAAC,OAAO;YAAE,SAAQ;QAC5B,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAA;QACrD,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG;YACvB,MAAM;YACN,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,GAAG,CAAC,KAAK,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC;YAClE,GAAG,CAAC,KAAK,CAAC,eAAe,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,KAAK,CAAC,eAAe,EAAE,CAAC;YAC1F,GAAG,CAAC,KAAK,CAAC,gBAAgB,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,gBAAgB,EAAE,KAAK,CAAC,gBAAgB,EAAE,CAAC;YAC7F,GAAG,CAAC,KAAK,CAAC,qBAAqB,KAAK,SAAS;gBAC3C,CAAC,CAAC,EAAE;gBACJ,CAAC,CAAC,EAAE,qBAAqB,EAAE,KAAK,CAAC,qBAAqB,EAAE,CAAC;SAC5D,CAAA;IACH,CAAC;IACD,OAAO,MAAgC,CAAA;AACzC,CAAC"}
@@ -0,0 +1,70 @@
1
+ import type { ProviderName } from './registry.js';
2
+ export interface StoredProviderConfig {
3
+ readonly provider: ProviderName;
4
+ readonly enabled: boolean;
5
+ readonly model: string;
6
+ readonly baseUrl?: string;
7
+ /** Last 4 characters of the real key, for the admin to confirm which key is saved without ever re-displaying it in full. */
8
+ readonly maskedKey: string;
9
+ readonly updatedAt: string;
10
+ /**
11
+ * The completion budget (`ProviderClient.maxOutputTokens`), request retry
12
+ * count (`maxCorrectionAttempts`) and HTTP/agent-loop timeout
13
+ * (`requestTimeoutMs`, milliseconds) this provider's client resolves to.
14
+ * Absent means "use the built-in fallback" (`resolve.ts`) — every one of
15
+ * these was, before this admin surface existed, a number hardcoded per
16
+ * call site with no way for an admin to say "this particular model needs
17
+ * more room to think" (the exact bug a real reasoning-model run
18
+ * reproduced: DeepSeek's `deepseek-v4-flash` silently truncated to an
19
+ * empty response at a too-low hardcoded ceiling).
20
+ */
21
+ readonly maxOutputTokens?: number;
22
+ readonly requestTimeoutMs?: number;
23
+ readonly maxCorrectionAttempts?: number;
24
+ }
25
+ export interface ProviderConfigInput {
26
+ readonly provider: ProviderName;
27
+ readonly apiKey: string;
28
+ readonly model: string;
29
+ readonly baseUrl?: string;
30
+ readonly enabled?: boolean;
31
+ readonly maxOutputTokens?: number;
32
+ readonly requestTimeoutMs?: number;
33
+ readonly maxCorrectionAttempts?: number;
34
+ }
35
+ export interface ProviderConfigStore {
36
+ list(): Promise<readonly StoredProviderConfig[]>;
37
+ get(provider: ProviderName): Promise<StoredProviderConfig | undefined>;
38
+ /** Encrypts and persists `apiKey`; creates or overwrites this provider's one record. */
39
+ upsert(input: ProviderConfigInput): Promise<StoredProviderConfig>;
40
+ setEnabled(provider: ProviderName, enabled: boolean): Promise<StoredProviderConfig>;
41
+ /**
42
+ * Changes `model`/`baseUrl`/tuning without touching the saved key — so an
43
+ * admin can adjust any of these, including *after* the first save,
44
+ * without being made to re-paste an API key they may no longer have
45
+ * handy. `undefined` on a tuning field leaves it as saved; `null`
46
+ * explicitly clears it back to "use the built-in default" (the one thing
47
+ * a plain optional field can't express — leaving it out of the patch and
48
+ * clearing it back to unset need distinct wire shapes). Throws
49
+ * `PROVIDER_NOT_CONFIGURED` if this provider has no saved key yet.
50
+ */
51
+ updateSettings(provider: ProviderName, patch: {
52
+ readonly model?: string;
53
+ readonly baseUrl?: string;
54
+ readonly maxOutputTokens?: number | null;
55
+ readonly requestTimeoutMs?: number | null;
56
+ readonly maxCorrectionAttempts?: number | null;
57
+ }): Promise<StoredProviderConfig>;
58
+ remove(provider: ProviderName): Promise<void>;
59
+ /** The one place the real key is ever decrypted — never exposed on `StoredProviderConfig` itself. Throws `PROVIDER_NOT_CONFIGURED` if this provider has no saved key. */
60
+ decryptKey(provider: ProviderName): Promise<string>;
61
+ }
62
+ export interface FileProviderConfigStoreOptions {
63
+ readonly dir: string;
64
+ /** `COGENTA_AUTH_SIGNING_KEY` — the encryption key is derived from it, never stored itself. */
65
+ readonly signingKey: string;
66
+ readonly now?: () => Date;
67
+ }
68
+ /** One `<provider>.json` record per configured provider, under `options.dir` — the same one-file-per-record shape every other file store in this package uses (R1: no external service). */
69
+ export declare function createFileProviderConfigStore(options: FileProviderConfigStoreOptions): ProviderConfigStore;
70
+ //# sourceMappingURL=store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/providers/store.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAqEjD,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAA;IAC/B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;IACzB,4HAA4H;IAC5H,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAA;IACjC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;IAClC,QAAQ,CAAC,qBAAqB,CAAC,EAAE,MAAM,CAAA;CACxC;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAA;IAC/B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAA;IAC1B,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAA;IACjC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;IAClC,QAAQ,CAAC,qBAAqB,CAAC,EAAE,MAAM,CAAA;CACxC;AA+BD,MAAM,WAAW,mBAAmB;IAClC,IAAI,IAAI,OAAO,CAAC,SAAS,oBAAoB,EAAE,CAAC,CAAA;IAChD,GAAG,CAAC,QAAQ,EAAE,YAAY,GAAG,OAAO,CAAC,oBAAoB,GAAG,SAAS,CAAC,CAAA;IACtE,wFAAwF;IACxF,MAAM,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAA;IACjE,UAAU,CAAC,QAAQ,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAA;IACnF;;;;;;;;;OASG;IACH,cAAc,CACZ,QAAQ,EAAE,YAAY,EACtB,KAAK,EAAE;QACL,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;QACvB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;QACzB,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;QACxC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;QACzC,QAAQ,CAAC,qBAAqB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAC/C,GACA,OAAO,CAAC,oBAAoB,CAAC,CAAA;IAChC,MAAM,CAAC,QAAQ,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC7C,yKAAyK;IACzK,UAAU,CAAC,QAAQ,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;CACpD;AAqDD,MAAM,WAAW,8BAA8B;IAC7C,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,+FAA+F;IAC/F,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,IAAI,CAAA;CAC1B;AAED,4LAA4L;AAC5L,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,8BAA8B,GACtC,mBAAmB,CAmMrB"}
@@ -0,0 +1,308 @@
1
+ import { createCipheriv, createDecipheriv, randomBytes, scryptSync } from 'node:crypto';
2
+ import { mkdir, readdir, readFile, rm, writeFile } from 'node:fs/promises';
3
+ import { join } from 'node:path';
4
+ import { CogentaError } from '@cogenta/core';
5
+ import { findProviderCatalogEntry } from './catalog.js';
6
+ /**
7
+ * L22 task 1bis's "Providers" screen: which LLM providers this site has
8
+ * configured, each one's API key, and its default model — persisted so an
9
+ * operator can turn a provider on from the admin instead of only via
10
+ * `COGENTA_LLM_API_KEY`/`cogenta.config.mjs`'s single `llm` section
11
+ * (`@cogenta/core`'s `llmSchema`, unchanged and still the install-time
12
+ * default — `agents/orchestrator.ts` imports it as the first configured
13
+ * provider the first time this store is read, so an existing site loses
14
+ * nothing by upgrading).
15
+ *
16
+ * Fiche 56 widened `provider` from the closed 3-literal union to a free
17
+ * string (`registry.ts`'s `ProviderName`) so a catalog id (OpenRouter,
18
+ * DeepSeek, Qwen, GLM, …) or an operator-chosen custom id both fit. `upsert`
19
+ * is the write boundary that keeps this safe: `assertValidProviderId` rejects
20
+ * anything that is not a plain slug (this store builds a filename directly
21
+ * from `provider` — see `fileFor` — so a malformed id is a path-traversal
22
+ * risk, not merely an aesthetic one), and a name absent from the catalog
23
+ * must carry its own `baseUrl` or it could never resolve to a working client
24
+ * (`registry.ts`'s `buildClient` throws `PROVIDER_CUSTOM_BASE_URL_REQUIRED`
25
+ * for exactly that case — this store refuses the same shape earlier, at the
26
+ * point an operator can still fix it, rather than at first agent run).
27
+ *
28
+ * "Jamais affichée en clair une fois enregistrée" (the lot's own words, same
29
+ * discipline as `create-cogenta`'s masked key prompt) rules out storing the
30
+ * key as recoverable plaintext an API response could echo back — but an LLM
31
+ * call still needs the real key at request time, which rules out a one-way
32
+ * hash (`@cogenta/auth`'s `ApiKeyStore` model: fine for a bearer token this
33
+ * site itself verifies, useless for a key a *vendor* must see). This store
34
+ * therefore encrypts at rest (AES-256-GCM, `node:crypto`, zero new
35
+ * dependency — R9/R10) with a key derived from `COGENTA_AUTH_SIGNING_KEY`
36
+ * (the secret every real deployment already has, R7 — no second secret to
37
+ * generate, rotate or lose) via `scryptSync` with a purpose-specific salt,
38
+ * so the derived key is never the literal signing key reused across
39
+ * purposes. `list()`/`get()` return only a masked preview; the plaintext key
40
+ * is decrypted solely inside `resolveProviderRegistryConfig`, which the
41
+ * runtime hands straight to `createProviderRegistry` and never logs or
42
+ * returns over the wire (R7).
43
+ */
44
+ /**
45
+ * A safe filename component and a reasonable admin-typed identifier: lower-
46
+ * case slug, 2-64 characters, no leading/trailing/doubled hyphen. Every
47
+ * catalog id in `catalog.ts` matches this by construction; the check exists
48
+ * for an operator-typed custom provider id.
49
+ */
50
+ const PROVIDER_ID_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+){0,10}$/u;
51
+ function assertValidProviderId(provider) {
52
+ if (PROVIDER_ID_PATTERN.test(provider) && provider.length <= 64)
53
+ return;
54
+ throw new CogentaError({
55
+ code: 'PROVIDER_ID_INVALID',
56
+ message: `"${provider}" is not a valid provider id.`,
57
+ hint: 'Use lowercase letters, digits and single hyphens only (e.g. "openrouter", "my-vllm-server").',
58
+ });
59
+ }
60
+ /** A provider id the catalog does not know needs its own `baseUrl` — otherwise it could never resolve to a working client (see `registry.ts`'s `buildClient`). */
61
+ function assertResolvable(provider, baseUrl) {
62
+ if (findProviderCatalogEntry(provider) !== undefined)
63
+ return;
64
+ if (baseUrl !== undefined && baseUrl.trim().length > 0)
65
+ return;
66
+ throw new CogentaError({
67
+ code: 'PROVIDER_CUSTOM_BASE_URL_REQUIRED',
68
+ message: `"${provider}" is not a built-in provider — a custom provider needs a non-empty "baseUrl".`,
69
+ hint: 'Add a baseUrl pointing at an OpenAI-compatible chat completions endpoint, or use a catalog provider id.',
70
+ });
71
+ }
72
+ /** Bounds wide enough for any real model/deployment, narrow enough to catch a typo (a negative, a zero, or a value nobody would deliberately set) before it reaches an HTTP request. */
73
+ const TUNING_BOUNDS = {
74
+ maxOutputTokens: { min: 1, max: 200_000 },
75
+ requestTimeoutMs: { min: 1000, max: 600_000 },
76
+ maxCorrectionAttempts: { min: 1, max: 10 },
77
+ };
78
+ function assertValidTuning(input) {
79
+ for (const [field, bounds] of Object.entries(TUNING_BOUNDS)) {
80
+ const value = input[field];
81
+ if (value === undefined)
82
+ continue;
83
+ if (!Number.isInteger(value) || value < bounds.min || value > bounds.max) {
84
+ throw new CogentaError({
85
+ code: 'PROVIDER_TUNING_INVALID',
86
+ message: `"${field}" must be a whole number between ${bounds.min} and ${bounds.max}.`,
87
+ hint: 'Leave it empty to use the built-in default for this field.',
88
+ });
89
+ }
90
+ }
91
+ }
92
+ const KEY_DERIVATION_SALT = 'cogenta-provider-secrets-v1';
93
+ const ALGORITHM = 'aes-256-gcm';
94
+ function deriveKey(signingKey) {
95
+ return scryptSync(signingKey, KEY_DERIVATION_SALT, 32);
96
+ }
97
+ function mask(apiKey) {
98
+ const tail = apiKey.slice(-4);
99
+ return tail.length === 0 ? '••••' : `••••${tail}`;
100
+ }
101
+ function providerNotConfigured(provider) {
102
+ return new CogentaError({
103
+ code: 'PROVIDER_NOT_CONFIGURED',
104
+ message: `No API key is saved for "${provider}".`,
105
+ hint: 'Configure it from the admin\'s "Providers" screen first.',
106
+ });
107
+ }
108
+ function toSummary(record) {
109
+ return {
110
+ provider: record.provider,
111
+ enabled: record.enabled,
112
+ model: record.model,
113
+ ...(record.baseUrl === undefined ? {} : { baseUrl: record.baseUrl }),
114
+ maskedKey: record.maskedKey,
115
+ updatedAt: record.updatedAt,
116
+ ...(record.maxOutputTokens === undefined ? {} : { maxOutputTokens: record.maxOutputTokens }),
117
+ ...(record.requestTimeoutMs === undefined ? {} : { requestTimeoutMs: record.requestTimeoutMs }),
118
+ ...(record.maxCorrectionAttempts === undefined
119
+ ? {}
120
+ : { maxCorrectionAttempts: record.maxCorrectionAttempts }),
121
+ };
122
+ }
123
+ /** One `<provider>.json` record per configured provider, under `options.dir` — the same one-file-per-record shape every other file store in this package uses (R1: no external service). */
124
+ export function createFileProviderConfigStore(options) {
125
+ const now = options.now ?? (() => new Date());
126
+ const key = deriveKey(options.signingKey);
127
+ const ready = mkdir(options.dir, { recursive: true });
128
+ /**
129
+ * The one place every method that touches disk builds a path from
130
+ * `provider` — validating here, rather than only in `upsert`, is what
131
+ * closes the path-traversal gap `PATCH`/`DELETE /api/providers/:provider`
132
+ * would otherwise reopen: the router no longer allowlists `provider`
133
+ * against a fixed name list before calling `setEnabled`/`updateSettings`/
134
+ * `remove` (fiche 56 removed that gate to admit catalog and custom ids),
135
+ * so this store is the only remaining checkpoint before an attacker-
136
+ * controlled string like `../../agents/some-agent` reaches `readFile`/
137
+ * `writeFile`/`rm`. A caller of `get`/`decryptKey` on a malformed id gets
138
+ * the same `PROVIDER_ID_INVALID` an `upsert` would — never a silent
139
+ * "not found" that would let the check be bypassed by relying on ENOENT.
140
+ */
141
+ function fileFor(provider) {
142
+ assertValidProviderId(provider);
143
+ return join(options.dir, `${provider}.json`);
144
+ }
145
+ function encrypt(plaintext) {
146
+ const iv = randomBytes(12);
147
+ const cipher = createCipheriv(ALGORITHM, key, iv);
148
+ const ciphertext = Buffer.concat([cipher.update(plaintext, 'utf8'), cipher.final()]);
149
+ return {
150
+ iv: iv.toString('base64'),
151
+ authTag: cipher.getAuthTag().toString('base64'),
152
+ ciphertext: ciphertext.toString('base64'),
153
+ };
154
+ }
155
+ function decrypt(record) {
156
+ const decipher = createDecipheriv(ALGORITHM, key, Buffer.from(record.iv, 'base64'));
157
+ decipher.setAuthTag(Buffer.from(record.authTag, 'base64'));
158
+ const plaintext = Buffer.concat([
159
+ decipher.update(Buffer.from(record.ciphertext, 'base64')),
160
+ decipher.final(),
161
+ ]);
162
+ return plaintext.toString('utf8');
163
+ }
164
+ async function readRecord(provider) {
165
+ // `fileFor` (which validates `provider`) is called outside the try
166
+ // block on purpose: a `PROVIDER_ID_INVALID` it throws must propagate as
167
+ // itself, never be caught below and rewritten into a misleading
168
+ // "the file may be corrupted" `INTERNAL` error.
169
+ const path = fileFor(provider);
170
+ try {
171
+ const raw = await readFile(path, 'utf8');
172
+ return JSON.parse(raw);
173
+ }
174
+ catch (error) {
175
+ if (error.code === 'ENOENT')
176
+ return null;
177
+ throw new CogentaError({
178
+ code: 'INTERNAL',
179
+ message: `Could not read the saved configuration for provider "${provider}".`,
180
+ hint: 'The file may be corrupted; consider removing it and reconfiguring the provider.',
181
+ cause: error,
182
+ });
183
+ }
184
+ }
185
+ return {
186
+ async list() {
187
+ await ready;
188
+ const filenames = await readdir(options.dir).catch(() => []);
189
+ const records = [];
190
+ for (const filename of filenames) {
191
+ if (!filename.endsWith('.json'))
192
+ continue;
193
+ const provider = filename.replace(/\.json$/u, '');
194
+ if (!PROVIDER_ID_PATTERN.test(provider))
195
+ continue;
196
+ const record = await readRecord(provider);
197
+ if (record !== null)
198
+ records.push(toSummary(record));
199
+ }
200
+ return records.sort((a, b) => a.provider.localeCompare(b.provider));
201
+ },
202
+ async get(provider) {
203
+ await ready;
204
+ const record = await readRecord(provider);
205
+ return record === null ? undefined : toSummary(record);
206
+ },
207
+ async upsert(input) {
208
+ await ready;
209
+ assertValidProviderId(input.provider);
210
+ assertResolvable(input.provider, input.baseUrl);
211
+ assertValidTuning(input);
212
+ const { iv, authTag, ciphertext } = encrypt(input.apiKey);
213
+ const record = {
214
+ provider: input.provider,
215
+ enabled: input.enabled ?? true,
216
+ model: input.model,
217
+ ...(input.baseUrl === undefined ? {} : { baseUrl: input.baseUrl }),
218
+ maskedKey: mask(input.apiKey),
219
+ iv,
220
+ authTag,
221
+ ciphertext,
222
+ updatedAt: now().toISOString(),
223
+ ...(input.maxOutputTokens === undefined ? {} : { maxOutputTokens: input.maxOutputTokens }),
224
+ ...(input.requestTimeoutMs === undefined
225
+ ? {}
226
+ : { requestTimeoutMs: input.requestTimeoutMs }),
227
+ ...(input.maxCorrectionAttempts === undefined
228
+ ? {}
229
+ : { maxCorrectionAttempts: input.maxCorrectionAttempts }),
230
+ };
231
+ await writeFile(fileFor(input.provider), JSON.stringify(record, null, 2), 'utf8');
232
+ return toSummary(record);
233
+ },
234
+ async setEnabled(provider, enabled) {
235
+ await ready;
236
+ const existing = await readRecord(provider);
237
+ if (existing === null)
238
+ throw providerNotConfigured(provider);
239
+ const updated = { ...existing, enabled, updatedAt: now().toISOString() };
240
+ await writeFile(fileFor(provider), JSON.stringify(updated, null, 2), 'utf8');
241
+ return toSummary(updated);
242
+ },
243
+ async remove(provider) {
244
+ await ready;
245
+ await rm(fileFor(provider), { force: true });
246
+ },
247
+ async updateSettings(provider, patch) {
248
+ await ready;
249
+ const existing = await readRecord(provider);
250
+ if (existing === null)
251
+ throw providerNotConfigured(provider);
252
+ const nextBaseUrl = patch.baseUrl !== undefined
253
+ ? patch.baseUrl
254
+ : existing.baseUrl === undefined
255
+ ? undefined
256
+ : existing.baseUrl;
257
+ assertResolvable(provider, nextBaseUrl);
258
+ assertValidTuning({
259
+ ...(patch.maxOutputTokens === undefined || patch.maxOutputTokens === null
260
+ ? {}
261
+ : { maxOutputTokens: patch.maxOutputTokens }),
262
+ ...(patch.requestTimeoutMs === undefined || patch.requestTimeoutMs === null
263
+ ? {}
264
+ : { requestTimeoutMs: patch.requestTimeoutMs }),
265
+ ...(patch.maxCorrectionAttempts === undefined || patch.maxCorrectionAttempts === null
266
+ ? {}
267
+ : { maxCorrectionAttempts: patch.maxCorrectionAttempts }),
268
+ });
269
+ // `null` clears a tuning field back to "use the built-in default";
270
+ // `undefined` leaves it exactly as saved — the reason this can't just
271
+ // be `patch.x ?? existing.x` the way `model` above is. Starting from
272
+ // `existing` stripped of all three (rather than the full record) and
273
+ // re-adding only what survives is what lets a `null` actually delete
274
+ // the key instead of merely being overwritten back to its old value.
275
+ const { maxOutputTokens: _existingMaxOutputTokens, requestTimeoutMs: _existingRequestTimeoutMs, maxCorrectionAttempts: _existingMaxCorrectionAttempts, ...existingWithoutTuning } = existing;
276
+ const nextMaxOutputTokens = patch.maxOutputTokens === undefined
277
+ ? existing.maxOutputTokens
278
+ : (patch.maxOutputTokens ?? undefined);
279
+ const nextRequestTimeoutMs = patch.requestTimeoutMs === undefined
280
+ ? existing.requestTimeoutMs
281
+ : (patch.requestTimeoutMs ?? undefined);
282
+ const nextMaxCorrectionAttempts = patch.maxCorrectionAttempts === undefined
283
+ ? existing.maxCorrectionAttempts
284
+ : (patch.maxCorrectionAttempts ?? undefined);
285
+ const updated = {
286
+ ...existingWithoutTuning,
287
+ model: patch.model ?? existing.model,
288
+ ...(nextBaseUrl === undefined ? {} : { baseUrl: nextBaseUrl }),
289
+ updatedAt: now().toISOString(),
290
+ ...(nextMaxOutputTokens === undefined ? {} : { maxOutputTokens: nextMaxOutputTokens }),
291
+ ...(nextRequestTimeoutMs === undefined ? {} : { requestTimeoutMs: nextRequestTimeoutMs }),
292
+ ...(nextMaxCorrectionAttempts === undefined
293
+ ? {}
294
+ : { maxCorrectionAttempts: nextMaxCorrectionAttempts }),
295
+ };
296
+ await writeFile(fileFor(provider), JSON.stringify(updated, null, 2), 'utf8');
297
+ return toSummary(updated);
298
+ },
299
+ async decryptKey(provider) {
300
+ await ready;
301
+ const record = await readRecord(provider);
302
+ if (record === null)
303
+ throw providerNotConfigured(provider);
304
+ return decrypt(record);
305
+ },
306
+ };
307
+ }
308
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/providers/store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { ChatRequest } from './types.js';
2
+ export declare function encodeToolName(name: string): string;
3
+ /**
4
+ * The decoder for one request. Throws when two distinct tool names would
5
+ * collide on the wire (`a.b` next to `a__b`) — a misconfiguration worth a
6
+ * loud error, never a silently wrong tool.
7
+ */
8
+ export declare function createToolNameDecoder(request: ChatRequest): (wire: string) => string;
9
+ //# sourceMappingURL=tool-names.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-names.d.ts","sourceRoot":"","sources":["../../src/providers/tool-names.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AA4B7C,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,WAAW,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAmBpF"}
@@ -0,0 +1,56 @@
1
+ import { CogentaError } from '@cogenta/core';
2
+ /**
3
+ * Contract C names its tools with a dot (`content.read`, `redirects.create`,
4
+ * `code.propose_patch`); every vendor wire format refuses that character in
5
+ * a function name — OpenAI-compatible endpoints (OpenAI, DeepSeek, Qwen,
6
+ * OpenRouter…) and Anthropic both enforce `^[a-zA-Z0-9_-]+$`, and Gemini
7
+ * has its own narrower rules. Found live: DeepSeek answered every agent run
8
+ * with `400 Invalid 'tools[0].function.name': string does not match
9
+ * pattern` before the request ever reached a model, and nothing in the
10
+ * catalog could have worked with a single tool declared.
11
+ *
12
+ * The fix lives here rather than in the tool names themselves: contract C
13
+ * is frozen, and a dot is the right separator for humans, the audit log
14
+ * and the permission taxonomy. Each adapter encodes on the way out and
15
+ * decodes on the way back, so no other layer ever sees a wire name.
16
+ *
17
+ * Encoding is deterministic (`.` and anything else outside the safe set →
18
+ * `__`), which is what lets an assistant message from earlier in the
19
+ * conversation — one that echoes a previous tool call by name — be encoded
20
+ * without any state. Decoding needs the reverse map, built from the request
21
+ * itself; a wire name the map does not know (a model inventing a tool) is
22
+ * returned unchanged, and the runtime's own registry refuses it downstream
23
+ * exactly as it would have before.
24
+ */
25
+ const UNSAFE = /[^a-zA-Z0-9_-]/gu;
26
+ export function encodeToolName(name) {
27
+ return name.replace(UNSAFE, '__');
28
+ }
29
+ /**
30
+ * The decoder for one request. Throws when two distinct tool names would
31
+ * collide on the wire (`a.b` next to `a__b`) — a misconfiguration worth a
32
+ * loud error, never a silently wrong tool.
33
+ */
34
+ export function createToolNameDecoder(request) {
35
+ const byWire = new Map();
36
+ const register = (name) => {
37
+ const wire = encodeToolName(name);
38
+ const existing = byWire.get(wire);
39
+ if (existing !== undefined && existing !== name) {
40
+ throw new CogentaError({
41
+ code: 'PROVIDER_REQUEST_FAILED',
42
+ message: `Tool names "${existing}" and "${name}" are indistinguishable once encoded for the provider ("${wire}").`,
43
+ hint: 'Rename one of the two tools so they differ by more than characters the wire format refuses.',
44
+ });
45
+ }
46
+ byWire.set(wire, name);
47
+ };
48
+ for (const tool of request.tools ?? [])
49
+ register(tool.name);
50
+ for (const message of request.messages) {
51
+ for (const call of message.toolCalls ?? [])
52
+ register(call.name);
53
+ }
54
+ return (wire) => byWire.get(wire) ?? wire;
55
+ }
56
+ //# sourceMappingURL=tool-names.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-names.js","sourceRoot":"","sources":["../../src/providers/tool-names.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAG5C;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,MAAM,MAAM,GAAG,kBAAkB,CAAA;AAEjC,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,CAAA;AACnC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,qBAAqB,CAAC,OAAoB;IACxD,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAA;IACxC,MAAM,QAAQ,GAAG,CAAC,IAAY,EAAQ,EAAE;QACtC,MAAM,IAAI,GAAG,cAAc,CAAC,IAAI,CAAC,CAAA;QACjC,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;QACjC,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;YAChD,MAAM,IAAI,YAAY,CAAC;gBACrB,IAAI,EAAE,yBAAyB;gBAC/B,OAAO,EAAE,eAAe,QAAQ,UAAU,IAAI,2DAA2D,IAAI,KAAK;gBAClH,IAAI,EAAE,6FAA6F;aACpG,CAAC,CAAA;QACJ,CAAC;QACD,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;IACxB,CAAC,CAAA;IACD,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,KAAK,IAAI,EAAE;QAAE,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAC3D,KAAK,MAAM,OAAO,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;QACvC,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,SAAS,IAAI,EAAE;YAAE,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACjE,CAAC;IACD,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,CAAA;AAC3C,CAAC"}