stable-harness 0.0.3 → 0.0.4
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.
- package/dist/cli.js +1 -1
- package/dist/compat/agent-harness.js +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -1
- package/dist/runtime/compat/agent-harness-compat-runner.js +1 -1
- package/dist/runtime/compat/json.js +1 -1
- package/dist/runtime/compat/presentation.js +1 -1
- package/dist/runtime/compat/prompts.js +1 -1
- package/dist/runtime/model/ollama.js +1 -1
- package/dist/runtime/skills/skill-metadata.js +1 -1
- package/dist/workspace/compile.js +1 -1
- package/package.json +4 -3
- package/packages/adapter-deepagents/dist/src/adapter.js +1 -1
- package/packages/adapter-deepagents/dist/src/internal/builtin-args.d.ts +4 -0
- package/packages/adapter-deepagents/dist/src/internal/builtin-args.js +1 -0
- package/packages/adapter-deepagents/dist/src/internal/builtin-tool-policy.d.ts +9 -4
- package/packages/adapter-deepagents/dist/src/internal/builtin-tool-policy.js +1 -1
- package/packages/adapter-deepagents/dist/src/internal/gateway-tools.d.ts +29 -1
- package/packages/adapter-deepagents/dist/src/internal/gateway-tools.js +1 -1
- package/packages/adapter-deepagents/dist/src/internal/messages.js +1 -1
- package/packages/adapter-deepagents/dist/src/internal/raw-tool-call-parser.d.ts +12 -0
- package/packages/adapter-deepagents/dist/src/internal/raw-tool-call-parser.js +1 -0
- package/packages/adapter-deepagents/dist/src/internal/skill-file-policy.d.ts +10 -0
- package/packages/adapter-deepagents/dist/src/internal/skill-file-policy.js +1 -0
- package/packages/adapter-deepagents/dist/src/internal/stream-events.js +1 -1
- package/packages/adapter-deepagents/dist/src/internal/tool-repeat-visibility.d.ts +4 -0
- package/packages/adapter-deepagents/dist/src/internal/tool-repeat-visibility.js +1 -0
- package/packages/adapter-deepagents/dist/src/internal/trace-projection.d.ts +1 -1
- package/packages/adapter-deepagents/dist/src/internal/trace-projection.js +1 -1
- package/packages/adapter-deepagents/dist/src/memory.js +1 -1
- package/packages/adapter-deepagents/dist/src/model-providers.d.ts +4 -0
- package/packages/adapter-deepagents/dist/src/model-providers.js +1 -0
- package/packages/adapter-deepagents/dist/src/retry-policy.js +1 -1
- package/packages/adapter-deepagents/dist/src/types.d.ts +7 -1
- package/packages/adapter-deepagents/package.json +1 -0
- package/packages/adapter-langgraph/dist/src/graph.js +1 -1
- package/packages/adapter-langgraph/dist/src/runtime.js +1 -1
- package/packages/adapter-langgraph/dist/src/skill-providers.js +1 -1
- package/packages/cli/dist/src/args.d.ts +6 -3
- package/packages/cli/dist/src/args.js +1 -1
- package/packages/cli/dist/src/cli.js +1 -1
- package/packages/cli/dist/src/event-view.d.ts +9 -0
- package/packages/cli/dist/src/event-view.js +1 -0
- package/packages/cli/dist/src/index.d.ts +3 -0
- package/packages/cli/dist/src/index.js +1 -1
- package/packages/cli/dist/src/langgraph-env.d.ts +5 -0
- package/packages/cli/dist/src/langgraph-env.js +1 -0
- package/packages/cli/dist/src/langgraph-official.d.ts +2 -0
- package/packages/cli/dist/src/langgraph-official.js +1 -1
- package/packages/cli/dist/src/memory/lifecycle.d.ts +2 -0
- package/packages/cli/dist/src/memory/lifecycle.js +1 -0
- package/packages/cli/dist/src/memory/providers.d.ts +3 -0
- package/packages/cli/dist/src/memory/providers.js +1 -0
- package/packages/cli/dist/src/output.js +1 -1
- package/packages/cli/dist/src/server.d.ts +2 -0
- package/packages/cli/dist/src/server.js +1 -1
- package/packages/cli/package.json +2 -0
- package/packages/core/dist/evaluations/index.d.ts +18 -0
- package/packages/core/dist/evaluations/index.js +1 -0
- package/packages/core/dist/execution-contract.js +1 -1
- package/packages/core/dist/index.d.ts +3 -0
- package/packages/core/dist/index.js +1 -1
- package/packages/core/dist/memory-plugins/maintenance.js +1 -1
- package/packages/core/dist/memory-plugins/shared.js +1 -1
- package/packages/core/dist/memory-plugins.js +1 -1
- package/packages/core/dist/recovery/tool-call.d.ts +15 -0
- package/packages/core/dist/recovery/tool-call.js +1 -1
- package/packages/core/dist/runtime/completion.js +1 -1
- package/packages/core/dist/runtime/direct-tool-call.js +1 -1
- package/packages/core/dist/runtime/events.d.ts +77 -20
- package/packages/core/dist/runtime/memory.js +1 -1
- package/packages/core/dist/runtime/persistence/artifacts.js +1 -1
- package/packages/core/dist/runtime/persistence/inspection.js +1 -1
- package/packages/core/dist/runtime/persistence/queue.js +1 -1
- package/packages/core/dist/runtime/persistence/stores.js +1 -1
- package/packages/core/dist/runtime/progress-narration.d.ts +33 -0
- package/packages/core/dist/runtime/progress-narration.js +1 -0
- package/packages/core/dist/runtime/tool-gateway.d.ts +5 -0
- package/packages/core/dist/runtime.d.ts +2 -1
- package/packages/core/dist/runtime.js +1 -1
- package/packages/core/dist/spec-driven/config.d.ts +4 -0
- package/packages/core/dist/spec-driven/config.js +1 -0
- package/packages/core/dist/spec-driven/events.d.ts +11 -0
- package/packages/core/dist/spec-driven/events.js +1 -0
- package/packages/core/dist/spec-driven/index.d.ts +4 -0
- package/packages/core/dist/spec-driven/index.js +1 -0
- package/packages/core/dist/spec-driven/lifecycle.d.ts +11 -0
- package/packages/core/dist/spec-driven/lifecycle.js +1 -0
- package/packages/core/dist/spec-driven/types.d.ts +38 -0
- package/packages/core/dist/spec-driven/types.js +1 -0
- package/packages/core/dist/trace.d.ts +1 -1
- package/packages/core/dist/trace.js +1 -1
- package/packages/core/dist/types.d.ts +15 -1
- package/packages/core/dist/workflows/index.js +1 -1
- package/packages/core/dist/workflows/runtime.js +1 -1
- package/packages/core/dist/workspace/types.d.ts +9 -0
- package/packages/governance/dist/src/skill-candidates.js +1 -1
- package/packages/memory/dist/src/langmem-service.js +1 -1
- package/packages/memory/dist/src/maintenance.js +1 -1
- package/packages/memory/dist/src/policy.js +1 -1
- package/packages/memory/dist/src/provider.js +1 -1
- package/packages/memory/dist/src/store.js +1 -1
- package/packages/protocols/dist/src/http-server.js +1 -1
- package/packages/protocols/dist/src/openai-compatible.js +1 -1
- package/packages/protocols/dist/src/openai-payload.js +1 -1
- package/packages/protocols/dist/src/openai-stream.js +1 -1
- package/packages/tool-gateway/dist/src/argument-guard.d.ts +2 -1
- package/packages/tool-gateway/dist/src/argument-guard.js +1 -1
- package/packages/tool-gateway/dist/src/in-memory.js +1 -1
- package/packages/tool-gateway/dist/src/module-loader.js +1 -1
- package/packages/tool-gateway/dist/src/schema-validation.js +1 -1
- package/packages/tool-gateway/dist/src/types.d.ts +3 -0
- package/packages/tool-gateway/package.json +1 -1
- package/packages/workspace-yaml/dist/discovery.js +1 -1
- package/packages/workspace-yaml/dist/documents.js +1 -1
- package/packages/workspace-yaml/dist/evaluations.d.ts +9 -0
- package/packages/workspace-yaml/dist/evaluations.js +1 -0
- package/packages/workspace-yaml/dist/loader.js +1 -1
- package/packages/workspace-yaml/dist/workflows.js +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
export function compileWorkflowPlan(
|
|
1
|
+
export function compileWorkflowPlan(e){const n=e.entry??e.nodes[0]?.id;if(!n)throw new Error(`Workflow ${e.id} has no entry node`);const t=function buildAdjacency(e){const n=new Map(e.nodes.map(e=>[e.id,[]]));for(const t of e.edges)n.get(t.from)?.push(t.to);return n}(e),o=function collectReachable(e,n){const t=new Set,o=[e];for(;o.length>0;){const e=o.pop();t.has(e)||(t.add(e),o.push(...n.get(e)??[]))}return t}(n,t),a=function findCycles(e,n){const t=[];for(const o of e)collectCycles(o,o,n,[],t);return function dedupeCycles(e){const n=new Set;return e.filter(e=>{const t=function canonicalCycleKey(e){const n=e.slice(0,-1);return n.map((e,t)=>[...n.slice(t),...n.slice(0,t)].join("|")).sort()[0]??""}(e);return!n.has(t)&&(n.add(t),!0)})}(t)}(e.nodes.map(e=>e.id),t);return{workflowId:e.id,...e.adapter?{adapter:e.adapter}:{},entry:n,nodes:e.nodes,edges:e.edges,terminalNodes:e.nodes.map(e=>e.id).filter(e=>0===(t.get(e)??[]).length),unreachableNodes:e.nodes.map(e=>e.id).filter(e=>!o.has(e)),cycles:a}}export function renderWorkflowMermaid(e){const n=["flowchart TD"];for(const t of e.nodes)n.push(` ${escapeId(t.id)}["${escapeLabel(`${t.id}\\n${t.use}`)}"]`);for(const t of e.edges){const e=t.condition?`|${escapeLabel(t.condition)}|`:"";n.push(` ${escapeId(t.from)} --\x3e${e} ${escapeId(t.to)}`)}return n.join("\n")}export function renderAgentMermaid(e,n){const t=e.agents.get(n);if(!t)throw new Error(`Agent is not defined: ${n}`);const o=function agentGraphNodes(e){return[...e.subagents.map(e=>agentGraphNode("agent",e)),...(e.skills??[]).map(e=>agentGraphNode("skill",e)),...e.tools.map(e=>agentGraphNode("tool",e))]}(t),a=["flowchart TD",` START_${escapeId(t.id)}([START])`,` END_${escapeId(t.id)}([END])`];for(const e of o)a.push(` ${e.diagramId}["${escapeLabel(`${e.id}\\n${e.label}`)}"]`);return 0===o.length?(a.push(` START_${escapeId(t.id)} --\x3e END_${escapeId(t.id)}`),a.join("\n")):[...a,...t.edges?.length?explicitAgentMermaidEdges(t,o):inventoryAgentMermaidEdges(t,o)].join("\n")}function agentGraphNode(e,n){return{id:n,diagramId:`${e}_${escapeId(n)}`,label:`${e}: ${n}`}}function explicitAgentMermaidEdges(e,n){const t=new Map(n.map(e=>[e.id,e.diagramId])),o=new Set((e.edges??[]).map(e=>e.to)),a=new Set((e.edges??[]).map(e=>e.from)),d=n.filter(e=>!o.has(e.id)).map(e=>e.diagramId),r=n.filter(e=>!a.has(e.id)).map(e=>e.diagramId);return[...d.map(n=>` START_${escapeId(e.id)} --\x3e ${escapeId(n)}`),...(e.edges??[]).flatMap(e=>function renderAgentEdge(e,n){const t=n.get(e.from),o=n.get(e.to);return t&&o?[` ${t} --\x3e${e.condition?`|${escapeLabel(e.condition)}|`:""} ${o}`]:[]}(e,t)),...r.map(n=>` ${escapeId(n)} --\x3e END_${escapeId(e.id)}`)]}function inventoryAgentMermaidEdges(e,n){return n.flatMap(n=>[` START_${escapeId(e.id)} -. available .-> ${n.diagramId}`,` ${n.diagramId} -.-> END_${escapeId(e.id)}`])}function collectCycles(e,n,t,o,a){const d=[...o,n];for(const r of t.get(n)??[])r===e?a.push([...d,e]):o.includes(r)||collectCycles(e,r,t,d,a)}function escapeId(e){return e.replace(/[^A-Za-z0-9_]/gu,"_")}function escapeLabel(e){return e.replace(/"/gu,'\\"')}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export async function runWorkflowRequest(e){const o=function(e,o){const
|
|
1
|
+
export async function runWorkflowRequest(e){const o=function resolveWorkflow(e,o){const r=o.routeId?e.runtime.workflowRouting?.routes?.find(e=>e.id===o.routeId):void 0;if(o.routeId&&!r)throw new Error(`Workflow route is not defined: ${o.routeId}`);const t=o.workflowId??r?.workflowId??e.runtime.workflowRouting?.defaultWorkflowId;if(!t)throw new Error("Workflow request requires workflowId, routeId, or runtime.workflowRouting.defaultWorkflowId");const n=e.workflows.get(t);if(!n)throw new Error(`Workflow is not defined: ${t}`);return n}(e.workspace,e.request),r=function resolveWorkflowAdapter(e,o){const r=o?e.find(e=>e.name===o):e[0];if(!r)throw new Error("No workflow adapter is configured"+(o?` for ${o}`:""));return r}(e.adapters,o.adapter);e.emit({type:"runtime.workflow.started",requestId:e.requestId,sessionId:e.sessionId,agentId:e.agentId,adapter:r.name,workflowId:o.id});const t=await r.run({workspace:e.workspace,workflow:o,request:e.request,requestId:e.requestId,sessionId:e.sessionId,toolGateway:e.toolGateway,emit:o=>e.emit({type:"runtime.adapter.event",requestId:e.requestId,sessionId:e.sessionId,agentId:e.agentId,event:o})});return e.emit({type:"runtime.workflow.completed",requestId:e.requestId,sessionId:e.sessionId,agentId:e.agentId,adapter:r.name,workflowId:o.id}),"string"==typeof t?{text:t}:t}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { WorkspaceEvaluation } from "../evaluations/index.js";
|
|
2
|
+
import type { WorkspaceSpecDrivenWorkflowPolicy } from "../spec-driven/index.js";
|
|
1
3
|
import type { WorkspaceWorkflow, WorkspaceWorkflowEdge, WorkspaceWorkflowRoutingPolicy } from "../workflows/index.js";
|
|
2
4
|
export type WorkspaceModel = {
|
|
3
5
|
id: string;
|
|
@@ -51,11 +53,17 @@ export type WorkspaceRuntimePolicy = {
|
|
|
51
53
|
profile?: string;
|
|
52
54
|
adapters?: WorkspaceAdapterPolicy[];
|
|
53
55
|
workflowRouting?: WorkspaceWorkflowRoutingPolicy;
|
|
56
|
+
specDrivenWorkflow?: WorkspaceSpecDrivenWorkflowPolicy;
|
|
54
57
|
approvals?: Record<string, unknown>;
|
|
55
58
|
recovery?: Record<string, unknown>;
|
|
56
59
|
retry?: WorkspaceRetryPolicy;
|
|
60
|
+
toolGateway?: Record<string, unknown>;
|
|
57
61
|
memory?: Record<string, unknown>;
|
|
58
62
|
protocols?: Record<string, unknown>;
|
|
63
|
+
progress?: Record<string, unknown>;
|
|
64
|
+
cli?: Record<string, unknown>;
|
|
65
|
+
responseLanguage?: Record<string, unknown>;
|
|
66
|
+
responsePresentation?: Record<string, unknown>;
|
|
59
67
|
};
|
|
60
68
|
export type WorkspaceAdapterPolicy = {
|
|
61
69
|
name: string;
|
|
@@ -89,4 +97,5 @@ export type CompiledWorkspace = {
|
|
|
89
97
|
skills: Map<string, WorkspaceSkill>;
|
|
90
98
|
memories: Map<string, WorkspaceMemory>;
|
|
91
99
|
workflows: Map<string, WorkspaceWorkflow>;
|
|
100
|
+
evaluations?: Map<string, WorkspaceEvaluation>;
|
|
92
101
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{randomUUID as e}from"node:crypto";import{mkdirSync as t}from"node:fs";import n from"node:path";import{DatabaseSync as
|
|
1
|
+
import{randomUUID as e}from"node:crypto";import{mkdirSync as t}from"node:fs";import n from"node:path";import{DatabaseSync as a}from"node:sqlite";export function createSqliteSkillCandidateStore(d){t(n.dirname(d),{recursive:!0});const r=new a(d);return function init(e){e.exec("\n create table if not exists skill_candidates (\n id text primary key, workspace_id text not null, name text not null,\n status text not null, confidence real not null, evidence_count integer not null,\n proposed_path text, title text not null, summary text not null,\n draft_markdown text not null, created_at text not null, updated_at text not null,\n reviewed_at text, reviewed_by text, rejection_reason text,\n unique(workspace_id, name)\n );\n create table if not exists skill_candidate_evidence (\n id text primary key, candidate_id text not null, evidence_type text not null,\n evidence_ref text not null, summary text, weight real, created_at text not null,\n foreign key(candidate_id) references skill_candidates(id)\n );\n ")}(r),{async upsert(t){const n=(new Date).toISOString(),a=function findByName(e,t,n){const a=e.prepare("select * from skill_candidates where workspace_id = ? and name = ?").get(t,n);return a?rowToCandidate(a):void 0}(r,t.workspaceId,t.name),d=a?function updateCandidate(e,t,n,a){return e.prepare("\n update skill_candidates\n set status = ?, confidence = ?, evidence_count = ?, proposed_path = ?,\n title = ?, summary = ?, draft_markdown = ?, updated_at = ?\n where id = ?\n ").run(n.status??"review_required",n.confidence,n.evidence.length,n.proposedPath??null,n.title,n.summary,n.draftMarkdown,a,t),readCandidate(e,t)}(r,a.id,t,n):function insertCandidate(t,n,a){const d=String(e());return t.prepare("\n insert into skill_candidates\n (id, workspace_id, name, status, confidence, evidence_count, proposed_path,\n title, summary, draft_markdown, created_at, updated_at)\n values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n ").run(d,n.workspaceId,n.name,n.status??"review_required",n.confidence,n.evidence.length,n.proposedPath??null,n.title,n.summary,n.draftMarkdown,a,a),readCandidate(t,d)}(r,t,n);return function replaceEvidence(t,n,a,d){t.prepare("delete from skill_candidate_evidence where candidate_id = ?").run(n);const r=t.prepare("\n insert into skill_candidate_evidence\n (id, candidate_id, evidence_type, evidence_ref, summary, weight, created_at)\n values (?, ?, ?, ?, ?, ?, ?)\n ");for(const t of a)r.run(String(e()),n,t.evidenceType,t.evidenceRef,t.summary??null,t.weight??null,d)}(r,d.id,t.evidence,n),d},list:async(e={})=>function listCandidates(e,t,n){return(t&&n?e.prepare("select * from skill_candidates where workspace_id = ? and status = ? order by updated_at desc").all(t,n):t?e.prepare("select * from skill_candidates where workspace_id = ? order by updated_at desc").all(t):e.prepare("select * from skill_candidates order by updated_at desc").all()).map(e=>rowToCandidate(e))}(r,e.workspaceId,e.status),get:async e=>readCandidate(r,e),listEvidence:async e=>function listEvidence(e,t){return e.prepare("select * from skill_candidate_evidence where candidate_id = ? order by created_at asc").all(t).map(e=>function rowToEvidence(e){return{id:String(e.id),candidateId:String(e.candidate_id),evidenceType:e.evidence_type,evidenceRef:String(e.evidence_ref),summary:readOptionalString(e.summary),weight:"number"==typeof e.weight?e.weight:void 0,createdAt:String(e.created_at)}}(e))}(r,e),async updateStatus(e){const t=(new Date).toISOString();return r.prepare("\n update skill_candidates\n set status = ?, reviewed_at = ?, reviewed_by = ?, rejection_reason = ?, updated_at = ?\n where id = ?\n ").run(e.status,t,e.reviewedBy??null,e.rejectionReason??null,t,e.id),readCandidate(r,e.id)}}}function readCandidate(e,t){const n=e.prepare("select * from skill_candidates where id = ?").get(t);return n?rowToCandidate(n):void 0}function rowToCandidate(e){return{id:String(e.id),workspaceId:String(e.workspace_id),name:String(e.name),status:e.status,confidence:Number(e.confidence),evidenceCount:Number(e.evidence_count),proposedPath:readOptionalString(e.proposed_path),title:String(e.title),summary:String(e.summary),draftMarkdown:String(e.draft_markdown),createdAt:String(e.created_at),updatedAt:String(e.updated_at),reviewedAt:readOptionalString(e.reviewed_at),reviewedBy:readOptionalString(e.reviewed_by),rejectionReason:readOptionalString(e.rejection_reason)}}function readOptionalString(e){return"string"==typeof e&&e?e:void 0}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export function createLangMemServiceProvider(
|
|
1
|
+
export function createLangMemServiceProvider(e){const n=function normalizeBaseUrl(e){return e.replace(/\/+$/u,"")}(e.baseUrl),t={...e.config,provider:"langmem-service"};return{name:"langmem-service",config:t,propose:async o=>(await postJson(n,"/memory/propose",{...o,config:t},e)).candidates??[],async search(o){const r=await(o.store?.list({namespace:o.namespace,kinds:o.kinds}))??[];return(await postJson(n,"/memory/search",{...withoutStore(o),records:r,config:t},e)).records??[]},consolidate:async o=>(await postJson(n,"/memory/consolidate",{...o,config:t},e)).operations??[]}}async function postJson(e,n,t,o){const r=new AbortController,a=setTimeout(()=>r.abort(),o.timeoutMs??3e4);try{const a=await fetch(`${e}${n}`,{method:"POST",headers:{"content-type":"application/json",...o.headers},body:JSON.stringify(t),signal:r.signal});return await async function readResponse(e,n){const t=await e.text();if(!e.ok)throw new Error(`LangMem service ${n} failed with ${e.status}: ${t}`);return t?JSON.parse(t):{}}(a,n)}finally{clearTimeout(a)}}function withoutStore(e){return{namespace:e.namespace,query:e.query,limit:e.limit,kinds:e.kinds,records:[]}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export async function applyMemoryMaintenance(e
|
|
1
|
+
export async function applyMemoryMaintenance(a,e){const t=[];for(const n of e)t.push(await applyOperation(a,n));return t}async function applyOperation(a,e){return"archive"===e.action?result(e,await a.archive(e.recordId,e.reason)):"mark_stale"===e.action?result(e,await a.update({id:e.recordId,status:"stale",metadata:{maintenanceReason:e.reason}})):"refresh"===e.action?result(e,await a.update({id:e.recordId,status:"active",metadata:{maintenanceReason:e.reason}})):result(e,await a.update({id:e.recordId,status:"archived",metadata:{maintenanceReason:e.reason,supersededBy:e.replacementRecordId}}))}function result(a,e){return{operation:a,record:e,applied:Boolean(e),reason:e?a.reason:"record not found"}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export function createDefaultMemoryPolicy(){return{decide:
|
|
1
|
+
export function createDefaultMemoryPolicy(){return{decide:e=>e.noStore?{action:"reject",reason:"candidate marked noStore",reviewRequired:!1}:e.content.trim()?"sensitive"===e.sensitivity||"restricted"===e.sensitivity?{action:"review",reason:"sensitive memory requires operator approval",kind:e.kindHint??"semantic",scope:e.scopeHint??"workspace",confidence:normalizeConfidence(e.confidenceHint),reviewRequired:!0}:{action:"store",reason:"candidate accepted by default runtime policy",kind:e.kindHint??"semantic",scope:e.scopeHint??"workspace",confidence:normalizeConfidence(e.confidenceHint),retrievalPriority:0,reviewRequired:!1}:{action:"reject",reason:"candidate content is empty",reviewRequired:!1}}}function normalizeConfidence(e){return void 0===e||Number.isNaN(e)?.6:Math.min(1,Math.max(0,e))}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export function createEmbeddedMemoryProvider(e={}){return{name:"embedded",config:e,async propose(n){const s=n.kindHint??function(e){const n=e.toLowerCase();return n.includes("must ")||n.includes("should ")?"procedural":n.includes("run ")||n.includes("failed ")?"episodic":"semantic"}(n.content);return function(e,n){return!1!==e.types?.[n]}(e,s)?[{namespace:n.namespace,content:n.content,sourceType:n.sourceType,sourceRef:n.sourceRef,kindHint:s,scopeHint:n.scopeHint??e.defaults?.scope??"workspace",sensitivity:n.sensitivity??e.defaults?.sensitivity??"internal",confidenceHint:.6,metadata:n.metadata}]:[]},search:async e=>e.store?(await e.store.recall({namespace:e.namespace,query:e.query,limit:e.limit,kinds:e.kinds})).records:[],consolidate:async e=>e.records.filter(e=>"stale"===e.status).map(e=>({action:"archive",recordId:e.id,reason:"embedded provider archives stale records during consolidation"}))}}
|
|
1
|
+
export function createEmbeddedMemoryProvider(e={}){return{name:"embedded",config:e,async propose(n){const s=n.kindHint??function inferKind(e){const n=e.toLowerCase();return n.includes("must ")||n.includes("should ")?"procedural":n.includes("run ")||n.includes("failed ")?"episodic":"semantic"}(n.content);return function isKindEnabled(e,n){return!1!==e.types?.[n]}(e,s)?[{namespace:n.namespace,content:n.content,sourceType:n.sourceType,sourceRef:n.sourceRef,kindHint:s,scopeHint:n.scopeHint??e.defaults?.scope??"workspace",sensitivity:n.sensitivity??e.defaults?.sensitivity??"internal",confidenceHint:.6,metadata:n.metadata}]:[]},search:async e=>e.store?(await e.store.recall({namespace:e.namespace,query:e.query,limit:e.limit,kinds:e.kinds})).records:[],consolidate:async e=>e.records.filter(e=>"stale"===e.status).map(e=>({action:"archive",recordId:e.id,reason:"embedded provider archives stale records during consolidation"}))}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{randomUUID as e}from"node:crypto";import{createDefaultMemoryPolicy as t}from"./policy.js";import{cloneRecords as n}from"./persistence.js";export function createInMemoryRuntimeMemoryStore(e={}){const
|
|
1
|
+
import{randomUUID as e}from"node:crypto";import{createDefaultMemoryPolicy as t}from"./policy.js";import{cloneRecords as n}from"./persistence.js";export function createInMemoryRuntimeMemoryStore(e={}){const r=e.policy??t(),o=n(e.records??[]);return{async submitCandidate(e){const t=r.decide(e);if("store"!==t.action)return{candidate:e,decision:t};const n=createRecord({namespace:e.namespace,content:e.content,kind:t.kind,scope:t.scope,summary:e.summary,confidence:t.confidence,tags:e.tags,sensitivity:e.sensitivity,sourceType:e.sourceType,sourceRef:e.sourceRef,metadata:e.metadata,provenance:e.provenance,observedAt:e.observedAt,retrievalPriority:t.retrievalPriority});return o.push(n),{candidate:e,decision:{...t,recordId:n.id},record:cloneRecord(n)}},async memorize(e){const t=createRecord(e);return o.push(t),cloneRecord(t)},async recall(e){const t=e.query.toLowerCase(),n=filterRecords(o,e).filter(e=>function matchesQuery(e,t){return[e.canonicalKey,e.content,e.summary??"",...e.tags].join("\n").toLowerCase().includes(t)}(e,t)).sort(compareRecallPriority).slice(0,e.limit??10);return{records:n,context:buildMemoryContext(n)}},list:async e=>n(filterRecords(o,e)),async update(e){const t=o.find(t=>t.id===e.id);if(t)return function applyUpdate(e,t){e.content=t.content??e.content,e.summary=t.summary??e.summary,e.status=t.status??e.status,e.confidence=normalizeConfidence(t.confidence??e.confidence),e.tags=t.tags??e.tags,e.metadata=t.metadata?{...e.metadata,...t.metadata}:e.metadata,e.lastConfirmedAt=(new Date).toISOString(),e.revision+=1}(t,e),cloneRecord(t)},async archive(e,t){const n=o.find(t=>t.id===e);if(n)return n.status="archived",n.metadata={...n.metadata,archiveReason:t},n.revision+=1,cloneRecord(n)}}}function cloneRecord(e){return n([e])[0]}function createRecord(t){const n=(new Date).toISOString();return{id:e(),namespace:t.namespace,canonicalKey:(r=t.namespace,o=t.content,`${r}:${o.trim().toLowerCase().replace(/\s+/gu," ").slice(0,120)}`),kind:t.kind??"semantic",scope:t.scope??"workspace",status:"active",content:t.content,summary:t.summary,confidence:normalizeConfidence(t.confidence),sourceType:t.sourceType,sourceRefs:t.sourceRef?[t.sourceRef]:[],tags:t.tags??[],sensitivity:t.sensitivity??"internal",metadata:t.metadata??{},createdAt:n,observedAt:t.observedAt??n,lastConfirmedAt:n,provenance:t.provenance??{},revision:1,supersedes:[],conflictsWith:[],retrievalPriority:t.retrievalPriority??0};var r,o}function filterRecords(e,t){return e.filter(e=>e.namespace===t.namespace).filter(e=>!t.kinds||t.kinds.includes(e.kind)).filter(e=>!t.scopes||t.scopes.includes(e.scope)).filter(e=>(t.statuses??["active"]).includes(e.status))}function compareRecallPriority(e,t){return t.retrievalPriority-e.retrievalPriority||t.confidence-e.confidence||t.lastConfirmedAt.localeCompare(e.lastConfirmedAt)}function buildMemoryContext(e){return e.map(e=>`- [${e.kind}/${e.scope}] ${e.summary??e.content}`).join("\n")}function normalizeConfidence(e){return void 0===e||Number.isNaN(e)?.6:Math.min(1,Math.max(0,e))}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createServer as
|
|
1
|
+
import{createServer as e}from"node:http";import{compileWorkflowPlan as o,projectRuntimeTrace as t,renderWorkflowMermaid as r}from"@stable-harness/core";export function createHttpServer(n){return e(async(e,s)=>{try{if("GET"===e.method&&"/health"===e.url)return void sendJson(s,200,{ok:!0});if("GET"===e.method&&"/inspect"===e.url)return void sendJson(s,200,n.inspect());if("GET"===e.method&&"/requests"===e.url)return void sendJson(s,200,n.listRequests());if("GET"===e.method&&"/sessions"===e.url)return void sendJson(s,200,n.listSessions());if("GET"===e.method&&"/workflows"===e.url)return void sendJson(s,200,n.inspect().workflows);const d=function readWorkflowMermaidId(e){const o=(e??"").match(/^\/workflows\/([^/]+)\/mermaid$/u);return o?.[1]?decodeURIComponent(o[1]):void 0}(e.url);if("GET"===e.method&&d){const e=n.getWorkflow(d);return void sendJson(s,e?200:404,e?{mermaid:r(e)}:{error:"workflow_not_found"})}const a=function readWorkflowPlanId(e){const o=(e??"").match(/^\/workflows\/([^/]+)\/plan$/u);return o?.[1]?decodeURIComponent(o[1]):void 0}(e.url);if("GET"===e.method&&a){const e=n.getWorkflow(a);return void sendJson(s,e?200:404,e?o(e):{error:"workflow_not_found"})}const i=function readRequestInspectionId(e){const o=(e??"").match(/^\/requests\/([^/]+)$/u);return o?.[1]?decodeURIComponent(o[1]):void 0}(e.url);if("GET"===e.method&&i){const e=n.inspectRequest(i);return void sendJson(s,e?200:404,e??{error:"request_not_found"})}const u=function readTraceRequestId(e){const o=(e??"").match(/^\/runs\/([^/]+)\/trace$/u);return o?.[1]?decodeURIComponent(o[1]):void 0}(e.url);if("GET"===e.method&&u){const e=n.getRun(u);return void sendJson(s,e?200:404,e?t(e):{error:"run_not_found"})}if("POST"===e.method&&"/requests"===e.url){const o=await async function readJson(e){const o=[];for await(const t of e)o.push(Buffer.isBuffer(t)?t:Buffer.from(t));return 0===o.length?{}:JSON.parse(Buffer.concat(o).toString("utf8"))}(e);return void sendJson(s,200,await n.request(function readRuntimeRequest(e){const o=function readToolCall(e){if("object"!=typeof e||null===e)return;const o=e;return"string"==typeof o.toolId?{toolId:o.toolId,args:o.args}:void 0}(e.toolCall),t=function readWorkflow(e){const o=readRecord(e);if(o)return{..."string"==typeof o.workflowId?{workflowId:o.workflowId}:{},..."string"==typeof o.routeId?{routeId:o.routeId}:{},...void 0!==o.input?{input:o.input}:{},..."object"==typeof o.metadata&&o.metadata?{metadata:o.metadata}:{}}}(e.workflow),r=function readMemory(e){const o=readRecord(e);if(o)return{..."string"==typeof o.namespace?{namespace:o.namespace}:{},...!1===o.recall||readRecord(o.recall)?{recall:o.recall}:{},...Array.isArray(o.candidates)?{candidates:o.candidates}:{}}}(e.memory),n=readRecord(e.metadata);return{input:"string"==typeof e.input?e.input:"",..."string"==typeof e.agentId?{agentId:e.agentId}:{},..."string"==typeof e.sessionId?{sessionId:e.sessionId}:{},..."string"==typeof e.requestId?{requestId:e.requestId}:{},..."string"==typeof e.parentRunId?{parentRunId:e.parentRunId}:{},...o?{toolCall:o}:{},...t?{workflow:t}:{},...r?{memory:r}:{},...n?{metadata:n}:{}}}(o)))}sendJson(s,404,{error:"not_found"})}catch(e){sendJson(s,500,{error:e instanceof Error?e.message:String(e)})}})}function readRecord(e){return"object"!=typeof e||null===e||Array.isArray(e)?void 0:e}function sendJson(e,o,t){e.writeHead(o,{"content-type":"application/json"}),e.end(JSON.stringify(t))}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createServer as e}from"node:http";import{createCapabilitiesResponse as
|
|
1
|
+
import{createServer as e}from"node:http";import{createCapabilitiesResponse as r,createModelsResponse as t,resolveAgentId as o,toChatCompletion as n,toRuntimeRequest as s}from"./openai-payload.js";import{createContentChunk as a,createRoleChunk as i,createStopChunk as d,missingFinalDelta as c,writeChatSse as l,writeRuntimeStreamEvent as u,writeSseHeaders as f}from"./openai-stream.js";export function createOpenAiCompatibleHttpServer(p,m={}){const g=function resolveServerOptions(e,r){const t=function readOpenAiProtocolConfig(e){const r=readRecord(e)??{};return readRecord(r.openaiCompatible)??readRecord(r["openai-compatible"])??readRecord(r.openai)??{}}(e.getRuntimePolicy().protocols);return{bearerToken:r.bearerToken??readConfigString(t.bearerToken),corsOrigins:r.corsOrigins??(o=t.corsOrigins,Array.isArray(o)?o.filter(e=>"string"==typeof e&&e.trim().length>0):void 0),modelAgentMap:r.modelAgentMap??readStringRecord(t.modelAgentMap),defaultModel:r.defaultModel??readConfigString(t.defaultModel)};var o}(p,m);return e(async(e,m)=>{try{if(function applyCorsHeaders(e,r,t){const o=function allowedCorsOrigin(e,r){if(e)return r.corsOrigins?.includes("*")?"*":r.corsOrigins?.includes(e)||function isLoopbackOrigin(e){try{const r=new URL(e);return"http:"===r.protocol&&["localhost","127.0.0.1","[::1]"].includes(r.hostname)}catch{return!1}}(e)?e:void 0}(e.headers.origin,t);o&&(r.setHeader("access-control-allow-origin",o),r.setHeader("vary","origin"))}(e,m,g),function handleCors(e,r){return"OPTIONS"===e.method&&(r.writeHead(204,{"access-control-allow-headers":"authorization, content-type, idempotency-key","access-control-allow-methods":"GET, POST, OPTIONS"}),r.end(),!0)}(e,m))return;if(!function isAuthorized(e,r){return!r.bearerToken||e.headers.authorization===`Bearer ${r.bearerToken}`}(e,g))return void sendJson(m,401,{error:{message:"unauthorized",type:"invalid_request_error"}});if("GET"===e.method&&"/v1/models"===e.url)return void sendJson(m,200,t(p,g));if("GET"===e.method&&"/v1/capabilities"===e.url)return void sendJson(m,200,r());if("POST"===e.method&&"/v1/chat/completions"===e.url)return void await async function handleChatCompletion(e,r,t,p){const m=await async function readJson(e){const r=[];for await(const t of e)r.push(Buffer.isBuffer(t)?t:Buffer.from(t));return 0===r.length?{}:JSON.parse(Buffer.concat(r).toString("utf8"))}(r);if(m.model&&!o(m.model,e,p))return void sendJson(t,404,{error:{message:`model_not_found: ${m.model}`,type:"invalid_request_error"}});const g=s(m,e,p,{sessionId:readHeaderString(r.headers["x-stable-harness-session-id"])});if(m.stream)return void await async function streamChatCompletion(e,r,t,o){f(r,{"access-control-allow-headers":"authorization, content-type, idempotency-key","access-control-allow-methods":"GET, POST, OPTIONS"}),l(r,i(o.requestId,t.model));let n="";const s=e.subscribe(e=>{e.requestId===o.requestId&&(n+=u(r,e,o.requestId,t.model)??"")});try{const s=await e.request(o),i=c(n,s.output);i&&l(r,a(o.requestId,t.model,i)),l(r,d(o.requestId,t.model)),r.write("data: [DONE]\n\n"),r.end()}finally{s()}}(e,t,m,g);const h=await e.request(g);sendJson(t,200,n(m,h))}(p,e,m,g);sendJson(m,404,{error:{message:"not_found",type:"invalid_request_error"}})}catch(e){sendJson(m,400,{error:{message:e instanceof Error?e.message:String(e),type:"invalid_request_error"}})}})}function readRecord(e){return"object"!=typeof e||null===e||Array.isArray(e)?void 0:e}function readStringRecord(e){const r=readRecord(e);if(r)return Object.fromEntries(Object.entries(r).filter(e=>"string"==typeof e[1]))}function readConfigString(e){if("string"!=typeof e||!e.trim())return;const r=e.match(/^\$\{env:([A-Za-z_][A-Za-z0-9_]*)(?::-(.*))?\}$/u);return r?process.env[r[1]]??r[2]:e}function readHeaderString(e){const r=Array.isArray(e)?e[0]:e;return r&&r.trim()?r:void 0}function sendJson(e,r,t,o){e.writeHead(r,{"content-type":"application/json","access-control-allow-headers":"authorization, content-type, idempotency-key","access-control-allow-methods":"GET, POST, OPTIONS"}),e.end(JSON.stringify(t))}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{randomUUID as
|
|
1
|
+
import{randomUUID as e}from"node:crypto";export function toRuntimeRequest(t,n,s,o={}){const r=function messagesToInput(e){if(!Array.isArray(e)||0===e.length)throw new Error("messages must be a non-empty array");return e.map(e=>`${e.role??"user"}: ${contentToText(e.content)}`).join("\n\n")}(t.messages),a=`chatcmpl-${e()}`,i=o.sessionId??function readSessionId(e){const t=e?.sessionId??e?.session_id??e?.conversationId??e?.conversation_id;return"string"==typeof t&&t.trim()?t:void 0}(t.metadata),c=normalizeOpenAiMessages(t.messages),u=i?function prependSessionMessages(e,t,n){if(function hasClientHistory(e){return e.some(e=>"assistant"===e.role)||e.filter(e=>"user"===e.role).length>1}(n))return n;const s=e.listRequests({sessionId:t,state:"completed"}).flatMap(t=>function inspectSessionTurn(e,t){const n=e.inspectRequest(t),s=n?.output?.trim(),o=function lastUserMessage(e){return normalizeOpenAiMessages(Array.isArray(e)?e:void 0).filter(e=>"user"===e.role&&e.content.trim()).at(-1)}(n?.metadata?.openaiMessages)?.content;return o&&s?[{role:"user",content:o},{role:"assistant",content:s}]:[]}(e,t.requestId)).slice(-12);return s.length>0?[...s,...n]:n}(n,i,c):c;return{input:r,requestId:a,agentId:resolveAgentId(t.model,n,s),...i?{sessionId:i}:{},metadata:{protocol:"openai-compatible",openaiStream:!0===t.stream,openaiMessages:u,openaiSessionHistory:u.length>c.length,model:t.model,user:t.user,clientMetadata:t.metadata}}}export function resolveAgentId(e,t,n){if(!e)return;const s=n.modelAgentMap?.[e];return s||(t.inspect().agents.includes(e)?e:void 0)}export function createModelsResponse(e,t){const n=Object.keys(t.modelAgentMap??{});return{object:"list",data:[...new Set([...e.inspect().agents,...n])].sort().map(e=>({id:e,object:"model",created:0,owned_by:"stable-harness"}))}}export function createCapabilitiesResponse(){return{object:"stable_harness.capabilities",endpoints:["/v1/models","/v1/chat/completions","/v1/capabilities"],streaming:!0,toolProgressEvents:!0}}export function toChatCompletion(e,t){return{id:t.requestId,object:"chat.completion",created:Math.floor(Date.now()/1e3),model:e.model??t.agentId,choices:[{index:0,message:{role:"assistant",content:t.output},finish_reason:"stop"}],usage:estimateUsage(e.messages,t.output),metadata:{sessionId:t.sessionId,agentId:t.agentId,state:t.state}}}function normalizeOpenAiMessages(e){return Array.isArray(e)?e.map(e=>({role:e.role??"user",content:contentToText(e.content)})):[]}function contentToText(e){if("string"==typeof e)return e;if(!Array.isArray(e))throw new Error("message content must be a string or content part array");return e.map(contentPartToText).join("\n")}function contentPartToText(e){if("object"!=typeof e||null===e)throw new Error("message content parts must be objects");const t=e;if("text"===t.type&&"string"==typeof t.text)return t.text;const n=t.image_url;if("image_url"===t.type&&"string"==typeof n?.url)return`[image:${n.url}]`;throw new Error("unsupported_content_type")}function estimateUsage(e,t){const n=estimateTokens(Array.isArray(e)?e.map(e=>contentToText(e.content)).join("\n"):""),s=estimateTokens(t);return{prompt_tokens:n,completion_tokens:s,total_tokens:n+s}}function estimateTokens(e){return e.trim()?Math.ceil(1.3*e.trim().split(/\s+/u).length):0}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export function missingFinalDelta(t
|
|
1
|
+
export function missingFinalDelta(e,t){return e?!t||e.includes(t)?"":t.startsWith(e)?t.slice(e.length):t:t}export function createRoleChunk(e,t){return createChunk(e,t,{role:"assistant"},null)}export function createContentChunk(e,t,n){return createChunk(e,t,{content:n},null)}export function createStopChunk(e,t){return createChunk(e,t,{},"stop")}export function writeRuntimeStreamEvent(e,t,n,r){const o=function readAdapterDelta(e){if("runtime.adapter.event"!==e.type||"object"!=typeof e.event||null===e.event)return;const t=e.event;return"agent.output.delta"===t.phase&&"string"==typeof t.text?t.text:void 0}(t);if(o)return writeChatSse(e,createContentChunk(n,r,o)),o;!function writeProgressEvent(e,t){const n=function readToolProgress(e){if("runtime.tool.direct.started"===e.type||"runtime.tool.direct.completed"===e.type)return{request_id:e.requestId,session_id:e.sessionId,agent_id:e.agentId,type:e.type,tool_id:e.toolId};if("runtime.adapter.event"!==e.type||"object"!=typeof e.event||null===e.event)return;const t=e.event,n="agent.tool.start"===t.phase||"agent.tool.result"===t.phase?t.phase:void 0,r="string"==typeof t.toolId?t.toolId:void 0;return n&&r?{request_id:e.requestId,session_id:e.sessionId,agent_id:e.agentId,type:n,tool_id:r,adapter:t.adapter}:void 0}(t);n&&writeSse(e,"stable_harness.tool.progress",n)}(e,t),function writeNarrationEvent(e,t){"runtime.progress.narration"===t.type&&writeSse(e,"stable_harness.progress.narration",{request_id:t.requestId,session_id:t.sessionId,agent_id:t.agentId,type:t.type,message:t.message,provider:t.provider,source_event_types:t.sourceEventTypes,source_event_ids:t.sourceEventIds,model:t.model,style:t.style})}(e,t)}export function writeSseHeaders(e,t){e.writeHead(200,{"content-type":"text/event-stream","cache-control":"no-cache",connection:"keep-alive",...t})}export function writeChatSse(e,t){e.write(`data: ${JSON.stringify(t)}\n\n`)}function createChunk(e,t,n,r){return{id:e,object:"chat.completion.chunk",created:Math.floor(Date.now()/1e3),model:t??"stable-harness",choices:[{index:0,delta:n,finish_reason:r}]}}function writeSse(e,t,n){e.write(`event: ${t}\n`),e.write(`data: ${JSON.stringify(n)}\n\n`)}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { BetterToolLike, RepairFunction, RepairModelLike } from "@botbotgo/better-call";
|
|
1
|
+
import type { BetterToolLike, RepairFunction, RepairModelLike, RepairPolicy } from "@botbotgo/better-call";
|
|
2
2
|
import type { ToolArgumentGuard, ToolArgumentIssue, ToolGatewayContext, ToolGatewayTool } from "./types.js";
|
|
3
3
|
type ToolGatewayRuntimeTool = ToolGatewayTool & {
|
|
4
4
|
validationTool?: BetterToolLike;
|
|
@@ -7,6 +7,7 @@ export type BetterCallArgumentRepairOptions = {
|
|
|
7
7
|
mode?: "guard" | "repair" | "review";
|
|
8
8
|
repair?: RepairFunction;
|
|
9
9
|
repairModel?: RepairModelLike;
|
|
10
|
+
repairPolicy?: RepairPolicy;
|
|
10
11
|
};
|
|
11
12
|
export type ToolArgumentGuardOptions = {
|
|
12
13
|
betterCall?: BetterCallArgumentRepairOptions;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{BetterToolValidationError as o,betterTools as t,defaultRepair as e,reliableToolCalls as
|
|
1
|
+
import{BetterToolValidationError as o,betterTools as t,defaultRepair as e,reliableToolCalls as a}from"@botbotgo/better-call";import{isRecord as r,validateWithZodSchema as i}from"./schema-validation.js";export class ToolArgumentValidationError extends Error{toolId;issues;constructor(o,t){super(`Tool argument validation failed for ${o}: ${t.map(o=>`${o.path} ${o.message}`).join("; ")}`),this.toolId=o,this.issues=t,this.name="ToolArgumentValidationError"}}export function createDefaultArgumentGuard(t={}){return{async validate(e){const a=e.tool.validateArgs?await e.tool.validateArgs({args:e.args,context:e.context}):{action:"allow",args:e.args};if("reject"===a.action)return a;const r=await async function validateWithBetterCall(t,e,a){const r=i(t.schema,e);if(void 0===t.schema)return r??{action:"allow",args:e};const l=await async function invokeBetterCallValidation(t,e,a){try{return{action:"allow",args:await createBetterCallValidationTool(t,a).invoke(e)}}catch(t){if(t instanceof o)return{action:"reject",reason:"BetterCall validation failed",issues:t.issues.map(toToolArgumentIssue)};throw t}}(t,"allow"===r?.action?r.args:e,a);return r?"allow"===r.action?l:"reject"===l.action?r:i(t.schema,l.args)||l:l}(e.tool,a.args,t.betterCall);return"reject"===r.action?r:"repair"===a.action?{...a,args:r.args}:r}}}export function assertToolArguments(o,t,e,a){return Promise.resolve(a.validate({tool:o,args:t,context:e})).then(t=>{if("reject"===t.action)throw new ToolArgumentValidationError(o.id,t.issues);return t.args})}export function prepareBetterCallTools(o,e){const a=t(o.map(toBetterCallTool),toBetterToolsOptions(e));return o.map((o,t)=>({...o,validationTool:a[t]}))}export async function repairBetterCallToolSelection(o){const t=function resolveRepair(o){return o?.repair??(o?.repairModel?e(o.repairModel):void 0)}(o.options);if(!t||0===o.tools.length)return;const i=await a({userInput:JSON.stringify({tool:o.toolId,args:o.args}),tools:o.tools.map(toToolDefinition),calls:[{tool:o.toolId,args:(l=o.args,r(l)?l:{input:l})}],repair:t,repairPolicy:o.options?.repairPolicy??{allowCoercion:!0,allowClamp:!0,allowArrayStringSplit:!0,allowModelRepair:!0},mode:o.options?.mode??"repair"});var l;const n=i.ok?i.calls.find(t=>o.tools.some(o=>o.id===t.tool)):void 0;return n?{toolId:n.tool,args:n.args}:void 0}function createBetterCallValidationTool(o,e){return o.validationTool??t([toBetterCallTool(o)],toBetterToolsOptions(e))[0]}function toBetterCallTool(o){return{name:o.id,description:o.description,schema:o.schema,invoke:o=>o}}function toToolDefinition(o){return{name:o.id,description:o.description,schema:o.schema}}function toToolArgumentIssue(o){return{path:o.path.replace(/^\$\.calls\[\d+\]\.args/u,"$"),message:o.message,expected:void 0===o.expected?void 0:String(o.expected),actual:o.actual}}function toBetterToolsOptions(o){return{mode:o?.mode??"repair",repair:o?.repair,repairModel:o?.repairModel,repairPolicy:o?.repairPolicy??{allowCoercion:!0,allowClamp:!0,allowArrayStringSplit:!0,allowModelRepair:!0}}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{assertToolArguments as o,createDefaultArgumentGuard as t,prepareBetterCallTools as e,repairBetterCallToolSelection as a}from"./argument-guard.js";export function createInMemoryToolGateway(
|
|
1
|
+
import{assertToolArguments as o,createDefaultArgumentGuard as t,prepareBetterCallTools as e,repairBetterCallToolSelection as r,ToolArgumentValidationError as a}from"./argument-guard.js";export function createInMemoryToolGateway(l,i={}){const s=new Map(e(l,i.betterCall).map(o=>[o.id,o])),n=t(i),repairToolCall=async o=>{const t=o.allowedToolIds?new Set(o.allowedToolIds):void 0,e=[...s.values()].filter(o=>!t||t.has(o.id));return r({toolId:o.toolId,args:o.args,tools:e,options:withRequestRepairModel(i.betterCall,o.repairModel)})};return{list:()=>[...s.values()],get:o=>s.get(o),repairToolCall:repairToolCall,async invoke(t){const e=s.has(t.toolId)?void 0:await repairToolCall(t),r=e?.toolId??t.toolId,l=s.get(r);if(!l)throw new Error(`Tool is not registered: ${t.toolId}`);const i=await async function assertToolArgumentsWithRepair(t){try{return await o(t.tool,t.initialArgs,t.request.context,t.guard)}catch(e){if(!(e instanceof a))throw e;const r=await t.repairToolCall({...t.request,args:t.initialArgs,allowedToolIds:[t.tool.id]});if(!r||r.toolId!==t.tool.id)throw e;return o(t.tool,r.args,t.request.context,t.guard)}}({request:t,tool:l,initialArgs:e?.args??t.args,repairToolCall:repairToolCall,guard:n});return{toolId:l.id,output:await l.invoke(i,t.context)}}}}function withRequestRepairModel(o,t){return!t||o?.repair||o?.repairModel?o:{...o,mode:o?.mode??"repair",repairModel:t}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import o from"node:path";import{pathToFileURL as e}from"node:url";import{createInMemoryToolGateway as t}from"./in-memory.js";export async function createModuleToolGateway(o){const e=[];for(const t of o.tools){const o=await
|
|
1
|
+
import o from"node:path";import{pathToFileURL as e}from"node:url";import{createInMemoryToolGateway as t}from"./in-memory.js";export async function createModuleToolGateway(o){const e=[];for(const t of o.tools){const o=await loadModuleTool(t);o&&e.push(o)}return t(e,o.options)}async function loadModuleTool(t){if(!t.sourcePath)return;const n=await import(e(o.resolve(t.sourcePath)).href),r=n[t.name??t.id]??n.default;return function hasInvoke(o){return"object"==typeof o&&null!==o&&"invoke"in o&&"function"==typeof o.invoke}(r)?{id:t.id,description:t.description??r.description,schema:t.schema??r.schema,validateArgs:r.validateArgs,invoke:(o,e)=>async function invokeWithWorkspaceCwd(o,e,t){const n=process.cwd();try{return process.chdir(t.workspaceRoot),await o(e)}finally{process.chdir(n)}}(r.invoke,o,e)}:void 0}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export function validateWithZodSchema(
|
|
1
|
+
import{normalizeArgsBySchema as e}from"@botbotgo/better-call";export function validateWithZodSchema(t,o){return isZodLike(t)?toZodGuardResult(t.safeParse(o??{})):function isZodShape(e){return isRecord(e)&&Object.values(e).length>0&&Object.values(e).every(isZodLike)}(t)?function validateWithZodShape(t,o){const r=function normalizeZodShapeArgs(t,o){const r=isRecord(o)?o:{};return e(t,r,{allowCoercion:!0,allowClamp:!0,allowArrayStringSplit:!0}).args}(t,o),a={},s=[];for(const[e,o]of Object.entries(t)){const t=o.safeParse(r[e]);t.success?void 0!==t.data&&(a[e]=t.data):s.push(...t.error.issues.map(t=>({...t,path:[e,...t.path]})))}return s.length>0?toZodGuardResult({success:!1,error:{issues:s}}):{action:"allow",args:a}}(t,o):void 0}export function isRecord(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}function toZodGuardResult(e){return e.success?{action:"allow",args:e.data}:{action:"reject",reason:"Zod schema validation failed",issues:e.error.issues.map(e=>{return{path:(t=e.path,t.length>0?`$.${t.map(String).join(".")}`:"$"),message:e.message,expected:"schema"};var t})}}function isZodLike(e){return isRecord(e)&&"function"==typeof e.safeParse}
|
|
@@ -44,6 +44,9 @@ export type ToolArgumentValidator = (input: {
|
|
|
44
44
|
export type ToolGatewayInvokeRequest = {
|
|
45
45
|
toolId: string;
|
|
46
46
|
args?: unknown;
|
|
47
|
+
repairModel?: {
|
|
48
|
+
invoke(input: unknown): Promise<unknown> | unknown;
|
|
49
|
+
};
|
|
47
50
|
context: ToolGatewayContext;
|
|
48
51
|
};
|
|
49
52
|
export type ToolGatewayRepairRequest = ToolGatewayInvokeRequest & {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{readdir as t,readFile as
|
|
1
|
+
import{readdir as t,readFile as r}from"node:fs/promises";import e from"node:path";import{parseAllDocuments as i}from"yaml";export async function listYamlFiles(r){const i=await t(r,{withFileTypes:!0});return(await Promise.all(i.map(async t=>{const i=e.join(r,t.name);return t.isDirectory()?listYamlFiles(i):t.isFile()&&/\.ya?ml$/iu.test(t.name)?[i]:[]}))).flat().sort()}export async function discoverModuleTools(i){const a=e.join(i,"resources","tools");let n;try{n=await t(a,{withFileTypes:!0})}catch{return[]}return(await Promise.all(n.filter(t=>t.isFile()&&t.name.endsWith(".mjs")&&!t.name.startsWith("_")).map(t=>async function discoverModuleToolFile(t){const i=[...(await r(t,"utf8")).matchAll(/export\s+const\s+([A-Za-z_][A-Za-z0-9_]*)\s*=\s*tool\s*\(/gu)].map(t=>t[1]).filter(t=>"default"!==t);return(i.length>0?i:[e.basename(t,".mjs")]).map(r=>({id:r,sourcePath:t}))}(e.join(a,t.name))))).flat()}export async function discoverSkills(a){const n=e.join(a,"resources","skills");let o;try{o=await t(n,{withFileTypes:!0})}catch{return[]}return(await Promise.all(o.filter(t=>t.isDirectory()).map(t=>async function readSkill(t,a){const n=e.join(t,"SKILL.md");let o;try{o=await r(n,"utf8")}catch{return}const s=function readFrontMatter(t){const r=t.match(/^---\n([\s\S]*?)\n---/u);if(!r)return{};const e=i(r[1]).at(0)?.toJSON();return"object"!=typeof e||null===e||Array.isArray(e)?{}:e}(o);return{id:readOptionalString(s.name)??a,path:n,...readOptionalString(s.description)?{description:readOptionalString(s.description)}:{},allowedTools:(l=s["allowed-tools"],Array.isArray(l)?l.filter(t=>"string"==typeof t&&t.trim().length>0):[])};var l}(e.join(n,t.name),t.name)))).filter(t=>Boolean(t))}function readOptionalString(t){return"string"==typeof t&&t.trim()?t.trim():void 0}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
function
|
|
1
|
+
import{assertSpecDrivenWorkflowPolicy as e,createSpecDrivenWorkflowPolicy as r}from"@stable-harness/core";function assertRecord(e,r){if("object"!=typeof e||null===e||Array.isArray(e))throw new Error(`${r} must be an object`);return e}function readName(e,r){const t=e.metadata?.name;if("string"==typeof t&&t.trim())return t.trim();if(r)return r;throw new Error(`Document kind ${String(e.kind)} requires metadata.name`)}function readDescription(e){const r=e.metadata?.description;return"string"==typeof r&&r.trim()?r.trim():void 0}function readOptionalString(e){return"string"==typeof e&&e.trim()?e.trim():void 0}function toStringArray(e){return Array.isArray(e)?e.filter(e=>"string"==typeof e&&e.trim().length>0):[]}function resolveValue(e){if("string"!=typeof e)return e;const r=e.match(/^\$\{env:([A-Za-z_][A-Za-z0-9_]*)(?::-(.*))?\}$/u);return r?process.env[r[1]]??r[2]??"":e}export function compileRuntime(e){const r=assertRecord(e.spec,"Runtime.spec"),t=assertRecord(r.routing??{},"Runtime.spec.routing");return{defaultAgentId:"string"==typeof t.defaultAgentId&&t.defaultAgentId.trim()?t.defaultAgentId.trim():"orchestra",...readOptionalString(r.workspaceId)?{workspaceId:readOptionalString(r.workspaceId)}:{},...readOptionalString(r.profile)?{profile:readOptionalString(r.profile)}:{},...void 0!==r.adapters?{adapters:readAdapters(r.adapters)}:{},..."object"==typeof r.workflowRouting&&r.workflowRouting?{workflowRouting:readWorkflowRouting(r.workflowRouting)}:{},..."object"==typeof r.specDrivenWorkflow&&r.specDrivenWorkflow?{specDrivenWorkflow:readSpecDrivenWorkflow(r.specDrivenWorkflow)}:{},..."object"==typeof r.approvals&&r.approvals?{approvals:r.approvals}:{},..."object"==typeof r.recovery&&r.recovery?{recovery:r.recovery}:{},..."object"==typeof r.retry&&r.retry?{retry:r.retry}:{},..."object"==typeof r.toolGateway&&r.toolGateway?{toolGateway:r.toolGateway}:{},..."object"==typeof r.memory&&r.memory?{memory:r.memory}:{},..."object"==typeof r.protocols&&r.protocols?{protocols:r.protocols}:{},..."object"==typeof r.progress&&r.progress?{progress:r.progress}:{},..."object"==typeof r.cli&&r.cli?{cli:r.cli}:{},..."object"==typeof r.responseLanguage&&r.responseLanguage?{responseLanguage:r.responseLanguage}:{},..."object"==typeof r.responsePresentation&&r.responsePresentation?{responsePresentation:r.responsePresentation}:{}}}function readSpecDrivenWorkflow(t){const o=assertRecord(t,"Runtime.spec.specDrivenWorkflow"),n=r({enabled:!0===o.enabled,constitution:readOptionalString(o.constitution),artifactsDir:readOptionalString(o.artifactsDir),phases:void 0===o.phases?void 0:readSpecDrivenPhases(o.phases),..."object"==typeof o.gates&&o.gates?{gates:o.gates}:{},..."object"==typeof o.config&&o.config?{config:o.config}:{}});return e(n),n}function readSpecDrivenPhases(e){if(!Array.isArray(e))throw new Error("Runtime.spec.specDrivenWorkflow.phases must be an array");return e.map(e=>{if("string"==typeof e&&e.trim())return{id:e.trim()};const r=assertRecord(e,"Runtime.spec.specDrivenWorkflow.phases[]"),t=readOptionalString(r.id);if(!t)throw new Error("Runtime.spec.specDrivenWorkflow.phases[] requires id");return{id:t,...readOptionalString(r.artifactKind)?{artifactKind:readOptionalString(r.artifactKind)}:{},..."boolean"==typeof r.required?{required:r.required}:{},...readOptionalString(r.gate)?{gate:readOptionalString(r.gate)}:{},..."object"==typeof r.config&&r.config?{config:r.config}:{}}})}export function compileAgent(e,r){const t=assertRecord(e.spec,"Agent.spec"),o=readName(e),n=readOptionalString(t.backend);if(!n)throw new Error(`Agent ${o} requires spec.backend`);const i="object"==typeof t.config&&t.config?t.config:{},a="string"==typeof t.systemPrompt?t.systemPrompt:"string"==typeof i.systemPrompt?i.systemPrompt:void 0;return{id:o,...readDescription(e)?{description:readDescription(e)}:{},sourcePath:r,backend:n,..."string"==typeof t.modelRef&&t.modelRef.trim()?{modelRef:(s=t.modelRef,s.replace(/^[^/]+\//u,""))}:{},...void 0!==a?{systemPrompt:a}:{},tools:toStringArray(t.tools),skills:toStringArray(t.skills),memory:Array.isArray(t.memory)?t.memory:[],subagents:toStringArray(t.subagents),...void 0!==t.edges?{edges:readAgentEdges(t.edges,o)}:{},config:i};var s}export function compileModel(e){return compileModelSpec(assertRecord(e.spec,"Model.spec"),readName(e))}export function compileModelSpec(e,r){const t="string"==typeof e.name&&e.name.trim()?e.name.trim():r??"default",o=resolveValue(e.provider),n=resolveValue(e.model),i="string"==typeof o&&o.trim()?o.trim():"unknown",a="string"==typeof n&&n.trim()?n.trim():t,s={...e};return delete s.name,delete s.provider,delete s.model,{id:t,provider:i,model:a,config:Object.fromEntries(Object.entries(s).map(([e,r])=>[e,resolveValue(r)]))}}export function compileTool(e){const r=assertRecord(e.spec,"Tool.spec");return{id:readName(e),..."string"==typeof r.description?{description:r.description}:{},...void 0!==r.schema?{schema:r.schema}:{},..."string"==typeof r.implementation?{implementation:r.implementation}:{}}}export function compileMemory(e){const r=assertRecord(e.spec,"Memory.spec"),t=readName(e),o={...r};return delete o.provider,delete o.profile,delete o.mode,delete o.enabled,delete o.prompts,{id:t,provider:readOptionalString(r.provider)??"langmem",...readOptionalString(r.profile)?{profile:readOptionalString(r.profile)}:{},...readOptionalString(r.mode)?{mode:readOptionalString(r.mode)}:{},enabled:!1!==r.enabled,..."object"==typeof r.prompts&&r.prompts?{prompts:readMemoryPrompts(r.prompts)}:{},...Object.keys(o).length>0?{config:o}:{}}}function readWorkflowRouting(e){const r=assertRecord(e,"Runtime.spec.workflowRouting"),t=void 0===r.routes?void 0:function readWorkflowRoutes(e){if(!Array.isArray(e))throw new Error("Runtime.spec.workflowRouting.routes must be an array");return e.map(e=>{const r=assertRecord(e,"Runtime.spec.workflowRouting.routes[]"),t=readOptionalString(r.id),o=readOptionalString(r.workflowId);if(!t||!o)throw new Error("Runtime.spec.workflowRouting.routes[] requires id and workflowId");return{id:t,workflowId:o,...readOptionalString(r.description)?{description:readOptionalString(r.description)}:{},..."object"==typeof r.metadata&&r.metadata?{metadata:r.metadata}:{}}})}(r.routes);return{...readOptionalString(r.defaultWorkflowId)?{defaultWorkflowId:readOptionalString(r.defaultWorkflowId)}:{},...t?{routes:t}:{}}}function readAdapters(e){if(!Array.isArray(e))throw new Error("Runtime.spec.adapters must be an array");return e.map(readAdapter)}function readAgentEdges(e,r){if(!Array.isArray(e))throw new Error(`Agent ${r} spec.edges must be an array`);return e.map(e=>{const t=assertRecord(e,`Agent ${r} spec.edges[]`),o=readOptionalString(t.from),n=readOptionalString(t.to);if(!o||!n)throw new Error(`Agent ${r} spec.edges[] requires from and to`);return{from:o,to:n,...readOptionalString(t.condition)?{condition:readOptionalString(t.condition)}:{}}})}function readAdapter(e){if("string"==typeof e&&e.trim())return{name:e.trim()};const r=assertRecord(e,"Runtime.spec.adapters[]"),t=readOptionalString(r.name)??readOptionalString(r.id)??readOptionalString(r.backend);if(!t)throw new Error("Runtime.spec.adapters[] requires name");return{name:t,..."boolean"==typeof r.enabled?{enabled:r.enabled}:{},..."object"==typeof r.config&&r.config?{config:r.config}:{}}}function readMemoryPrompts(e){const r=assertRecord(e,"Memory.spec.prompts");return{...readOptionalString(r.semantic)?{semantic:readOptionalString(r.semantic)}:{},...readOptionalString(r.episodic)?{episodic:readOptionalString(r.episodic)}:{},...readOptionalString(r.procedural)?{procedural:readOptionalString(r.procedural)}:{}}}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { WorkspaceAgent, WorkspaceEvaluation, WorkspaceTool, WorkspaceWorkflow } from "@stable-harness/core";
|
|
2
|
+
import type { RawDocument } from "./documents.js";
|
|
3
|
+
export declare function compileEvaluation(document: RawDocument, sourcePath: string): WorkspaceEvaluation;
|
|
4
|
+
export declare function validateEvaluations(input: {
|
|
5
|
+
evaluations: Map<string, WorkspaceEvaluation>;
|
|
6
|
+
agents: Map<string, WorkspaceAgent>;
|
|
7
|
+
tools: Map<string, WorkspaceTool>;
|
|
8
|
+
workflows: Map<string, WorkspaceWorkflow>;
|
|
9
|
+
}): void;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export function compileEvaluation(r,t){const e=assertRecord(r.spec,"Evaluation.spec"),o=function readName(r){const t=r.metadata?.name;if("string"==typeof t&&t.trim())return t.trim();throw new Error("Evaluation document requires metadata.name")}(r);return{id:o,...readDescription(r)?{description:readDescription(r)}:{},sourcePath:t,...readString(e.suite)?{suite:readString(e.suite)}:{},cases:readCases(e.cases,o),..."object"==typeof e.config&&e.config?{config:e.config}:{}}}export function validateEvaluations(r){for(const t of r.evaluations.values())for(const e of t.cases){if(e.agentId&&!r.agents.has(e.agentId))throw new Error(`Evaluation ${t.id} case ${e.id} references unknown agent ${e.agentId}`);if(e.workflowId&&!r.workflows.has(e.workflowId))throw new Error(`Evaluation ${t.id} case ${e.id} references unknown workflow ${e.workflowId}`);for(const o of e.tools??[])if(!r.tools.has(o))throw new Error(`Evaluation ${t.id} case ${e.id} references unknown tool ${o}`)}}function readCases(r,t){if(!Array.isArray(r)||0===r.length)throw new Error(`Evaluation ${t} spec.cases must be a non-empty array`);return r.map(r=>{const e=assertRecord(r,`Evaluation ${t} spec.cases[]`),o=readString(e.id);if(!o)throw new Error(`Evaluation ${t} spec.cases[] requires id`);return{id:o,...readString(e.description)?{description:readString(e.description)}:{},...readString(e.agentId)?{agentId:readString(e.agentId)}:{},...readString(e.workflowId)?{workflowId:readString(e.workflowId)}:{},...void 0!==e.input?{input:e.input}:{},...Array.isArray(e.tools)?{tools:e.tools.filter(r=>"string"==typeof r&&r.trim().length>0)}:{},..."object"==typeof e.assertions&&e.assertions?{assertions:e.assertions}:{},..."object"==typeof e.metadata&&e.metadata?{metadata:e.metadata}:{}}})}function assertRecord(r,t){if("object"!=typeof r||null===r||Array.isArray(r))throw new Error(`${t} must be an object`);return r}function readDescription(r){return readString(r.metadata?.description)}function readString(r){return"string"==typeof r&&r.trim()?r.trim():void 0}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{readFile as o}from"node:fs/promises";import e from"node:path";import{parseAllDocuments as s}from"yaml";import{discoverModuleTools as
|
|
1
|
+
import{readFile as o}from"node:fs/promises";import e from"node:path";import{parseAllDocuments as s}from"yaml";import{discoverModuleTools as t,discoverSkills as a,listYamlFiles as r}from"./discovery.js";import{compileAgent as i,compileMemory as l,compileModel as n,compileModelSpec as f,compileRuntime as c,compileTool as w}from"./documents.js";import{compileWorkflow as d,validateWorkflows as m}from"./workflows.js";import{compileEvaluation as k,validateEvaluations as p}from"./evaluations.js";export async function loadWorkspaceFromYaml(u){const M=e.join(u,"config"),g=await r(M),v=[],y=new Map,b=new Map,h=new Map,W=new Map,A=new Map,R=new Map,I=new Map;for(const e of g){const t=await o(e,"utf8"),a=s(t).map(o=>o.toJSON()).filter(o=>null!==o);for(const o of a)if("string"==typeof o.kind)switch(o.kind){case"Runtime":v.push(c(o));break;case"Agent":{const s=i(o,e);y.set(s.id,s);break}case"Model":{const e=n(o);b.set(e.id,e);break}case"Models":if(Array.isArray(o.spec))for(const e of o.spec)if("object"==typeof e&&null!==e&&!Array.isArray(e)){const o=f(e);b.set(o.id,o)}break;case"Tool":{const e=w(o);h.set(e.id,e);break}case"Memory":{const e=l(o);A.set(e.id,e);break}case"Workflow":{const s=d(o,e);R.set(s.id,s);break}case"Evaluation":{const s=k(o,e);I.set(s.id,s);break}}}for(const o of await t(u))h.has(o.id)||h.set(o.id,o);for(const o of await a(u))W.set(o.id,o);const j=v.at(-1)??{defaultAgentId:"orchestra"};return m({workflows:R,agents:y,tools:h,skills:W}),p({evaluations:I,agents:y,tools:h,workflows:R}),function validateWorkflowRouting(o,e){const s=o.workflowRouting;if(s){if(s.defaultWorkflowId&&!e.has(s.defaultWorkflowId))throw new Error(`Runtime workflowRouting.defaultWorkflowId references unknown workflow ${s.defaultWorkflowId}`);for(const o of s.routes??[])if(!e.has(o.workflowId))throw new Error(`Runtime workflowRouting route ${o.id} references unknown workflow ${o.workflowId}`)}}(j,R),{root:u,runtime:j,agents:y,models:b,tools:h,skills:W,memories:A,workflows:R,evaluations:I}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export function compileWorkflow(
|
|
1
|
+
export function compileWorkflow(o,r){const e=assertRecord(o.spec,"Workflow.spec"),t="object"==typeof e.config&&e.config?e.config:{};return{id:readName(o),...readDescription(o)?{description:readDescription(o)}:{},sourcePath:r,...readOptionalString(e.adapter)?{adapter:readOptionalString(e.adapter)}:{},...readOptionalString(e.entry)?{entry:readOptionalString(e.entry)}:{},..."object"==typeof e.state&&e.state?{state:readWorkflowState(e.state)}:{},nodes:readWorkflowNodes(e.nodes),edges:readWorkflowEdges(e.edges),..."object"==typeof e.policies&&e.policies?{policies:e.policies}:{},...Object.keys(t).length>0?{config:t}:{}}}export function validateWorkflows(o){for(const r of o.workflows.values()){const e=new Set(r.nodes.map(o=>o.id));validateWorkflowEntry(r,e),validateWorkflowEdges(r,e);for(const e of r.nodes)validateWorkflowUse(e.use,o)}}function readWorkflowState(o){const r=assertRecord(o,"Workflow.spec.state");return{...readOptionalString(r.schema)?{schema:readOptionalString(r.schema)}:{},..."object"==typeof r.config&&r.config?{config:r.config}:{}}}function readWorkflowNodes(o){if(!Array.isArray(o)||0===o.length)throw new Error("Workflow.spec.nodes must be a non-empty array");return o.map(o=>{const r=assertRecord(o,"Workflow.spec.nodes[]"),e=readOptionalString(r.id),t=readOptionalString(r.use);if(!e||!t)throw new Error("Workflow.spec.nodes[] requires id and use");return{id:e,use:t,...readOptionalString(r.type)?{type:readOptionalString(r.type)}:{},..."object"==typeof r.config&&r.config?{config:r.config}:{}}})}function readWorkflowEdges(o){if(!Array.isArray(o))throw new Error("Workflow.spec.edges must be an array");return o.map(o=>{const r=assertRecord(o,"Workflow.spec.edges[]"),e=readOptionalString(r.from),t=readOptionalString(r.to);if(!e||!t)throw new Error("Workflow.spec.edges[] requires from and to");return{from:e,to:t,...readOptionalString(r.condition)?{condition:readOptionalString(r.condition)}:{}}})}function validateWorkflowEntry(o,r){if(o.entry&&!r.has(o.entry))throw new Error(`Workflow ${o.id} entry references unknown node ${o.entry}`)}function validateWorkflowEdges(o,r){for(const e of o.edges)if(!r.has(e.from)||!r.has(e.to))throw new Error(`Workflow ${o.id} edge references unknown node ${e.from}->${e.to}`)}function validateWorkflowUse(o,r){const e=o.indexOf("."),t=e>0?o.slice(0,e):"",n=e>0?o.slice(e+1):"";if(!t||!n)throw new Error(`Workflow node use must reference inventory as agents.<id>, tools.<id>, skills.<id>, or workflows.<id>: ${o}`);const i="agents"===t?r.agents:"tools"===t?r.tools:"skills"===t?r.skills:"workflows"===t?r.workflows:void 0;if(!i?.has(n))throw new Error(`Workflow node references unknown ${t}.${n}`)}function assertRecord(o,r){if("object"!=typeof o||null===o||Array.isArray(o))throw new Error(`${r} must be an object`);return o}function readName(o){const r=o.metadata?.name;if("string"==typeof r&&r.trim())return r.trim();throw new Error("Workflow document requires metadata.name")}function readDescription(o){const r=o.metadata?.description;return"string"==typeof r&&r.trim()?r.trim():void 0}function readOptionalString(o){return"string"==typeof o&&o.trim()?o.trim():void 0}
|