stable-harness 0.0.36 → 0.0.38

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 (233) hide show
  1. package/node_modules/@stable-harness/adapter-deepagents/dist/src/adapter.d.ts +9 -0
  2. package/node_modules/@stable-harness/adapter-deepagents/dist/src/adapter.js +1 -0
  3. package/node_modules/@stable-harness/adapter-deepagents/dist/src/index.d.ts +4 -0
  4. package/node_modules/@stable-harness/adapter-deepagents/dist/src/index.js +1 -0
  5. package/node_modules/@stable-harness/adapter-deepagents/dist/src/internal/builtin-args.d.ts +5 -0
  6. package/node_modules/@stable-harness/adapter-deepagents/dist/src/internal/builtin-args.js +1 -0
  7. package/node_modules/@stable-harness/adapter-deepagents/dist/src/internal/builtin-call-repair.d.ts +9 -0
  8. package/node_modules/@stable-harness/adapter-deepagents/dist/src/internal/builtin-call-repair.js +1 -0
  9. package/node_modules/@stable-harness/adapter-deepagents/dist/src/internal/builtin-tool-policy.d.ts +39 -0
  10. package/node_modules/@stable-harness/adapter-deepagents/dist/src/internal/builtin-tool-policy.js +1 -0
  11. package/node_modules/@stable-harness/adapter-deepagents/dist/src/internal/gateway/tool-evidence.d.ts +10 -0
  12. package/node_modules/@stable-harness/adapter-deepagents/dist/src/internal/gateway/tool-evidence.js +1 -0
  13. package/node_modules/@stable-harness/adapter-deepagents/dist/src/internal/gateway/tool-failure-events.d.ts +2 -0
  14. package/node_modules/@stable-harness/adapter-deepagents/dist/src/internal/gateway/tool-failure-events.js +1 -0
  15. package/node_modules/@stable-harness/adapter-deepagents/dist/src/internal/gateway-tools.d.ts +33 -0
  16. package/node_modules/@stable-harness/adapter-deepagents/dist/src/internal/gateway-tools.js +1 -0
  17. package/node_modules/@stable-harness/adapter-deepagents/dist/src/internal/messages.d.ts +9 -0
  18. package/node_modules/@stable-harness/adapter-deepagents/dist/src/internal/messages.js +1 -0
  19. package/node_modules/@stable-harness/adapter-deepagents/dist/src/internal/raw-tool-call-parser.d.ts +12 -0
  20. package/node_modules/@stable-harness/adapter-deepagents/dist/src/internal/raw-tool-call-parser.js +1 -0
  21. package/node_modules/@stable-harness/adapter-deepagents/dist/src/internal/skill-file-policy.d.ts +10 -0
  22. package/node_modules/@stable-harness/adapter-deepagents/dist/src/internal/skill-file-policy.js +1 -0
  23. package/node_modules/@stable-harness/adapter-deepagents/dist/src/internal/stream-events.d.ts +2 -0
  24. package/node_modules/@stable-harness/adapter-deepagents/dist/src/internal/stream-events.js +1 -0
  25. package/node_modules/@stable-harness/adapter-deepagents/dist/src/internal/tool-repeat-visibility.d.ts +4 -0
  26. package/node_modules/@stable-harness/adapter-deepagents/dist/src/internal/tool-repeat-visibility.js +1 -0
  27. package/node_modules/@stable-harness/adapter-deepagents/dist/src/internal/trace-projection.d.ts +16 -0
  28. package/node_modules/@stable-harness/adapter-deepagents/dist/src/internal/trace-projection.js +1 -0
  29. package/node_modules/@stable-harness/adapter-deepagents/dist/src/memory.d.ts +5 -0
  30. package/node_modules/@stable-harness/adapter-deepagents/dist/src/memory.js +1 -0
  31. package/node_modules/@stable-harness/adapter-deepagents/dist/src/model-providers.d.ts +4 -0
  32. package/node_modules/@stable-harness/adapter-deepagents/dist/src/model-providers.js +1 -0
  33. package/node_modules/@stable-harness/adapter-deepagents/dist/src/retry-policy.d.ts +2 -0
  34. package/node_modules/@stable-harness/adapter-deepagents/dist/src/retry-policy.js +1 -0
  35. package/node_modules/@stable-harness/adapter-deepagents/dist/src/types.d.ts +12 -0
  36. package/node_modules/@stable-harness/adapter-deepagents/dist/src/types.js +1 -0
  37. package/node_modules/@stable-harness/adapter-deepagents/package.json +26 -0
  38. package/node_modules/@stable-harness/adapter-langgraph/dist/src/graph.d.ts +3 -0
  39. package/node_modules/@stable-harness/adapter-langgraph/dist/src/graph.js +1 -0
  40. package/node_modules/@stable-harness/adapter-langgraph/dist/src/index.d.ts +8 -0
  41. package/node_modules/@stable-harness/adapter-langgraph/dist/src/index.js +1 -0
  42. package/node_modules/@stable-harness/adapter-langgraph/dist/src/runtime.d.ts +3 -0
  43. package/node_modules/@stable-harness/adapter-langgraph/dist/src/runtime.js +1 -0
  44. package/node_modules/@stable-harness/adapter-langgraph/dist/src/skill-providers.d.ts +29 -0
  45. package/node_modules/@stable-harness/adapter-langgraph/dist/src/skill-providers.js +1 -0
  46. package/node_modules/@stable-harness/adapter-langgraph/dist/src/types.d.ts +60 -0
  47. package/node_modules/@stable-harness/adapter-langgraph/dist/src/types.js +1 -0
  48. package/node_modules/@stable-harness/adapter-langgraph/package.json +16 -0
  49. package/node_modules/@stable-harness/core/dist/boundary-scan.d.ts +38 -0
  50. package/node_modules/@stable-harness/core/dist/boundary-scan.js +1 -0
  51. package/node_modules/@stable-harness/core/dist/evaluations/index.d.ts +18 -0
  52. package/node_modules/@stable-harness/core/dist/evaluations/index.js +1 -0
  53. package/node_modules/@stable-harness/core/dist/execution-contract.d.ts +9 -0
  54. package/node_modules/@stable-harness/core/dist/execution-contract.js +1 -0
  55. package/node_modules/@stable-harness/core/dist/index.d.ts +20 -0
  56. package/node_modules/@stable-harness/core/dist/index.js +1 -0
  57. package/node_modules/@stable-harness/core/dist/memory-plugins/maintenance.d.ts +42 -0
  58. package/node_modules/@stable-harness/core/dist/memory-plugins/maintenance.js +1 -0
  59. package/node_modules/@stable-harness/core/dist/memory-plugins/shared.d.ts +8 -0
  60. package/node_modules/@stable-harness/core/dist/memory-plugins/shared.js +1 -0
  61. package/node_modules/@stable-harness/core/dist/memory-plugins.d.ts +25 -0
  62. package/node_modules/@stable-harness/core/dist/memory-plugins.js +1 -0
  63. package/node_modules/@stable-harness/core/dist/quality/event-evidence.d.ts +11 -0
  64. package/node_modules/@stable-harness/core/dist/quality/event-evidence.js +1 -0
  65. package/node_modules/@stable-harness/core/dist/quality/execution-review.d.ts +2 -0
  66. package/node_modules/@stable-harness/core/dist/quality/execution-review.js +1 -0
  67. package/node_modules/@stable-harness/core/dist/quality/index.d.ts +9 -0
  68. package/node_modules/@stable-harness/core/dist/quality/index.js +1 -0
  69. package/node_modules/@stable-harness/core/dist/quality/llm-review.d.ts +7 -0
  70. package/node_modules/@stable-harness/core/dist/quality/llm-review.js +1 -0
  71. package/node_modules/@stable-harness/core/dist/quality/planning-review.d.ts +2 -0
  72. package/node_modules/@stable-harness/core/dist/quality/planning-review.js +1 -0
  73. package/node_modules/@stable-harness/core/dist/quality/profile.d.ts +3 -0
  74. package/node_modules/@stable-harness/core/dist/quality/profile.js +1 -0
  75. package/node_modules/@stable-harness/core/dist/quality/recovery-policy.d.ts +11 -0
  76. package/node_modules/@stable-harness/core/dist/quality/recovery-policy.js +1 -0
  77. package/node_modules/@stable-harness/core/dist/quality/runtime.d.ts +13 -0
  78. package/node_modules/@stable-harness/core/dist/quality/runtime.js +1 -0
  79. package/node_modules/@stable-harness/core/dist/quality/synthesis/fields.d.ts +19 -0
  80. package/node_modules/@stable-harness/core/dist/quality/synthesis/fields.js +1 -0
  81. package/node_modules/@stable-harness/core/dist/quality/synthesis/language.d.ts +3 -0
  82. package/node_modules/@stable-harness/core/dist/quality/synthesis/language.js +1 -0
  83. package/node_modules/@stable-harness/core/dist/quality/synthesis/observed.d.ts +3 -0
  84. package/node_modules/@stable-harness/core/dist/quality/synthesis/observed.js +1 -0
  85. package/node_modules/@stable-harness/core/dist/quality/synthesis.d.ts +2 -0
  86. package/node_modules/@stable-harness/core/dist/quality/synthesis.js +1 -0
  87. package/node_modules/@stable-harness/core/dist/quality/types.d.ts +52 -0
  88. package/node_modules/@stable-harness/core/dist/quality/types.js +1 -0
  89. package/node_modules/@stable-harness/core/dist/recovery/tool-call.d.ts +28 -0
  90. package/node_modules/@stable-harness/core/dist/recovery/tool-call.js +1 -0
  91. package/node_modules/@stable-harness/core/dist/runtime/capabilities.d.ts +47 -0
  92. package/node_modules/@stable-harness/core/dist/runtime/capabilities.js +1 -0
  93. package/node_modules/@stable-harness/core/dist/runtime/completion.d.ts +18 -0
  94. package/node_modules/@stable-harness/core/dist/runtime/completion.js +1 -0
  95. package/node_modules/@stable-harness/core/dist/runtime/direct-tool-call.d.ts +11 -0
  96. package/node_modules/@stable-harness/core/dist/runtime/direct-tool-call.js +1 -0
  97. package/node_modules/@stable-harness/core/dist/runtime/events.d.ts +295 -0
  98. package/node_modules/@stable-harness/core/dist/runtime/events.js +1 -0
  99. package/node_modules/@stable-harness/core/dist/runtime/governance/approval-gate.d.ts +8 -0
  100. package/node_modules/@stable-harness/core/dist/runtime/governance/approval-gate.js +1 -0
  101. package/node_modules/@stable-harness/core/dist/runtime/governance/sandbox.d.ts +9 -0
  102. package/node_modules/@stable-harness/core/dist/runtime/governance/sandbox.js +1 -0
  103. package/node_modules/@stable-harness/core/dist/runtime/inspection/artifacts.d.ts +15 -0
  104. package/node_modules/@stable-harness/core/dist/runtime/inspection/artifacts.js +1 -0
  105. package/node_modules/@stable-harness/core/dist/runtime/inspection/methods.d.ts +11 -0
  106. package/node_modules/@stable-harness/core/dist/runtime/inspection/methods.js +1 -0
  107. package/node_modules/@stable-harness/core/dist/runtime/inspection/replay.d.ts +6 -0
  108. package/node_modules/@stable-harness/core/dist/runtime/inspection/replay.js +1 -0
  109. package/node_modules/@stable-harness/core/dist/runtime/memory.d.ts +29 -0
  110. package/node_modules/@stable-harness/core/dist/runtime/memory.js +1 -0
  111. package/node_modules/@stable-harness/core/dist/runtime/persistence/artifacts.d.ts +8 -0
  112. package/node_modules/@stable-harness/core/dist/runtime/persistence/artifacts.js +1 -0
  113. package/node_modules/@stable-harness/core/dist/runtime/persistence/inspection.d.ts +4 -0
  114. package/node_modules/@stable-harness/core/dist/runtime/persistence/inspection.js +1 -0
  115. package/node_modules/@stable-harness/core/dist/runtime/persistence/queue.d.ts +2 -0
  116. package/node_modules/@stable-harness/core/dist/runtime/persistence/queue.js +1 -0
  117. package/node_modules/@stable-harness/core/dist/runtime/persistence/stores.d.ts +3 -0
  118. package/node_modules/@stable-harness/core/dist/runtime/persistence/stores.js +1 -0
  119. package/node_modules/@stable-harness/core/dist/runtime/progress-narration.d.ts +38 -0
  120. package/node_modules/@stable-harness/core/dist/runtime/progress-narration.js +1 -0
  121. package/node_modules/@stable-harness/core/dist/runtime/selection-repair.d.ts +24 -0
  122. package/node_modules/@stable-harness/core/dist/runtime/selection-repair.js +1 -0
  123. package/node_modules/@stable-harness/core/dist/runtime/tool-failure.d.ts +41 -0
  124. package/node_modules/@stable-harness/core/dist/runtime/tool-failure.js +1 -0
  125. package/node_modules/@stable-harness/core/dist/runtime/tool-gateway.d.ts +59 -0
  126. package/node_modules/@stable-harness/core/dist/runtime/tool-gateway.js +1 -0
  127. package/node_modules/@stable-harness/core/dist/runtime/types.d.ts +191 -0
  128. package/node_modules/@stable-harness/core/dist/runtime/types.js +1 -0
  129. package/node_modules/@stable-harness/core/dist/runtime.d.ts +21 -0
  130. package/node_modules/@stable-harness/core/dist/runtime.js +1 -0
  131. package/node_modules/@stable-harness/core/dist/spec-driven/config.d.ts +4 -0
  132. package/node_modules/@stable-harness/core/dist/spec-driven/config.js +1 -0
  133. package/node_modules/@stable-harness/core/dist/spec-driven/events.d.ts +11 -0
  134. package/node_modules/@stable-harness/core/dist/spec-driven/events.js +1 -0
  135. package/node_modules/@stable-harness/core/dist/spec-driven/index.d.ts +4 -0
  136. package/node_modules/@stable-harness/core/dist/spec-driven/index.js +1 -0
  137. package/node_modules/@stable-harness/core/dist/spec-driven/lifecycle.d.ts +11 -0
  138. package/node_modules/@stable-harness/core/dist/spec-driven/lifecycle.js +1 -0
  139. package/node_modules/@stable-harness/core/dist/spec-driven/types.d.ts +38 -0
  140. package/node_modules/@stable-harness/core/dist/spec-driven/types.js +1 -0
  141. package/node_modules/@stable-harness/core/dist/trace.d.ts +15 -0
  142. package/node_modules/@stable-harness/core/dist/trace.js +1 -0
  143. package/node_modules/@stable-harness/core/dist/types.d.ts +144 -0
  144. package/node_modules/@stable-harness/core/dist/types.js +1 -0
  145. package/node_modules/@stable-harness/core/dist/workflows/index.d.ts +70 -0
  146. package/node_modules/@stable-harness/core/dist/workflows/index.js +1 -0
  147. package/node_modules/@stable-harness/core/dist/workflows/runtime.d.ts +12 -0
  148. package/node_modules/@stable-harness/core/dist/workflows/runtime.js +1 -0
  149. package/node_modules/@stable-harness/core/dist/workspace/tool-quality.d.ts +22 -0
  150. package/node_modules/@stable-harness/core/dist/workspace/tool-quality.js +1 -0
  151. package/node_modules/@stable-harness/core/dist/workspace/types.d.ts +134 -0
  152. package/node_modules/@stable-harness/core/dist/workspace/types.js +1 -0
  153. package/node_modules/@stable-harness/core/package.json +18 -0
  154. package/node_modules/@stable-harness/governance/dist/src/approval-queue.d.ts +2 -0
  155. package/node_modules/@stable-harness/governance/dist/src/approval-queue.js +1 -0
  156. package/node_modules/@stable-harness/governance/dist/src/index.d.ts +4 -0
  157. package/node_modules/@stable-harness/governance/dist/src/index.js +1 -0
  158. package/node_modules/@stable-harness/governance/dist/src/policy-engine.d.ts +2 -0
  159. package/node_modules/@stable-harness/governance/dist/src/policy-engine.js +1 -0
  160. package/node_modules/@stable-harness/governance/dist/src/skill-candidates.d.ts +2 -0
  161. package/node_modules/@stable-harness/governance/dist/src/skill-candidates.js +1 -0
  162. package/node_modules/@stable-harness/governance/dist/src/types.d.ts +101 -0
  163. package/node_modules/@stable-harness/governance/dist/src/types.js +1 -0
  164. package/node_modules/@stable-harness/governance/package.json +12 -0
  165. package/node_modules/@stable-harness/memory/dist/src/index.d.ts +9 -0
  166. package/node_modules/@stable-harness/memory/dist/src/index.js +1 -0
  167. package/node_modules/@stable-harness/memory/dist/src/langmem-service.d.ts +8 -0
  168. package/node_modules/@stable-harness/memory/dist/src/langmem-service.js +1 -0
  169. package/node_modules/@stable-harness/memory/dist/src/maintenance.d.ts +2 -0
  170. package/node_modules/@stable-harness/memory/dist/src/maintenance.js +1 -0
  171. package/node_modules/@stable-harness/memory/dist/src/persistence.d.ts +4 -0
  172. package/node_modules/@stable-harness/memory/dist/src/persistence.js +1 -0
  173. package/node_modules/@stable-harness/memory/dist/src/policy.d.ts +2 -0
  174. package/node_modules/@stable-harness/memory/dist/src/policy.js +1 -0
  175. package/node_modules/@stable-harness/memory/dist/src/provider.d.ts +50 -0
  176. package/node_modules/@stable-harness/memory/dist/src/provider.js +1 -0
  177. package/node_modules/@stable-harness/memory/dist/src/store.d.ts +5 -0
  178. package/node_modules/@stable-harness/memory/dist/src/store.js +1 -0
  179. package/node_modules/@stable-harness/memory/dist/src/types.d.ts +138 -0
  180. package/node_modules/@stable-harness/memory/dist/src/types.js +1 -0
  181. package/node_modules/@stable-harness/memory/package.json +12 -0
  182. package/node_modules/@stable-harness/protocols/dist/src/http-server.d.ts +3 -0
  183. package/node_modules/@stable-harness/protocols/dist/src/http-server.js +1 -0
  184. package/node_modules/@stable-harness/protocols/dist/src/in-process-client.d.ts +2 -0
  185. package/node_modules/@stable-harness/protocols/dist/src/in-process-client.js +1 -0
  186. package/node_modules/@stable-harness/protocols/dist/src/index.d.ts +4 -0
  187. package/node_modules/@stable-harness/protocols/dist/src/index.js +1 -0
  188. package/node_modules/@stable-harness/protocols/dist/src/openai-compatible.d.ts +9 -0
  189. package/node_modules/@stable-harness/protocols/dist/src/openai-compatible.js +1 -0
  190. package/node_modules/@stable-harness/protocols/dist/src/openai-payload.d.ts +74 -0
  191. package/node_modules/@stable-harness/protocols/dist/src/openai-payload.js +1 -0
  192. package/node_modules/@stable-harness/protocols/dist/src/openai-stream.d.ts +39 -0
  193. package/node_modules/@stable-harness/protocols/dist/src/openai-stream.js +1 -0
  194. package/node_modules/@stable-harness/protocols/package.json +15 -0
  195. package/node_modules/@stable-harness/tool-gateway/dist/src/argument-guard.d.ts +33 -0
  196. package/node_modules/@stable-harness/tool-gateway/dist/src/argument-guard.js +1 -0
  197. package/node_modules/@stable-harness/tool-gateway/dist/src/in-memory.d.ts +4 -0
  198. package/node_modules/@stable-harness/tool-gateway/dist/src/in-memory.js +1 -0
  199. package/node_modules/@stable-harness/tool-gateway/dist/src/index.d.ts +7 -0
  200. package/node_modules/@stable-harness/tool-gateway/dist/src/index.js +1 -0
  201. package/node_modules/@stable-harness/tool-gateway/dist/src/module-loader.d.ts +13 -0
  202. package/node_modules/@stable-harness/tool-gateway/dist/src/module-loader.js +1 -0
  203. package/node_modules/@stable-harness/tool-gateway/dist/src/schema-validation.d.ts +3 -0
  204. package/node_modules/@stable-harness/tool-gateway/dist/src/schema-validation.js +1 -0
  205. package/node_modules/@stable-harness/tool-gateway/dist/src/types.d.ts +79 -0
  206. package/node_modules/@stable-harness/tool-gateway/dist/src/types.js +1 -0
  207. package/node_modules/@stable-harness/tool-gateway/package.json +15 -0
  208. package/node_modules/@stable-harness/workspace-yaml/dist/boundary-scan.d.ts +3 -0
  209. package/node_modules/@stable-harness/workspace-yaml/dist/boundary-scan.js +1 -0
  210. package/node_modules/@stable-harness/workspace-yaml/dist/discovery.d.ts +4 -0
  211. package/node_modules/@stable-harness/workspace-yaml/dist/discovery.js +1 -0
  212. package/node_modules/@stable-harness/workspace-yaml/dist/documents.d.ts +16 -0
  213. package/node_modules/@stable-harness/workspace-yaml/dist/documents.js +1 -0
  214. package/node_modules/@stable-harness/workspace-yaml/dist/evaluations.d.ts +9 -0
  215. package/node_modules/@stable-harness/workspace-yaml/dist/evaluations.js +1 -0
  216. package/node_modules/@stable-harness/workspace-yaml/dist/index.d.ts +1 -0
  217. package/node_modules/@stable-harness/workspace-yaml/dist/index.js +1 -0
  218. package/node_modules/@stable-harness/workspace-yaml/dist/loader.d.ts +2 -0
  219. package/node_modules/@stable-harness/workspace-yaml/dist/loader.js +1 -0
  220. package/node_modules/@stable-harness/workspace-yaml/dist/workflows.d.ts +16 -0
  221. package/node_modules/@stable-harness/workspace-yaml/dist/workflows.js +1 -0
  222. package/node_modules/@stable-harness/workspace-yaml/package.json +16 -0
  223. package/package.json +32 -10
  224. package/packages/adapter-deepagents/package.json +4 -6
  225. package/packages/adapter-langgraph/package.json +1 -1
  226. package/packages/cli/package.json +1 -1
  227. package/packages/core/dist/quality/synthesis/fields.js +1 -1
  228. package/packages/core/dist/quality/synthesis.js +1 -1
  229. package/packages/core/package.json +1 -1
  230. package/packages/evaluation/package.json +1 -1
  231. package/packages/protocols/package.json +1 -1
  232. package/packages/tool-gateway/package.json +1 -1
  233. package/packages/workspace-yaml/package.json +1 -1
