stable-harness 0.0.3 → 0.0.5

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 (120) hide show
  1. package/README.md +189 -9
  2. package/dist/cli.js +1 -1
  3. package/dist/compat/agent-harness.js +1 -1
  4. package/dist/index.d.ts +2 -1
  5. package/dist/index.js +1 -1
  6. package/dist/runtime/compat/agent-harness-compat-runner.js +1 -1
  7. package/dist/runtime/compat/json.js +1 -1
  8. package/dist/runtime/compat/presentation.js +1 -1
  9. package/dist/runtime/compat/prompts.js +1 -1
  10. package/dist/runtime/model/ollama.js +1 -1
  11. package/dist/runtime/skills/skill-metadata.js +1 -1
  12. package/dist/workspace/compile.js +1 -1
  13. package/package.json +4 -3
  14. package/packages/adapter-deepagents/dist/src/adapter.js +1 -1
  15. package/packages/adapter-deepagents/dist/src/internal/builtin-args.d.ts +4 -0
  16. package/packages/adapter-deepagents/dist/src/internal/builtin-args.js +1 -0
  17. package/packages/adapter-deepagents/dist/src/internal/builtin-tool-policy.d.ts +9 -4
  18. package/packages/adapter-deepagents/dist/src/internal/builtin-tool-policy.js +1 -1
  19. package/packages/adapter-deepagents/dist/src/internal/gateway-tools.d.ts +29 -1
  20. package/packages/adapter-deepagents/dist/src/internal/gateway-tools.js +1 -1
  21. package/packages/adapter-deepagents/dist/src/internal/messages.js +1 -1
  22. package/packages/adapter-deepagents/dist/src/internal/raw-tool-call-parser.d.ts +12 -0
  23. package/packages/adapter-deepagents/dist/src/internal/raw-tool-call-parser.js +1 -0
  24. package/packages/adapter-deepagents/dist/src/internal/skill-file-policy.d.ts +10 -0
  25. package/packages/adapter-deepagents/dist/src/internal/skill-file-policy.js +1 -0
  26. package/packages/adapter-deepagents/dist/src/internal/stream-events.js +1 -1
  27. package/packages/adapter-deepagents/dist/src/internal/tool-repeat-visibility.d.ts +4 -0
  28. package/packages/adapter-deepagents/dist/src/internal/tool-repeat-visibility.js +1 -0
  29. package/packages/adapter-deepagents/dist/src/internal/trace-projection.d.ts +1 -1
  30. package/packages/adapter-deepagents/dist/src/internal/trace-projection.js +1 -1
  31. package/packages/adapter-deepagents/dist/src/memory.js +1 -1
  32. package/packages/adapter-deepagents/dist/src/model-providers.d.ts +4 -0
  33. package/packages/adapter-deepagents/dist/src/model-providers.js +1 -0
  34. package/packages/adapter-deepagents/dist/src/retry-policy.js +1 -1
  35. package/packages/adapter-deepagents/dist/src/types.d.ts +7 -1
  36. package/packages/adapter-deepagents/package.json +1 -0
  37. package/packages/adapter-langgraph/dist/src/graph.js +1 -1
  38. package/packages/adapter-langgraph/dist/src/runtime.js +1 -1
  39. package/packages/adapter-langgraph/dist/src/skill-providers.js +1 -1
  40. package/packages/cli/dist/src/args.d.ts +6 -3
  41. package/packages/cli/dist/src/args.js +1 -1
  42. package/packages/cli/dist/src/cli.js +1 -1
  43. package/packages/cli/dist/src/event-view.d.ts +9 -0
  44. package/packages/cli/dist/src/event-view.js +1 -0
  45. package/packages/cli/dist/src/index.d.ts +3 -0
  46. package/packages/cli/dist/src/index.js +1 -1
  47. package/packages/cli/dist/src/langgraph-env.d.ts +5 -0
  48. package/packages/cli/dist/src/langgraph-env.js +1 -0
  49. package/packages/cli/dist/src/langgraph-official.d.ts +2 -0
  50. package/packages/cli/dist/src/langgraph-official.js +1 -1
  51. package/packages/cli/dist/src/memory/lifecycle.d.ts +2 -0
  52. package/packages/cli/dist/src/memory/lifecycle.js +1 -0
  53. package/packages/cli/dist/src/memory/providers.d.ts +3 -0
  54. package/packages/cli/dist/src/memory/providers.js +1 -0
  55. package/packages/cli/dist/src/output.js +1 -1
  56. package/packages/cli/dist/src/server.d.ts +2 -0
  57. package/packages/cli/dist/src/server.js +1 -1
  58. package/packages/cli/package.json +2 -0
  59. package/packages/core/dist/evaluations/index.d.ts +18 -0
  60. package/packages/core/dist/evaluations/index.js +1 -0
  61. package/packages/core/dist/execution-contract.js +1 -1
  62. package/packages/core/dist/index.d.ts +3 -0
  63. package/packages/core/dist/index.js +1 -1
  64. package/packages/core/dist/memory-plugins/maintenance.js +1 -1
  65. package/packages/core/dist/memory-plugins/shared.js +1 -1
  66. package/packages/core/dist/memory-plugins.js +1 -1
  67. package/packages/core/dist/recovery/tool-call.d.ts +15 -0
  68. package/packages/core/dist/recovery/tool-call.js +1 -1
  69. package/packages/core/dist/runtime/completion.js +1 -1
  70. package/packages/core/dist/runtime/direct-tool-call.js +1 -1
  71. package/packages/core/dist/runtime/events.d.ts +77 -20
  72. package/packages/core/dist/runtime/memory.js +1 -1
  73. package/packages/core/dist/runtime/persistence/artifacts.js +1 -1
  74. package/packages/core/dist/runtime/persistence/inspection.js +1 -1
  75. package/packages/core/dist/runtime/persistence/queue.js +1 -1
  76. package/packages/core/dist/runtime/persistence/stores.js +1 -1
  77. package/packages/core/dist/runtime/progress-narration.d.ts +33 -0
  78. package/packages/core/dist/runtime/progress-narration.js +1 -0
  79. package/packages/core/dist/runtime/tool-gateway.d.ts +5 -0
  80. package/packages/core/dist/runtime.d.ts +2 -1
  81. package/packages/core/dist/runtime.js +1 -1
  82. package/packages/core/dist/spec-driven/config.d.ts +4 -0
  83. package/packages/core/dist/spec-driven/config.js +1 -0
  84. package/packages/core/dist/spec-driven/events.d.ts +11 -0
  85. package/packages/core/dist/spec-driven/events.js +1 -0
  86. package/packages/core/dist/spec-driven/index.d.ts +4 -0
  87. package/packages/core/dist/spec-driven/index.js +1 -0
  88. package/packages/core/dist/spec-driven/lifecycle.d.ts +11 -0
  89. package/packages/core/dist/spec-driven/lifecycle.js +1 -0
  90. package/packages/core/dist/spec-driven/types.d.ts +38 -0
  91. package/packages/core/dist/spec-driven/types.js +1 -0
  92. package/packages/core/dist/trace.d.ts +1 -1
  93. package/packages/core/dist/trace.js +1 -1
  94. package/packages/core/dist/types.d.ts +15 -1
  95. package/packages/core/dist/workflows/index.js +1 -1
  96. package/packages/core/dist/workflows/runtime.js +1 -1
  97. package/packages/core/dist/workspace/types.d.ts +9 -0
  98. package/packages/governance/dist/src/skill-candidates.js +1 -1
  99. package/packages/memory/dist/src/langmem-service.js +1 -1
  100. package/packages/memory/dist/src/maintenance.js +1 -1
  101. package/packages/memory/dist/src/policy.js +1 -1
  102. package/packages/memory/dist/src/provider.js +1 -1
  103. package/packages/memory/dist/src/store.js +1 -1
  104. package/packages/protocols/dist/src/http-server.js +1 -1
  105. package/packages/protocols/dist/src/openai-compatible.js +1 -1
  106. package/packages/protocols/dist/src/openai-payload.js +1 -1
  107. package/packages/protocols/dist/src/openai-stream.js +1 -1
  108. package/packages/tool-gateway/dist/src/argument-guard.d.ts +2 -1
  109. package/packages/tool-gateway/dist/src/argument-guard.js +1 -1
  110. package/packages/tool-gateway/dist/src/in-memory.js +1 -1
  111. package/packages/tool-gateway/dist/src/module-loader.js +1 -1
  112. package/packages/tool-gateway/dist/src/schema-validation.js +1 -1
  113. package/packages/tool-gateway/dist/src/types.d.ts +3 -0
  114. package/packages/tool-gateway/package.json +1 -1
  115. package/packages/workspace-yaml/dist/discovery.js +1 -1
  116. package/packages/workspace-yaml/dist/documents.js +1 -1
  117. package/packages/workspace-yaml/dist/evaluations.d.ts +9 -0
  118. package/packages/workspace-yaml/dist/evaluations.js +1 -0
  119. package/packages/workspace-yaml/dist/loader.js +1 -1
  120. package/packages/workspace-yaml/dist/workflows.js +1 -1
