@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,164 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: rag-loaders-and-stores
|
|
3
|
+
description: 'Turn any source into a RagDocument and index it in a production vector store — the document loaders ai.rag.loadText / loadHtml / loadWeb (SSRF-safe via guardedFetch) / loadPdf (lazy pdf-parse peer), plus the swappable stores ai.rag.pgVectorStore({client}) (pgvector + ensureSchema DDL + hnsw/ivfflat index) and ai.rag.cacheVectorStore(driver), both satisfying VectorStoreContract (upsert / query / removeNamespace). Loaders return the exact RagDocument[] that kb.index() consumes — no adapter. Triggers: `ai.rag.loadText`, `ai.rag.loadHtml`, `ai.rag.loadWeb`, `ai.rag.loadPdf`, `loadText`, `loadHtml`, `loadWeb`, `loadPdf`, `ai.rag.pgVectorStore`, `ai.rag.cacheVectorStore`, `pgVectorStore`, `cacheVectorStore`, `VectorStore`, `PgVectorStoreOptions`, `PgVectorStoreInstance`, `ensureSchema`, `schema()`, `RagLoaderResult`, `LoadWebOptions`, `LoadPdfOptions`, `perPage`, `OutboundPolicy`, `guardedFetch`, `hnsw`, `ivfflat`, `pgvector`, `dimensions`, `PgClientLike`, `PDF_PARSE_INSTALL_INSTRUCTIONS`; ''load a website into a knowledge base'', ''index a PDF for RAG'', ''strip HTML to text for embedding'', ''pgvector store for RAG'', ''SSRF-safe document fetch'', ''one document per PDF page'', ''swap the vector store''; typical import `import { ai } from "@warlock.js/ai"`. Skip: the chunk → embed → retrieve → rerank → cite pipeline that consumes these — `@warlock.js/ai/run-ai-rag/SKILL.md`; the raw embedder primitive — `@warlock.js/ai/embed-text/SKILL.md`; cache similarity internals — `@warlock.js/cache/use-cache-similarity/SKILL.md`; competing libs `langchain` loaders, `llamaindex` readers.'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# RAG loaders + vector stores — source → `RagDocument` → durable store
|
|
7
|
+
|
|
8
|
+
Two feature groups that bracket `ai.rag()`: **loaders** turn a source (string, raw HTML, a URL, or PDF bytes) into the exact `RagDocument[]` shape `kb.index()` consumes, and **stores** are the swappable backends that hold the embeddings. Both live on the `ai.rag.*` namespace — present the moment `@warlock.js/ai` is imported, no side-effect import, no module augmentation.
|
|
9
|
+
|
|
10
|
+
## Contract — what each side produces / satisfies
|
|
11
|
+
|
|
12
|
+
Every loader returns `RagLoaderResult` — a plain `RagDocument[]` — so a load feeds `index()` with no adapter and callers never branch on arity (one page ⇒ 1 doc, a per-page PDF ⇒ N docs):
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
type RagLoaderResult = RagDocument[];
|
|
16
|
+
type RagDocument = { id: string; text: string; metadata?: Record<string, unknown>; tags?: string[] };
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Every store satisfies the three-method `VectorStore` contract (a thin narrowing of the cache `similar()` surface — NOT a new engine):
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
interface VectorStore {
|
|
23
|
+
upsert(key: string, value: unknown, vector: number[], tags?: string[]): Promise<void>;
|
|
24
|
+
query<T>(vector: number[], options: { topK: number; threshold?: number; tags?: string[] }): Promise<{ key: string; value: T; score: number }[]>;
|
|
25
|
+
removeNamespace(namespace: string): Promise<void>;
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Loaders
|
|
30
|
+
|
|
31
|
+
| Loader | Input | Deps | Emits |
|
|
32
|
+
|---|---|---|---|
|
|
33
|
+
| `ai.rag.loadText(input, opts?)` | `string` \| `{ id, text }` \| array of either | none | one doc per non-empty item |
|
|
34
|
+
| `ai.rag.loadHtml(html, opts?)` | raw HTML string | none (regex strip) | one doc, `metadata.title` from `<title>` |
|
|
35
|
+
| `ai.rag.loadWeb(url, opts?)` | absolute URL | none (uses core `guardedFetch`) | one doc, SSRF-safe fetch |
|
|
36
|
+
| `ai.rag.loadPdf(bytes, opts?)` | `Buffer` \| `ArrayBuffer` \| `Uint8Array` | lazy `pdf-parse` peer | one doc, or one per page with `perPage: true` |
|
|
37
|
+
|
|
38
|
+
Shared options (`RagLoaderOptions`): `id` (source id — falls back to the URL for web, `"document"` otherwise), `metadata` (merged **over** the loader-derived keys, so an explicit `metadata.title` always wins), and `tags` (applied to every chunk for `retrieve({ tags })` filtering). Loader-derived keys: `source`, `loader` (`"text" | "html" | "web" | "pdf"`), plus `title` / `page` / `pageCount` / `contentType` where determinable. Empty / whitespace-only / all-markup inputs emit **no** document — never a no-op record for `index()` to skip.
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
import { ai } from "@warlock.js/ai";
|
|
42
|
+
|
|
43
|
+
// Bare string, or many records → many distinctly-identified docs:
|
|
44
|
+
await kb.index(ai.rag.loadText([
|
|
45
|
+
{ id: "faq-billing", text: "…", metadata: { section: "billing" } },
|
|
46
|
+
{ id: "faq-shipping", text: "…" },
|
|
47
|
+
]));
|
|
48
|
+
|
|
49
|
+
// Raw HTML → readable text (scripts/styles dropped, entities decoded):
|
|
50
|
+
await kb.index(ai.rag.loadHtml(rawHtml, { id: "landing", tags: ["marketing"] }));
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### `loadWeb` is SSRF-safe — never a raw `fetch`
|
|
54
|
+
|
|
55
|
+
Every request goes through core's `guardedFetch` under an `OutboundPolicy`. The strict defaults (https-only, private-IP-deny on, 10s timeout, 5 MiB cap) apply even when you pass no `policy`, so an untuned call is already hardened. Tighten it per call:
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
await kb.index(await ai.rag.loadWeb("https://docs.example.com/guide", {
|
|
59
|
+
policy: { hostAllowlist: ["docs.example.com"], maxBytes: 2_000_000, timeoutMs: 5_000 },
|
|
60
|
+
tags: ["docs"],
|
|
61
|
+
}));
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
HTML responses run through the same tag-strip pass as `loadHtml`; non-HTML text (`text/plain`, markdown) is used verbatim. `metadata.source` is the resolved URL, `metadata.contentType` the server-reported type. A non-OK response, a policy block, a timeout, or an over-cap body throws `OutboundPolicyError`.
|
|
65
|
+
|
|
66
|
+
### `loadPdf` — lazy optional peer, page-precise citations
|
|
67
|
+
|
|
68
|
+
`pdf-parse` is an **optional** peer, dynamic-imported on the FIRST `loadPdf` call — importing `@warlock.js/ai` never forces it. When it is absent, the curated `PDF_PARSE_INSTALL_INSTRUCTIONS` string is thrown as a plain `Error` (a missing infra peer, not a content problem), never a raw module-resolution stack trace.
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
import { readFile } from "node:fs/promises";
|
|
72
|
+
|
|
73
|
+
// Whole PDF → one doc carrying metadata.pageCount:
|
|
74
|
+
await kb.index(await ai.rag.loadPdf(await readFile("manual.pdf"), { id: "manual" }));
|
|
75
|
+
|
|
76
|
+
// One doc per page → citations stay page-precise (id suffixed `#p<n>`, metadata.page set):
|
|
77
|
+
await kb.index(await ai.rag.loadPdf(bytes, { id: "manual", perPage: true }));
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
An image-only / scanned page has no text layer and is dropped, so a fully-scanned PDF yields zero docs (nothing to embed).
|
|
81
|
+
|
|
82
|
+
## Stores
|
|
83
|
+
|
|
84
|
+
### `ai.rag.cacheVectorStore(driver)` — adapt any `@warlock.js/cache` driver
|
|
85
|
+
|
|
86
|
+
The cache driver **is** the vector store — `upsert → set({ vector, tags })`, `query → similar()`, `removeNamespace → removeNamespace()`. A driver without similarity support throws `CacheUnsupportedError` unchanged (pointing you at the `pg` / `redis` cache drivers).
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
import { MemoryCacheDriver } from "@warlock.js/cache";
|
|
90
|
+
|
|
91
|
+
const store = ai.rag.cacheVectorStore(new MemoryCacheDriver()); // dev / tests
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### `ai.rag.pgVectorStore(options)` — production pgvector
|
|
95
|
+
|
|
96
|
+
One durable row per chunk keyed by the pipeline's dotted key, the chunk payload in a `JSONB` `value` column, the embedding in a pgvector `vector` column. Pass a live pool (`{ client }` — `@warlock.js/ai` imports **nothing**) or a `{ connectionString }` and let the store lazily `import("pg")` (the optional peer; curated install string on first use if absent). Exactly one of the two is required.
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
type PgVectorStoreOptions = {
|
|
100
|
+
client?: PgClientLike; // a pg.Pool / pg.Client — only `query` is ever called
|
|
101
|
+
connectionString?: string; // else the store builds its own Pool lazily
|
|
102
|
+
table?: string; // default "warlock_ai_rag_vectors"; must be a safe identifier
|
|
103
|
+
dimensions?: number; // vector(N) width in the DDL, default 1536
|
|
104
|
+
index?: "hnsw" | "ivfflat" | "none"; // ANN strategy, default "hnsw"
|
|
105
|
+
ivfflatLists?: number; // ivfflat only, default 100
|
|
106
|
+
};
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
`schema()` (alias `ensureSchema()`) returns the reference migration DDL — `CREATE EXTENSION vector`, the table, a GIN index on `tags`, and the chosen ANN index (`USING hnsw (embedding vector_cosine_ops)`). It **only returns the string**; the framework never auto-migrates — you run it once through your own tool. Index and query MUST use the same embedding model: the `vector(N)` width is fixed at table-creation time from `dimensions`.
|
|
110
|
+
|
|
111
|
+
```ts
|
|
112
|
+
import { Pool } from "pg";
|
|
113
|
+
|
|
114
|
+
const pool = new Pool({ connectionString: process.env.DATABASE_URL });
|
|
115
|
+
const store = ai.rag.pgVectorStore({ client: pool, dimensions: 1536, index: "hnsw" });
|
|
116
|
+
|
|
117
|
+
// Once, via your migration tooling — never auto-run:
|
|
118
|
+
await pool.query(store.ensureSchema());
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
`query()` runs the cosine floor (`threshold`) and `tags` overlap filter **in SQL** (a below-floor row never crosses the wire), orders by `embedding <=> $vec`, caps at `topK`, and maps the pgvector distance back to a `[0,1]` cosine-similarity `score` — the same scale the cache store emits. `removeNamespace()` is a prefix DELETE that escapes `_` / `%` so dropping `ai.rag.docs` never also catches `ai.rag.docs2`.
|
|
122
|
+
|
|
123
|
+
## Pattern — a knowledge base from a website, backed by pgvector
|
|
124
|
+
|
|
125
|
+
```ts
|
|
126
|
+
import { Pool } from "pg";
|
|
127
|
+
import { ai } from "@warlock.js/ai";
|
|
128
|
+
import { OpenAISDK } from "@warlock.js/ai-openai";
|
|
129
|
+
|
|
130
|
+
const openai = new OpenAISDK({ apiKey: process.env.OPENAI_API_KEY! });
|
|
131
|
+
const pool = new Pool({ connectionString: process.env.DATABASE_URL });
|
|
132
|
+
|
|
133
|
+
const store = ai.rag.pgVectorStore({ client: pool, dimensions: 1536 });
|
|
134
|
+
await pool.query(store.ensureSchema()); // once at boot / migration
|
|
135
|
+
|
|
136
|
+
const kb = ai.rag({
|
|
137
|
+
name: "docs",
|
|
138
|
+
embedder: openai.embedder({ name: "text-embedding-3-small" }), // 1536 dims — matches the DDL
|
|
139
|
+
store,
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
// Crawl a few pages (SSRF-safe) + a spec PDF into the same namespace:
|
|
143
|
+
for (const url of ["https://docs.example.com/intro", "https://docs.example.com/config"]) {
|
|
144
|
+
await kb.index(await ai.rag.loadWeb(url, { policy: { hostAllowlist: ["docs.example.com"] }, tags: ["docs"] }));
|
|
145
|
+
}
|
|
146
|
+
await kb.index(await ai.rag.loadPdf(await readFile("spec.pdf"), { id: "spec", perPage: true, tags: ["spec"] }));
|
|
147
|
+
|
|
148
|
+
// Now retrieve — every hit's citation traces back to its source URL / page:
|
|
149
|
+
const { chunks } = await kb.retrieve("how do I configure caching?", { topK: 4, tags: ["docs"] });
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
The `embedder`'s `dimensions` MUST equal the store's `dimensions` — a mismatch is a runtime insert failure at the pgvector column, not a type error.
|
|
153
|
+
|
|
154
|
+
## Cost + testing
|
|
155
|
+
|
|
156
|
+
- **Loaders are cheap.** `loadText` / `loadHtml` are zero-dependency string passes; `loadWeb` costs one guarded HTTP round-trip; `loadPdf` costs the `pdf-parse` parse. **None embed** — embedding cost lands entirely in `kb.index()` (batched, 96 texts per `embedMany` call). The token spend is per chunk, so `perPage` PDFs and finer chunking mean more, smaller vectors.
|
|
157
|
+
- **`pgVectorStore` construction is synchronous and does no I/O** — the `pg` import + pool build are deferred to first `query`/`upsert`. Table-name validation (`/^[A-Za-z_][A-Za-z0-9_]*$/`) throws at construction, so a `table: "bad; DROP TABLE x"` fails fast.
|
|
158
|
+
- **Unit-test loaders with fixtures** (a stubbed `policy.fetch` for `loadWeb`, `vi.mock("pdf-parse")` for `loadPdf` — the literal specifier is mockable). Test stores against a `FakePgClient` implementing `{ query }`, or `cacheVectorStore(new MemoryCacheDriver())` for a real end-to-end index/retrieve with no external service.
|
|
159
|
+
|
|
160
|
+
## See also
|
|
161
|
+
|
|
162
|
+
- [[run-ai-rag]] — the chunk → embed → retrieve → rerank → cite pipeline that **consumes** these loaders and stores (`ai.rag({ embedder, store })`, `index()` / `retrieve()`).
|
|
163
|
+
- [[embed-text]] — the `sdk.embedder` primitive whose `dimensions` must match the store's `vector(N)` width.
|
|
164
|
+
- [`@warlock.js/cache/use-cache-similarity/SKILL.md`](@warlock.js/cache/use-cache-similarity/SKILL.md) — the cache driver `cacheVectorStore` adapts.
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: record-replay-llm
|
|
3
|
+
description: 'Deterministic, offline LLM tests with ai.vcr(model,{path,mode}) — a record/replay decorator over ANY ModelContract that intercepts only complete()/stream(), delegates name/provider/capabilities/pricing to the inner model, and hashes each request against a JSON cassette on disk. Covers the three modes (record / replay / auto), the cassette format, save(), VcrCassetteMissError, streaming round-trip, hashOptions, and composing below fallbackModel. Triggers: `ai.vcr`, `vcr`, `VcrModel`, `VcrOptions`, `VcrMode`, `Cassette`, `CassetteEntry`, `VcrCassetteMissError`, `hashRequest`, `DEFAULT_HASH_OPTIONS`, `mode`, `path`, `hashOptions`, `save`, `cassette`, record, replay, cassette; ''record LLM responses for tests'', ''replay model calls offline in CI'', ''deterministic agent test without hitting the provider'', ''cassette for model calls''; typical import `import { ai } from "@warlock.js/ai"`. Skip: eval scoring + regression gating — `@warlock.js/ai/eval-datasets-and-ci/SKILL.md`; the Vitest matchers + mockRouter — `@warlock.js/ai/ai-dx-helpers/SKILL.md`; choosing a provider adapter — `@warlock.js/ai/pick-ai-provider/SKILL.md`; competing libs `nock`, `polly.js`.'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# `ai.vcr()` — record / replay any model
|
|
7
|
+
|
|
8
|
+
`ai.vcr(model, { path, mode })` wraps any `ModelContract` in a record/replay decorator backed by a JSON cassette on disk. It intercepts only `complete()` / `stream()` — the single seam every agent trip funnels through — and delegates `name`, `provider`, `capabilities`, and `pricing` to the inner model untouched, so cost accounting and capability detection are unchanged. Depends only on `ModelContract`, so it works with **any** adapter.
|
|
9
|
+
|
|
10
|
+
## Shape
|
|
11
|
+
|
|
12
|
+
```ts
|
|
13
|
+
import { ai } from "@warlock.js/ai";
|
|
14
|
+
import { OpenAISDK } from "@warlock.js/ai-openai";
|
|
15
|
+
|
|
16
|
+
const openai = new OpenAISDK({ apiKey: process.env.OPENAI_API_KEY! });
|
|
17
|
+
const live = openai.model({ name: "gpt-4o-mini" });
|
|
18
|
+
|
|
19
|
+
const model = ai.vcr(live, {
|
|
20
|
+
path: "./cassettes/support.json", // cassette file (JSON); read on construct, written on save()
|
|
21
|
+
mode: "auto", // "record" | "replay" | "auto" (default)
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
const agent = ai.agent({ model, systemPrompt: "..." });
|
|
25
|
+
const result = await agent.execute("hi");
|
|
26
|
+
|
|
27
|
+
await model.save(); // first run records; later runs replay deterministically
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
The returned `VcrModel` is a `ModelContract` plus `save(): Promise<void>` and a readonly `cassette` (exposed for assertions).
|
|
31
|
+
|
|
32
|
+
## Modes — `VcrMode`
|
|
33
|
+
|
|
34
|
+
- **`record`** — always calls the inner model and appends a cassette entry. Never replays (the in-memory cassette starts empty, so a record run never accidentally replays a stale entry). Use to (re)capture a fresh cassette.
|
|
35
|
+
- **`replay`** — never calls the inner model. A cassette hit returns the stored response / re-yields its chunks / re-throws its error; a **miss throws `VcrCassetteMissError`** — never a silent live call. Use in CI for deterministic, offline tests.
|
|
36
|
+
- **`auto`** (default) — replay on a hit, record on a miss. The friendliest mode for local dev: records once, replays thereafter.
|
|
37
|
+
|
|
38
|
+
## Request hashing — `hashOptions`
|
|
39
|
+
|
|
40
|
+
On each call VCR computes a stable hash over `{ messages, picked options }` and looks for a matching `CassetteEntry`. The hashed option fields default to:
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
["temperature", "maxTokens", "responseSchema", "tools", "reasoning"]
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
(`DEFAULT_HASH_OPTIONS`). `signal` and unknown provider keys are **always excluded**, so an otherwise-identical logical call still matches. `tools` are hashed by name + description + input-schema shape, not object identity. Override `hashOptions` to widen / narrow what counts as "the same request". `hashRequest(messages, options, hashOptions)` is exported for direct use.
|
|
47
|
+
|
|
48
|
+
## Cassette format
|
|
49
|
+
|
|
50
|
+
A `Cassette` is `{ version: 1, model, provider, entries: CassetteEntry[] }`. Each `CassetteEntry` is `{ requestHash, request: { messages, options? }, ... }` where **exactly one** of `response` / `chunks` / `error` is populated — mirroring the three outcomes of a model call (non-streaming reply, streamed chunk list, or a thrown provider error). The full `request` is stored verbatim for human readability and so the cassette can be re-hashed if the hashing format ever changes.
|
|
51
|
+
|
|
52
|
+
## Streaming round-trip
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
for await (const chunk of model.stream(messages)) {
|
|
56
|
+
// record mode: buffers each chunk into entry.chunks[] while re-emitting
|
|
57
|
+
// replay mode: re-yields the stored chunks in order (delta / tool-call / done sequence)
|
|
58
|
+
}
|
|
59
|
+
await model.save();
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Recorded chunks reproduce the exact `delta` / `tool-call` / `done` sequence on replay; a recorded error is re-thrown.
|
|
63
|
+
|
|
64
|
+
## `VcrCassetteMissError`
|
|
65
|
+
|
|
66
|
+
```ts
|
|
67
|
+
import { VcrCassetteMissError } from "@warlock.js/ai";
|
|
68
|
+
|
|
69
|
+
try {
|
|
70
|
+
await vcrModel.complete(messages);
|
|
71
|
+
} catch (error) {
|
|
72
|
+
if (error instanceof VcrCassetteMissError) {
|
|
73
|
+
console.error("Re-record the cassette:", error.path, error.requestHash);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Thrown only in `replay` mode on a miss (code `"VCR_CASSETTE_MISS"`). It carries the looked-up `requestHash` and the cassette `path` so a failing CI run names exactly which call was not recorded. Extends `AIError` directly (not `ProviderError`) — a miss is a harness/config failure, not a provider failure. **The whole point:** `replay` never falls back to a live call, which would silently re-introduce non-determinism into a test that asked for the opposite. Re-record by running once in `record` / `auto`.
|
|
79
|
+
|
|
80
|
+
## `save()` — flush new entries
|
|
81
|
+
|
|
82
|
+
`save()` writes newly recorded entries to `path`. It is a **no-op when nothing was recorded** (pure replay, or a record/auto run that only hit cached entries), so calling it unconditionally is safe.
|
|
83
|
+
|
|
84
|
+
## Composition
|
|
85
|
+
|
|
86
|
+
VCR composes **below** `ai.fallbackModel` and works with any adapter. Wrap the live model in `vcr(...)`, then pass it anywhere a `ModelContract` is accepted (agent, planner, reranker, judge).
|
|
87
|
+
|
|
88
|
+
## See also
|
|
89
|
+
|
|
90
|
+
- [`@warlock.js/ai/eval-datasets-and-ci/SKILL.md`](@warlock.js/ai/eval-datasets-and-ci/SKILL.md) — pair a cassette with a dataset for fully offline eval CI
|
|
91
|
+
- [`@warlock.js/ai/ai-dx-helpers/SKILL.md`](@warlock.js/ai/ai-dx-helpers/SKILL.md) — `ai.mockRouter` + Vitest matchers for the rest of the test surface
|
|
92
|
+
- [`@warlock.js/ai/pick-ai-provider/SKILL.md`](@warlock.js/ai/pick-ai-provider/SKILL.md) — the adapters whose models VCR wraps
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: run-ai-agent
|
|
3
|
-
description: 'Build agents with ai.agent({...}) — the single-LLM-turn primitive. Covers execute / stream, attachments, structured output, placeholders, events, agent.eval scoring, and auto-adapting raw executables in tools:[]. Triggers: `ai.agent`, `agent.execute`, `agent.stream`, `agent.eval`, `AgentResult`, `AgentReport`, `AgentToolEntry`, `streamingToolGuard`, `attachments`, `repair`, `maxTrips`, `sessionId`, `spawnSubAgent`, `SpawnSubAgentSpec`; ''run an agent'', ''stream an agent response'', ''structured output schema'', ''pass image to agent'', ''evaluate an agent'', ''put a supervisor in tools'', ''cancel an agent run'', ''spawn a one-shot sub-agent with a per-task budget''; typical import `import { ai } from "@warlock.js/ai"`. Skip: tool definition — `@warlock.js/ai/define-ai-tool/SKILL.md`; workflows — `@warlock.js/ai/run-ai-workflow/SKILL.md`; eval matchers / batch / fallback detail — `@warlock.js/ai/ai-dx-helpers/SKILL.md`; competing libs `langchain`, `ai` (Vercel), raw `openai`.'
|
|
3
|
+
description: 'Build agents with ai.agent({...}) — the single-LLM-turn primitive. Covers execute / stream, attachments, structured output, placeholders, events, agent.eval scoring, the judge-safe preset for resilient LLM-as-judge / verdict classifiers (ai.agent.judge / judge: true — lenient JSON parse + repair + never-throw, for Nova-class models), and auto-adapting raw executables in tools:[]. Triggers: `ai.agent`, `ai.agent.judge`, `agent.execute`, `agent.stream`, `agent.eval`, `AgentResult`, `AgentReport`, `AgentToolEntry`, `JudgeConfig`, `JudgeAgentConfig`, `judge`, `repairAttempts`, `streamingToolGuard`, `attachments`, `repair`, `maxTrips`, `sessionId`, `spawnSubAgent`, `SpawnSubAgentSpec`; ''run an agent'', ''stream an agent response'', ''structured output schema'', ''pass image to agent'', ''evaluate an agent'', ''LLM-as-judge that survives malformed JSON'', ''grade with a Nova model without crashing'', ''put a supervisor in tools'', ''cancel an agent run'', ''spawn a one-shot sub-agent with a per-task budget''; typical import `import { ai } from "@warlock.js/ai"`. Skip: tool definition — `@warlock.js/ai/define-ai-tool/SKILL.md`; workflows — `@warlock.js/ai/run-ai-workflow/SKILL.md`; eval matchers / batch / fallback detail — `@warlock.js/ai/ai-dx-helpers/SKILL.md`; competing libs `langchain`, `ai` (Vercel), raw `openai`.'
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# `ai.agent()` — single-turn primitive
|
|
@@ -183,6 +183,31 @@ await myAgent.execute(input, {
|
|
|
183
183
|
|
|
184
184
|
Disabled by default. Each repair attempt counts against `maxTrips`.
|
|
185
185
|
|
|
186
|
+
## `judge` preset — resilient LLM-as-judge / verdict classifiers
|
|
187
|
+
|
|
188
|
+
For graders and verdict classifiers running on models that emit **corrupted** structured output — notably the Amazon Nova family, which wraps verdicts in fenced ` ```json ` blocks, prepends prose, or trails commentary — set `judge: true` (or a `JudgeConfig`). It turns on three behaviors at once:
|
|
189
|
+
|
|
190
|
+
```ts
|
|
191
|
+
const grader = ai.agent.judge({
|
|
192
|
+
model: nova.model({ name: "amazon.nova-pro-v1:0" }),
|
|
193
|
+
systemPrompt: "Grade the answer. Respond with JSON only.",
|
|
194
|
+
output: verdictSchema,
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
const result = await grader.execute(prompt);
|
|
198
|
+
if (result.error) {
|
|
199
|
+
// graceful default — the judge couldn't produce a clean verdict
|
|
200
|
+
}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
1. **Repair** — a couple of re-ask attempts by default (`repairAttempts`, defaults to `2`; bounded by `maxTrips`) when the verdict fails to parse / validate. The caller's per-call `options.repair` still wins.
|
|
204
|
+
2. **Lenient verdict parsing** — extracts the first balanced JSON object / array (tolerating fenced blocks + surrounding prose) instead of the strict parser.
|
|
205
|
+
3. **Never throws on a parse miss** — even an unparseable verdict yields a well-formed result (`result.error` populated, `result.data` undefined), so a flaky judge degrades instead of crashing the flow.
|
|
206
|
+
|
|
207
|
+
`ai.agent.judge(config, judge?)` is sugar for `ai.agent({ ...config, judge })`; the bare `ai.agent({ judge: true })` option does the same. `judge: {}` ≡ `judge: true` (every field falls back to its resilient default); `judge: { repairAttempts: 0 }` keeps the lenient parser + never-throw guarantee but disables repair.
|
|
208
|
+
|
|
209
|
+
**Trade-off — resilience over strictness.** The lenient parse can recover JSON the strict parser would (correctly) reject — leave `judge` **off** for normal structured output, where a hard parse failure is a useful signal. Off by default; omitting it parses strictly and never auto-enables repair, byte-for-byte as before. (This is the same Nova-safe judge the unified prompt `validate()` uses — see [`@warlock.js/ai/manage-prompts/SKILL.md`](@warlock.js/ai/manage-prompts/SKILL.md).)
|
|
210
|
+
|
|
186
211
|
## Pattern — image attachments
|
|
187
212
|
|
|
188
213
|
```ts
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: run-ai-rag
|
|
3
|
+
description: 'Retrieval-augmented generation with ai.rag({...}) — a chunk → embed → vector-store → retrieve → rerank → cite pipeline that reuses ai.embedder + a @warlock.js/cache CacheDriver. Covers index() / retrieve() / clear() / asTool(), chunking strategies (recursive | markdown | sentence | fixed), Citation / RetrievedChunk provenance, and the opt-in rerankers ai.rag.keywordReranker / ai.rag.llmReranker. Triggers: `ai.rag`, `rag.index`, `rag.retrieve`, `rag.clear`, `rag.asTool`, `RagConfig`, `RagDocument`, `RetrieveOptions`, `RetrieveResult`, `RetrievedChunk`, `Citation`, `ChunkOptions`, `ChunkType`, `ai.rag.keywordReranker`, `ai.rag.llmReranker`, `cacheVectorStore`, `VectorStore`, `topK`, `threshold`, `candidates`; ''build a knowledge base'', ''retrieve relevant chunks for a query'', ''cite the source of an answer'', ''chunk markdown for embedding'', ''rerank retrieval results'', ''expose retrieval as a tool''; typical import `import { ai } from "@warlock.js/ai"`. Skip: raw single-string embedding — `@warlock.js/ai/embed-text/SKILL.md`; exact + vector LLM-response cache — `@warlock.js/ai/attach-ai-middleware/SKILL.md` (ai.middleware.semanticCache); tool wiring — `@warlock.js/ai/define-ai-tool/SKILL.md`; competing libs `langchain`, `llamaindex`.'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# `ai.rag()` — chunk → embed → retrieve → rerank → cite
|
|
7
|
+
|
|
8
|
+
A self-contained retrieval pipeline. It reuses the embedder you already have (`provider.embedder(...)`), a `@warlock.js/cache` vector-capable `CacheDriver` as the store, and the composite-as-tool engine for `asTool()`. Zero new dependencies. `ai.rag` is a native core verb — present the moment `@warlock.js/ai` is imported (no module augmentation, no side-effect import).
|
|
9
|
+
|
|
10
|
+
## Factory shape
|
|
11
|
+
|
|
12
|
+
```ts
|
|
13
|
+
import { ai } from "@warlock.js/ai";
|
|
14
|
+
import { MemoryCacheDriver } from "@warlock.js/cache";
|
|
15
|
+
import { OpenAISDK } from "@warlock.js/ai-openai";
|
|
16
|
+
|
|
17
|
+
const openai = new OpenAISDK({ apiKey: process.env.OPENAI_API_KEY! });
|
|
18
|
+
|
|
19
|
+
const kb = ai.rag({
|
|
20
|
+
name: "docs", // default "rag"
|
|
21
|
+
embedder: openai.embedder({ name: "text-embedding-3-small" }), // REQUIRED
|
|
22
|
+
store: new MemoryCacheDriver(), // or ai.config({ defaultStore })
|
|
23
|
+
namespace: "ai.rag.docs", // default `ai.rag.<name>`
|
|
24
|
+
chunk: { type: "markdown", size: 800, overlap: 120 }, // index() defaults
|
|
25
|
+
reranker: ai.rag.keywordReranker(), // OFF by default (cosine-only)
|
|
26
|
+
retrieve: { topK: 4, threshold: 0.5 }, // default retrieval knobs
|
|
27
|
+
});
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Resolution is **loud at construction** (mirrors `ai.memory`):
|
|
31
|
+
|
|
32
|
+
- `embedder` is **required** — a provider with no embedder must be caught here, not at first `index()`.
|
|
33
|
+
- `store` falls back to `ai.config({ defaultStore })`; if neither resolves, the factory throws.
|
|
34
|
+
|
|
35
|
+
## Surface — `Rag`
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
interface Rag {
|
|
39
|
+
readonly name: string;
|
|
40
|
+
index(docs: RagDocument[], chunk?: ChunkOptions): Promise<{ chunks: number }>;
|
|
41
|
+
retrieve(query: string, options?: RetrieveOptions): Promise<RetrieveResult>;
|
|
42
|
+
clear(): Promise<void>;
|
|
43
|
+
asTool(options?: RagAsToolOptions): ToolContract<{ query: string }, RetrieveResult>;
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## `index()` — chunk, embed (batched), store
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
await kb.index([
|
|
51
|
+
{ id: "guide", text: longMarkdown, metadata: { url: "/guide" }, tags: ["frontend"] },
|
|
52
|
+
{ id: "faq", text: faqText },
|
|
53
|
+
]);
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
A `RagDocument` is `{ id, text, metadata?, tags? }` — **you** load + parse documents to text (loaders are out of scope for v1). Each doc is split into chunks, embedded in sub-batches of 96 texts per `embedMany()` call (so one giant doc never blows the provider's per-request cap), and upserted. Returns the chunk count written. Empty / whitespace-only documents yield zero chunks — nothing is embedded. The per-call `chunk` arg overrides `config.chunk` for that index.
|
|
57
|
+
|
|
58
|
+
## Chunking — `ChunkOptions`
|
|
59
|
+
|
|
60
|
+
All sizing is in **characters** (tokenizer-free; the embedder owns token counting). `chunk(text, options)` is also exported standalone.
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
type ChunkType = "recursive" | "sentence" | "fixed" | "markdown";
|
|
64
|
+
|
|
65
|
+
{
|
|
66
|
+
type?: ChunkType, // default "recursive"
|
|
67
|
+
size?: number, // target chars per chunk, default 1000
|
|
68
|
+
overlap?: number, // chars carried between adjacent chunks, default 200
|
|
69
|
+
separators?: string[], // recursive only; default ["\n\n", "\n", ". ", " ", ""]
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
- **`recursive`** (default) — separator-aware greedy packing, largest unit first.
|
|
74
|
+
- **`markdown`** — heading/section-aware, then recursive within each section.
|
|
75
|
+
- **`sentence`** — packs whole sentences up to `size`.
|
|
76
|
+
- **`fixed`** — back-to-back character windows.
|
|
77
|
+
|
|
78
|
+
Every chunk records its exact `[start, end)` span in the original text, so a `Citation.span` is precise.
|
|
79
|
+
|
|
80
|
+
## `retrieve()` — embed query, fetch, rerank, slice, cite
|
|
81
|
+
|
|
82
|
+
```ts
|
|
83
|
+
const { query, chunks } = await kb.retrieve("how do I configure caching?", {
|
|
84
|
+
topK: 4, // returned AFTER reranking. default 5
|
|
85
|
+
threshold: 0.5, // cosine floor at the store stage. default 0.5
|
|
86
|
+
candidates: 16, // pool fetched before rerank. default topK * 4 (clamped >= topK)
|
|
87
|
+
tags: ["frontend"], // restrict to chunks whose source had one of these tags
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
for (const hit of chunks) {
|
|
91
|
+
console.log(hit.score, hit.text);
|
|
92
|
+
console.log(hit.citation.sourceId, hit.citation.chunkIndex, hit.citation.span);
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
`retrieve()` is **return-only** — it never auto-injects into a prompt. The caller formats the cited chunks (or uses `asTool()` for the agent loop). A `RetrievedChunk` carries `{ text, score, citation }`; the `Citation` is `{ sourceId, chunkIndex, span, score, metadata? }`. The reranker is **OFF by default** (cosine ranking only) unless `config.reranker` is set.
|
|
97
|
+
|
|
98
|
+
## Rerankers — opt-in, on `ai.rag.*`
|
|
99
|
+
|
|
100
|
+
Both are exposed as namespaced helpers on the factory (`ai.rag.keywordReranker`, `ai.rag.llmReranker`).
|
|
101
|
+
|
|
102
|
+
```ts
|
|
103
|
+
// Zero-dependency lexical reranker (BM25-lite keyword overlap).
|
|
104
|
+
ai.rag.keywordReranker({ weight: 0.5 }); // weight in [0,1]; 1 = pure keyword, 0 = keep cosine
|
|
105
|
+
|
|
106
|
+
// Model-backed reranker — one or more model calls per retrieval.
|
|
107
|
+
ai.rag.llmReranker({ model: openai.model({ name: "gpt-4o-mini" }), batchSize: 10 });
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
- **`keywordReranker`** — blends lexical query-term overlap with the original cosine score by `weight`; ties keep the incoming cosine order. Costs nothing beyond string splits. Reach for it when embedding-only ranking buries a keyword-rich chunk.
|
|
111
|
+
- **`llmReranker`** — asks an LLM to grade each over-fetched candidate `0..1` and sorts by that. Candidates the model fails to score keep their cosine score, so a garbled reply degrades gracefully. Opt in only when precision beats latency/cost. Both implement the `RagReranker` contract, so you can write your own.
|
|
112
|
+
|
|
113
|
+
## `asTool()` — drop retrieval into an agent's `tools: []`
|
|
114
|
+
|
|
115
|
+
```ts
|
|
116
|
+
const agent = ai.agent({
|
|
117
|
+
model: openai.model({ name: "gpt-4o" }),
|
|
118
|
+
tools: [kb.asTool({ name: "search_docs", retrieve: { topK: 6 } })],
|
|
119
|
+
});
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Input is `{ query: string }`; output is the `RetrieveResult`. Default tool name is `retrieve_<rag.name>`; `description` and a per-tool `retrieve` override are optional. Built via the same composite-as-tool engine every other primitive uses.
|
|
123
|
+
|
|
124
|
+
## `clear()`
|
|
125
|
+
|
|
126
|
+
```ts
|
|
127
|
+
await kb.clear(); // drops every entry written under this rag's namespace
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Advanced
|
|
131
|
+
|
|
132
|
+
- `cacheVectorStore(driver)` + the `VectorStore` contract are exported for swapping in a custom store.
|
|
133
|
+
- A stored chunk's namespaced key is `${namespace}.${sourceId}.${chunkIndex}`.
|
|
134
|
+
|
|
135
|
+
## See also
|
|
136
|
+
|
|
137
|
+
- [`@warlock.js/ai/embed-text/SKILL.md`](@warlock.js/ai/embed-text/SKILL.md) — the `sdk.embedder` primitive this consumes
|
|
138
|
+
- [`@warlock.js/ai/define-ai-tool/SKILL.md`](@warlock.js/ai/define-ai-tool/SKILL.md) — what `asTool()` produces
|
|
139
|
+
- [`@warlock.js/ai/run-ai-agent/SKILL.md`](@warlock.js/ai/run-ai-agent/SKILL.md) — wiring the retrieval tool into an agent
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: run-ai-team
|
|
3
|
+
description: 'Manager-led multi-agent teams with ai.team({...}) — transparent sugar over ai.supervisor that maps a manager → route/router, members → intents, and a gate → evaluate, returning a REAL SupervisorContract (no new loop, no new contract). Covers the built-in gate strings "quality" (review-then-fix) and "verify" (test-then-fix), a custom gate function, role mapping (roles / gateKey), and the verbatim supervisor pass-throughs (goal / output / state / maxIterations / snapshotStore / on / observe). Triggers: `ai.team`, `TeamConfig`, `TeamGate`, `TeamGateFn`, `TeamMemberValue`, `manager`, `members`, `gate`, `roles`, `gateKey`, `buildQualityGate`, `buildVerifyGate`, `SupervisorContract`, `ReportType`; ''build a team of agents'', ''manager that delegates to members'', ''review then fix loop'', ''test then fix loop'', ''quality gate for a multi-agent run'', ''report type team''; typical import `import { ai } from "@warlock.js/ai"`. Skip: routing one input to a fixed roster directly — `@warlock.js/ai/run-supervisor/SKILL.md` (team is sugar over it); durable cross-turn sessions — `@warlock.js/ai/run-orchestrator/SKILL.md`; LLM-generated plans — `@warlock.js/ai/run-planner/SKILL.md`; competing libs `crewai`, `autogen`.'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# `ai.team()` — manager + members + a quality gate
|
|
7
|
+
|
|
8
|
+
`ai.team(config)` is **thin, transparent sugar over `ai.supervisor`**. It builds a `SupervisorConfig` from the team-shaped config, calls `supervisor(...)`, and returns the **unchanged** `SupervisorContract<TOutput>` — the exact object `ai.supervisor` returns. So `ctx.intents.<member>.execute()`, `.asTool()`, `.resume()`, snapshots, and events all stay intact. `team()` owns no loop of its own.
|
|
9
|
+
|
|
10
|
+
The mapping:
|
|
11
|
+
|
|
12
|
+
| team field | becomes supervisor field |
|
|
13
|
+
| --- | --- |
|
|
14
|
+
| `manager` | `route` (deterministic `{ route }`) XOR `router` (an agent / `RouterEntry`) |
|
|
15
|
+
| `members` | `intents` |
|
|
16
|
+
| `gate` | `evaluate` |
|
|
17
|
+
|
|
18
|
+
Everything else passes through 1:1 — the sole exception is the report/result `type`, which is stamped `"team"` (see [Pass-throughs](#pass-throughs-verbatim-supervisor-semantics)).
|
|
19
|
+
|
|
20
|
+
## Shape
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
import { ai } from "@warlock.js/ai";
|
|
24
|
+
import { v } from "@warlock.js/seal";
|
|
25
|
+
|
|
26
|
+
const codeTeam = ai.team({
|
|
27
|
+
name: "code-team",
|
|
28
|
+
goal: "Ship a tested module that passes review.",
|
|
29
|
+
manager: techLeadRouter, // an agent / RouterEntry → router; or { route } → deterministic
|
|
30
|
+
members: { builder, reviewer, fixer }, // role-name → agent | workflow
|
|
31
|
+
gate: "quality", // "quality" | "verify" | (ctx) => EvaluateResult
|
|
32
|
+
output: v.object({ code: v.string() }),
|
|
33
|
+
maxIterations: 6, // default 10 (supervisor's)
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const { data, report } = await codeTeam.execute("Build a debounce<T> utility.");
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
A `member` is an `AgentContract` or a `WorkflowInstance` (the `TeamMemberValue` union — the autocomplete-friendly common case; callback / full-entry intent shapes still work when forwarded). The keys are both the role names the manager routes to AND the keys `ctx.intents.<role>` exposes (the supervisor escape hatch is preserved).
|
|
40
|
+
|
|
41
|
+
## The manager — `route` XOR `router`
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
// LLM-driven manager: an agent (or RouterEntry) → becomes SupervisorConfig.router
|
|
45
|
+
manager: techLeadRouter
|
|
46
|
+
|
|
47
|
+
// Deterministic manager: { route } → becomes SupervisorConfig.route
|
|
48
|
+
manager: { route: (ctx) => (ctx.iteration === 0 ? "builder" : "reviewer") }
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Exactly one form is forwarded — mutually exclusive, mirroring the supervisor's own `router` XOR `route` rule. A malformed manager surfaces the existing `SupervisorFailedError` downstream.
|
|
52
|
+
|
|
53
|
+
## Gates — `"quality"` | `"verify"` | a function
|
|
54
|
+
|
|
55
|
+
A `gate` string selects a pre-built `evaluate` strategy; both desugar to a concrete `evaluate` callback that leans entirely on the already-shipped `EvaluateResult` semantics (`satisfied` terminates, `reassignTo` re-dispatches the fixer, `feedback` threads forward) — **no new termination or loop code**.
|
|
56
|
+
|
|
57
|
+
### `gate: "quality"` — review-then-fix
|
|
58
|
+
|
|
59
|
+
After each iteration's members settle and merge into supervisor `state`, the gate reads `state.approved` (the `gateKey`, default `"approved"`). If truthy → `{ satisfied: true }`; otherwise → `{ reassignTo: "fixer", feedback: String(state.notes ?? "") }`. The reviewer's feedback (`state.notes`) threads into the next iteration.
|
|
60
|
+
|
|
61
|
+
### `gate: "verify"` — test-then-fix
|
|
62
|
+
|
|
63
|
+
Identical shape but keyed on the tester's pass/fail slice `state.passed` (default `gateKey`) rather than a subjective score. On failure it re-dispatches the fixer; there is no feedback channel for a pass/fail signal, so none is threaded.
|
|
64
|
+
|
|
65
|
+
> The named member whose `output` schema writes the gate slice must produce a boolean into `gateKey`.
|
|
66
|
+
|
|
67
|
+
### A custom gate (full escape hatch)
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
gate: (ctx) => {
|
|
71
|
+
if (ctx.state.score >= 0.9) return { satisfied: true };
|
|
72
|
+
return { reassignTo: "fixer", feedback: ctx.state.review };
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Supplying a `TeamGateFn` instead of a string opts out of the sugar entirely while keeping the rest of `team()`'s wiring — it forwards straight to `SupervisorConfig.evaluate` with zero wrapping.
|
|
77
|
+
|
|
78
|
+
## Role mapping — `roles` + `gateKey`
|
|
79
|
+
|
|
80
|
+
The string gates default to canonical role names. Override when your `members` keys differ:
|
|
81
|
+
|
|
82
|
+
```ts
|
|
83
|
+
ai.team({
|
|
84
|
+
name: "qa-team",
|
|
85
|
+
manager,
|
|
86
|
+
members: { author, critic, patcher },
|
|
87
|
+
gate: "quality",
|
|
88
|
+
roles: { reviewer: "critic", fixer: "patcher" }, // map gate roles → your member keys
|
|
89
|
+
gateKey: "ok", // state slice the gate reads
|
|
90
|
+
});
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
**Construction-time validation:** when the gate is a string, the resolved `fixer` (and, for `"quality"`, the `reviewer`) role is checked against `members`. A missing role throws an authoring-style `SupervisorFailedError` (`context: { authoring: true }`) immediately — rather than silently starving until `maxIterations`.
|
|
94
|
+
|
|
95
|
+
## Pass-throughs (verbatim supervisor semantics)
|
|
96
|
+
|
|
97
|
+
`goal`, `output`, `state`, `maxIterations`, `snapshotStore`, `on`, `observe`, and `version` are forwarded unchanged. Because the returned object IS a supervisor, observability rides the same generic `Observer` seam every other flow uses (see `observe-ai-flows`), and snapshot resume works exactly as on a bare supervisor.
|
|
98
|
+
|
|
99
|
+
The one behavioural difference from a bare supervisor: a team stamps **`type: "team"`** on both its report (a first-class `ReportType`, was `"supervisor"`) and its result, so Panoptic and any `Observer` can distinguish, group, filter, and label team runs as their own type rather than folding them into plain supervisor runs. Everything else passes through 1:1.
|
|
100
|
+
|
|
101
|
+
A member callback that calls `agent.execute()` **directly** still nests `member → agent → tool` under the member span with usage rolled up — the same ambient-`RunFrame` auto-nesting as a bare supervisor. See [`@warlock.js/ai/run-supervisor/SKILL.md`](@warlock.js/ai/run-supervisor/SKILL.md).
|
|
102
|
+
|
|
103
|
+
## See also
|
|
104
|
+
|
|
105
|
+
- [`@warlock.js/ai/run-supervisor/SKILL.md`](@warlock.js/ai/run-supervisor/SKILL.md) — the primitive team desugars into (intents, route/router, evaluate, ctx.intents)
|
|
106
|
+
- [`@warlock.js/ai/run-orchestrator/SKILL.md`](@warlock.js/ai/run-orchestrator/SKILL.md) — wrap a team in durable cross-turn session state
|
|
107
|
+
- [`@warlock.js/ai/observe-ai-flows/SKILL.md`](@warlock.js/ai/observe-ai-flows/SKILL.md) — the `observe` seam a team inherits
|
|
@@ -86,6 +86,8 @@ result.compaction; // CompactionResult when a turn compacted (and
|
|
|
86
86
|
|
|
87
87
|
`report.children[]` carries ONLY the current turn's dispatched primitive reports. Full session history lives on `report.turns[]` — a `children[]` walker will NOT reach prior turns (intentional). Child `supervisor.*` / `agent.*` events bubble up unmodified under their own identity.
|
|
88
88
|
|
|
89
|
+
A turn callback that calls `agent.execute()` **directly** (not via `ctx.run` / `ctx.intents`) still nests `callback → agent → tool` inside the turn's report tree, with usage rolled up and the session's `sessionId` stamped onto the captured subtree — an ambient `RunFrame` handles the self-attach. See [`@warlock.js/ai/run-supervisor/SKILL.md`](@warlock.js/ai/run-supervisor/SKILL.md).
|
|
90
|
+
|
|
89
91
|
**`awaiting-input` is the only non-terminal status across the unified result tree.** Code branching on `status === "completed"` MUST explicitly handle `"awaiting-input"` as a session-continues path, not a failure.
|
|
90
92
|
|
|
91
93
|
## `iterate` — single dispatch vs. internal supervisor
|