@warlock.js/ai 4.4.0 → 4.6.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 +63 -52
- package/cjs/index.cjs +240 -14147
- package/cjs/src-Bmajk4Qg.cjs +30 -0
- package/cjs/src-OZyDYHxm.cjs +25089 -0
- package/cjs/src-OZyDYHxm.cjs.map +1 -0
- package/esm/agent/agent-config.type.d.mts +119 -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 +328 -36
- 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/agent/signature.mjs +57 -0
- package/esm/agent/signature.mjs.map +1 -0
- package/esm/agent/snapshot.mjs +101 -0
- package/esm/agent/snapshot.mjs.map +1 -0
- package/esm/ai-openai/src/embedder.mjs +4 -0
- package/esm/ai-openai/src/image.mjs +5 -0
- package/esm/ai-openai/src/index.mjs +7 -0
- package/esm/ai-openai/src/model.mjs +5 -0
- package/esm/ai-openai/src/sdk.mjs +9 -0
- package/esm/ai-openai/src/speech.mjs +5 -0
- package/esm/ai-openai/src/transcription.mjs +6 -0
- package/esm/ai-openai/src/utils/index.mjs +5 -0
- package/esm/ai-openai/src/utils/to-openai-messages.mjs +3 -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 +164 -53
- package/esm/ai.d.mts.map +1 -1
- package/esm/ai.mjs +79 -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 +33 -5
- package/esm/contracts/agent/agent-options.type.d.mts.map +1 -1
- package/esm/contracts/agent/agent-snapshot.type.d.mts +90 -0
- package/esm/contracts/agent/agent-snapshot.type.d.mts.map +1 -0
- package/esm/contracts/agent/agent.contract.d.mts +29 -1
- package/esm/contracts/agent/agent.contract.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/agent/index.d.mts +2 -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/image-model.contract.d.mts +156 -0
- package/esm/contracts/image-model.contract.d.mts.map +1 -0
- package/esm/contracts/index.d.mts +13 -6
- 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 +3 -2
- package/esm/contracts/planner/planner-config.type.d.mts +61 -0
- package/esm/contracts/planner/planner-config.type.d.mts.map +1 -1
- package/esm/contracts/planner/planner-execute-options.type.d.mts +60 -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-snapshot.type.d.mts +77 -0
- package/esm/contracts/planner/planner-snapshot.type.d.mts.map +1 -0
- package/esm/contracts/planner/planner.contract.d.mts +21 -1
- package/esm/contracts/planner/planner.contract.d.mts.map +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/sdk-adapter.contract.d.mts +37 -0
- package/esm/contracts/sdk-adapter.contract.d.mts.map +1 -1
- package/esm/contracts/speech-model.contract.d.mts +97 -0
- package/esm/contracts/speech-model.contract.d.mts.map +1 -0
- 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/transcription-model.contract.d.mts +101 -0
- package/esm/contracts/transcription-model.contract.d.mts.map +1 -0
- 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/agent-drift-error.d.mts +32 -0
- package/esm/errors/agent-drift-error.d.mts.map +1 -0
- package/esm/errors/agent-drift-error.mjs +31 -0
- package/esm/errors/agent-drift-error.mjs.map +1 -0
- package/esm/errors/error-code.type.d.mts +1 -1
- package/esm/errors/index.d.mts +3 -0
- package/esm/errors/index.mjs +3 -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/errors/planner-drift-error.d.mts +34 -0
- package/esm/errors/planner-drift-error.d.mts.map +1 -0
- package/esm/errors/planner-drift-error.mjs +33 -0
- package/esm/errors/planner-drift-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/image/image-cost.d.mts +32 -0
- package/esm/image/image-cost.d.mts.map +1 -0
- package/esm/image/image-cost.mjs +55 -0
- package/esm/image/image-cost.mjs.map +1 -0
- package/esm/image/image.d.mts +92 -0
- package/esm/image/image.d.mts.map +1 -0
- package/esm/image/image.mjs +113 -0
- package/esm/image/image.mjs.map +1 -0
- package/esm/image/index.mjs +4 -0
- package/esm/index.d.mts +137 -24
- package/esm/index.mjs +101 -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/mock/index.d.mts +3 -0
- package/esm/mock/index.mjs +3 -0
- package/esm/mock/mock-config.type.d.mts +22 -0
- package/esm/mock/mock-config.type.d.mts.map +1 -1
- package/esm/mock/mock-image-model.d.mts +41 -0
- package/esm/mock/mock-image-model.d.mts.map +1 -0
- package/esm/mock/mock-image-model.mjs +52 -0
- package/esm/mock/mock-image-model.mjs.map +1 -0
- package/esm/mock/mock-sdk.d.mts +7 -1
- package/esm/mock/mock-sdk.d.mts.map +1 -1
- package/esm/mock/mock-sdk.mjs +27 -0
- package/esm/mock/mock-sdk.mjs.map +1 -1
- package/esm/mock/mock-speech-model.d.mts +31 -0
- package/esm/mock/mock-speech-model.d.mts.map +1 -0
- package/esm/mock/mock-speech-model.mjs +39 -0
- package/esm/mock/mock-speech-model.mjs.map +1 -0
- package/esm/mock/mock-transcription-model.d.mts +32 -0
- package/esm/mock/mock-transcription-model.d.mts.map +1 -0
- package/esm/mock/mock-transcription-model.mjs +36 -0
- package/esm/mock/mock-transcription-model.mjs.map +1 -0
- 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 +8 -0
- package/esm/planner/planner-run.d.mts.map +1 -1
- package/esm/planner/planner-run.mjs +457 -31
- package/esm/planner/planner-run.mjs.map +1 -1
- package/esm/planner/planner.d.mts.map +1 -1
- package/esm/planner/planner.mjs +26 -2
- package/esm/planner/planner.mjs.map +1 -1
- package/esm/planner/snapshot.mjs +95 -0
- package/esm/planner/snapshot.mjs.map +1 -0
- 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 +22 -0
- package/esm/rag/index.mjs +18 -0
- package/esm/rag/loaders/errors.d.mts +19 -0
- package/esm/rag/loaders/errors.d.mts.map +1 -0
- package/esm/rag/loaders/errors.mjs +25 -0
- package/esm/rag/loaders/errors.mjs.map +1 -0
- package/esm/rag/loaders/index.mjs +7 -0
- package/esm/rag/loaders/load-html.d.mts +26 -0
- package/esm/rag/loaders/load-html.d.mts.map +1 -0
- package/esm/rag/loaders/load-html.mjs +138 -0
- package/esm/rag/loaders/load-html.mjs.map +1 -0
- package/esm/rag/loaders/load-pdf.d.mts +38 -0
- package/esm/rag/loaders/load-pdf.d.mts.map +1 -0
- package/esm/rag/loaders/load-pdf.mjs +150 -0
- package/esm/rag/loaders/load-pdf.mjs.map +1 -0
- package/esm/rag/loaders/load-text.d.mts +47 -0
- package/esm/rag/loaders/load-text.d.mts.map +1 -0
- package/esm/rag/loaders/load-text.mjs +60 -0
- package/esm/rag/loaders/load-text.mjs.map +1 -0
- package/esm/rag/loaders/load-web.d.mts +42 -0
- package/esm/rag/loaders/load-web.d.mts.map +1 -0
- package/esm/rag/loaders/load-web.mjs +89 -0
- package/esm/rag/loaders/load-web.mjs.map +1 -0
- package/esm/rag/loaders/loader.type.d.mts +89 -0
- package/esm/rag/loaders/loader.type.d.mts.map +1 -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/pg-vector-store.d.mts +139 -0
- package/esm/rag/store/pg-vector-store.d.mts.map +1 -0
- package/esm/rag/store/pg-vector-store.mjs +328 -0
- package/esm/rag/store/pg-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/speech/index.mjs +3 -0
- package/esm/speech/speech.d.mts +65 -0
- package/esm/speech/speech.d.mts.map +1 -0
- package/esm/speech/speech.mjs +123 -0
- package/esm/speech/speech.mjs.map +1 -0
- package/esm/supervisor/as-tool.mjs +2 -2
- package/esm/supervisor/as-tool.mjs.map +1 -1
- package/esm/supervisor/entries.mjs +2 -2
- package/esm/supervisor/entries.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/transcribe/audio-input.d.mts +47 -0
- package/esm/transcribe/audio-input.d.mts.map +1 -0
- package/esm/transcribe/audio-input.mjs +84 -0
- package/esm/transcribe/audio-input.mjs.map +1 -0
- package/esm/transcribe/index.mjs +4 -0
- package/esm/transcribe/transcribe.d.mts +64 -0
- package/esm/transcribe/transcribe.d.mts.map +1 -0
- package/esm/transcribe/transcribe.mjs +128 -0
- package/esm/transcribe/transcribe.mjs.map +1 -0
- 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 +2572 -204
- package/llms.txt +21 -4
- package/package.json +7 -3
- package/skills/README.md +44 -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-agent-runs/SKILL.md +135 -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/generate-images/SKILL.md +138 -0
- package/skills/generate-speech/SKILL.md +139 -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/rag-loaders-and-stores/SKILL.md +164 -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/transcribe-audio/SKILL.md +157 -0
- 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,139 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: generate-speech
|
|
3
|
+
description: 'Text-to-speech via ai.speech({ model: sdk.speech({ name }), text }) — the audio-OUTPUT verb (Theme I), returning the uniform never-throws { data, error, usage, report } envelope with cost-truth + panoptic observation. Models come from an adapter''s speech() factory: OpenAI tts-1 / tts-1-hd (per-character) or gpt-4o-mini-tts (per-token). Synthesized audio is a discriminated GeneratedAudio = { type: "base64"; base64; mediaType }. Options: voice / format / speed / instructions / signal. Triggers: `ai.speech`, `sdk.speech`, `openai.speech`, `SpeechModelContract`, `GeneratedAudio`, `SpeechModelPricing`, `SpeechOptions`, `MockSpeechModel`; ''text to speech'', ''TTS'', ''synthesize voice'', ''read this aloud'', ''tts-1'', ''gpt-4o-mini-tts'', ''voice narration'', ''audio output'', ''speak this text''; typical import `import { ai } from "@warlock.js/ai"` + `import { OpenAISDK } from "@warlock.js/ai-openai"`. Skip: speech-to-text / transcribing a voice note — [[transcribe-audio]]; image OUTPUT — [[generate-images]]; competing libs raw `openai.audio.speech.create`, `elevenlabs` SDK.'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Generate speech — the text-to-speech verb (`ai.speech`)
|
|
7
|
+
|
|
8
|
+
`ai.speech()` is the audio-output counterpart to `ai.image()` on the output-modality track (Theme I). Text-in / audio-out, wrapped in the same uniform result contract every executable returns — so a synthesized voicemail slots into cost dashboards and panoptic traces exactly like an agent run.
|
|
9
|
+
|
|
10
|
+
This is audio **output** (TTS). For audio **input** (speech-to-text on a WhatsApp voice note or a meeting recording), see [[transcribe-audio]].
|
|
11
|
+
|
|
12
|
+
## Shape
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
// 1. Build a speech model from an adapter's speech() factory.
|
|
16
|
+
const model = openai.speech({ name: "tts-1", voice: "alloy" }); // SpeechModelContract
|
|
17
|
+
|
|
18
|
+
// 2. Run the verb — never throws; failures land on result.error.
|
|
19
|
+
const { data, error, usage, report } = await ai.speech({ model, text: "Your order has shipped." });
|
|
20
|
+
|
|
21
|
+
if (error) {
|
|
22
|
+
console.warn(error.code); // typed AIError (auth / rate-limit / content-filter / …)
|
|
23
|
+
} else {
|
|
24
|
+
const { base64, mediaType } = data.audio; // GeneratedAudio (always base64 today)
|
|
25
|
+
await fs.writeFile("ship.mp3", Buffer.from(base64, "base64"));
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
`SpeechModelContract` mirrors `EmbedderContract` / `ImageModelContract` — a peer primitive produced by the adapter's optional `speech?()` factory. An adapter without a TTS API simply doesn't define `speech()`, so calling it is a **compile-time** error, not a silent runtime failure. A non-TTS model id (`openai.speech({ name: "gpt-4o" })`) throws `InvalidRequestError` **at construction** — fail fast, like the embedder/image guards.
|
|
30
|
+
|
|
31
|
+
## The result envelope
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
type SpeechResult = {
|
|
35
|
+
type: "speech";
|
|
36
|
+
data?: { audio: GeneratedAudio }; // undefined on failure
|
|
37
|
+
error?: AIError; // undefined on success — NEVER thrown
|
|
38
|
+
usage: Usage; // tokens (gpt-4o-mini-tts) + cost when priced
|
|
39
|
+
report: SpeechReport; // type:"speech", model, characters, lineage
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
type GeneratedAudio = {
|
|
43
|
+
type: "base64";
|
|
44
|
+
base64: string; // base64-encoded audio bytes
|
|
45
|
+
mediaType: string; // IANA type, e.g. "audio/mpeg", "audio/wav"
|
|
46
|
+
};
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
`GeneratedAudio` is a discriminated union with a single `base64` variant today — the union leaves room for a future hosted-`url` variant without a breaking change, so always branch on `audio.type` rather than assuming `base64`.
|
|
50
|
+
|
|
51
|
+
## Generation options (provider-neutral)
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
await ai.speech({
|
|
55
|
+
model,
|
|
56
|
+
text: "Welcome aboard. Let's get you set up.",
|
|
57
|
+
voice: "verse", // voice id/name; overrides the model's default
|
|
58
|
+
format: "wav", // "mp3" | "opus" | "aac" | "flac" | "wav" | "pcm"
|
|
59
|
+
speed: 1.25, // playback multiplier (OpenAI 0.25–4.0)
|
|
60
|
+
instructions: "calm, warm", // tone/delivery steering (gpt-4o-mini-tts only)
|
|
61
|
+
signal, // AbortSignal
|
|
62
|
+
observe: collector, // route the report to an Observer (panoptic), like agents
|
|
63
|
+
sessionId: "onboarding-42", // group into a session for flat cost/trace queries
|
|
64
|
+
options: { /* provider passthrough */ },
|
|
65
|
+
});
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Each adapter maps the options its API supports and forwards `options` verbatim. On OpenAI the container defaults to `mp3` (→ `audio/mpeg`); `speed` and `instructions` are only sent when set, and the default voice is `alloy` when neither the call nor the model config supplies one.
|
|
69
|
+
|
|
70
|
+
## OpenAI — tts-1 (per-character) + gpt-4o-mini-tts (per-token)
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
import { ai } from "@warlock.js/ai";
|
|
74
|
+
import { OpenAISDK } from "@warlock.js/ai-openai";
|
|
75
|
+
|
|
76
|
+
const openai = new OpenAISDK({ apiKey: process.env.OPENAI_API_KEY! });
|
|
77
|
+
|
|
78
|
+
// tts-1 / tts-1-hd — billed per INPUT CHARACTER.
|
|
79
|
+
const classic = openai.speech({ name: "tts-1", voice: "alloy", pricing: { perMillionCharacters: 15 } });
|
|
80
|
+
|
|
81
|
+
// gpt-4o-mini-tts — billed per TOKEN like a chat model; supports `instructions`.
|
|
82
|
+
const steered = openai.speech({ name: "gpt-4o-mini-tts", pricing: { input: 0.6, output: 12 } });
|
|
83
|
+
|
|
84
|
+
const { data } = await ai.speech({ model: steered, text: "Read this warmly.", instructions: "gentle" });
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Cost-truth — one rollup, two metering models
|
|
88
|
+
|
|
89
|
+
`ai.speech` fills `usage.cost` (a USD breakdown) so TTS spend folds into the **same** `Usage.cost` rollup as text — no second accounting path:
|
|
90
|
+
|
|
91
|
+
- **Per-character** (`tts-1` / `tts-1-hd`): `{ perMillionCharacters }` × `report.characters` → `cost.input`. The Speech API reports no token usage, so `usage` tokens stay `{ 0, 0, 0 }` and spend is priced entirely from the input character count.
|
|
92
|
+
- **Token-metered** (`gpt-4o-mini-tts`): `{ input, output }` USD-per-1M-tokens → standard `computeCost` against the returned token usage.
|
|
93
|
+
|
|
94
|
+
Per-character wins when both are set. An unpriced model leaves `usage.cost` **`undefined`** (honest "cost unknown", never a false zero); a pre-priced adapter response is honored, not overwritten.
|
|
95
|
+
|
|
96
|
+
## Pattern — order-confirmation voice line in a workflow `run` step
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
ai.step({
|
|
100
|
+
name: "voiceLine",
|
|
101
|
+
run: async (ctx) => {
|
|
102
|
+
const { data, error } = await ai.speech({
|
|
103
|
+
model: openai.speech({ name: "tts-1", voice: "alloy" }),
|
|
104
|
+
text: `Order ${ctx.steps.order.output.id} confirmed. Thank you!`,
|
|
105
|
+
format: "mp3",
|
|
106
|
+
});
|
|
107
|
+
if (error) throw error; // step retry/backoff handles transient provider faults
|
|
108
|
+
ctx.state.audio = data.audio; // { type:"base64", base64, mediaType:"audio/mpeg" }
|
|
109
|
+
},
|
|
110
|
+
});
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Observability
|
|
114
|
+
|
|
115
|
+
The completed `SpeechReport` (with `report.characters` and cost/latency attributed to `report.model`) routes to any registered `Observer` (panoptic, OTel, …) through the shared `observe` seam — pass `observe: true` (global), an `Observer` object (flow-local), or rely on observe-all. See [[observe-ai-flows]]. Provider faults surface as typed `AIError`s on `result.error`; see [[handle-ai-errors]].
|
|
116
|
+
|
|
117
|
+
## Testing
|
|
118
|
+
|
|
119
|
+
`MockSpeechModel(name, responses, pricing?)` is a deterministic `SpeechModelContract` double — no HTTP. Script audio/usage/errors and inspect `model.calls`. `MockSDK({ speechResponses, speechPricing }).speech({ name })` wires the same double behind a full adapter.
|
|
120
|
+
|
|
121
|
+
```ts
|
|
122
|
+
import { MockSpeechModel } from "@warlock.js/ai";
|
|
123
|
+
import { speech } from "@warlock.js/ai";
|
|
124
|
+
|
|
125
|
+
const model = new MockSpeechModel("tts-1", [{}], { perMillionCharacters: 15 });
|
|
126
|
+
const { data, usage } = await speech({ model, text: "abcdefghij" }); // 10 chars
|
|
127
|
+
// data.audio → { type:"base64", base64:"AAAA", mediaType:"audio/mpeg" }
|
|
128
|
+
// usage.cost.input → (10 * 15) / 1_000_000
|
|
129
|
+
// model.calls[0] records { text, options } for assertions
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Scripting `[{ error: new ProviderRateLimitError("slow down") }]` drives the never-throws path — `result.error` is the typed error and `result.data` is `undefined`.
|
|
133
|
+
|
|
134
|
+
## See also
|
|
135
|
+
|
|
136
|
+
- [[transcribe-audio]] — the inverse verb (`ai.transcribe`), audio → text
|
|
137
|
+
- [[generate-images]] — the sibling image-output verb (`ai.image`)
|
|
138
|
+
- [[observe-ai-flows]] — routing the `SpeechReport` to panoptic / OTel
|
|
139
|
+
- [[handle-ai-errors]] — the typed `AIError` taxonomy on `result.error`
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: guard-input-output
|
|
3
|
+
description: 'Build the composed guardrail middleware with @warlock.js/ai-guard and wire it into an agent — `ai.guardrail({ input, output, tool, toolNames, escalation })`. Triggers: `ai.guardrail`, `guard`, `GuardOptions`, `GuardrailVerdict`, `GuardrailDetector`, `GuardrailPhase`, `GuardrailMatch`, `GuardrailViolationError`, `ai.guardrail.topic`, `ai.guardrail.injection`, `topicFilter`, `injectionDetector`, `toolNames`, `forTool`; ''add a guardrail to my agent'', ''block prompt injection'', ''filter banned topics'', ''guard agent input and output'', ''stop the model leaking data into a tool call'', ''scope a detector to one tool''; typical import `import "@warlock.js/ai-guard"` (registers `ai.guardrail`) or `import { guard } from "@warlock.js/ai-guard"`. Skip: PII detection/redaction specifically — `@warlock.js/ai-guard/detect-and-redact-pii/SKILL.md`; routing a block to a human — `@warlock.js/ai-guard/escalate-block-to-human/SKILL.md`; the core middleware pipeline / hook contract — `@warlock.js/ai/run-ai-agent/SKILL.md`.'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Guard agent input, output, and tool args
|
|
7
|
+
|
|
8
|
+
`ai.guardrail(...)` is a **middleware factory**. It produces one `AgentMiddleware` that runs your detectors at three hook points and maps each verdict onto the agent pipeline's existing throw / return / record mechanics. Importing the package registers the verb (and its attached detector factories) on the shared `ai` namespace:
|
|
9
|
+
|
|
10
|
+
```ts
|
|
11
|
+
import { ai } from "@warlock.js/ai";
|
|
12
|
+
import "@warlock.js/ai-guard"; // registers ai.guardrail + ai.guardrail.pii/.topic/.injection/.moderation
|
|
13
|
+
|
|
14
|
+
const policy = ai.guardrail({
|
|
15
|
+
name: "compliance",
|
|
16
|
+
input: [ai.guardrail.injection({ onMatch: "block" })],
|
|
17
|
+
output: [ai.guardrail.topic({ deny: [/medical advice/i, "diagnosis"], onMatch: "block" })],
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
const agent = ai.agent({ model, middleware: [policy] });
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
A named-export form is available for callers who prefer not to rely on the augmented namespace:
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
import { guard, topic, injection } from "@warlock.js/ai-guard";
|
|
27
|
+
const policy = guard({ input: [injection({ onMatch: "block" })] });
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## The three phases
|
|
31
|
+
|
|
32
|
+
| Phase | Hook | Inspected text | Set with |
|
|
33
|
+
|---|---|---|---|
|
|
34
|
+
| **input** | `trip.before` | the outbound prompt (`extractUserText(ctx.messages)`) | `input: [...]` |
|
|
35
|
+
| **output** | `trip.after` | `response.content` | `output: [...]` |
|
|
36
|
+
| **tool** | `tool.before` | `JSON.stringify(toolArgs)` | `tool: [...]` |
|
|
37
|
+
|
|
38
|
+
Each phase array runs its detectors in **registration order**; the first non-`allow` verdict decides the action for that phase (short-circuit). A phase you don't configure is inert — a guard with no detectors is a no-op middleware.
|
|
39
|
+
|
|
40
|
+
## The verdict model
|
|
41
|
+
|
|
42
|
+
A detector inspects text and returns a `GuardrailVerdict`, discriminated by `type` (never `kind`):
|
|
43
|
+
|
|
44
|
+
| `type` | Effect |
|
|
45
|
+
|---|---|
|
|
46
|
+
| `allow` | Pass to the next detector. |
|
|
47
|
+
| `redact` | Rewrite the inspected text and continue — **output phase only** (see limitation below). |
|
|
48
|
+
| `block` | Short-circuit with the existing `GuardrailViolationError`. |
|
|
49
|
+
| `flag` | Pass, but append a `FlagRecord` into `ctx.state` under `<name>.flags` for a downstream observer (panoptic, the caller). |
|
|
50
|
+
|
|
51
|
+
`agent.execute()` **never throws** — a `block` surfaces on `result.error` as a `GuardrailViolationError`, exactly like every other `AIError`. Branch on it after the run:
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
const result = await agent.execute(userInput);
|
|
55
|
+
|
|
56
|
+
if (result.error instanceof ai.errors.GuardrailViolationError) {
|
|
57
|
+
// result.error.phase is "input" | "output" | "tool"
|
|
58
|
+
// result.error.reason / result.error.guardrail carry the detail
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Built-in detectors
|
|
63
|
+
|
|
64
|
+
Three zero-dependency detectors ship (a fourth, `moderation`, is an optional `openai` peer — see [`detect-and-redact-pii/SKILL.md`](@warlock.js/ai-guard/detect-and-redact-pii/SKILL.md)):
|
|
65
|
+
|
|
66
|
+
- **`ai.guardrail.injection(options?)`** — jailbreak / prompt-injection marker phrases. Extra `markers` (string | RegExp); `onMatch` defaults to `"flag"`, callers commonly use `"block"` on input.
|
|
67
|
+
- **`ai.guardrail.topic(options)`** — `deny` (string substring | RegExp) and/or `allow` (allow-list miss triggers `onMatch`). `onMatch` is `"block" | "flag"`, default `"block"`.
|
|
68
|
+
- **`ai.guardrail.pii(options?)`** — PII regex + dictionary (its own skill).
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
const policy = ai.guardrail({
|
|
72
|
+
input: [
|
|
73
|
+
ai.guardrail.injection({ onMatch: "block", markers: ["ignore previous instructions"] }),
|
|
74
|
+
ai.guardrail.topic({ deny: ["competitor-name"], onMatch: "block" }),
|
|
75
|
+
],
|
|
76
|
+
});
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Scope tool detectors to specific tools
|
|
80
|
+
|
|
81
|
+
`tool` detectors fire on **every** tool call by default. Set `toolNames` to scope them — the whole middleware is wrapped with the core `forTool(toolNames, mw)` helper so the `tool` hooks fire only for those names; `input` / `output` (`trip`) hooks are unaffected:
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
const policy = ai.guardrail({
|
|
85
|
+
tool: [ai.guardrail.pii({ onMatch: "block" })], // stop PII reaching the tool
|
|
86
|
+
toolNames: ["send_email", "post_webhook"], // ...only for these tools
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
const agent = ai.agent({ model, tools: [sendEmail, postWebhook, lookup], middleware: [policy] });
|
|
90
|
+
// `lookup` runs unguarded; `send_email` / `post_webhook` block on PII in their args.
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
A `block` from `tool.before` aborts that tool dispatch and surfaces on `result.error` with `phase: "tool"` — the agent run itself still never crashes.
|
|
94
|
+
|
|
95
|
+
## Install order
|
|
96
|
+
|
|
97
|
+
A guard is a normal `AgentMiddleware`; registration order is execution order (`before` top-down, `after` bottom-up). The canonical order is `[cache, budget, guardrail, observability]`. A `semanticCache` that short-circuits `trip.before` runs *before* the guard — a cached response then skips the **output** detectors, so place the guard before the cache if you don't trust cached contents.
|
|
98
|
+
|
|
99
|
+
## Input-redaction limitation (v1)
|
|
100
|
+
|
|
101
|
+
The core `trip.before` hook can only **short-circuit** (return a `ModelResponse`); it cannot rewrite the outbound prompt and continue. So:
|
|
102
|
+
|
|
103
|
+
- **Input detectors are `block` / `flag` only.** A `redact` verdict on an input detector is treated as a `block` rather than silently passing an un-redacted prompt.
|
|
104
|
+
- **Output redaction works** — `trip.after` returns a replacement `ModelResponse` with the rewritten `content`.
|
|
105
|
+
- **Tool-arg `redact` is also withheld** — it downgrades to a `block` (`reason: "tool-arg-redaction-unsupported"`), because silently rewriting tool arguments changes the call's side-effects unpredictably.
|
|
106
|
+
|
|
107
|
+
Lifting the input limitation needs a small, non-breaking core affordance and is deferred.
|
|
108
|
+
|
|
109
|
+
## Failure isolation
|
|
110
|
+
|
|
111
|
+
A detector's `check()` **rejecting** is an infrastructure fault, not a content violation — it is recorded as a `flag` (`<detector>.error`) into `ctx.state` and the fold **continues** (fail-open). A moderation-API outage degrades to missing annotation, never a failed agent run.
|
|
112
|
+
|
|
113
|
+
## See also
|
|
114
|
+
|
|
115
|
+
- [`@warlock.js/ai-guard/detect-and-redact-pii/SKILL.md`](@warlock.js/ai-guard/detect-and-redact-pii/SKILL.md) — the `pii` detector (detect/redact/block), the `mask` template, and the optional `moderation` peer.
|
|
116
|
+
- [`@warlock.js/ai-guard/escalate-block-to-human/SKILL.md`](@warlock.js/ai-guard/escalate-block-to-human/SKILL.md) — routing a `block` to a human-review surface via `escalation.onBlock`.
|
|
117
|
+
- [`@warlock.js/ai/run-ai-agent/SKILL.md`](@warlock.js/ai/run-ai-agent/SKILL.md) — running the agent, the middleware pipeline, and the `GuardrailViolationError` on `result.error`.
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: manage-prompts
|
|
3
|
+
description: 'Unified prompt registry — ai.prompts: one process-wide store of named, versioned systemPrompt(...) builders keyed by name@version. Register by giving a prompt a meta.name (auto-registers), resolve by get(name) / resolve(name, versionOrTag, placeholders) / the inline name@selector form, bulk-register with define(name, versions), pin tags with tag(name, tag, version), compare with diff(name, from, to), round-trip with export() / import(snapshot), and quality-check with a unified validate(target, options) (deterministic missing-placeholder check + optional Nova-safe LLM-as-judge with verdict caching). Compose registered prompts into new ones with systemPrompt().merge(name, { fromVersion }) — provenance recorded in meta.composedFrom. ai.prompt is now a thin FACADE over ai.prompts (BREAKING vs the old standalone registry). Triggers: `ai.prompts`, `ai.prompt`, `PromptsManagerContract`, `PromptsManagerEntry`, `SystemPromptContract`, `SystemPromptMeta`, `SystemPromptMergeOptions`, `PromptsValidateOptions`, `PromptValidationResult`, `PromptValidateTarget`, `PromptTemplateVersion`, `PromptDiff`, `ExportedRegistry`, `defaultPromptsManager`, `prompts()`, `promptKey`, `meta`, `name`, `version`, `composedFrom`, `fromVersion`, `register`, `create`, `get`, `has`, `list`, `versions`, `resolve`, `define`, `tag`, `validate`, `diff`, `export`, `import`, `merge`, `judge`, `judgeCache`; ''register a prompt by name'', ''resolve a prompt by name@version or tag'', ''pin a production tag to a prompt version'', ''diff two prompt versions'', ''export / import the prompt registry'', ''validate a prompt for missing placeholders'', ''merge a registered prompt into another''; typical import `import { ai } from "@warlock.js/ai"`. Skip: composing a single prompt from persona + instruction blocks (the builder itself) — `@warlock.js/ai/write-system-prompt/SKILL.md`; runtime loadable skill bodies — `@warlock.js/ai/use-runtime-skills/SKILL.md`; eval scoring of agent outputs — `@warlock.js/ai/eval-datasets-and-ci/SKILL.md`; competing libs `langfuse` (direct), `promptfoo`.'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# `ai.prompts` — the unified prompt registry
|
|
7
|
+
|
|
8
|
+
`ai.prompts` is ONE process-wide registry of named, versioned `systemPrompt(...)` builders keyed by `name@version`. A `systemPrompt(input, { name })` (or any `.meta({ name })` rename) auto-registers here; `ai.prompts.get(name)` / `.resolve(name)` read them back; `systemPrompt().merge(name)` folds a registered prompt into a new one. There is exactly **one storage shape** behind the whole prompt surface — a `SystemPromptContract` keyed by `name@version` — and `ai.prompt(...)` is now a thin facade over it (see the migration note below).
|
|
9
|
+
|
|
10
|
+
```ts
|
|
11
|
+
import { ai } from "@warlock.js/ai";
|
|
12
|
+
|
|
13
|
+
// Register: any named systemPrompt auto-registers in ai.prompts.
|
|
14
|
+
ai.systemPrompt("You are support for {{product}}.", { name: "support" });
|
|
15
|
+
|
|
16
|
+
// Resolve back — latest version, or a version / pinned tag.
|
|
17
|
+
ai.prompts.get("support"); // → the SystemPromptContract
|
|
18
|
+
ai.prompts.resolve("support", undefined, { product: "Warlock" }); // → final string
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
`ai.prompts` is the process-wide default (`defaultPromptsManager()`). For an **isolated** registry (parallel test suites, multi-tenant apps) call the `prompts()` factory — same `PromptsManagerContract`, its own store, no global side effects.
|
|
22
|
+
|
|
23
|
+
## Identity — `SystemPromptMeta` (`meta.name` / `version` / `description` / `required` / `composedFrom`)
|
|
24
|
+
|
|
25
|
+
A prompt's identity rides on its `meta`. Read it with the no-argument accessor; update it immutably with the one-argument form:
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
const base = ai.systemPrompt("You are support.", {
|
|
29
|
+
name: "support",
|
|
30
|
+
version: "1",
|
|
31
|
+
description: "Tier-1 support persona.",
|
|
32
|
+
required: ["product"],
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
base.meta(); // → { name: "support", version: "1", description, required }
|
|
36
|
+
const v2 = base.meta({ version: "2" }); // new builder, shallow-merged meta; original untouched
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
- **`name`** — when present, the prompt auto-registers in `ai.prompts` under `name@version`. Anonymous prompts (no `name`) are never registered.
|
|
40
|
+
- **`version`** — free-form label (`"1"`, `"2025-draft"`). Defaults to the **next integer** for that name when omitted.
|
|
41
|
+
- **`description`** — human-readable purpose (carried through `export`).
|
|
42
|
+
- **`required`** — placeholder keys callers must supply; `validate()` reads them.
|
|
43
|
+
- **`composedFrom`** — deterministic source labels a prompt was merged from (e.g. `["base@2", "global@1"]`). No random suffixes — the same merge always yields the same labels.
|
|
44
|
+
|
|
45
|
+
## Register / resolve — `register` / `get` / `resolve` / `has` / `list` / `versions`
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
const registry = ai.prompts; // or prompts() for an isolated one
|
|
49
|
+
|
|
50
|
+
registry.register(ai.systemPrompt("You are support.", { name: "support" }));
|
|
51
|
+
registry.versions("support"); // ["1"] — version derived as next integer
|
|
52
|
+
|
|
53
|
+
registry.get("support"); // latest SystemPromptContract
|
|
54
|
+
registry.get("support@1"); // inline name@selector
|
|
55
|
+
registry.resolve("support", "1", { product: "Warlock" }); // pick version + render in one call
|
|
56
|
+
|
|
57
|
+
registry.has("support"); // boolean
|
|
58
|
+
registry.list(); // every registered name, first-seen order
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
- **Version selection** — `get(name)` / `resolve(name)` return the **latest** by insertion order; pass a version label, a pinned tag, or fold it into the first arg as `name@selector` (`get("support@1")`, `resolve("support@production")`).
|
|
62
|
+
- **Duplicates** — re-registering the same `name@version` throws `InvalidRequestError` **unless** the content is byte-identical (idempotent re-registration is a no-op).
|
|
63
|
+
- **Unknown name / version / tag** → `InvalidRequestError`.
|
|
64
|
+
- `register()` throws if the prompt has no `meta.name`.
|
|
65
|
+
|
|
66
|
+
## `create()` — build + register in one entry point
|
|
67
|
+
|
|
68
|
+
`ai.prompts.create(input?, meta?)` is a documented alias of `ai.systemPrompt(...)` — identical input forms (no arg → empty builder; a string → one instruction; an array of blocks → verbatim). Pass `meta.name` to auto-register, so authoring and lookup read side-by-side:
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
ai.prompts.create("You are support for {{product}}.", { name: "support" });
|
|
72
|
+
ai.prompts.resolve("support", undefined, { product: "Warlock" });
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## `define()` — bulk-register many versions
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
ai.prompts.define("agent", [
|
|
79
|
+
{ version: "1", template: "You are v1." },
|
|
80
|
+
{ version: "2", template: [ai.persona("You are Alex."), ai.instruction("Be concise.")] },
|
|
81
|
+
]);
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
A `PromptTemplateVersion`'s `template` is a raw string (wrapped into one instruction block) or an explicit ordered block list (verbatim). Versions register **oldest-first** in array order; the same duplicate / idempotency rule applies per `name@version`. Returns the manager for chaining.
|
|
85
|
+
|
|
86
|
+
## `tag()` — pin a moving label to a version
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
ai.prompts.tag("agent", "production", "2"); // pin "production" → version 2
|
|
90
|
+
|
|
91
|
+
ai.prompts.get("agent", "production"); // resolves through the tag
|
|
92
|
+
ai.prompts.resolve("agent", "production");
|
|
93
|
+
ai.prompts.get("agent@production"); // inline form
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Re-pinning an existing tag moves it. An unknown name / version throws `InvalidRequestError`. Tags survive `export` / `import`.
|
|
97
|
+
|
|
98
|
+
## `validate()` — unified deterministic + optional LLM-judge
|
|
99
|
+
|
|
100
|
+
```ts
|
|
101
|
+
const report = await ai.prompts.validate("support", {
|
|
102
|
+
placeholders: { product: "Warlock" }, // values you intend to supply
|
|
103
|
+
declare: ["language"], // extra keys to treat as known
|
|
104
|
+
judge: judgeModel, // optional — turns on the LLM-as-judge pass
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
report.ok; // true iff no required placeholder is missing (DETERMINISTIC verdict alone)
|
|
108
|
+
report.missing; // placeholder keys referenced with no default, unsupplied, undeclared
|
|
109
|
+
report.score; // 0..1 — present ONLY when a judge ran and produced a usable verdict
|
|
110
|
+
report.issues; // advisory judge reasons / a degrade note — present only when a judge was supplied
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
- **Always** runs the deterministic check: every `{{key}}` with no inline default that is neither supplied (`placeholders`), declared (`declare`), nor in the prompt's `meta.required` lands in `missing`; `ok` is `true` iff `missing` is empty.
|
|
114
|
+
- **`judge`** adds a **Nova-safe** LLM-as-judge quality pass — it **never throws** and degrades to an `issues` note (leaving `score` undefined) on failure, so a flaky judge can **never flip `ok`**.
|
|
115
|
+
- **`target`** is a registered name (or `name@selector`), a `SystemPromptContract` instance, or a raw prompt string.
|
|
116
|
+
- **`judgeCache`** (per-call or via the `prompts({ judgeCache })` factory option) memoizes judge verdicts by a content hash of the resolved body + the judge model id — a structural `{ get, set }` subset of `@warlock.js/cache`'s `CacheDriver`, so the cache package stays a strictly **optional** peer.
|
|
117
|
+
|
|
118
|
+
`systemPrompt().validate(options?)` is the per-builder sugar — `ai.prompts.validate(this, options)` under the hood, same result shape.
|
|
119
|
+
|
|
120
|
+
## `diff()` — block-level version diff
|
|
121
|
+
|
|
122
|
+
```ts
|
|
123
|
+
const diff = ai.prompts.diff("agent", "1", "2");
|
|
124
|
+
|
|
125
|
+
diff.identical; // true when both versions have identical blocks in identical order
|
|
126
|
+
diff.added; // blocks in `to` not at the same position in `from`
|
|
127
|
+
diff.removed; // blocks in `from` not at the same position in `to`
|
|
128
|
+
diff.changed; // [{ from, to }] — same position, type/text changed
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Blocks are matched **positionally**. Unknown name / version → `InvalidRequestError`.
|
|
132
|
+
|
|
133
|
+
## `export()` / `import()` — portable JSON round-trip
|
|
134
|
+
|
|
135
|
+
```ts
|
|
136
|
+
const snapshot = ai.prompts.export(); // ExportedRegistry — every name, version, pinned tag, description/required
|
|
137
|
+
otherRegistry.import(snapshot); // rehydrate (same duplicate / idempotency rule; tags restored)
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Each version flattens to `{ type, text }` blocks so the registry round-trips without live builder instances — commit a snapshot, ship it, restore it elsewhere.
|
|
141
|
+
|
|
142
|
+
## Compose registered prompts — `systemPrompt().merge(name, { fromVersion })`
|
|
143
|
+
|
|
144
|
+
`merge` folds another prompt's blocks into a new builder (persona **replaces**, instructions **append**) and records `meta.composedFrom`:
|
|
145
|
+
|
|
146
|
+
```ts
|
|
147
|
+
ai.systemPrompt("Always answer in {{language|English}}.", { name: "global", version: "1" });
|
|
148
|
+
|
|
149
|
+
const supportPrompt = ai.systemPrompt("You are support for {{product}}.")
|
|
150
|
+
.merge("global", { fromVersion: "1" }); // fold the registered prompt by name
|
|
151
|
+
|
|
152
|
+
supportPrompt.meta()?.composedFrom; // ["…", "global@1"] — deterministic provenance
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
`merge` accepts three source forms: a pre-built block, another `SystemPromptContract`, or a **registered name** resolved from `ai.prompts` (latest version unless `options.fromVersion` selects another — an unknown name / version throws `InvalidRequestError`).
|
|
156
|
+
|
|
157
|
+
## `ai.prompt(...)` — now a thin facade (⚠ breaking vs the old registry)
|
|
158
|
+
|
|
159
|
+
`ai.prompt` has **two** call forms, both backed by the unified manager — there is no longer a separate prompt store:
|
|
160
|
+
|
|
161
|
+
```ts
|
|
162
|
+
// (a) Resolve a globally-registered prompt from ai.prompts by name.
|
|
163
|
+
ai.systemPrompt("You are support.", { name: "support" });
|
|
164
|
+
const sp = ai.prompt("support"); // → SystemPromptContract (latest)
|
|
165
|
+
const v1 = ai.prompt("support", "1"); // → a specific version / pinned tag
|
|
166
|
+
|
|
167
|
+
// (b) Build an ISOLATED legacy-shaped registry (PromptRegistryContract).
|
|
168
|
+
const reg = ai.prompt({
|
|
169
|
+
prompts: [{ name: "summarizer", versions: [{ version: "1", template: "Summarize: {{text}}" }] }],
|
|
170
|
+
});
|
|
171
|
+
const resolved = reg.resolve("summarizer", { placeholders: { text } });
|
|
172
|
+
resolved.toSystemPrompt(); // drop-in for ai.agent({ systemPrompt })
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
**⚠ Migration.** Before unification, `ai.prompt(...)` only built a standalone, self-contained registry with its **own private** storage. It now:
|
|
176
|
+
|
|
177
|
+
1. Adds the **string overload** `ai.prompt(name, versionOrTag?)` → resolves from the shared `ai.prompts` manager. (New capability — `ai.prompt("x")` used to be a type error.)
|
|
178
|
+
2. Backs the **options form** (`ai.prompt({ ... })` → `PromptRegistryContract`) by an internal `PromptsManagerContract`, so its storage shape and validation primitives are now the unified ones. The legacy method surface (`register` / `add` / `versions` / `resolve` / `validate` / `sync` + the `{ score, notes }` report shape) is **unchanged**, and each `ai.prompt({ ... })` call still returns its **own isolated** registry — no shared global state.
|
|
179
|
+
|
|
180
|
+
If you only ever called `ai.prompt({ ... })` and used the returned registry, **no code change is needed**. The new behavior is additive: prefer `ai.prompts` (the unified manager) for new code; reach for `ai.prompt({ ... })` only when you want the legacy `ResolvedPrompt` / `toSystemPrompt()` ergonomics or the optional Langfuse sync. The legacy facade's reference — `register` / `add` / `resolve(name, { version, placeholders })` / `validate` (`{ score, notes }`) / `sync()` (lazy `langfuse` peer) — is documented inline in `src/prompt/prompt.ts`.
|
|
181
|
+
|
|
182
|
+
## See also
|
|
183
|
+
|
|
184
|
+
- [`@warlock.js/ai/write-system-prompt/SKILL.md`](@warlock.js/ai/write-system-prompt/SKILL.md) — the `systemPrompt()` / `persona()` / `instruction()` builder, `.meta()`, and `merge()` this registry stores and composes
|
|
185
|
+
- [`@warlock.js/ai/eval-datasets-and-ci/SKILL.md`](@warlock.js/ai/eval-datasets-and-ci/SKILL.md) — the eval `judge` scorer `validate()`'s LLM pass reuses
|
|
186
|
+
- [`@warlock.js/ai/run-ai-agent/SKILL.md`](@warlock.js/ai/run-ai-agent/SKILL.md) — wiring a resolved prompt into an agent, plus the judge-safe agent preset (`ai.agent.judge`)
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: observe-ai-flows
|
|
3
|
+
description: 'The core Observer seam — a generic, tool-agnostic observability hook every flow routes its completed ExecutionReport through. Covers the per-flow `observe?: boolean | Observer` option on ai.agent / workflow / supervisor / team, the global registry (registerObserver / getObservers / setObserveAll / isObserveAll / clearObservers), resolveObservers / notifyObservers resolution, the opt-in AgentConfig.captureMessages → AgentReport.messages full-history capture, the onConfigApplied dependency-inversion seam, and that @warlock.js/ai-panoptic is the batteries-included Observer. Triggers: `Observer`, `observe`, `registerObserver`, `getObservers`, `setObserveAll`, `isObserveAll`, `clearObservers`, `resolveObservers`, `notifyObservers`, `FlowObserveOption`, `ExecutionReport`, `captureMessages`, `AgentReport.messages`, `CapturedMessage`, `onConfigApplied`, `observeAll`; ''observe an agent run'', ''send finished reports to a collector'', ''capture the full message history'', ''observe every flow by default'', ''wire panoptic / tracing''; typical import `import { ai, registerObserver } from "@warlock.js/ai"`. Skip: structured logging of events — `@warlock.js/ai/log-ai-calls/SKILL.md`; reading the report tree shape (trips / children) — `@warlock.js/ai/run-ai-agent/SKILL.md`; per-call cost / usage rollup — `@warlock.js/ai/handle-ai-errors/SKILL.md`. The batteries-included Observer is the `@warlock.js/ai-panoptic` package.'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# The `Observer` seam — generic, tool-agnostic observability
|
|
7
|
+
|
|
8
|
+
Core defines a structural `Observer` and a tiny registry; it never imports any observability package (panoptic, OTel, Langfuse, …). A flow that resolves to "observed" hands its completed `ExecutionReport` to every registered observer. An observability tool **implements `Observer` and registers itself**, so `observe: true` / observe-all route reports without coupling core to the tool — the dependency inversion that keeps the two sides decoupled.
|
|
9
|
+
|
|
10
|
+
```ts
|
|
11
|
+
export interface Observer {
|
|
12
|
+
collect(report: ExecutionReport): void | Promise<void>;
|
|
13
|
+
}
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
`collect` may be sync or async — the flow awaits it. A throw is **swallowed** by the flow (never breaks the run), mirroring the existing `onUsage` / `onComplete` hooks.
|
|
17
|
+
|
|
18
|
+
## Per-flow `observe` option
|
|
19
|
+
|
|
20
|
+
`observe?: boolean | Observer` (`FlowObserveOption`) is accepted on **`ai.agent`, `ai.workflow`, `ai.supervisor`, and `ai.team`** (a team forwards it verbatim to the supervisor it desugars into):
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
const collector: Observer = { collect(report) { exporter.send(report); } };
|
|
24
|
+
|
|
25
|
+
ai.agent({ model, observe: true }); // → the globally registered observers, even if observe-all is off
|
|
26
|
+
ai.agent({ model, observe: false }); // → opt out entirely, even when observe-all is on
|
|
27
|
+
ai.agent({ model, observe: collector }); // → a flow-LOCAL collector; only this flow's report, only to it
|
|
28
|
+
ai.agent({ model }); // → undefined: follow the global observe-all flag
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Resolution (`resolveObservers(observe)`):
|
|
32
|
+
|
|
33
|
+
- `false` → `[]` (opted out).
|
|
34
|
+
- `true` → the globally registered observers.
|
|
35
|
+
- an `Observer` object → just that one (flow-local; the global observers are skipped).
|
|
36
|
+
- `undefined` → the global observers when observe-all is on, otherwise `[]`.
|
|
37
|
+
|
|
38
|
+
`notifyObservers(observe, report)` routes a completed report to each resolved observer, awaiting each `collect` (so async exporters finish before the flow returns) and swallowing any throw. The object form is typed as the structural `Observer` (NOT a panoptic-specific type), so a panoptic flow-local collector — which implements `Observer` — can be passed directly.
|
|
39
|
+
|
|
40
|
+
## The global registry
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
import {
|
|
44
|
+
registerObserver, getObservers, setObserveAll, isObserveAll, clearObservers,
|
|
45
|
+
} from "@warlock.js/ai";
|
|
46
|
+
|
|
47
|
+
registerObserver(collector); // an observability tool registers ONE collector when its config is applied
|
|
48
|
+
getObservers(); // read-only snapshot of the registered observers (do not mutate)
|
|
49
|
+
|
|
50
|
+
setObserveAll(true); // "observe every flow by default" — flows without their own `observe` get observed
|
|
51
|
+
isObserveAll(); // read the flag (default false — opt-in observability)
|
|
52
|
+
|
|
53
|
+
clearObservers(); // test-only: reset observers + the observe-all flag for spec isolation
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
`observeAll` defaults to `false` (opt-in). A flow that never sets `observe` is observed **only** when observe-all is on; individual flows still opt out with `observe: false`.
|
|
57
|
+
|
|
58
|
+
## Full-history capture — `captureMessages` → `AgentReport.messages`
|
|
59
|
+
|
|
60
|
+
Off by default. When `ai.agent({ captureMessages: true })` is set, the agent normalizes the real assembled turn array onto `AgentReport.messages` as a `CapturedMessage[]`:
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
const { report } = await ai.agent({ model, tools, captureMessages: true }).execute("Go");
|
|
64
|
+
report.messages; // CapturedMessage[] — every role (system/user/assistant/tool), every trip
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
A `CapturedMessage` is a JSON-safe projection: `{ role, content, toolCalls?, toolCallId? }` — `content` is always a string (tool results stringified), assistant turns that triggered tools carry `toolCalls`, tool-result turns carry the `toolCallId` they answer. Unlike `trips[].input` (which stubs non-first trips with `"[tool results]"`), this preserves the **real** turn array. Omitted ⇒ the field is **absent** and the report is byte-for-byte as before. Opt-in because messages can be large and sensitive (full prompts, tool inputs/outputs) — and **required for panoptic full-history capture**.
|
|
68
|
+
|
|
69
|
+
## Callback sub-agents nest in the report tree
|
|
70
|
+
|
|
71
|
+
The `ExecutionReport` an observer receives reflects **full** lineage: a supervisor / team / orchestrator callback that calls `agent.execute()` directly auto-nests `callback → agent → tool` (via an ambient `RunFrame`), so usage / cost roll up and panoptic renders the sub-agent under its callback instead of as a lone `$0` span. No observer-side change is needed — the tree arrives already nested. A team's root span carries `type: "team"` (a first-class `ReportType`, not `"supervisor"`), so observers can distinguish, group, and label team runs as their own type. See [`@warlock.js/ai/run-supervisor/SKILL.md`](@warlock.js/ai/run-supervisor/SKILL.md).
|
|
72
|
+
|
|
73
|
+
## The config seam — `onConfigApplied`
|
|
74
|
+
|
|
75
|
+
An observability tool reacts to its own augmented config slot without core importing it. Core lets tools attach an opaque slot (e.g. `panoptic?`) via declaration merging on `AIConfig`, then fires registered listeners after each `ai.config(...)` merge:
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
import { onConfigApplied, getAIConfig } from "@warlock.js/ai";
|
|
79
|
+
|
|
80
|
+
onConfigApplied((config) => applyPanopticConfig(config.panoptic)); // react on every config merge
|
|
81
|
+
applyPanopticConfig(getAIConfig().panoptic); // catch a pre-set config
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
A misbehaving listener's throw is swallowed (same swallow-on-throw discipline as the observer hooks). This mirrors the `Observer` registry's dependency inversion: a tool flips `setObserveAll(true)` and calls `registerObserver(...)` from inside its `onConfigApplied` listener.
|
|
85
|
+
|
|
86
|
+
## The batteries-included Observer
|
|
87
|
+
|
|
88
|
+
`@warlock.js/ai-panoptic` is the shipped, full-featured `Observer` — install it, configure it via `ai.config({ panoptic })`, and it registers its collector + (optionally) flips observe-all for you. Core stays dependency-free; this skill documents the seam panoptic plugs into.
|
|
89
|
+
|
|
90
|
+
## See also
|
|
91
|
+
|
|
92
|
+
- [`@warlock.js/ai/run-ai-agent/SKILL.md`](@warlock.js/ai/run-ai-agent/SKILL.md) — the `AgentReport` / `ExecutionReport` tree (`trips`, `children`) an observer receives
|
|
93
|
+
- [`@warlock.js/ai/log-ai-calls/SKILL.md`](@warlock.js/ai/log-ai-calls/SKILL.md) — event-level structured logging (vs. report-level observation)
|
|
94
|
+
- [`@warlock.js/ai/run-ai-team/SKILL.md`](@warlock.js/ai/run-ai-team/SKILL.md) — a team inherits `observe` through the supervisor it forwards to
|