@@ -15,7 +15,9 @@
15
15
  "dependencies": {
16
16
  "@langchain/langgraph-api": "^1.2.1",
17
17
  "@stable-harness/adapter-deepagents": "0.0.1",
18
+ "@stable-harness/adapter-langgraph": "0.0.1",
18
19
  "@stable-harness/core": "0.0.1",
20
+ "@stable-harness/memory": "0.0.1",
19
21
  "@stable-harness/protocols": "0.0.1",
20
22
  "@stable-harness/tool-gateway": "0.0.1",
21
23
  "@stable-harness/workspace-yaml": "0.0.1"
@@ -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 @@
1
+ export{};
@@ -1 +1 @@
1
- export function assertExecutionContract(r){(function(e){const t=n(e?.executionContract)?e.executionContract:void 0;return!1===t?.enabled})(r.metadata)||(function(n){const r=e(n.agent);if(!r.requiresPlan)return;const i=o(r.planEvidenceTools);if(0===i.length)throw n.emit({type:"execution.contract.failed",requestId:n.requestId,sessionId:n.sessionId,agentId:n.agent.id,reason:"invalid_plan_contract"}),new Error("Execution contract requires plan evidence tools when requiresPlan is enabled");const s=n.store.getRun(n.requestId),c=new Set((s?.events??[]).flatMap(t));if(!i.some(e=>c.has(e)))throw n.emit({type:"execution.contract.failed",requestId:n.requestId,sessionId:n.sessionId,agentId:n.agent.id,reason:"missing_plan"}),new Error(`Execution contract requires a planning checkpoint from one of: ${i.join(", ")}`)}(r),function(n){const r=o(e(n.agent).requiredEvidenceTools);if(0===r.length)return;const i=n.store.getRun(n.requestId),s=new Set((i?.events??[]).flatMap(t)),c=r.filter(e=>!s.has(e));if(0!==c.length)throw n.emit({type:"execution.contract.failed",requestId:n.requestId,sessionId:n.sessionId,agentId:n.agent.id,reason:"missing_required_evidence",missingEvidenceTools:c}),new Error(`Execution contract missing required evidence tools: ${c.join(", ")}`)}(r))}function e(e){return n(e.config.executionContract)?e.config.executionContract:{}}function t(e){return"tool.completed"===e.type?[e.toolId]:"adapter.event"===e.type&&n(e.event)&&"tool.result"===e.event.phase&&"string"==typeof e.event.toolId?[e.event.toolId]:[]}function n(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}function o(e){return Array.isArray(e)?e.filter(e=>"string"==typeof e&&e.length>0):[]}
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 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?[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):[]}
@@ -1,5 +1,6 @@
1
1
  export * from "./runtime/persistence/artifacts.js";
2
2
  export * from "./execution-contract.js";
3
+ export * from "./recovery/tool-call.js";
3
4
  export * from "./runtime/persistence/inspection.js";
4
5
  export * from "./memory-plugins.js";
5
6
  export * from "./runtime/persistence/queue.js";
@@ -7,4 +8,6 @@ export * from "./runtime.js";
7
8
  export * from "./runtime/persistence/stores.js";
8
9
  export * from "./trace.js";
9
10
  export * from "./types.js";
11
+ export * from "./evaluations/index.js";
12
+ export * from "./spec-driven/index.js";
10
13
  export * from "./workflows/index.js";
