@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,170 @@
|
|
|
1
|
+
import { judge } from "../eval/judge-scorer.mjs";
|
|
2
|
+
|
|
3
|
+
//#region ../@warlock.js/ai/src/prompt/prompt-validate.ts
|
|
4
|
+
/**
|
|
5
|
+
* Placeholder matcher — kept in lock-step with the matcher
|
|
6
|
+
* `renderPlaceholders` uses (`src/system-prompt/render-placeholders.ts`) so the
|
|
7
|
+
* lint sees the same `{{key}}` / `{{a.b}}` / `{{key|default}}` set the renderer
|
|
8
|
+
* substitutes. Global so every occurrence is collected.
|
|
9
|
+
*/
|
|
10
|
+
const PLACEHOLDER_PATTERN = /\{\{\s*([^{}]+?)\s*\}\}/g;
|
|
11
|
+
/** Lower bound below which a prompt is suspiciously terse. */
|
|
12
|
+
const MIN_REASONABLE_LENGTH = 12;
|
|
13
|
+
/** Upper bound above which a prompt is likely bloated / unfocused. */
|
|
14
|
+
const MAX_REASONABLE_LENGTH = 8e3;
|
|
15
|
+
/**
|
|
16
|
+
* Severity rank for most-severe-first ordering. Higher sorts earlier.
|
|
17
|
+
*/
|
|
18
|
+
const SEVERITY_RANK = {
|
|
19
|
+
error: 2,
|
|
20
|
+
warn: 1,
|
|
21
|
+
info: 0
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* The fixed rubric the LLM-as-judge grades a prompt body against. Surfaced
|
|
25
|
+
* here (not inline) so the static-lint pass and the judge pass document the
|
|
26
|
+
* same quality dimensions.
|
|
27
|
+
*/
|
|
28
|
+
const PROMPT_JUDGE_RUBRIC = [
|
|
29
|
+
"Grade this SYSTEM PROMPT on a 0..1 scale for overall quality:",
|
|
30
|
+
"- Clarity: is the intent unambiguous and easy to follow?",
|
|
31
|
+
"- Role definition: does it clearly state who/what the assistant is?",
|
|
32
|
+
"- Output-format specificity: does it say how the answer should be shaped?",
|
|
33
|
+
"- No conflicting instructions: are any directives contradictory?",
|
|
34
|
+
"Score 1.0 only when all four hold; deduct for each weakness and explain why."
|
|
35
|
+
].join("\n");
|
|
36
|
+
/**
|
|
37
|
+
* Heuristic role-line detector — a prompt that never says "you are …" /
|
|
38
|
+
* "act as …" / "your role is …" typically lacks a persona. Case-insensitive.
|
|
39
|
+
*/
|
|
40
|
+
const ROLE_HINT_PATTERN = /\b(you are|act as|your role is|you're a|you will act)\b/i;
|
|
41
|
+
/**
|
|
42
|
+
* Run the cheap, model-free static lint over a prompt body. Flags:
|
|
43
|
+
* - length out of the reasonable band (too terse / too bloated),
|
|
44
|
+
* - any `{{placeholder}}` that survives (undeclared / unresolved at lint time),
|
|
45
|
+
* - a missing role line.
|
|
46
|
+
*
|
|
47
|
+
* Pure and synchronous — used standalone (no judge model) and merged with the
|
|
48
|
+
* judge findings when a model is available.
|
|
49
|
+
*
|
|
50
|
+
* @param text - The prompt body to lint.
|
|
51
|
+
*/
|
|
52
|
+
function staticLint(text) {
|
|
53
|
+
const notes = [];
|
|
54
|
+
const trimmed = text.trim();
|
|
55
|
+
if (trimmed.length < MIN_REASONABLE_LENGTH) notes.push({
|
|
56
|
+
severity: "warn",
|
|
57
|
+
message: `Prompt is very short (${trimmed.length} chars) — it may be too vague to steer the model.`,
|
|
58
|
+
suggestion: "Add an explicit role and at least one concrete instruction."
|
|
59
|
+
});
|
|
60
|
+
if (trimmed.length > MAX_REASONABLE_LENGTH) notes.push({
|
|
61
|
+
severity: "warn",
|
|
62
|
+
message: `Prompt is very long (${trimmed.length} chars) — long prompts dilute focus and inflate cost.`,
|
|
63
|
+
suggestion: "Split into a tighter persona plus a few focused instructions."
|
|
64
|
+
});
|
|
65
|
+
const placeholders = collectPlaceholders(text);
|
|
66
|
+
for (const placeholder of placeholders) notes.push({
|
|
67
|
+
severity: "info",
|
|
68
|
+
message: `Unresolved placeholder "{{${placeholder}}}" — confirm it is supplied at resolve time or give it a default ("{{${placeholder}|...}}").`
|
|
69
|
+
});
|
|
70
|
+
if (!ROLE_HINT_PATTERN.test(trimmed)) notes.push({
|
|
71
|
+
severity: "warn",
|
|
72
|
+
message: "No role line found — the prompt never states who the assistant is.",
|
|
73
|
+
suggestion: "Open with a role, e.g. \"You are a senior support engineer for …\"."
|
|
74
|
+
});
|
|
75
|
+
return notes;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Collect every distinct placeholder PATH (the part before any `|default`)
|
|
79
|
+
* from a template, in first-seen order. Matches `renderPlaceholders`' own
|
|
80
|
+
* parsing so the lint never disagrees with the renderer.
|
|
81
|
+
*/
|
|
82
|
+
function collectPlaceholders(template) {
|
|
83
|
+
const found = [];
|
|
84
|
+
const seen = /* @__PURE__ */ new Set();
|
|
85
|
+
for (const match of template.matchAll(PLACEHOLDER_PATTERN)) {
|
|
86
|
+
const path = match[1].split("|")[0].trim();
|
|
87
|
+
if (path.length > 0 && !seen.has(path)) {
|
|
88
|
+
seen.add(path);
|
|
89
|
+
found.push(path);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return found;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Stable, most-severe-first ordering: `error` before `warn` before `info`,
|
|
96
|
+
* preserving original order within a severity. Returns a fresh array.
|
|
97
|
+
*/
|
|
98
|
+
function sortNotesBySeverity(notes) {
|
|
99
|
+
return notes.map((note, index) => ({
|
|
100
|
+
note,
|
|
101
|
+
index
|
|
102
|
+
})).sort((a, b) => {
|
|
103
|
+
const rankDiff = SEVERITY_RANK[b.note.severity] - SEVERITY_RANK[a.note.severity];
|
|
104
|
+
return rankDiff !== 0 ? rankDiff : a.index - b.index;
|
|
105
|
+
}).map((entry) => entry.note);
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Score the static-lint findings alone, on a `0..1` scale. Starts at `1.0`
|
|
109
|
+
* and deducts per finding by severity, clamped at `0`. Used as the report
|
|
110
|
+
* score when no judge model is available.
|
|
111
|
+
*/
|
|
112
|
+
function staticScore(notes) {
|
|
113
|
+
let score = 1;
|
|
114
|
+
for (const note of notes) if (note.severity === "error") score -= .4;
|
|
115
|
+
else if (note.severity === "warn") score -= .2;
|
|
116
|
+
else score -= .05;
|
|
117
|
+
return Math.max(0, Number(score.toFixed(4)));
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Run the LLM-as-judge pass over `text` using a judge agent built from
|
|
121
|
+
* `model`, REUSING the eval `judge` scorer so there is no second judging
|
|
122
|
+
* path. Returns the judge `score` (`0..1`) and a single derived note carrying
|
|
123
|
+
* its reason (when present). The judge prompt is the prompt-quality rubric;
|
|
124
|
+
* the "answer to grade" is the prompt body itself.
|
|
125
|
+
*
|
|
126
|
+
* @param text - The prompt body under evaluation.
|
|
127
|
+
* @param model - The model that powers the judge agent.
|
|
128
|
+
* @param buildJudgeAgent - Factory that wraps a model into a name-bearing judge agent.
|
|
129
|
+
*/
|
|
130
|
+
async function judgePrompt(text, model, buildJudgeAgent) {
|
|
131
|
+
const score = await judge({
|
|
132
|
+
agent: buildJudgeAgent(model),
|
|
133
|
+
rubric: PROMPT_JUDGE_RUBRIC
|
|
134
|
+
})({
|
|
135
|
+
case: {
|
|
136
|
+
name: "prompt-quality",
|
|
137
|
+
input: "Grade the system prompt below."
|
|
138
|
+
},
|
|
139
|
+
text,
|
|
140
|
+
result: { text },
|
|
141
|
+
output: void 0
|
|
142
|
+
});
|
|
143
|
+
const notes = [];
|
|
144
|
+
if (score.reason) notes.push({
|
|
145
|
+
severity: score.passed ? "info" : "warn",
|
|
146
|
+
message: `LLM-as-judge: ${score.reason}`
|
|
147
|
+
});
|
|
148
|
+
return {
|
|
149
|
+
score: score.score,
|
|
150
|
+
notes
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Assemble the final {@link PromptValidationReport} from the static-lint
|
|
155
|
+
* findings and (optionally) the judge findings. Notes are merged and sorted
|
|
156
|
+
* most-severe-first. The score is the static score alone when no judge ran,
|
|
157
|
+
* else the mean of the static score and the judge score.
|
|
158
|
+
*/
|
|
159
|
+
function buildValidationReport(staticNotes, judgeResult) {
|
|
160
|
+
const allNotes = judgeResult ? [...staticNotes, ...judgeResult.notes] : staticNotes;
|
|
161
|
+
const lintScore = staticScore(staticNotes);
|
|
162
|
+
return {
|
|
163
|
+
score: judgeResult ? Number(((lintScore + judgeResult.score) / 2).toFixed(4)) : lintScore,
|
|
164
|
+
notes: sortNotesBySeverity(allNotes)
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
//#endregion
|
|
169
|
+
export { PROMPT_JUDGE_RUBRIC, buildValidationReport, judgePrompt, staticLint };
|
|
170
|
+
//# sourceMappingURL=prompt-validate.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt-validate.mjs","names":[],"sources":["../../../../../../../@warlock.js/ai/src/prompt/prompt-validate.ts"],"sourcesContent":["import type { AgentContract } from \"../contracts/agent/agent.contract\";\nimport type { ModelContract } from \"../contracts/model.contract\";\nimport { judge } from \"../eval/judge-scorer\";\nimport type { PromptValidationNote, PromptValidationReport } from \"./prompt.type\";\n\n/**\n * Placeholder matcher — kept in lock-step with the matcher\n * `renderPlaceholders` uses (`src/system-prompt/render-placeholders.ts`) so the\n * lint sees the same `{{key}}` / `{{a.b}}` / `{{key|default}}` set the renderer\n * substitutes. Global so every occurrence is collected.\n */\nconst PLACEHOLDER_PATTERN = /\\{\\{\\s*([^{}]+?)\\s*\\}\\}/g;\n\n/** Lower bound below which a prompt is suspiciously terse. */\nconst MIN_REASONABLE_LENGTH = 12;\n\n/** Upper bound above which a prompt is likely bloated / unfocused. */\nconst MAX_REASONABLE_LENGTH = 8000;\n\n/**\n * Severity rank for most-severe-first ordering. Higher sorts earlier.\n */\nconst SEVERITY_RANK: Record<PromptValidationNote[\"severity\"], number> = {\n error: 2,\n warn: 1,\n info: 0,\n};\n\n/**\n * The fixed rubric the LLM-as-judge grades a prompt body against. Surfaced\n * here (not inline) so the static-lint pass and the judge pass document the\n * same quality dimensions.\n */\nexport const PROMPT_JUDGE_RUBRIC = [\n \"Grade this SYSTEM PROMPT on a 0..1 scale for overall quality:\",\n \"- Clarity: is the intent unambiguous and easy to follow?\",\n \"- Role definition: does it clearly state who/what the assistant is?\",\n \"- Output-format specificity: does it say how the answer should be shaped?\",\n \"- No conflicting instructions: are any directives contradictory?\",\n \"Score 1.0 only when all four hold; deduct for each weakness and explain why.\",\n].join(\"\\n\");\n\n/**\n * Heuristic role-line detector — a prompt that never says \"you are …\" /\n * \"act as …\" / \"your role is …\" typically lacks a persona. Case-insensitive.\n */\nconst ROLE_HINT_PATTERN = /\\b(you are|act as|your role is|you're a|you will act)\\b/i;\n\n/**\n * Run the cheap, model-free static lint over a prompt body. Flags:\n * - length out of the reasonable band (too terse / too bloated),\n * - any `{{placeholder}}` that survives (undeclared / unresolved at lint time),\n * - a missing role line.\n *\n * Pure and synchronous — used standalone (no judge model) and merged with the\n * judge findings when a model is available.\n *\n * @param text - The prompt body to lint.\n */\nexport function staticLint(text: string): PromptValidationNote[] {\n const notes: PromptValidationNote[] = [];\n const trimmed = text.trim();\n\n if (trimmed.length < MIN_REASONABLE_LENGTH) {\n notes.push({\n severity: \"warn\",\n message: `Prompt is very short (${trimmed.length} chars) — it may be too vague to steer the model.`,\n suggestion: \"Add an explicit role and at least one concrete instruction.\",\n });\n }\n\n if (trimmed.length > MAX_REASONABLE_LENGTH) {\n notes.push({\n severity: \"warn\",\n message: `Prompt is very long (${trimmed.length} chars) — long prompts dilute focus and inflate cost.`,\n suggestion: \"Split into a tighter persona plus a few focused instructions.\",\n });\n }\n\n const placeholders = collectPlaceholders(text);\n\n for (const placeholder of placeholders) {\n notes.push({\n severity: \"info\",\n message: `Unresolved placeholder \"{{${placeholder}}}\" — confirm it is supplied at resolve time or give it a default (\"{{${placeholder}|...}}\").`,\n });\n }\n\n if (!ROLE_HINT_PATTERN.test(trimmed)) {\n notes.push({\n severity: \"warn\",\n message: \"No role line found — the prompt never states who the assistant is.\",\n suggestion: 'Open with a role, e.g. \"You are a senior support engineer for …\".',\n });\n }\n\n return notes;\n}\n\n/**\n * Collect every distinct placeholder PATH (the part before any `|default`)\n * from a template, in first-seen order. Matches `renderPlaceholders`' own\n * parsing so the lint never disagrees with the renderer.\n */\nfunction collectPlaceholders(template: string): string[] {\n const found: string[] = [];\n const seen = new Set<string>();\n\n for (const match of template.matchAll(PLACEHOLDER_PATTERN)) {\n const path = match[1].split(\"|\")[0].trim();\n\n if (path.length > 0 && !seen.has(path)) {\n seen.add(path);\n found.push(path);\n }\n }\n\n return found;\n}\n\n/**\n * Stable, most-severe-first ordering: `error` before `warn` before `info`,\n * preserving original order within a severity. Returns a fresh array.\n */\nexport function sortNotesBySeverity(\n notes: PromptValidationNote[],\n): PromptValidationNote[] {\n return notes\n .map((note, index) => ({ note, index }))\n .sort((a, b) => {\n const rankDiff = SEVERITY_RANK[b.note.severity] - SEVERITY_RANK[a.note.severity];\n\n return rankDiff !== 0 ? rankDiff : a.index - b.index;\n })\n .map(entry => entry.note);\n}\n\n/**\n * Score the static-lint findings alone, on a `0..1` scale. Starts at `1.0`\n * and deducts per finding by severity, clamped at `0`. Used as the report\n * score when no judge model is available.\n */\nexport function staticScore(notes: PromptValidationNote[]): number {\n let score = 1;\n\n for (const note of notes) {\n if (note.severity === \"error\") {\n score -= 0.4;\n } else if (note.severity === \"warn\") {\n score -= 0.2;\n } else {\n score -= 0.05;\n }\n }\n\n return Math.max(0, Number(score.toFixed(4)));\n}\n\n/**\n * Run the LLM-as-judge pass over `text` using a judge agent built from\n * `model`, REUSING the eval `judge` scorer so there is no second judging\n * path. Returns the judge `score` (`0..1`) and a single derived note carrying\n * its reason (when present). The judge prompt is the prompt-quality rubric;\n * the \"answer to grade\" is the prompt body itself.\n *\n * @param text - The prompt body under evaluation.\n * @param model - The model that powers the judge agent.\n * @param buildJudgeAgent - Factory that wraps a model into a name-bearing judge agent.\n */\nexport async function judgePrompt(\n text: string,\n model: ModelContract,\n buildJudgeAgent: (model: ModelContract) => AgentContract<unknown>,\n): Promise<{ score: number; notes: PromptValidationNote[] }> {\n const judgeAgent = buildJudgeAgent(model);\n const scorer = judge({ agent: judgeAgent, rubric: PROMPT_JUDGE_RUBRIC });\n\n const score = await scorer({\n // The judge scorer only reads `case.input` / `case.expected` / `text` /\n // `output` from the context. We feed the rubric question via `input` and\n // the prompt body as the answer to grade via `text`.\n case: { name: \"prompt-quality\", input: \"Grade the system prompt below.\" },\n text,\n // `result` is unused by the judge scorer's prompt builder; a minimal\n // stand-in keeps the structural contract satisfied without a real run.\n result: { text } as never,\n output: undefined,\n });\n\n const notes: PromptValidationNote[] = [];\n\n if (score.reason) {\n notes.push({\n severity: score.passed ? \"info\" : \"warn\",\n message: `LLM-as-judge: ${score.reason}`,\n });\n }\n\n return { score: score.score, notes };\n}\n\n/**\n * Assemble the final {@link PromptValidationReport} from the static-lint\n * findings and (optionally) the judge findings. Notes are merged and sorted\n * most-severe-first. The score is the static score alone when no judge ran,\n * else the mean of the static score and the judge score.\n */\nexport function buildValidationReport(\n staticNotes: PromptValidationNote[],\n judgeResult?: { score: number; notes: PromptValidationNote[] },\n): PromptValidationReport {\n const allNotes = judgeResult\n ? [...staticNotes, ...judgeResult.notes]\n : staticNotes;\n\n const lintScore = staticScore(staticNotes);\n\n const score = judgeResult\n ? Number(((lintScore + judgeResult.score) / 2).toFixed(4))\n : lintScore;\n\n return {\n score,\n notes: sortNotesBySeverity(allNotes),\n };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { SystemPromptContract } from "../contracts/system-prompt.contract.mjs";
|
|
2
|
+
import { PromptRegistryContract, PromptRegistryOptions } from "./prompt.type.mjs";
|
|
3
|
+
|
|
4
|
+
//#region ../@warlock.js/ai/src/prompt/prompt.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Create a versioned, typed prompt registry — a thin facade over the unified
|
|
7
|
+
* `ai.prompts` manager.
|
|
8
|
+
*
|
|
9
|
+
* **Role.** Public factory for {@link PromptRegistryContract}. Keeps
|
|
10
|
+
* user-facing code free of `new` and consistent with `ai.memory`,
|
|
11
|
+
* `ai.orchestrator`, `ai.batch` (all return instances). Each call returns a
|
|
12
|
+
* fresh, isolated registry backed by its own unified manager, so parallel test
|
|
13
|
+
* suites and multi-tenant apps never share mutable global prompt state.
|
|
14
|
+
*
|
|
15
|
+
* @param options - Seed entries, an optional default judge model, and an
|
|
16
|
+
* optional Langfuse sync.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* const prompts = prompt({
|
|
20
|
+
* prompts: [
|
|
21
|
+
* {
|
|
22
|
+
* name: "support-agent",
|
|
23
|
+
* versions: [
|
|
24
|
+
* { version: "1", template: "You are support for {{product}}. Reply in {{language|English}}." },
|
|
25
|
+
* { version: "2", template: "You are senior support for {{product}}.", required: ["product"] },
|
|
26
|
+
* ],
|
|
27
|
+
* },
|
|
28
|
+
* ],
|
|
29
|
+
* });
|
|
30
|
+
*
|
|
31
|
+
* const resolved = prompts.resolve("support-agent", { placeholders: { product: "Warlock" } });
|
|
32
|
+
* const agent = ai.agent({ model, systemPrompt: resolved.toSystemPrompt() });
|
|
33
|
+
* // resolved.version === "2"; a missing `product` would throw PromptValidationError.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* // Resolve a globally-registered prompt by name from `ai.prompts`.
|
|
37
|
+
* ai.systemPrompt("You are support.", { name: "support" });
|
|
38
|
+
* const sp = ai.prompt("support"); // → the registered SystemPromptContract
|
|
39
|
+
*/
|
|
40
|
+
declare function promptFactory(name: string, versionOrTag?: string): SystemPromptContract;
|
|
41
|
+
declare function promptFactory(options?: PromptRegistryOptions): PromptRegistryContract;
|
|
42
|
+
/**
|
|
43
|
+
* Create a versioned prompt registry, OR resolve a globally-registered prompt
|
|
44
|
+
* by name from `ai.prompts`.
|
|
45
|
+
*
|
|
46
|
+
* - `prompt(options?)` → a fresh, isolated {@link PromptRegistryContract}.
|
|
47
|
+
* - `prompt(name, versionOrTag?)` → the `SystemPromptContract` registered under
|
|
48
|
+
* `name` in the process-wide `ai.prompts` manager (latest version by default,
|
|
49
|
+
* or a specific version / pinned tag).
|
|
50
|
+
*/
|
|
51
|
+
declare const prompt: typeof promptFactory;
|
|
52
|
+
//#endregion
|
|
53
|
+
export { prompt };
|
|
54
|
+
//# sourceMappingURL=prompt.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt.d.mts","names":[],"sources":["../../../../../../../@warlock.js/ai/src/prompt/prompt.ts"],"mappings":";;;;;;AA+BuB;;;;;;;;AA+UA;AAAA;;;;;;;;AACwD;AAyB/E;;;;AAAyD;;;;;;;;;;;iBA7BhD,aAAA,CACP,IAAA,UACA,YAAA,YACC,oBAAoB;AAAA,iBACd,aAAA,CAAc,OAAA,GAAU,qBAAA,GAAwB,sBAAsB;;;;;;;;;;cAyBlE,MAAA,SAAe,aAA6B"}
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import { agent } from "../agent/agent.mjs";
|
|
2
|
+
import { renderPlaceholders } from "../system-prompt/render-placeholders.mjs";
|
|
3
|
+
import { Instruction } from "../system-prompt/instruction.mjs";
|
|
4
|
+
import { SystemPrompt } from "../system-prompt/system-prompt.mjs";
|
|
5
|
+
import { buildValidationReport, judgePrompt, staticLint } from "./prompt-validate.mjs";
|
|
6
|
+
import { defaultPromptsManager, prompts } from "../prompts/prompts-manager.mjs";
|
|
7
|
+
import { PromptNotFoundError, PromptValidationError } from "./errors.mjs";
|
|
8
|
+
import { syncLangfusePrompts, warmLangfuse } from "./prompt-langfuse-sync.mjs";
|
|
9
|
+
|
|
10
|
+
//#region ../@warlock.js/ai/src/prompt/prompt.ts
|
|
11
|
+
/**
|
|
12
|
+
* Build the one-shot judge agent the `validate()` LLM-as-judge pass runs.
|
|
13
|
+
* Name-bearing (the eval `judge` scorer requires a usable agent) and seeded
|
|
14
|
+
* with a strict-JSON instruction so its verdict parses even without an output
|
|
15
|
+
* schema. Kept module-private so the registry's only model dependency is the
|
|
16
|
+
* `agent()` factory.
|
|
17
|
+
*/
|
|
18
|
+
function buildJudgeAgent(model) {
|
|
19
|
+
return agent({
|
|
20
|
+
name: "prompt-quality-judge",
|
|
21
|
+
model,
|
|
22
|
+
systemPrompt: "You are a strict prompt-quality grader. Respond with JSON only: { \"score\": <0..1>, \"passed\": <true|false>, \"reason\": \"<short explanation>\" }."
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Build the `SystemPromptContract` a single {@link PromptVersion} maps to: its
|
|
27
|
+
* `template` becomes one instruction block, and its `required` keys ride along
|
|
28
|
+
* as `meta.required` so the unified manager (and `validate`) can see them.
|
|
29
|
+
*
|
|
30
|
+
* Deliberately ANONYMOUS (no `meta.name`) so the `SystemPrompt` constructor
|
|
31
|
+
* never auto-registers this version into the process-wide `ai.prompts` default
|
|
32
|
+
* manager — each `prompt()` registry owns its OWN isolated
|
|
33
|
+
* {@link PromptsManagerContract}, the single storage shape behind this facade.
|
|
34
|
+
*/
|
|
35
|
+
function versionToContract(version) {
|
|
36
|
+
return new SystemPrompt([new Instruction(version.template)], { ...version.required ? { required: version.required } : {} });
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Legacy `PromptRegistryContract` — now a THIN FACADE over the unified
|
|
40
|
+
* {@link PromptsManagerContract} (`ai.prompts`).
|
|
41
|
+
*
|
|
42
|
+
* **Role.** The store behind `ai.prompt(...)`. Historically it held a private
|
|
43
|
+
* `Map<string, PromptVersion[]>`; it now delegates ALL storage to a private,
|
|
44
|
+
* per-instance {@link PromptsManagerContract}, so there is exactly ONE storage
|
|
45
|
+
* shape across the whole prompt surface: a `SystemPromptContract` keyed by
|
|
46
|
+
* `name@version`. A version's raw `template` string maps to a single
|
|
47
|
+
* instruction block and its `required` keys to `meta.required`.
|
|
48
|
+
*
|
|
49
|
+
* **Responsibility.**
|
|
50
|
+
* - Owns: the legacy method surface (`register` / `add` / `versions` /
|
|
51
|
+
* `resolve` / `validate` / `sync`) and the back-compat behaviors — duplicate
|
|
52
|
+
* version rejection, required-key assertion on `resolve()`, the
|
|
53
|
+
* `{ score, notes }` validation report shape, and the optional Langfuse sync.
|
|
54
|
+
* - Does NOT own: the actual storage (delegated to the internal manager),
|
|
55
|
+
* placeholder rendering (delegated to `renderPlaceholders`), or the unified
|
|
56
|
+
* validation primitives (delegated to `prompt-validate`).
|
|
57
|
+
*
|
|
58
|
+
* Each `prompt(options)` call builds its own isolated manager — so parallel
|
|
59
|
+
* test suites and multi-tenant apps never share mutable global prompt state,
|
|
60
|
+
* exactly as before the unification.
|
|
61
|
+
*
|
|
62
|
+
* Users construct via the `prompt()` factory — `new PromptRegistry()` is not
|
|
63
|
+
* the public API.
|
|
64
|
+
*/
|
|
65
|
+
var PromptRegistry = class {
|
|
66
|
+
constructor(options = {}) {
|
|
67
|
+
this.options = options;
|
|
68
|
+
this.versionMeta = /* @__PURE__ */ new Map();
|
|
69
|
+
this.manager = prompts();
|
|
70
|
+
for (const entry of options.prompts ?? []) this.register(entry);
|
|
71
|
+
if (options.langfuse) warmLangfuse(options.langfuse);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Register a whole entry. Merges onto an existing name's history; a
|
|
75
|
+
* duplicate version label throws {@link PromptValidationError}.
|
|
76
|
+
*/
|
|
77
|
+
register(entry) {
|
|
78
|
+
for (const version of entry.versions) this.add(entry.name, version);
|
|
79
|
+
if (!this.versionMeta.has(entry.name)) this.versionMeta.set(entry.name, []);
|
|
80
|
+
return this;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Add a new version to a name (creating it when absent). A duplicate
|
|
84
|
+
* version label throws {@link PromptValidationError} — never a silent
|
|
85
|
+
* overwrite.
|
|
86
|
+
*/
|
|
87
|
+
add(name, version) {
|
|
88
|
+
const mirror = this.versionMeta.get(name) ?? [];
|
|
89
|
+
if (mirror.some((existing) => existing.version === version.version)) throw new PromptValidationError(`Prompt "${name}" already has a version labeled "${version.version}".`, { context: {
|
|
90
|
+
name,
|
|
91
|
+
version: version.version
|
|
92
|
+
} });
|
|
93
|
+
this.manager.register(versionToContract(version), {
|
|
94
|
+
name,
|
|
95
|
+
version: version.version
|
|
96
|
+
});
|
|
97
|
+
this.versionMeta.set(name, [...mirror, version]);
|
|
98
|
+
return this;
|
|
99
|
+
}
|
|
100
|
+
/** Whether a name is registered. */
|
|
101
|
+
has(name) {
|
|
102
|
+
return this.versionMeta.has(name);
|
|
103
|
+
}
|
|
104
|
+
/** Every registered prompt name, in registration order. */
|
|
105
|
+
list() {
|
|
106
|
+
return [...this.versionMeta.keys()];
|
|
107
|
+
}
|
|
108
|
+
/** Versions registered for a name, latest last. Throws on an unknown name. */
|
|
109
|
+
versions(name) {
|
|
110
|
+
const mirror = this.versionMeta.get(name);
|
|
111
|
+
if (!mirror) throw new PromptNotFoundError(name);
|
|
112
|
+
return [...mirror];
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Resolve + render. Picks the requested or latest version, validates the
|
|
116
|
+
* version's `required` keys against the merged placeholders, then renders by
|
|
117
|
+
* delegating to the shared `renderPlaceholders` over the contract's text.
|
|
118
|
+
*/
|
|
119
|
+
resolve(name, options = {}) {
|
|
120
|
+
const picked = this.pickVersion(name, options.version);
|
|
121
|
+
const placeholders = options.placeholders ?? {};
|
|
122
|
+
this.assertRequired(name, picked, placeholders);
|
|
123
|
+
const text = renderPlaceholders(this.manager.get(name, picked.version).blocks[0]?.text ?? picked.template, placeholders);
|
|
124
|
+
return {
|
|
125
|
+
name,
|
|
126
|
+
version: picked.version,
|
|
127
|
+
text,
|
|
128
|
+
toSystemPrompt: () => new SystemPrompt([new Instruction(text)])
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Quality-check a raw prompt body or a registered prompt (by name). Backed by
|
|
133
|
+
* the unified deterministic validate primitives plus the LLM-as-judge pass,
|
|
134
|
+
* but returns the legacy `{ score, notes }` report shape so existing callers
|
|
135
|
+
* keep working.
|
|
136
|
+
*
|
|
137
|
+
* Always runs the static lint; runs the LLM-as-judge pass too when a model is
|
|
138
|
+
* resolvable. Never throws when no judge model is available.
|
|
139
|
+
*/
|
|
140
|
+
async validate(textOrName, options = {}) {
|
|
141
|
+
const text = this.resolveValidationText(textOrName, options.version);
|
|
142
|
+
const staticNotes = staticLint(text);
|
|
143
|
+
const model = options.model ?? this.options.judgeModel;
|
|
144
|
+
if (!model) return buildValidationReport(staticNotes);
|
|
145
|
+
return buildValidationReport(staticNotes, await judgePrompt(text, model, buildJudgeAgent));
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Synchronize named prompts with Langfuse-prompts. No-op (resolves) when no
|
|
149
|
+
* `langfuse` option was configured. The resolved (rendered) body + the
|
|
150
|
+
* `name@version` label are what is pushed/pulled.
|
|
151
|
+
*/
|
|
152
|
+
async sync() {
|
|
153
|
+
if (!this.options.langfuse) return;
|
|
154
|
+
await syncLangfusePrompts(this.options.langfuse, this.list(), this.snapshotEntries(), (entry) => this.register(entry));
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Pick the requested (or latest) {@link PromptVersion} for a name from the
|
|
158
|
+
* mirror, throwing {@link PromptNotFoundError} on an unknown name or version.
|
|
159
|
+
*/
|
|
160
|
+
pickVersion(name, version) {
|
|
161
|
+
const mirror = this.versionMeta.get(name);
|
|
162
|
+
if (!mirror || mirror.length === 0) throw new PromptNotFoundError(name);
|
|
163
|
+
const picked = version ? mirror.find((candidate) => candidate.version === version) : mirror[mirror.length - 1];
|
|
164
|
+
if (!picked) throw new PromptNotFoundError(name, { context: {
|
|
165
|
+
name,
|
|
166
|
+
version
|
|
167
|
+
} });
|
|
168
|
+
return picked;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Resolve the text `validate()` should grade: a registered name yields its
|
|
172
|
+
* picked version's raw `template`; anything else is treated as the raw body.
|
|
173
|
+
*/
|
|
174
|
+
resolveValidationText(textOrName, version) {
|
|
175
|
+
const mirror = this.versionMeta.get(textOrName);
|
|
176
|
+
if (!mirror || mirror.length === 0) return textOrName;
|
|
177
|
+
const picked = version ? mirror.find((candidate) => candidate.version === version) : mirror[mirror.length - 1];
|
|
178
|
+
return picked ? picked.template : textOrName;
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Throw {@link PromptValidationError} listing every `required` key absent
|
|
182
|
+
* from the merged placeholders. A no-op when the version declares none.
|
|
183
|
+
*/
|
|
184
|
+
assertRequired(name, version, placeholders) {
|
|
185
|
+
if (!version.required || version.required.length === 0) return;
|
|
186
|
+
const missing = version.required.filter((key) => placeholders[key] === void 0 || placeholders[key] === null || placeholders[key] === "");
|
|
187
|
+
if (missing.length > 0) throw new PromptValidationError(`Prompt "${name}" version "${version.version}" is missing required placeholder${missing.length > 1 ? "s" : ""}: ${missing.join(", ")}.`, { context: {
|
|
188
|
+
name,
|
|
189
|
+
version: version.version,
|
|
190
|
+
missing
|
|
191
|
+
} });
|
|
192
|
+
}
|
|
193
|
+
/** Snapshot the catalog as `PromptEntry[]` (for the Langfuse push path). */
|
|
194
|
+
snapshotEntries() {
|
|
195
|
+
return [...this.versionMeta.entries()].map(([name, versions]) => ({
|
|
196
|
+
name,
|
|
197
|
+
versions: [...versions]
|
|
198
|
+
}));
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
function promptFactory(first, versionOrTag) {
|
|
202
|
+
if (typeof first === "string") return defaultPromptsManager().get(first, versionOrTag);
|
|
203
|
+
return new PromptRegistry(first);
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Create a versioned prompt registry, OR resolve a globally-registered prompt
|
|
207
|
+
* by name from `ai.prompts`.
|
|
208
|
+
*
|
|
209
|
+
* - `prompt(options?)` → a fresh, isolated {@link PromptRegistryContract}.
|
|
210
|
+
* - `prompt(name, versionOrTag?)` → the `SystemPromptContract` registered under
|
|
211
|
+
* `name` in the process-wide `ai.prompts` manager (latest version by default,
|
|
212
|
+
* or a specific version / pinned tag).
|
|
213
|
+
*/
|
|
214
|
+
const prompt = promptFactory;
|
|
215
|
+
|
|
216
|
+
//#endregion
|
|
217
|
+
export { prompt };
|
|
218
|
+
//# sourceMappingURL=prompt.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt.mjs","names":["createPromptsManager"],"sources":["../../../../../../../@warlock.js/ai/src/prompt/prompt.ts"],"sourcesContent":["import type { SystemPromptContract } from \"../contracts/system-prompt.contract\";\nimport {\n defaultPromptsManager,\n prompts as createPromptsManager,\n} from \"../prompts/prompts-manager\";\nimport type { PromptsManagerContract } from \"../prompts/prompts-manager.contract\";\nimport { Instruction } from \"../system-prompt/instruction\";\nimport { renderPlaceholders } from \"../system-prompt/render-placeholders\";\nimport { SystemPrompt } from \"../system-prompt/system-prompt\";\nimport { PromptNotFoundError, PromptValidationError } from \"./errors\";\nimport {\n syncLangfusePrompts,\n warmLangfuse,\n} from \"./prompt-langfuse-sync\";\nimport {\n buildValidationReport,\n judgePrompt,\n staticLint,\n} from \"./prompt-validate\";\nimport { agent } from \"../agent/agent\";\nimport type { AgentContract } from \"../contracts/agent/agent.contract\";\nimport type { ModelContract } from \"../contracts/model.contract\";\nimport type {\n PromptEntry,\n PromptRegistryContract,\n PromptRegistryOptions,\n PromptResolveOptions,\n PromptValidateOptions,\n PromptValidationReport,\n PromptVersion,\n ResolvedPrompt,\n} from \"./prompt.type\";\n\n/**\n * Build the one-shot judge agent the `validate()` LLM-as-judge pass runs.\n * Name-bearing (the eval `judge` scorer requires a usable agent) and seeded\n * with a strict-JSON instruction so its verdict parses even without an output\n * schema. Kept module-private so the registry's only model dependency is the\n * `agent()` factory.\n */\nfunction buildJudgeAgent(model: ModelContract): AgentContract<unknown> {\n return agent({\n name: \"prompt-quality-judge\",\n model,\n systemPrompt:\n \"You are a strict prompt-quality grader. Respond with JSON only: \" +\n '{ \"score\": <0..1>, \"passed\": <true|false>, \"reason\": \"<short explanation>\" }.',\n });\n}\n\n/**\n * Build the `SystemPromptContract` a single {@link PromptVersion} maps to: its\n * `template` becomes one instruction block, and its `required` keys ride along\n * as `meta.required` so the unified manager (and `validate`) can see them.\n *\n * Deliberately ANONYMOUS (no `meta.name`) so the `SystemPrompt` constructor\n * never auto-registers this version into the process-wide `ai.prompts` default\n * manager — each `prompt()` registry owns its OWN isolated\n * {@link PromptsManagerContract}, the single storage shape behind this facade.\n */\nfunction versionToContract(version: PromptVersion): SystemPromptContract {\n return new SystemPrompt([new Instruction(version.template)], {\n ...(version.required ? { required: version.required } : {}),\n });\n}\n\n/**\n * Legacy `PromptRegistryContract` — now a THIN FACADE over the unified\n * {@link PromptsManagerContract} (`ai.prompts`).\n *\n * **Role.** The store behind `ai.prompt(...)`. Historically it held a private\n * `Map<string, PromptVersion[]>`; it now delegates ALL storage to a private,\n * per-instance {@link PromptsManagerContract}, so there is exactly ONE storage\n * shape across the whole prompt surface: a `SystemPromptContract` keyed by\n * `name@version`. A version's raw `template` string maps to a single\n * instruction block and its `required` keys to `meta.required`.\n *\n * **Responsibility.**\n * - Owns: the legacy method surface (`register` / `add` / `versions` /\n * `resolve` / `validate` / `sync`) and the back-compat behaviors — duplicate\n * version rejection, required-key assertion on `resolve()`, the\n * `{ score, notes }` validation report shape, and the optional Langfuse sync.\n * - Does NOT own: the actual storage (delegated to the internal manager),\n * placeholder rendering (delegated to `renderPlaceholders`), or the unified\n * validation primitives (delegated to `prompt-validate`).\n *\n * Each `prompt(options)` call builds its own isolated manager — so parallel\n * test suites and multi-tenant apps never share mutable global prompt state,\n * exactly as before the unification.\n *\n * Users construct via the `prompt()` factory — `new PromptRegistry()` is not\n * the public API.\n */\nclass PromptRegistry implements PromptRegistryContract {\n /** The single backing store — one isolated unified manager per registry. */\n private readonly manager: PromptsManagerContract;\n\n /** Per-name version metadata mirror, kept so `versions()` returns the rich\n * {@link PromptVersion} shape (template + required + meta) the legacy API\n * promised — the manager itself only stores the flattened contract. */\n private readonly versionMeta = new Map<string, PromptVersion[]>();\n\n public constructor(private readonly options: PromptRegistryOptions = {}) {\n this.manager = createPromptsManager();\n\n for (const entry of options.prompts ?? []) {\n this.register(entry);\n }\n\n if (options.langfuse) {\n warmLangfuse(options.langfuse);\n }\n }\n\n /**\n * Register a whole entry. Merges onto an existing name's history; a\n * duplicate version label throws {@link PromptValidationError}.\n */\n public register(entry: PromptEntry): PromptRegistryContract {\n for (const version of entry.versions) {\n this.add(entry.name, version);\n }\n\n // An entry with an empty version list still creates the name so `has`\n // / `list` reflect it.\n if (!this.versionMeta.has(entry.name)) {\n this.versionMeta.set(entry.name, []);\n }\n\n return this;\n }\n\n /**\n * Add a new version to a name (creating it when absent). A duplicate\n * version label throws {@link PromptValidationError} — never a silent\n * overwrite.\n */\n public add(name: string, version: PromptVersion): PromptRegistryContract {\n const mirror = this.versionMeta.get(name) ?? [];\n\n if (mirror.some(existing => existing.version === version.version)) {\n throw new PromptValidationError(\n `Prompt \"${name}\" already has a version labeled \"${version.version}\".`,\n { context: { name, version: version.version } },\n );\n }\n\n this.manager.register(versionToContract(version), {\n name,\n version: version.version,\n });\n\n this.versionMeta.set(name, [...mirror, version]);\n\n return this;\n }\n\n /** Whether a name is registered. */\n public has(name: string): boolean {\n return this.versionMeta.has(name);\n }\n\n /** Every registered prompt name, in registration order. */\n public list(): string[] {\n return [...this.versionMeta.keys()];\n }\n\n /** Versions registered for a name, latest last. Throws on an unknown name. */\n public versions(name: string): PromptVersion[] {\n const mirror = this.versionMeta.get(name);\n\n if (!mirror) {\n throw new PromptNotFoundError(name);\n }\n\n return [...mirror];\n }\n\n /**\n * Resolve + render. Picks the requested or latest version, validates the\n * version's `required` keys against the merged placeholders, then renders by\n * delegating to the shared `renderPlaceholders` over the contract's text.\n */\n public resolve(name: string, options: PromptResolveOptions = {}): ResolvedPrompt {\n const picked = this.pickVersion(name, options.version);\n const placeholders = options.placeholders ?? {};\n\n this.assertRequired(name, picked, placeholders);\n\n // Render the RAW template (placeholders intact) against the merged values —\n // resolving the contract first would bake inline `{{key|default}}` defaults\n // in and shadow an explicitly-supplied value. The stored block text is the\n // single source of the un-rendered template.\n const contract = this.manager.get(name, picked.version);\n const template = contract.blocks[0]?.text ?? picked.template;\n const text = renderPlaceholders(template, placeholders);\n\n return {\n name,\n version: picked.version,\n text,\n toSystemPrompt: () => new SystemPrompt([new Instruction(text)]),\n };\n }\n\n /**\n * Quality-check a raw prompt body or a registered prompt (by name). Backed by\n * the unified deterministic validate primitives plus the LLM-as-judge pass,\n * but returns the legacy `{ score, notes }` report shape so existing callers\n * keep working.\n *\n * Always runs the static lint; runs the LLM-as-judge pass too when a model is\n * resolvable. Never throws when no judge model is available.\n */\n public async validate(\n textOrName: string,\n options: PromptValidateOptions = {},\n ): Promise<PromptValidationReport> {\n const text = this.resolveValidationText(textOrName, options.version);\n const staticNotes = staticLint(text);\n\n const model = options.model ?? this.options.judgeModel;\n\n if (!model) {\n return buildValidationReport(staticNotes);\n }\n\n const judgeResult = await judgePrompt(text, model, buildJudgeAgent);\n\n return buildValidationReport(staticNotes, judgeResult);\n }\n\n /**\n * Synchronize named prompts with Langfuse-prompts. No-op (resolves) when no\n * `langfuse` option was configured. The resolved (rendered) body + the\n * `name@version` label are what is pushed/pulled.\n */\n public async sync(): Promise<void> {\n if (!this.options.langfuse) {\n return;\n }\n\n await syncLangfusePrompts(\n this.options.langfuse,\n this.list(),\n this.snapshotEntries(),\n entry => this.register(entry),\n );\n }\n\n /**\n * Pick the requested (or latest) {@link PromptVersion} for a name from the\n * mirror, throwing {@link PromptNotFoundError} on an unknown name or version.\n */\n private pickVersion(name: string, version?: string): PromptVersion {\n const mirror = this.versionMeta.get(name);\n\n if (!mirror || mirror.length === 0) {\n throw new PromptNotFoundError(name);\n }\n\n const picked = version\n ? mirror.find(candidate => candidate.version === version)\n : mirror[mirror.length - 1];\n\n if (!picked) {\n throw new PromptNotFoundError(name, {\n context: { name, version },\n });\n }\n\n return picked;\n }\n\n /**\n * Resolve the text `validate()` should grade: a registered name yields its\n * picked version's raw `template`; anything else is treated as the raw body.\n */\n private resolveValidationText(textOrName: string, version?: string): string {\n const mirror = this.versionMeta.get(textOrName);\n\n if (!mirror || mirror.length === 0) {\n return textOrName;\n }\n\n const picked = version\n ? mirror.find(candidate => candidate.version === version)\n : mirror[mirror.length - 1];\n\n return picked ? picked.template : textOrName;\n }\n\n /**\n * Throw {@link PromptValidationError} listing every `required` key absent\n * from the merged placeholders. A no-op when the version declares none.\n */\n private assertRequired(\n name: string,\n version: PromptVersion,\n placeholders: Record<string, unknown>,\n ): void {\n if (!version.required || version.required.length === 0) {\n return;\n }\n\n const missing = version.required.filter(\n key => placeholders[key] === undefined || placeholders[key] === null || placeholders[key] === \"\",\n );\n\n if (missing.length > 0) {\n throw new PromptValidationError(\n `Prompt \"${name}\" version \"${version.version}\" is missing required placeholder${\n missing.length > 1 ? \"s\" : \"\"\n }: ${missing.join(\", \")}.`,\n { context: { name, version: version.version, missing } },\n );\n }\n }\n\n /** Snapshot the catalog as `PromptEntry[]` (for the Langfuse push path). */\n private snapshotEntries(): PromptEntry[] {\n return [...this.versionMeta.entries()].map(([name, versions]) => ({\n name,\n versions: [...versions],\n }));\n }\n}\n\n/**\n * Create a versioned, typed prompt registry — a thin facade over the unified\n * `ai.prompts` manager.\n *\n * **Role.** Public factory for {@link PromptRegistryContract}. Keeps\n * user-facing code free of `new` and consistent with `ai.memory`,\n * `ai.orchestrator`, `ai.batch` (all return instances). Each call returns a\n * fresh, isolated registry backed by its own unified manager, so parallel test\n * suites and multi-tenant apps never share mutable global prompt state.\n *\n * @param options - Seed entries, an optional default judge model, and an\n * optional Langfuse sync.\n *\n * @example\n * const prompts = prompt({\n * prompts: [\n * {\n * name: \"support-agent\",\n * versions: [\n * { version: \"1\", template: \"You are support for {{product}}. Reply in {{language|English}}.\" },\n * { version: \"2\", template: \"You are senior support for {{product}}.\", required: [\"product\"] },\n * ],\n * },\n * ],\n * });\n *\n * const resolved = prompts.resolve(\"support-agent\", { placeholders: { product: \"Warlock\" } });\n * const agent = ai.agent({ model, systemPrompt: resolved.toSystemPrompt() });\n * // resolved.version === \"2\"; a missing `product` would throw PromptValidationError.\n *\n * @example\n * // Resolve a globally-registered prompt by name from `ai.prompts`.\n * ai.systemPrompt(\"You are support.\", { name: \"support\" });\n * const sp = ai.prompt(\"support\"); // → the registered SystemPromptContract\n */\nfunction promptFactory(\n name: string,\n versionOrTag?: string,\n): SystemPromptContract;\nfunction promptFactory(options?: PromptRegistryOptions): PromptRegistryContract;\nfunction promptFactory(\n first?: string | PromptRegistryOptions,\n versionOrTag?: string,\n): SystemPromptContract | PromptRegistryContract {\n // String form: resolve a globally-registered prompt from the process-wide\n // `ai.prompts` manager (the single unified registry). This is the thin\n // facade's read path onto the shared store.\n if (typeof first === \"string\") {\n return defaultPromptsManager().get(first, versionOrTag);\n }\n\n // Options form: build an isolated registry backed by its own unified manager.\n return new PromptRegistry(first);\n}\n\n/**\n * Create a versioned prompt registry, OR resolve a globally-registered prompt\n * by name from `ai.prompts`.\n *\n * - `prompt(options?)` → a fresh, isolated {@link PromptRegistryContract}.\n * - `prompt(name, versionOrTag?)` → the `SystemPromptContract` registered under\n * `name` in the process-wide `ai.prompts` manager (latest version by default,\n * or a specific version / pinned tag).\n */\nexport const prompt: typeof promptFactory = promptFactory;\n"],"mappings":"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"}
|