agentfootprint 9.41.0 → 9.44.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +30 -1
- package/CLAUDE.md +3 -1
- package/ai-instructions/claude-code/SKILL.md +31 -1
- package/dist/adapters/hosting/agentcore.js +163 -23
- package/dist/adapters/hosting/agentcore.js.map +1 -1
- package/dist/adapters/hosting/firestoreSessions.js +184 -14
- package/dist/adapters/hosting/firestoreSessions.js.map +1 -1
- package/dist/adapters/hosting/googleAgentEngine.js +29 -0
- package/dist/adapters/hosting/googleAgentEngine.js.map +1 -1
- package/dist/artifacts/conformance/cases.js +20 -0
- package/dist/artifacts/conformance/cases.js.map +1 -1
- package/dist/artifacts/scopePath.js +41 -1
- package/dist/artifacts/scopePath.js.map +1 -1
- package/dist/core/Agent.js +17 -1
- package/dist/core/Agent.js.map +1 -1
- package/dist/core/agent/AgentBuilder.js +56 -1
- package/dist/core/agent/AgentBuilder.js.map +1 -1
- package/dist/core/agent/buildAgentChart.js +5 -1
- package/dist/core/agent/buildAgentChart.js.map +1 -1
- package/dist/core/agent/buildDynamicAgentChart.js +5 -1
- package/dist/core/agent/buildDynamicAgentChart.js.map +1 -1
- package/dist/core/agent/coverage/absent.js +163 -0
- package/dist/core/agent/coverage/absent.js.map +1 -0
- package/dist/core/agent/coverage/answer.js +90 -0
- package/dist/core/agent/coverage/answer.js.map +1 -0
- package/dist/core/agent/coverage/evidence.js +90 -0
- package/dist/core/agent/coverage/evidence.js.map +1 -0
- package/dist/core/agent/coverage/index.js +37 -0
- package/dist/core/agent/coverage/index.js.map +1 -0
- package/dist/core/agent/coverage/items.js +91 -0
- package/dist/core/agent/coverage/items.js.map +1 -0
- package/dist/core/agent/coverage/ledger.js +131 -0
- package/dist/core/agent/coverage/ledger.js.map +1 -0
- package/dist/core/agent/coverage/read.js +56 -0
- package/dist/core/agent/coverage/read.js.map +1 -0
- package/dist/core/agent/coverage/types.js +15 -0
- package/dist/core/agent/coverage/types.js.map +1 -0
- package/dist/core/agent/evidence/evidenceIndex.js +18 -1
- package/dist/core/agent/evidence/evidenceIndex.js.map +1 -1
- package/dist/core/agent/stages/prepareFinal.js +44 -3
- package/dist/core/agent/stages/prepareFinal.js.map +1 -1
- package/dist/core/agent/stages/toolCalls.js +109 -3
- package/dist/core/agent/stages/toolCalls.js.map +1 -1
- package/dist/core/agent/toolEffects.js +1 -1
- package/dist/core/outputFallback.js.map +1 -1
- package/dist/debug.js +49 -25
- package/dist/debug.js.map +1 -1
- package/dist/esm/adapters/hosting/agentcore.d.ts +8 -0
- package/dist/esm/adapters/hosting/agentcore.js +163 -23
- package/dist/esm/adapters/hosting/agentcore.js.map +1 -1
- package/dist/esm/adapters/hosting/firestoreSessions.d.ts +162 -14
- package/dist/esm/adapters/hosting/firestoreSessions.js +182 -13
- package/dist/esm/adapters/hosting/firestoreSessions.js.map +1 -1
- package/dist/esm/adapters/hosting/googleAgentEngine.d.ts +16 -1
- package/dist/esm/adapters/hosting/googleAgentEngine.js +29 -0
- package/dist/esm/adapters/hosting/googleAgentEngine.js.map +1 -1
- package/dist/esm/artifacts/conformance/cases.js +20 -0
- package/dist/esm/artifacts/conformance/cases.js.map +1 -1
- package/dist/esm/artifacts/scopePath.d.ts +31 -0
- package/dist/esm/artifacts/scopePath.js +41 -1
- package/dist/esm/artifacts/scopePath.js.map +1 -1
- package/dist/esm/core/Agent.d.ts +8 -1
- package/dist/esm/core/Agent.js +18 -2
- package/dist/esm/core/Agent.js.map +1 -1
- package/dist/esm/core/agent/AgentBuilder.d.ts +43 -0
- package/dist/esm/core/agent/AgentBuilder.js +56 -1
- package/dist/esm/core/agent/AgentBuilder.js.map +1 -1
- package/dist/esm/core/agent/buildAgentChart.d.ts +9 -0
- package/dist/esm/core/agent/buildAgentChart.js +6 -2
- package/dist/esm/core/agent/buildAgentChart.js.map +1 -1
- package/dist/esm/core/agent/buildDynamicAgentChart.js +6 -2
- package/dist/esm/core/agent/buildDynamicAgentChart.js.map +1 -1
- package/dist/esm/core/agent/coverage/absent.d.ts +104 -0
- package/dist/esm/core/agent/coverage/absent.js +157 -0
- package/dist/esm/core/agent/coverage/absent.js.map +1 -0
- package/dist/esm/core/agent/coverage/answer.d.ts +46 -0
- package/dist/esm/core/agent/coverage/answer.js +86 -0
- package/dist/esm/core/agent/coverage/answer.js.map +1 -0
- package/dist/esm/core/agent/coverage/evidence.d.ts +68 -0
- package/dist/esm/core/agent/coverage/evidence.js +86 -0
- package/dist/esm/core/agent/coverage/evidence.js.map +1 -0
- package/dist/esm/core/agent/coverage/index.d.ts +17 -0
- package/dist/esm/core/agent/coverage/index.js +17 -0
- package/dist/esm/core/agent/coverage/index.js.map +1 -0
- package/dist/esm/core/agent/coverage/items.d.ts +35 -0
- package/dist/esm/core/agent/coverage/items.js +85 -0
- package/dist/esm/core/agent/coverage/items.js.map +1 -0
- package/dist/esm/core/agent/coverage/ledger.d.ts +80 -0
- package/dist/esm/core/agent/coverage/ledger.js +125 -0
- package/dist/esm/core/agent/coverage/ledger.js.map +1 -0
- package/dist/esm/core/agent/coverage/read.d.ts +51 -0
- package/dist/esm/core/agent/coverage/read.js +52 -0
- package/dist/esm/core/agent/coverage/read.js.map +1 -0
- package/dist/esm/core/agent/coverage/types.d.ts +142 -0
- package/dist/esm/core/agent/coverage/types.js +14 -0
- package/dist/esm/core/agent/coverage/types.js.map +1 -0
- package/dist/esm/core/agent/evidence/evidenceIndex.d.ts +7 -0
- package/dist/esm/core/agent/evidence/evidenceIndex.js +18 -1
- package/dist/esm/core/agent/evidence/evidenceIndex.js.map +1 -1
- package/dist/esm/core/agent/stages/prepareFinal.d.ts +18 -0
- package/dist/esm/core/agent/stages/prepareFinal.js +42 -2
- package/dist/esm/core/agent/stages/prepareFinal.js.map +1 -1
- package/dist/esm/core/agent/stages/toolCalls.js +109 -3
- package/dist/esm/core/agent/stages/toolCalls.js.map +1 -1
- package/dist/esm/core/agent/toolEffects.d.ts +2 -2
- package/dist/esm/core/agent/toolEffects.js +1 -1
- package/dist/esm/core/agent/types.d.ts +14 -0
- package/dist/esm/core/outputFallback.d.ts +15 -1
- package/dist/esm/core/outputFallback.js.map +1 -1
- package/dist/esm/debug.d.ts +1 -0
- package/dist/esm/debug.js +7 -0
- package/dist/esm/debug.js.map +1 -1
- package/dist/esm/events/dispatcher.d.ts +1 -1
- package/dist/esm/events/dispatcher.js.map +1 -1
- package/dist/esm/events/payloads.d.ts +82 -0
- package/dist/esm/events/registry.d.ts +11 -1
- package/dist/esm/events/registry.js +10 -0
- package/dist/esm/events/registry.js.map +1 -1
- package/dist/esm/hosting/conformance/cases.d.ts +2 -1
- package/dist/esm/hosting/conformance/cases.js +229 -22
- package/dist/esm/hosting/conformance/cases.js.map +1 -1
- package/dist/esm/hosting/conformance/types.d.ts +7 -7
- package/dist/esm/hosting/errors.d.ts +28 -0
- package/dist/esm/hosting/errors.js +40 -0
- package/dist/esm/hosting/errors.js.map +1 -1
- package/dist/esm/hosting/index.d.ts +11 -3
- package/dist/esm/hosting/index.js +15 -2
- package/dist/esm/hosting/index.js.map +1 -1
- package/dist/esm/hosting/memorySessions.js +39 -0
- package/dist/esm/hosting/memorySessions.js.map +1 -1
- package/dist/esm/hosting/sessionRetention.d.ts +56 -0
- package/dist/esm/hosting/sessionRetention.js +69 -0
- package/dist/esm/hosting/sessionRetention.js.map +1 -0
- package/dist/esm/hosting/sqliteSessions.d.ts +11 -1
- package/dist/esm/hosting/sqliteSessions.js +51 -0
- package/dist/esm/hosting/sqliteSessions.js.map +1 -1
- package/dist/esm/hosting/types.d.ts +184 -0
- package/dist/esm/hosting/types.js +9 -0
- package/dist/esm/hosting/types.js.map +1 -1
- package/dist/esm/hosting-providers.d.ts +15 -11
- package/dist/esm/hosting-providers.js +21 -11
- package/dist/esm/hosting-providers.js.map +1 -1
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.js +18 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/lib/context-bisect/arms/apply.d.ts +54 -0
- package/dist/esm/lib/context-bisect/arms/apply.js +41 -0
- package/dist/esm/lib/context-bisect/arms/apply.js.map +1 -0
- package/dist/esm/lib/context-bisect/arms/compare.d.ts +27 -0
- package/dist/esm/lib/context-bisect/arms/compare.js +112 -0
- package/dist/esm/lib/context-bisect/arms/compare.js.map +1 -0
- package/dist/esm/lib/context-bisect/arms/index.d.ts +16 -0
- package/dist/esm/lib/context-bisect/arms/index.js +16 -0
- package/dist/esm/lib/context-bisect/arms/index.js.map +1 -0
- package/dist/esm/lib/context-bisect/arms/manifest.d.ts +79 -0
- package/dist/esm/lib/context-bisect/arms/manifest.js +199 -0
- package/dist/esm/lib/context-bisect/arms/manifest.js.map +1 -0
- package/dist/esm/lib/context-bisect/arms/probe.d.ts +54 -0
- package/dist/esm/lib/context-bisect/arms/probe.js +125 -0
- package/dist/esm/lib/context-bisect/arms/probe.js.map +1 -0
- package/dist/esm/lib/context-bisect/arms/types.d.ts +319 -0
- package/dist/esm/lib/context-bisect/arms/types.js +67 -0
- package/dist/esm/lib/context-bisect/arms/types.js.map +1 -0
- package/dist/esm/lib/context-bisect/arms/validate.d.ts +26 -0
- package/dist/esm/lib/context-bisect/arms/validate.js +122 -0
- package/dist/esm/lib/context-bisect/arms/validate.js.map +1 -0
- package/dist/esm/lib/context-bisect/arms/verdict.d.ts +53 -0
- package/dist/esm/lib/context-bisect/arms/verdict.js +103 -0
- package/dist/esm/lib/context-bisect/arms/verdict.js.map +1 -0
- package/dist/esm/lib/context-bisect/index.d.ts +1 -0
- package/dist/esm/lib/context-bisect/index.js +5 -0
- package/dist/esm/lib/context-bisect/index.js.map +1 -1
- package/dist/esm/lib/injection-engine/index.d.ts +1 -1
- package/dist/esm/lib/injection-engine/index.js +3 -1
- package/dist/esm/lib/injection-engine/index.js.map +1 -1
- package/dist/esm/lib/injection-engine/skillExamples.d.ts +16 -13
- package/dist/esm/lib/injection-engine/skillExamples.js +16 -60
- package/dist/esm/lib/injection-engine/skillExamples.js.map +1 -1
- package/dist/esm/lib/injection-engine/skillGraph.d.ts +50 -0
- package/dist/esm/lib/injection-engine/skillGraph.js +52 -1
- package/dist/esm/lib/injection-engine/skillGraph.js.map +1 -1
- package/dist/esm/lib/injection-engine/skillGraphCheckup.d.ts +6 -5
- package/dist/esm/lib/injection-engine/skillGraphCheckup.js.map +1 -1
- package/dist/esm/lib/injection-engine/skillNeverRoutes.d.ts +131 -0
- package/dist/esm/lib/injection-engine/skillNeverRoutes.js +228 -0
- package/dist/esm/lib/injection-engine/skillNeverRoutes.js.map +1 -0
- package/dist/esm/lib/injection-engine/skillPartition.d.ts +69 -0
- package/dist/esm/lib/injection-engine/skillPartition.js +273 -0
- package/dist/esm/lib/injection-engine/skillPartition.js.map +1 -0
- package/dist/esm/lib/injection-engine/skillsFromDir.d.ts +83 -3
- package/dist/esm/lib/injection-engine/skillsFromDir.js +118 -7
- package/dist/esm/lib/injection-engine/skillsFromDir.js.map +1 -1
- package/dist/esm/lib/injection-engine/skillsFromDirRoutes.d.ts +105 -0
- package/dist/esm/lib/injection-engine/skillsFromDirRoutes.js +169 -0
- package/dist/esm/lib/injection-engine/skillsFromDirRoutes.js.map +1 -0
- package/dist/esm/lib/injection-engine/startRuleClaim.d.ts +91 -0
- package/dist/esm/lib/injection-engine/startRuleClaim.js +78 -0
- package/dist/esm/lib/injection-engine/startRuleClaim.js.map +1 -0
- package/dist/esm/lib/injection-engine/toolOutcome.d.ts +12 -3
- package/dist/esm/lib/injection-engine/toolOutcome.js +2 -1
- package/dist/esm/lib/injection-engine/toolOutcome.js.map +1 -1
- package/dist/events/dispatcher.js.map +1 -1
- package/dist/events/registry.js +10 -0
- package/dist/events/registry.js.map +1 -1
- package/dist/hosting/conformance/cases.js +229 -22
- package/dist/hosting/conformance/cases.js.map +1 -1
- package/dist/hosting/errors.js +42 -1
- package/dist/hosting/errors.js.map +1 -1
- package/dist/hosting/index.js +18 -2
- package/dist/hosting/index.js.map +1 -1
- package/dist/hosting/memorySessions.js +39 -0
- package/dist/hosting/memorySessions.js.map +1 -1
- package/dist/hosting/sessionRetention.js +73 -0
- package/dist/hosting/sessionRetention.js.map +1 -0
- package/dist/hosting/sqliteSessions.js +51 -0
- package/dist/hosting/sqliteSessions.js.map +1 -1
- package/dist/hosting/types.js +10 -1
- package/dist/hosting/types.js.map +1 -1
- package/dist/hosting-providers.js +21 -11
- package/dist/hosting-providers.js.map +1 -1
- package/dist/index.js +72 -43
- package/dist/index.js.map +1 -1
- package/dist/lib/context-bisect/arms/apply.js +45 -0
- package/dist/lib/context-bisect/arms/apply.js.map +1 -0
- package/dist/lib/context-bisect/arms/compare.js +116 -0
- package/dist/lib/context-bisect/arms/compare.js.map +1 -0
- package/dist/lib/context-bisect/arms/index.js +35 -0
- package/dist/lib/context-bisect/arms/index.js.map +1 -0
- package/dist/lib/context-bisect/arms/manifest.js +207 -0
- package/dist/lib/context-bisect/arms/manifest.js.map +1 -0
- package/dist/lib/context-bisect/arms/probe.js +132 -0
- package/dist/lib/context-bisect/arms/probe.js.map +1 -0
- package/dist/lib/context-bisect/arms/types.js +68 -0
- package/dist/lib/context-bisect/arms/types.js.map +1 -0
- package/dist/lib/context-bisect/arms/validate.js +128 -0
- package/dist/lib/context-bisect/arms/validate.js.map +1 -0
- package/dist/lib/context-bisect/arms/verdict.js +107 -0
- package/dist/lib/context-bisect/arms/verdict.js.map +1 -0
- package/dist/lib/context-bisect/index.js +23 -1
- package/dist/lib/context-bisect/index.js.map +1 -1
- package/dist/lib/injection-engine/index.js +4 -1
- package/dist/lib/injection-engine/index.js.map +1 -1
- package/dist/lib/injection-engine/skillExamples.js +24 -68
- package/dist/lib/injection-engine/skillExamples.js.map +1 -1
- package/dist/lib/injection-engine/skillGraph.js +52 -1
- package/dist/lib/injection-engine/skillGraph.js.map +1 -1
- package/dist/lib/injection-engine/skillGraphCheckup.js.map +1 -1
- package/dist/lib/injection-engine/skillNeverRoutes.js +234 -0
- package/dist/lib/injection-engine/skillNeverRoutes.js.map +1 -0
- package/dist/lib/injection-engine/skillPartition.js +277 -0
- package/dist/lib/injection-engine/skillPartition.js.map +1 -0
- package/dist/lib/injection-engine/skillsFromDir.js +121 -9
- package/dist/lib/injection-engine/skillsFromDir.js.map +1 -1
- package/dist/lib/injection-engine/skillsFromDirRoutes.js +174 -0
- package/dist/lib/injection-engine/skillsFromDirRoutes.js.map +1 -0
- package/dist/lib/injection-engine/startRuleClaim.js +85 -0
- package/dist/lib/injection-engine/startRuleClaim.js.map +1 -0
- package/dist/lib/injection-engine/toolOutcome.js +2 -1
- package/dist/lib/injection-engine/toolOutcome.js.map +1 -1
- package/dist/types/adapters/hosting/agentcore.d.ts +8 -0
- package/dist/types/adapters/hosting/agentcore.d.ts.map +1 -1
- package/dist/types/adapters/hosting/firestoreSessions.d.ts +162 -14
- package/dist/types/adapters/hosting/firestoreSessions.d.ts.map +1 -1
- package/dist/types/adapters/hosting/googleAgentEngine.d.ts +16 -1
- package/dist/types/adapters/hosting/googleAgentEngine.d.ts.map +1 -1
- package/dist/types/artifacts/conformance/cases.d.ts.map +1 -1
- package/dist/types/artifacts/scopePath.d.ts +31 -0
- package/dist/types/artifacts/scopePath.d.ts.map +1 -1
- package/dist/types/core/Agent.d.ts +8 -1
- package/dist/types/core/Agent.d.ts.map +1 -1
- package/dist/types/core/agent/AgentBuilder.d.ts +43 -0
- package/dist/types/core/agent/AgentBuilder.d.ts.map +1 -1
- package/dist/types/core/agent/buildAgentChart.d.ts +9 -0
- package/dist/types/core/agent/buildAgentChart.d.ts.map +1 -1
- package/dist/types/core/agent/buildDynamicAgentChart.d.ts.map +1 -1
- package/dist/types/core/agent/coverage/absent.d.ts +105 -0
- package/dist/types/core/agent/coverage/absent.d.ts.map +1 -0
- package/dist/types/core/agent/coverage/answer.d.ts +47 -0
- package/dist/types/core/agent/coverage/answer.d.ts.map +1 -0
- package/dist/types/core/agent/coverage/evidence.d.ts +69 -0
- package/dist/types/core/agent/coverage/evidence.d.ts.map +1 -0
- package/dist/types/core/agent/coverage/index.d.ts +18 -0
- package/dist/types/core/agent/coverage/index.d.ts.map +1 -0
- package/dist/types/core/agent/coverage/items.d.ts +36 -0
- package/dist/types/core/agent/coverage/items.d.ts.map +1 -0
- package/dist/types/core/agent/coverage/ledger.d.ts +81 -0
- package/dist/types/core/agent/coverage/ledger.d.ts.map +1 -0
- package/dist/types/core/agent/coverage/read.d.ts +52 -0
- package/dist/types/core/agent/coverage/read.d.ts.map +1 -0
- package/dist/types/core/agent/coverage/types.d.ts +143 -0
- package/dist/types/core/agent/coverage/types.d.ts.map +1 -0
- package/dist/types/core/agent/evidence/evidenceIndex.d.ts +7 -0
- package/dist/types/core/agent/evidence/evidenceIndex.d.ts.map +1 -1
- package/dist/types/core/agent/stages/prepareFinal.d.ts +18 -0
- package/dist/types/core/agent/stages/prepareFinal.d.ts.map +1 -1
- package/dist/types/core/agent/stages/toolCalls.d.ts.map +1 -1
- package/dist/types/core/agent/toolEffects.d.ts +2 -2
- package/dist/types/core/agent/types.d.ts +14 -0
- package/dist/types/core/agent/types.d.ts.map +1 -1
- package/dist/types/core/outputFallback.d.ts +15 -1
- package/dist/types/core/outputFallback.d.ts.map +1 -1
- package/dist/types/debug.d.ts +1 -0
- package/dist/types/debug.d.ts.map +1 -1
- package/dist/types/events/dispatcher.d.ts +1 -1
- package/dist/types/events/dispatcher.d.ts.map +1 -1
- package/dist/types/events/payloads.d.ts +82 -0
- package/dist/types/events/payloads.d.ts.map +1 -1
- package/dist/types/events/registry.d.ts +11 -1
- package/dist/types/events/registry.d.ts.map +1 -1
- package/dist/types/hosting/conformance/cases.d.ts +2 -1
- package/dist/types/hosting/conformance/cases.d.ts.map +1 -1
- package/dist/types/hosting/conformance/types.d.ts +7 -7
- package/dist/types/hosting/conformance/types.d.ts.map +1 -1
- package/dist/types/hosting/errors.d.ts +28 -0
- package/dist/types/hosting/errors.d.ts.map +1 -1
- package/dist/types/hosting/index.d.ts +11 -3
- package/dist/types/hosting/index.d.ts.map +1 -1
- package/dist/types/hosting/memorySessions.d.ts.map +1 -1
- package/dist/types/hosting/sessionRetention.d.ts +57 -0
- package/dist/types/hosting/sessionRetention.d.ts.map +1 -0
- package/dist/types/hosting/sqliteSessions.d.ts +11 -1
- package/dist/types/hosting/sqliteSessions.d.ts.map +1 -1
- package/dist/types/hosting/types.d.ts +184 -0
- package/dist/types/hosting/types.d.ts.map +1 -1
- package/dist/types/hosting-providers.d.ts +15 -11
- package/dist/types/hosting-providers.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/lib/context-bisect/arms/apply.d.ts +55 -0
- package/dist/types/lib/context-bisect/arms/apply.d.ts.map +1 -0
- package/dist/types/lib/context-bisect/arms/compare.d.ts +28 -0
- package/dist/types/lib/context-bisect/arms/compare.d.ts.map +1 -0
- package/dist/types/lib/context-bisect/arms/index.d.ts +17 -0
- package/dist/types/lib/context-bisect/arms/index.d.ts.map +1 -0
- package/dist/types/lib/context-bisect/arms/manifest.d.ts +80 -0
- package/dist/types/lib/context-bisect/arms/manifest.d.ts.map +1 -0
- package/dist/types/lib/context-bisect/arms/probe.d.ts +55 -0
- package/dist/types/lib/context-bisect/arms/probe.d.ts.map +1 -0
- package/dist/types/lib/context-bisect/arms/types.d.ts +320 -0
- package/dist/types/lib/context-bisect/arms/types.d.ts.map +1 -0
- package/dist/types/lib/context-bisect/arms/validate.d.ts +27 -0
- package/dist/types/lib/context-bisect/arms/validate.d.ts.map +1 -0
- package/dist/types/lib/context-bisect/arms/verdict.d.ts +54 -0
- package/dist/types/lib/context-bisect/arms/verdict.d.ts.map +1 -0
- package/dist/types/lib/context-bisect/index.d.ts +1 -0
- package/dist/types/lib/context-bisect/index.d.ts.map +1 -1
- package/dist/types/lib/injection-engine/index.d.ts +1 -1
- package/dist/types/lib/injection-engine/index.d.ts.map +1 -1
- package/dist/types/lib/injection-engine/skillExamples.d.ts +16 -13
- package/dist/types/lib/injection-engine/skillExamples.d.ts.map +1 -1
- package/dist/types/lib/injection-engine/skillGraph.d.ts +50 -0
- package/dist/types/lib/injection-engine/skillGraph.d.ts.map +1 -1
- package/dist/types/lib/injection-engine/skillGraphCheckup.d.ts +6 -5
- package/dist/types/lib/injection-engine/skillGraphCheckup.d.ts.map +1 -1
- package/dist/types/lib/injection-engine/skillNeverRoutes.d.ts +132 -0
- package/dist/types/lib/injection-engine/skillNeverRoutes.d.ts.map +1 -0
- package/dist/types/lib/injection-engine/skillPartition.d.ts +70 -0
- package/dist/types/lib/injection-engine/skillPartition.d.ts.map +1 -0
- package/dist/types/lib/injection-engine/skillsFromDir.d.ts +83 -3
- package/dist/types/lib/injection-engine/skillsFromDir.d.ts.map +1 -1
- package/dist/types/lib/injection-engine/skillsFromDirRoutes.d.ts +106 -0
- package/dist/types/lib/injection-engine/skillsFromDirRoutes.d.ts.map +1 -0
- package/dist/types/lib/injection-engine/startRuleClaim.d.ts +92 -0
- package/dist/types/lib/injection-engine/startRuleClaim.d.ts.map +1 -0
- package/dist/types/lib/injection-engine/toolOutcome.d.ts +12 -3
- package/dist/types/lib/injection-engine/toolOutcome.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skillNeverRoutes.js","sourceRoot":"","sources":["../../../../src/lib/injection-engine/skillNeverRoutes.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* skillPartition — three ADVISORY signals about the shape of the partition
|
|
3
|
+
* itself: how a graph cut the world into skills.
|
|
4
|
+
*
|
|
5
|
+
* ## Why the partition is worth a check at all
|
|
6
|
+
*
|
|
7
|
+
* Everything else the check-up reports is a wiring fact — an edge to a skill
|
|
8
|
+
* that is not there, a rule that can never win. The partition is upstream of
|
|
9
|
+
* all of it, and it is the decision with the most leverage: a graph whose
|
|
10
|
+
* skills follow SYSTEMS rather than CAPABILITIES makes one ordinary question
|
|
11
|
+
* cross four skills, and the capability the user actually wanted ends up
|
|
12
|
+
* implemented outside the graph, by hand, where nothing can see it. Field use
|
|
13
|
+
* produced exactly that shape — nineteen skills, ONE declared edge, and tool
|
|
14
|
+
* names carrying the system that owns them (`influx_*`, `pmax_*`, `pstore_*`,
|
|
15
|
+
* `rvtools_*`) with the skills following the prefixes.
|
|
16
|
+
*
|
|
17
|
+
* The important part: all three of those are visible from NAMES AND STRUCTURE
|
|
18
|
+
* ALONE, at build time, with no run and no model. So the runtime can say them.
|
|
19
|
+
*
|
|
20
|
+
* ## Why every one of them is an advisory, and stays one
|
|
21
|
+
*
|
|
22
|
+
* Each signal has a legitimate design behind it:
|
|
23
|
+
*
|
|
24
|
+
* • a skill really can be one system's capability (a weather skill wrapping a
|
|
25
|
+
* weather API is not a mistake);
|
|
26
|
+
* • a deliberately FLAT menu of independent skills really does declare almost
|
|
27
|
+
* no edges — a scorer or the model picks, and there is nothing to hand off;
|
|
28
|
+
* • a one-call capability really can be one tool with a short body.
|
|
29
|
+
*
|
|
30
|
+
* So none of them is ever an error, and none of them says "this is wrong". Each
|
|
31
|
+
* message states the SIGNAL AS A FACT the author can check against their own
|
|
32
|
+
* intent — "your 19 skills declare 1 route", "every tool in `powerstore` shares
|
|
33
|
+
* the prefix `pstore_`" — and then names the design each fact usually indicates
|
|
34
|
+
* and the design it is also consistent with. This library's check-up teaches;
|
|
35
|
+
* it does not grade.
|
|
36
|
+
*
|
|
37
|
+
* ## The thresholds, and why each one is where it is
|
|
38
|
+
*
|
|
39
|
+
* Named constants below, each with the argument beside it. They are chosen so a
|
|
40
|
+
* SMALL graph is silent (small graphs have no partition problem worth naming),
|
|
41
|
+
* so a trivially-true observation is never dressed up as a finding (one tool
|
|
42
|
+
* shares a prefix with itself), and so the commonest honest naming convention —
|
|
43
|
+
* a VERB first — never fires.
|
|
44
|
+
*
|
|
45
|
+
* Zone: PURE CORE. Pinned by
|
|
46
|
+
* `test/lib/injection-engine/skill-graph-fence.test.ts`.
|
|
47
|
+
*/
|
|
48
|
+
import type { GraphProblem } from './skillGraphCheckup.js';
|
|
49
|
+
import type { Injection } from './types.js';
|
|
50
|
+
/** What the partition check reads. Counts, because that is what the signals
|
|
51
|
+
* are about — no check here reasons about which edge goes where. */
|
|
52
|
+
export interface PartitionInput {
|
|
53
|
+
/** Every skill in the graph (wired or not). */
|
|
54
|
+
readonly skills: readonly Injection[];
|
|
55
|
+
/** Declared routes, of any kind (a bare/model edge is still a declared
|
|
56
|
+
* handoff — the signal is about handoffs that were never written down at
|
|
57
|
+
* all, not about how deterministic they are). */
|
|
58
|
+
readonly routeCount: number;
|
|
59
|
+
/** Declared entries — quoted in the ratio message so the fact is complete. */
|
|
60
|
+
readonly entryCount: number;
|
|
61
|
+
/** A decision `tree()` owns its own routing and declares no routes by
|
|
62
|
+
* construction, so the edge-ratio signal does not apply there. */
|
|
63
|
+
readonly isTree: boolean;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Run the three partition signals. Pure, and cheap: one pass over the skills
|
|
67
|
+
* and two integers. Every problem it produces is a WARNING.
|
|
68
|
+
*/
|
|
69
|
+
export declare function checkPartition(input: PartitionInput): GraphProblem[];
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* skillPartition — three ADVISORY signals about the shape of the partition
|
|
3
|
+
* itself: how a graph cut the world into skills.
|
|
4
|
+
*
|
|
5
|
+
* ## Why the partition is worth a check at all
|
|
6
|
+
*
|
|
7
|
+
* Everything else the check-up reports is a wiring fact — an edge to a skill
|
|
8
|
+
* that is not there, a rule that can never win. The partition is upstream of
|
|
9
|
+
* all of it, and it is the decision with the most leverage: a graph whose
|
|
10
|
+
* skills follow SYSTEMS rather than CAPABILITIES makes one ordinary question
|
|
11
|
+
* cross four skills, and the capability the user actually wanted ends up
|
|
12
|
+
* implemented outside the graph, by hand, where nothing can see it. Field use
|
|
13
|
+
* produced exactly that shape — nineteen skills, ONE declared edge, and tool
|
|
14
|
+
* names carrying the system that owns them (`influx_*`, `pmax_*`, `pstore_*`,
|
|
15
|
+
* `rvtools_*`) with the skills following the prefixes.
|
|
16
|
+
*
|
|
17
|
+
* The important part: all three of those are visible from NAMES AND STRUCTURE
|
|
18
|
+
* ALONE, at build time, with no run and no model. So the runtime can say them.
|
|
19
|
+
*
|
|
20
|
+
* ## Why every one of them is an advisory, and stays one
|
|
21
|
+
*
|
|
22
|
+
* Each signal has a legitimate design behind it:
|
|
23
|
+
*
|
|
24
|
+
* • a skill really can be one system's capability (a weather skill wrapping a
|
|
25
|
+
* weather API is not a mistake);
|
|
26
|
+
* • a deliberately FLAT menu of independent skills really does declare almost
|
|
27
|
+
* no edges — a scorer or the model picks, and there is nothing to hand off;
|
|
28
|
+
* • a one-call capability really can be one tool with a short body.
|
|
29
|
+
*
|
|
30
|
+
* So none of them is ever an error, and none of them says "this is wrong". Each
|
|
31
|
+
* message states the SIGNAL AS A FACT the author can check against their own
|
|
32
|
+
* intent — "your 19 skills declare 1 route", "every tool in `powerstore` shares
|
|
33
|
+
* the prefix `pstore_`" — and then names the design each fact usually indicates
|
|
34
|
+
* and the design it is also consistent with. This library's check-up teaches;
|
|
35
|
+
* it does not grade.
|
|
36
|
+
*
|
|
37
|
+
* ## The thresholds, and why each one is where it is
|
|
38
|
+
*
|
|
39
|
+
* Named constants below, each with the argument beside it. They are chosen so a
|
|
40
|
+
* SMALL graph is silent (small graphs have no partition problem worth naming),
|
|
41
|
+
* so a trivially-true observation is never dressed up as a finding (one tool
|
|
42
|
+
* shares a prefix with itself), and so the commonest honest naming convention —
|
|
43
|
+
* a VERB first — never fires.
|
|
44
|
+
*
|
|
45
|
+
* Zone: PURE CORE. Pinned by
|
|
46
|
+
* `test/lib/injection-engine/skill-graph-fence.test.ts`.
|
|
47
|
+
*/
|
|
48
|
+
import { skillToolNames } from './skillContract.js';
|
|
49
|
+
/**
|
|
50
|
+
* How many tools a skill needs before "they all share a prefix" is evidence of
|
|
51
|
+
* anything. ONE tool shares a prefix with itself — a trivial truth, and the
|
|
52
|
+
* skill it describes has its own signal below. TWO is two coin flips; a
|
|
53
|
+
* `get_order` / `get_invoice` pair is a naming habit, not a system boundary.
|
|
54
|
+
* At THREE the shared prefix is a decision somebody made about scope.
|
|
55
|
+
*/
|
|
56
|
+
const MIN_TOOLS_FOR_PREFIX = 3;
|
|
57
|
+
/**
|
|
58
|
+
* First segments that are NOT a system — they are the verb half of the house
|
|
59
|
+
* naming convention (`get_price`, `issue_refund`, `lookup_order`). Verified
|
|
60
|
+
* against this repo's real tool names, where the ten commonest first segments
|
|
61
|
+
* are all verbs and outnumber every system prefix put together: without this
|
|
62
|
+
* list the check would fire on the best-named skills in the library, which is
|
|
63
|
+
* the fastest way to teach an author to ignore a check-up.
|
|
64
|
+
*
|
|
65
|
+
* The test is deliberately crude — a first segment either IS one of these words
|
|
66
|
+
* or it is not. A cleverer part-of-speech guess would be wrong more quietly.
|
|
67
|
+
*/
|
|
68
|
+
const VERB_PREFIXES = new Set([
|
|
69
|
+
'get',
|
|
70
|
+
'set',
|
|
71
|
+
'put',
|
|
72
|
+
'post',
|
|
73
|
+
'add',
|
|
74
|
+
'read',
|
|
75
|
+
'write',
|
|
76
|
+
'list',
|
|
77
|
+
'find',
|
|
78
|
+
'fetch',
|
|
79
|
+
'load',
|
|
80
|
+
'save',
|
|
81
|
+
'open',
|
|
82
|
+
'close',
|
|
83
|
+
'make',
|
|
84
|
+
'create',
|
|
85
|
+
'update',
|
|
86
|
+
'delete',
|
|
87
|
+
'remove',
|
|
88
|
+
'search',
|
|
89
|
+
'query',
|
|
90
|
+
'count',
|
|
91
|
+
'check',
|
|
92
|
+
'verify',
|
|
93
|
+
'validate',
|
|
94
|
+
'run',
|
|
95
|
+
'exec',
|
|
96
|
+
'execute',
|
|
97
|
+
'send',
|
|
98
|
+
'call',
|
|
99
|
+
'ask',
|
|
100
|
+
'show',
|
|
101
|
+
'lookup',
|
|
102
|
+
'issue',
|
|
103
|
+
'approve',
|
|
104
|
+
'deny',
|
|
105
|
+
'pay',
|
|
106
|
+
'process',
|
|
107
|
+
'resolve',
|
|
108
|
+
'respond',
|
|
109
|
+
'inspect',
|
|
110
|
+
'export',
|
|
111
|
+
'import',
|
|
112
|
+
'start',
|
|
113
|
+
'stop',
|
|
114
|
+
'cancel',
|
|
115
|
+
'compute',
|
|
116
|
+
'calculate',
|
|
117
|
+
'generate',
|
|
118
|
+
'summarize',
|
|
119
|
+
'transform',
|
|
120
|
+
]);
|
|
121
|
+
/**
|
|
122
|
+
* The floor under ALL THREE signals: below this many skills there is no
|
|
123
|
+
* partition to have an opinion about.
|
|
124
|
+
*
|
|
125
|
+
* This is the module's one structural decision, and it is what keeps the
|
|
126
|
+
* advisories quiet by construction. Every signal here is a statement about how
|
|
127
|
+
* a graph CUT THE WORLD; a two-skill graph with no edge is a menu, one skill
|
|
128
|
+
* wrapping one tool is a choice about that skill, and a pair of tools sharing a
|
|
129
|
+
* prefix is a naming habit. None of those become a partition question until
|
|
130
|
+
* there are enough skills for the cut itself to be the design — and the field
|
|
131
|
+
* case that motivated all three had nineteen. A check that fires on a
|
|
132
|
+
* three-skill graph teaches an author to stop reading the check-up, which costs
|
|
133
|
+
* more than the finding is worth.
|
|
134
|
+
*/
|
|
135
|
+
const MIN_SKILLS_FOR_PARTITION = 5;
|
|
136
|
+
/**
|
|
137
|
+
* The ratio that counts as "almost no declared edges". A graph needs N−1 edges
|
|
138
|
+
* to connect N skills into one routed structure; this fires below ONE EDGE PER
|
|
139
|
+
* FOUR SKILLS, which is four times sparser than a bare chain — far enough from
|
|
140
|
+
* the boundary that a graph tripping it is not a matter of taste. (The field
|
|
141
|
+
* case: 19 skills, 1 route — a ratio of 0.05.)
|
|
142
|
+
*/
|
|
143
|
+
const MIN_ROUTES_PER_SKILL = 0.25;
|
|
144
|
+
/**
|
|
145
|
+
* Word count below which a body carries no knowledge the tool schema does not
|
|
146
|
+
* already carry. One sentence of real guidance — when to reach for this, what
|
|
147
|
+
* to check first, what the failure looks like — does not fit in 25 words, so a
|
|
148
|
+
* body under it is either a restatement of the tool's own description or a
|
|
149
|
+
* placeholder. Counted in whitespace-separated words, the only measure that
|
|
150
|
+
* means the same thing in prose as in markdown.
|
|
151
|
+
*/
|
|
152
|
+
const THIN_BODY_WORDS = 25;
|
|
153
|
+
/**
|
|
154
|
+
* Run the three partition signals. Pure, and cheap: one pass over the skills
|
|
155
|
+
* and two integers. Every problem it produces is a WARNING.
|
|
156
|
+
*/
|
|
157
|
+
export function checkPartition(input) {
|
|
158
|
+
const skillCount = input.skills.length;
|
|
159
|
+
// The floor, applied once for all three signals — see
|
|
160
|
+
// MIN_SKILLS_FOR_PARTITION. A small graph reports byte-identically to the
|
|
161
|
+
// way it did before this module existed.
|
|
162
|
+
if (skillCount < MIN_SKILLS_FOR_PARTITION)
|
|
163
|
+
return [];
|
|
164
|
+
const problems = [];
|
|
165
|
+
for (const skill of input.skills) {
|
|
166
|
+
const tools = skillToolNames(skill);
|
|
167
|
+
const id = idOf(skill);
|
|
168
|
+
// 1. tools-share-prefix — every tool in the skill comes from one system.
|
|
169
|
+
// Computed from the first `_`-delimited segment, which is where a system
|
|
170
|
+
// prefix lives when there is one (`pstore_list_volumes` → `pstore`), and
|
|
171
|
+
// silent when that segment is a verb (see VERB_PREFIXES).
|
|
172
|
+
const prefix = sharedPrefix(tools);
|
|
173
|
+
if (tools.length >= MIN_TOOLS_FOR_PREFIX && prefix !== undefined) {
|
|
174
|
+
problems.push({
|
|
175
|
+
kind: 'warning',
|
|
176
|
+
code: 'tools-share-prefix',
|
|
177
|
+
message: `Every tool in "${id}" shares the prefix \`${prefix}_\` (${tools.join(', ')}). ` +
|
|
178
|
+
`A skill whose whole tool set comes from one system is usually a wrapper around ` +
|
|
179
|
+
`that SYSTEM rather than a CAPABILITY — and when the skills follow the systems, one ` +
|
|
180
|
+
`ordinary question crosses several of them, so the thing the user actually asked ` +
|
|
181
|
+
`for gets built outside the graph where nothing can route it. Worth checking: ` +
|
|
182
|
+
`could a user's question be answered by "${id}" alone, or does answering it need ` +
|
|
183
|
+
`two of these skills at once? If it needs two, the capability is the skill and ` +
|
|
184
|
+
`\`${prefix}_\` is just where its tools happen to come from. If "${id}" really is ` +
|
|
185
|
+
`one system's capability, this is exactly right and there is nothing to fix.`,
|
|
186
|
+
skill: id,
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
// 2. skill-wraps-one-tool — one tool, and a body that adds nothing to its
|
|
190
|
+
// schema. The body is what the model reads to decide HOW to use the
|
|
191
|
+
// tool; when it is this short there is no procedure in the graph, only
|
|
192
|
+
// an endpoint with a name.
|
|
193
|
+
if (tools.length === 1 && tools[0] !== undefined) {
|
|
194
|
+
const words = wordCount(bodyOf(skill));
|
|
195
|
+
if (words < THIN_BODY_WORDS) {
|
|
196
|
+
problems.push({
|
|
197
|
+
kind: 'warning',
|
|
198
|
+
code: 'skill-wraps-one-tool',
|
|
199
|
+
message: `Skill "${id}" carries one tool (\`${tools[0]}\`) and a ${words}-word body — ` +
|
|
200
|
+
`under the ${THIN_BODY_WORDS} words it takes to say when to reach for it, what to ` +
|
|
201
|
+
`check first, or what a bad answer looks like. A skill whose body adds nothing to ` +
|
|
202
|
+
`the tool's own schema is an endpoint wrapper: the model already sees the tool, so ` +
|
|
203
|
+
`the skill buys nothing but a name and an activation. Either put the knowledge in ` +
|
|
204
|
+
`the body (that is the half a schema cannot carry), or drop the skill and register ` +
|
|
205
|
+
`\`${tools[0]}\` on the agent directly. If it is genuinely a one-call capability ` +
|
|
206
|
+
`with nothing to say about it, registering the tool is the smaller thing.`,
|
|
207
|
+
skill: id,
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
// 3. few-declared-edges — many skills, almost no declared handoffs. A graph
|
|
213
|
+
// level fact, reported once, and never for a tree (a tree declares its
|
|
214
|
+
// routing as the tree).
|
|
215
|
+
if (!input.isTree && input.routeCount < skillCount * MIN_ROUTES_PER_SKILL) {
|
|
216
|
+
problems.push({
|
|
217
|
+
kind: 'warning',
|
|
218
|
+
code: 'few-declared-edges',
|
|
219
|
+
message: `This graph declares ${plural(skillCount, 'skill', 'skills')}, ${plural(input.entryCount, 'entry', 'entries')} and ${plural(input.routeCount, 'route', 'routes')} — fewer than one route per four ` +
|
|
220
|
+
`skills, where connecting ${skillCount} skills into one routed structure takes at ` +
|
|
221
|
+
`least ${skillCount - 1}. When skills hand off to each other in PROSE ("then use the ` +
|
|
222
|
+
`capacity skill"), the handoff is invisible: nothing draws it, \`checkup()\` cannot ` +
|
|
223
|
+
`check it, the reachability walk cannot see it, and \`read_skill\`'s gate cannot ` +
|
|
224
|
+
`offer it — the model is left to infer the sequence every turn. Declaring the ones ` +
|
|
225
|
+
`you already rely on (\`.route(a, b, { onToolReturn })\`) turns each into something ` +
|
|
226
|
+
`the graph can route and a reader can see. If this is a deliberately flat menu of ` +
|
|
227
|
+
`independent skills — a scorer or the model picks one and it answers alone — then ` +
|
|
228
|
+
`there is nothing to hand off and this is the shape you meant.`,
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
return problems;
|
|
232
|
+
}
|
|
233
|
+
/** The id, read structurally like every other check in this family. */
|
|
234
|
+
function idOf(skill) {
|
|
235
|
+
return skill.id;
|
|
236
|
+
}
|
|
237
|
+
/** The skill's BODY — the prose that lands in the system slot when it
|
|
238
|
+
* activates. Same accessor `skillContract.ts` reads. */
|
|
239
|
+
function bodyOf(skill) {
|
|
240
|
+
return skill.inject?.systemPrompt ?? '';
|
|
241
|
+
}
|
|
242
|
+
function wordCount(text) {
|
|
243
|
+
const trimmed = text.trim();
|
|
244
|
+
return trimmed.length === 0 ? 0 : trimmed.split(/\s+/).length;
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* The first `_`-delimited segment shared by EVERY name, or undefined when there
|
|
248
|
+
* is none, when a name carries no `_` at all, or when the shared segment is a
|
|
249
|
+
* verb (a convention, not a system — see {@link VERB_PREFIXES}).
|
|
250
|
+
*
|
|
251
|
+
* Case-folded, because a tool registry that mixes `PSTORE_get` and
|
|
252
|
+
* `pstore_list` is still one system.
|
|
253
|
+
*/
|
|
254
|
+
function sharedPrefix(names) {
|
|
255
|
+
if (names.length === 0)
|
|
256
|
+
return undefined;
|
|
257
|
+
let shared;
|
|
258
|
+
for (const name of names) {
|
|
259
|
+
const separator = name.indexOf('_');
|
|
260
|
+
if (separator <= 0)
|
|
261
|
+
return undefined; // no prefix segment to speak of
|
|
262
|
+
const segment = name.slice(0, separator).toLowerCase();
|
|
263
|
+
if (shared === undefined)
|
|
264
|
+
shared = segment;
|
|
265
|
+
else if (shared !== segment)
|
|
266
|
+
return undefined;
|
|
267
|
+
}
|
|
268
|
+
return shared !== undefined && !VERB_PREFIXES.has(shared) ? shared : undefined;
|
|
269
|
+
}
|
|
270
|
+
function plural(n, one, many) {
|
|
271
|
+
return `${n} ${n === 1 ? one : many}`;
|
|
272
|
+
}
|
|
273
|
+
//# sourceMappingURL=skillPartition.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skillPartition.js","sourceRoot":"","sources":["../../../../src/lib/injection-engine/skillPartition.ts"],"names":[],"mappings":"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"}
|
|
@@ -76,9 +76,36 @@
|
|
|
76
76
|
* others take `defineSkill`'s defaults.
|
|
77
77
|
* - unknown frontmatter keys are still IGNORED, not rejected, so a file
|
|
78
78
|
* carrying another tool's metadata still loads here. `name`,
|
|
79
|
-
* `description`, `tools`, `steps` and `
|
|
80
|
-
* that used one of those
|
|
81
|
-
* release can change, and it changes it loudly.
|
|
79
|
+
* `description`, `tools`, `steps`, `onSkip` and `routes` are the KNOWN
|
|
80
|
+
* keys — a file that used one of those six for something else is the one
|
|
81
|
+
* case a release can change, and it changes it loudly.
|
|
82
|
+
*
|
|
83
|
+
* ── The routing, and the door that reads it (9.43.0) ─────────────────────────
|
|
84
|
+
* A runbook says what to do, what to do it with, in what order — and where the
|
|
85
|
+
* work goes NEXT. That last part is the graph, and until now it had to be
|
|
86
|
+
* hand-wired in code even when the files said it plainly. `routes:` closes it:
|
|
87
|
+
*
|
|
88
|
+
* ---
|
|
89
|
+
* name: billing
|
|
90
|
+
* tools: lookup_order, issue_refund
|
|
91
|
+
* routes:
|
|
92
|
+
* - escalation: on issue_refund status=denied
|
|
93
|
+
* - receipts: on issue_refund
|
|
94
|
+
* ---
|
|
95
|
+
*
|
|
96
|
+
* const runbook = await runbookFromDir('./skills', { tools: [...] });
|
|
97
|
+
* const graph = skillGraph({ ...runbook, start: 'billing' });
|
|
98
|
+
*
|
|
99
|
+
* TWO DOORS, one truth: `skillsFromDir` returns skills and REFUSES a file that
|
|
100
|
+
* declares `routes:` (a door that dropped the routing would hand back a graph
|
|
101
|
+
* you believed was declared on disk); {@link runbookFromDir} returns
|
|
102
|
+
* `{ skills, steps }`. Same law as `tools:` — the file PICKS (a route names a
|
|
103
|
+
* skill id this directory declares; an unknown id is refused at load, by name,
|
|
104
|
+
* listing what is available), it never DEFINES. A guard is one of the two DATA
|
|
105
|
+
* conditions a route already has (`on <tool_name>`, `status=<outcome>`), and
|
|
106
|
+
* nothing else: a `when` predicate is CODE, no file can carry code, and that
|
|
107
|
+
* conditional stays in your source. See `skillsFromDirRoutes.ts` for the whole
|
|
108
|
+
* grammar and every refusal.
|
|
82
109
|
*
|
|
83
110
|
* A worked example feeding this into a graph:
|
|
84
111
|
* `examples/features/47-skills-from-dir-graph.ts`.
|
|
@@ -111,6 +138,7 @@
|
|
|
111
138
|
import type { Injection } from './types.js';
|
|
112
139
|
import type { Tool } from '../../core/tools.js';
|
|
113
140
|
import { type SurfaceMode } from './factories/defineSkill.js';
|
|
141
|
+
import type { SkillGraphStep } from './skillGraph.js';
|
|
114
142
|
export interface SkillsFromDirOptions {
|
|
115
143
|
/**
|
|
116
144
|
* Where a loaded skill's body lands once activated. Defaults to
|
|
@@ -133,6 +161,31 @@ export interface SkillsFromDirOptions {
|
|
|
133
161
|
*/
|
|
134
162
|
readonly tools?: readonly Tool[];
|
|
135
163
|
}
|
|
164
|
+
/**
|
|
165
|
+
* A whole runbook directory, read as the two things a graph is made of
|
|
166
|
+
* (9.43.0): the skills, and the edges between them.
|
|
167
|
+
*
|
|
168
|
+
* Spreads straight into the graph — the field names are the graph's own, so
|
|
169
|
+
* nothing has to be translated at the call site:
|
|
170
|
+
*
|
|
171
|
+
* const runbook = await runbookFromDir('./skills', { tools });
|
|
172
|
+
* const graph = skillGraph({ ...runbook, start: 'triage' });
|
|
173
|
+
*/
|
|
174
|
+
export interface DirRunbook {
|
|
175
|
+
/** Every `SKILL.md` under the directory, as Skill Injections — byte-identical
|
|
176
|
+
* to what `skillsFromDir` returns for the same directory. */
|
|
177
|
+
readonly skills: readonly Injection[];
|
|
178
|
+
/**
|
|
179
|
+
* The declared edges, ready for `skillGraph({ steps })`. In skill-name order,
|
|
180
|
+
* then file order, so a graph built from a directory is stable.
|
|
181
|
+
*
|
|
182
|
+
* NAME NOTE, because two different things are spelled `steps` in this
|
|
183
|
+
* library: a file's own `steps:` key is that SKILL's tool sequence (which
|
|
184
|
+
* rides on the skill, unchanged); these `steps` are the GRAPH's edges, read
|
|
185
|
+
* from each file's `routes:` key. They never meet.
|
|
186
|
+
*/
|
|
187
|
+
readonly steps: readonly SkillGraphStep[];
|
|
188
|
+
}
|
|
136
189
|
/**
|
|
137
190
|
* Load every `SKILL.md` under `dir` as a Skill Injection.
|
|
138
191
|
*
|
|
@@ -155,3 +208,30 @@ export interface SkillsFromDirOptions {
|
|
|
155
208
|
* does not carry, or sequences a tool the file itself did not declare.
|
|
156
209
|
*/
|
|
157
210
|
export declare function skillsFromDir(dir: string, opts?: SkillsFromDirOptions): Promise<readonly Injection[]>;
|
|
211
|
+
/**
|
|
212
|
+
* Load a directory as a whole RUNBOOK (9.43.0) — the skills AND the edges
|
|
213
|
+
* between them.
|
|
214
|
+
*
|
|
215
|
+
* `skillsFromDir` reads what one skill is; this reads what the skills are TO
|
|
216
|
+
* EACH OTHER, from each file's `routes:` key, and hands back both halves ready
|
|
217
|
+
* for `skillGraph({ ...runbook, start })`. Everything else is identical: same
|
|
218
|
+
* layouts, same frontmatter, same tool registry, same refusals.
|
|
219
|
+
*
|
|
220
|
+
* The routing a file may carry is deliberately small, and the boundary is a
|
|
221
|
+
* security property rather than a limitation — see `skillsFromDirRoutes.ts`:
|
|
222
|
+
* a route NAMES a skill this directory declares (an unknown id is refused at
|
|
223
|
+
* load, by name, listing what is available — never a half-graph), and a guard
|
|
224
|
+
* is one of the two DATA conditions a route already has (`on <tool>`,
|
|
225
|
+
* `status=<outcome>`). A `when` predicate is code, so no file can express one;
|
|
226
|
+
* that conditional stays in your source, where `skillGraph({ steps })` takes it.
|
|
227
|
+
*
|
|
228
|
+
* @param dir - A local filesystem path. Same rule as `skillsFromDir`.
|
|
229
|
+
* @param opts - Applied uniformly to every loaded skill.
|
|
230
|
+
*
|
|
231
|
+
* @throws everything `skillsFromDir` throws, plus: a route to an id no
|
|
232
|
+
* `SKILL.md` in the directory declares (the message lists what is
|
|
233
|
+
* available), a guard the grammar cannot express (the message quotes the
|
|
234
|
+
* whole grammar), a guard naming a tool the file itself does not declare,
|
|
235
|
+
* and a file routing to the same skill twice.
|
|
236
|
+
*/
|
|
237
|
+
export declare function runbookFromDir(dir: string, opts?: SkillsFromDirOptions): Promise<DirRunbook>;
|
|
@@ -76,9 +76,36 @@
|
|
|
76
76
|
* others take `defineSkill`'s defaults.
|
|
77
77
|
* - unknown frontmatter keys are still IGNORED, not rejected, so a file
|
|
78
78
|
* carrying another tool's metadata still loads here. `name`,
|
|
79
|
-
* `description`, `tools`, `steps` and `
|
|
80
|
-
* that used one of those
|
|
81
|
-
* release can change, and it changes it loudly.
|
|
79
|
+
* `description`, `tools`, `steps`, `onSkip` and `routes` are the KNOWN
|
|
80
|
+
* keys — a file that used one of those six for something else is the one
|
|
81
|
+
* case a release can change, and it changes it loudly.
|
|
82
|
+
*
|
|
83
|
+
* ── The routing, and the door that reads it (9.43.0) ─────────────────────────
|
|
84
|
+
* A runbook says what to do, what to do it with, in what order — and where the
|
|
85
|
+
* work goes NEXT. That last part is the graph, and until now it had to be
|
|
86
|
+
* hand-wired in code even when the files said it plainly. `routes:` closes it:
|
|
87
|
+
*
|
|
88
|
+
* ---
|
|
89
|
+
* name: billing
|
|
90
|
+
* tools: lookup_order, issue_refund
|
|
91
|
+
* routes:
|
|
92
|
+
* - escalation: on issue_refund status=denied
|
|
93
|
+
* - receipts: on issue_refund
|
|
94
|
+
* ---
|
|
95
|
+
*
|
|
96
|
+
* const runbook = await runbookFromDir('./skills', { tools: [...] });
|
|
97
|
+
* const graph = skillGraph({ ...runbook, start: 'billing' });
|
|
98
|
+
*
|
|
99
|
+
* TWO DOORS, one truth: `skillsFromDir` returns skills and REFUSES a file that
|
|
100
|
+
* declares `routes:` (a door that dropped the routing would hand back a graph
|
|
101
|
+
* you believed was declared on disk); {@link runbookFromDir} returns
|
|
102
|
+
* `{ skills, steps }`. Same law as `tools:` — the file PICKS (a route names a
|
|
103
|
+
* skill id this directory declares; an unknown id is refused at load, by name,
|
|
104
|
+
* listing what is available), it never DEFINES. A guard is one of the two DATA
|
|
105
|
+
* conditions a route already has (`on <tool_name>`, `status=<outcome>`), and
|
|
106
|
+
* nothing else: a `when` predicate is CODE, no file can carry code, and that
|
|
107
|
+
* conditional stays in your source. See `skillsFromDirRoutes.ts` for the whole
|
|
108
|
+
* grammar and every refusal.
|
|
82
109
|
*
|
|
83
110
|
* A worked example feeding this into a graph:
|
|
84
111
|
* `examples/features/47-skills-from-dir-graph.ts`.
|
|
@@ -109,6 +136,7 @@
|
|
|
109
136
|
* import detonates a browser bundle at module-eval even when nothing calls it.
|
|
110
137
|
*/
|
|
111
138
|
import { defineSkill } from './factories/defineSkill.js';
|
|
139
|
+
import { readDeclaredRoutes, toGraphSteps } from './skillsFromDirRoutes.js';
|
|
112
140
|
/** The file name every skill folder is expected to use. */
|
|
113
141
|
const SKILL_FILE = 'SKILL.md';
|
|
114
142
|
/**
|
|
@@ -144,6 +172,68 @@ const NAMES_IN_REFUSAL = 20;
|
|
|
144
172
|
* does not carry, or sequences a tool the file itself did not declare.
|
|
145
173
|
*/
|
|
146
174
|
export async function skillsFromDir(dir, opts = {}) {
|
|
175
|
+
const { parsed, skills } = await loadSkillDir(dir, opts);
|
|
176
|
+
// A file that declares `routes:` loaded through THIS door would hand back a
|
|
177
|
+
// skill set with its routing silently dropped — the same failure the tool
|
|
178
|
+
// registry refuses ("a skill that loads without the tool it asked for still
|
|
179
|
+
// runs and still sounds sure of itself"). Refused by name, pointing at the
|
|
180
|
+
// door that reads the whole runbook.
|
|
181
|
+
const routing = parsed.find((skill) => skill.routes !== undefined);
|
|
182
|
+
if (routing !== undefined) {
|
|
183
|
+
throw new Error(`skillsFromDir: '${routing.file}' declares 'routes', and skillsFromDir returns SKILLS ` +
|
|
184
|
+
`only — the routing would be dropped without a word, leaving you a graph you thought ` +
|
|
185
|
+
`was declared on disk. Read the whole runbook instead: ` +
|
|
186
|
+
`const { skills, steps } = await runbookFromDir(dir, opts); ` +
|
|
187
|
+
`skillGraph({ skills, steps, start: '<entry id>' }). ` +
|
|
188
|
+
`(If 'routes' in this file belongs to another program, rename that key — it is a key ` +
|
|
189
|
+
`this loader now reads.)`);
|
|
190
|
+
}
|
|
191
|
+
return skills;
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Load a directory as a whole RUNBOOK (9.43.0) — the skills AND the edges
|
|
195
|
+
* between them.
|
|
196
|
+
*
|
|
197
|
+
* `skillsFromDir` reads what one skill is; this reads what the skills are TO
|
|
198
|
+
* EACH OTHER, from each file's `routes:` key, and hands back both halves ready
|
|
199
|
+
* for `skillGraph({ ...runbook, start })`. Everything else is identical: same
|
|
200
|
+
* layouts, same frontmatter, same tool registry, same refusals.
|
|
201
|
+
*
|
|
202
|
+
* The routing a file may carry is deliberately small, and the boundary is a
|
|
203
|
+
* security property rather than a limitation — see `skillsFromDirRoutes.ts`:
|
|
204
|
+
* a route NAMES a skill this directory declares (an unknown id is refused at
|
|
205
|
+
* load, by name, listing what is available — never a half-graph), and a guard
|
|
206
|
+
* is one of the two DATA conditions a route already has (`on <tool>`,
|
|
207
|
+
* `status=<outcome>`). A `when` predicate is code, so no file can express one;
|
|
208
|
+
* that conditional stays in your source, where `skillGraph({ steps })` takes it.
|
|
209
|
+
*
|
|
210
|
+
* @param dir - A local filesystem path. Same rule as `skillsFromDir`.
|
|
211
|
+
* @param opts - Applied uniformly to every loaded skill.
|
|
212
|
+
*
|
|
213
|
+
* @throws everything `skillsFromDir` throws, plus: a route to an id no
|
|
214
|
+
* `SKILL.md` in the directory declares (the message lists what is
|
|
215
|
+
* available), a guard the grammar cannot express (the message quotes the
|
|
216
|
+
* whole grammar), a guard naming a tool the file itself does not declare,
|
|
217
|
+
* and a file routing to the same skill twice.
|
|
218
|
+
*/
|
|
219
|
+
export async function runbookFromDir(dir, opts = {}) {
|
|
220
|
+
const { parsed, skills } = await loadSkillDir(dir, opts);
|
|
221
|
+
// Resolved only once every file is in hand: "which ids exist" is a fact about
|
|
222
|
+
// the DIRECTORY, and no single file can be asked it.
|
|
223
|
+
const known = new Set(parsed.map((skill) => skill.name));
|
|
224
|
+
const steps = parsed.flatMap((skill) => skill.routes === undefined ? [] : toGraphSteps(skill.name, skill.routes, skill.file, known));
|
|
225
|
+
return { skills, steps };
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* The shared load: read the directory, parse every file, resolve the tools,
|
|
229
|
+
* build the skills. Both doors run exactly this — they differ only in what they
|
|
230
|
+
* do with the ROUTING each file declared, which is the one thing a skill list
|
|
231
|
+
* cannot carry.
|
|
232
|
+
*
|
|
233
|
+
* Returns the parsed files and the built skills IN THE SAME ORDER (sorted by
|
|
234
|
+
* skill name), so a caller can pair them by index.
|
|
235
|
+
*/
|
|
236
|
+
async function loadSkillDir(dir, opts) {
|
|
147
237
|
assertLocalDirectoryArgument(dir);
|
|
148
238
|
assertNoViaToolNameOption(opts);
|
|
149
239
|
// Lazy node imports (browser-compat) — see module header.
|
|
@@ -205,10 +295,8 @@ export async function skillsFromDir(dir, opts = {}) {
|
|
|
205
295
|
// shape. `undefined` (option omitted) is DISTINCT from an empty registry: the
|
|
206
296
|
// refusals say different things, because the fixes are different.
|
|
207
297
|
const registry = indexToolRegistry(opts.tools);
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
.sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0))
|
|
211
|
-
.map((skill) => {
|
|
298
|
+
const sorted = parsed.slice().sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));
|
|
299
|
+
const skills = sorted.map((skill) => {
|
|
212
300
|
const tools = resolveDeclaredTools(skill, opts.tools, registry);
|
|
213
301
|
return defineSkill({
|
|
214
302
|
id: skill.name,
|
|
@@ -220,6 +308,7 @@ export async function skillsFromDir(dir, opts = {}) {
|
|
|
220
308
|
...(opts.surfaceMode !== undefined && { surfaceMode: opts.surfaceMode }),
|
|
221
309
|
});
|
|
222
310
|
});
|
|
311
|
+
return { parsed: sorted, skills };
|
|
223
312
|
}
|
|
224
313
|
// ─── Authorship guard ──────────────────────────────────────────────
|
|
225
314
|
/**
|
|
@@ -390,6 +479,7 @@ function parseSkillFile(raw, file) {
|
|
|
390
479
|
const toolNames = readToolNames(fields, file);
|
|
391
480
|
const steps = readSteps(fields, file, toolNames);
|
|
392
481
|
const onSkip = readOnSkip(fields, file, steps);
|
|
482
|
+
const routes = readRoutes(fields, file, toolNames);
|
|
393
483
|
return {
|
|
394
484
|
name,
|
|
395
485
|
description,
|
|
@@ -397,6 +487,7 @@ function parseSkillFile(raw, file) {
|
|
|
397
487
|
...(toolNames !== undefined && { toolNames }),
|
|
398
488
|
...(steps !== undefined && { steps }),
|
|
399
489
|
...(onSkip !== undefined && { onSkip }),
|
|
490
|
+
...(routes !== undefined && { routes }),
|
|
400
491
|
file,
|
|
401
492
|
};
|
|
402
493
|
}
|
|
@@ -553,6 +644,26 @@ function readSteps(fields, file, toolNames) {
|
|
|
553
644
|
return { tool: item.key, note: item.value };
|
|
554
645
|
});
|
|
555
646
|
}
|
|
647
|
+
/**
|
|
648
|
+
* `routes:` → the edges out of this skill (9.43.0), as data.
|
|
649
|
+
*
|
|
650
|
+
* A block list, like `steps:` and for the same reason: routing is an ordered
|
|
651
|
+
* list of pairs (a target and its guard), and one line cannot carry that
|
|
652
|
+
* without a separator soup. The grammar itself — and every refusal in it —
|
|
653
|
+
* lives in `skillsFromDirRoutes.ts`; this reader only decides that the key is
|
|
654
|
+
* present and shaped like a list.
|
|
655
|
+
*/
|
|
656
|
+
function readRoutes(fields, file, toolNames) {
|
|
657
|
+
const field = fields.get('routes');
|
|
658
|
+
if (field === undefined)
|
|
659
|
+
return undefined;
|
|
660
|
+
if (field.kind === 'scalar') {
|
|
661
|
+
throw new Error(`skillsFromDir: '${file}' writes 'routes' on one line, and routing is a LIST of edges ` +
|
|
662
|
+
`(each with its own guard). Write it as a block:\nroutes:\n - escalation: on ` +
|
|
663
|
+
`issue_refund status=denied\n - receipts: on issue_refund`);
|
|
664
|
+
}
|
|
665
|
+
return readDeclaredRoutes(field.items, file, toolNames);
|
|
666
|
+
}
|
|
556
667
|
/** `onSkip:` → the skip policy. Refused here rather than at `defineSkill` so
|
|
557
668
|
* the message can name the file the author has to open. */
|
|
558
669
|
function readOnSkip(fields, file, steps) {
|