@@ -1 +1 @@
1
- export*from"./runtime/persistence/artifacts.js";export*from"./execution-contract.js";export*from"./runtime/persistence/inspection.js";export*from"./memory-plugins.js";export*from"./runtime/persistence/queue.js";export*from"./runtime.js";export*from"./runtime/persistence/stores.js";export*from"./trace.js";export*from"./types.js";export*from"./workflows/index.js";
1
+ export*from"./runtime/persistence/artifacts.js";export*from"./execution-contract.js";export*from"./recovery/tool-call.js";export*from"./runtime/persistence/inspection.js";export*from"./memory-plugins.js";export*from"./runtime/persistence/queue.js";export*from"./runtime.js";export*from"./runtime/persistence/stores.js";export*from"./trace.js";export*from"./types.js";export*from"./evaluations/index.js";export*from"./spec-driven/index.js";export*from"./workflows/index.js";
@@ -1 +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(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??u(e.workspace)},s=[];for(const t of e.targets)s.push(await o(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 c=s(t.workspace,t.agent,{input:"",sessionId:t.sessionId},o),d=i(await a.search({namespace:c,query:t.prompt,limit:e.limit??100}),await a.search({namespace:c,query:"",limit:e.limit??100}));n.push(...await a.consolidate({records:d}))}return{operations:n}}}}export function createSkillCandidateMinerTarget(e){return{name:"skillCandidateMiner",async run(t){const n=await async function(e,t){const n=[];for(const o of a(t.workspace,"all")){const a=r(e??[],o.provider);if(!a)continue;const c=s(t.workspace,t.agent,{input:"",sessionId:t.sessionId},o);n.push(...i(await a.search({namespace:c,query:t.prompt,limit:100}),await a.search({namespace:c,query:"",limit:100})))}return i(n,[])}(e.providers,t),o=function(e){const t=new Map;for(const n of e){const e=c(n);e&&t.set(e,[...t.get(e)??[],n])}return t}(n),m=[];for(const[n,a]of o){if(a.length<(e.minEvidenceCount??3))continue;const r=await e.store.upsert(d(t.workspace,n,a));m.push(r),t.emit({type:"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:m.length}}}}}async function o(t,n){t.emit({type:"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:"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:"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 i(e,t){const n=new Map;for(const a of[...e,...t])n.set(a.id,a);return[...n.values()]}function c(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(e){return e.toLowerCase().replace(/[^a-z0-9]+/gu,"-").replace(/^-+|-+$/gu,"")}(r):void 0}function d(e,t,a){const r=function(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:m(r,a),evidence:a.map(e=>({evidenceType:"memory_record",evidenceRef:e.id,summary:e.summary??e.content.slice(0,160),weight:e.confidence}))}}function m(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 u(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"}
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"}
@@ -1 +1 @@
1
- export function resolveEnabledMemories(r,o="all"){const n=r.runtime.memory??{};if(!function(r,o){return!1!==r.enabled&&("recall"!==o||!1!==r.recall&&!1!==r.read&&!1!==e(r,"LangMem","read"))&&("write"!==o||!1!==r.write&&!1!==e(r,"LangMem","write"))}(n,o))return[];const t=Array.isArray(n.refs)?n.refs.filter(e=>"string"==typeof e):[];return(t.length>0?t:[...r.memories.keys()]).map(e=>r.memories.get(e)).filter(e=>Boolean(e?.enabled))}export function resolvePluginNamespace(e,r,o,n){const t=readWorkspaceId(e),i=n.profile??n.id;return"agent"===i?`${t}:agent:${r.id}:${n.id}`:"user"===i?`${t}:user:${function(e){return e.metadata?.userId??"local"}(o)}:${n.id}`:"session"===i?`${t}:session:${o.sessionId??"default"}:${n.id}`:`${t}:${i}:${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 e(e,r,o){const n=readRecord(e[r])??readRecord(e[r.toLowerCase()]);return"boolean"==typeof n?.[o]?n[o]:void 0}
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}
@@ -1 +1 @@
1
- import{formatError as e,readRecord as r,readWorkspaceId as t,resolveEnabledMemories as n,resolveMemoryProvider as o,resolvePluginNamespace as s}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 a(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=>async function(e,r){const t=o(e.providers??[],r.provider);if(!t)return;const n=s(e.workspace,e.agent,e.request,r),a=await t.search({namespace:n,query:i(e),limit:c(e.workspace)});return{namespace:n,records:a,context:a.map(e=>`- ${e.summary??e.content}\n ${e.content}`).join("\n")}}(e,r)));return t.filter(e=>Boolean(e?.context))}async function a(r,t){const n=o(r.providers??[],t.provider);if(!n)return;const a=s(r.workspace,r.agent,r.request,t);r.emit({type:"memory.plugin.started",requestId:r.requestId,sessionId:r.sessionId,agentId:r.agent.id,memoryId:t.id,provider:n.name,namespace:a});try{const e=await n.propose(function(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,a));r.emit({type:"memory.plugin.completed",requestId:r.requestId,sessionId:r.sessionId,agentId:r.agent.id,memoryId:t.id,provider:n.name,namespace:a,candidateCount:e.length})}catch(o){r.emit({type:"memory.plugin.failed",requestId:r.requestId,sessionId:r.sessionId,agentId:r.agent.id,memoryId:t.id,provider:n.name,namespace:a,error:e(o)})}}function i(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=(o=e.request.metadata,"string"==typeof o?.recentContext?o.recentContext.slice(0,3e3):Array.isArray(o?.recentTurns)?o.recentTurns.filter(e=>"string"==typeof e).slice(-6).join("\n").slice(0,3e3):void 0);var o;return n?[...r,`recent_context: ${n}`].join("\n"):r.join("\n")}function c(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}
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}
@@ -6,8 +6,23 @@ export declare function buildResultRecoveryRequest(input: {
6
6
  request: RuntimeRequest;
7
7
  output: string;
8
8
  events: RuntimeEvent[];
9
+ availableToolIds?: string[];
10
+ policy: unknown;
11
+ }): RuntimeRequest | undefined;
12
+ export declare function buildExecutionContractRecoveryRequest(input: {
13
+ request: RuntimeRequest;
14
+ events: RuntimeEvent[];
9
15
  policy: unknown;
10
16
  }): RuntimeRequest | undefined;
11
17
  export declare function assertNoRawToolCallOutput(output: string, policy: unknown): void;
12
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;
13
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;
@@ -1 +1 @@
1
- export function toolCallRecoveryEnabled(t){return!0===o(t).enabled}export function isRecoverableAdapterError(t,e){const n=o(e);if(!0!==n.enabled)return!1;const a=t instanceof Error?t.message:String(t);return r(n.adapterErrorPatterns,[/XML syntax error|tool.?call.*syntax|malformed.*(?:XML|tool)|Non string tool message content/iu]).some(t=>t.test(a))}export function buildAdapterErrorRecoveryPrompt(e,r,n){const a=r instanceof Error?r.message:String(r),l=o(n).instruction;return t(e,["Stable runtime recovery: the backend failed while parsing a tool call.",`Parser error: ${a}`,"string"==typeof l?l:"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(r){const a=o(r.policy);if(!0!==a.enabled)return;if(e(r.output,a))return t(r.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, then return a final human-readable answer. Do not print XML, JSON, or pseudo tool-call text in the final answer.","","Previous invalid final answer:",r.output]);const l=function(t,e){const o=(r=e.eventRecoveryHints,(Array.isArray(r)?r:[]).flatMap(t=>n(t)&&"string"==typeof t.instruction?[{..."string"==typeof t.toolId?{toolId:t.toolId}:{},..."string"==typeof t.phase?{phase:t.phase}:{},..."string"==typeof t.outputIncludes?{outputIncludes:t.outputIncludes}:{},instruction:t.instruction}]:[]));var r;if(0!==o.length)return t.flatMap(t=>function(t,e){const o="adapter.event"===t.type&&n(t.event)?t.event:void 0;return o?e.filter(t=>function(t,e){return(!e.toolId||t.toolId===e.toolId)&&(!e.phase||t.phase===e.phase)&&(!e.outputIncludes||"string"==typeof t.output&&t.output.includes(e.outputIncludes))}(o,t)).map(t=>({output:"string"==typeof o.output?o.output:"Adapter event matched configured recovery hint.",instruction:t.instruction})):[]}(t,o)).at(-1)}(r.events,a);return l?t(r.request,["Stable runtime recovery: a previous adapter event matched a configured recovery hint.",l.output,l.instruction]):void 0}export function assertNoRawToolCallOutput(t,e){if(containsRawToolCallOutput(t,e))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.")}export function containsRawToolCallOutput(t,r){const n=o(r);return!0===n.enabled&&e(t,n)}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(" ")}function t(t,e){return{...t,input:[t.input,"",...e].join("\n"),metadata:{...t.metadata,stableHarnessRecovery:"tool_call"}}}function e(t,e){return r(e.rawOutputPatterns,[/<\s*(?:tool_call|task)\b[^>]*>/iu,/<\s*\/\s*(?:tool_call|task)\s*>/iu]).some(e=>e.test(t))}function o(t){if(!n(t))return{};const e=n(t.recovery)?t.recovery:{};return n(e.toolCall)?e.toolCall:{}}function r(t,e){const o=(Array.isArray(t)?t:[]).filter(t=>"string"==typeof t&&t.length>0).map(t=>new RegExp(t,"iu"));return o.length>0?o:e}function n(t){return"object"==typeof t&&null!==t&&!Array.isArray(t)}
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=recentToolEvidence(e.events,6e3);return 0!==o.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,o):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,o):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)}
@@ -1 +1 @@
1
- export function completeRun(e){const s=e.store.getRun(e.requestId);if("cancelled"===s?.state)return t(e,"cancelled");s&&e.store.updateRun(e.requestId,{state:"completed",output:e.result.text,metadata:{...s.metadata,...e.result.metadata},artifacts:[...s.artifacts,...e.result.artifacts??[]],completedAt:(new Date).toISOString()});for(const t of e.result.artifacts??[])e.emit({type:"artifact.created",requestId:e.requestId,sessionId:e.sessionId,agentId:e.agent.id,artifact:t});return e.emit({type:"request.completed",requestId:e.requestId,sessionId:e.sessionId,agentId:e.agent.id,output:e.result.text}),t(e,"completed")}export function failRun(t){const e=t.error instanceof Error?t.error.message:String(t.error);return t.store.getRun(t.requestId)&&t.store.updateRun(t.requestId,{state:"failed",error:e,completedAt:(new Date).toISOString()}),t.emit({type:"request.failed",requestId:t.requestId,sessionId:t.sessionId,agentId:t.agent.id,error:e}),{requestId:t.requestId,sessionId:t.sessionId,agentId:t.agent.id,state:"failed",output:e}}function t(t,e){return{requestId:t.requestId,sessionId:t.sessionId,agentId:t.agent.id,state:e,output:t.result.text,metadata:t.result.metadata,artifacts:t.result.artifacts}}
1
+ export function completeRun(e){const t=e.store.getRun(e.requestId);if("cancelled"===t?.state)return response(e,"cancelled",t.artifacts);if(t){const s=function mergeArtifacts(e,t){const s=new Map;for(const r of[...e??[],...t??[]])s.set(r.id,r);return[...s.values()]}(t.artifacts,e.result.artifacts??[]);e.store.updateRun(e.requestId,{state:"completed",output:e.result.text,metadata:{...t.metadata,...e.result.metadata},artifacts:s,completedAt:(new Date).toISOString()})}for(const t of e.result.artifacts??[])e.emit({type:"runtime.artifact.created",requestId:e.requestId,sessionId:e.sessionId,agentId:e.agent.id,artifact:t});return e.emit({type:"runtime.request.completed",requestId:e.requestId,sessionId:e.sessionId,agentId:e.agent.id,output:e.result.text}),response(e,"completed",e.store.getRun(e.requestId)?.artifacts)}export function failRun(e){const t=e.error instanceof Error?e.error.message:String(e.error);return e.store.getRun(e.requestId)&&e.store.updateRun(e.requestId,{state:"failed",error:t,completedAt:(new Date).toISOString()}),e.emit({type:"runtime.request.failed",requestId:e.requestId,sessionId:e.sessionId,agentId:e.agent.id,error:t}),{requestId:e.requestId,sessionId:e.sessionId,agentId:e.agent.id,state:"failed",output:t}}function response(e,t,s){return{requestId:e.requestId,sessionId:e.sessionId,agentId:e.agent.id,state:t,output:e.result.text,metadata:e.result.metadata,artifacts:s??e.result.artifacts}}
@@ -1 +1 @@
1
- export async function runDirectToolCall(o){const t=o.request.toolCall;if(!t)throw new Error("Direct tool call request is missing");if(!o.gateway)throw new Error("Runtime tool gateway is not configured");const e=await async function(o){if(o.agent.tools.includes(o.toolId)&&o.gateway.get(o.toolId))return{toolId:o.toolId,args:o.args};const t=await(o.gateway.repairToolCall?.({toolId:o.toolId,args:o.args,allowedToolIds:o.agent.tools,context:{workspaceRoot:o.workspace.root,requestId:o.requestId,sessionId:o.sessionId,agentId:o.agent.id}}));if(t&&o.agent.tools.includes(t.toolId)&&o.gateway.get(t.toolId))return t;if(!o.agent.tools.includes(o.toolId))throw new Error(`Tool ${o.toolId} is not assigned to agent ${o.agent.id}`);throw new Error(`Tool is not registered: ${o.toolId}`)}({gateway:o.gateway,workspace:o.workspace,requestId:o.requestId,sessionId:o.sessionId,agent:o.agent,toolId:t.toolId,args:t.args});o.emit({type:"tool.started",requestId:o.requestId,sessionId:o.sessionId,agentId:o.agent.id,toolId:e.toolId});const s=await o.gateway.invoke({toolId:e.toolId,args:e.args,context:{workspaceRoot:o.workspace.root,requestId:o.requestId,sessionId:o.sessionId,agentId:o.agent.id}});return o.emit({type:"tool.completed",requestId:o.requestId,sessionId:o.sessionId,agentId:o.agent.id,toolId:s.toolId,output:s.output}),{text:(a=s.output,"string"==typeof a?a:JSON.stringify(a)),metadata:{toolCall:{toolId:s.toolId}}};var a}
1
+ export async function runDirectToolCall(o){const t=o.request.toolCall;if(!t)throw new Error("Direct tool call request is missing");if(!o.gateway)throw new Error("Runtime tool gateway is not configured");const e=await async function resolveDirectToolCall(o){if(o.agent.tools.includes(o.toolId)&&o.gateway.get(o.toolId))return{toolId:o.toolId,args:o.args};const t=await(o.gateway.repairToolCall?.({toolId:o.toolId,args:o.args,allowedToolIds:o.agent.tools,context:{workspaceRoot:o.workspace.root,requestId:o.requestId,sessionId:o.sessionId,agentId:o.agent.id}}));if(t&&o.agent.tools.includes(t.toolId)&&o.gateway.get(t.toolId))return t;if(!o.agent.tools.includes(o.toolId))throw new Error(`Tool ${o.toolId} is not assigned to agent ${o.agent.id}`);throw new Error(`Tool is not registered: ${o.toolId}`)}({gateway:o.gateway,workspace:o.workspace,requestId:o.requestId,sessionId:o.sessionId,agent:o.agent,toolId:t.toolId,args:t.args});o.emit({type:"runtime.tool.direct.started",requestId:o.requestId,sessionId:o.sessionId,agentId:o.agent.id,toolId:e.toolId});const s=await o.gateway.invoke({toolId:e.toolId,args:e.args,context:{workspaceRoot:o.workspace.root,requestId:o.requestId,sessionId:o.sessionId,agentId:o.agent.id}});return o.emit({type:"runtime.tool.direct.completed",requestId:o.requestId,sessionId:o.sessionId,agentId:o.agent.id,toolId:s.toolId,output:s.output}),{text:(r=s.output,"string"==typeof r?r:JSON.stringify(r)),metadata:{toolCall:{toolId:s.toolId}}};var r}
@@ -2,62 +2,108 @@ import type { MemoryCandidate, MemoryDecision, MemoryRecord } from "@stable-harn
2
2
  import type { ApprovalRequest } from "@stable-harness/governance";
3
3
  import type { RuntimeArtifact } from "../types.js";
4
4
  export type RuntimeEvent = {
5
- type: "request.started";
5
+ type: "runtime.request.started";
6
6
  requestId: string;
7
7
  sessionId: string;
8
8
  agentId: string;
9
+ input?: string;
9
10
  } | {
10
- type: "request.completed";
11
+ type: "runtime.request.completed";
11
12
  requestId: string;
12
13
  sessionId: string;
13
14
  agentId: string;
14
15
  output: string;
15
16
  } | {
16
- type: "request.failed";
17
+ type: "runtime.request.failed";
17
18
  requestId: string;
18
19
  sessionId: string;
19
20
  agentId: string;
20
21
  error: string;
21
22
  } | {
22
- type: "request.cancelled";
23
+ type: "runtime.request.cancelled";
23
24
  requestId: string;
24
25
  sessionId: string;
25
26
  agentId: string;
26
27
  reason?: string;
27
28
  } | {
28
- type: "artifact.created";
29
+ type: "runtime.artifact.created";
29
30
  requestId: string;
30
31
  sessionId: string;
31
32
  agentId: string;
32
33
  artifact: RuntimeArtifact;
33
34
  } | {
34
- type: "execution.contract.failed";
35
+ type: "runtime.execution.contract.failed";
35
36
  requestId: string;
36
37
  sessionId: string;
37
38
  agentId: string;
38
39
  reason: string;
39
40
  missingEvidenceTools?: string[];
40
41
  } | {
41
- type: "tool.started";
42
+ type: "runtime.tool.direct.started";
42
43
  requestId: string;
43
44
  sessionId: string;
44
45
  agentId: string;
45
46
  toolId: string;
46
47
  } | {
47
- type: "tool.completed";
48
+ type: "runtime.tool.direct.completed";
48
49
  requestId: string;
49
50
  sessionId: string;
50
51
  agentId: string;
51
52
  toolId: string;
52
53
  output: unknown;
53
54
  } | {
54
- type: "memory.lifecycle";
55
+ type: "runtime.workflow.started";
56
+ requestId: string;
57
+ sessionId: string;
58
+ agentId: string;
59
+ workflowId: string;
60
+ adapter: string;
61
+ } | {
62
+ type: "runtime.workflow.completed";
63
+ requestId: string;
64
+ sessionId: string;
65
+ agentId: string;
66
+ workflowId: string;
67
+ adapter: string;
68
+ } | {
69
+ type: "runtime.specDriven.phase.started";
70
+ requestId: string;
71
+ sessionId: string;
72
+ agentId: string;
73
+ phaseId: string;
74
+ workflowId?: string;
75
+ } | {
76
+ type: "runtime.specDriven.phase.blocked";
77
+ requestId: string;
78
+ sessionId: string;
79
+ agentId: string;
80
+ phaseId: string;
81
+ workflowId?: string;
82
+ reason: string;
83
+ } | {
84
+ type: "runtime.specDriven.phase.completed";
85
+ requestId: string;
86
+ sessionId: string;
87
+ agentId: string;
88
+ phaseId: string;
89
+ workflowId?: string;
90
+ artifact?: RuntimeArtifact;
91
+ } | {
92
+ type: "runtime.specDriven.phase.verified";
93
+ requestId: string;
94
+ sessionId: string;
95
+ agentId: string;
96
+ phaseId: string;
97
+ workflowId?: string;
98
+ artifact?: RuntimeArtifact;
99
+ } | {
100
+ type: "runtime.memory.lifecycle";
55
101
  requestId: string;
56
102
  sessionId: string;
57
103
  agentId: string;
58
104
  hook: RuntimeMemoryHook;
59
105
  } | {
60
- type: "memory.recall.completed";
106
+ type: "runtime.memory.recall.completed";
61
107
  requestId: string;
62
108
  sessionId: string;
63
109
  agentId: string;
@@ -65,7 +111,7 @@ export type RuntimeEvent = {
65
111
  recordIds: string[];
66
112
  context: string;
67
113
  } | {
68
- type: "memory.candidate.submitted";
114
+ type: "runtime.memory.candidate.submitted";
69
115
  requestId: string;
70
116
  sessionId: string;
71
117
  agentId: string;
@@ -73,13 +119,13 @@ export type RuntimeEvent = {
73
119
  decision: MemoryDecision;
74
120
  record?: MemoryRecord;
75
121
  } | {
76
- type: "memory.approval.requested";
122
+ type: "runtime.memory.approval.requested";
77
123
  requestId: string;
78
124
  sessionId: string;
79
125
  agentId: string;
80
126
  approval: ApprovalRequest;
81
127
  } | {
82
- type: "memory.plugin.started";
128
+ type: "runtime.memory.plugin.started";
83
129
  requestId: string;
84
130
  sessionId: string;
85
131
  agentId: string;
@@ -87,7 +133,7 @@ export type RuntimeEvent = {
87
133
  provider: string;
88
134
  namespace: string;
89
135
  } | {
90
- type: "memory.plugin.completed";
136
+ type: "runtime.memory.plugin.completed";
91
137
  requestId: string;
92
138
  sessionId: string;
93
139
  agentId: string;
@@ -96,7 +142,7 @@ export type RuntimeEvent = {
96
142
  namespace: string;
97
143
  candidateCount: number;
98
144
  } | {
99
- type: "memory.plugin.failed";
145
+ type: "runtime.memory.plugin.failed";
100
146
  requestId: string;
101
147
  sessionId: string;
102
148
  agentId: string;
@@ -105,27 +151,27 @@ export type RuntimeEvent = {
105
151
  namespace: string;
106
152
  error: string;
107
153
  } | {
108
- type: "memory.maintenance.started";
154
+ type: "runtime.memory.maintenance.started";
109
155
  requestId: string;
110
156
  sessionId: string;
111
157
  agentId: string;
112
158
  target: string;
113
159
  } | {
114
- type: "memory.maintenance.completed";
160
+ type: "runtime.memory.maintenance.completed";
115
161
  requestId: string;
116
162
  sessionId: string;
117
163
  agentId: string;
118
164
  target: string;
119
165
  operationCount: number;
120
166
  } | {
121
- type: "memory.maintenance.failed";
167
+ type: "runtime.memory.maintenance.failed";
122
168
  requestId: string;
123
169
  sessionId: string;
124
170
  agentId: string;
125
171
  target: string;
126
172
  error: string;
127
173
  } | {
128
- type: "skill.candidate.created";
174
+ type: "runtime.skill.candidate.created";
129
175
  requestId: string;
130
176
  sessionId: string;
131
177
  agentId: string;
@@ -136,7 +182,18 @@ export type RuntimeEvent = {
136
182
  status: string;
137
183
  proposedPath?: string;
138
184
  } | {
139
- type: "adapter.event";
185
+ type: "runtime.progress.narration";
186
+ requestId: string;
187
+ sessionId: string;
188
+ agentId: string;
189
+ message: string;
190
+ provider: string;
191
+ sourceEventTypes: string[];
192
+ sourceEventIds?: string[];
193
+ model?: string;
194
+ style?: string;
195
+ } | {
196
+ type: "runtime.adapter.event";
140
197
  requestId: string;
141
198
  sessionId: string;
142
199
  agentId: string;
@@ -1 +1 @@
1
- export function emitMemoryLifecycle(e,t,r,s,n,o){e&&t({type:"memory.lifecycle",requestId:r,sessionId:s,agentId:n,hook:o})}export async function runMemoryRecall(t){if(!t.memory)return;if(emitMemoryLifecycle(t.memory,t.emit,t.requestId,t.sessionId,t.agent.id,"read-before-plan"),!1===t.request.memory?.recall)return;const r=e(t.workspace,t.agent,t.request),s=t.request.memory?.recall?.query??t.request.input,n=await t.memory.recall({namespace:r,query:s,limit:t.request.memory?.recall?.limit});return t.emit({type:"memory.recall.completed",requestId:t.requestId,sessionId:t.sessionId,agentId:t.agent.id,namespace:r,recordIds:n.records.map(e=>e.id),context:n.context}),{namespace:r,records:n.records,context:n.context}}export async function submitMemoryCandidates(t){if(!t.memory||!t.request.memory?.candidates?.length)return;emitMemoryLifecycle(t.memory,t.emit,t.requestId,t.sessionId,t.agent.id,"write-after-run");const r=e(t.workspace,t.agent,t.request);for(const e of t.request.memory.candidates){const s={...e,namespace:e.namespace??r},n=await t.memory.submitCandidate(s);if(t.emit({type:"memory.candidate.submitted",requestId:t.requestId,sessionId:t.sessionId,agentId:t.agent.id,candidate:n.candidate,decision:n.decision,record:n.record}),"review"===n.decision.action&&t.approvals){const e=await t.approvals.create({kind:"memory_write",reason:n.decision.reason,requestId:t.requestId,sessionId:t.sessionId,agentId:t.agent.id,subject:{candidate:n.candidate,decision:n.decision}});t.emit({type:"memory.approval.requested",requestId:t.requestId,sessionId:t.sessionId,agentId:t.agent.id,approval:e})}}}function e(e,t,r){return r.memory?.namespace??`${e.root}:${t.id}`}
1
+ export function emitMemoryLifecycle(e,r,t,s,o,n){e&&r({type:"runtime.memory.lifecycle",requestId:t,sessionId:s,agentId:o,hook:n})}export async function runMemoryRecall(e){if(!e.memory)return;if(emitMemoryLifecycle(e.memory,e.emit,e.requestId,e.sessionId,e.agent.id,"read-before-plan"),!1===e.request.memory?.recall)return;const r=resolveMemoryNamespace(e.workspace,e.agent,e.request),t=e.request.memory?.recall?.query??e.request.input,s=await e.memory.recall({namespace:r,query:t,limit:e.request.memory?.recall?.limit});return e.emit({type:"runtime.memory.recall.completed",requestId:e.requestId,sessionId:e.sessionId,agentId:e.agent.id,namespace:r,recordIds:s.records.map(e=>e.id),context:s.context}),{namespace:r,records:s.records,context:s.context}}export async function submitMemoryCandidates(e){if(!e.memory||!e.request.memory?.candidates?.length)return;emitMemoryLifecycle(e.memory,e.emit,e.requestId,e.sessionId,e.agent.id,"write-after-run");const r=resolveMemoryNamespace(e.workspace,e.agent,e.request);for(const t of e.request.memory.candidates){const s={...t,namespace:t.namespace??r},o=await e.memory.submitCandidate(s);if(e.emit({type:"runtime.memory.candidate.submitted",requestId:e.requestId,sessionId:e.sessionId,agentId:e.agent.id,candidate:o.candidate,decision:o.decision,record:o.record}),"review"===o.decision.action&&e.approvals){const r=await e.approvals.create({kind:"memory_write",reason:o.decision.reason,requestId:e.requestId,sessionId:e.sessionId,agentId:e.agent.id,subject:{candidate:o.candidate,decision:o.decision}});e.emit({type:"runtime.memory.approval.requested",requestId:e.requestId,sessionId:e.sessionId,agentId:e.agent.id,approval:r})}}}function resolveMemoryNamespace(e,r,t){return t.memory?.namespace??`${e.root}:${r.id}`}
@@ -1 +1 @@
1
- import{existsSync as t,mkdirSync as e,readFileSync as r,writeFileSync as n}from"node:fs";import i from"node:path";export function createInMemoryArtifactStore(t){const e=new Map((t?.records??[]).map(t=>[t.id,s(t)])),r=new Map(Object.entries(t?.contents??{}).map(([t,e])=>[t,structuredClone(e)]));return{createArtifact(t){const n=function(t){return{id:t.id,kind:t.kind,uri:t.uri,metadata:t.metadata,requestId:t.requestId,sessionId:t.sessionId,agentId:t.agentId,contentType:t.contentType,createdAt:t.createdAt??(new Date).toISOString(),size:(e=t.content,Buffer.byteLength(JSON.stringify(e??null),"utf8"))};var e}(t);return e.set(n.id,n),r.set(n.id,structuredClone(t.content??null)),s(n)},listArtifacts:t=>[...e.values()].filter(e=>function(t,e){return!e||!(e.requestId&&e.requestId!==t.requestId||e.sessionId&&e.sessionId!==t.sessionId||e.agentId&&e.agentId!==t.agentId)}(e,t)).map(s),readArtifact(t){if(!r.has(t))throw new Error(`Artifact not found: ${t}`);return structuredClone(r.get(t))}}}export function createJsonFileArtifactStore(s){const o=i.resolve(s),c=createInMemoryArtifactStore(function(e){if(!t(e))return{records:[],contents:{}};const n=JSON.parse(r(e,"utf8"));if("object"!=typeof(i=n)||null===i||!Array.isArray(i.records)||"object"!=typeof i.contents)throw new Error(`Invalid artifact store file: ${e}`);var i;return n}(o));return{createArtifact(t){const r=c.createArtifact(t);return function(t,r){e(i.dirname(t),{recursive:!0}),n(t,`${JSON.stringify({version:1,...r},null,2)}\n`)}(o,function(t){const e=t.listArtifacts(),r=Object.fromEntries(e.map(e=>[e.id,t.readArtifact(e.id)]));return{records:e,contents:r}}(c)),r},listArtifacts:t=>c.listArtifacts(t),readArtifact:t=>c.readArtifact(t)}}function s(t){return structuredClone(t)}
1
+ import{existsSync as t,mkdirSync as e,readFileSync as r,writeFileSync as n}from"node:fs";import i from"node:path";export function createInMemoryArtifactStore(t){const e=new Map((t?.records??[]).map(t=>[t.id,cloneRecord(t)])),r=new Map(Object.entries(t?.contents??{}).map(([t,e])=>[t,structuredClone(e)]));return{createArtifact(t){const n=function toRecord(t){return{id:t.id,kind:t.kind,uri:t.uri,metadata:t.metadata,requestId:t.requestId,sessionId:t.sessionId,agentId:t.agentId,contentType:t.contentType,createdAt:t.createdAt??(new Date).toISOString(),size:(e=t.content,Buffer.byteLength(JSON.stringify(e??null),"utf8"))};var e}(t);return e.set(n.id,n),r.set(n.id,structuredClone(t.content??null)),cloneRecord(n)},listArtifacts:t=>[...e.values()].filter(e=>function matchesFilter(t,e){return!e||!(e.requestId&&e.requestId!==t.requestId||e.sessionId&&e.sessionId!==t.sessionId||e.agentId&&e.agentId!==t.agentId)}(e,t)).map(cloneRecord),readArtifact(t){if(!r.has(t))throw new Error(`Artifact not found: ${t}`);return structuredClone(r.get(t))}}}export function createJsonFileArtifactStore(c){const o=i.resolve(c),s=createInMemoryArtifactStore(function readArtifactFile(e){if(!t(e))return{records:[],contents:{}};const n=JSON.parse(r(e,"utf8"));if(!function isState(t){return"object"==typeof t&&null!==t&&Array.isArray(t.records)&&"object"==typeof t.contents}(n))throw new Error(`Invalid artifact store file: ${e}`);return n}(o));return{createArtifact(t){const r=s.createArtifact(t);return function writeArtifactFile(t,r){e(i.dirname(t),{recursive:!0}),n(t,`${JSON.stringify({version:1,...r},null,2)}\n`)}(o,function snapshot(t){const e=t.listArtifacts(),r=Object.fromEntries(e.map(e=>[e.id,t.readArtifact(e.id)]));return{records:e,contents:r}}(s)),r},listArtifacts:t=>s.listArtifacts(t),readArtifact:t=>s.readArtifact(t)}}function cloneRecord(t){return structuredClone(t)}
@@ -1 +1 @@
1
- export function projectRequestSummary(t){return{requestId:t.requestId,sessionId:t.sessionId,agentId:t.agentId,parentRunId:t.parentRunId,state:t.state,startedAt:t.startedAt,completedAt:t.completedAt,eventCount:t.events.length,artifactCount:t.artifacts.length}}export function projectSessionSummaries(t){const e=new Map;for(const n of t)e.set(n.sessionId,[...e.get(n.sessionId)??[],n]);return[...e.entries()].map(([t,e])=>function(t,e){const r=[...e].sort((t,e)=>t.startedAt.localeCompare(e.startedAt));return{sessionId:t,requestCount:e.length,agentIds:[...new Set(e.map(t=>t.agentId))].sort(),states:n(e),startedAt:r[0]?.startedAt??"",updatedAt:s(e)}}(t,e)).sort((t,e)=>e.updatedAt.localeCompare(t.updatedAt))}export function projectRequestInspection(n,s){return{summary:projectRequestSummary(s),input:s.input,output:s.output,error:s.error,metadata:s.metadata,artifacts:s.artifacts,runtimeSnapshot:t(n,s.agentId),timeline:e(s)}}function t(t,e){const n=t.agents.get(e);return{workspaceRoot:t.root,agentId:e,backend:n?.backend??"unknown",modelRef:n?.modelRef,tools:[...n?.tools??[]],skills:[...n?.skills??[]],subagents:[...n?.subagents??[]]}}function e(t){return t.events.map((t,e)=>({index:e,type:t.type,event:t}))}function n(t){return t.reduce((t,e)=>(t[e.state]=(t[e.state]??0)+1,t),{})}function s(t){return t.map(t=>t.completedAt??t.startedAt).sort((t,e)=>e.localeCompare(t))[0]??""}
1
+ import{applySpecDrivenPhaseTransition as t,createSpecDrivenWorkflowState as e}from"../../spec-driven/index.js";export function projectRequestSummary(t){return{requestId:t.requestId,sessionId:t.sessionId,agentId:t.agentId,parentRunId:t.parentRunId,state:t.state,startedAt:t.startedAt,completedAt:t.completedAt,eventCount:t.events.length,artifactCount:t.artifacts.length}}export function projectSessionSummaries(t){const e=new Map;for(const n of t)e.set(n.sessionId,[...e.get(n.sessionId)??[],n]);return[...e.entries()].map(([t,e])=>function projectSessionSummary(t,e){const n=[...e].sort((t,e)=>t.startedAt.localeCompare(e.startedAt));return{sessionId:t,requestCount:e.length,agentIds:[...new Set(e.map(t=>t.agentId))].sort(),states:countStates(e),startedAt:n[0]?.startedAt??"",updatedAt:latestTimestamp(e)}}(t,e)).sort((t,e)=>e.updatedAt.localeCompare(t.updatedAt))}export function projectRequestInspection(t,e){return{summary:projectRequestSummary(e),input:e.input,output:e.output,error:e.error,metadata:e.metadata,artifacts:e.artifacts,runtimeSnapshot:projectBindingSnapshot(t,e.agentId),...t.runtime.specDrivenWorkflow?{specDrivenWorkflow:projectSpecDrivenState(t.runtime.specDrivenWorkflow,e)}:{},timeline:projectTimeline(e)}}function projectSpecDrivenState(n,r){const s=new Set(n.phases.map(t=>t.id));return r.events.map(specDrivenTransition).filter(t=>void 0!==t&&s.has(t.phaseId)).reduce(t,e(n))}function specDrivenTransition(t){if(!function isSpecDrivenPhaseEvent(t){return t.type.startsWith("runtime.specDriven.phase.")}(t))return;const e=t.type.slice(25);return["started","blocked","completed","verified"].includes(e)?{phaseId:t.phaseId,status:e,..."artifact"in t&&t.artifact?{artifact:t.artifact}:{},..."reason"in t?{reason:t.reason}:{}}:void 0}function projectBindingSnapshot(t,e){const n=t.agents.get(e);return{workspaceRoot:t.root,agentId:e,backend:n?.backend??"unknown",modelRef:n?.modelRef,tools:[...n?.tools??[]],skills:[...n?.skills??[]],subagents:[...n?.subagents??[]]}}function projectTimeline(t){return t.events.map((t,e)=>({index:e,type:t.type,event:t}))}function countStates(t){return t.reduce((t,e)=>(t[e.state]=(t[e.state]??0)+1,t),{})}function latestTimestamp(t){return t.map(t=>t.completedAt??t.startedAt).sort((t,e)=>e.localeCompare(t))[0]??""}
@@ -1 +1 @@
1
- export function createInMemoryRuntimeQueueStore(){const s=new Map,a=new Map,o=new Map;return{enqueue(e){const t=e.enqueuedAt??(new Date).toISOString(),n=r({...e,enqueuedAt:t,attemptCount:e.attemptCount??0});return s.set(n.requestId,n),r(n)},listQueue:()=>e([...s.values()]).map(r),getQueuedRequest:e=>t(s.get(e),r),claimNext(t){const n=function(t,r){const n=Date.parse(r.now??(new Date).toISOString());return e(t).find(e=>{const t=Date.parse(e.availableAt)<=n,u=!r.queueKey||e.queueKey===r.queueKey,s=!e.leaseExpiresAt||Date.parse(e.leaseExpiresAt)<=n;return t&&u&&s})}([...s.values()],t);if(!n)return;const u=t.now??(new Date).toISOString(),o=function(e,t,r,n){return{...e,claimedBy:t,claimedAt:r,leaseExpiresAt:new Date(Date.parse(r)+n).toISOString(),attemptCount:e.attemptCount+1}}(n,t.workerId,u,t.leaseMs);return s.set(o.requestId,o),a.set(o.requestId,{requestId:o.requestId,cancelRequested:a.get(o.requestId)?.cancelRequested??!1,workerId:t.workerId,workerStartedAt:a.get(o.requestId)?.workerStartedAt??u,heartbeatAt:u}),r(o)},heartbeat(e){const t=a.get(e.requestId);if(!t||t.workerId!==e.workerId)return;const r={...t,heartbeatAt:e.now??(new Date).toISOString()};return a.set(e.requestId,r),n(r)},requestCancel(e){const t={...a.get(e.requestId),requestId:e.requestId,cancelRequested:!0,cancelReason:e.reason,cancelRequestedAt:e.now??(new Date).toISOString()};return a.set(e.requestId,t),n(t)},getControl:e=>t(a.get(e),n),listStuck(e){const t=Date.parse(e.now??(new Date).toISOString());return[...s.values()].filter(r=>function(e,t,r,n){if(!e.claimedAt)return!1;const u=Date.parse(t?.heartbeatAt??e.claimedAt);return!!e.leaseExpiresAt&&Date.parse(e.leaseExpiresAt)<r||r-u>n}(r,a.get(r.requestId),t,e.staleAfterMs)).map(r)},saveRecoveryIntent:e=>(o.set(e.requestId,u(e)),u(e)),getRecoveryIntent:e=>t(o.get(e),u),clearRecoveryIntent:e=>o.delete(e)}}function e(e){return[...e].sort((e,t)=>{const r=t.priority-e.priority;return 0===r?e.enqueuedAt.localeCompare(t.enqueuedAt):r})}function t(e,t){return e?t(e):void 0}function r(e){return structuredClone(e)}function n(e){return structuredClone(e)}function u(e){return structuredClone(e)}
1
+ export function createInMemoryRuntimeQueueStore(){const e=new Map,t=new Map,r=new Map;return{enqueue(t){const r=t.enqueuedAt??(new Date).toISOString(),n=cloneQueueRecord({...t,enqueuedAt:r,attemptCount:t.attemptCount??0});return e.set(n.requestId,n),cloneQueueRecord(n)},listQueue:()=>sortQueue([...e.values()]).map(cloneQueueRecord),getQueuedRequest:t=>cloneOptional(e.get(t),cloneQueueRecord),claimNext(r){const n=function findClaimCandidate(e,t){const r=Date.parse(t.now??(new Date).toISOString());return sortQueue(e).find(e=>{const n=Date.parse(e.availableAt)<=r,o=!t.queueKey||e.queueKey===t.queueKey,u=!e.leaseExpiresAt||Date.parse(e.leaseExpiresAt)<=r;return n&&o&&u})}([...e.values()],r);if(!n)return;const o=r.now??(new Date).toISOString(),u=function claimRecord(e,t,r,n){return{...e,claimedBy:t,claimedAt:r,leaseExpiresAt:new Date(Date.parse(r)+n).toISOString(),attemptCount:e.attemptCount+1}}(n,r.workerId,o,r.leaseMs);return e.set(u.requestId,u),t.set(u.requestId,{requestId:u.requestId,cancelRequested:t.get(u.requestId)?.cancelRequested??!1,workerId:r.workerId,workerStartedAt:t.get(u.requestId)?.workerStartedAt??o,heartbeatAt:o}),cloneQueueRecord(u)},heartbeat(e){const r=t.get(e.requestId);if(!r||r.workerId!==e.workerId)return;const n={...r,heartbeatAt:e.now??(new Date).toISOString()};return t.set(e.requestId,n),cloneControl(n)},requestCancel(e){const r={...t.get(e.requestId),requestId:e.requestId,cancelRequested:!0,cancelReason:e.reason,cancelRequestedAt:e.now??(new Date).toISOString()};return t.set(e.requestId,r),cloneControl(r)},getControl:e=>cloneOptional(t.get(e),cloneControl),listStuck(r){const n=Date.parse(r.now??(new Date).toISOString());return[...e.values()].filter(e=>function isStuck(e,t,r,n){if(!e.claimedAt)return!1;const o=Date.parse(t?.heartbeatAt??e.claimedAt);return!!e.leaseExpiresAt&&Date.parse(e.leaseExpiresAt)<r||r-o>n}(e,t.get(e.requestId),n,r.staleAfterMs)).map(cloneQueueRecord)},saveRecoveryIntent:e=>(r.set(e.requestId,cloneRecovery(e)),cloneRecovery(e)),getRecoveryIntent:e=>cloneOptional(r.get(e),cloneRecovery),clearRecoveryIntent:e=>r.delete(e)}}function sortQueue(e){return[...e].sort((e,t)=>{const r=t.priority-e.priority;return 0===r?e.enqueuedAt.localeCompare(t.enqueuedAt):r})}function cloneOptional(e,t){return e?t(e):void 0}function cloneQueueRecord(e){return structuredClone(e)}function cloneControl(e){return structuredClone(e)}function cloneRecovery(e){return structuredClone(e)}
@@ -1 +1 @@
1
- import{existsSync as e,mkdirSync as n,readFileSync as t,writeFileSync as r}from"node:fs";import u from"node:path";export function createInMemoryRuntimeStore(e=[]){const n=new Map(e.map(e=>[e.requestId,o(e)]));return{createRun(e){n.set(e.requestId,o(e))},updateRun(e,t){const r=n.get(e);if(r)return Object.assign(r,function(e){return structuredClone(e)}(t)),o(r)},appendEvent(e){const t=n.get(e.requestId);if(t)return t.events.push(function(e){return structuredClone(e)}(e)),o(t)},getRun(e){return(t=n.get(e))?o(t):void 0;var t},listRuns:e=>[...n.values()].filter(n=>function(e,n){return!n||!(n.agentId&&n.agentId!==e.agentId||n.sessionId&&n.sessionId!==e.sessionId||n.state&&n.state!==e.state)}(n,e)).map(o)}}export function createJsonFileRuntimeStore(n){const r=u.resolve(n),o=createInMemoryRuntimeStore(function(n){if(!e(n))return[];const r=JSON.parse(t(n,"utf8"));if(!a(r)||!Array.isArray(r.runs))throw new Error(`Invalid runtime store file: ${n}`);return r.runs.map(i)}(r));return{createRun(e){o.createRun(e),s(r,o.listRuns())},updateRun(e,n){const t=o.updateRun(e,n);return s(r,o.listRuns()),t},appendEvent(e){const n=o.appendEvent(e);return s(r,o.listRuns()),n},getRun:e=>o.getRun(e),listRuns:e=>o.listRuns(e)}}function s(e,t){n(u.dirname(e),{recursive:!0}),r(e,`${JSON.stringify({version:1,runs:t},null,2)}\n`)}function i(e){if(!a(e)||"string"!=typeof e.requestId)throw new Error("Invalid runtime run record in store file");return o(e)}function o(e){return structuredClone(e)}function a(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}
1
+ import{existsSync as e,mkdirSync as t,readFileSync as n,writeFileSync as r}from"node:fs";import u from"node:path";export function createInMemoryRuntimeStore(e=[]){const t=new Map(e.map(e=>[e.requestId,cloneRun(e)]));return{createRun(e){t.set(e.requestId,cloneRun(e))},updateRun(e,n){const r=t.get(e);if(r)return Object.assign(r,function clonePatch(e){return structuredClone(e)}(n)),cloneRun(r)},appendEvent(e){const n=t.get(e.requestId);if(!n)return;const r=function eventArtifact(e){return"artifact"in e&&e.artifact?e.artifact:void 0}(e);return r&&!n.artifacts.some(e=>e.id===r.id)&&n.artifacts.push(structuredClone(r)),n.events.push(function cloneEvent(e){return structuredClone(e)}(e)),cloneRun(n)},getRun:e=>function cloneOptionalRun(e){return e?cloneRun(e):void 0}(t.get(e)),listRuns:e=>[...t.values()].filter(t=>function matchesFilter(e,t){return!t||!(t.agentId&&t.agentId!==e.agentId||t.sessionId&&t.sessionId!==e.sessionId||t.state&&t.state!==e.state)}(t,e)).map(cloneRun)}}export function createJsonFileRuntimeStore(t){const r=u.resolve(t),i=createInMemoryRuntimeStore(function readStoreFile(t){if(!e(t))return[];const r=JSON.parse(n(t,"utf8"));if(!isRecord(r)||!Array.isArray(r.runs))throw new Error(`Invalid runtime store file: ${t}`);return r.runs.map(assertRunRecord)}(r));return{createRun(e){i.createRun(e),writeStoreFile(r,i.listRuns())},updateRun(e,t){const n=i.updateRun(e,t);return writeStoreFile(r,i.listRuns()),n},appendEvent(e){const t=i.appendEvent(e);return writeStoreFile(r,i.listRuns()),t},getRun:e=>i.getRun(e),listRuns:e=>i.listRuns(e)}}function writeStoreFile(e,n){t(u.dirname(e),{recursive:!0}),r(e,`${JSON.stringify({version:1,runs:n},null,2)}\n`)}function assertRunRecord(e){if(!isRecord(e)||"string"!=typeof e.requestId)throw new Error("Invalid runtime run record in store file");return cloneRun(e)}function cloneRun(e){return structuredClone(e)}function isRecord(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}
@@ -0,0 +1,33 @@
1
+ import type { RuntimeEvent } from "./events.js";
2
+ export type RuntimeProgressNarrationProvider = {
3
+ name: string;
4
+ narrate(event: RuntimeEvent, context: RuntimeProgressNarrationContext): RuntimeProgressNarrationResult;
5
+ };
6
+ export type RuntimeProgressNarrationResult = RuntimeProgressNarrationOutput | undefined | Promise<RuntimeProgressNarrationOutput | undefined>;
7
+ export type RuntimeProgressNarrationContext = {
8
+ style?: string;
9
+ model?: string;
10
+ };
11
+ export type RuntimeProgressNarrationOutput = {
12
+ message: string;
13
+ sourceEventTypes?: string[];
14
+ sourceEventIds?: string[];
15
+ model?: string;
16
+ style?: string;
17
+ };
18
+ export type RuntimeProgressNarrationOptions = {
19
+ enabled?: boolean;
20
+ style?: string;
21
+ model?: string;
22
+ provider?: RuntimeProgressNarrationProvider;
23
+ };
24
+ export declare function resolveProgressNarrator(input: {
25
+ options?: RuntimeProgressNarrationOptions | false;
26
+ policy?: Record<string, unknown>;
27
+ }): RuntimeProgressNarrationProvider | undefined;
28
+ export declare function createProgressNarrationEvent(input: {
29
+ source: RuntimeEvent;
30
+ narrator: RuntimeProgressNarrationProvider | undefined;
31
+ options?: RuntimeProgressNarrationOptions | false;
32
+ policy?: Record<string, unknown>;
33
+ }): RuntimeEvent | Promise<RuntimeEvent | undefined> | undefined;
@@ -0,0 +1 @@
1
+ export function resolveProgressNarrator(e){if(!1===e.options)return;const t=readProgressPolicy(e.policy);return e.options?.enabled??t.enabled?e.options?.provider??function createTemplateProgressNarrator(){const e=new Map,t=new Map;return{name:"template",narrate(r,n){var o;"runtime.request.started"===r.type&&(e.set(r.requestId,{language:(o=r.input??"",/\p{Script=Han}/u.test(o)?"zh":void 0),input:r.input}),t.delete(r.requestId));const i=function templateMessage(e,t){const r="zh"===t?.language;return"runtime.request.started"===e.type?r?`我开始处理这个请求:${summarizeText(e.input)}`:`I'm starting on this request: ${summarizeText(e.input)}`:"runtime.request.completed"===e.type?r?"我已经完成执行链,正在交付最终结果。":"I've finished the execution chain and am returning the final result.":"runtime.request.failed"===e.type?r?"执行链失败了,我会保留具体错误方便定位。":"The execution chain failed; I'm keeping the concrete error visible for diagnosis.":"runtime.request.cancelled"===e.type?r?"这个请求已取消,后续执行会停止。":"The request was cancelled, so the remaining execution will stop.":"runtime.tool.direct.started"===e.type?r?`我正在运行 ${e.toolId}。`:`I'm running ${e.toolId}.`:"runtime.tool.direct.completed"===e.type?r?`${e.toolId} 已返回结果,我会继续使用这份证据。`:`${e.toolId} returned; I'll keep using that evidence.`:"runtime.workflow.started"===e.type?r?`我正在启动 workflow ${e.workflowId}。`:`I'm starting workflow ${e.workflowId}.`:"runtime.workflow.completed"===e.type?r?`workflow ${e.workflowId} 已完成。`:`Workflow ${e.workflowId} is complete.`:"runtime.specDriven.phase.started"===e.type?r?`我正在进入 spec-driven 阶段 ${e.phaseId}。`:`I'm starting spec-driven phase ${e.phaseId}.`:"runtime.specDriven.phase.blocked"===e.type?r?`spec-driven 阶段 ${e.phaseId} 被 gate 阻塞。`:`Spec-driven phase ${e.phaseId} is blocked by a gate.`:"runtime.specDriven.phase.completed"===e.type?r?`spec-driven 阶段 ${e.phaseId} 已完成。`:`Spec-driven phase ${e.phaseId} is complete.`:"runtime.specDriven.phase.verified"===e.type?r?`spec-driven 阶段 ${e.phaseId} 已验证。`:`Spec-driven phase ${e.phaseId} is verified.`:"runtime.artifact.created"===e.type?r?"我已经保存一份运行产物。":"I've saved a runtime artifact.":"runtime.execution.contract.failed"===e.type?r?"运行证据没有满足执行契约,我会进入恢复或失败路径。":"The run evidence did not satisfy the execution contract, so I'll recover or fail explicitly.":"runtime.skill.candidate.created"===e.type?r?`我发现一个可沉淀的 skill 候选:${e.name}。`:`I found a reusable skill candidate: ${e.name}.`:e.type.startsWith("runtime.memory.")?function memoryMessage(e,t){return"runtime.memory.lifecycle"===e.type?t?`我进入记忆阶段:${e.hook}。`:`I'm in the memory lifecycle phase: ${e.hook}.`:"runtime.memory.recall.completed"===e.type?t?`我召回了 ${e.recordIds.length} 条相关记忆。`:`I recalled ${e.recordIds.length} relevant memory records.`:"runtime.memory.candidate.submitted"===e.type?t?"我提交了一条候选记忆。":"I submitted a memory candidate.":"runtime.memory.approval.requested"===e.type?t?"我提交了记忆审批请求。":"I requested memory approval.":"runtime.memory.plugin.started"===e.type?t?`我正在运行记忆插件 ${e.provider}。`:`I'm running memory plugin ${e.provider}.`:"runtime.memory.plugin.completed"===e.type?t?`记忆插件 ${e.provider} 已完成。`:`Memory plugin ${e.provider} completed.`:"runtime.memory.plugin.failed"===e.type?t?`记忆插件 ${e.provider} 失败了;主任务会继续,不把它当成执行结果。`:`Memory plugin ${e.provider} failed; the main task will continue without treating it as the result.`:"runtime.memory.maintenance.started"===e.type?t?`我正在维护 ${e.target} 记忆。`:`I'm maintaining ${e.target} memory.`:"runtime.memory.maintenance.completed"===e.type?t?`${e.target} 记忆维护完成。`:`${e.target} memory maintenance completed.`:"runtime.memory.maintenance.failed"===e.type?t?`${e.target} 记忆维护失败。`:`${e.target} memory maintenance failed.`:void 0}(e,r):"runtime.adapter.event"===e.type?function adapterMessage(e,t){if(isRecord(e))return"agent.handoff"===e.phase?t?"我把请求交给上游 agent backend,让它负责规划和执行。":"I'm handing the request to the upstream agent backend for planning and execution.":"agent.tool.start"===e.phase&&"string"==typeof e.toolId?function toolStartMessage(e,t,r){if("task"===e){const e=function readTaskTarget(e){const t=isRecord(e)?e:{};return readString(t.subagent_type)??readString(t.subagentType)}(t),n=function readDescription(e){const t=isRecord(e)?e:{};return summarizeText(readString(t.description)??readString(t.task))}(t);if(e&&n)return r?`我正在请求 task 工具委派给 ${e}:${n}`:`I'm asking the task tool to delegate to ${e}: ${n}`;if(e)return r?`我正在请求 task 工具委派给 ${e}。`:`I'm asking the task tool to delegate to ${e}.`}return r?`我正在运行 ${e} 收集证据。`:`I'm running ${e} to gather evidence.`}(e.toolId,e.args,t):"agent.tool.result"===e.phase&&"string"==typeof e.toolId?function toolResultMessage(e,t,r,n,o){if(r)return o?`${e} 返回错误:${summarizeText(String(r))}`:`${e} returned an error: ${summarizeText(String(r))}`;const i="string"==typeof n?n:function readToolControlStatus(e){const t=function parseToolOutputRecord(e){if(isRecord(e))return e;if("string"==typeof e)try{const t=JSON.parse(e);return isRecord(t)?t:void 0}catch{return}}(e);return"string"==typeof t?.status?t.status:"string"==typeof t?.error?t.error:"string"==typeof e&&e.startsWith("Task delegation target is not in the workspace inventory")?"task_inventory_blocked":void 0}(t);if(i)return function toolControlMessage(e,t,r){return"duplicate_tool_call"===t?r?`${e} 重复调用已复用已有证据。`:`${e} repeated an equivalent call, so the existing evidence was reused.`:"repeated_tool_call_limit"===t?r?`${e} 出现重复调用循环,我会基于已有证据继续收敛。`:`${e} entered a repeated-call loop, so I'll continue from the evidence already collected.`:"tool_argument_error"===t||"tool_argument_validation_failed"===t?r?`${e} 参数被工具 schema 拒绝,我会让 agent 修正参数或改用合适工具。`:`${e} arguments were rejected by the tool schema; I'll have the agent repair them or choose a suitable tool.`:"task_inventory_blocked"===t?r?"task 委派目标不在当前 workspace inventory 中,已被运行时策略阻止。":"The task delegation target is not in the current workspace inventory and was blocked by runtime policy.":r?`${e} 返回运行时控制状态:${t}。`:`${e} returned runtime control status: ${t}.`}(e,i,o);if("task"===e)return o?"委派任务已返回结果,我会基于这些证据继续推进。":"The delegated task returned; I'll keep going with that evidence.";const a=function summarizeToolOutput(e){if("string"==typeof e)return summarizeText(e);if(isRecord(e)){if("string"==typeof e.status)return summarizeText(e.status);if("string"==typeof e.summary)return summarizeText(e.summary)}}(t);return o?`${e} 已返回${a?`:${a}`:",我会继续判断下一步。"}`:`${e} returned${a?`: ${a}`:"; I'll decide the next step from here."}`}(e.toolId,e.output,e.error,e.controlStatus,t):"agent.langgraph.invoke"===e.phase?t?"我正在调用 workflow backend。":"I'm invoking the workflow backend.":"agent.node.completed"===e.phase&&"string"==typeof e.nodeId?t?`节点 ${e.nodeId} 已完成。`:`Node ${e.nodeId} is complete.`:void 0}(e.event,r):void 0}(r,e.get(r.requestId));if(i&&i!==t.get(r.requestId))return t.set(r.requestId,i),"runtime.request.failed"!==r.type&&"runtime.request.cancelled"!==r.type||(e.delete(r.requestId),t.delete(r.requestId)),function pruneRequestState(e,t){for(;e.size>200;){const r=e.keys().next().value;if(!r)break;e.delete(r),t.delete(r)}}(e,t),{message:i,style:n.style,model:n.model}}}}():void 0}export function createProgressNarrationEvent(e){if(!e.narrator||"runtime.progress.narration"===e.source.type)return;const t=readProgressPolicy(e.policy),r=!1===e.options?void 0:e.options,n=e.narrator.narrate(e.source,{style:r?.style??t.style,model:r?.model??t.model});return function isPromiseLike(e){return isRecord(e)&&"function"==typeof e.then}(n)?n.then(t=>toNarrationEvent(e.source,e.narrator,t)):toNarrationEvent(e.source,e.narrator,n)}function toNarrationEvent(e,t,r){if(r?.message.trim())return{type:"runtime.progress.narration",requestId:e.requestId,sessionId:e.sessionId,agentId:e.agentId,message:r.message,provider:t.name,sourceEventTypes:r.sourceEventTypes??[e.type],sourceEventIds:r.sourceEventIds,model:r.model,style:r.style}}function summarizeText(e){const t=e?.replace(/\s+/gu," ").trim();return t?t.length>120?`${t.slice(0,117)}...`:t:""}function readString(e){return"string"==typeof e&&e.trim()?e:void 0}function readProgressPolicy(e){const t=isRecord(e?.progress)?e.progress:{},r=isRecord(t.narration)?t.narration:{};return{enabled:"boolean"==typeof r.enabled?r.enabled:void 0,style:"string"==typeof r.style?r.style:void 0,model:"string"==typeof r.model?r.model:void 0}}function isRecord(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}
@@ -13,12 +13,16 @@ export type RuntimeToolGatewayTool = {
13
13
  description?: string;
14
14
  schema?: unknown;
15
15
  };
16
+ export type RuntimeToolRepairModel = {
17
+ invoke(input: unknown): Promise<unknown> | unknown;
18
+ };
16
19
  export type RuntimeToolGateway = {
17
20
  get(toolId: string): RuntimeToolGatewayTool | undefined;
18
21
  repairToolCall?(request: {
19
22
  toolId: string;
20
23
  args?: unknown;
21
24
  allowedToolIds?: string[];
25
+ repairModel?: RuntimeToolRepairModel;
22
26
  context: RuntimeToolGatewayContext;
23
27
  }): Promise<{
24
28
  toolId: string;
@@ -27,6 +31,7 @@ export type RuntimeToolGateway = {
27
31
  invoke(request: {
28
32
  toolId: string;
29
33
  args?: unknown;
34
+ repairModel?: RuntimeToolRepairModel;
30
35
  context: RuntimeToolGatewayContext;
31
36
  }): Promise<{
32
37
  toolId: string;
@@ -1,6 +1,6 @@
1
1
  import type { ApprovalQueue } from "@stable-harness/governance";
2
2
  import type { MemoryProvider, RuntimeMemoryStore } from "@stable-harness/memory";
3
- import type { CompiledWorkspace, RuntimeToolGateway, RuntimeAdapter, RuntimeStore, RuntimeWorkflowAdapter, StableHarnessRuntime } from "./types.js";
3
+ import type { CompiledWorkspace, RuntimeToolGateway, RuntimeAdapter, RuntimeStore, RuntimeProgressNarrationOptions, RuntimeWorkflowAdapter, StableHarnessRuntime } from "./types.js";
4
4
  type RuntimeFactoryInput = {
5
5
  workspace: CompiledWorkspace;
6
6
  adapters: RuntimeAdapter[];
@@ -10,6 +10,7 @@ type RuntimeFactoryInput = {
10
10
  approvals?: ApprovalQueue;
11
11
  toolGateway?: RuntimeToolGateway;
12
12
  store?: RuntimeStore;
13
+ progressNarration?: RuntimeProgressNarrationOptions | false;
13
14
  };
14
15
  export declare function createStableHarnessRuntime(input: RuntimeFactoryInput): StableHarnessRuntime;
15
16
  export {};