@cat-factory/agents 0.6.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 (226) hide show
  1. package/LICENSE +21 -0
  2. package/dist/agents/AiAgentExecutor.d.ts +72 -0
  3. package/dist/agents/AiAgentExecutor.d.ts.map +1 -0
  4. package/dist/agents/AiAgentExecutor.js +125 -0
  5. package/dist/agents/AiAgentExecutor.js.map +1 -0
  6. package/dist/agents/acceptance-prompts.d.ts +29 -0
  7. package/dist/agents/acceptance-prompts.d.ts.map +1 -0
  8. package/dist/agents/acceptance-prompts.js +112 -0
  9. package/dist/agents/acceptance-prompts.js.map +1 -0
  10. package/dist/agents/agent-catalog.d.ts +6 -0
  11. package/dist/agents/agent-catalog.d.ts.map +1 -0
  12. package/dist/agents/agent-catalog.js +197 -0
  13. package/dist/agents/agent-catalog.js.map +1 -0
  14. package/dist/agents/agent-configs.d.ts +17 -0
  15. package/dist/agents/agent-configs.d.ts.map +1 -0
  16. package/dist/agents/agent-configs.js +66 -0
  17. package/dist/agents/agent-configs.js.map +1 -0
  18. package/dist/agents/agent-routing.d.ts +57 -0
  19. package/dist/agents/agent-routing.d.ts.map +1 -0
  20. package/dist/agents/agent-routing.js +41 -0
  21. package/dist/agents/agent-routing.js.map +1 -0
  22. package/dist/agents/business-logic-prompts.d.ts +28 -0
  23. package/dist/agents/business-logic-prompts.d.ts.map +1 -0
  24. package/dist/agents/business-logic-prompts.js +96 -0
  25. package/dist/agents/business-logic-prompts.js.map +1 -0
  26. package/dist/agents/catalog.d.ts +6 -0
  27. package/dist/agents/catalog.d.ts.map +1 -0
  28. package/dist/agents/catalog.js +168 -0
  29. package/dist/agents/catalog.js.map +1 -0
  30. package/dist/agents/ci-gate.d.ts +2 -0
  31. package/dist/agents/ci-gate.d.ts.map +1 -0
  32. package/dist/agents/ci-gate.js +33 -0
  33. package/dist/agents/ci-gate.js.map +1 -0
  34. package/dist/agents/companion-prompts.d.ts +4 -0
  35. package/dist/agents/companion-prompts.d.ts.map +1 -0
  36. package/dist/agents/companion-prompts.js +27 -0
  37. package/dist/agents/companion-prompts.js.map +1 -0
  38. package/dist/agents/companions.d.ts +20 -0
  39. package/dist/agents/companions.d.ts.map +1 -0
  40. package/dist/agents/companions.js +38 -0
  41. package/dist/agents/companions.js.map +1 -0
  42. package/dist/agents/kinds/companions.d.ts +20 -0
  43. package/dist/agents/kinds/companions.d.ts.map +1 -0
  44. package/dist/agents/kinds/companions.js +39 -0
  45. package/dist/agents/kinds/companions.js.map +1 -0
  46. package/dist/agents/kinds/configs.d.ts +17 -0
  47. package/dist/agents/kinds/configs.d.ts.map +1 -0
  48. package/dist/agents/kinds/configs.js +66 -0
  49. package/dist/agents/kinds/configs.js.map +1 -0
  50. package/dist/agents/kinds/read-only.d.ts +13 -0
  51. package/dist/agents/kinds/read-only.d.ts.map +1 -0
  52. package/dist/agents/kinds/read-only.js +32 -0
  53. package/dist/agents/kinds/read-only.js.map +1 -0
  54. package/dist/agents/kinds/registry.d.ts +70 -0
  55. package/dist/agents/kinds/registry.d.ts.map +1 -0
  56. package/dist/agents/kinds/registry.js +51 -0
  57. package/dist/agents/kinds/registry.js.map +1 -0
  58. package/dist/agents/kinds/traits.d.ts +60 -0
  59. package/dist/agents/kinds/traits.d.ts.map +1 -0
  60. package/dist/agents/kinds/traits.js +123 -0
  61. package/dist/agents/kinds/traits.js.map +1 -0
  62. package/dist/agents/kinds/versions.d.ts +46 -0
  63. package/dist/agents/kinds/versions.d.ts.map +1 -0
  64. package/dist/agents/kinds/versions.js +22 -0
  65. package/dist/agents/kinds/versions.js.map +1 -0
  66. package/dist/agents/mock-prompts.d.ts +12 -0
  67. package/dist/agents/mock-prompts.d.ts.map +1 -0
  68. package/dist/agents/mock-prompts.js +61 -0
  69. package/dist/agents/mock-prompts.js.map +1 -0
  70. package/dist/agents/prompt-fragments.d.ts +17 -0
  71. package/dist/agents/prompt-fragments.d.ts.map +1 -0
  72. package/dist/agents/prompt-fragments.js +33 -0
  73. package/dist/agents/prompt-fragments.js.map +1 -0
  74. package/dist/agents/prompt-shared.d.ts +7 -0
  75. package/dist/agents/prompt-shared.d.ts.map +1 -0
  76. package/dist/agents/prompt-shared.js +10 -0
  77. package/dist/agents/prompt-shared.js.map +1 -0
  78. package/dist/agents/prompt-versions.d.ts +48 -0
  79. package/dist/agents/prompt-versions.d.ts.map +1 -0
  80. package/dist/agents/prompt-versions.js +55 -0
  81. package/dist/agents/prompt-versions.js.map +1 -0
  82. package/dist/agents/prompts/acceptance.d.ts +29 -0
  83. package/dist/agents/prompts/acceptance.d.ts.map +1 -0
  84. package/dist/agents/prompts/acceptance.js +112 -0
  85. package/dist/agents/prompts/acceptance.js.map +1 -0
  86. package/dist/agents/prompts/business-logic.d.ts +28 -0
  87. package/dist/agents/prompts/business-logic.d.ts.map +1 -0
  88. package/dist/agents/prompts/business-logic.js +98 -0
  89. package/dist/agents/prompts/business-logic.js.map +1 -0
  90. package/dist/agents/prompts/clarity.d.ts +10 -0
  91. package/dist/agents/prompts/clarity.d.ts.map +1 -0
  92. package/dist/agents/prompts/clarity.js +40 -0
  93. package/dist/agents/prompts/clarity.js.map +1 -0
  94. package/dist/agents/prompts/companion.d.ts +4 -0
  95. package/dist/agents/prompts/companion.d.ts.map +1 -0
  96. package/dist/agents/prompts/companion.js +61 -0
  97. package/dist/agents/prompts/companion.js.map +1 -0
  98. package/dist/agents/prompts/delivery-contract.d.ts +2 -0
  99. package/dist/agents/prompts/delivery-contract.d.ts.map +1 -0
  100. package/dist/agents/prompts/delivery-contract.js +33 -0
  101. package/dist/agents/prompts/delivery-contract.js.map +1 -0
  102. package/dist/agents/prompts/mock.d.ts +12 -0
  103. package/dist/agents/prompts/mock.d.ts.map +1 -0
  104. package/dist/agents/prompts/mock.js +61 -0
  105. package/dist/agents/prompts/mock.js.map +1 -0
  106. package/dist/agents/prompts/requirements.d.ts +13 -0
  107. package/dist/agents/prompts/requirements.d.ts.map +1 -0
  108. package/dist/agents/prompts/requirements.js +45 -0
  109. package/dist/agents/prompts/requirements.js.map +1 -0
  110. package/dist/agents/prompts/roles.d.ts +16 -0
  111. package/dist/agents/prompts/roles.d.ts.map +1 -0
  112. package/dist/agents/prompts/roles.js +74 -0
  113. package/dist/agents/prompts/roles.js.map +1 -0
  114. package/dist/agents/prompts/shared.d.ts +19 -0
  115. package/dist/agents/prompts/shared.d.ts.map +1 -0
  116. package/dist/agents/prompts/shared.js +25 -0
  117. package/dist/agents/prompts/shared.js.map +1 -0
  118. package/dist/agents/prompts/standard-templates.generated.d.ts +36 -0
  119. package/dist/agents/prompts/standard-templates.generated.d.ts.map +1 -0
  120. package/dist/agents/prompts/standard-templates.generated.js +122 -0
  121. package/dist/agents/prompts/standard-templates.generated.js.map +1 -0
  122. package/dist/agents/prompts/standard.d.ts +36 -0
  123. package/dist/agents/prompts/standard.d.ts.map +1 -0
  124. package/dist/agents/prompts/standard.js +208 -0
  125. package/dist/agents/prompts/standard.js.map +1 -0
  126. package/dist/agents/prompts/testing.d.ts +12 -0
  127. package/dist/agents/prompts/testing.d.ts.map +1 -0
  128. package/dist/agents/prompts/testing.js +94 -0
  129. package/dist/agents/prompts/testing.js.map +1 -0
  130. package/dist/agents/read-only.d.ts +13 -0
  131. package/dist/agents/read-only.d.ts.map +1 -0
  132. package/dist/agents/read-only.js +29 -0
  133. package/dist/agents/read-only.js.map +1 -0
  134. package/dist/agents/registry.d.ts +70 -0
  135. package/dist/agents/registry.d.ts.map +1 -0
  136. package/dist/agents/registry.js +51 -0
  137. package/dist/agents/registry.js.map +1 -0
  138. package/dist/agents/runtime/executor.d.ts +72 -0
  139. package/dist/agents/runtime/executor.d.ts.map +1 -0
  140. package/dist/agents/runtime/executor.js +125 -0
  141. package/dist/agents/runtime/executor.js.map +1 -0
  142. package/dist/agents/runtime/fragments.d.ts +17 -0
  143. package/dist/agents/runtime/fragments.d.ts.map +1 -0
  144. package/dist/agents/runtime/fragments.js +33 -0
  145. package/dist/agents/runtime/fragments.js.map +1 -0
  146. package/dist/agents/runtime/routing.d.ts +57 -0
  147. package/dist/agents/runtime/routing.d.ts.map +1 -0
  148. package/dist/agents/runtime/routing.js +41 -0
  149. package/dist/agents/runtime/routing.js.map +1 -0
  150. package/dist/agents/runtime/web-search.d.ts +43 -0
  151. package/dist/agents/runtime/web-search.d.ts.map +1 -0
  152. package/dist/agents/runtime/web-search.js +102 -0
  153. package/dist/agents/runtime/web-search.js.map +1 -0
  154. package/dist/agents/standard-prompt-templates.generated.d.ts +36 -0
  155. package/dist/agents/standard-prompt-templates.generated.d.ts.map +1 -0
  156. package/dist/agents/standard-prompt-templates.generated.js +122 -0
  157. package/dist/agents/standard-prompt-templates.generated.js.map +1 -0
  158. package/dist/agents/standard-prompts.d.ts +36 -0
  159. package/dist/agents/standard-prompts.d.ts.map +1 -0
  160. package/dist/agents/standard-prompts.js +202 -0
  161. package/dist/agents/standard-prompts.js.map +1 -0
  162. package/dist/agents/test-prompts.d.ts +12 -0
  163. package/dist/agents/test-prompts.d.ts.map +1 -0
  164. package/dist/agents/test-prompts.js +92 -0
  165. package/dist/agents/test-prompts.js.map +1 -0
  166. package/dist/agents/traits.d.ts +56 -0
  167. package/dist/agents/traits.d.ts.map +1 -0
  168. package/dist/agents/traits.js +100 -0
  169. package/dist/agents/traits.js.map +1 -0
  170. package/dist/agents/web-search.d.ts +43 -0
  171. package/dist/agents/web-search.d.ts.map +1 -0
  172. package/dist/agents/web-search.js +102 -0
  173. package/dist/agents/web-search.js.map +1 -0
  174. package/dist/fragmentLibrary/DeterministicFragmentSelector.d.ts +10 -0
  175. package/dist/fragmentLibrary/DeterministicFragmentSelector.d.ts.map +1 -0
  176. package/dist/fragmentLibrary/DeterministicFragmentSelector.js +12 -0
  177. package/dist/fragmentLibrary/DeterministicFragmentSelector.js.map +1 -0
  178. package/dist/fragmentLibrary/FragmentLibraryService.d.ts +55 -0
  179. package/dist/fragmentLibrary/FragmentLibraryService.d.ts.map +1 -0
  180. package/dist/fragmentLibrary/FragmentLibraryService.js +203 -0
  181. package/dist/fragmentLibrary/FragmentLibraryService.js.map +1 -0
  182. package/dist/fragmentLibrary/FragmentSourceService.d.ts +51 -0
  183. package/dist/fragmentLibrary/FragmentSourceService.d.ts.map +1 -0
  184. package/dist/fragmentLibrary/FragmentSourceService.js +181 -0
  185. package/dist/fragmentLibrary/FragmentSourceService.js.map +1 -0
  186. package/dist/fragmentLibrary/LlmFragmentSelector.d.ts +21 -0
  187. package/dist/fragmentLibrary/LlmFragmentSelector.d.ts.map +1 -0
  188. package/dist/fragmentLibrary/LlmFragmentSelector.js +87 -0
  189. package/dist/fragmentLibrary/LlmFragmentSelector.js.map +1 -0
  190. package/dist/fragmentLibrary/fragment-catalog.d.ts +43 -0
  191. package/dist/fragmentLibrary/fragment-catalog.d.ts.map +1 -0
  192. package/dist/fragmentLibrary/fragment-catalog.js +129 -0
  193. package/dist/fragmentLibrary/fragment-catalog.js.map +1 -0
  194. package/dist/fragmentLibrary/fragment-source.logic.d.ts +34 -0
  195. package/dist/fragmentLibrary/fragment-source.logic.d.ts.map +1 -0
  196. package/dist/fragmentLibrary/fragment-source.logic.js +172 -0
  197. package/dist/fragmentLibrary/fragment-source.logic.js.map +1 -0
  198. package/dist/index.d.ts +30 -0
  199. package/dist/index.d.ts.map +1 -0
  200. package/dist/index.js +43 -0
  201. package/dist/index.js.map +1 -0
  202. package/dist/providers/cache.d.ts +22 -0
  203. package/dist/providers/cache.d.ts.map +1 -0
  204. package/dist/providers/cache.js +64 -0
  205. package/dist/providers/cache.js.map +1 -0
  206. package/dist/providers/endpoints.d.ts +8 -0
  207. package/dist/providers/endpoints.d.ts.map +1 -0
  208. package/dist/providers/endpoints.js +23 -0
  209. package/dist/providers/endpoints.js.map +1 -0
  210. package/dist/providers/index.d.ts +6 -0
  211. package/dist/providers/index.d.ts.map +1 -0
  212. package/dist/providers/index.js +6 -0
  213. package/dist/providers/index.js.map +1 -0
  214. package/dist/providers/instrumented.d.ts +28 -0
  215. package/dist/providers/instrumented.d.ts.map +1 -0
  216. package/dist/providers/instrumented.js +147 -0
  217. package/dist/providers/instrumented.js.map +1 -0
  218. package/dist/providers/registry.d.ts +26 -0
  219. package/dist/providers/registry.d.ts.map +1 -0
  220. package/dist/providers/registry.js +32 -0
  221. package/dist/providers/registry.js.map +1 -0
  222. package/dist/providers/resolvers.d.ts +58 -0
  223. package/dist/providers/resolvers.d.ts.map +1 -0
  224. package/dist/providers/resolvers.js +78 -0
  225. package/dist/providers/resolvers.js.map +1 -0
  226. package/package.json +39 -0