@@ -0,0 +1,38 @@
1
+ import type { WorkspaceBoundaryDiagnostic, WorkspaceBoundaryDiagnosticCode, WorkspaceBoundaryScanPolicy } from "./workspace/types.js";
2
+ export type BoundaryScanLayer = "tool" | "skill" | "subagent";
3
+ export type BoundaryScanResource = {
4
+ id: string;
5
+ description?: string;
6
+ text?: string;
7
+ tools?: string[];
8
+ skills?: string[];
9
+ subagents?: string[];
10
+ locations?: string[];
11
+ metadata?: Record<string, unknown>;
12
+ };
13
+ export type BoundaryScanFinding = {
14
+ code: WorkspaceBoundaryDiagnosticCode;
15
+ layer: BoundaryScanLayer;
16
+ resources: string[];
17
+ message: string;
18
+ locations: string[];
19
+ details: Record<string, unknown>;
20
+ };
21
+ export type BoundaryScanLayerResult = {
22
+ resources: BoundaryScanResource[];
23
+ findings: BoundaryScanFinding[];
24
+ };
25
+ export type BoundaryScanResult = {
26
+ tools: BoundaryScanLayerResult;
27
+ skills: BoundaryScanLayerResult;
28
+ subagents: BoundaryScanLayerResult;
29
+ findings: BoundaryScanFinding[];
30
+ };
31
+ export declare function scanAgentBoundary(input: {
32
+ tools?: BoundaryScanResource[];
33
+ skills?: BoundaryScanResource[];
34
+ subagents?: BoundaryScanResource[];
35
+ }): BoundaryScanResult;
36
+ export declare function checkBoundaryScanPolicy(result: BoundaryScanResult, policy: WorkspaceBoundaryScanPolicy | undefined): WorkspaceBoundaryDiagnostic[];
37
+ export declare function assertBoundaryPolicyDiagnostics(diagnostics: WorkspaceBoundaryDiagnostic[]): void;
38
+ export declare function formatBoundaryDiagnostic(diagnostic: WorkspaceBoundaryDiagnostic): string;
@@ -0,0 +1 @@
1
+ export function scanAgentBoundary(e){const n=scanLayer("tool",e.tools??[]),i=scanLayer("skill",e.skills??[]),o=scanLayer("subagent",e.subagents??[]);return{tools:n,skills:i,subagents:o,findings:[...n.findings,...i.findings,...o.findings]}}export function checkBoundaryScanPolicy(e,n){return e.findings.map(e=>({code:e.code,layer:e.layer,resources:e.resources,severity:!0===n?.failOn?.[e.code]?"error":"warning",message:e.message,locations:e.locations,details:e.details}))}export function assertBoundaryPolicyDiagnostics(e){if(0!==e.filter(e=>"error"===e.severity).length)throw new Error(`Workspace boundary scan failed:\n${e.map(formatBoundaryDiagnostic).join("\n")}`)}export function formatBoundaryDiagnostic(e){const n=e.locations.length>0?` (${e.locations.join(", ")})`:"";return`- ${e.severity} ${e.code} [${e.layer}] ${e.resources.join(", ")}: ${e.message}${n}`}function scanLayer(e,n){const i=n.flatMap(i=>[...scanSingleResource(e,i),...scanHardcodedSiblingRouting(e,i,n)]);for(let o=0;o<n.length;o+=1)for(let t=o+1;t<n.length;t+=1)i.push(...scanResourcePair(e,n[o],n[t]));return{resources:n,findings:i}}function scanSingleResource(e,n){const i=[],o=resourceText(n);return(0===(n.description??"").trim().length||meaningfulTokens(o).length<3)&&i.push(createFinding("weak-positive-boundary",e,[n],`${e} ${n.id} does not declare a clear positive responsibility boundary.`)),function hasBroadFallbackLanguage(e){return positiveSentences(e).some(e=>/\b(any|anything|all|everything|general|generic|fallback|catch[-\s]?all)\b/iu.test(e))}(o)&&!function hasLocalScopeLanguage(e){return/\b(only|specific|scope|focused|owned|responsible|specialized|local|bounded)\b/iu.test(e)}(o)&&i.push(createFinding("broad-fallback-scope",e,[n],`${e} ${n.id} uses broad fallback language without declaring local scope.`)),function hasOnlyExclusionLanguage(e){return/\b(do not|don't|except|exclude|avoid|not for|never)\b/iu.test(e)&&!/\b(handle|provide|manage|analyze|create|run|execute|inspect|summarize|search|own|owns)\b/iu.test(e)}(o)&&i.push(createFinding("weak-positive-boundary",e,[n],`${e} ${n.id} relies on exclusions without a positive capability boundary.`)),i}function scanHardcodedSiblingRouting(e,n,i){return i.filter(e=>e.id!==n.id).filter(e=>function mentionsSiblingRouting(e,n){const i=n.replace(/[.*+?^${}()|[\]\\]/gu,"\\$&"),o=new RegExp(`\\b(route|delegate|send|handoff|assign|use)\\b[^.!?\\n]{0,80}(?:^|[^\\p{L}\\p{N}_-])${i}(?:$|[^\\p{L}\\p{N}_-])`,"iu");return positiveSentences(e).some(e=>o.test(e))}(resourceText(n),e.id)).map(i=>createFinding("hardcoded-sibling-routing",e,[n,i],`${e} ${n.id} hardcodes routing to sibling ${i.id}; use loaded metadata or explicit runtime policy instead.`,{sibling:i.id}))}function scanResourcePair(e,n,i){const o=normalizeScope(n.description??""),t=normalizeScope(i.description??"");if(o&&o===t)return[createFinding("duplicate-scope",e,[n,i],`${e} resources ${n.id} and ${i.id} declare the same responsibility scope.`)];const s=function lexicalSimilarity(e,n){const i=new Set(meaningfulTokens(e)),o=new Set(meaningfulTokens(n));return 0===i.size||0===o.size?0:[...i].filter(e=>o.has(e)).length/new Set([...i,...o]).size}(resourceText(n),resourceText(i));return s>=.72?[createFinding("possible-sibling-overlap",e,[n,i],`${e} resources ${n.id} and ${i.id} have likely overlapping model-visible boundaries.`,{similarity:s})]:[]}function createFinding(e,n,i,o,t={}){return{code:e,layer:n,resources:i.map(e=>e.id),message:o,locations:[...new Set(i.flatMap(e=>e.locations??[]))],details:{...t,resourceCount:i.length}}}function resourceText(e){return[e.description,e.text,e.tools?.join(" "),e.skills?.join(" "),e.subagents?.join(" ")].filter(Boolean).join("\n")}function normalizeScope(e){return meaningfulTokens(e).join(" ")}function meaningfulTokens(n){return[...n.toLowerCase().matchAll(/[a-z0-9][a-z0-9_-]{2,}/gu)].map(e=>e[0]).filter(n=>!e.has(n))}function positiveSentences(e){return e.split(/[.!?\n]+/u).map(e=>e.trim()).filter(e=>e.length>0).filter(e=>!/\b(do not|does not|don't|not for|never|exclude|avoid)\b/iu.test(e))}const e=new Set(["and","are","for","from","into","that","the","this","with","when","workspace","agent","subagent","skill","tool"]);
@@ -0,0 +1,18 @@
1
+ export type WorkspaceEvaluation = {
2
+ id: string;
3
+ description?: string;
4
+ sourcePath?: string;
5
+ suite?: string;
6
+ cases: WorkspaceEvaluationCase[];
7
+ config?: Record<string, unknown>;
8
+ };
9
+ export type WorkspaceEvaluationCase = {
10
+ id: string;
11
+ description?: string;
12
+ agentId?: string;
13
+ workflowId?: string;
14
+ input?: unknown;
15
+ tools?: string[];
16
+ assertions?: Record<string, unknown>;
17
+ metadata?: Record<string, unknown>;
18
+ };
@@ -0,0 +1,9 @@
1
+ import type { RuntimeEmit, RuntimeStore, WorkspaceAgent } from "./types.js";
2
+ export declare function assertExecutionContract(input: {
3
+ store: RuntimeStore;
4
+ emit: RuntimeEmit;
5
+ requestId: string;
6
+ sessionId: string;
7
+ agent: WorkspaceAgent;
8
+ metadata?: Record<string, unknown>;
9
+ }): void;
@@ -0,0 +1 @@
1
+ export function assertExecutionContract(e){(function contractDisabled(e){const t=isRecord(e?.executionContract)?e.executionContract:void 0;return!1===t?.enabled})(e.metadata)||(function assertRequiredPlan(e){const t=readExecutionContract(e.agent);if(!t.requiresPlan)return;const n=readStringArray(t.planEvidenceTools);if(0===n.length)throw e.emit({type:"runtime.execution.contract.failed",requestId:e.requestId,sessionId:e.sessionId,agentId:e.agent.id,reason:"invalid_plan_contract"}),new Error("Execution contract requires plan evidence tools when requiresPlan is enabled");const r=e.store.getRun(e.requestId),o=new Set((r?.events??[]).flatMap(readEvidenceToolId));if(!n.some(e=>o.has(e)))throw e.emit({type:"runtime.execution.contract.failed",requestId:e.requestId,sessionId:e.sessionId,agentId:e.agent.id,reason:"missing_plan",missingEvidenceTools:n}),new Error(`Execution contract requires a planning checkpoint from one of: ${n.join(", ")}`)}(e),function assertRequiredEvidenceTools(e){const t=function readRequiredEvidenceTools(e){return readStringArray(readExecutionContract(e).requiredEvidenceTools)}(e.agent);if(0===t.length)return;const n=e.store.getRun(e.requestId),r=new Set((n?.events??[]).flatMap(readEvidenceToolId)),o=t.filter(e=>!r.has(e));if(0!==o.length)throw e.emit({type:"runtime.execution.contract.failed",requestId:e.requestId,sessionId:e.sessionId,agentId:e.agent.id,reason:"missing_required_evidence",missingEvidenceTools:o}),new Error(`Execution contract missing required evidence tools: ${o.join(", ")}`)}(e),function assertToolDependencies(e){const t=readExecutionContract(e.agent),n=isRecord(t.toolDependencies)?t.toolDependencies:{},r=Object.entries(n).map(([e,t])=>[e,readStringArray(t)]).filter(e=>e[1].length>0);if(0===r.length)return;const o=e.store.getRun(e.requestId),i=new Set((o?.events??[]).flatMap(readEvidenceToolId)),s=r.filter(([e])=>i.has(e)).flatMap(([e,t])=>t.filter(e=>!i.has(e)).map(t=>`${e} requires ${t}`));if(0!==s.length)throw e.emit({type:"runtime.execution.contract.failed",requestId:e.requestId,sessionId:e.sessionId,agentId:e.agent.id,reason:"missing_tool_dependency",missingEvidenceTools:s}),new Error(`Execution contract missing required tool dependencies: ${s.join(", ")}`)}(e))}function readExecutionContract(e){return isRecord(e.config.executionContract)?e.config.executionContract:{}}function readEvidenceToolId(e){return"runtime.tool.direct.completed"===e.type?[e.toolId]:"runtime.adapter.event"===e.type&&isRecord(e.event)?"agent.tool.result"!==e.event.phase||"string"!=typeof e.event.toolId?[]:function isSuccessfulEvidenceEvent(e){const t=function readString(e){return"string"==typeof e&&e.length>0?e:void 0}(e.controlStatus)??function readOutputStatus(e){if("string"!=typeof e)return;const t=function parseJsonRecord(e){try{const t=JSON.parse(e);return isRecord(t)?t:void 0}catch{return}}(e);return"string"==typeof t?.status?t.status:e.match(/^Status:\s*([A-Za-z0-9_-]+)/imu)?.[1]}(e.output);return!t||/^(?:completed|success|ok|recorded)$/iu.test(t)}(e.event)?[e.event.toolId]:[]:[]}function isRecord(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}function readStringArray(e){return Array.isArray(e)?e.filter(e=>"string"==typeof e&&e.length>0):[]}
@@ -0,0 +1,20 @@
1
+ export * from "./runtime/persistence/artifacts.js";
2
+ export type { ApprovalRequest, ApprovalRequestStatus } from "@stable-harness/governance";
3
+ export * from "./boundary-scan.js";
4
+ export * from "./execution-contract.js";
5
+ export * from "./recovery/tool-call.js";
6
+ export * from "./runtime/persistence/inspection.js";
7
+ export { createWorkspaceSandboxPolicy } from "./runtime/governance/sandbox.js";
8
+ export * from "./memory-plugins.js";
9
+ export * from "./runtime/persistence/queue.js";
10
+ export * from "./runtime.js";
11
+ export * from "./runtime/selection-repair.js";
12
+ export * from "./runtime/tool-failure.js";
13
+ export * from "./runtime/persistence/stores.js";
14
+ export * from "./trace.js";
15
+ export * from "./types.js";
16
+ export * from "./workspace/tool-quality.js";
17
+ export * from "./evaluations/index.js";
18
+ export * from "./quality/index.js";
19
+ export * from "./spec-driven/index.js";
20
+ export * from "./workflows/index.js";
@@ -0,0 +1 @@
1
+ export*from"./runtime/persistence/artifacts.js";export*from"./boundary-scan.js";export*from"./execution-contract.js";export*from"./recovery/tool-call.js";export*from"./runtime/persistence/inspection.js";export{createWorkspaceSandboxPolicy}from"./runtime/governance/sandbox.js";export*from"./memory-plugins.js";export*from"./runtime/persistence/queue.js";export*from"./runtime.js";export*from"./runtime/selection-repair.js";export*from"./runtime/tool-failure.js";export*from"./runtime/persistence/stores.js";export*from"./trace.js";export*from"./types.js";export*from"./workspace/tool-quality.js";export*from"./evaluations/index.js";export*from"./quality/index.js";export*from"./spec-driven/index.js";export*from"./workflows/index.js";
@@ -0,0 +1,42 @@
1
+ import type { MemoryMaintenanceOperation, MemoryProvider } from "@stable-harness/memory";
2
+ import type { ApprovalQueue, SkillCandidateStore } from "@stable-harness/governance";
3
+ import type { CompiledWorkspace, RuntimeEmit, WorkspaceAgent } from "../types.js";
4
+ export type MemoryMaintenanceTarget = {
5
+ name: string;
6
+ run(input: MemoryMaintenanceTargetInput): Promise<MemoryMaintenanceResult>;
7
+ };
8
+ export type MemoryMaintenanceTargetInput = {
9
+ emit: RuntimeEmit;
10
+ requestId: string;
11
+ sessionId: string;
12
+ agent: WorkspaceAgent;
13
+ workspace: CompiledWorkspace;
14
+ prompt: string;
15
+ };
16
+ export type MemoryMaintenanceResult = {
17
+ operations?: MemoryMaintenanceOperation[];
18
+ metadata?: Record<string, unknown>;
19
+ };
20
+ export type MemoryMaintenanceDaemon = {
21
+ runOnce(input?: Partial<Pick<MemoryMaintenanceTargetInput, "requestId" | "sessionId" | "agent">>): Promise<MemoryMaintenanceResult[]>;
22
+ start(): void;
23
+ stop(): void;
24
+ };
25
+ export declare function createMemoryMaintenanceDaemon(input: {
26
+ workspace: CompiledWorkspace;
27
+ emit?: RuntimeEmit;
28
+ targets: MemoryMaintenanceTarget[];
29
+ intervalMs?: number;
30
+ prompt?: string;
31
+ defaultAgentId?: string;
32
+ }): MemoryMaintenanceDaemon;
33
+ export declare function createLangMemMaintenanceTarget(input: {
34
+ providers: MemoryProvider[] | undefined;
35
+ limit?: number;
36
+ }): MemoryMaintenanceTarget;
37
+ export declare function createSkillCandidateMinerTarget(input: {
38
+ providers: MemoryProvider[] | undefined;
39
+ store: SkillCandidateStore;
40
+ approvals?: ApprovalQueue;
41
+ minEvidenceCount?: number;
42
+ }): MemoryMaintenanceTarget;
@@ -0,0 +1 @@
1
+ import{formatError as e,readRecord as t,readWorkspaceId as n,resolveEnabledMemories as a,resolveMemoryProvider as r,resolvePluginNamespace as s}from"./shared.js";export function createMemoryMaintenanceDaemon(e){let t;const n=e.emit??(()=>{});return{async runOnce(t={}){const a=t.agent??function resolveMaintenanceAgent(e,t){const n=e.agents.get(t??e.runtime.defaultAgentId);if(!n)throw new Error("Memory maintenance requires a configured default agent");return n}(e.workspace,e.defaultAgentId),r={emit:n,requestId:t.requestId??`memory-maintenance-${Date.now()}`,sessionId:t.sessionId??"memory-maintenance",agent:a,workspace:e.workspace,prompt:e.prompt??defaultMaintenancePrompt(e.workspace)},s=[];for(const t of e.targets)s.push(await runMaintenanceTarget(r,t));return s},start(){e.intervalMs&&!t&&(t=setInterval(()=>{this.runOnce()},e.intervalMs))},stop(){t&&(clearInterval(t),t=void 0)}}}export function createLangMemMaintenanceTarget(e){return{name:"LangMem",async run(t){const n=[];for(const o of a(t.workspace,"write")){const a=r(e.providers??[],o.provider);if(!a)continue;const i=s(t.workspace,t.agent,{input:"",sessionId:t.sessionId},o),c=mergeMemoryRecords(await a.search({namespace:i,query:t.prompt,limit:e.limit??100}),await a.search({namespace:i,query:"",limit:e.limit??100}));n.push(...await a.consolidate({records:c}))}return{operations:n}}}}export function createSkillCandidateMinerTarget(e){return{name:"skillCandidateMiner",async run(t){const n=await async function collectMaintenanceRecords(e,t){const n=[];for(const o of a(t.workspace,"all")){const a=r(e??[],o.provider);if(!a)continue;const i=s(t.workspace,t.agent,{input:"",sessionId:t.sessionId},o);n.push(...mergeMemoryRecords(await a.search({namespace:i,query:t.prompt,limit:100}),await a.search({namespace:i,query:"",limit:100})))}return mergeMemoryRecords(n,[])}(e.providers,t),o=function groupSkillCandidateRecords(e){const t=new Map;for(const n of e){const e=readSkillCandidateName(n);e&&t.set(e,[...t.get(e)??[],n])}return t}(n),i=[];for(const[n,a]of o){if(a.length<(e.minEvidenceCount??3))continue;const r=await e.store.upsert(createSkillCandidateInput(t.workspace,n,a));i.push(r),t.emit({type:"runtime.skill.candidate.created",requestId:t.requestId,sessionId:t.sessionId,agentId:t.agent.id,candidateId:r.id,name:r.name,confidence:r.confidence,evidenceCount:r.evidenceCount,status:r.status,proposedPath:r.proposedPath}),await(e.approvals?.create({kind:"skill_candidate",reason:`Review mined skill candidate ${r.name}`,requestId:t.requestId,sessionId:t.sessionId,agentId:t.agent.id,subject:{candidate:r}}))}return{operations:[],metadata:{candidateCount:i.length}}}}}async function runMaintenanceTarget(t,n){t.emit({type:"runtime.memory.maintenance.started",requestId:t.requestId,sessionId:t.sessionId,agentId:t.agent.id,target:n.name});try{const e=await n.run(t);return t.emit({type:"runtime.memory.maintenance.completed",requestId:t.requestId,sessionId:t.sessionId,agentId:t.agent.id,target:n.name,operationCount:e.operations?.length??0}),e}catch(a){return t.emit({type:"runtime.memory.maintenance.failed",requestId:t.requestId,sessionId:t.sessionId,agentId:t.agent.id,target:n.name,error:e(a)}),{operations:[],metadata:{error:e(a)}}}}function mergeMemoryRecords(e,t){const n=new Map;for(const a of[...e,...t])n.set(a.id,a);return[...n.values()]}function readSkillCandidateName(e){const n=t(e.metadata?.skillCandidate),a=t(t(e.metadata?.requestMetadata)?.skillCandidate),r=n?.name??a?.name;return"string"==typeof r&&r.trim()?function slugify(e){return e.toLowerCase().replace(/[^a-z0-9]+/gu,"-").replace(/^-+|-+$/gu,"")}(r):void 0}function createSkillCandidateInput(e,t,a){const r=function titleFromName(e){return e.split("-").filter(Boolean).map(e=>`${e[0]?.toUpperCase()??""}${e.slice(1)}`).join(" ")}(t);return{workspaceId:n(e),name:t,status:"review_required",confidence:Math.min(.95,.55+.1*a.length),proposedPath:`resources/skills/${t}/SKILL.md`,title:r,summary:`Repeated stable workflow mined from ${a.length} memory records.`,draftMarkdown:renderSkillDraft(r,a),evidence:a.map(e=>({evidenceType:"memory_record",evidenceRef:e.id,summary:e.summary??e.content.slice(0,160),weight:e.confidence}))}}function renderSkillDraft(e,t){return[`# ${e}`,"","## Purpose","","Apply this stable workflow when the task matches the evidence.","","## Evidence","",t.map(e=>`- ${e.summary??e.content}`).join("\n")].join("\n")}function defaultMaintenancePrompt(e){const n=t(e.runtime.memory?.maintenance);return"string"==typeof n?.prompt?n.prompt:"durable preferences workspace facts reusable procedures prior corrections stale duplicated contradicted memories"}
@@ -0,0 +1,8 @@
1
+ import type { MemoryProvider } from "@stable-harness/memory";
2
+ import type { CompiledWorkspace, RuntimeRequest, WorkspaceAgent, WorkspaceMemory } from "../types.js";
3
+ export declare function resolveEnabledMemories(workspace: CompiledWorkspace, phase?: "all" | "recall" | "write"): WorkspaceMemory[];
4
+ export declare function resolvePluginNamespace(workspace: CompiledWorkspace, agent: WorkspaceAgent, request: RuntimeRequest, memory: WorkspaceMemory): string;
5
+ export declare function resolveMemoryProvider(providers: MemoryProvider[], configuredProvider: string): MemoryProvider | undefined;
6
+ export declare function readRecord(value: unknown): Record<string, unknown> | undefined;
7
+ export declare function readWorkspaceId(workspace: CompiledWorkspace): string;
8
+ export declare function formatError(error: unknown): string;
@@ -0,0 +1 @@
1
+ export function resolveEnabledMemories(e,r="all"){const o=e.runtime.memory??{};if(!function isMemoryPhaseEnabled(e,r){return!1!==e.enabled&&("recall"!==r||!1!==e.recall&&!1!==e.read&&!1!==readMemoryFlag(e,"LangMem","read"))&&("write"!==r||!1!==e.write&&!1!==readMemoryFlag(e,"LangMem","write"))}(o,r))return[];const n=Array.isArray(o.refs)?o.refs.filter(e=>"string"==typeof e):[];return(n.length>0?n:[...e.memories.keys()]).map(r=>e.memories.get(r)).filter(e=>Boolean(e?.enabled))}export function resolvePluginNamespace(e,r,o,n){const t=readWorkspaceId(e),a=n.profile??n.id;return"agent"===a?`${t}:agent:${r.id}:${n.id}`:"user"===a?`${t}:user:${function readUserId(e){return e.metadata?.userId??"local"}(o)}:${n.id}`:"session"===a?`${t}:session:${o.sessionId??"default"}:${n.id}`:`${t}:${a}:${n.id}`}export function resolveMemoryProvider(e,r){return e.find(e=>e.name===r||e.name===`${r}-service`)}export function readRecord(e){return"object"!=typeof e||null===e||Array.isArray(e)?void 0:e}export function readWorkspaceId(e){return e.runtime.workspaceId??e.runtime.profile??e.root}export function formatError(e){return e instanceof Error?e.message:String(e)}function readMemoryFlag(e,r,o){const n=readRecord(e[r])??readRecord(e[r.toLowerCase()]);return"boolean"==typeof n?.[o]?n[o]:void 0}
@@ -0,0 +1,25 @@
1
+ import type { MemoryProvider, MemoryRecord } from "@stable-harness/memory";
2
+ import type { CompiledWorkspace, RuntimeEmit, RuntimeOutput, RuntimeRequest, WorkspaceAgent } from "./types.js";
3
+ export { resolveEnabledMemories, resolvePluginNamespace, } from "./memory-plugins/shared.js";
4
+ export type { MemoryMaintenanceDaemon, MemoryMaintenanceResult, MemoryMaintenanceTarget, MemoryMaintenanceTargetInput, } from "./memory-plugins/maintenance.js";
5
+ export { createLangMemMaintenanceTarget, createMemoryMaintenanceDaemon, createSkillCandidateMinerTarget, } from "./memory-plugins/maintenance.js";
6
+ export declare function runMemoryPlugins(input: {
7
+ providers: MemoryProvider[] | undefined;
8
+ emit: RuntimeEmit;
9
+ request: RuntimeRequest;
10
+ requestId: string;
11
+ sessionId: string;
12
+ agent: WorkspaceAgent;
13
+ workspace: CompiledWorkspace;
14
+ result: RuntimeOutput;
15
+ }): Promise<void>;
16
+ export declare function recallMemoryPlugins(input: {
17
+ providers: MemoryProvider[] | undefined;
18
+ request: RuntimeRequest;
19
+ agent: WorkspaceAgent;
20
+ workspace: CompiledWorkspace;
21
+ }): Promise<Array<{
22
+ namespace: string;
23
+ records: MemoryRecord[];
24
+ context: string;
25
+ }>>;
@@ -0,0 +1 @@
1
+ import{formatError as e,readRecord as r,readWorkspaceId as t,resolveEnabledMemories as n,resolveMemoryProvider as o,resolvePluginNamespace as a}from"./memory-plugins/shared.js";export{resolveEnabledMemories,resolvePluginNamespace}from"./memory-plugins/shared.js";export{createLangMemMaintenanceTarget,createMemoryMaintenanceDaemon,createSkillCandidateMinerTarget}from"./memory-plugins/maintenance.js";export async function runMemoryPlugins(e){const r=n(e.workspace,"write");if(e.providers?.length&&0!==r.length&&!1!==e.request.metadata?.memoryWrite)for(const t of r)await runMemoryPlugin(e,t)}export async function recallMemoryPlugins(e){const r=n(e.workspace,"recall");if(!e.providers?.length||0===r.length)return[];const t=await Promise.all(r.map(async r=>{try{return await async function recallMemoryPlugin(e,r){const t=o(e.providers??[],r.provider);if(!t)return;const n=a(e.workspace,e.agent,e.request,r),s=await t.search({namespace:n,query:buildRecallQuery(e),limit:readRecallLimit(e.workspace)});return{namespace:n,records:s,context:formatRecallContext(e.workspace,s)}}(e,r)}catch{return}}));return t.filter(e=>Boolean(e?.context))}async function runMemoryPlugin(r,t){const n=o(r.providers??[],t.provider);if(!n)return;const s=a(r.workspace,r.agent,r.request,t);r.emit({type:"runtime.memory.plugin.started",requestId:r.requestId,sessionId:r.sessionId,agentId:r.agent.id,memoryId:t.id,provider:n.name,namespace:s});try{const e=await n.propose(function createPluginProposeInput(e,r,t){return{namespace:t,content:[`User input:\n${e.request.input}`,`Agent output:\n${e.result.text}`].join("\n\n"),sourceType:"runtime-run",sourceRef:e.requestId,metadata:{memoryId:r.id,provider:r.provider,profile:r.profile,mode:r.mode,prompts:r.prompts,workspaceRoot:e.workspace.root,agentId:e.agent.id,sessionId:e.sessionId,requestMetadata:e.request.metadata}}}(r,t,s));r.emit({type:"runtime.memory.plugin.completed",requestId:r.requestId,sessionId:r.sessionId,agentId:r.agent.id,memoryId:t.id,provider:n.name,namespace:s,candidateCount:e.length})}catch(o){r.emit({type:"runtime.memory.plugin.failed",requestId:r.requestId,sessionId:r.sessionId,agentId:r.agent.id,memoryId:t.id,provider:n.name,namespace:s,error:e(o)})}}function buildRecallQuery(e){const r=[`task: ${e.request.input}`,`workspace: ${t(e.workspace)}`,`agent: ${e.agent.id}`,"memory_needed: durable preferences, workspace facts, reusable procedures, prior corrections"],n=function readRecentContext(e){return"string"==typeof e?.recentContext?e.recentContext.slice(0,3e3):Array.isArray(e?.recentTurns)?e.recentTurns.filter(e=>"string"==typeof e).slice(-6).join("\n").slice(0,3e3):void 0}(e.request.metadata);return n?[...r,`recent_context: ${n}`].join("\n"):r.join("\n")}function readRecallLimit(e){const t=r(e.runtime.memory?.LangMem),n=r(t?.recall),o=n?.topK??n?.limit;return"number"==typeof o&&Number.isFinite(o)?o:10}function formatRecallContext(e,t){const n=function readRecallContextLimits(e){const t=r(e.runtime.memory?.LangMem),n=r(t?.recall);return{maxContextChars:readPositiveNumber(n?.maxContextChars)??4e3,maxRecordChars:readPositiveNumber(n?.maxRecordChars)??1e3}}(e),o=[];let a=n.maxContextChars;for(const e of t){if(a<=0)break;const r=truncateText(formatRecallRecord(e),Math.min(n.maxRecordChars,a));r.trim()&&(o.push(r),a-=r.length+1)}return o.join("\n")}function formatRecallRecord(e){return`- ${e.summary??e.content}\n ${e.content}`}function readPositiveNumber(e){return"number"==typeof e&&Number.isFinite(e)&&e>0?Math.floor(e):void 0}function truncateText(e,r){return e.length>r?`${e.slice(0,Math.max(0,r-13))}\n [truncated]`:e}
@@ -0,0 +1,11 @@
1
+ import type { RuntimeEvent } from "../types.js";
2
+ export declare function hasPlanningEvidence(events: RuntimeEvent[]): boolean;
3
+ export declare function successfulEvidenceToolIds(events: RuntimeEvent[]): string[];
4
+ export declare function successfulEvidenceOutputs(events: RuntimeEvent[]): string[];
5
+ export type SuccessfulEvidenceItem = {
6
+ source: string;
7
+ output: string;
8
+ };
9
+ export declare function successfulEvidenceItems(events: RuntimeEvent[]): SuccessfulEvidenceItem[];
10
+ export declare function controlBlockers(events: RuntimeEvent[]): string[];
11
+ export declare function controlGaps(events: RuntimeEvent[]): string[];
@@ -0,0 +1 @@
1
+ export function hasPlanningEvidence(t){return t.some(t=>{const e=readAdapterEvent(t);return!!e&&("plan"===e.traceType||String(e.traceLabel??"").startsWith("plan.")||"write_todos"===e.toolId&&String(e.phase??"").startsWith("agent.tool."))})}export function successfulEvidenceToolIds(t){const e=t.flatMap(t=>{if("runtime.tool.direct.completed"===t.type)return[t.toolId];const e=readAdapterEvent(t);return e&&"agent.tool.result"===e.phase&&"string"==typeof e.toolId&&isSuccessfulEvidenceEvent(e)?[e.toolId]:[]});return[...new Set(e)]}export function successfulEvidenceOutputs(t){return successfulEvidenceItems(t).map(t=>t.output)}export function successfulEvidenceItems(t){return t.flatMap(t=>{if("runtime.tool.direct.completed"===t.type)return stringifyEvidence(t.output).map(e=>({source:t.toolId,output:e}));const e=readAdapterEvent(t);return e&&"agent.tool.result"===e.phase&&"string"==typeof e.toolId?!isSuccessfulEvidenceEvent(e)||function isPlanningTool(t){return/^(?:write_todos|read_todos)$/u.test(t)}(e.toolId)?[]:stringifyEvidence(e.evidenceOutput??e.output).filter(t=>function isUsableEvidenceOutput(t,e){return"task"!==t||!function looksLikeUnexecutedToolIntent(t){const e=t.trim();return!(e.length>4e3)&&[/\b(?:I need to|I will|I'll|I am going to|I'm going to|Let me)\s+(?:call|use|run|invoke|get|fetch|check)\b[\s\S]{0,1200}\b(?:tool|function|system_time|web_search|url_text_fetch|task)\b/iu,/(?:我需要|我要|我会|我将|让我|我来|接下来我(?:会|将)?)\s*(?:先)?(?:调用|使用|运行|执行|检查|获取|查看)\b[\s\S]{0,1200}\b(?:工具|函数|system_time|web_search|url_text_fetch|task)\b/iu,/```(?:json)?\s*(?:system_time|web_search|url_text_fetch|task)\s*```/iu].some(t=>t.test(e))}(e)&&!function looksLikeDelegatedCommentary(t){const e=t.trim();return!(e.length>8e3)&&[/(?:这篇文章|this article)[\s\S]{0,1200}(?:我认为|我认同|打动我|值得深入探讨|特别认同|what I find|I think|I agree)/iu,/(?:你还有什么|还想深入探讨|would you like|do you want).{0,120}[??]\s*$/iu].some(t=>t.test(e))}(e)}(e.toolId,t)).map(t=>({source:e.toolId,output:t})):[]})}export function controlBlockers(t){const e=function successfulEventIndexesBySource(t){const e=new Map;return t.forEach((t,n)=>{const o=function successfulEventSource(t){if("runtime.tool.direct.completed"===t.type)return t.toolId;const e=readAdapterEvent(t);return e&&"agent.tool.result"===e.phase&&"string"==typeof e.toolId&&isSuccessfulEvidenceEvent(e)?e.toolId:void 0}(t);o&&e.set(o,[...e.get(o)??[],n])}),e}(t);return t.flatMap((t,n)=>{const o=readAdapterEvent(t),r=readString(o?.controlStatus)??readOutputStatus(o?.output),s=readString(o?.toolId)??"tool";return r&&isBlockerStatus(r)?isResolvedByLaterCompletion(r)&&function completedAfter(t,e,n){return(t.get(e)??[]).some(t=>t>n)}(e,s,n)?[]:[`${s}:${r}`]:[]})}export function controlGaps(t){const e=new Set(successfulEvidenceItems(t).map(t=>t.source));return t.flatMap(t=>{const n=readAdapterEvent(t),o=readString(n?.controlStatus)??readOutputStatus(n?.output),r=readString(n?.toolId)??"tool";return o&&isGapStatus(o)?e.has(r)&&isResolvedByLaterCompletion(o)?[]:[`${r}:${o}`]:[]})}function stringifyEvidence(t){return"string"==typeof t?t.trim()?[t]:[]:null==t?[]:[JSON.stringify(t)]}function readAdapterEvent(t){return"runtime.adapter.event"===t.type&&isRecord(t.event)?t.event:void 0}function isSuccessfulEvidenceEvent(t){const e=readString(t.controlStatus)??readOutputStatus(t.output);return!e||/^(?:completed|success|ok|recorded)$/iu.test(e)}function isBlockerStatus(t){return/^(?:blocked|approval_required|schema_repair_failed|tool_argument_error|invalid_input)$/iu.test(t)}function isGapStatus(t){return/^(?:dependency_required|plan_required|repeated_tool_call_limit|duplicate_tool_call)$/iu.test(t)}function isResolvedByLaterCompletion(t){return isGapStatus(t)||isBlockerStatus(t)}function readOutputStatus(t){if("string"!=typeof t)return;const e=function parseJsonRecord(t){try{const e=JSON.parse(t);return isRecord(e)?e:void 0}catch{return}}(t);return"string"==typeof e?.status?e.status:t.match(/^Status:\s*([A-Za-z0-9_-]+)/imu)?.[1]}function isRecord(t){return"object"==typeof t&&null!==t&&!Array.isArray(t)}function readString(t){return"string"==typeof t&&t.trim()?t:void 0}
@@ -0,0 +1,2 @@
1
+ import type { QualityPolicy, QualityReviewInput, QualityReviewResult } from "./types.js";
2
+ export declare function reviewExecutionEvidence(input: QualityReviewInput, policy: QualityPolicy): QualityReviewResult;
@@ -0,0 +1 @@
1
+ import{controlBlockers as e,successfulEvidenceOutputs as n,successfulEvidenceToolIds as t}from"./event-evidence.js";const r=/(?<![\w.])(?:\d{1,3}(?:,\d{3})+|\d+)(?:\.\d+)?[%kKmMbBtTxX]?(?!\w)/gu;export function reviewExecutionEvidence(e,n){if(!n.enabled||!n.executionReview.enabled)return{verdict:"pass",issues:[]};const t=[...blockerIssues(e,n),...emptyFinalIssues(e,n),...toolEvidenceIssues(e,n),...ungroundedNumberIssues(e,n)];return 0===t.length?{verdict:"pass",issues:[]}:{verdict:t.some(e=>!e.recoverable)?"blocked":"continue_react",issues:t}}function ungroundedNumberIssues(e,t){if(!t.executionReview.rejectUngroundedNumbers||!e.output?.text.trim())return[];const r=numberSet(n(e.events).join("\n"));if(0===r.size)return[];const s=[...numberSet(e.output.text)].filter(e=>!function isSupportedNumber(e,n){if(n.has(e))return!0;const t=Number.parseFloat(e);if(!Number.isFinite(t))return!1;for(const e of n){const n=Number.parseFloat(e);if(Number.isFinite(n)&&Math.abs(n-t)<=roundingTolerance(t))return!0}return!1}(e,r));return 0===s.length?[]:[{code:"ungrounded_numeric_claim",message:`Final answer contains numeric claims not found in successful tool evidence: ${s.slice(0,12).join(", ")}`,recoverable:!1}]}function numberSet(e){const n=new Set;for(const t of e.matchAll(r)){const e=normalizeNumber(t[0]);e&&n.add(e)}return n}function normalizeNumber(e){const n=e.replace(/,/gu,"").replace(/^\+/u,"").replace(/[%kKmMbBtTxX]$/u,"").trim();if(n){if(/^\d+$/u.test(n)){const e=Number.parseInt(n,10);if(e>=1&&e<=20)return;return String(e)}return/^\d+\.\d+$/u.test(n)?n.replace(/0+$/u,"").replace(/\.$/u,""):void 0}}function roundingTolerance(e){return Math.abs(e)>=1e3?1:Math.abs(e)>=100?.1:Math.abs(e)>=10?.05:.005}function blockerIssues(n,t){return t.executionReview.stopOnBlocker?e(n.events).map(e=>({code:"control_blocker",message:`Execution produced a control blocker: ${e}`,recoverable:!1})):[]}function emptyFinalIssues(e,n){return!n.executionReview.rejectEmptyFinal||e.output?.text.trim()?[]:[{code:"empty_final_answer",message:"The final answer is empty.",recoverable:!0}]}function toolEvidenceIssues(e,n){return!n.executionReview.requireToolEvidence||t(e.events).length>0?[]:[{code:"missing_tool_evidence",message:"No successful tool or delegated-task evidence was observed.",recoverable:!0}]}
@@ -0,0 +1,9 @@
1
+ export * from "./types.js";
2
+ export * from "./profile.js";
3
+ export * from "./planning-review.js";
4
+ export * from "./execution-review.js";
5
+ export * from "./event-evidence.js";
6
+ export * from "./llm-review.js";
7
+ export * from "./recovery-policy.js";
8
+ export * from "./synthesis.js";
9
+ export * from "./runtime.js";
@@ -0,0 +1 @@
1
+ export*from"./types.js";export*from"./profile.js";export*from"./planning-review.js";export*from"./execution-review.js";export*from"./event-evidence.js";export*from"./llm-review.js";export*from"./recovery-policy.js";export*from"./synthesis.js";export*from"./runtime.js";
@@ -0,0 +1,7 @@
1
+ import type { QualityPolicy, QualityReviewInput, QualityReviewModel, QualityReviewResult } from "./types.js";
2
+ export declare function reviewWithLlm(input: {
3
+ phase: "planning" | "execution";
4
+ review: QualityReviewInput;
5
+ policy: QualityPolicy;
6
+ model?: QualityReviewModel;
7
+ }): Promise<QualityReviewResult | undefined>;
@@ -0,0 +1 @@
1
+ export async function reviewWithLlm(e){if(!e.model||"llm"!==e.policy.reviewer?.mode)return;const t="planning"===e.phase?e.policy.reviewer.planningPrompt??function defaultPlanningPrompt(){return["You are Stable Harness planning quality review.","Review only generic agent-work quality: goal coverage, executable steps, and declared inventory fit.",'Do not invent a domain workflow. Return only JSON: {"verdict":"pass|revise_plan|blocked","issues":[{"code":"...","message":"...","recoverable":true}]}'].join("\n")}():e.policy.reviewer.executionPrompt??function defaultExecutionPrompt(){return["You are Stable Harness execution evidence review.","Review only whether execution evidence supports the final answer and whether unresolved blockers or gaps remain.",'Do not answer the user request. Return only JSON: {"verdict":"pass|continue_react|blocked","issues":[{"code":"...","message":"...","recoverable":true}]}'].join("\n")}();return function parseReviewResult(e){const t=function readResponseText(e){if("string"==typeof e)return e;if(!isRecord(e))return;if("string"==typeof e.content)return e.content;const t=isRecord(e.message)?e.message:void 0;return"string"==typeof t?.content?t.content:void 0}(e),n="string"==typeof t?function parseJsonRecord(e){const t=e.trim().replace(/^```(?:json)?\s*/iu,"").replace(/\s*```$/u,"");try{const e=JSON.parse(t);return isRecord(e)?e:void 0}catch{return}}(t):isRecord(e)?e:void 0,r=function readVerdict(e){return"pass"===e||"revise_plan"===e||"continue_react"===e||"blocked"===e?e:void 0}(n?.verdict);if(n&&r)return{verdict:r,issues:readIssues(n.issues)}}(await e.model.invoke([{role:"system",content:t},{role:"user",content:JSON.stringify(buildReviewContext(e.review),null,2)}]))}function buildReviewContext(e){return{userRequest:e.request.input,agent:{id:e.agent.id,tools:e.agent.tools,skills:e.agent.skills??[],subagents:e.agent.subagents},finalOutput:e.output?.text,events:e.events.slice(-30).map(projectEvent)}}function projectEvent(e){return"runtime.adapter.event"===e.type?{type:e.type,event:e.event}:{...e}}function readIssues(e){return Array.isArray(e)?e.flatMap(e=>isRecord(e)&&"string"==typeof e.code&&"string"==typeof e.message?[{code:e.code,message:e.message,recoverable:!1!==e.recoverable}]:[]):[]}function isRecord(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}
@@ -0,0 +1,2 @@
1
+ import type { QualityPolicy, QualityReviewInput, QualityReviewResult } from "./types.js";
2
+ export declare function reviewPlanningEvidence(input: QualityReviewInput, policy: QualityPolicy): QualityReviewResult;
@@ -0,0 +1 @@
1
+ import{hasPlanningEvidence as e}from"./event-evidence.js";export function reviewPlanningEvidence(n,s){return s.enabled&&s.planningReview.enabled&&s.planningReview.requirePlan?e(n.events)?{verdict:"pass",issues:[]}:{verdict:"revise_plan",issues:[{code:"missing_plan_evidence",message:"No upstream planning evidence was observed before the agent produced a result.",recoverable:!0}]}:{verdict:"pass",issues:[]}}
@@ -0,0 +1,3 @@
1
+ import type { WorkspaceAgent, WorkspaceRuntimePolicy } from "../types.js";
2
+ import type { QualityPolicy } from "./types.js";
3
+ export declare function resolveQualityPolicy(runtime: WorkspaceRuntimePolicy, agent: WorkspaceAgent): QualityPolicy;
@@ -0,0 +1 @@
1
+ export function resolveQualityPolicy(e,n){const r=n.config.quality??e.quality,i=function readProfile(e){const n="string"==typeof e?e:isRecord(e)?e.profile:void 0;return"fast"===n||"balanced"===n||"strict"===n?n:"off"}(r),o=function profileDefaults(e,n){const r=n.tools.length>0||n.subagents.length>0||(n.skills?.length??0)>0;return"off"===e?function disabledPolicy(e){return{enabled:!1,profile:e,reviewer:{mode:"deterministic"},planningReview:{enabled:!1,requirePlan:!1},executionReview:{enabled:!1,requireToolEvidence:!1,rejectEmptyFinal:!1,stopOnBlocker:!1,rejectUngroundedNumbers:!1},synthesis:{enabled:!1,mode:"evidence_only",maxEvidenceItems:5},recovery:{enabled:!1,maxLoops:0}}}(e):{enabled:!0,profile:e,planningReview:{enabled:"fast"!==e,requirePlan:"fast"!==e&&r},executionReview:{enabled:!0,requireToolEvidence:"strict"===e&&r,rejectEmptyFinal:!0,stopOnBlocker:!0,rejectUngroundedNumbers:"strict"===e},synthesis:{enabled:!1,mode:"evidence_only",maxEvidenceItems:5},recovery:{enabled:"fast"!==e,maxLoops:"strict"===e?3:2}}}(i,n),t=isRecord(r)?r:{},a=function readReviewer(e){const n=isRecord(e.reviewer)?e.reviewer:e,r="llm"===n.mode||"string"==typeof n.modelRef?"llm":"deterministic",i=isRecord(n.prompts)?n.prompts:{},o=readString(n.modelRef);return{mode:r,...o?{modelRef:o}:{},...readString(n.planningPrompt)??readString(i.planning)?{planningPrompt:readString(n.planningPrompt)??readString(i.planning)}:{},...readString(n.executionPrompt)??readString(i.execution)?{executionPrompt:readString(n.executionPrompt)??readString(i.execution)}:{}}}(t);return{enabled:o.enabled,profile:i,...a?{reviewer:a}:{},planningReview:{enabled:readBoolean(t.planningReview,"enabled")??o.planningReview.enabled,requirePlan:readBoolean(t.planningReview,"requirePlan")??o.planningReview.requirePlan},executionReview:{enabled:readBoolean(t.executionReview,"enabled")??o.executionReview.enabled,requireToolEvidence:readBoolean(t.executionReview,"requireToolEvidence")??o.executionReview.requireToolEvidence,rejectEmptyFinal:readBoolean(t.executionReview,"rejectEmptyFinal")??o.executionReview.rejectEmptyFinal,stopOnBlocker:readBoolean(t.executionReview,"stopOnBlocker")??o.executionReview.stopOnBlocker,rejectUngroundedNumbers:readBoolean(t.executionReview,"rejectUngroundedNumbers")??o.executionReview.rejectUngroundedNumbers},synthesis:{enabled:readBoolean(t.synthesis,"enabled")??o.synthesis.enabled,mode:(d=t.synthesis,("evidence_only"===(isRecord(d)?d:{}).mode?"evidence_only":void 0)??o.synthesis.mode),maxEvidenceItems:readPositiveInteger(t.synthesis,"maxEvidenceItems")??o.synthesis.maxEvidenceItems},recovery:{enabled:readBoolean(t.recovery,"enabled")??o.recovery.enabled,maxLoops:readPositiveInteger(t.recovery,"maxLoops")??o.recovery.maxLoops}};var d}function readString(e){return"string"==typeof e&&e.trim()?e.trim():void 0}function readBoolean(e,n){const r=isRecord(e)?e:{};return"boolean"==typeof r[n]?r[n]:void 0}function readPositiveInteger(e,n){const r=(isRecord(e)?e:{})[n];return"number"==typeof r&&Number.isInteger(r)&&r>0?r:void 0}function isRecord(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}
@@ -0,0 +1,11 @@
1
+ import type { RuntimeRequest } from "../types.js";
2
+ import type { QualityPolicy, QualityReviewResult } from "./types.js";
3
+ export declare function buildQualityRecoveryRequest(input: {
4
+ request: RuntimeRequest;
5
+ result: QualityReviewResult;
6
+ phase: "planning" | "execution";
7
+ policy: QualityPolicy;
8
+ availableToolIds: string[];
9
+ availableSubagentIds: string[];
10
+ observedEvidence?: string[];
11
+ }): RuntimeRequest | undefined;
@@ -0,0 +1 @@
1
+ export function buildQualityRecoveryRequest(e){if(!e.policy.recovery.enabled||"pass"===e.result.verdict||"blocked"===e.result.verdict)return;const n="planning"===e.phase?function planningLines(e){return["Stable runtime quality review: the previous plan was not ready to execute.",...issueLines(e.result),inventoryLine("Available configured tools",e.availableToolIds),inventoryLine("Available configured subagents",e.availableSubagentIds),"Revise the plan using only the declared inventory, then continue through the backend's normal planning and tool-calling flow.","Do not invent tools, subagents, or a separate planning language."].filter(e=>e.length>0)}(e):function executionLines(e){return["Stable runtime quality review: the execution evidence is not sufficient for a final answer.",...issueLines(e.result),inventoryLine("Available configured tools",e.availableToolIds),inventoryLine("Available configured subagents",e.availableSubagentIds),...(n=e.observedEvidence??[],0===n.length?[]:["Completed observed evidence available for synthesis:",...n.slice(-8).map((e,n)=>`Evidence ${n+1}: ${function compact(e){const n=e.replace(/\s+/gu," ").trim();return n.length>900?`${n.slice(0,897)}...`:n}(e)}`)]),"Continue from the current state using ReAct: inspect the evidence gap, then either synthesize directly from completed observed evidence or choose one remaining declared tool/subagent action.","Do not call tools that already produced completed evidence or a repeat-limit control result for the same evidence need.","Preserve blockers explicitly instead of converting control states into unsupported factual answers."].filter(e=>e.length>0);var n}(e);return{...e.request,input:[e.request.input,"",...n].join("\n"),metadata:{...e.request.metadata,stableHarnessRecovery:`quality_${e.phase}`}}}function issueLines(e){return e.issues.map(e=>`- ${e.code}: ${e.message}`)}function inventoryLine(e,n){return n.length>0?`${e}: ${n.join(", ")}`:""}
@@ -0,0 +1,13 @@
1
+ import type { RuntimeMemoryContext, RuntimeOutput, RuntimeRequest } from "../types.js";
2
+ import type { QualityPolicy, QualityReviewInput, QualityReviewModel } from "./types.js";
3
+ export type QualityRuntimeInput = QualityReviewInput & {
4
+ requestId: string;
5
+ sessionId: string;
6
+ emit: (event: import("../types.js").RuntimeEvent) => void;
7
+ getEvents: () => import("../types.js").RuntimeEvent[];
8
+ runAdapter: (request: RuntimeRequest) => Promise<RuntimeOutput>;
9
+ reviewModel?: QualityReviewModel;
10
+ memory?: RuntimeMemoryContext;
11
+ pluginMemories: RuntimeMemoryContext[];
12
+ };
13
+ export declare function recoverQualityReview(input: QualityRuntimeInput, request: RuntimeRequest, result: RuntimeOutput, policy: QualityPolicy): Promise<RuntimeOutput>;
@@ -0,0 +1 @@
1
+ import{successfulEvidenceOutputs as e}from"./event-evidence.js";import{buildQualityRecoveryRequest as t}from"./recovery-policy.js";import{reviewExecutionEvidence as i}from"./execution-review.js";import{reviewWithLlm as n}from"./llm-review.js";import{reviewPlanningEvidence as r}from"./planning-review.js";import{synthesizeEvidenceOnlyReport as s}from"./synthesis.js";export async function recoverQualityReview(e,t,i,n){if(!n.enabled)return i;let r=t,s=i;for(let t=0;t<n.recovery.maxLoops+1;t+=1){const i=await emitPlanningReview(e,r,s,n);if("blocked"===i.verdict)return qualityFailureOutput("planning",i);const u=buildQualityRecovery(e,r,i,"planning",n,t);if(u){r=u,s=await e.runAdapter(r);continue}const o=await emitExecutionReview(e,r,s,n);if("pass"!==o.verdict){const t=await trySynthesizeExecution(e,r,o,n);if(t)return t}const a=buildQualityRecovery(e,r,o,"execution",n,t);if(!a)return"pass"===o.verdict?s:await trySynthesizeExecution(e,r,o,n)??qualityFailureOutput("execution",o);r=a,s=await e.runAdapter(r)}return qualityFailureOutput("execution",{verdict:"blocked",issues:[{code:"quality_recovery_exhausted",message:`Quality recovery exceeded maxLoops=${n.recovery.maxLoops}.`,recoverable:!1}]})}async function trySynthesizeExecution(e,t,n,r){const u=s({...reviewInputFor(e,t),output:void 0},n,r);if(!u)return;e.emit({type:"runtime.quality.synthesis.created",requestId:e.requestId,sessionId:e.sessionId,agentId:e.agent.id,mode:r.synthesis.mode});const o={text:u},a=i({...reviewInputFor(e,t),output:o},r);return emitReviewEvent(e,"execution",a),"pass"===a.verdict?o:void 0}function emitPlanningReview(e,t,i,n){return emitReview(e,"planning",r,t,i,n)}function emitExecutionReview(e,t,n,r){return emitReview(e,"execution",i,t,n,r)}async function emitReview(e,t,i,r,s,u){const o={...reviewInputFor(e,r),output:s},a="planning"===t?u.planningReview.enabled:u.executionReview.enabled;if(!a)return i(o,u);const c=i(o,u),d=await n({phase:t,review:o,policy:u,model:e.reviewModel}),v="pass"===c.verdict?d??c:c;return a&&emitReviewEvent(e,t,v),v}function emitReviewEvent(e,t,i){"planning"!==t?e.emit({type:"runtime.quality.execution.reviewed",requestId:e.requestId,sessionId:e.sessionId,agentId:e.agent.id,verdict:i.verdict,issues:i.issues}):e.emit({type:"runtime.quality.planning.reviewed",requestId:e.requestId,sessionId:e.sessionId,agentId:e.agent.id,verdict:i.verdict,issues:i.issues})}function buildQualityRecovery(i,n,r,s,u,o){if(o>=u.recovery.maxLoops)return;const a=t({request:n,result:r,phase:s,policy:u,availableToolIds:i.agent.tools,availableSubagentIds:i.agent.subagents,observedEvidence:"execution"===s?e(i.getEvents()):[]});return a&&i.emit({type:"runtime.quality.recovery.started",requestId:i.requestId,sessionId:i.sessionId,agentId:i.agent.id,phase:s,attempt:o+1,verdict:r.verdict}),a}function reviewInputFor(e,t){return{workspace:e.workspace,agent:e.agent,request:t,events:e.getEvents()}}function qualityFailureOutput(e,t){return{text:[`Stable runtime quality review blocked final delivery during ${e}.`,"",...t.issues.length>0?t.issues.map(e=>`- ${e.code}: ${e.message}`):["- quality_review_failed: Quality review did not pass."]].join("\n")}}
@@ -0,0 +1,19 @@
1
+ import type { SynthesisLanguage } from "./language.js";
2
+ export type FactKind = "context" | "data" | "timeBound" | "limit" | "other";
3
+ export type EvidenceFact = {
4
+ source: string;
5
+ text: string;
6
+ kind: FactKind;
7
+ };
8
+ export type EvidenceField = {
9
+ source: string;
10
+ label: string;
11
+ value: string;
12
+ kind: FactKind;
13
+ };
14
+ export declare function evidenceFields(facts: EvidenceFact[]): EvidenceField[];
15
+ export declare function selectSectionFields(fields: EvidenceField[], kind: FactKind, limit: number): EvidenceField[];
16
+ export declare function fieldTableLines(fields: EvidenceField[], language: SynthesisLanguage): string[];
17
+ export declare function hasExtractableFields(text: string): boolean;
18
+ export declare function classifyFact(text: string): FactKind;
19
+ export declare function normalizeFieldLabel(label: string): string;
@@ -0,0 +1 @@
1
+ export function evidenceFields(e){const t=new Set,a=[];for(const l of e)for(const e of parseEvidenceFields(l)){const l=`${normalizeFieldLabel(e.label)}\0${e.value.toLowerCase()}`;t.has(l)||(t.add(l),a.push(e))}return a}export function selectSectionFields(e,t,a){return function withSourceCoverage(e,t){const a=[...e].sort((e,t)=>scoreField(t)-scoreField(e)),l=new Map;for(const e of[...new Set(a.map(e=>e.source))]){const t=a.find(t=>t.source===e);t&&l.set(fieldKey(t),t)}for(const e of a)if(l.set(fieldKey(e),e),l.size>=t)break;return[...l.values()].slice(0,t)}(e.filter(e=>e.kind===t),a).sort((e,t)=>scoreField(t)-scoreField(e)||e.label.localeCompare(t.label))}export function fieldTableLines(e,t){return 0===e.length?[]:[..."zh"===t?["| 项目 | 数值 | 来源 |","|---|---:|---|"]:["| Field | Value | Source |","|---|---:|---|"],...e.map(e=>`| ${escapeTableCell(e.label)} | ${escapeTableCell(e.value)} | ${escapeTableCell(function humanSourceLabel(e){const t=e.replace(/([a-z])([A-Z])/gu,"$1 $2").split(/[_:.\-\s]+/u).map(e=>e.trim()).filter(Boolean);return 0===t.length?e:t.map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(" ")}(e.source))} |`)]}export function hasExtractableFields(e){return extractKeyValueFields(e).some(e=>!isBoilerplateField(e.label)&&e.value.length>0)}export function classifyFact(e){return/(?:gap|blocked|missing|unavailable|unsupported|缺口|阻塞|缺失|不支持|无法|未提供)/iu.test(e)?"limit":/(?:news|headline|recent|latest|filing|event|公告|新闻|近期|最新|披露|\b20\d{2}[-/年])/iu.test(e)?"timeBound":/(?:[$€£¥%]|\b\d[\d,]*(?:\.\d+)?\b)/u.test(e)?"data":/(?:name|company|symbol|resolved|overview|query|名称|公司|代码|概览|识别)/iu.test(e)?"context":"other"}function parseEvidenceFields(e){return extractKeyValueFields(e.text).filter(e=>e.value.length>0&&!isBoilerplateField(e.label)).filter(e=>!function isLowValueField(e,t){return!!/(?:snapshot for|source type|loaded sources)/iu.test(e)||!!/^\d{1,2}\s+(?:jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)\b/iu.test(e)||scoreField({source:"",label:e,value:t,kind:"other"})<0}(e.label,e.value)).map(t=>{const a=classifyFact(`${t.label}: ${t.value}`);return{source:e.source,label:titleCaseLabel(t.label),value:formatEvidence(t.value),kind:"other"===a?e.kind:a}})}function scoreField(e){const t=normalizeFieldLabel(e.label);let a=e.value.length>0?10:0;return/(?:price|value|amount|total|ratio|rate|range|target|estimate|revenue|income|earnings|margin|volume|date|rating|status|count|metric|价格|收入|利润|目标|评级|数量|日期|范围|比率)/iu.test(t)&&(a+=8),/(?:pe ratio|p b|market cap|book value|52 week range|day range|target estimate|revenue|net income|operating income|diluted eps)/iu.test(t)&&(a+=12),/(?:name|company|symbol|title|headline|summary|名称|公司|代码|标题|摘要)/iu.test(t)&&(a+=6),/(?:unix|epoch|timestamp|raw|html|url|href|source|id|identifier|internal|debug)/iu.test(t)&&(a-=20),/^(?:date|time|cik)$/iu.test(t)&&(a-=12),/^(?:open|high|low)$/iu.test(t)&&(a-=4),(/^https?:\/\//iu.test(e.value)||"/"===e.value)&&(a-=12),e.value.length>240&&(a-=5),a}function extractKeyValueFields(e){const t=[...e.matchAll(/(^|[\s;|])([\p{L}\p{N}][\p{L}\p{N} _./()%&+\-]{0,48})[::](?!\/\/)\s*/gu)].filter(e=>void 0!==e.index).map((e,t,a)=>{a[t-1];const l=function cleanFieldLabel(e){const t=e.replace(/^(?:[-*]\s*)+/u,"").replace(/\s+/gu," ").trim(),a=t.match(/^.+\b(PE Ratio TTM)$/iu);if(a?.[1]&&a[1]!==t&&/(?:beta|\b20\d{2}|\b(?:jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)\b)/iu.test(t))return a[1];const l=t.split(" ").filter(Boolean);return l.length>1&&/^\d{4}$/u.test(l[0]??"")||l.length>1&&/^\d+(?:\.\d+)?$/u.test(l[0]??"")&&/^(?:\d+|beta|pe|p\/b)$/iu.test(l[1]??"")||l.length>1&&/^[A-Z]$/u.test(l[0]??"")||l.length>1&&/^(?:inc\.?|llc\.?|ltd\.?|corp\.?|corporation|co\.?)$/iu.test(l[0]??"")||l.length>1&&/^(?:usd|eur|gbp|jpy|cny|cad|aud)$/iu.test(l[0]??"")||l.length>1&&/^(?:gmt|utc)$/iu.test(l[0]??"")?l.slice(1).join(" "):function trailingKnownLabel(e){if(/\bPE Ratio TTM$/iu.test(e)&&!/^PE Ratio TTM$/iu.test(e))return"PE Ratio TTM";const t=e.match(/\b(?:Revenue|Net Income|Operating Income|Diluted EPS|EPS|Market Cap|Book Value|Target Estimate|Target Mean Price|Target Median Price|Target High Price|Target Low Price|PE Ratio TTM|P\/B|Beta(?: 5Y Monthly)?|Published|Updated|Date|Time|Summary|Title|Headline)$/iu);return t&&/(?:filed|\b20\d{2}|10-k|10-q|\bfy\b|\b(?:jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)\b|\s{3,}|[a-z].{8,}\s)/iu.test(e.slice(0,t.index))?t?.[0]??e:e}(t)}(e[2]??""),i=function droppedLabelPrefix(e,t){const a=e.trim();if(a===t)return"";const l=a.toLowerCase().lastIndexOf(t.toLowerCase());return l>0?a.slice(0,l):""}(e[2]??"",l);return{index:(e.index??0)+String(e[1]??"").length+i.length,start:(e.index??0)+e[0].length,label:l,rawLabel:e[2]??""}}).filter(e=>!isBoundaryNoiseLabel(e.label)&&!isBoundaryNoiseLabel(e.rawLabel));return t.map((a,l)=>{const i=t[l+1]?.index??e.length;return{label:a.label,value:cleanFieldValue(e.slice(a.start,i),a.label)}}).filter(e=>e.label.length>0)}function cleanFieldValue(e,t){const a=e.replace(/^[\s,;|.-]+/u,"").replace(/[\s,;|.-]+$/u,"").replace(/\s+/gu," ").trim(),l=normalizeFieldLabel(t);if(/\brange\b/iu.test(l))return a.replace(/\s+Beta\b.*$/iu,"").trim();if(/^(?:ticker|symbol|resolved symbol|resolved ticker|股票 resolved ticker|代码)$/iu.test(l)){const e=a.match(/^([A-Z0-9._-]{1,24})(?:\s+\d+[.)]\s+|$)/u);if(e?.[1])return e[1]}return a}function isBoilerplateField(e){return/^(?:status|control status|evidence tool|tool|source|来源)$/iu.test(e.trim())}function isBoundaryNoiseLabel(e){return/^\d{1,2}\s+(?:jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)\b/iu.test(e)||/^(?:jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)\s+\d{1,4}(?:\s+\d{1,2})?$/iu.test(e)||/^\d{4}\s+\d{1,2}$/u.test(e)}export function normalizeFieldLabel(e){return e.toLowerCase().replace(/[^a-z0-9\p{L}\p{N}]+/giu," ").trim()}function titleCaseLabel(e){if(/\p{Script=Han}/u.test(e))return e;const t=e.split(/[^A-Za-z0-9]+/u).filter(Boolean);return normalizeFieldLabel(e).split(" ").filter(Boolean).map((e,a)=>{const l=t[a]??e;return/^[A-Z0-9]{2,}$/u.test(l)?l:e.charAt(0).toUpperCase()+e.slice(1)}).join(" ")}function formatEvidence(e){const t=e.replace(/\s+/gu," ").trim();return t.length>1200?`${t.slice(0,1197)}...`:t}function escapeTableCell(e){return e.replace(/\|/gu,"\\|").replace(/\r?\n/gu," ")}function fieldKey(e){return`${e.source}\0${normalizeFieldLabel(e.label)}\0${e.value.toLowerCase()}`}
@@ -0,0 +1,3 @@
1
+ import type { QualityReviewInput } from "../types.js";
2
+ export type SynthesisLanguage = "en" | "zh";
3
+ export declare function detectSynthesisLanguage(input: QualityReviewInput): SynthesisLanguage;
@@ -0,0 +1 @@
1
+ export function detectSynthesisLanguage(e){const t=e.workspace.runtime.responseLanguage;if(function isRecord(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}(t)){const e=readString(t.language)??readString(t.locale)??readString(t.target);if(e&&/^(?:zh|zh-|chinese|中文|汉语|漢語)/iu.test(e))return"zh";if(e&&/^(?:en|en-|english)$/iu.test(e))return"en"}return/\p{Script=Han}/u.test(e.request.input)?"zh":"en"}function readString(e){return"string"==typeof e&&e.trim()?e.trim():void 0}
@@ -0,0 +1,3 @@
1
+ import type { EvidenceField } from "./fields.js";
2
+ import type { SynthesisLanguage } from "./language.js";
3
+ export declare function observedResultLines(fields: EvidenceField[], language: SynthesisLanguage): string[];
@@ -0,0 +1 @@
1
+ import{normalizeFieldLabel as e}from"./fields.js";export function observedResultLines(e,t){const i=takeFields(e,isIdentityField,3),n=takeFields(e,isDataField,4),a=takeFields(e,isRecentField,2),o=[i.length>0?observationLine("identity",i,t):void 0,n.length>0?observationLine("data",n,t):void 0,a.length>0?observationLine("recent",a,t):void 0].filter(e=>Boolean(e));return o.length>0?o:["zh"===t?"- 只观察到原始证据,无法形成更具体的归纳。":"- Only raw evidence was observed; no more specific synthesis is available."]}function takeFields(t,i,n){const a=[],o=new Set;for(const s of t){const t=e(s.label);if(!o.has(t)&&i(s)&&(o.add(t),a.push(s),a.length>=n))break}return a}function observationLine(e,t,i){const n=t.map(e=>`${e.label} ${e.value}`).join("zh"===i?";":"; ");return"zh"===i?`- ${"identity"===e?"已确认标识":"data"===e?"关键数据":"近期证据"}:${n}。`:`- ${"identity"===e?"Confirmed identifiers":"data"===e?"Observed data":"Recent evidence"}: ${n}.`}function isIdentityField(t){const i=e(t.label);return/(?:company|name|symbol|ticker|resolved|identifier|entity|名称|公司|代码|标识)/iu.test(i)}function isDataField(t){const i=e(t.label);return"data"===t.kind||/(?:price|value|amount|total|ratio|rate|range|target|estimate|revenue|income|earnings|margin|volume|count|metric|价格|收入|利润|目标|评级|数量|范围|比率)/iu.test(i)}function isRecentField(t){const i=e(t.label);return"timeBound"===t.kind||/(?:date|time|published|updated|headline|summary|event|filing|日期|时间|发布|更新|标题|摘要|事件|披露)/iu.test(i)}
@@ -0,0 +1,2 @@
1
+ import type { QualityPolicy, QualityReviewInput, QualityReviewResult } from "./types.js";
2
+ export declare function synthesizeEvidenceOnlyReport(input: QualityReviewInput, review: QualityReviewResult, policy: QualityPolicy): string | undefined;
@@ -0,0 +1 @@
1
+ import{controlBlockers as e,controlGaps as t,successfulEvidenceItems as n}from"./event-evidence.js";import{classifyFact as s,evidenceFields as r,fieldTableLines as o,hasExtractableFields as i,selectSectionFields as c}from"./synthesis/fields.js";import{detectSynthesisLanguage as u}from"./synthesis/language.js";import{observedResultLines as a}from"./synthesis/observed.js";export function synthesizeEvidenceOnlyReport(s,r,o){if(!o.enabled||!o.synthesis.enabled||"evidence_only"!==o.synthesis.mode)return;if("pass"===r.verdict||!function hasRecoverableSynthesisIssue(e){return e.issues.some(e=>"control_blocker"!==e.code)}(r))return;const i=n(s.events).slice(-o.synthesis.maxEvidenceItems),c=e(s.events),a=t(s.events);if(0===i.length&&0===c.length&&0===a.length)return;const l=function latestDelegatedReport(e){const t=e.filter(e=>"task"===e.source&&function looksLikeFinalReport(e){const t=e.trim();return!(t.length<80)&&(/^#{1,3}\s+\S/mu.test(t)||/\n#{1,3}\s+\S/mu.test(t)||/\n-{3,}\n/u.test(t))}(e.output)&&!function looksLikeCommentaryInsteadOfEvidence(e){const t=e.trim();return!(t.length>8e3)&&[/(?:这篇文章|this article)[\s\S]{0,1200}(?:我认为|我认同|打动我|值得深入探讨|特别认同|what I find|I think|I agree)/iu,/(?:你还有什么|还想深入探讨|would you like|do you want).{0,120}[??]\s*$/iu].some(e=>e.test(t))}(e.output)).at(-1)?.output.trim();return t||void 0}(i);return l||("zh"===u(s)?function buildChineseReport(e,t,n){const s=evidenceFacts(e);return["# 调查结果","","## 结论",...resultSummaryLines(e,s,t,n,"zh"),"","## 证据摘要",...summaryLines(e,t,n,"zh"),"",...structuredFactSections(s,"zh"),"","## 证据缺口与阻塞",...gapLines(t,n,"zh"),"","## 使用的证据来源",...sourceLines(sourceSummary(e),"zh")].join("\n")}(i,c,a):function buildEnglishReport(e,t,n){const s=evidenceFacts(e);return["# Result","","## Conclusion",...resultSummaryLines(e,s,t,n,"en"),"","## Evidence summary",...summaryLines(e,t,n,"en"),"",...structuredFactSections(s,"en"),"","## Evidence gaps and blockers",...gapLines(t,n,"en"),"","## Sources used",...sourceLines(sourceSummary(e),"en")].join("\n")}(i,c,a))}function resultSummaryLines(e,t,n,s,o){if(0===e.length)return["zh"===o?"- 没有成功证据可用于形成调查结论。":"- No successful evidence was available for a result."];const i=[...new Set(e.map(e=>humanSourceLabel(e.source)))],c=r(t),u=a(c,o),l=0===n.length&&0===s.length?"zh"===o?"未观察到运行时阻塞;未覆盖的业务、估值或风险细节不应视为已确认。":"No runtime blocker was observed; uncovered business, valuation, or risk details should not be treated as confirmed.":"zh"===o?`仍有 ${n.length+s.length} 个证据缺口或阻塞,结论应按部分调查读取。`:`${n.length+s.length} evidence gap(s) or blocker(s) remain, so read this as a partial result.`;return["zh"===o?`- 已基于 ${i.join("、")} 形成可交付结果。`:`- Result formed from ${i.join(", ")}.`,`- ${l}`,...u]}function sourceSummary(e){const t=new Map;for(const n of e){const e=t.get(n.source)??{source:n.source,count:0,facts:[]};e.count+=1,e.facts.push(...factLines(n.output)),t.set(n.source,e)}return[...t.values()].map(t=>({...t,facts:t.facts.length>0?t.facts.slice(0,8):[fallbackEvidenceText(evidenceTextForSource(e,t.source))]}))}function evidenceFacts(e){return e.flatMap(e=>{const t=factLines(e.output);return(t.length>0?t:[fallbackEvidenceText(e.output)]).map(t=>({source:e.source,text:t,kind:s(t)}))}).slice(0,40)}function summaryLines(e,t,n,s){if(0===e.length)return["zh"===s?"- 未观察到成功的工具或委托任务证据。":"- No successful tool or delegated-task evidence was observed."];const r=new Set(e.map(e=>e.source)).size,o=0===t.length&&0===n.length?"zh"===s?"未观察到未解决的运行时证据缺口或阻塞。":"No unresolved runtime evidence gaps or blockers were observed.":"zh"===s?`仍有 ${t.length+n.length} 个运行时证据缺口或阻塞。`:`${t.length+n.length} runtime evidence gaps or blockers remain.`;return["zh"===s?`- 已使用 ${e.length} 条完成证据,来自 ${r} 个来源。`:`- Used ${e.length} completed evidence item(s) from ${r} source(s).`,`- ${o}`]}function structuredFactSections(e,t){if(0===e.length)return["zh"===t?"- 证据缺口:没有可用于生成事实性结论的成功证据。":"- Evidence gap: no successful tool or delegated-task evidence was available."];const n=r(e);return[{kind:"context",title:"zh"===t?"## 已确认背景":"## Confirmed context"},{kind:"data",title:"zh"===t?"## 观察到的数据":"## Observed data points"},{kind:"timeBound",title:"zh"===t?"## 近期或时间相关证据":"## Recent or time-bound evidence"},{kind:"limit",title:"zh"===t?"## 证据限制":"## Evidence limits"},{kind:"other",title:"zh"===t?"## 其他观察":"## Additional observations"}].flatMap(s=>{const r=c(n,s.kind,12),u=e.filter(e=>e.kind===s.kind&&!i(e.text)).filter(e=>!function isLowValueTextFact(e){const t=e.trim();return/^https?:\/\/\S+$/iu.test(t)||/^source\s*:/iu.test(t)||/^来源\s*[::]/u.test(t)}(e.text)).slice(0,5);return 0===r.length&&0===u.length?[]:[s.title,...o(r,t),...u.map(e=>function factLine(e,t){const n=humanSourceLabel(e.source);return"zh"===t?`- ${e.text}(来源:${n})`:`- ${e.text} (source: ${n})`}(e,t)),""]}).filter((e,t,n)=>""!==e||t<n.length-1)}function sourceLines(e,t){return 0===e.length?["zh"===t?"- 未使用成功证据来源。":"- No successful evidence source was used."]:e.map(e=>`- ${humanSourceLabel(e.source)}${e.count>1?` (${e.count})`:""}: ${e.source}`)}function gapLines(e,t,n){return 0===e.length&&0===t.length?["zh"===n?"- 未观察到未解决的运行时证据缺口或阻塞。":"- No unresolved runtime evidence gaps or blockers were observed."]:"zh"===n?[...e.map(e=>`- 阻塞:${e}`),...t.map(e=>`- 证据缺口:${e}`)]:[...e.map(e=>`- Blocked: ${e}`),...t.map(e=>`- Evidence gap: ${e}`)]}function formatEvidence(e){const t=e.replace(/\s+/gu," ").trim();return t.length>1200?`${t.slice(0,1197)}...`:t}function factLines(e){const t=function factLinesFromJson(e){try{const t=JSON.parse(e);return function isRecord(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}(t)?Object.entries(t).filter(([e])=>!/^(?:status|controlStatus)$/iu.test(e)).slice(0,8).map(([e,t])=>`${e}: ${formatEvidence(function stringifyJsonValue(e){return"string"==typeof e?e:JSON.stringify(e)}(t))}`):[]}catch{return[]}}(e);return t.length>0?t:function splitPlainTextFacts(e){const t=function stripControlPreamble(e){return e.replace(/^(?:Status:\s*(?:completed|success|ok|recorded)\b\.?\s*)+/iu,"").replace(/^(?:Evidence tool:\s*[A-Za-z0-9_.-]+\b\.?\s*)+/iu,"").trim()}(e);return t.split(/\r?\n|;\s*/u).map(e=>e.trim()).map(stripControlFragments).map(normalizePlainFactLine).filter(e=>e&&!function isControlFact(e){return/^Status:\s*(?:completed|success|ok|recorded)$/iu.test(e)||/^Evidence tool:\s*[A-Za-z0-9_.-]+$/iu.test(e)}(e))}(e).slice(0,8).map(formatEvidence)}function stripControlFragments(e){return e.replace(/\bStatus:\s*(?:completed|success|ok|recorded)\b\.?\s*/giu,"").replace(/\bEvidence tool:\s*[A-Za-z0-9_.-]+\b\.?\s*/giu,"").trim()}function normalizePlainFactLine(e){if(/^https?:\/\//iu.test(e))return"";const t=e.match(/^\d+[.)]\s+(.+)$/u);return t?.[1]?`Headline: ${t[1]}`:e}function evidenceTextForSource(e,t){return e.find(e=>e.source===t)?.output??""}function fallbackEvidenceText(e){return formatEvidence(e)}function humanSourceLabel(e){const t=e.replace(/([a-z])([A-Z])/gu,"$1 $2").split(/[_:.\-\s]+/u).map(e=>e.trim()).filter(Boolean);return 0===t.length?e:t.map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(" ")}
@@ -0,0 +1,52 @@
1
+ import type { CompiledWorkspace, RuntimeEvent, RuntimeOutput, RuntimeRequest, WorkspaceAgent } from "../types.js";
2
+ export type QualityProfile = "off" | "fast" | "balanced" | "strict";
3
+ export type QualityReviewVerdict = "pass" | "revise_plan" | "continue_react" | "blocked";
4
+ export type QualityReviewIssue = {
5
+ code: string;
6
+ message: string;
7
+ recoverable: boolean;
8
+ };
9
+ export type QualityReviewResult = {
10
+ verdict: QualityReviewVerdict;
11
+ issues: QualityReviewIssue[];
12
+ };
13
+ export type QualityPolicy = {
14
+ enabled: boolean;
15
+ profile: QualityProfile;
16
+ reviewer?: {
17
+ mode: "deterministic" | "llm";
18
+ modelRef?: string;
19
+ planningPrompt?: string;
20
+ executionPrompt?: string;
21
+ };
22
+ planningReview: {
23
+ enabled: boolean;
24
+ requirePlan: boolean;
25
+ };
26
+ executionReview: {
27
+ enabled: boolean;
28
+ requireToolEvidence: boolean;
29
+ rejectEmptyFinal: boolean;
30
+ stopOnBlocker: boolean;
31
+ rejectUngroundedNumbers: boolean;
32
+ };
33
+ synthesis: {
34
+ enabled: boolean;
35
+ mode: "evidence_only";
36
+ maxEvidenceItems: number;
37
+ };
38
+ recovery: {
39
+ enabled: boolean;
40
+ maxLoops: number;
41
+ };
42
+ };
43
+ export type QualityReviewInput = {
44
+ workspace: CompiledWorkspace;
45
+ agent: WorkspaceAgent;
46
+ request: RuntimeRequest;
47
+ events: RuntimeEvent[];
48
+ output?: RuntimeOutput;
49
+ };
50
+ export type QualityReviewModel = {
51
+ invoke(input: unknown): Promise<unknown> | unknown;
52
+ };
@@ -0,0 +1,28 @@
1
+ import type { RuntimeEvent, RuntimeRequest } from "../types.js";
2
+ export declare function toolCallRecoveryEnabled(policy: unknown): boolean;
3
+ export declare function isRecoverableAdapterError(error: unknown, policy: unknown): boolean;
4
+ export declare function buildAdapterErrorRecoveryPrompt(request: RuntimeRequest, error: unknown, policy: unknown): RuntimeRequest;
5
+ export declare function buildResultRecoveryRequest(input: {
6
+ request: RuntimeRequest;
7
+ output: string;
8
+ events: RuntimeEvent[];
9
+ availableToolIds?: string[];
10
+ policy: unknown;
11
+ }): RuntimeRequest | undefined;
12
+ export declare function buildExecutionContractRecoveryRequest(input: {
13
+ request: RuntimeRequest;
14
+ events: RuntimeEvent[];
15
+ policy: unknown;
16
+ }): RuntimeRequest | undefined;
17
+ export declare function assertNoRawToolCallOutput(output: string, policy: unknown): void;
18
+ export declare function containsRawToolCallOutput(output: string, policy: unknown): boolean;
19
+ export declare function containsRecoverableResultOutput(output: string, policy: unknown): boolean;
20
+ export declare function assertNoToolExecutionErrorOutput(output: string, policy: unknown): void;
21
+ export declare function rawToolCallFailureMessage(): string;
22
+ export declare function buildEvidenceSynthesisOutput(input: {
23
+ request: RuntimeRequest;
24
+ output: string;
25
+ events: RuntimeEvent[];
26
+ policy: unknown;
27
+ }): string | undefined;
28
+ export declare function rawToolCallOutputPreview(output: string): string;
@@ -0,0 +1 @@
1
+ export function toolCallRecoveryEnabled(e){return!0===readToolCallRecovery(e).enabled}export function isRecoverableAdapterError(e,t){const o=readToolCallRecovery(t);if(!0!==o.enabled)return!1;const n=e instanceof Error?e.message:String(e);return readRegexps(o.adapterErrorPatterns,[/XML syntax error|tool.?call.*syntax|malformed.*(?:XML|tool)|Non string tool message content|repeat limit reached for tool/iu]).some(e=>e.test(n))}export function buildAdapterErrorRecoveryPrompt(e,t,o){const n=t instanceof Error?t.message:String(t),r=readToolCallRecovery(o).instruction;return recoverRequest(e,["Stable runtime recovery: the backend failed while parsing a tool call.",`Parser error: ${n}`,"string"==typeof r?r:"Continue the same user request using the backend's normal tool-calling mechanism, then return a final human-readable answer.","Do not print raw tool-call markup, JSON tool-call envelopes, or pseudo tool-call text in the final answer."])}export function buildResultRecoveryRequest(e){const t=readToolCallRecovery(e.policy);if(!0!==t.enabled)return;if(containsRawToolCallText(e.output,t)){const t=recentToolEvidence(e.events,1e3);return recoverRequest(e.request,["Stable runtime recovery: your previous final answer printed raw tool-call markup instead of executing the tool.","Continue the same user request by calling the available upstream tool normally when more evidence is required.","If you call a tool, the next assistant action must be the backend's structured tool call itself, with no prose before it.",...e.availableToolIds?.length?[`Available configured tools: ${e.availableToolIds.join(", ")}`,"Do not invent, print, or call tools that are not in this list."]:[],"If the conversation context already contains enough evidence to answer, synthesize the final answer from that context instead.","Do not print XML, JSON, markdown fences, pseudo tool-call text, plans, or future-intent text such as saying you will call or wait for a tool.",...t.length>0?["","Recent executed tool evidence:",...t]:[],"","Previous invalid final answer:",e.output])}if(containsToolExecutionErrorText(e.output,t)){const t=recentToolEvidence(e.events,1e3);return recoverRequest(e.request,["Stable runtime recovery: your previous final answer exposed a backend tool execution error instead of handling it.","Continue the same user request using the backend's normal structured tool-calling mechanism.","Do not retry the same invalid tool arguments. If the failed tool is not required to answer the user, synthesize the final answer from the available context instead.",...e.availableToolIds?.length?[`Available configured tools: ${e.availableToolIds.join(", ")}`,"Do not invent, print, or call tools that are not in this list."]:[],"Do not print tool error stacks, schema validation diagnostics, raw tool-call markup, JSON tool-call envelopes, or pseudo tool-call text in the final answer.",...t.length>0?["","Recent executed tool evidence:",...t]:[],"","Previous invalid final answer:",e.output])}const o=function lastConfiguredEventHint(e,t){const o=function readEventRecoveryHints(e){return(Array.isArray(e)?e:[]).flatMap(e=>isRecord(e)&&"string"==typeof e.instruction?[{..."string"==typeof e.toolId?{toolId:e.toolId}:{},..."string"==typeof e.phase?{phase:e.phase}:{},..."string"==typeof e.outputIncludes?{outputIncludes:e.outputIncludes}:{},..."string"==typeof e.outputMatches?{outputMatches:e.outputMatches}:{},instruction:e.instruction}]:[])}(t.eventRecoveryHints);if(0!==o.length)return e.flatMap(e=>function readMatchingHints(e,t){const o="runtime.adapter.event"===e.type&&isRecord(e.event)?e.event:void 0;return o?t.filter(e=>function eventMatchesHint(e,t){return(!t.toolId||e.toolId===t.toolId)&&(!t.phase||e.phase===t.phase)&&(t.outputIncludes?"string"==typeof e.output&&e.output.includes(t.outputIncludes):!t.outputMatches||"string"==typeof e.output&&new RegExp(t.outputMatches,"u").test(e.output))}(o,e)).map(e=>({output:"string"==typeof o.output?o.output:"Adapter event matched configured recovery hint.",instruction:e.instruction})):[]}(e,o)).at(-1)}(e.events,t);return o?recoverRequest(e.request,["Stable runtime recovery: a previous adapter event matched a configured recovery hint.",o.output,o.instruction]):void 0}export function buildExecutionContractRecoveryRequest(e){if(!0!==readToolCallRecovery(e.policy).enabled)return;const t=function lastMissingEvidenceTools(e){for(let t=e.length-1;t>=0;t-=1){const o=e[t];if("runtime.execution.contract.failed"===o?.type)return readStringArray(o.missingEvidenceTools)}return[]}(e.events);return 0!==t.length?recoverRequest(e.request,["Stable runtime recovery: the execution contract was not satisfied.",`Required evidence tool(s) were missing: ${t.join(", ")}`,"Continue the same user request by calling the missing required evidence tool(s) through the backend's normal structured tool-calling mechanism.","Do not produce a final answer until the required evidence tool call has executed and you have synthesized its result.","Do not print XML, JSON, markdown fences, pseudo tool-call text, plans, or future-intent text in the final answer."]):void 0}export function assertNoRawToolCallOutput(e,t){if(containsRawToolCallOutput(e,t))throw new Error(`Adapter returned raw tool-call text as the final answer after recovery. The backend must execute tools instead of printing tool-call markup. Output preview: ${previewOutput(e)}`)}export function containsRawToolCallOutput(e,t){const o=readToolCallRecovery(t);return!0===o.enabled&&containsRawToolCallText(e,o)}export function containsRecoverableResultOutput(e,t){const o=readToolCallRecovery(t);return!0===o.enabled&&containsRecoverableResultFailureText(e,o)}export function assertNoToolExecutionErrorOutput(e,t){const o=readToolCallRecovery(t);if(!0===o.enabled&&containsToolExecutionErrorText(e,o))throw new Error(`Adapter returned a tool execution error as the final answer after recovery. Output preview: ${previewOutput(e)}`)}export function rawToolCallFailureMessage(){return["The model attempted to call a tool but returned the tool call as text instead of executing it.","Please retry the request or use a model/backend configuration with reliable tool calling for this workspace."].join(" ")}export function buildEvidenceSynthesisOutput(e){const t=readToolCallRecovery(e.policy);if(!0!==t.enabled||!1===t.synthesizeFromEvidenceOnFailure||!containsRecoverableResultFailureText(e.output,t))return;const o=function latestDelegatedTaskReport(e){return e.flatMap(e=>{const t="runtime.adapter.event"===e.type&&isRecord(e.event)?e.event:void 0;if(!t||"agent.tool.result"!==t.phase||"task"!==t.toolId)return[];const o="string"==typeof t.output?t.output.trim():"";return function looksLikeFinalReport(e){const t=e.trim();return!(t.length<80)&&(/^#{1,3}\s+\S/mu.test(t)||/\n#{1,3}\s+\S/mu.test(t)||/\n-{3,}\n/u.test(t))}(o)?[o]:[]}).at(-1)||void 0}(e.events);if(o)return o;const n=recentToolEvidence(e.events,6e3);return 0!==n.length?"zh"==(/\p{Script=Han}/u.test(e.request.input)?"zh":"en")?function buildChineseEvidenceSynthesis(e,t){return["上游模型在已有工具证据后仍输出了伪工具调用;runtime 已拒绝该 raw 输出,并直接交付已执行工具返回的证据结果。","","已执行的工具证据:",...t,"",`被拒绝的最终输出预览:${previewRejectedOutput(e)}`].join("\n")}(e.output,n):function buildEnglishEvidenceSynthesis(e,t){return["The upstream model still returned pseudo tool-call text after tool evidence was available. The runtime rejected that raw output and is returning the executed tool evidence directly.","","Executed tool evidence:",...t,"",`Rejected final output preview: ${previewRejectedOutput(e)}`].join("\n")}(e.output,n):void 0}function previewOutput(e){const t=e.replace(/\s+/gu," ").trim();return t.length>300?`${t.slice(0,297)}...`:t}function previewRejectedOutput(e){return previewOutput(e).replace(/[<>]/gu,"")}export function rawToolCallOutputPreview(e){return previewOutput(e)}function recoverRequest(e,t){return{...e,input:[e.input,"",...t].join("\n"),metadata:{...e.metadata,stableHarnessRecovery:"tool_call"}}}function containsRawToolCallText(e,t){const o=readRegexps(t.rawOutputPatterns,[/\{\s*"name"\s*:\s*"[^"]+"\s*,\s*"arguments"\s*:/iu,/\{\s*"tool_name"\s*:\s*"[^"]+"\s*,\s*"parameters"\s*:/iu,/\{\s*"type"\s*:\s*"[^"]+"\s*,\s*"args"\s*:/iu,/^\s*[A-Za-z_][\w.-]*\s*\([^)]{0,2000}\)\s*$/iu,/^\s*[A-Za-z_][\w.-]*(?:_command|_tool|_analysis|_investigate|task)\s*$/iu,/```(?:json)?[\s\S]{0,4000}"(?:tool_name|tool|name|subagent_type)"\s*:/iu,/```(?:json)?[\s\S]{0,4000}"(?:tool_name|tool|name|subagent_type)"\s*:[\s\S]{0,4000}"(?:arguments|parameters|task)"\s*:/iu,/```(?:json)?[\s\S]{0,2000}"query"\s*:[\s\S]{0,2000}"(?:max_results|count|freshness|market)"\s*:/iu]);return!![/<\s*(?:tool_call|task)\b[^>]*>/iu,/<\s*\/\s*(?:tool_call|task)\s*>/iu,/<\s*\/?\s*tool_code\b[^>]*>/iu,/<\s*\/?\s*[A-Za-z_][\w.-]*(?:_command|_tool|_analysis|_investigate|_todos|task)\b[^>]*>/iu].some(t=>t.test(e))||function looksLikeStandaloneRecoveryCandidate(e){const t=e.trim();return t.length<=6e3||/^\s*(?:```|\{|\[|[A-Za-z_][\w.-]*\s*\()/u.test(t)}(e)&&(o.some(t=>t.test(e))||[/^[\s\S]{0,2400}\b(?:I need to|I will|I'll|I am going to|I'm going to)\s+(?:call|use|invoke|delegate)\b[\s\S]{0,1200}\b(?:tool|function|specialist|subagent)\b[\s\S]{0,400}$/iu,/^[\s\S]{0,2400}\b(?:I will|I'll|I am going to|I'm going to)\s+(?:investigate|gather|check)\b[\s\S]{0,1200}\b(?:evidence|cluster|system|results?)\b[\s\S]{0,400}$/iu,/^[\s\S]{0,2400}\b(?:waiting for|wait for)\b[\s\S]{0,1200}\b(?:tool|function|specialist|subagent)\b[\s\S]{0,400}$/iu,/^[\s\S]{0,2400}\b(?:Would you like me to|Do you want me to|Should I|I can help with)\b[\s\S]{0,1200}\?[\s\S]{0,400}$/iu,/^[\s\S]{0,2400}\bCould you please provide\b[\s\S]{0,1200}\b(?:tool|function|specialist|subagent|task)\b[\s\S]{0,400}$/iu,/^[\s\S]{0,2400}\b(?:I don't|I do not) have enough information\b[\s\S]{0,1200}\b(?:tool|function|specialist|subagent|task|context)\b[\s\S]{0,400}$/iu,/^[\s\S]{0,2400}\bLet me\s+(?:call|use|invoke|delegate|check|run|verify|gather|inspect)\b[\s\S]{0,1200}\b(?:tool|function|specialist|subagent|results?|data|evidence|commands?)\b[\s\S]{0,400}$/iu,/^[\s\S]{0,2400}(?:我需要|我要|我会|我将|让我|我来|接下来我(?:会|将)?)\s*(?:先)?(?:调用|使用|运行|执行|检查|读取|收集|调查|验证|查看)[\s\S]{0,1200}$/iu,/^[\s\S]{0,2400}(?:要不要|是否需要|需要我|你想让我)[\s\S]{0,1200}(?:继续|进一步|帮你|分析|检查)[\s\S]{0,1200}[??][\s\S]{0,400}$/iu].some(t=>t.test(e)))}function containsRecoverableResultFailureText(e,t){return containsRawToolCallText(e,t)||containsToolExecutionErrorText(e,t)}function containsToolExecutionErrorText(e,t){return readRegexps(t.toolFailureOutputPatterns,[/^Error invoking tool ['"][^'"]+['"] with kwargs /iu,/Received tool input did not match expected schema/iu,/ToolMessage.*status.*error/iu]).some(t=>t.test(e))}function recentToolEvidence(e,t){return e.flatMap(e=>{const o="runtime.adapter.event"===e.type&&isRecord(e.event)?e.event:void 0;return o&&"agent.tool.result"===o.phase&&"string"==typeof o.toolId?function isControlToolOutput(e){if("string"!=typeof e||!e.trim().startsWith("{"))return!1;try{const t=JSON.parse(e),o=isRecord(t)?t.status:void 0;return"duplicate_tool_call"===o||"repeated_tool_call_limit"===o||"tool_argument_error"===o}catch{return!1}}(o.output)?[]:[`- ${o.toolId}: ${formatToolEvidence(o,t)}`]:[]}).slice(-5)}function formatToolEvidence(e,t=1e3){return"string"==typeof e.output&&e.output.trim()?e.output.slice(0,t):"string"==typeof e.error&&e.error.trim()?`error: ${e.error.slice(0,t)}`:isRecord(e.args)?`completed with args: ${previewOutput(JSON.stringify(e.args))}`:"completed"}function readToolCallRecovery(e){if(!isRecord(e))return{};const t=isRecord(e.recovery)?e.recovery:{};return isRecord(t.toolCall)?t.toolCall:{}}function readRegexps(e,t){const o=(Array.isArray(e)?e:[]).filter(e=>"string"==typeof e&&e.length>0).map(e=>new RegExp(e,"iu"));return o.length>0?o:t}function readStringArray(e){return Array.isArray(e)?e.filter(e=>"string"==typeof e&&e.length>0):[]}function isRecord(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}