@warlock.js/ai 4.4.0 → 4.5.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/CHANGELOG.md +52 -55
- package/cjs/index.cjs +221 -14147
- package/cjs/src-C02yzsLs.cjs +22991 -0
- package/cjs/src-C02yzsLs.cjs.map +1 -0
- package/cjs/src-DFibP2FQ.cjs +30 -0
- package/esm/agent/agent-config.type.d.mts +90 -1
- package/esm/agent/agent-config.type.d.mts.map +1 -1
- package/esm/agent/agent-input-builder.mjs +27 -6
- package/esm/agent/agent-input-builder.mjs.map +1 -1
- package/esm/agent/agent.d.mts +40 -1
- package/esm/agent/agent.d.mts.map +1 -1
- package/esm/agent/agent.mjs +203 -30
- package/esm/agent/agent.mjs.map +1 -1
- package/esm/agent/index.d.mts +2 -1
- package/esm/agent/index.mjs +1 -0
- package/esm/agent/judge-config.type.d.mts +33 -0
- package/esm/agent/judge-config.type.d.mts.map +1 -0
- package/esm/agent/judge-config.type.mjs +13 -0
- package/esm/agent/judge-config.type.mjs.map +1 -0
- package/esm/ai-openai/src/embedder.mjs +4 -0
- package/esm/ai-openai/src/index.mjs +4 -0
- package/esm/ai-openai/src/model.mjs +5 -0
- package/esm/ai-openai/src/sdk.mjs +6 -0
- package/esm/ai-openai/src/utils/index.mjs +4 -0
- package/esm/ai-openai/src/utils/to-openai-tools.mjs +3 -0
- package/esm/ai-openai/src/utils/wrap-openai-error.mjs +4 -0
- package/esm/ai.d.mts +119 -53
- package/esm/ai.d.mts.map +1 -1
- package/esm/ai.mjs +43 -8
- package/esm/ai.mjs.map +1 -1
- package/esm/batch/batch.d.mts.map +1 -1
- package/esm/batch/batch.mjs +21 -1
- package/esm/batch/batch.mjs.map +1 -1
- package/esm/batch/batch.type.d.mts +11 -4
- package/esm/batch/batch.type.d.mts.map +1 -1
- package/esm/config.d.mts +39 -3
- package/esm/config.d.mts.map +1 -1
- package/esm/config.mjs +26 -2
- package/esm/config.mjs.map +1 -1
- package/esm/contracts/agent/agent-options.type.d.mts +11 -3
- package/esm/contracts/agent/agent-options.type.d.mts.map +1 -1
- package/esm/contracts/agent/eval.type.d.mts +43 -2
- package/esm/contracts/agent/eval.type.d.mts.map +1 -1
- package/esm/contracts/attachment-policy.type.d.mts +51 -0
- package/esm/contracts/attachment-policy.type.d.mts.map +1 -0
- package/esm/contracts/attachment.type.d.mts +16 -7
- package/esm/contracts/attachment.type.d.mts.map +1 -1
- package/esm/contracts/content-part.type.d.mts +14 -5
- package/esm/contracts/content-part.type.d.mts.map +1 -1
- package/esm/contracts/events/supervisor-events.type.d.mts.map +1 -1
- package/esm/contracts/index.d.mts +6 -4
- package/esm/contracts/model.contract.d.mts +11 -8
- package/esm/contracts/model.contract.d.mts.map +1 -1
- package/esm/contracts/orchestrator/index.d.mts +1 -0
- package/esm/contracts/orchestrator/orchestrator-config.type.d.mts +31 -2
- package/esm/contracts/orchestrator/orchestrator-config.type.d.mts.map +1 -1
- package/esm/contracts/orchestrator/session-lock.contract.d.mts +47 -0
- package/esm/contracts/orchestrator/session-lock.contract.d.mts.map +1 -0
- package/esm/contracts/planner/index.d.mts +1 -1
- package/esm/contracts/planner/planner-config.type.d.mts +31 -0
- package/esm/contracts/planner/planner-config.type.d.mts.map +1 -1
- package/esm/contracts/planner/planner-execute-options.type.d.mts +48 -1
- package/esm/contracts/planner/planner-execute-options.type.d.mts.map +1 -1
- package/esm/contracts/planner/planner-result.type.d.mts +8 -0
- package/esm/contracts/planner/planner-result.type.d.mts.map +1 -1
- package/esm/contracts/planner/planner.contract.d.mts +1 -1
- package/esm/contracts/result/agent-result.type.d.mts +6 -4
- package/esm/contracts/result/agent-result.type.d.mts.map +1 -1
- package/esm/contracts/result/base-report.type.d.mts +21 -3
- package/esm/contracts/result/base-report.type.d.mts.map +1 -1
- package/esm/contracts/result/base-report.type.mjs.map +1 -1
- package/esm/contracts/result/execution-report.type.d.mts +53 -1
- package/esm/contracts/result/execution-report.type.d.mts.map +1 -1
- package/esm/contracts/result/supervisor-result.type.d.mts +14 -2
- package/esm/contracts/result/supervisor-result.type.d.mts.map +1 -1
- package/esm/contracts/result/workflow-result.type.d.mts +2 -1
- package/esm/contracts/result/workflow-result.type.d.mts.map +1 -1
- package/esm/contracts/supervisor/supervisor-config.type.d.mts +29 -0
- package/esm/contracts/supervisor/supervisor-config.type.d.mts.map +1 -1
- package/esm/contracts/system-prompt.contract.d.mts +103 -1
- package/esm/contracts/system-prompt.contract.d.mts.map +1 -1
- package/esm/contracts/team/index.d.mts +1 -0
- package/esm/contracts/team/team-config.type.d.mts +127 -0
- package/esm/contracts/team/team-config.type.d.mts.map +1 -0
- package/esm/contracts/tool.contract.d.mts +4 -2
- package/esm/contracts/tool.contract.d.mts.map +1 -1
- package/esm/contracts/workflow/step.contract.d.mts +30 -5
- package/esm/contracts/workflow/step.contract.d.mts.map +1 -1
- package/esm/contracts/workflow/workflow.contract.d.mts +16 -0
- package/esm/contracts/workflow/workflow.contract.d.mts.map +1 -1
- package/esm/errors/error-code.type.d.mts +1 -1
- package/esm/errors/index.d.mts +1 -0
- package/esm/errors/index.mjs +1 -0
- package/esm/errors/outbound-policy-error.d.mts +27 -0
- package/esm/errors/outbound-policy-error.d.mts.map +1 -0
- package/esm/errors/outbound-policy-error.mjs +32 -0
- package/esm/errors/outbound-policy-error.mjs.map +1 -0
- package/esm/eval/dataset.d.mts +28 -0
- package/esm/eval/dataset.d.mts.map +1 -0
- package/esm/eval/dataset.mjs +112 -0
- package/esm/eval/dataset.mjs.map +1 -0
- package/esm/eval/dataset.type.d.mts +53 -0
- package/esm/eval/dataset.type.d.mts.map +1 -0
- package/esm/eval/eval-runner.d.mts.map +1 -1
- package/esm/eval/eval-runner.mjs +16 -2
- package/esm/eval/eval-runner.mjs.map +1 -1
- package/esm/eval/index.d.mts +20 -1
- package/esm/eval/index.d.mts.map +1 -1
- package/esm/eval/index.mjs +20 -2
- package/esm/eval/index.mjs.map +1 -1
- package/esm/eval/regression.d.mts +30 -0
- package/esm/eval/regression.d.mts.map +1 -0
- package/esm/eval/regression.mjs +51 -0
- package/esm/eval/regression.mjs.map +1 -0
- package/esm/eval/report-json.d.mts +30 -0
- package/esm/eval/report-json.d.mts.map +1 -0
- package/esm/eval/report-json.mjs +33 -0
- package/esm/eval/report-json.mjs.map +1 -0
- package/esm/eval/report-junit.d.mts +22 -0
- package/esm/eval/report-junit.d.mts.map +1 -0
- package/esm/eval/report-junit.mjs +60 -0
- package/esm/eval/report-junit.mjs.map +1 -0
- package/esm/guard/contracts/guard-options.type.d.mts +165 -0
- package/esm/guard/contracts/guard-options.type.d.mts.map +1 -0
- package/esm/guard/contracts/guardrail.contract.d.mts +78 -0
- package/esm/guard/contracts/guardrail.contract.d.mts.map +1 -0
- package/esm/guard/contracts/index.d.mts +4 -0
- package/esm/guard/contracts/openai-client.contract.d.mts +51 -0
- package/esm/guard/contracts/openai-client.contract.d.mts.map +1 -0
- package/esm/guard/contracts/verdict.type.d.mts +76 -0
- package/esm/guard/contracts/verdict.type.d.mts.map +1 -0
- package/esm/guard/detectors/index.d.mts +4 -0
- package/esm/guard/detectors/index.mjs +6 -0
- package/esm/guard/detectors/injection.d.mts +34 -0
- package/esm/guard/detectors/injection.d.mts.map +1 -0
- package/esm/guard/detectors/injection.mjs +254 -0
- package/esm/guard/detectors/injection.mjs.map +1 -0
- package/esm/guard/detectors/moderation.d.mts +32 -0
- package/esm/guard/detectors/moderation.d.mts.map +1 -0
- package/esm/guard/detectors/moderation.mjs +134 -0
- package/esm/guard/detectors/moderation.mjs.map +1 -0
- package/esm/guard/detectors/pii.d.mts +41 -0
- package/esm/guard/detectors/pii.d.mts.map +1 -0
- package/esm/guard/detectors/pii.mjs +199 -0
- package/esm/guard/detectors/pii.mjs.map +1 -0
- package/esm/guard/detectors/topic.d.mts +29 -0
- package/esm/guard/detectors/topic.d.mts.map +1 -0
- package/esm/guard/detectors/topic.mjs +99 -0
- package/esm/guard/detectors/topic.mjs.map +1 -0
- package/esm/guard/errors.d.mts +12 -0
- package/esm/guard/errors.d.mts.map +1 -0
- package/esm/guard/errors.mjs +18 -0
- package/esm/guard/errors.mjs.map +1 -0
- package/esm/guard/guard.d.mts +67 -0
- package/esm/guard/guard.d.mts.map +1 -0
- package/esm/guard/guard.mjs +209 -0
- package/esm/guard/guard.mjs.map +1 -0
- package/esm/guard/guardrail.d.mts +39 -0
- package/esm/guard/guardrail.d.mts.map +1 -0
- package/esm/guard/guardrail.mjs +22 -0
- package/esm/guard/guardrail.mjs.map +1 -0
- package/esm/human/contracts/approval.type.d.mts +154 -0
- package/esm/human/contracts/approval.type.d.mts.map +1 -0
- package/esm/human/contracts/human-approval.type.d.mts +38 -0
- package/esm/human/contracts/human-approval.type.d.mts.map +1 -0
- package/esm/human/contracts/index.d.mts +4 -0
- package/esm/human/contracts/interrupt-store.contract.d.mts +112 -0
- package/esm/human/contracts/interrupt-store.contract.d.mts.map +1 -0
- package/esm/human/contracts/resume.type.d.mts +77 -0
- package/esm/human/contracts/resume.type.d.mts.map +1 -0
- package/esm/human/errors.d.mts +84 -0
- package/esm/human/errors.d.mts.map +1 -0
- package/esm/human/errors.mjs +60 -0
- package/esm/human/errors.mjs.map +1 -0
- package/esm/human/human-approval.d.mts +57 -0
- package/esm/human/human-approval.d.mts.map +1 -0
- package/esm/human/human-approval.mjs +170 -0
- package/esm/human/human-approval.mjs.map +1 -0
- package/esm/human/policy.d.mts +55 -0
- package/esm/human/policy.d.mts.map +1 -0
- package/esm/human/policy.mjs +67 -0
- package/esm/human/policy.mjs.map +1 -0
- package/esm/human/register.mjs +37 -0
- package/esm/human/register.mjs.map +1 -0
- package/esm/human/resume-seed.mjs +53 -0
- package/esm/human/resume-seed.mjs.map +1 -0
- package/esm/human/resume.d.mts +54 -0
- package/esm/human/resume.d.mts.map +1 -0
- package/esm/human/resume.mjs +121 -0
- package/esm/human/resume.mjs.map +1 -0
- package/esm/human/stores/index.mjs +5 -0
- package/esm/human/stores/memory.d.mts +30 -0
- package/esm/human/stores/memory.d.mts.map +1 -0
- package/esm/human/stores/memory.mjs +91 -0
- package/esm/human/stores/memory.mjs.map +1 -0
- package/esm/human/stores/pg.d.mts +59 -0
- package/esm/human/stores/pg.d.mts.map +1 -0
- package/esm/human/stores/pg.mjs +220 -0
- package/esm/human/stores/pg.mjs.map +1 -0
- package/esm/human/stores/redis.d.mts +56 -0
- package/esm/human/stores/redis.d.mts.map +1 -0
- package/esm/human/stores/redis.mjs +201 -0
- package/esm/human/stores/redis.mjs.map +1 -0
- package/esm/index.d.mts +113 -22
- package/esm/index.mjs +82 -11
- package/esm/middleware/builtins/budget.mjs +6 -2
- package/esm/middleware/builtins/budget.mjs.map +1 -1
- package/esm/middleware/utils/extract-user-text.d.mts +8 -1
- package/esm/middleware/utils/extract-user-text.d.mts.map +1 -1
- package/esm/middleware/utils/extract-user-text.mjs +8 -1
- package/esm/middleware/utils/extract-user-text.mjs.map +1 -1
- package/esm/object-stream/index.d.mts +2 -0
- package/esm/object-stream/index.mjs +4 -0
- package/esm/object-stream/parse-partial-json.d.mts +22 -0
- package/esm/object-stream/parse-partial-json.d.mts.map +1 -0
- package/esm/object-stream/parse-partial-json.mjs +78 -0
- package/esm/object-stream/parse-partial-json.mjs.map +1 -0
- package/esm/object-stream/stream-object.d.mts +68 -0
- package/esm/object-stream/stream-object.d.mts.map +1 -0
- package/esm/object-stream/stream-object.mjs +104 -0
- package/esm/object-stream/stream-object.mjs.map +1 -0
- package/esm/observe/index.mjs +4 -0
- package/esm/observe/observer-registry.d.mts +30 -0
- package/esm/observe/observer-registry.d.mts.map +1 -0
- package/esm/observe/observer-registry.mjs +51 -0
- package/esm/observe/observer-registry.mjs.map +1 -0
- package/esm/observe/observer.contract.d.mts +40 -0
- package/esm/observe/observer.contract.d.mts.map +1 -0
- package/esm/observe/resolve-observers.d.mts +40 -0
- package/esm/observe/resolve-observers.d.mts.map +1 -0
- package/esm/observe/resolve-observers.mjs +73 -0
- package/esm/observe/resolve-observers.mjs.map +1 -0
- package/esm/orchestrator/execution.d.mts.map +1 -1
- package/esm/orchestrator/execution.mjs +5 -2
- package/esm/orchestrator/execution.mjs.map +1 -1
- package/esm/orchestrator/index.d.mts +1 -0
- package/esm/orchestrator/index.mjs +1 -0
- package/esm/orchestrator/orchestrator.d.mts.map +1 -1
- package/esm/orchestrator/orchestrator.mjs +39 -6
- package/esm/orchestrator/orchestrator.mjs.map +1 -1
- package/esm/orchestrator/session-lock.d.mts +25 -0
- package/esm/orchestrator/session-lock.d.mts.map +1 -0
- package/esm/orchestrator/session-lock.mjs +83 -0
- package/esm/orchestrator/session-lock.mjs.map +1 -0
- package/esm/planner/dag-scheduler.mjs +97 -0
- package/esm/planner/dag-scheduler.mjs.map +1 -0
- package/esm/planner/plan-prompt.d.mts +1 -1
- package/esm/planner/plan-prompt.d.mts.map +1 -1
- package/esm/planner/plan-prompt.mjs +2 -1
- package/esm/planner/plan-prompt.mjs.map +1 -1
- package/esm/planner/planner-run.d.mts.map +1 -1
- package/esm/planner/planner-run.mjs +300 -29
- package/esm/planner/planner-run.mjs.map +1 -1
- package/esm/planner/planner.mjs +1 -1
- package/esm/planner/planner.mjs.map +1 -1
- package/esm/prompt/errors.d.mts +57 -0
- package/esm/prompt/errors.d.mts.map +1 -0
- package/esm/prompt/errors.mjs +73 -0
- package/esm/prompt/errors.mjs.map +1 -0
- package/esm/prompt/index.d.mts +3 -0
- package/esm/prompt/index.mjs +4 -0
- package/esm/prompt/prompt-langfuse-sync.mjs +104 -0
- package/esm/prompt/prompt-langfuse-sync.mjs.map +1 -0
- package/esm/prompt/prompt-langfuse-sync.type.d.mts +32 -0
- package/esm/prompt/prompt-langfuse-sync.type.d.mts.map +1 -0
- package/esm/prompt/prompt-validate.mjs +170 -0
- package/esm/prompt/prompt-validate.mjs.map +1 -0
- package/esm/prompt/prompt.d.mts +54 -0
- package/esm/prompt/prompt.d.mts.map +1 -0
- package/esm/prompt/prompt.mjs +218 -0
- package/esm/prompt/prompt.mjs.map +1 -0
- package/esm/prompt/prompt.type.d.mts +174 -0
- package/esm/prompt/prompt.type.d.mts.map +1 -0
- package/esm/prompts/index.d.mts +3 -0
- package/esm/prompts/index.mjs +3 -0
- package/esm/prompts/prompts-manager.contract.d.mts +154 -0
- package/esm/prompts/prompts-manager.contract.d.mts.map +1 -0
- package/esm/prompts/prompts-manager.d.mts +38 -0
- package/esm/prompts/prompts-manager.d.mts.map +1 -0
- package/esm/prompts/prompts-manager.mjs +410 -0
- package/esm/prompts/prompts-manager.mjs.map +1 -0
- package/esm/prompts/prompts-manager.type.d.mts +172 -0
- package/esm/prompts/prompts-manager.type.d.mts.map +1 -0
- package/esm/prompts/prompts-validate.mjs +200 -0
- package/esm/prompts/prompts-validate.mjs.map +1 -0
- package/esm/rag/as-tool.mjs +48 -0
- package/esm/rag/as-tool.mjs.map +1 -0
- package/esm/rag/chunk/chunk.d.mts +24 -0
- package/esm/rag/chunk/chunk.d.mts.map +1 -0
- package/esm/rag/chunk/chunk.mjs +44 -0
- package/esm/rag/chunk/chunk.mjs.map +1 -0
- package/esm/rag/chunk/fixed.mjs +32 -0
- package/esm/rag/chunk/fixed.mjs.map +1 -0
- package/esm/rag/chunk/markdown.mjs +75 -0
- package/esm/rag/chunk/markdown.mjs.map +1 -0
- package/esm/rag/chunk/recursive.mjs +132 -0
- package/esm/rag/chunk/recursive.mjs.map +1 -0
- package/esm/rag/chunk/sentence.mjs +73 -0
- package/esm/rag/chunk/sentence.mjs.map +1 -0
- package/esm/rag/contracts/chunk-options.type.d.mts +35 -0
- package/esm/rag/contracts/chunk-options.type.d.mts.map +1 -0
- package/esm/rag/contracts/citation.type.d.mts +35 -0
- package/esm/rag/contracts/citation.type.d.mts.map +1 -0
- package/esm/rag/contracts/index.d.mts +4 -0
- package/esm/rag/contracts/rag-config.type.d.mts +68 -0
- package/esm/rag/contracts/rag-config.type.d.mts.map +1 -0
- package/esm/rag/contracts/rag-document.type.d.mts +21 -0
- package/esm/rag/contracts/rag-document.type.d.mts.map +1 -0
- package/esm/rag/hybrid/bm25.d.mts +23 -0
- package/esm/rag/hybrid/bm25.d.mts.map +1 -0
- package/esm/rag/hybrid/bm25.mjs +51 -0
- package/esm/rag/hybrid/bm25.mjs.map +1 -0
- package/esm/rag/hybrid/hybrid-rank.d.mts +33 -0
- package/esm/rag/hybrid/hybrid-rank.d.mts.map +1 -0
- package/esm/rag/hybrid/hybrid-rank.mjs +29 -0
- package/esm/rag/hybrid/hybrid-rank.mjs.map +1 -0
- package/esm/rag/hybrid/rrf.d.mts +25 -0
- package/esm/rag/hybrid/rrf.d.mts.map +1 -0
- package/esm/rag/hybrid/rrf.mjs +30 -0
- package/esm/rag/hybrid/rrf.mjs.map +1 -0
- package/esm/rag/index.d.mts +15 -0
- package/esm/rag/index.mjs +11 -0
- package/esm/rag/rag.d.mts +38 -0
- package/esm/rag/rag.d.mts.map +1 -0
- package/esm/rag/rag.mjs +126 -0
- package/esm/rag/rag.mjs.map +1 -0
- package/esm/rag/rerank/keyword-reranker.d.mts +32 -0
- package/esm/rag/rerank/keyword-reranker.d.mts.map +1 -0
- package/esm/rag/rerank/keyword-reranker.mjs +58 -0
- package/esm/rag/rerank/keyword-reranker.mjs.map +1 -0
- package/esm/rag/rerank/llm-reranker.d.mts +36 -0
- package/esm/rag/rerank/llm-reranker.d.mts.map +1 -0
- package/esm/rag/rerank/llm-reranker.mjs +85 -0
- package/esm/rag/rerank/llm-reranker.mjs.map +1 -0
- package/esm/rag/rerank/reranker.contract.d.mts +28 -0
- package/esm/rag/rerank/reranker.contract.d.mts.map +1 -0
- package/esm/rag/retrieve.mjs +68 -0
- package/esm/rag/retrieve.mjs.map +1 -0
- package/esm/rag/store/cache-vector-store.d.mts +27 -0
- package/esm/rag/store/cache-vector-store.d.mts.map +1 -0
- package/esm/rag/store/cache-vector-store.mjs +48 -0
- package/esm/rag/store/cache-vector-store.mjs.map +1 -0
- package/esm/rag/store/vector-store.contract.d.mts +38 -0
- package/esm/rag/store/vector-store.contract.d.mts.map +1 -0
- package/esm/rag/transforms/multi-query.d.mts +27 -0
- package/esm/rag/transforms/multi-query.d.mts.map +1 -0
- package/esm/rag/transforms/multi-query.mjs +41 -0
- package/esm/rag/transforms/multi-query.mjs.map +1 -0
- package/esm/security/index.mjs +5 -0
- package/esm/security/outbound-policy.d.mts +46 -0
- package/esm/security/outbound-policy.d.mts.map +1 -0
- package/esm/security/outbound-policy.mjs +187 -0
- package/esm/security/outbound-policy.mjs.map +1 -0
- package/esm/security/outbound-policy.type.d.mts +74 -0
- package/esm/security/outbound-policy.type.d.mts.map +1 -0
- package/esm/security/private-ip.d.mts +15 -0
- package/esm/security/private-ip.d.mts.map +1 -0
- package/esm/security/private-ip.mjs +48 -0
- package/esm/security/private-ip.mjs.map +1 -0
- package/esm/security/redact.d.mts +59 -0
- package/esm/security/redact.d.mts.map +1 -0
- package/esm/security/redact.mjs +122 -0
- package/esm/security/redact.mjs.map +1 -0
- package/esm/serve/serve.d.mts +50 -0
- package/esm/serve/serve.d.mts.map +1 -0
- package/esm/serve/serve.mjs +90 -0
- package/esm/serve/serve.mjs.map +1 -0
- package/esm/serve/sse.d.mts +20 -0
- package/esm/serve/sse.d.mts.map +1 -0
- package/esm/serve/sse.mjs +25 -0
- package/esm/serve/sse.mjs.map +1 -0
- package/esm/serve/stream-to-sse.d.mts +29 -0
- package/esm/serve/stream-to-sse.d.mts.map +1 -0
- package/esm/serve/stream-to-sse.mjs +37 -0
- package/esm/serve/stream-to-sse.mjs.map +1 -0
- package/esm/skills/catalog.d.mts +49 -0
- package/esm/skills/catalog.d.mts.map +1 -0
- package/esm/skills/catalog.mjs +140 -0
- package/esm/skills/catalog.mjs.map +1 -0
- package/esm/skills/contracts/skill-record.type.d.mts +37 -0
- package/esm/skills/contracts/skill-record.type.d.mts.map +1 -0
- package/esm/skills/contracts/skills-config.type.d.mts +108 -0
- package/esm/skills/contracts/skills-config.type.d.mts.map +1 -0
- package/esm/skills/contracts/skills-store.contract.d.mts +28 -0
- package/esm/skills/contracts/skills-store.contract.d.mts.map +1 -0
- package/esm/skills/contracts/skills.contract.d.mts +43 -0
- package/esm/skills/contracts/skills.contract.d.mts.map +1 -0
- package/esm/skills/index.d.mts +16 -0
- package/esm/skills/index.mjs +14 -0
- package/esm/skills/load-skill-tool.d.mts +38 -0
- package/esm/skills/load-skill-tool.d.mts.map +1 -0
- package/esm/skills/load-skill-tool.mjs +65 -0
- package/esm/skills/load-skill-tool.mjs.map +1 -0
- package/esm/skills/review-gate.d.mts +33 -0
- package/esm/skills/review-gate.d.mts.map +1 -0
- package/esm/skills/review-gate.mjs +60 -0
- package/esm/skills/review-gate.mjs.map +1 -0
- package/esm/skills/save-skill-tool.d.mts +39 -0
- package/esm/skills/save-skill-tool.d.mts.map +1 -0
- package/esm/skills/save-skill-tool.mjs +65 -0
- package/esm/skills/save-skill-tool.mjs.map +1 -0
- package/esm/skills/skills.d.mts +33 -0
- package/esm/skills/skills.d.mts.map +1 -0
- package/esm/skills/skills.mjs +109 -0
- package/esm/skills/skills.mjs.map +1 -0
- package/esm/skills/sources/directory-source.d.mts +19 -0
- package/esm/skills/sources/directory-source.d.mts.map +1 -0
- package/esm/skills/sources/directory-source.mjs +108 -0
- package/esm/skills/sources/directory-source.mjs.map +1 -0
- package/esm/skills/sources/index.d.mts +18 -0
- package/esm/skills/sources/index.d.mts.map +1 -0
- package/esm/skills/sources/index.mjs +27 -0
- package/esm/skills/sources/index.mjs.map +1 -0
- package/esm/skills/sources/parse-frontmatter.d.mts +27 -0
- package/esm/skills/sources/parse-frontmatter.d.mts.map +1 -0
- package/esm/skills/sources/parse-frontmatter.mjs +46 -0
- package/esm/skills/sources/parse-frontmatter.mjs.map +1 -0
- package/esm/skills/sources/store-source.d.mts +14 -0
- package/esm/skills/sources/store-source.d.mts.map +1 -0
- package/esm/skills/sources/store-source.mjs +15 -0
- package/esm/skills/sources/store-source.mjs.map +1 -0
- package/esm/skills/sources/url-source.d.mts +29 -0
- package/esm/skills/sources/url-source.d.mts.map +1 -0
- package/esm/skills/sources/url-source.mjs +117 -0
- package/esm/skills/sources/url-source.mjs.map +1 -0
- package/esm/skills/store/mock-skills-store.d.mts +57 -0
- package/esm/skills/store/mock-skills-store.d.mts.map +1 -0
- package/esm/skills/store/mock-skills-store.mjs +100 -0
- package/esm/skills/store/mock-skills-store.mjs.map +1 -0
- package/esm/skills/store/procedural-skill-store.d.mts +30 -0
- package/esm/skills/store/procedural-skill-store.d.mts.map +1 -0
- package/esm/skills/store/procedural-skill-store.mjs +125 -0
- package/esm/skills/store/procedural-skill-store.mjs.map +1 -0
- package/esm/supervisor/as-tool.mjs +2 -2
- package/esm/supervisor/as-tool.mjs.map +1 -1
- package/esm/supervisor/execution.d.mts.map +1 -1
- package/esm/supervisor/execution.mjs +31 -28
- package/esm/supervisor/execution.mjs.map +1 -1
- package/esm/supervisor/supervisor.d.mts.map +1 -1
- package/esm/supervisor/supervisor.mjs +8 -3
- package/esm/supervisor/supervisor.mjs.map +1 -1
- package/esm/system-prompt/index.d.mts +4 -0
- package/esm/system-prompt/system-prompt.d.mts +68 -4
- package/esm/system-prompt/system-prompt.d.mts.map +1 -1
- package/esm/system-prompt/system-prompt.mjs +89 -5
- package/esm/system-prompt/system-prompt.mjs.map +1 -1
- package/esm/team/gates.mjs +48 -0
- package/esm/team/gates.mjs.map +1 -0
- package/esm/team/index.d.mts +1 -0
- package/esm/team/index.mjs +3 -0
- package/esm/team/team.d.mts +42 -0
- package/esm/team/team.d.mts.map +1 -0
- package/esm/team/team.mjs +94 -0
- package/esm/team/team.mjs.map +1 -0
- package/esm/tool/executable-as-tool.d.mts.map +1 -1
- package/esm/tool/executable-as-tool.mjs +2 -2
- package/esm/tool/executable-as-tool.mjs.map +1 -1
- package/esm/tool/tool.d.mts.map +1 -1
- package/esm/tool/tool.mjs +2 -2
- package/esm/tool/tool.mjs.map +1 -1
- package/esm/utils/compute-cost.d.mts +17 -1
- package/esm/utils/compute-cost.d.mts.map +1 -1
- package/esm/utils/compute-cost.mjs +26 -1
- package/esm/utils/compute-cost.mjs.map +1 -1
- package/esm/utils/extract-json-lenient.d.mts +42 -0
- package/esm/utils/extract-json-lenient.d.mts.map +1 -0
- package/esm/utils/extract-json-lenient.mjs +97 -0
- package/esm/utils/extract-json-lenient.mjs.map +1 -0
- package/esm/utils/index.d.mts +4 -2
- package/esm/utils/index.mjs +3 -1
- package/esm/utils/json-schema.d.mts +1 -1
- package/esm/utils/prepare-attachment-part.d.mts +10 -1
- package/esm/utils/prepare-attachment-part.d.mts.map +1 -1
- package/esm/utils/prepare-attachment-part.mjs +103 -11
- package/esm/utils/prepare-attachment-part.mjs.map +1 -1
- package/esm/utils/resolve-attachment.d.mts +4 -3
- package/esm/utils/resolve-attachment.d.mts.map +1 -1
- package/esm/utils/resolve-attachment.mjs +4 -3
- package/esm/utils/resolve-attachment.mjs.map +1 -1
- package/esm/utils/run-context.d.mts +94 -0
- package/esm/utils/run-context.d.mts.map +1 -0
- package/esm/utils/run-context.mjs +98 -0
- package/esm/utils/run-context.mjs.map +1 -0
- package/esm/vcr/cassette-io.mjs +57 -0
- package/esm/vcr/cassette-io.mjs.map +1 -0
- package/esm/vcr/errors.d.mts +42 -0
- package/esm/vcr/errors.d.mts.map +1 -0
- package/esm/vcr/errors.mjs +37 -0
- package/esm/vcr/errors.mjs.map +1 -0
- package/esm/vcr/hash-request.d.mts +28 -0
- package/esm/vcr/hash-request.d.mts.map +1 -0
- package/esm/vcr/hash-request.mjs +118 -0
- package/esm/vcr/hash-request.mjs.map +1 -0
- package/esm/vcr/index.d.mts +4 -0
- package/esm/vcr/index.mjs +5 -0
- package/esm/vcr/vcr.d.mts +32 -0
- package/esm/vcr/vcr.d.mts.map +1 -0
- package/esm/vcr/vcr.mjs +248 -0
- package/esm/vcr/vcr.mjs.map +1 -0
- package/esm/vcr/vcr.type.d.mts +118 -0
- package/esm/vcr/vcr.type.d.mts.map +1 -0
- package/esm/workflow/as-tool.mjs +2 -2
- package/esm/workflow/as-tool.mjs.map +1 -1
- package/esm/workflow/engine.mjs +1 -0
- package/esm/workflow/engine.mjs.map +1 -1
- package/esm/workflow/step-runner.mjs +19 -20
- package/esm/workflow/step-runner.mjs.map +1 -1
- package/esm/workflow/workflow.d.mts.map +1 -1
- package/esm/workflow/workflow.mjs +8 -3
- package/esm/workflow/workflow.mjs.map +1 -1
- package/llms-full.txt +1683 -68
- package/llms.txt +16 -4
- package/package.json +7 -3
- package/skills/README.md +40 -4
- package/skills/ai-dx-helpers/SKILL.md +2 -2
- package/skills/approve-tool-calls/SKILL.md +134 -0
- package/skills/attach-ai-middleware/SKILL.md +1 -1
- package/skills/detect-and-redact-pii/SKILL.md +104 -0
- package/skills/durable-resume/SKILL.md +128 -0
- package/skills/escalate-block-to-human/SKILL.md +85 -0
- package/skills/eval-datasets-and-ci/SKILL.md +117 -0
- package/skills/guard-input-output/SKILL.md +117 -0
- package/skills/manage-prompts/SKILL.md +186 -0
- package/skills/observe-ai-flows/SKILL.md +94 -0
- package/skills/record-replay-llm/SKILL.md +92 -0
- package/skills/run-ai-agent/SKILL.md +26 -1
- package/skills/run-ai-rag/SKILL.md +139 -0
- package/skills/run-ai-team/SKILL.md +107 -0
- package/skills/run-orchestrator/SKILL.md +2 -0
- package/skills/run-planner/SKILL.md +73 -8
- package/skills/run-supervisor/SKILL.md +20 -1
- package/skills/use-runtime-skills/SKILL.md +106 -0
- package/skills/write-system-prompt/SKILL.md +30 -1
- package/cjs/index.cjs.map +0 -1
- package/esm/contracts/result/index.d.mts +0 -15
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { InterruptPolicy, PolicyContext } from "./contracts/approval.type.mjs";
|
|
2
|
+
//#region ../@warlock.js/ai/src/human/policy.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* Verdict of evaluating an {@link InterruptPolicy} against a single
|
|
5
|
+
* pending tool call.
|
|
6
|
+
*
|
|
7
|
+
* - `requiresApproval` — `true` when the call must be routed to a human
|
|
8
|
+
* before the real tool runs; `false` when the policy lets it through
|
|
9
|
+
* untouched.
|
|
10
|
+
* - `tags` — author-supplied labels from the matched rule (e.g.
|
|
11
|
+
* `"destructive"`, `"money"`), surfaced verbatim on the resulting
|
|
12
|
+
* `ApprovalRequest.context.tags`. Only ever present when
|
|
13
|
+
* `requiresApproval` is `true`; `undefined` when the rule produced no
|
|
14
|
+
* tags.
|
|
15
|
+
*/
|
|
16
|
+
interface PolicyVerdict {
|
|
17
|
+
/** Whether this tool call must be approved by a human. */
|
|
18
|
+
requiresApproval: boolean;
|
|
19
|
+
/** Author-supplied tags from the matched rule, when any. */
|
|
20
|
+
tags?: string[];
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Decide whether a single pending tool call requires human approval —
|
|
24
|
+
* the pure core behind the `ai.human.approval` middleware's gate.
|
|
25
|
+
*
|
|
26
|
+
* **Pure.** No IO, no throwing, no mutation of `policy` or `context`. The
|
|
27
|
+
* middleware calls this once per tool dispatch and routes to a human only
|
|
28
|
+
* when {@link PolicyVerdict.requiresApproval} is `true`.
|
|
29
|
+
*
|
|
30
|
+
* **The three rule types** ({@link InterruptPolicy}):
|
|
31
|
+
* - `allowlist` — gate the call **only** when its tool name is listed; an
|
|
32
|
+
* optional `tags(toolName)` callback derives the verdict tags.
|
|
33
|
+
* - `denylist` — gate **every** call **except** the listed tool names;
|
|
34
|
+
* the same optional `tags(toolName)` callback applies to the gated
|
|
35
|
+
* (non-listed) name.
|
|
36
|
+
* - `predicate` — gate the call when `requiresApproval(context)` returns a
|
|
37
|
+
* truthy result. A non-empty `string[]` both gates the call **and**
|
|
38
|
+
* supplies the verdict tags; `true` gates with no tags; `false` (or an
|
|
39
|
+
* **empty** array — "no rule matched") lets the call through.
|
|
40
|
+
*
|
|
41
|
+
* @param policy - The interrupt policy to evaluate.
|
|
42
|
+
* @param context - The read-only view of the pending tool call.
|
|
43
|
+
* @returns A {@link PolicyVerdict} — gate-or-skip plus any tags.
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* const verdict = evaluatePolicy(
|
|
47
|
+
* { type: "allowlist", tools: ["refundCustomer"], tags: () => ["money"] },
|
|
48
|
+
* { toolName: "refundCustomer", args: { amount: 50 }, agentName: "support", tripIndex: 0 },
|
|
49
|
+
* );
|
|
50
|
+
* // → { requiresApproval: true, tags: ["money"] }
|
|
51
|
+
*/
|
|
52
|
+
declare function evaluatePolicy(policy: InterruptPolicy, context: PolicyContext): PolicyVerdict;
|
|
53
|
+
//#endregion
|
|
54
|
+
export { PolicyVerdict, evaluatePolicy };
|
|
55
|
+
//# sourceMappingURL=policy.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy.d.mts","names":[],"sources":["../../../../../../../@warlock.js/ai/src/human/policy.ts"],"mappings":";;;;;AAeA;;;;AAKM;AAoDN;;;;;UAzDiB,aAAA;EA4DD;EA1Dd,gBAAA;EAwDQ;EArDR,IAAI;AAAA;;;;AAuDU;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAHA,cAAA,CACd,MAAA,EAAQ,eAAA,EACR,OAAA,EAAS,aAAA,GACR,aAAA"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
//#region ../@warlock.js/ai/src/human/policy.ts
|
|
2
|
+
/**
|
|
3
|
+
* A verdict that lets a call through untouched. Frozen and shared so the
|
|
4
|
+
* (common) skip path allocates nothing.
|
|
5
|
+
*/
|
|
6
|
+
const SKIP = Object.freeze({ requiresApproval: false });
|
|
7
|
+
/**
|
|
8
|
+
* Normalize an author-supplied tags array into the verdict shape — an
|
|
9
|
+
* empty array is treated as "no tags" so callers never have to
|
|
10
|
+
* distinguish `[]` from `undefined`.
|
|
11
|
+
*/
|
|
12
|
+
function withTags(tags) {
|
|
13
|
+
if (tags === void 0 || tags.length === 0) return { requiresApproval: true };
|
|
14
|
+
return {
|
|
15
|
+
requiresApproval: true,
|
|
16
|
+
tags
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Decide whether a single pending tool call requires human approval —
|
|
21
|
+
* the pure core behind the `ai.human.approval` middleware's gate.
|
|
22
|
+
*
|
|
23
|
+
* **Pure.** No IO, no throwing, no mutation of `policy` or `context`. The
|
|
24
|
+
* middleware calls this once per tool dispatch and routes to a human only
|
|
25
|
+
* when {@link PolicyVerdict.requiresApproval} is `true`.
|
|
26
|
+
*
|
|
27
|
+
* **The three rule types** ({@link InterruptPolicy}):
|
|
28
|
+
* - `allowlist` — gate the call **only** when its tool name is listed; an
|
|
29
|
+
* optional `tags(toolName)` callback derives the verdict tags.
|
|
30
|
+
* - `denylist` — gate **every** call **except** the listed tool names;
|
|
31
|
+
* the same optional `tags(toolName)` callback applies to the gated
|
|
32
|
+
* (non-listed) name.
|
|
33
|
+
* - `predicate` — gate the call when `requiresApproval(context)` returns a
|
|
34
|
+
* truthy result. A non-empty `string[]` both gates the call **and**
|
|
35
|
+
* supplies the verdict tags; `true` gates with no tags; `false` (or an
|
|
36
|
+
* **empty** array — "no rule matched") lets the call through.
|
|
37
|
+
*
|
|
38
|
+
* @param policy - The interrupt policy to evaluate.
|
|
39
|
+
* @param context - The read-only view of the pending tool call.
|
|
40
|
+
* @returns A {@link PolicyVerdict} — gate-or-skip plus any tags.
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* const verdict = evaluatePolicy(
|
|
44
|
+
* { type: "allowlist", tools: ["refundCustomer"], tags: () => ["money"] },
|
|
45
|
+
* { toolName: "refundCustomer", args: { amount: 50 }, agentName: "support", tripIndex: 0 },
|
|
46
|
+
* );
|
|
47
|
+
* // → { requiresApproval: true, tags: ["money"] }
|
|
48
|
+
*/
|
|
49
|
+
function evaluatePolicy(policy, context) {
|
|
50
|
+
if (policy.type === "allowlist") {
|
|
51
|
+
if (!policy.tools.includes(context.toolName)) return SKIP;
|
|
52
|
+
return withTags(policy.tags?.(context.toolName));
|
|
53
|
+
}
|
|
54
|
+
if (policy.type === "denylist") {
|
|
55
|
+
if (policy.tools.includes(context.toolName)) return SKIP;
|
|
56
|
+
return withTags(policy.tags?.(context.toolName));
|
|
57
|
+
}
|
|
58
|
+
const outcome = policy.requiresApproval(context);
|
|
59
|
+
if (outcome === false) return SKIP;
|
|
60
|
+
if (outcome === true) return { requiresApproval: true };
|
|
61
|
+
if (outcome.length === 0) return SKIP;
|
|
62
|
+
return withTags(outcome);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
//#endregion
|
|
66
|
+
export { evaluatePolicy };
|
|
67
|
+
//# sourceMappingURL=policy.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy.mjs","names":[],"sources":["../../../../../../../@warlock.js/ai/src/human/policy.ts"],"sourcesContent":["import type { InterruptPolicy, PolicyContext } from \"./contracts\";\n\n/**\n * Verdict of evaluating an {@link InterruptPolicy} against a single\n * pending tool call.\n *\n * - `requiresApproval` — `true` when the call must be routed to a human\n * before the real tool runs; `false` when the policy lets it through\n * untouched.\n * - `tags` — author-supplied labels from the matched rule (e.g.\n * `\"destructive\"`, `\"money\"`), surfaced verbatim on the resulting\n * `ApprovalRequest.context.tags`. Only ever present when\n * `requiresApproval` is `true`; `undefined` when the rule produced no\n * tags.\n */\nexport interface PolicyVerdict {\n /** Whether this tool call must be approved by a human. */\n requiresApproval: boolean;\n\n /** Author-supplied tags from the matched rule, when any. */\n tags?: string[];\n}\n\n/**\n * A verdict that lets a call through untouched. Frozen and shared so the\n * (common) skip path allocates nothing.\n */\nconst SKIP: PolicyVerdict = Object.freeze({ requiresApproval: false });\n\n/**\n * Normalize an author-supplied tags array into the verdict shape — an\n * empty array is treated as \"no tags\" so callers never have to\n * distinguish `[]` from `undefined`.\n */\nfunction withTags(tags: string[] | undefined): PolicyVerdict {\n if (tags === undefined || tags.length === 0) {\n return { requiresApproval: true };\n }\n\n return { requiresApproval: true, tags };\n}\n\n/**\n * Decide whether a single pending tool call requires human approval —\n * the pure core behind the `ai.human.approval` middleware's gate.\n *\n * **Pure.** No IO, no throwing, no mutation of `policy` or `context`. The\n * middleware calls this once per tool dispatch and routes to a human only\n * when {@link PolicyVerdict.requiresApproval} is `true`.\n *\n * **The three rule types** ({@link InterruptPolicy}):\n * - `allowlist` — gate the call **only** when its tool name is listed; an\n * optional `tags(toolName)` callback derives the verdict tags.\n * - `denylist` — gate **every** call **except** the listed tool names;\n * the same optional `tags(toolName)` callback applies to the gated\n * (non-listed) name.\n * - `predicate` — gate the call when `requiresApproval(context)` returns a\n * truthy result. A non-empty `string[]` both gates the call **and**\n * supplies the verdict tags; `true` gates with no tags; `false` (or an\n * **empty** array — \"no rule matched\") lets the call through.\n *\n * @param policy - The interrupt policy to evaluate.\n * @param context - The read-only view of the pending tool call.\n * @returns A {@link PolicyVerdict} — gate-or-skip plus any tags.\n *\n * @example\n * const verdict = evaluatePolicy(\n * { type: \"allowlist\", tools: [\"refundCustomer\"], tags: () => [\"money\"] },\n * { toolName: \"refundCustomer\", args: { amount: 50 }, agentName: \"support\", tripIndex: 0 },\n * );\n * // → { requiresApproval: true, tags: [\"money\"] }\n */\nexport function evaluatePolicy(\n policy: InterruptPolicy,\n context: PolicyContext,\n): PolicyVerdict {\n if (policy.type === \"allowlist\") {\n if (!policy.tools.includes(context.toolName)) {\n return SKIP;\n }\n\n return withTags(policy.tags?.(context.toolName));\n }\n\n if (policy.type === \"denylist\") {\n if (policy.tools.includes(context.toolName)) {\n return SKIP;\n }\n\n return withTags(policy.tags?.(context.toolName));\n }\n\n // Predicate: a truthy result gates the call; a `string[]` doubles as the\n // verdict tags.\n const outcome = policy.requiresApproval(context);\n\n if (outcome === false) {\n return SKIP;\n }\n\n if (outcome === true) {\n return { requiresApproval: true };\n }\n\n // `outcome` is a `string[]`. Per the contract, an EMPTY array means \"no\n // rule matched\" and skips approval; a non-empty array gates the call and\n // doubles as the verdict tags.\n if (outcome.length === 0) {\n return SKIP;\n }\n\n return withTags(outcome);\n}\n"],"mappings":";;;;;AA2BA,MAAM,OAAsB,OAAO,OAAO,EAAE,kBAAkB,MAAM,CAAC;;;;;;AAOrE,SAAS,SAAS,MAA2C;CAC3D,IAAI,SAAS,UAAa,KAAK,WAAW,GACxC,OAAO,EAAE,kBAAkB,KAAK;CAGlC,OAAO;EAAE,kBAAkB;EAAM;CAAK;AACxC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCA,SAAgB,eACd,QACA,SACe;CACf,IAAI,OAAO,SAAS,aAAa;EAC/B,IAAI,CAAC,OAAO,MAAM,SAAS,QAAQ,QAAQ,GACzC,OAAO;EAGT,OAAO,SAAS,OAAO,OAAO,QAAQ,QAAQ,CAAC;CACjD;CAEA,IAAI,OAAO,SAAS,YAAY;EAC9B,IAAI,OAAO,MAAM,SAAS,QAAQ,QAAQ,GACxC,OAAO;EAGT,OAAO,SAAS,OAAO,OAAO,QAAQ,QAAQ,CAAC;CACjD;CAIA,MAAM,UAAU,OAAO,iBAAiB,OAAO;CAE/C,IAAI,YAAY,OACd,OAAO;CAGT,IAAI,YAAY,MACd,OAAO,EAAE,kBAAkB,KAAK;CAMlC,IAAI,QAAQ,WAAW,GACrB,OAAO;CAGT,OAAO,SAAS,OAAO;AACzB"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { humanApproval } from "./human-approval.mjs";
|
|
2
|
+
import { resume } from "./resume.mjs";
|
|
3
|
+
import { memory } from "./stores/memory.mjs";
|
|
4
|
+
import { pg } from "./stores/pg.mjs";
|
|
5
|
+
import { redis } from "./stores/redis.mjs";
|
|
6
|
+
import "./stores/index.mjs";
|
|
7
|
+
|
|
8
|
+
//#region ../@warlock.js/ai/src/human/register.ts
|
|
9
|
+
/**
|
|
10
|
+
* The assembled `ai.human.*` namespace — the human-in-the-loop surface
|
|
11
|
+
* mounted onto the shared `ai` object in `../ai`.
|
|
12
|
+
*
|
|
13
|
+
* - `approval(options)` — the `tool.before` approval-gate middleware.
|
|
14
|
+
* - `resume(id, decision, options)` — out-of-process durable resume.
|
|
15
|
+
* - `interrupt.{memory,pg,redis}()` — the
|
|
16
|
+
* {@link import("./contracts").InterruptStore} factories (memory ships
|
|
17
|
+
* real; pg/redis lazily import their optional-peer driver).
|
|
18
|
+
*
|
|
19
|
+
* Declared as a standalone object so `../ai` can spread it onto the `ai`
|
|
20
|
+
* literal and pin the `Ai.human` member to this exact shape with no casts.
|
|
21
|
+
* Lives here (not inlined into `../ai`) to keep the human factories grouped
|
|
22
|
+
* with the rest of the human module and avoid `../ai` reaching into each
|
|
23
|
+
* store/middleware file directly.
|
|
24
|
+
*/
|
|
25
|
+
const human = {
|
|
26
|
+
approval: humanApproval,
|
|
27
|
+
resume,
|
|
28
|
+
interrupt: {
|
|
29
|
+
memory,
|
|
30
|
+
pg,
|
|
31
|
+
redis
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
//#endregion
|
|
36
|
+
export { human };
|
|
37
|
+
//# sourceMappingURL=register.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register.mjs","names":["interruptMemory","interruptPg","interruptRedis"],"sources":["../../../../../../../@warlock.js/ai/src/human/register.ts"],"sourcesContent":["import { humanApproval } from \"./human-approval\";\nimport { resume } from \"./resume\";\nimport { interruptMemory, interruptPg, interruptRedis } from \"./stores\";\n\n/**\n * The assembled `ai.human.*` namespace — the human-in-the-loop surface\n * mounted onto the shared `ai` object in `../ai`.\n *\n * - `approval(options)` — the `tool.before` approval-gate middleware.\n * - `resume(id, decision, options)` — out-of-process durable resume.\n * - `interrupt.{memory,pg,redis}()` — the\n * {@link import(\"./contracts\").InterruptStore} factories (memory ships\n * real; pg/redis lazily import their optional-peer driver).\n *\n * Declared as a standalone object so `../ai` can spread it onto the `ai`\n * literal and pin the `Ai.human` member to this exact shape with no casts.\n * Lives here (not inlined into `../ai`) to keep the human factories grouped\n * with the rest of the human module and avoid `../ai` reaching into each\n * store/middleware file directly.\n */\nexport const human = {\n approval: humanApproval,\n resume,\n interrupt: {\n memory: interruptMemory,\n pg: interruptPg,\n redis: interruptRedis,\n },\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAoBA,MAAa,QAAQ;CACnB,UAAU;CACV;CACA,WAAW;EACDA;EACJC;EACGC;CACT;AACF"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
//#region ../@warlock.js/ai/src/human/resume-seed.ts
|
|
2
|
+
/**
|
|
3
|
+
* Process-local registry of decisions pre-seeded for a durable re-run.
|
|
4
|
+
*
|
|
5
|
+
* **Why it exists.** v1 durable resume re-runs the *same* agent turn with
|
|
6
|
+
* the human's decision already in hand (it does **not** rehydrate an
|
|
7
|
+
* in-flight supervisor — that is the deferred v2 lift). The agent's
|
|
8
|
+
* `ai.human.approval(...)` middleware is baked in at construction, so the
|
|
9
|
+
* re-run cannot be handed a different handler. Instead, `ai.human.resume(...)`
|
|
10
|
+
* stashes the decision here keyed by the agent name; the approval
|
|
11
|
+
* middleware's handler consults the registry **before** calling the
|
|
12
|
+
* author's handler and, on a hit, replays the seeded decision exactly once
|
|
13
|
+
* — so the gated tool call this time resolves to the human's ruling instead
|
|
14
|
+
* of pausing again.
|
|
15
|
+
*
|
|
16
|
+
* Keyed by agent name (not interrupt id): the re-run produces a *fresh*
|
|
17
|
+
* interrupt id (the id embeds a random segment), so the seed must be
|
|
18
|
+
* matched to the run, not the prior id. The registry holds at most one
|
|
19
|
+
* seeded decision per agent and consumes it on first read, so a second
|
|
20
|
+
* gated call in the same re-run falls through to the author's handler.
|
|
21
|
+
*/
|
|
22
|
+
const seededDecisions = /* @__PURE__ */ new Map();
|
|
23
|
+
/**
|
|
24
|
+
* Stash a decision to be replayed on the next gated tool call of `agentName`.
|
|
25
|
+
* Overwrites any prior seed for the same agent (a re-run carries exactly one
|
|
26
|
+
* pre-seeded decision).
|
|
27
|
+
*/
|
|
28
|
+
function seedDecision(agentName, decision) {
|
|
29
|
+
seededDecisions.set(agentName, decision);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Take (read **and** remove) the seeded decision for `agentName`, or
|
|
33
|
+
* `undefined` when none is staged. Consuming on read makes the seed
|
|
34
|
+
* one-shot: only the first gated call of a re-run replays it.
|
|
35
|
+
*/
|
|
36
|
+
function takeSeededDecision(agentName) {
|
|
37
|
+
const decision = seededDecisions.get(agentName);
|
|
38
|
+
if (decision === void 0) return;
|
|
39
|
+
seededDecisions.delete(agentName);
|
|
40
|
+
return decision;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Drop any staged seed for `agentName` without consuming it as a decision.
|
|
44
|
+
* Used to clean up after a re-run that errored before the seeded call fired,
|
|
45
|
+
* so a stale seed never leaks into an unrelated later run of the same agent.
|
|
46
|
+
*/
|
|
47
|
+
function clearSeededDecision(agentName) {
|
|
48
|
+
seededDecisions.delete(agentName);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
//#endregion
|
|
52
|
+
export { clearSeededDecision, seedDecision, takeSeededDecision };
|
|
53
|
+
//# sourceMappingURL=resume-seed.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resume-seed.mjs","names":[],"sources":["../../../../../../../@warlock.js/ai/src/human/resume-seed.ts"],"sourcesContent":["import type { ApprovalDecision } from \"./contracts\";\n\n/**\n * Process-local registry of decisions pre-seeded for a durable re-run.\n *\n * **Why it exists.** v1 durable resume re-runs the *same* agent turn with\n * the human's decision already in hand (it does **not** rehydrate an\n * in-flight supervisor — that is the deferred v2 lift). The agent's\n * `ai.human.approval(...)` middleware is baked in at construction, so the\n * re-run cannot be handed a different handler. Instead, `ai.human.resume(...)`\n * stashes the decision here keyed by the agent name; the approval\n * middleware's handler consults the registry **before** calling the\n * author's handler and, on a hit, replays the seeded decision exactly once\n * — so the gated tool call this time resolves to the human's ruling instead\n * of pausing again.\n *\n * Keyed by agent name (not interrupt id): the re-run produces a *fresh*\n * interrupt id (the id embeds a random segment), so the seed must be\n * matched to the run, not the prior id. The registry holds at most one\n * seeded decision per agent and consumes it on first read, so a second\n * gated call in the same re-run falls through to the author's handler.\n */\nconst seededDecisions = new Map<string, ApprovalDecision>();\n\n/**\n * Stash a decision to be replayed on the next gated tool call of `agentName`.\n * Overwrites any prior seed for the same agent (a re-run carries exactly one\n * pre-seeded decision).\n */\nexport function seedDecision(agentName: string, decision: ApprovalDecision): void {\n seededDecisions.set(agentName, decision);\n}\n\n/**\n * Take (read **and** remove) the seeded decision for `agentName`, or\n * `undefined` when none is staged. Consuming on read makes the seed\n * one-shot: only the first gated call of a re-run replays it.\n */\nexport function takeSeededDecision(agentName: string): ApprovalDecision | undefined {\n const decision = seededDecisions.get(agentName);\n\n if (decision === undefined) {\n return undefined;\n }\n\n seededDecisions.delete(agentName);\n\n return decision;\n}\n\n/**\n * Drop any staged seed for `agentName` without consuming it as a decision.\n * Used to clean up after a re-run that errored before the seeded call fired,\n * so a stale seed never leaks into an unrelated later run of the same agent.\n */\nexport function clearSeededDecision(agentName: string): void {\n seededDecisions.delete(agentName);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAsBA,MAAM,kCAAkB,IAAI,IAA8B;;;;;;AAO1D,SAAgB,aAAa,WAAmB,UAAkC;CAChF,gBAAgB,IAAI,WAAW,QAAQ;AACzC;;;;;;AAOA,SAAgB,mBAAmB,WAAiD;CAClF,MAAM,WAAW,gBAAgB,IAAI,SAAS;CAE9C,IAAI,aAAa,QACf;CAGF,gBAAgB,OAAO,SAAS;CAEhC,OAAO;AACT;;;;;;AAOA,SAAgB,oBAAoB,WAAyB;CAC3D,gBAAgB,OAAO,SAAS;AAClC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { ApprovalDecision } from "./contracts/approval.type.mjs";
|
|
2
|
+
import { ResumeOptions, ResumeResult } from "./contracts/resume.type.mjs";
|
|
3
|
+
//#region ../@warlock.js/ai/src/human/resume.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Apply a human's decision to a persisted interrupt — the out-of-process
|
|
6
|
+
* resume entry point behind `ai.human.resume(interruptId, decision, options)`.
|
|
7
|
+
*
|
|
8
|
+
* **Durable v1 model — re-run, not mid-supervisor suspend.** This loads the
|
|
9
|
+
* {@link PendingInterrupt} from `options.store`, validates the decision,
|
|
10
|
+
* deletes the pending record, and (when an `agent` is supplied) re-executes
|
|
11
|
+
* the original turn with the decision **pre-seeded**, so the gated tool call
|
|
12
|
+
* resolves to the ruling instead of pausing again. It does **not** rehydrate
|
|
13
|
+
* an in-flight supervisor — that is the deferred v2 lift.
|
|
14
|
+
*
|
|
15
|
+
* **Idempotent.** A second resume of an already-resolved (deleted) or
|
|
16
|
+
* never-raised interrupt is a no-op: it returns `{ type: "already-resolved" }`
|
|
17
|
+
* without re-applying the decision or re-running the turn — mirroring the
|
|
18
|
+
* orchestrator resume's drain idempotency. The record is deleted **before**
|
|
19
|
+
* the re-run, so even a re-run that itself raises a fresh interrupt cannot
|
|
20
|
+
* collide with the one being resolved.
|
|
21
|
+
*
|
|
22
|
+
* **Two shapes** (see {@link ResumeOptions}):
|
|
23
|
+
* - **apply-only** — omit `agent`: load, validate, delete, return
|
|
24
|
+
* `{ type: "applied", decision }` for a caller-owned re-drive.
|
|
25
|
+
* - **re-run** — pass `agent`: additionally re-execute the turn; the
|
|
26
|
+
* {@link import("@warlock.js/ai").AgentResult} rides `result.result`.
|
|
27
|
+
*
|
|
28
|
+
* @param interruptId - Id of the persisted interrupt to resolve.
|
|
29
|
+
* @param decision - The human's ruling (approve / reject / edit).
|
|
30
|
+
* @param options - The durable `store` (required) plus optional re-run
|
|
31
|
+
* `agent` / `input` / `executeOptions`.
|
|
32
|
+
* @returns A {@link ResumeResult} — `"applied"` or idempotent
|
|
33
|
+
* `"already-resolved"`.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* // Process B (webhook, hours later) — apply-only:
|
|
37
|
+
* const outcome = await ai.human.resume(interruptId, { type: "reject", reason: "Out of policy" }, {
|
|
38
|
+
* store,
|
|
39
|
+
* });
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* // Re-run the turn with the decision pre-seeded:
|
|
43
|
+
* const outcome = await ai.human.resume(interruptId, { type: "edit", args: { amount: 5 } }, {
|
|
44
|
+
* store,
|
|
45
|
+
* agent: support,
|
|
46
|
+
* });
|
|
47
|
+
* if (outcome.type === "applied" && outcome.result) {
|
|
48
|
+
* console.log(outcome.result.text);
|
|
49
|
+
* }
|
|
50
|
+
*/
|
|
51
|
+
declare function resume<TOutput = unknown>(interruptId: string, decision: ApprovalDecision, options: ResumeOptions<TOutput>): Promise<ResumeResult<TOutput>>;
|
|
52
|
+
//#endregion
|
|
53
|
+
export { resume };
|
|
54
|
+
//# sourceMappingURL=resume.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resume.d.mts","names":[],"sources":["../../../../../../../@warlock.js/ai/src/human/resume.ts"],"mappings":";;;;;;;AAyIA;;;;;;;;;;;;;;;;;;;;;;AAI+B;;;;;;;;;;;;;;;;;;;;;iBAJT,MAAA,oBACpB,WAAA,UACA,QAAA,EAAU,gBAAA,EACV,OAAA,EAAS,aAAA,CAAc,OAAA,IACtB,OAAA,CAAQ,YAAA,CAAa,OAAA"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { clearSeededDecision, seedDecision } from "./resume-seed.mjs";
|
|
2
|
+
|
|
3
|
+
//#region ../@warlock.js/ai/src/human/resume.ts
|
|
4
|
+
/**
|
|
5
|
+
* Validate that a decision is a well-formed {@link ApprovalDecision}.
|
|
6
|
+
*
|
|
7
|
+
* `ai.human.resume(...)` is a public, out-of-process entry point — a
|
|
8
|
+
* webhook can hand it anything. Guard the closed `type` union (and the
|
|
9
|
+
* per-variant required fields) before applying it, so a malformed payload
|
|
10
|
+
* fails loudly here rather than silently mis-driving the re-run.
|
|
11
|
+
*/
|
|
12
|
+
function assertDecision(decision) {
|
|
13
|
+
if (decision.type === "approve") return;
|
|
14
|
+
if (decision.type === "reject") {
|
|
15
|
+
if (typeof decision.reason !== "string") throw new TypeError("ai.human.resume: a 'reject' decision requires a string 'reason'.");
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
if (decision.type === "edit") {
|
|
19
|
+
if (!("args" in decision)) throw new TypeError("ai.human.resume: an 'edit' decision requires replacement 'args'.");
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
throw new TypeError(`ai.human.resume: unknown decision type '${decision.type}'. Expected one of: approve, reject, edit.`);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Re-run the agent for a resumed interrupt with the decision pre-seeded.
|
|
26
|
+
*
|
|
27
|
+
* Stages the decision in the process-local seed registry (keyed by agent
|
|
28
|
+
* name), then re-executes the original prompt. The agent's
|
|
29
|
+
* `ai.human.approval(...)` middleware consumes the seed on the gated tool
|
|
30
|
+
* call — so this time it resolves to the human's ruling instead of pausing
|
|
31
|
+
* again. The seed is cleared in a `finally` so a re-run that errors before
|
|
32
|
+
* the gated call never leaks a stale seed into a later run.
|
|
33
|
+
*/
|
|
34
|
+
async function rerun(pending, decision, options) {
|
|
35
|
+
const { agent } = options;
|
|
36
|
+
if (!agent) return {
|
|
37
|
+
type: "applied",
|
|
38
|
+
interruptId: pending.interruptId,
|
|
39
|
+
decision
|
|
40
|
+
};
|
|
41
|
+
const input = options.input ?? pending.request.context.originalInput ?? "";
|
|
42
|
+
seedDecision(agent.name, decision);
|
|
43
|
+
try {
|
|
44
|
+
const result = await agent.execute(input, options.executeOptions);
|
|
45
|
+
return {
|
|
46
|
+
type: "applied",
|
|
47
|
+
interruptId: pending.interruptId,
|
|
48
|
+
decision,
|
|
49
|
+
result
|
|
50
|
+
};
|
|
51
|
+
} finally {
|
|
52
|
+
clearSeededDecision(agent.name);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Apply a human's decision to a persisted interrupt — the out-of-process
|
|
57
|
+
* resume entry point behind `ai.human.resume(interruptId, decision, options)`.
|
|
58
|
+
*
|
|
59
|
+
* **Durable v1 model — re-run, not mid-supervisor suspend.** This loads the
|
|
60
|
+
* {@link PendingInterrupt} from `options.store`, validates the decision,
|
|
61
|
+
* deletes the pending record, and (when an `agent` is supplied) re-executes
|
|
62
|
+
* the original turn with the decision **pre-seeded**, so the gated tool call
|
|
63
|
+
* resolves to the ruling instead of pausing again. It does **not** rehydrate
|
|
64
|
+
* an in-flight supervisor — that is the deferred v2 lift.
|
|
65
|
+
*
|
|
66
|
+
* **Idempotent.** A second resume of an already-resolved (deleted) or
|
|
67
|
+
* never-raised interrupt is a no-op: it returns `{ type: "already-resolved" }`
|
|
68
|
+
* without re-applying the decision or re-running the turn — mirroring the
|
|
69
|
+
* orchestrator resume's drain idempotency. The record is deleted **before**
|
|
70
|
+
* the re-run, so even a re-run that itself raises a fresh interrupt cannot
|
|
71
|
+
* collide with the one being resolved.
|
|
72
|
+
*
|
|
73
|
+
* **Two shapes** (see {@link ResumeOptions}):
|
|
74
|
+
* - **apply-only** — omit `agent`: load, validate, delete, return
|
|
75
|
+
* `{ type: "applied", decision }` for a caller-owned re-drive.
|
|
76
|
+
* - **re-run** — pass `agent`: additionally re-execute the turn; the
|
|
77
|
+
* {@link import("@warlock.js/ai").AgentResult} rides `result.result`.
|
|
78
|
+
*
|
|
79
|
+
* @param interruptId - Id of the persisted interrupt to resolve.
|
|
80
|
+
* @param decision - The human's ruling (approve / reject / edit).
|
|
81
|
+
* @param options - The durable `store` (required) plus optional re-run
|
|
82
|
+
* `agent` / `input` / `executeOptions`.
|
|
83
|
+
* @returns A {@link ResumeResult} — `"applied"` or idempotent
|
|
84
|
+
* `"already-resolved"`.
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* // Process B (webhook, hours later) — apply-only:
|
|
88
|
+
* const outcome = await ai.human.resume(interruptId, { type: "reject", reason: "Out of policy" }, {
|
|
89
|
+
* store,
|
|
90
|
+
* });
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
* // Re-run the turn with the decision pre-seeded:
|
|
94
|
+
* const outcome = await ai.human.resume(interruptId, { type: "edit", args: { amount: 5 } }, {
|
|
95
|
+
* store,
|
|
96
|
+
* agent: support,
|
|
97
|
+
* });
|
|
98
|
+
* if (outcome.type === "applied" && outcome.result) {
|
|
99
|
+
* console.log(outcome.result.text);
|
|
100
|
+
* }
|
|
101
|
+
*/
|
|
102
|
+
async function resume(interruptId, decision, options) {
|
|
103
|
+
assertDecision(decision);
|
|
104
|
+
const { store } = options;
|
|
105
|
+
const pending = await store.load(interruptId);
|
|
106
|
+
if (pending === void 0 || pending.status !== "pending") return {
|
|
107
|
+
type: "already-resolved",
|
|
108
|
+
interruptId
|
|
109
|
+
};
|
|
110
|
+
await store.delete(interruptId);
|
|
111
|
+
if (!options.agent) return {
|
|
112
|
+
type: "applied",
|
|
113
|
+
interruptId,
|
|
114
|
+
decision
|
|
115
|
+
};
|
|
116
|
+
return rerun(pending, decision, options);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
//#endregion
|
|
120
|
+
export { resume };
|
|
121
|
+
//# sourceMappingURL=resume.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resume.mjs","names":[],"sources":["../../../../../../../@warlock.js/ai/src/human/resume.ts"],"sourcesContent":["import type {\n ApprovalDecision,\n PendingInterrupt,\n ResumeOptions,\n ResumeResult,\n} from \"./contracts\";\nimport { clearSeededDecision, seedDecision } from \"./resume-seed\";\n\n/**\n * Validate that a decision is a well-formed {@link ApprovalDecision}.\n *\n * `ai.human.resume(...)` is a public, out-of-process entry point — a\n * webhook can hand it anything. Guard the closed `type` union (and the\n * per-variant required fields) before applying it, so a malformed payload\n * fails loudly here rather than silently mis-driving the re-run.\n */\nfunction assertDecision(decision: ApprovalDecision): void {\n if (decision.type === \"approve\") {\n return;\n }\n\n if (decision.type === \"reject\") {\n if (typeof decision.reason !== \"string\") {\n throw new TypeError(\n \"ai.human.resume: a 'reject' decision requires a string 'reason'.\",\n );\n }\n\n return;\n }\n\n if (decision.type === \"edit\") {\n if (!(\"args\" in decision)) {\n throw new TypeError(\n \"ai.human.resume: an 'edit' decision requires replacement 'args'.\",\n );\n }\n\n return;\n }\n\n throw new TypeError(\n `ai.human.resume: unknown decision type '${(decision as { type: string }).type}'. Expected one of: approve, reject, edit.`,\n );\n}\n\n/**\n * Re-run the agent for a resumed interrupt with the decision pre-seeded.\n *\n * Stages the decision in the process-local seed registry (keyed by agent\n * name), then re-executes the original prompt. The agent's\n * `ai.human.approval(...)` middleware consumes the seed on the gated tool\n * call — so this time it resolves to the human's ruling instead of pausing\n * again. The seed is cleared in a `finally` so a re-run that errors before\n * the gated call never leaks a stale seed into a later run.\n */\nasync function rerun<TOutput>(\n pending: PendingInterrupt,\n decision: ApprovalDecision,\n options: ResumeOptions<TOutput>,\n): Promise<ResumeResult<TOutput>> {\n const { agent } = options;\n\n // `agent` is guaranteed by the caller (this is only reached on the\n // re-run path), but narrow for the type system.\n if (!agent) {\n return { type: \"applied\", interruptId: pending.interruptId, decision };\n }\n\n const input = options.input ?? pending.request.context.originalInput ?? \"\";\n\n seedDecision(agent.name, decision);\n\n try {\n const result = await agent.execute(input, options.executeOptions);\n\n return {\n type: \"applied\",\n interruptId: pending.interruptId,\n decision,\n result,\n };\n } finally {\n // If the seeded call never fired (the re-run errored early, or the\n // policy no longer gates the tool), drop the stale seed so it cannot\n // leak into an unrelated later run of the same agent.\n clearSeededDecision(agent.name);\n }\n}\n\n/**\n * Apply a human's decision to a persisted interrupt — the out-of-process\n * resume entry point behind `ai.human.resume(interruptId, decision, options)`.\n *\n * **Durable v1 model — re-run, not mid-supervisor suspend.** This loads the\n * {@link PendingInterrupt} from `options.store`, validates the decision,\n * deletes the pending record, and (when an `agent` is supplied) re-executes\n * the original turn with the decision **pre-seeded**, so the gated tool call\n * resolves to the ruling instead of pausing again. It does **not** rehydrate\n * an in-flight supervisor — that is the deferred v2 lift.\n *\n * **Idempotent.** A second resume of an already-resolved (deleted) or\n * never-raised interrupt is a no-op: it returns `{ type: \"already-resolved\" }`\n * without re-applying the decision or re-running the turn — mirroring the\n * orchestrator resume's drain idempotency. The record is deleted **before**\n * the re-run, so even a re-run that itself raises a fresh interrupt cannot\n * collide with the one being resolved.\n *\n * **Two shapes** (see {@link ResumeOptions}):\n * - **apply-only** — omit `agent`: load, validate, delete, return\n * `{ type: \"applied\", decision }` for a caller-owned re-drive.\n * - **re-run** — pass `agent`: additionally re-execute the turn; the\n * {@link import(\"@warlock.js/ai\").AgentResult} rides `result.result`.\n *\n * @param interruptId - Id of the persisted interrupt to resolve.\n * @param decision - The human's ruling (approve / reject / edit).\n * @param options - The durable `store` (required) plus optional re-run\n * `agent` / `input` / `executeOptions`.\n * @returns A {@link ResumeResult} — `\"applied\"` or idempotent\n * `\"already-resolved\"`.\n *\n * @example\n * // Process B (webhook, hours later) — apply-only:\n * const outcome = await ai.human.resume(interruptId, { type: \"reject\", reason: \"Out of policy\" }, {\n * store,\n * });\n *\n * @example\n * // Re-run the turn with the decision pre-seeded:\n * const outcome = await ai.human.resume(interruptId, { type: \"edit\", args: { amount: 5 } }, {\n * store,\n * agent: support,\n * });\n * if (outcome.type === \"applied\" && outcome.result) {\n * console.log(outcome.result.text);\n * }\n */\nexport async function resume<TOutput = unknown>(\n interruptId: string,\n decision: ApprovalDecision,\n options: ResumeOptions<TOutput>,\n): Promise<ResumeResult<TOutput>> {\n assertDecision(decision);\n\n const { store } = options;\n const pending = await store.load(interruptId);\n\n // No live interrupt — already resolved + deleted, or never raised. Never\n // double-apply; never re-run. Idempotent no-op.\n if (pending === undefined || pending.status !== \"pending\") {\n return { type: \"already-resolved\", interruptId };\n }\n\n // Resolve + delete BEFORE the re-run so a re-run that itself raises a new\n // interrupt cannot collide with the one being resolved, and a concurrent\n // resume of the same id sees it gone.\n await store.delete(interruptId);\n\n if (!options.agent) {\n return { type: \"applied\", interruptId, decision };\n }\n\n return rerun(pending, decision, options);\n}\n"],"mappings":";;;;;;;;;;;AAgBA,SAAS,eAAe,UAAkC;CACxD,IAAI,SAAS,SAAS,WACpB;CAGF,IAAI,SAAS,SAAS,UAAU;EAC9B,IAAI,OAAO,SAAS,WAAW,UAC7B,MAAM,IAAI,UACR,kEACF;EAGF;CACF;CAEA,IAAI,SAAS,SAAS,QAAQ;EAC5B,IAAI,EAAE,UAAU,WACd,MAAM,IAAI,UACR,kEACF;EAGF;CACF;CAEA,MAAM,IAAI,UACR,2CAA4C,SAA8B,KAAK,2CACjF;AACF;;;;;;;;;;;AAYA,eAAe,MACb,SACA,UACA,SACgC;CAChC,MAAM,EAAE,UAAU;CAIlB,IAAI,CAAC,OACH,OAAO;EAAE,MAAM;EAAW,aAAa,QAAQ;EAAa;CAAS;CAGvE,MAAM,QAAQ,QAAQ,SAAS,QAAQ,QAAQ,QAAQ,iBAAiB;CAExE,aAAa,MAAM,MAAM,QAAQ;CAEjC,IAAI;EACF,MAAM,SAAS,MAAM,MAAM,QAAQ,OAAO,QAAQ,cAAc;EAEhE,OAAO;GACL,MAAM;GACN,aAAa,QAAQ;GACrB;GACA;EACF;CACF,UAAU;EAIR,oBAAoB,MAAM,IAAI;CAChC;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiDA,eAAsB,OACpB,aACA,UACA,SACgC;CAChC,eAAe,QAAQ;CAEvB,MAAM,EAAE,UAAU;CAClB,MAAM,UAAU,MAAM,MAAM,KAAK,WAAW;CAI5C,IAAI,YAAY,UAAa,QAAQ,WAAW,WAC9C,OAAO;EAAE,MAAM;EAAoB;CAAY;CAMjD,MAAM,MAAM,OAAO,WAAW;CAE9B,IAAI,CAAC,QAAQ,OACX,OAAO;EAAE,MAAM;EAAW;EAAa;CAAS;CAGlD,OAAO,MAAM,SAAS,UAAU,OAAO;AACzC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { InterruptStore } from "../contracts/interrupt-store.contract.mjs";
|
|
2
|
+
|
|
3
|
+
//#region ../@warlock.js/ai/src/human/stores/memory.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Create an in-memory {@link InterruptStore}. Zero-config — no client, no
|
|
6
|
+
* connection. Suitable for dev, tests, and single-process apps whose
|
|
7
|
+
* approval flow stays interactive and doesn't need resume across
|
|
8
|
+
* restarts.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* import { ai } from "@warlock.js/ai";
|
|
12
|
+
*
|
|
13
|
+
* const store = ai.human.interrupt.memory();
|
|
14
|
+
*
|
|
15
|
+
* const agent = ai.agent({
|
|
16
|
+
* model,
|
|
17
|
+
* tools: [deleteAccount],
|
|
18
|
+
* middleware: [
|
|
19
|
+
* ai.human.approval({
|
|
20
|
+
* policy: { type: "allowlist", tools: ["deleteAccount"] },
|
|
21
|
+
* store,
|
|
22
|
+
* handler,
|
|
23
|
+
* }),
|
|
24
|
+
* ],
|
|
25
|
+
* });
|
|
26
|
+
*/
|
|
27
|
+
declare function memory(): InterruptStore;
|
|
28
|
+
//#endregion
|
|
29
|
+
export { memory };
|
|
30
|
+
//# sourceMappingURL=memory.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory.d.mts","names":[],"sources":["../../../../../../../../@warlock.js/ai/src/human/stores/memory.ts"],"mappings":";;;;;AAmGA;;;;AAAwC;;;;;;;;;;;;;;;;;iBAAxB,MAAA,IAAU,cAAc"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
//#region ../@warlock.js/ai/src/human/stores/memory.ts
|
|
2
|
+
/**
|
|
3
|
+
* In-memory {@link InterruptStore} — pending interrupts held in a
|
|
4
|
+
* process-local `Map`, never persisted to disk.
|
|
5
|
+
*
|
|
6
|
+
* Owns: the `interruptId → {@link PendingInterrupt}` index and the
|
|
7
|
+
* last-writer-wins `save` / `load` / `delete` / `list` semantics the
|
|
8
|
+
* contract declares. Does NOT own: durability, cross-process sharing, or
|
|
9
|
+
* TTL eviction — it is the zero-config default for dev, tests, and
|
|
10
|
+
* single-process apps whose approval flow stays interactive (the run
|
|
11
|
+
* `await`s the decision in-process and never needs to survive a restart).
|
|
12
|
+
* Reach for `ai.human.interrupt.pg()` / `ai.human.interrupt.redis()` when
|
|
13
|
+
* a reviewer rules out-of-process, hours later.
|
|
14
|
+
*
|
|
15
|
+
* Front it with the {@link memory} factory — callers never `new` it.
|
|
16
|
+
*/
|
|
17
|
+
var MemoryInterruptStore = class {
|
|
18
|
+
constructor() {
|
|
19
|
+
this.interrupts = /* @__PURE__ */ new Map();
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Persist a pending interrupt, keyed by its own `interruptId`.
|
|
23
|
+
* Overwrites any prior record for the same id — a call has exactly one
|
|
24
|
+
* live interrupt, so a re-save replaces rather than appends.
|
|
25
|
+
*/
|
|
26
|
+
async save(record) {
|
|
27
|
+
this.interrupts.set(record.interruptId, record);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Return the interrupt for an `interruptId`, or `undefined` when none is
|
|
31
|
+
* recorded (never raised, or already resolved + deleted).
|
|
32
|
+
*/
|
|
33
|
+
async load(interruptId) {
|
|
34
|
+
return this.interrupts.get(interruptId);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Drop the interrupt for an `interruptId`. Idempotent — deleting an
|
|
38
|
+
* absent id is a no-op.
|
|
39
|
+
*/
|
|
40
|
+
async delete(interruptId) {
|
|
41
|
+
this.interrupts.delete(interruptId);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* List the interrupt ids the store knows, optionally filtered by a
|
|
45
|
+
* prefix. Returns a fresh array each call so a caller can mutate it
|
|
46
|
+
* freely without touching the backing index.
|
|
47
|
+
*/
|
|
48
|
+
async list(prefix) {
|
|
49
|
+
const ids = [...this.interrupts.keys()];
|
|
50
|
+
if (prefix === void 0) return ids;
|
|
51
|
+
return ids.filter((id) => id.startsWith(prefix));
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* The memory store has no backing table — there is nothing to migrate.
|
|
55
|
+
* Returns an empty string so callers can treat `schema()` uniformly
|
|
56
|
+
* across drivers.
|
|
57
|
+
*/
|
|
58
|
+
schema() {
|
|
59
|
+
return "";
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* Create an in-memory {@link InterruptStore}. Zero-config — no client, no
|
|
64
|
+
* connection. Suitable for dev, tests, and single-process apps whose
|
|
65
|
+
* approval flow stays interactive and doesn't need resume across
|
|
66
|
+
* restarts.
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* import { ai } from "@warlock.js/ai";
|
|
70
|
+
*
|
|
71
|
+
* const store = ai.human.interrupt.memory();
|
|
72
|
+
*
|
|
73
|
+
* const agent = ai.agent({
|
|
74
|
+
* model,
|
|
75
|
+
* tools: [deleteAccount],
|
|
76
|
+
* middleware: [
|
|
77
|
+
* ai.human.approval({
|
|
78
|
+
* policy: { type: "allowlist", tools: ["deleteAccount"] },
|
|
79
|
+
* store,
|
|
80
|
+
* handler,
|
|
81
|
+
* }),
|
|
82
|
+
* ],
|
|
83
|
+
* });
|
|
84
|
+
*/
|
|
85
|
+
function memory() {
|
|
86
|
+
return new MemoryInterruptStore();
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
//#endregion
|
|
90
|
+
export { memory };
|
|
91
|
+
//# sourceMappingURL=memory.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory.mjs","names":[],"sources":["../../../../../../../../@warlock.js/ai/src/human/stores/memory.ts"],"sourcesContent":["import type {\n InterruptStore,\n PendingInterrupt,\n} from \"../contracts/interrupt-store.contract\";\n\n/**\n * In-memory {@link InterruptStore} — pending interrupts held in a\n * process-local `Map`, never persisted to disk.\n *\n * Owns: the `interruptId → {@link PendingInterrupt}` index and the\n * last-writer-wins `save` / `load` / `delete` / `list` semantics the\n * contract declares. Does NOT own: durability, cross-process sharing, or\n * TTL eviction — it is the zero-config default for dev, tests, and\n * single-process apps whose approval flow stays interactive (the run\n * `await`s the decision in-process and never needs to survive a restart).\n * Reach for `ai.human.interrupt.pg()` / `ai.human.interrupt.redis()` when\n * a reviewer rules out-of-process, hours later.\n *\n * Front it with the {@link memory} factory — callers never `new` it.\n */\nclass MemoryInterruptStore implements InterruptStore {\n /** Pending interrupts keyed by their own `interruptId`. */\n private readonly interrupts = new Map<string, PendingInterrupt>();\n\n /**\n * Persist a pending interrupt, keyed by its own `interruptId`.\n * Overwrites any prior record for the same id — a call has exactly one\n * live interrupt, so a re-save replaces rather than appends.\n */\n public async save(record: PendingInterrupt): Promise<void> {\n this.interrupts.set(record.interruptId, record);\n }\n\n /**\n * Return the interrupt for an `interruptId`, or `undefined` when none is\n * recorded (never raised, or already resolved + deleted).\n */\n public async load(\n interruptId: string,\n ): Promise<PendingInterrupt | undefined> {\n return this.interrupts.get(interruptId);\n }\n\n /**\n * Drop the interrupt for an `interruptId`. Idempotent — deleting an\n * absent id is a no-op.\n */\n public async delete(interruptId: string): Promise<void> {\n this.interrupts.delete(interruptId);\n }\n\n /**\n * List the interrupt ids the store knows, optionally filtered by a\n * prefix. Returns a fresh array each call so a caller can mutate it\n * freely without touching the backing index.\n */\n public async list(prefix?: string): Promise<string[]> {\n const ids = [...this.interrupts.keys()];\n\n if (prefix === undefined) {\n return ids;\n }\n\n return ids.filter((id) => id.startsWith(prefix));\n }\n\n /**\n * The memory store has no backing table — there is nothing to migrate.\n * Returns an empty string so callers can treat `schema()` uniformly\n * across drivers.\n */\n public schema(): string {\n return \"\";\n }\n}\n\n/**\n * Create an in-memory {@link InterruptStore}. Zero-config — no client, no\n * connection. Suitable for dev, tests, and single-process apps whose\n * approval flow stays interactive and doesn't need resume across\n * restarts.\n *\n * @example\n * import { ai } from \"@warlock.js/ai\";\n *\n * const store = ai.human.interrupt.memory();\n *\n * const agent = ai.agent({\n * model,\n * tools: [deleteAccount],\n * middleware: [\n * ai.human.approval({\n * policy: { type: \"allowlist\", tools: [\"deleteAccount\"] },\n * store,\n * handler,\n * }),\n * ],\n * });\n */\nexport function memory(): InterruptStore {\n return new MemoryInterruptStore();\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAoBA,IAAM,uBAAN,MAAqD;;oCAErB,IAAI,IAA8B;;;;;;;CAOhE,MAAa,KAAK,QAAyC;EACzD,KAAK,WAAW,IAAI,OAAO,aAAa,MAAM;CAChD;;;;;CAMA,MAAa,KACX,aACuC;EACvC,OAAO,KAAK,WAAW,IAAI,WAAW;CACxC;;;;;CAMA,MAAa,OAAO,aAAoC;EACtD,KAAK,WAAW,OAAO,WAAW;CACpC;;;;;;CAOA,MAAa,KAAK,QAAoC;EACpD,MAAM,MAAM,CAAC,GAAG,KAAK,WAAW,KAAK,CAAC;EAEtC,IAAI,WAAW,QACb,OAAO;EAGT,OAAO,IAAI,QAAQ,OAAO,GAAG,WAAW,MAAM,CAAC;CACjD;;;;;;CAOA,AAAO,SAAiB;EACtB,OAAO;CACT;AACF;;;;;;;;;;;;;;;;;;;;;;;;AAyBA,SAAgB,SAAyB;CACvC,OAAO,IAAI,qBAAqB;AAClC"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { InterruptStore, PgClientLike } from "../contracts/interrupt-store.contract.mjs";
|
|
2
|
+
|
|
3
|
+
//#region ../@warlock.js/ai/src/human/stores/pg.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Options for the Postgres {@link InterruptStore}.
|
|
6
|
+
*
|
|
7
|
+
* Two mutually-supportive ways to supply the connection:
|
|
8
|
+
* - **`client`** — pass an already-built `pg.Pool` / `pg.Client` (anything
|
|
9
|
+
* satisfying {@link PgClientLike}). The store only ever calls `query`
|
|
10
|
+
* and never opens or closes it; a single pool can back both an
|
|
11
|
+
* orchestrator's checkpoint/snapshot stores and this interrupt table.
|
|
12
|
+
* - **`connectionString`** — let the store lazily `import("pg")` and build
|
|
13
|
+
* its own `Pool`. `@warlock.js/ai` takes **no** hard dependency on
|
|
14
|
+
* `pg` (it is an optional peer); when it is absent the store throws a
|
|
15
|
+
* curated install string at first use, never a raw module-resolution
|
|
16
|
+
* stack trace at import.
|
|
17
|
+
*
|
|
18
|
+
* Exactly one of the two must be present.
|
|
19
|
+
*/
|
|
20
|
+
interface PgInterruptOptions {
|
|
21
|
+
/** An already-built `pg.Pool` / `pg.Client` — anything matching {@link PgClientLike}. */
|
|
22
|
+
client?: PgClientLike;
|
|
23
|
+
/** Connection string the store passes to a lazily-imported `pg.Pool`. */
|
|
24
|
+
connectionString?: string;
|
|
25
|
+
/**
|
|
26
|
+
* Backing table name. Defaults to `warlock_ai_human_interrupts`. Must be
|
|
27
|
+
* a safe SQL identifier — it is interpolated into DDL/DML.
|
|
28
|
+
*/
|
|
29
|
+
table?: string;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Create a Postgres-backed {@link InterruptStore}. Either pass a live
|
|
33
|
+
* `pg.Pool` / `pg.Client` (`{ client }`) — `@warlock.js/ai` never
|
|
34
|
+
* imports `pg` in that case — or a `{ connectionString }` and let the
|
|
35
|
+
* store lazily `import("pg")` to build its own pool. When `pg` is not
|
|
36
|
+
* installed, the curated install string surfaces on first use, never at
|
|
37
|
+
* import. Run {@link InterruptStore.schema} through your migration tool
|
|
38
|
+
* once before use; the store never auto-migrates.
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* import { Pool } from "pg";
|
|
42
|
+
* import { ai } from "@warlock.js/ai";
|
|
43
|
+
*
|
|
44
|
+
* const pool = new Pool({ connectionString: process.env.DATABASE_URL });
|
|
45
|
+
* const store = ai.human.interrupt.pg({ client: pool });
|
|
46
|
+
*
|
|
47
|
+
* // Once, via your migration tooling:
|
|
48
|
+
* // await pool.query(store.schema());
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* // Let the store build its own pool from a connection string:
|
|
52
|
+
* const store = ai.human.interrupt.pg({
|
|
53
|
+
* connectionString: process.env.DATABASE_URL,
|
|
54
|
+
* });
|
|
55
|
+
*/
|
|
56
|
+
declare function pg(options: PgInterruptOptions): InterruptStore;
|
|
57
|
+
//#endregion
|
|
58
|
+
export { PgInterruptOptions, pg };
|
|
59
|
+
//# sourceMappingURL=pg.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pg.d.mts","names":[],"sources":["../../../../../../../../@warlock.js/ai/src/human/stores/pg.ts"],"mappings":";;;;;AAsBA;;;;;;;;;AAWO;AA0TP;;;;UArUiB,kBAAA;EAqUE;EAnUjB,MAAA,GAAS,YAAY;EAmUwC;EAhU7D,gBAAA;;;;;EAMA,KAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;iBA0Tc,EAAA,CAAG,OAAA,EAAS,kBAAA,GAAqB,cAAc"}
|