@@ -0,0 +1,92 @@
1
+ import { STANDARDS_FOOTER } from './prompt-shared.js';
2
+ import { TESTER_ENVIRONMENT_CONFIG_ID } from './agent-configs.js';
3
+ // Built-out role prompts for the Tester → Fixer loop. The `tester` clones the PR
4
+ // branch, brings its dependencies up (locally via docker-compose, or against the
5
+ // provisioned ephemeral environment — the task's `tester.environment` config picks
6
+ // which), exercises this task's requirements plus best-judgement regression of
7
+ // related behaviour, and returns ONLY a structured JSON report (it makes no commits,
8
+ // like the `merger`). When the report withholds its greenlight the engine dispatches
9
+ // the `fixer` with the report folded in; the fixer commits fixes to the same branch
10
+ // and the Tester re-runs, until greenlight or the attempt budget is spent.
11
+ const TESTER_AGENT_KIND = 'tester';
12
+ const FIXER_AGENT_KIND = 'fixer';
13
+ /** The JSON shape the Tester must emit, kept in sync with `testReportSchema`. */
14
+ const TEST_REPORT_SHAPE = [
15
+ 'Respond with ONLY a JSON object (no prose, no code fences) of this shape:',
16
+ '{',
17
+ ' "greenlight": boolean, // true only when the change is safe to release',
18
+ ' "summary": string, // overall prose summary of the session',
19
+ ' "tested": string[], // what you chose to exercise (requirements + regression areas)',
20
+ ' "outcomes": [ // per-area results',
21
+ ' { "name": string, "status": "passed" | "failed" | "skipped", "detail"?: string }',
22
+ ' ],',
23
+ ' "concerns": [ // bugs/risks to fix before re-testing; non-empty ⇒ greenlight false',
24
+ ' { "title": string, "detail": string, "severity": "low" | "medium" | "high" | "critical" }',
25
+ ' ],',
26
+ ' "environment"?: "local" | "ephemeral"',
27
+ '}',
28
+ ].join('\n');
29
+ const TESTER_SYSTEM_PROMPT = [
30
+ 'You are a meticulous test engineer doing EXPLORATORY testing of a pull request before release.',
31
+ 'You actually run the software and observe its behaviour — you do NOT pass judgement by reading the diff or restating what the implementer says they did. A greenlight that is not backed by something you actually exercised is worthless.',
32
+ '',
33
+ 'Bootstrap your environment from the repository:',
34
+ "- Read the repo's README.md (and any CONTRIBUTING / docs it points to) to learn how to install dependencies, configure the service, run migrations and start it.",
35
+ "- Local mode: the platform has stood up the service's infra dependencies from its docker-compose file (including the WireMock mocks the mocker step added for the service's external dependencies) and exposed them on localhost. Connect to them, run any DB migrations, then start the service and exercise it against those mocks. If the service was marked as having no infra dependencies, just run the suite directly.",
36
+ '- Ephemeral mode: a deployed environment URL (and access credentials) is provided in the run context; test against it rather than starting anything locally.',
37
+ '',
38
+ 'What to test:',
39
+ "- Start from the specs written in earlier steps: the unified spec under `spec/` and especially its Gherkin acceptance scenarios in `spec/features/*.feature`. Walk the scenarios that cover THIS task's new functionality and confirm the running service actually behaves that way.",
40
+ '- Explore the new functionality beyond the happy path: probe edge cases, bad input, error and boundary conditions, and the failure responses the external mocks can return — the kinds of things a scripted suite tends to miss.',
41
+ '- Then do a REASONABLE amount of regression testing of related behaviour the change could plausibly affect — target the blast radius, do not re-test the whole system.',
42
+ '- Run the existing automated suite where present, and add your own ad-hoc checks (API calls, flows, UI interactions) on top of it.',
43
+ '',
44
+ 'Rules:',
45
+ "- Make NO commits and open NO pull request — you only assess and report. Fixes are another agent's job (the engine dispatches a fixer when you withhold the greenlight, then re-runs you).",
46
+ '- Base every outcome on something you actually observed. Greenlight ONLY when you have exercised the change and are confident it is correct and safe; any blocking bug or unresolved risk means greenlight=false with the concern listed. Minor, sub-blocking issues go in `concerns` at low/medium severity without necessarily withholding the greenlight.',
47
+ '',
48
+ TEST_REPORT_SHAPE,
49
+ ].join('\n');
50
+ const FIXER_SYSTEM_PROMPT = [
51
+ 'You are a software engineer fixing problems a tester found on this pull-request branch.',
52
+ 'The tester’s structured report (what was tested, the outcomes, and the concerns/bugs to fix) is provided in the run context below.',
53
+ '',
54
+ 'Address every concern the tester raised:',
55
+ '- Reproduce each issue, find the root cause, and make the minimal correct change to fix it.',
56
+ '- Do not disable, skip or weaken tests to make them pass; fix the underlying behaviour.',
57
+ '- Keep the project building and the existing tests green.',
58
+ '',
59
+ 'Commit your fixes to the current branch (no new branch, no new PR) so the tester can re-run against them.',
60
+ '',
61
+ STANDARDS_FOOTER,
62
+ ].join('\n');
63
+ /** True when the kind is part of the Tester/Fixer track. */
64
+ export function isTestingKind(kind) {
65
+ return kind === TESTER_AGENT_KIND || kind === FIXER_AGENT_KIND;
66
+ }
67
+ /** The built-out system prompt for a Tester/Fixer kind, or undefined otherwise. */
68
+ export function testingSystemPrompt(kind) {
69
+ if (kind === TESTER_AGENT_KIND)
70
+ return TESTER_SYSTEM_PROMPT;
71
+ if (kind === FIXER_AGENT_KIND)
72
+ return FIXER_SYSTEM_PROMPT;
73
+ return undefined;
74
+ }
75
+ /**
76
+ * The "which environment to run in" section for a Tester step, rendered from the
77
+ * block's contributed `tester.environment` config value. Empty for non-tester kinds
78
+ * or when nothing is set, so callers can append it unconditionally.
79
+ */
80
+ export function testerEnvironmentSection(context) {
81
+ if (context.agentKind !== TESTER_AGENT_KIND)
82
+ return '';
83
+ const env = context.block.agentConfig?.[TESTER_ENVIRONMENT_CONFIG_ID];
84
+ if (env === 'ephemeral') {
85
+ return '\nRun mode: ephemeral environment — test against the provided environment URL; do not start the service locally.';
86
+ }
87
+ if (env === 'local') {
88
+ return '\nRun mode: local — the service’s infra dependencies have been stood up on localhost; start the service yourself and test it there.';
89
+ }
90
+ return '';
91
+ }
92
+ //# sourceMappingURL=test-prompts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-prompts.js","sourceRoot":"","sources":["../../src/agents/test-prompts.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AACrD,OAAO,EAAE,4BAA4B,EAAE,MAAM,oBAAoB,CAAA;AAEjE,iFAAiF;AACjF,iFAAiF;AACjF,mFAAmF;AACnF,+EAA+E;AAC/E,qFAAqF;AACrF,qFAAqF;AACrF,oFAAoF;AACpF,2EAA2E;AAE3E,MAAM,iBAAiB,GAAG,QAAQ,CAAA;AAClC,MAAM,gBAAgB,GAAG,OAAO,CAAA;AAEhC,iFAAiF;AACjF,MAAM,iBAAiB,GAAG;IACxB,2EAA2E;IAC3E,GAAG;IACH,qFAAqF;IACrF,4EAA4E;IAC5E,oGAAoG;IACpG,wDAAwD;IACxD,sFAAsF;IACtF,MAAM;IACN,yGAAyG;IACzG,+FAA+F;IAC/F,MAAM;IACN,yCAAyC;IACzC,GAAG;CACJ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AAEZ,MAAM,oBAAoB,GAAG;IAC3B,gGAAgG;IAChG,4OAA4O;IAC5O,EAAE;IACF,iDAAiD;IACjD,kKAAkK;IAClK,+ZAA+Z;IAC/Z,8JAA8J;IAC9J,EAAE;IACF,eAAe;IACf,sRAAsR;IACtR,kOAAkO;IAClO,wKAAwK;IACxK,oIAAoI;IACpI,EAAE;IACF,QAAQ;IACR,4LAA4L;IAC5L,8VAA8V;IAC9V,EAAE;IACF,iBAAiB;CAClB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AAEZ,MAAM,mBAAmB,GAAG;IAC1B,yFAAyF;IACzF,oIAAoI;IACpI,EAAE;IACF,0CAA0C;IAC1C,6FAA6F;IAC7F,yFAAyF;IACzF,2DAA2D;IAC3D,EAAE;IACF,2GAA2G;IAC3G,EAAE;IACF,gBAAgB;CACjB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AAEZ,4DAA4D;AAC5D,MAAM,UAAU,aAAa,CAAC,IAAe;IAC3C,OAAO,IAAI,KAAK,iBAAiB,IAAI,IAAI,KAAK,gBAAgB,CAAA;AAChE,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,mBAAmB,CAAC,IAAe;IACjD,IAAI,IAAI,KAAK,iBAAiB;QAAE,OAAO,oBAAoB,CAAA;IAC3D,IAAI,IAAI,KAAK,gBAAgB;QAAE,OAAO,mBAAmB,CAAA;IACzD,OAAO,SAAS,CAAA;AAClB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,wBAAwB,CAAC,OAAwB;IAC/D,IAAI,OAAO,CAAC,SAAS,KAAK,iBAAiB;QAAE,OAAO,EAAE,CAAA;IACtD,MAAM,GAAG,GAAG,OAAO,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,4BAA4B,CAAC,CAAA;IACrE,IAAI,GAAG,KAAK,WAAW,EAAE,CAAC;QACxB,OAAO,kHAAkH,CAAA;IAC3H,CAAC;IACD,IAAI,GAAG,KAAK,OAAO,EAAE,CAAC;QACpB,OAAO,qIAAqI,CAAA;IAC9I,CAAC;IACD,OAAO,EAAE,CAAA;AACX,CAAC"}
@@ -0,0 +1,56 @@
1
+ import type { AgentKind } from '@cat-factory/kernel';
2
+ /** A trait id. Free-form so deployments can define their own beyond the standard two. */
3
+ export type AgentTrait = string;
4
+ /**
5
+ * Code-aware kinds read and/or change the service's code. The service's selected
6
+ * best-practice / guideline fragments (Node, Fastify, performance, …) are folded into
7
+ * their system prompt by the execution engine.
8
+ */
9
+ export declare const CODE_AWARE_TRAIT: AgentTrait;
10
+ /**
11
+ * Spec-aware kinds are told to read the in-repo `spec/` artifact (the prescriptive
12
+ * service specification) and how to interpret it. The instruction is appended to their
13
+ * system prompt via {@link traitGuidanceFor}.
14
+ */
15
+ export declare const SPEC_AWARE_TRAIT: AgentTrait;
16
+ /** The guidance appended to a spec-aware kind's system prompt — explains the spec format. */
17
+ export declare const SPEC_AWARE_GUIDANCE: string;
18
+ /**
19
+ * Built-in trait assignment per agent kind.
20
+ * - `code-aware`: the kinds that read/modify the service's code, so the service's
21
+ * best-practice fragments are relevant to them.
22
+ * - `spec-aware`: every code-touching kind (anything that clones and reads the repo),
23
+ * so each is pointed at the in-repo spec. The `spec-writer` is intentionally absent —
24
+ * it AUTHORS the spec rather than consuming it.
25
+ */
26
+ export declare const STANDARD_AGENT_TRAITS: Partial<Record<AgentKind, AgentTrait[]>>;
27
+ /** Definition of a (custom) trait: its id and optional system-prompt guidance. */
28
+ export interface AgentTraitDefinition {
29
+ /** The trait id used in `STANDARD_AGENT_TRAITS` / `AgentKindDefinition.traits`. */
30
+ id: AgentTrait;
31
+ /**
32
+ * Guidance folded into the system prompt of every kind carrying this trait. A function
33
+ * form receives the kind id. Omit for a pure marker trait whose effect lives in the
34
+ * engine (like `code-aware`).
35
+ */
36
+ guidance?: string | ((kind: AgentKind) => string);
37
+ }
38
+ /** Register a custom trait definition. A later registration of the same id replaces it. */
39
+ export declare function registerAgentTrait(definition: AgentTraitDefinition): void;
40
+ /** Register several custom trait definitions at once. */
41
+ export declare function registerAgentTraits(definitions: Iterable<AgentTraitDefinition>): void;
42
+ /** The definition for a trait id, or undefined when it is a pure marker / unregistered. */
43
+ export declare function registeredAgentTrait(id: AgentTrait): AgentTraitDefinition | undefined;
44
+ /** Drop all registered (custom) traits. Intended for tests; standard traits re-register below. */
45
+ export declare function clearRegisteredAgentTraits(): void;
46
+ /** The traits a kind carries: its built-in set unioned with a registered custom kind's. */
47
+ export declare function traitsFor(kind: AgentKind): Set<AgentTrait>;
48
+ /** Whether `kind` carries `trait`. */
49
+ export declare function hasTrait(kind: AgentKind, trait: AgentTrait): boolean;
50
+ /**
51
+ * The guidance lines contributed by the traits a kind carries, in trait order. Folded
52
+ * into the kind's system prompt by `systemPromptFor`. Marker traits (no guidance, e.g.
53
+ * `code-aware`) contribute nothing here.
54
+ */
55
+ export declare function traitGuidanceFor(kind: AgentKind): string[];
56
+ //# sourceMappingURL=traits.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"traits.d.ts","sourceRoot":"","sources":["../../src/agents/traits.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAapD,yFAAyF;AACzF,MAAM,MAAM,UAAU,GAAG,MAAM,CAAA;AAE/B;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,EAAE,UAAyB,CAAA;AAExD;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,EAAE,UAAyB,CAAA;AAExD,6FAA6F;AAC7F,eAAO,MAAM,mBAAmB,QAOpB,CAAA;AAEZ;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB,EAAE,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,UAAU,EAAE,CAAC,CAe1E,CAAA;AAED,kFAAkF;AAClF,MAAM,WAAW,oBAAoB;IACnC,mFAAmF;IACnF,EAAE,EAAE,UAAU,CAAA;IACd;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,IAAI,EAAE,SAAS,KAAK,MAAM,CAAC,CAAA;CAClD;AAKD,2FAA2F;AAC3F,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,oBAAoB,GAAG,IAAI,CAEzE;AAED,yDAAyD;AACzD,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,QAAQ,CAAC,oBAAoB,CAAC,GAAG,IAAI,CAErF;AAED,2FAA2F;AAC3F,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,UAAU,GAAG,oBAAoB,GAAG,SAAS,CAErF;AAED,kGAAkG;AAClG,wBAAgB,0BAA0B,IAAI,IAAI,CAGjD;AAED,2FAA2F;AAC3F,wBAAgB,SAAS,CAAC,IAAI,EAAE,SAAS,GAAG,GAAG,CAAC,UAAU,CAAC,CAI1D;AAED,sCAAsC;AACtC,wBAAgB,QAAQ,CAAC,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAEpE;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,EAAE,CAQ1D"}
@@ -0,0 +1,100 @@
1
+ import { SPEC_FEATURES_DIR, SPEC_JSON_PATH, SPEC_OVERVIEW_PATH, SPEC_RULES_PATH, } from '@cat-factory/contracts';
2
+ import { registeredAgentKind } from './registry.js';
3
+ /**
4
+ * Code-aware kinds read and/or change the service's code. The service's selected
5
+ * best-practice / guideline fragments (Node, Fastify, performance, …) are folded into
6
+ * their system prompt by the execution engine.
7
+ */
8
+ export const CODE_AWARE_TRAIT = 'code-aware';
9
+ /**
10
+ * Spec-aware kinds are told to read the in-repo `spec/` artifact (the prescriptive
11
+ * service specification) and how to interpret it. The instruction is appended to their
12
+ * system prompt via {@link traitGuidanceFor}.
13
+ */
14
+ export const SPEC_AWARE_TRAIT = 'spec-aware';
15
+ /** The guidance appended to a spec-aware kind's system prompt — explains the spec format. */
16
+ export const SPEC_AWARE_GUIDANCE = [
17
+ `This repository may contain a prescriptive SPECIFICATION for the service under the \`spec/\` directory — the source of truth for what the service must do. When it is present, read it before doing the work:`,
18
+ `- \`${SPEC_OVERVIEW_PATH}\` first, for the high-level product intent.`,
19
+ `- \`${SPEC_RULES_PATH}\` for cross-cutting domain rules, invariants and constraints.`,
20
+ `- \`${SPEC_FEATURES_DIR}/*.feature\` for the Gherkin (Given/When/Then) acceptance scenarios.`,
21
+ `- \`${SPEC_JSON_PATH}\` is the canonical machine-readable tree the markdown/feature files are rendered from; consult it when you need exact detail.`,
22
+ `Treat the spec as authoritative for required behaviour: make your change satisfy it, and if your change conflicts with the spec, follow the spec or call out the discrepancy rather than silently diverging.`,
23
+ ].join('\n');
24
+ /**
25
+ * Built-in trait assignment per agent kind.
26
+ * - `code-aware`: the kinds that read/modify the service's code, so the service's
27
+ * best-practice fragments are relevant to them.
28
+ * - `spec-aware`: every code-touching kind (anything that clones and reads the repo),
29
+ * so each is pointed at the in-repo spec. The `spec-writer` is intentionally absent —
30
+ * it AUTHORS the spec rather than consuming it.
31
+ */
32
+ export const STANDARD_AGENT_TRAITS = {
33
+ architect: [CODE_AWARE_TRAIT, SPEC_AWARE_TRAIT],
34
+ coder: [CODE_AWARE_TRAIT, SPEC_AWARE_TRAIT],
35
+ reviewer: [CODE_AWARE_TRAIT, SPEC_AWARE_TRAIT],
36
+ 'ci-fixer': [CODE_AWARE_TRAIT, SPEC_AWARE_TRAIT],
37
+ fixer: [CODE_AWARE_TRAIT, SPEC_AWARE_TRAIT],
38
+ 'conflict-resolver': [SPEC_AWARE_TRAIT],
39
+ tester: [SPEC_AWARE_TRAIT],
40
+ playwright: [SPEC_AWARE_TRAIT],
41
+ blueprints: [SPEC_AWARE_TRAIT],
42
+ 'business-documenter': [SPEC_AWARE_TRAIT],
43
+ 'business-reviewer': [SPEC_AWARE_TRAIT],
44
+ analysis: [SPEC_AWARE_TRAIT],
45
+ mocker: [SPEC_AWARE_TRAIT],
46
+ merger: [SPEC_AWARE_TRAIT],
47
+ };
48
+ // Process-wide trait registry, mirroring the agent-kind / model-provider registries.
49
+ const traitRegistry = new Map();
50
+ /** Register a custom trait definition. A later registration of the same id replaces it. */
51
+ export function registerAgentTrait(definition) {
52
+ traitRegistry.set(definition.id, definition);
53
+ }
54
+ /** Register several custom trait definitions at once. */
55
+ export function registerAgentTraits(definitions) {
56
+ for (const definition of definitions)
57
+ registerAgentTrait(definition);
58
+ }
59
+ /** The definition for a trait id, or undefined when it is a pure marker / unregistered. */
60
+ export function registeredAgentTrait(id) {
61
+ return traitRegistry.get(id);
62
+ }
63
+ /** Drop all registered (custom) traits. Intended for tests; standard traits re-register below. */
64
+ export function clearRegisteredAgentTraits() {
65
+ traitRegistry.clear();
66
+ registerStandardTraits();
67
+ }
68
+ /** The traits a kind carries: its built-in set unioned with a registered custom kind's. */
69
+ export function traitsFor(kind) {
70
+ const traits = new Set(STANDARD_AGENT_TRAITS[kind] ?? []);
71
+ for (const trait of registeredAgentKind(kind)?.traits ?? [])
72
+ traits.add(trait);
73
+ return traits;
74
+ }
75
+ /** Whether `kind` carries `trait`. */
76
+ export function hasTrait(kind, trait) {
77
+ return traitsFor(kind).has(trait);
78
+ }
79
+ /**
80
+ * The guidance lines contributed by the traits a kind carries, in trait order. Folded
81
+ * into the kind's system prompt by `systemPromptFor`. Marker traits (no guidance, e.g.
82
+ * `code-aware`) contribute nothing here.
83
+ */
84
+ export function traitGuidanceFor(kind) {
85
+ const lines = [];
86
+ for (const trait of traitsFor(kind)) {
87
+ const guidance = traitRegistry.get(trait)?.guidance;
88
+ if (!guidance)
89
+ continue;
90
+ lines.push(typeof guidance === 'function' ? guidance(kind) : guidance);
91
+ }
92
+ return lines;
93
+ }
94
+ /** Register the two standard traits' definitions (spec-aware carries guidance). */
95
+ function registerStandardTraits() {
96
+ registerAgentTrait({ id: CODE_AWARE_TRAIT });
97
+ registerAgentTrait({ id: SPEC_AWARE_TRAIT, guidance: SPEC_AWARE_GUIDANCE });
98
+ }
99
+ registerStandardTraits();
100
+ //# sourceMappingURL=traits.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"traits.js","sourceRoot":"","sources":["../../src/agents/traits.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ import type { ToolSet } from 'ai';
2
+ /** Default inline kinds allowed to search the web — the design/research steps. */
3
+ export declare const DEFAULT_INLINE_WEB_SEARCH_KINDS: ReadonlySet<string>;
4
+ /** Default ceiling on provider web searches per inline run (Anthropic `maxUses`). */
5
+ export declare const DEFAULT_INLINE_WEB_SEARCH_MAX_USES = 5;
6
+ /** How inline web search is configured for a deployment (off unless built). */
7
+ export interface InlineWebSearchOptions {
8
+ /** Agent kinds permitted to use provider web search. */
9
+ kinds: ReadonlySet<string>;
10
+ /** Max provider web searches per run (Anthropic `maxUses`; OpenAI manages its own). */
11
+ maxUses: number;
12
+ }
13
+ /**
14
+ * The web-search guidance appended to an agent's context ONLY when the tools are
15
+ * actually available, so the model is never told about a tool it lacks. The hint is
16
+ * tailored to `kind`; `fetch` controls whether the companion `web_fetch` tool (the Pi
17
+ * container path has it; the inline provider tool does not) is mentioned. Mirrors the
18
+ * harness's own conservative framing: search is for things that change or that the
19
+ * agent is unsure of, not a reflex, and never a substitute for reading the code.
20
+ */
21
+ export declare function webResearchGuidanceFor(kind: string, opts?: {
22
+ fetch?: boolean;
23
+ }): string;
24
+ /**
25
+ * The provider-hosted web_search tool set for a provider, or undefined when the
26
+ * provider has no server-executed web search the AI SDK can run inline. Only the
27
+ * provider id is consulted — the actual search runs under the model request's own
28
+ * credentials, so this just selects the right provider-defined tool spec.
29
+ */
30
+ export declare function providerWebSearchTools(provider: string, maxUses?: number): ToolSet | undefined;
31
+ /**
32
+ * Read inline web-search configuration from a deployment's environment, or
33
+ * undefined when it is not enabled. `INLINE_WEB_SEARCH_ENABLED` (truthy) is the
34
+ * single opt-in switch; `INLINE_WEB_SEARCH_KINDS` (comma-separated) overrides the
35
+ * default architect/researcher allow-list, and `INLINE_WEB_SEARCH_MAX_USES` caps
36
+ * searches per run. Off ⇒ the inline agents run exactly as before.
37
+ */
38
+ export declare function inlineWebSearchOptionsFromEnv(env: {
39
+ INLINE_WEB_SEARCH_ENABLED?: string;
40
+ INLINE_WEB_SEARCH_KINDS?: string;
41
+ INLINE_WEB_SEARCH_MAX_USES?: string;
42
+ }): InlineWebSearchOptions | undefined;
43
+ //# sourceMappingURL=web-search.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web-search.d.ts","sourceRoot":"","sources":["../../src/agents/web-search.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,IAAI,CAAA;AAWjC,kFAAkF;AAClF,eAAO,MAAM,+BAA+B,EAAE,WAAW,CAAC,MAAM,CAG9D,CAAA;AAEF,qFAAqF;AACrF,eAAO,MAAM,kCAAkC,IAAI,CAAA;AAEnD,+EAA+E;AAC/E,MAAM,WAAW,sBAAsB;IACrC,wDAAwD;IACxD,KAAK,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;IAC1B,uFAAuF;IACvF,OAAO,EAAE,MAAM,CAAA;CAChB;AA8BD;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,MAAM,CAiB3F;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,MAA2C,GACnD,OAAO,GAAG,SAAS,CAYrB;AAED;;;;;;GAMG;AACH,wBAAgB,6BAA6B,CAAC,GAAG,EAAE;IACjD,yBAAyB,CAAC,EAAE,MAAM,CAAA;IAClC,uBAAuB,CAAC,EAAE,MAAM,CAAA;IAChC,0BAA0B,CAAC,EAAE,MAAM,CAAA;CACpC,GAAG,sBAAsB,GAAG,SAAS,CAerC"}
@@ -0,0 +1,102 @@
1
+ import { anthropic } from '@ai-sdk/anthropic';
2
+ import { openai } from '@ai-sdk/openai';
3
+ import { registeredWebResearchHint } from './registry.js';
4
+ // Provider-hosted web search for the INLINE agents (architect / researcher), which
5
+ // run a single `generateText` call via the AI SDK rather than going through the Pi
6
+ // container harness. Anthropic and OpenAI expose a server-executed web_search tool
7
+ // the SDK runs inline (the provider performs the search and folds the results into
8
+ // the same response — no client-side tool loop), exactly how Claude Code and Codex
9
+ // add web access. Providers without a hosted search (workers-ai, the
10
+ // OpenAI-compatible trio, mock) get no tool, so those deployments run unchanged.
11
+ /** Default inline kinds allowed to search the web — the design/research steps. */
12
+ export const DEFAULT_INLINE_WEB_SEARCH_KINDS = new Set([
13
+ 'architect',
14
+ 'researcher',
15
+ ]);
16
+ /** Default ceiling on provider web searches per inline run (Anthropic `maxUses`). */
17
+ export const DEFAULT_INLINE_WEB_SEARCH_MAX_USES = 5;
18
+ // Per-kind reason an agent reaches for web search, so the nudge speaks to what that
19
+ // agent is actually doing rather than a generic "verify facts". These are the defaults
20
+ // for the BUILT-IN kinds; a custom/proprietary kind supplies its own via the registry
21
+ // (`AgentKindDefinition.webResearchHint`), which wins — so the shared composition here
22
+ // never needs to know a proprietary kind exists. Resolution order is registry → these
23
+ // built-in defaults → GENERIC_WEB_RESEARCH_HINT (see `webResearchGuidanceFor`).
24
+ const BUILTIN_WEB_RESEARCH_HINTS = {
25
+ coder: 'confirm a current library/API signature before you rely on it, and check for a known breaking change when an import or call behaves unexpectedly',
26
+ 'ci-fixer': "search the exact failing error message, or a dependency's changelog/known issues, to find the real fix instead of guessing at versions",
27
+ mocker: "fetch the real third-party API's reference (endpoints, status codes, payload shapes, error formats) so the stubs match production behaviour",
28
+ analysis: 'check whether a dependency is deprecated, end-of-life, or has a known CVE / newer major version when judging technical debt',
29
+ 'business-documenter': 'verify domain or regulatory terminology when documenting business rules, so the captured rules use the correct, current vocabulary',
30
+ playwright: "confirm a current testing-framework or locator API when the project's version differs from what you remember",
31
+ architect: 'compare current library/framework options and their trade-offs, and verify a capability or version is real before you design around it',
32
+ researcher: 'this is your primary tool — survey prior art, candidate libraries, benchmarks and known pitfalls, and ground every recommendation in a cited source',
33
+ };
34
+ const GENERIC_WEB_RESEARCH_HINT = "verify a fact that genuinely changes — a library version, an API, a recent breaking change, a security advisory — when the repository itself can't answer it";
35
+ /**
36
+ * The web-search guidance appended to an agent's context ONLY when the tools are
37
+ * actually available, so the model is never told about a tool it lacks. The hint is
38
+ * tailored to `kind`; `fetch` controls whether the companion `web_fetch` tool (the Pi
39
+ * container path has it; the inline provider tool does not) is mentioned. Mirrors the
40
+ * harness's own conservative framing: search is for things that change or that the
41
+ * agent is unsure of, not a reflex, and never a substitute for reading the code.
42
+ */
43
+ export function webResearchGuidanceFor(kind, opts = {}) {
44
+ // A proprietary/custom kind's own hint wins (it knows its job; the shared library
45
+ // doesn't); then the built-in defaults; then the generic fallback.
46
+ const hint = registeredWebResearchHint(kind) ?? BUILTIN_WEB_RESEARCH_HINTS[kind] ?? GENERIC_WEB_RESEARCH_HINT;
47
+ const tools = opts.fetch
48
+ ? '`web_search` (titled result snippets for a query) and `web_fetch` (read a URL as text)'
49
+ : 'a `web_search` tool';
50
+ const them = opts.fetch ? 'them' : 'it';
51
+ return `
52
+
53
+ ## Web search (use sparingly)
54
+
55
+ You have ${tools}. Use ${them} mainly to ${hint}. Prefer first-party documentation, and
56
+ cite the source URL when a decision rests on what you find. Do not search for anything
57
+ already in the checkout or the context you were given, and don't let searching replace
58
+ reading the code.`;
59
+ }
60
+ /**
61
+ * The provider-hosted web_search tool set for a provider, or undefined when the
62
+ * provider has no server-executed web search the AI SDK can run inline. Only the
63
+ * provider id is consulted — the actual search runs under the model request's own
64
+ * credentials, so this just selects the right provider-defined tool spec.
65
+ */
66
+ export function providerWebSearchTools(provider, maxUses = DEFAULT_INLINE_WEB_SEARCH_MAX_USES) {
67
+ if (provider === 'anthropic') {
68
+ return { web_search: anthropic.tools.webSearch_20250305({ maxUses }) };
69
+ }
70
+ if (provider === 'openai') {
71
+ // OpenAI's hosted search runs via the Responses API; `@ai-sdk/openai`'s default
72
+ // model uses it, so a standard `openai:gpt-…` model resolves correctly. The
73
+ // per-run cap isn't a tool parameter here (OpenAI manages its own budget), so
74
+ // `maxUses` only applies to the Anthropic tool above.
75
+ return { web_search: openai.tools.webSearch({}) };
76
+ }
77
+ return undefined;
78
+ }
79
+ /**
80
+ * Read inline web-search configuration from a deployment's environment, or
81
+ * undefined when it is not enabled. `INLINE_WEB_SEARCH_ENABLED` (truthy) is the
82
+ * single opt-in switch; `INLINE_WEB_SEARCH_KINDS` (comma-separated) overrides the
83
+ * default architect/researcher allow-list, and `INLINE_WEB_SEARCH_MAX_USES` caps
84
+ * searches per run. Off ⇒ the inline agents run exactly as before.
85
+ */
86
+ export function inlineWebSearchOptionsFromEnv(env) {
87
+ const enabled = env.INLINE_WEB_SEARCH_ENABLED?.trim().toLowerCase();
88
+ if (enabled !== 'true' && enabled !== '1' && enabled !== 'yes')
89
+ return undefined;
90
+ const kindList = (env.INLINE_WEB_SEARCH_KINDS ?? '')
91
+ .split(',')
92
+ .map((k) => k.trim().toLowerCase())
93
+ .filter(Boolean);
94
+ const maxUses = Number(env.INLINE_WEB_SEARCH_MAX_USES);
95
+ return {
96
+ kinds: kindList.length ? new Set(kindList) : DEFAULT_INLINE_WEB_SEARCH_KINDS,
97
+ maxUses: Number.isFinite(maxUses) && maxUses > 0
98
+ ? Math.floor(maxUses)
99
+ : DEFAULT_INLINE_WEB_SEARCH_MAX_USES,
100
+ };
101
+ }
102
+ //# sourceMappingURL=web-search.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web-search.js","sourceRoot":"","sources":["../../src/agents/web-search.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import type { FragmentSelectionContext, FragmentSelector, SelectableFragment } from '@cat-factory/kernel';
2
+ /**
3
+ * The built-in {@link FragmentSelector}: matches on `appliesTo` + tag overlap
4
+ * with no model call. It is the default when the library module is wired without
5
+ * an LLM selector, and the fallback an LLM selector degrades to. See ADR 0006 §5.
6
+ */
7
+ export declare class DeterministicFragmentSelector implements FragmentSelector {
8
+ select(candidates: SelectableFragment[], context: FragmentSelectionContext): Promise<string[]>;
9
+ }
10
+ //# sourceMappingURL=DeterministicFragmentSelector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DeterministicFragmentSelector.d.ts","sourceRoot":"","sources":["../../src/fragmentLibrary/DeterministicFragmentSelector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,wBAAwB,EACxB,gBAAgB,EAChB,kBAAkB,EACnB,MAAM,qBAAqB,CAAA;AAG5B;;;;GAIG;AACH,qBAAa,6BAA8B,YAAW,gBAAgB;IAC9D,MAAM,CACV,UAAU,EAAE,kBAAkB,EAAE,EAChC,OAAO,EAAE,wBAAwB,GAChC,OAAO,CAAC,MAAM,EAAE,CAAC,CAEnB;CACF"}
@@ -0,0 +1,12 @@
1
+ import { selectDeterministic } from './fragment-catalog.js';
2
+ /**
3
+ * The built-in {@link FragmentSelector}: matches on `appliesTo` + tag overlap
4
+ * with no model call. It is the default when the library module is wired without
5
+ * an LLM selector, and the fallback an LLM selector degrades to. See ADR 0006 §5.
6
+ */
7
+ export class DeterministicFragmentSelector {
8
+ async select(candidates, context) {
9
+ return selectDeterministic(candidates, context);
10
+ }
11
+ }
12
+ //# sourceMappingURL=DeterministicFragmentSelector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DeterministicFragmentSelector.js","sourceRoot":"","sources":["../../src/fragmentLibrary/DeterministicFragmentSelector.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAA;AAE3D;;;;GAIG;AACH,MAAM,OAAO,6BAA6B;IACxC,KAAK,CAAC,MAAM,CACV,UAAgC,EAChC,OAAiC;QAEjC,OAAO,mBAAmB,CAAC,UAAU,EAAE,OAAO,CAAC,CAAA;IACjD,CAAC;CACF"}
@@ -0,0 +1,55 @@
1
+ import type { PromptFragment } from '@cat-factory/contracts';
2
+ import type { CreatePromptFragmentInput, FragmentOwnerKind, ResolvedFragment, UpdatePromptFragmentInput } from '@cat-factory/kernel';
3
+ import type { Clock } from '@cat-factory/kernel';
4
+ import type { FragmentSelector, FragmentResolver, FragmentResolverInput, FragmentRunSelection } from '@cat-factory/kernel';
5
+ import type { PromptFragmentRepository } from '@cat-factory/kernel';
6
+ import type { WorkspaceRepository } from '@cat-factory/kernel';
7
+ import { type ResolvedCatalogEntry } from './fragment-catalog.js';
8
+ export interface FragmentLibraryServiceDependencies {
9
+ promptFragmentRepository: PromptFragmentRepository;
10
+ workspaceRepository: WorkspaceRepository;
11
+ clock: Clock;
12
+ /** Relevance selector; defaults to the deterministic matcher when omitted. */
13
+ selector?: FragmentSelector;
14
+ /** Built-in catalog tier; overridable for tests. Defaults to the shipped FRAGMENTS. */
15
+ builtins?: PromptFragment[];
16
+ }
17
+ /**
18
+ * The fragment library's management service (ADR 0006). It owns the per-tier CRUD
19
+ * (account / workspace) and resolves the merged catalog a workspace sees (built-in ∪
20
+ * account ∪ workspace, override-by-id, tombstone-suppressed). It still implements
21
+ * {@link FragmentResolver} (`resolveForRun`), but the execution engine NO LONGER
22
+ * consumes it: fragment delivery is now the service-scoped `serviceFragmentIds` folded
23
+ * into `code-aware` agents, so this is a management surface only.
24
+ */
25
+ export declare class FragmentLibraryService implements FragmentResolver {
26
+ private readonly repo;
27
+ private readonly workspaces;
28
+ private readonly clock;
29
+ private readonly selector;
30
+ private readonly builtins;
31
+ constructor(deps: FragmentLibraryServiceDependencies);
32
+ /** This tier's hand-authored/sourced fragments (raw, not merged), newest first. */
33
+ listTier(ownerKind: FragmentOwnerKind, ownerId: string): Promise<PromptFragment[]>;
34
+ /** Create a hand-authored fragment at a tier. */
35
+ create(ownerKind: FragmentOwnerKind, ownerId: string, input: CreatePromptFragmentInput): Promise<PromptFragment>;
36
+ /**
37
+ * Edit a fragment at a tier. If no row exists yet (e.g. shadowing a built-in or
38
+ * inherited account fragment), the patch must carry enough to stand alone
39
+ * (title, summary, body); otherwise it merges over the existing record.
40
+ */
41
+ update(ownerKind: FragmentOwnerKind, ownerId: string, fragmentId: string, patch: UpdatePromptFragmentInput): Promise<PromptFragment>;
42
+ /**
43
+ * Tombstone a fragment at a tier. Suppresses an inherited built-in/account
44
+ * fragment, or removes a hand-authored one. Idempotent — writing a tombstone
45
+ * even when no row exists yet, so a tier can suppress something it inherits.
46
+ */
47
+ remove(ownerKind: FragmentOwnerKind, ownerId: string, fragmentId: string): Promise<void>;
48
+ /** Resolve the merged catalog a workspace sees (built-in ∪ account ∪ workspace). */
49
+ resolveCatalog(workspaceId: string): Promise<ResolvedCatalogEntry[]>;
50
+ /** The merged catalog as wire {@link ResolvedFragment}s for the management UI. */
51
+ resolvedCatalog(workspaceId: string): Promise<ResolvedFragment[]>;
52
+ /** {@link FragmentResolver}: pick + resolve the fragments to inject for a run. */
53
+ resolveForRun(input: FragmentResolverInput): Promise<FragmentRunSelection>;
54
+ }
55
+ //# sourceMappingURL=FragmentLibraryService.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FragmentLibraryService.d.ts","sourceRoot":"","sources":["../../src/fragmentLibrary/FragmentLibraryService.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAE5D,OAAO,KAAK,EACV,yBAAyB,EACzB,iBAAiB,EACjB,gBAAgB,EAChB,yBAAyB,EAC1B,MAAM,qBAAqB,CAAA;AAE5B,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAA;AAChD,OAAO,KAAK,EACV,gBAAgB,EAChB,gBAAgB,EAChB,qBAAqB,EACrB,oBAAoB,EACrB,MAAM,qBAAqB,CAAA;AAC5B,OAAO,KAAK,EAAwB,wBAAwB,EAAE,MAAM,qBAAqB,CAAA;AACzF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAA;AAE9D,OAAO,EACL,KAAK,oBAAoB,EAI1B,MAAM,uBAAuB,CAAA;AAG9B,MAAM,WAAW,kCAAkC;IACjD,wBAAwB,EAAE,wBAAwB,CAAA;IAClD,mBAAmB,EAAE,mBAAmB,CAAA;IACxC,KAAK,EAAE,KAAK,CAAA;IACZ,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,gBAAgB,CAAA;IAC3B,uFAAuF;IACvF,QAAQ,CAAC,EAAE,cAAc,EAAE,CAAA;CAC5B;AAED;;;;;;;GAOG;AACH,qBAAa,sBAAuB,YAAW,gBAAgB;IAC7D,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA0B;IAC/C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAqB;IAChD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAO;IAC7B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAkB;IAC3C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAkB;IAE3C,YAAY,IAAI,EAAE,kCAAkC,EAMnD;IAED,mFAAmF;IAC7E,QAAQ,CAAC,SAAS,EAAE,iBAAiB,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAGvF;IAED,iDAAiD;IAC3C,MAAM,CACV,SAAS,EAAE,iBAAiB,EAC5B,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,yBAAyB,GAC/B,OAAO,CAAC,cAAc,CAAC,CAwBzB;IAED;;;;OAIG;IACG,MAAM,CACV,SAAS,EAAE,iBAAiB,EAC5B,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,yBAAyB,GAC/B,OAAO,CAAC,cAAc,CAAC,CAsCzB;IAED;;;;OAIG;IACG,MAAM,CAAC,SAAS,EAAE,iBAAiB,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAyB7F;IAED,oFAAoF;IAC9E,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC,CAOzE;IAED,kFAAkF;IAC5E,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAGtE;IAED,kFAAkF;IAC5E,aAAa,CAAC,KAAK,EAAE,qBAAqB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAkC/E;CACF"}