@warlock.js/core 4.8.0 → 4.8.1
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 +6 -0
- package/esm/connectors/ai-connector.mjs +1 -1
- package/package.json +12 -9
- package/esm/ai/src/agent/agent-input-builder.mjs +0 -133
- package/esm/ai/src/agent/agent-input-builder.mjs.map +0 -1
- package/esm/ai/src/agent/agent-log-event.mjs +0 -101
- package/esm/ai/src/agent/agent-log-event.mjs.map +0 -1
- package/esm/ai/src/agent/agent-stream.mjs +0 -82
- package/esm/ai/src/agent/agent-stream.mjs.map +0 -1
- package/esm/ai/src/agent/agent-to-stream-event.mjs +0 -86
- package/esm/ai/src/agent/agent-to-stream-event.mjs.map +0 -1
- package/esm/ai/src/agent/agent.mjs +0 -1276
- package/esm/ai/src/agent/agent.mjs.map +0 -1
- package/esm/ai/src/agent/index.mjs +0 -5
- package/esm/ai/src/agent/json-stream-guard.mjs +0 -400
- package/esm/ai/src/agent/json-stream-guard.mjs.map +0 -1
- package/esm/ai/src/agent/signature.mjs +0 -57
- package/esm/ai/src/agent/signature.mjs.map +0 -1
- package/esm/ai/src/agent/snapshot.mjs +0 -101
- package/esm/ai/src/agent/snapshot.mjs.map +0 -1
- package/esm/ai/src/agent/spawn-sub-agent.mjs +0 -68
- package/esm/ai/src/agent/spawn-sub-agent.mjs.map +0 -1
- package/esm/ai/src/ai.mjs +0 -191
- package/esm/ai/src/ai.mjs.map +0 -1
- package/esm/ai/src/batch/batch.mjs +0 -198
- package/esm/ai/src/batch/batch.mjs.map +0 -1
- package/esm/ai/src/batch/index.mjs +0 -3
- package/esm/ai/src/batch/run-batch-item.mjs +0 -100
- package/esm/ai/src/batch/run-batch-item.mjs.map +0 -1
- package/esm/ai/src/batch/run-with-concurrency.mjs +0 -39
- package/esm/ai/src/batch/run-with-concurrency.mjs.map +0 -1
- package/esm/ai/src/checkpoint/memory.mjs +0 -0
- package/esm/ai/src/checkpoint/memory.mjs.map +0 -1
- package/esm/ai/src/checkpoint/pg.mjs +0 -265
- package/esm/ai/src/checkpoint/pg.mjs.map +0 -1
- package/esm/ai/src/checkpoint/redis.mjs +0 -200
- package/esm/ai/src/checkpoint/redis.mjs.map +0 -1
- package/esm/ai/src/config.mjs +0 -59
- package/esm/ai/src/config.mjs.map +0 -1
- package/esm/ai/src/contracts/end.type.mjs +0 -47
- package/esm/ai/src/contracts/end.type.mjs.map +0 -1
- package/esm/ai/src/errors/agent-cancelled-error.mjs +0 -43
- package/esm/ai/src/errors/agent-cancelled-error.mjs.map +0 -1
- package/esm/ai/src/errors/agent-drift-error.mjs +0 -31
- package/esm/ai/src/errors/agent-drift-error.mjs.map +0 -1
- package/esm/ai/src/errors/agent-execution-error.mjs +0 -35
- package/esm/ai/src/errors/agent-execution-error.mjs.map +0 -1
- package/esm/ai/src/errors/agent-max-trips-error.mjs +0 -41
- package/esm/ai/src/errors/agent-max-trips-error.mjs.map +0 -1
- package/esm/ai/src/errors/ai-error.mjs +0 -68
- package/esm/ai/src/errors/ai-error.mjs.map +0 -1
- package/esm/ai/src/errors/budget-exceeded-error.mjs +0 -31
- package/esm/ai/src/errors/budget-exceeded-error.mjs.map +0 -1
- package/esm/ai/src/errors/content-filter-error.mjs +0 -28
- package/esm/ai/src/errors/content-filter-error.mjs.map +0 -1
- package/esm/ai/src/errors/context-length-exceeded-error.mjs +0 -31
- package/esm/ai/src/errors/context-length-exceeded-error.mjs.map +0 -1
- package/esm/ai/src/errors/guardrail-violation-error.mjs +0 -41
- package/esm/ai/src/errors/guardrail-violation-error.mjs.map +0 -1
- package/esm/ai/src/errors/index.mjs +0 -40
- package/esm/ai/src/errors/invalid-request-error.mjs +0 -31
- package/esm/ai/src/errors/invalid-request-error.mjs.map +0 -1
- package/esm/ai/src/errors/max-iterations-error.mjs +0 -32
- package/esm/ai/src/errors/max-iterations-error.mjs.map +0 -1
- package/esm/ai/src/errors/max-steps-exceeded-error.mjs +0 -21
- package/esm/ai/src/errors/max-steps-exceeded-error.mjs.map +0 -1
- package/esm/ai/src/errors/orchestrator-cancelled-error.mjs +0 -31
- package/esm/ai/src/errors/orchestrator-cancelled-error.mjs.map +0 -1
- package/esm/ai/src/errors/orchestrator-config-error.mjs +0 -30
- package/esm/ai/src/errors/orchestrator-config-error.mjs.map +0 -1
- package/esm/ai/src/errors/orchestrator-drift-error.mjs +0 -37
- package/esm/ai/src/errors/orchestrator-drift-error.mjs.map +0 -1
- package/esm/ai/src/errors/orchestrator-failed-error.mjs +0 -36
- package/esm/ai/src/errors/orchestrator-failed-error.mjs.map +0 -1
- package/esm/ai/src/errors/outbound-policy-error.mjs +0 -32
- package/esm/ai/src/errors/outbound-policy-error.mjs.map +0 -1
- package/esm/ai/src/errors/planner-cancelled-error.mjs +0 -29
- package/esm/ai/src/errors/planner-cancelled-error.mjs.map +0 -1
- package/esm/ai/src/errors/planner-drift-error.mjs +0 -33
- package/esm/ai/src/errors/planner-drift-error.mjs.map +0 -1
- package/esm/ai/src/errors/planner-failed-error.mjs +0 -37
- package/esm/ai/src/errors/planner-failed-error.mjs.map +0 -1
- package/esm/ai/src/errors/planner-plan-invalid-error.mjs +0 -25
- package/esm/ai/src/errors/planner-plan-invalid-error.mjs.map +0 -1
- package/esm/ai/src/errors/prompt-refinement-error.mjs +0 -27
- package/esm/ai/src/errors/prompt-refinement-error.mjs.map +0 -1
- package/esm/ai/src/errors/provider-auth-error.mjs +0 -26
- package/esm/ai/src/errors/provider-auth-error.mjs.map +0 -1
- package/esm/ai/src/errors/provider-error.mjs +0 -42
- package/esm/ai/src/errors/provider-error.mjs.map +0 -1
- package/esm/ai/src/errors/provider-rate-limit-error.mjs +0 -31
- package/esm/ai/src/errors/provider-rate-limit-error.mjs.map +0 -1
- package/esm/ai/src/errors/provider-timeout-error.mjs +0 -26
- package/esm/ai/src/errors/provider-timeout-error.mjs.map +0 -1
- package/esm/ai/src/errors/quota-exceeded-error.mjs +0 -40
- package/esm/ai/src/errors/quota-exceeded-error.mjs.map +0 -1
- package/esm/ai/src/errors/routing-error.mjs +0 -23
- package/esm/ai/src/errors/routing-error.mjs.map +0 -1
- package/esm/ai/src/errors/schema-validation-error.mjs +0 -37
- package/esm/ai/src/errors/schema-validation-error.mjs.map +0 -1
- package/esm/ai/src/errors/step-failed-error.mjs +0 -19
- package/esm/ai/src/errors/step-failed-error.mjs.map +0 -1
- package/esm/ai/src/errors/supervisor-cancelled-error.mjs +0 -29
- package/esm/ai/src/errors/supervisor-cancelled-error.mjs.map +0 -1
- package/esm/ai/src/errors/supervisor-drift-error.mjs +0 -30
- package/esm/ai/src/errors/supervisor-drift-error.mjs.map +0 -1
- package/esm/ai/src/errors/supervisor-failed-error.mjs +0 -43
- package/esm/ai/src/errors/supervisor-failed-error.mjs.map +0 -1
- package/esm/ai/src/errors/supervisor-routing-error.mjs +0 -39
- package/esm/ai/src/errors/supervisor-routing-error.mjs.map +0 -1
- package/esm/ai/src/errors/tool-execution-error.mjs +0 -32
- package/esm/ai/src/errors/tool-execution-error.mjs.map +0 -1
- package/esm/ai/src/errors/workflow-cancelled-error.mjs +0 -23
- package/esm/ai/src/errors/workflow-cancelled-error.mjs.map +0 -1
- package/esm/ai/src/errors/workflow-drift-error.mjs +0 -24
- package/esm/ai/src/errors/workflow-drift-error.mjs.map +0 -1
- package/esm/ai/src/errors/workflow-error.mjs +0 -18
- package/esm/ai/src/errors/workflow-error.mjs.map +0 -1
- package/esm/ai/src/eval/dataset.mjs +0 -112
- package/esm/ai/src/eval/dataset.mjs.map +0 -1
- package/esm/ai/src/eval/eval-runner.mjs +0 -135
- package/esm/ai/src/eval/eval-runner.mjs.map +0 -1
- package/esm/ai/src/eval/index.mjs +0 -48
- package/esm/ai/src/eval/index.mjs.map +0 -1
- package/esm/ai/src/eval/judge-scorer.mjs +0 -87
- package/esm/ai/src/eval/judge-scorer.mjs.map +0 -1
- package/esm/ai/src/eval/regression.mjs +0 -51
- package/esm/ai/src/eval/regression.mjs.map +0 -1
- package/esm/ai/src/eval/report-json.mjs +0 -33
- package/esm/ai/src/eval/report-json.mjs.map +0 -1
- package/esm/ai/src/eval/report-junit.mjs +0 -60
- package/esm/ai/src/eval/report-junit.mjs.map +0 -1
- package/esm/ai/src/eval/scorers.mjs +0 -101
- package/esm/ai/src/eval/scorers.mjs.map +0 -1
- package/esm/ai/src/guard/detectors/index.mjs +0 -6
- package/esm/ai/src/guard/detectors/injection.mjs +0 -254
- package/esm/ai/src/guard/detectors/injection.mjs.map +0 -1
- package/esm/ai/src/guard/detectors/moderation.mjs +0 -134
- package/esm/ai/src/guard/detectors/moderation.mjs.map +0 -1
- package/esm/ai/src/guard/detectors/pii.mjs +0 -199
- package/esm/ai/src/guard/detectors/pii.mjs.map +0 -1
- package/esm/ai/src/guard/detectors/topic.mjs +0 -99
- package/esm/ai/src/guard/detectors/topic.mjs.map +0 -1
- package/esm/ai/src/guard/errors.mjs +0 -18
- package/esm/ai/src/guard/errors.mjs.map +0 -1
- package/esm/ai/src/guard/guard.mjs +0 -209
- package/esm/ai/src/guard/guard.mjs.map +0 -1
- package/esm/ai/src/guard/guardrail.mjs +0 -22
- package/esm/ai/src/guard/guardrail.mjs.map +0 -1
- package/esm/ai/src/human/errors.mjs +0 -60
- package/esm/ai/src/human/errors.mjs.map +0 -1
- package/esm/ai/src/human/human-approval.mjs +0 -170
- package/esm/ai/src/human/human-approval.mjs.map +0 -1
- package/esm/ai/src/human/policy.mjs +0 -67
- package/esm/ai/src/human/policy.mjs.map +0 -1
- package/esm/ai/src/human/register.mjs +0 -37
- package/esm/ai/src/human/register.mjs.map +0 -1
- package/esm/ai/src/human/resume-seed.mjs +0 -53
- package/esm/ai/src/human/resume-seed.mjs.map +0 -1
- package/esm/ai/src/human/resume.mjs +0 -121
- package/esm/ai/src/human/resume.mjs.map +0 -1
- package/esm/ai/src/human/stores/index.mjs +0 -5
- package/esm/ai/src/human/stores/memory.mjs +0 -91
- package/esm/ai/src/human/stores/memory.mjs.map +0 -1
- package/esm/ai/src/human/stores/pg.mjs +0 -220
- package/esm/ai/src/human/stores/pg.mjs.map +0 -1
- package/esm/ai/src/human/stores/redis.mjs +0 -201
- package/esm/ai/src/human/stores/redis.mjs.map +0 -1
- package/esm/ai/src/image/image-cost.mjs +0 -55
- package/esm/ai/src/image/image-cost.mjs.map +0 -1
- package/esm/ai/src/image/image.mjs +0 -112
- package/esm/ai/src/image/image.mjs.map +0 -1
- package/esm/ai/src/image/index.mjs +0 -4
- package/esm/ai/src/index.mjs +0 -196
- package/esm/ai/src/memory/derive-id.mjs +0 -24
- package/esm/ai/src/memory/derive-id.mjs.map +0 -1
- package/esm/ai/src/memory/episodic-memory.mjs +0 -106
- package/esm/ai/src/memory/episodic-memory.mjs.map +0 -1
- package/esm/ai/src/memory/memory.mjs +0 -166
- package/esm/ai/src/memory/memory.mjs.map +0 -1
- package/esm/ai/src/memory/procedural-memory.mjs +0 -103
- package/esm/ai/src/memory/procedural-memory.mjs.map +0 -1
- package/esm/ai/src/memory/semantic-memory.mjs +0 -80
- package/esm/ai/src/memory/semantic-memory.mjs.map +0 -1
- package/esm/ai/src/memory/working-memory.mjs +0 -62
- package/esm/ai/src/memory/working-memory.mjs.map +0 -1
- package/esm/ai/src/middleware/builtins/budget.mjs +0 -219
- package/esm/ai/src/middleware/builtins/budget.mjs.map +0 -1
- package/esm/ai/src/middleware/builtins/guardrail.mjs +0 -76
- package/esm/ai/src/middleware/builtins/guardrail.mjs.map +0 -1
- package/esm/ai/src/middleware/builtins/semantic-cache.mjs +0 -149
- package/esm/ai/src/middleware/builtins/semantic-cache.mjs.map +0 -1
- package/esm/ai/src/middleware/helpers/compose.mjs +0 -52
- package/esm/ai/src/middleware/helpers/compose.mjs.map +0 -1
- package/esm/ai/src/middleware/helpers/for-tool.mjs +0 -80
- package/esm/ai/src/middleware/helpers/for-tool.mjs.map +0 -1
- package/esm/ai/src/middleware/index.mjs +0 -10
- package/esm/ai/src/middleware/pipeline.mjs +0 -100
- package/esm/ai/src/middleware/pipeline.mjs.map +0 -1
- package/esm/ai/src/middleware/utils/extract-user-text.mjs +0 -47
- package/esm/ai/src/middleware/utils/extract-user-text.mjs.map +0 -1
- package/esm/ai/src/middleware/utils/namespaced-state.mjs +0 -60
- package/esm/ai/src/middleware/utils/namespaced-state.mjs.map +0 -1
- package/esm/ai/src/mock/index.mjs +0 -4
- package/esm/ai/src/mock/mock-agent.mjs +0 -3
- package/esm/ai/src/mock/mock-router.mjs +0 -58
- package/esm/ai/src/mock/mock-router.mjs.map +0 -1
- package/esm/ai/src/model/fallback-model.mjs +0 -218
- package/esm/ai/src/model/fallback-model.mjs.map +0 -1
- package/esm/ai/src/model/index.mjs +0 -3
- package/esm/ai/src/object-stream/index.mjs +0 -4
- package/esm/ai/src/object-stream/parse-partial-json.mjs +0 -78
- package/esm/ai/src/object-stream/parse-partial-json.mjs.map +0 -1
- package/esm/ai/src/object-stream/stream-object.mjs +0 -97
- package/esm/ai/src/object-stream/stream-object.mjs.map +0 -1
- package/esm/ai/src/observe/index.mjs +0 -4
- package/esm/ai/src/observe/observer-registry.mjs +0 -35
- package/esm/ai/src/observe/observer-registry.mjs.map +0 -1
- package/esm/ai/src/observe/resolve-observers.mjs +0 -73
- package/esm/ai/src/observe/resolve-observers.mjs.map +0 -1
- package/esm/ai/src/orchestrator/as-tool.mjs +0 -98
- package/esm/ai/src/orchestrator/as-tool.mjs.map +0 -1
- package/esm/ai/src/orchestrator/checkpoint.mjs +0 -75
- package/esm/ai/src/orchestrator/checkpoint.mjs.map +0 -1
- package/esm/ai/src/orchestrator/commands.mjs +0 -34
- package/esm/ai/src/orchestrator/commands.mjs.map +0 -1
- package/esm/ai/src/orchestrator/compaction.mjs +0 -206
- package/esm/ai/src/orchestrator/compaction.mjs.map +0 -1
- package/esm/ai/src/orchestrator/dispatch.mjs +0 -171
- package/esm/ai/src/orchestrator/dispatch.mjs.map +0 -1
- package/esm/ai/src/orchestrator/emitter.mjs +0 -85
- package/esm/ai/src/orchestrator/emitter.mjs.map +0 -1
- package/esm/ai/src/orchestrator/execution.mjs +0 -395
- package/esm/ai/src/orchestrator/execution.mjs.map +0 -1
- package/esm/ai/src/orchestrator/index.mjs +0 -11
- package/esm/ai/src/orchestrator/load.mjs +0 -49
- package/esm/ai/src/orchestrator/load.mjs.map +0 -1
- package/esm/ai/src/orchestrator/lock.mjs +0 -75
- package/esm/ai/src/orchestrator/lock.mjs.map +0 -1
- package/esm/ai/src/orchestrator/memory.mjs +0 -141
- package/esm/ai/src/orchestrator/memory.mjs.map +0 -1
- package/esm/ai/src/orchestrator/orchestrator-stream.mjs +0 -98
- package/esm/ai/src/orchestrator/orchestrator-stream.mjs.map +0 -1
- package/esm/ai/src/orchestrator/orchestrator.mjs +0 -206
- package/esm/ai/src/orchestrator/orchestrator.mjs.map +0 -1
- package/esm/ai/src/orchestrator/resume.mjs +0 -74
- package/esm/ai/src/orchestrator/resume.mjs.map +0 -1
- package/esm/ai/src/orchestrator/session-lock.mjs +0 -83
- package/esm/ai/src/orchestrator/session-lock.mjs.map +0 -1
- package/esm/ai/src/orchestrator/signature.mjs +0 -120
- package/esm/ai/src/orchestrator/signature.mjs.map +0 -1
- package/esm/ai/src/orchestrator/window.mjs +0 -56
- package/esm/ai/src/orchestrator/window.mjs.map +0 -1
- package/esm/ai/src/planner/dag-scheduler.mjs +0 -97
- package/esm/ai/src/planner/dag-scheduler.mjs.map +0 -1
- package/esm/ai/src/planner/index.mjs +0 -6
- package/esm/ai/src/planner/plan-prompt.mjs +0 -31
- package/esm/ai/src/planner/plan-prompt.mjs.map +0 -1
- package/esm/ai/src/planner/plan-schema.mjs +0 -120
- package/esm/ai/src/planner/plan-schema.mjs.map +0 -1
- package/esm/ai/src/planner/planner-run.mjs +0 -769
- package/esm/ai/src/planner/planner-run.mjs.map +0 -1
- package/esm/ai/src/planner/planner.mjs +0 -144
- package/esm/ai/src/planner/planner.mjs.map +0 -1
- package/esm/ai/src/planner/signature.mjs +0 -27
- package/esm/ai/src/planner/signature.mjs.map +0 -1
- package/esm/ai/src/planner/snapshot.mjs +0 -95
- package/esm/ai/src/planner/snapshot.mjs.map +0 -1
- package/esm/ai/src/prompt/errors.mjs +0 -73
- package/esm/ai/src/prompt/errors.mjs.map +0 -1
- package/esm/ai/src/prompt/index.mjs +0 -4
- package/esm/ai/src/prompt/prompt-langfuse-sync.mjs +0 -104
- package/esm/ai/src/prompt/prompt-langfuse-sync.mjs.map +0 -1
- package/esm/ai/src/prompt/prompt-validate.mjs +0 -170
- package/esm/ai/src/prompt/prompt-validate.mjs.map +0 -1
- package/esm/ai/src/prompt/prompt.mjs +0 -218
- package/esm/ai/src/prompt/prompt.mjs.map +0 -1
- package/esm/ai/src/prompts/index.mjs +0 -3
- package/esm/ai/src/prompts/prompts-manager.mjs +0 -410
- package/esm/ai/src/prompts/prompts-manager.mjs.map +0 -1
- package/esm/ai/src/prompts/prompts-validate.mjs +0 -0
- package/esm/ai/src/prompts/prompts-validate.mjs.map +0 -1
- package/esm/ai/src/rag/as-tool.mjs +0 -48
- package/esm/ai/src/rag/as-tool.mjs.map +0 -1
- package/esm/ai/src/rag/chunk/chunk.mjs +0 -44
- package/esm/ai/src/rag/chunk/chunk.mjs.map +0 -1
- package/esm/ai/src/rag/chunk/fixed.mjs +0 -32
- package/esm/ai/src/rag/chunk/fixed.mjs.map +0 -1
- package/esm/ai/src/rag/chunk/markdown.mjs +0 -75
- package/esm/ai/src/rag/chunk/markdown.mjs.map +0 -1
- package/esm/ai/src/rag/chunk/recursive.mjs +0 -132
- package/esm/ai/src/rag/chunk/recursive.mjs.map +0 -1
- package/esm/ai/src/rag/chunk/sentence.mjs +0 -73
- package/esm/ai/src/rag/chunk/sentence.mjs.map +0 -1
- package/esm/ai/src/rag/hybrid/bm25.mjs +0 -51
- package/esm/ai/src/rag/hybrid/bm25.mjs.map +0 -1
- package/esm/ai/src/rag/hybrid/hybrid-rank.mjs +0 -29
- package/esm/ai/src/rag/hybrid/hybrid-rank.mjs.map +0 -1
- package/esm/ai/src/rag/hybrid/rrf.mjs +0 -30
- package/esm/ai/src/rag/hybrid/rrf.mjs.map +0 -1
- package/esm/ai/src/rag/index.mjs +0 -18
- package/esm/ai/src/rag/loaders/errors.mjs +0 -25
- package/esm/ai/src/rag/loaders/errors.mjs.map +0 -1
- package/esm/ai/src/rag/loaders/index.mjs +0 -7
- package/esm/ai/src/rag/loaders/load-html.mjs +0 -138
- package/esm/ai/src/rag/loaders/load-html.mjs.map +0 -1
- package/esm/ai/src/rag/loaders/load-pdf.mjs +0 -150
- package/esm/ai/src/rag/loaders/load-pdf.mjs.map +0 -1
- package/esm/ai/src/rag/loaders/load-text.mjs +0 -60
- package/esm/ai/src/rag/loaders/load-text.mjs.map +0 -1
- package/esm/ai/src/rag/loaders/load-web.mjs +0 -89
- package/esm/ai/src/rag/loaders/load-web.mjs.map +0 -1
- package/esm/ai/src/rag/rag.mjs +0 -126
- package/esm/ai/src/rag/rag.mjs.map +0 -1
- package/esm/ai/src/rag/rerank/keyword-reranker.mjs +0 -58
- package/esm/ai/src/rag/rerank/keyword-reranker.mjs.map +0 -1
- package/esm/ai/src/rag/rerank/llm-reranker.mjs +0 -85
- package/esm/ai/src/rag/rerank/llm-reranker.mjs.map +0 -1
- package/esm/ai/src/rag/retrieve.mjs +0 -68
- package/esm/ai/src/rag/retrieve.mjs.map +0 -1
- package/esm/ai/src/rag/store/cache-vector-store.mjs +0 -48
- package/esm/ai/src/rag/store/cache-vector-store.mjs.map +0 -1
- package/esm/ai/src/rag/store/pg-vector-store.mjs +0 -328
- package/esm/ai/src/rag/store/pg-vector-store.mjs.map +0 -1
- package/esm/ai/src/rag/transforms/multi-query.mjs +0 -41
- package/esm/ai/src/rag/transforms/multi-query.mjs.map +0 -1
- package/esm/ai/src/security/index.mjs +0 -5
- package/esm/ai/src/security/outbound-policy.mjs +0 -187
- package/esm/ai/src/security/outbound-policy.mjs.map +0 -1
- package/esm/ai/src/security/private-ip.mjs +0 -48
- package/esm/ai/src/security/private-ip.mjs.map +0 -1
- package/esm/ai/src/security/redact.mjs +0 -60
- package/esm/ai/src/security/redact.mjs.map +0 -1
- package/esm/ai/src/serve/serve.mjs +0 -90
- package/esm/ai/src/serve/serve.mjs.map +0 -1
- package/esm/ai/src/serve/sse.mjs +0 -25
- package/esm/ai/src/serve/sse.mjs.map +0 -1
- package/esm/ai/src/serve/stream-to-sse.mjs +0 -37
- package/esm/ai/src/serve/stream-to-sse.mjs.map +0 -1
- package/esm/ai/src/skills/catalog.mjs +0 -140
- package/esm/ai/src/skills/catalog.mjs.map +0 -1
- package/esm/ai/src/skills/index.mjs +0 -11
- package/esm/ai/src/skills/load-skill-tool.mjs +0 -65
- package/esm/ai/src/skills/load-skill-tool.mjs.map +0 -1
- package/esm/ai/src/skills/save-skill-tool.mjs +0 -65
- package/esm/ai/src/skills/save-skill-tool.mjs.map +0 -1
- package/esm/ai/src/skills/skills.mjs +0 -109
- package/esm/ai/src/skills/skills.mjs.map +0 -1
- package/esm/ai/src/skills/sources/directory-source.mjs +0 -108
- package/esm/ai/src/skills/sources/directory-source.mjs.map +0 -1
- package/esm/ai/src/skills/sources/index.mjs +0 -27
- package/esm/ai/src/skills/sources/index.mjs.map +0 -1
- package/esm/ai/src/skills/sources/parse-frontmatter.mjs +0 -46
- package/esm/ai/src/skills/sources/parse-frontmatter.mjs.map +0 -1
- package/esm/ai/src/skills/sources/store-source.mjs +0 -15
- package/esm/ai/src/skills/sources/store-source.mjs.map +0 -1
- package/esm/ai/src/skills/sources/url-source.mjs +0 -117
- package/esm/ai/src/skills/sources/url-source.mjs.map +0 -1
- package/esm/ai/src/snapshot/memory.mjs +0 -81
- package/esm/ai/src/snapshot/memory.mjs.map +0 -1
- package/esm/ai/src/snapshot/pg.mjs +0 -146
- package/esm/ai/src/snapshot/pg.mjs.map +0 -1
- package/esm/ai/src/snapshot/redis.mjs +0 -101
- package/esm/ai/src/snapshot/redis.mjs.map +0 -1
- package/esm/ai/src/speech/index.mjs +0 -3
- package/esm/ai/src/speech/speech.mjs +0 -122
- package/esm/ai/src/speech/speech.mjs.map +0 -1
- package/esm/ai/src/supervisor/as-tool.mjs +0 -74
- package/esm/ai/src/supervisor/as-tool.mjs.map +0 -1
- package/esm/ai/src/supervisor/cancellation.mjs +0 -22
- package/esm/ai/src/supervisor/cancellation.mjs.map +0 -1
- package/esm/ai/src/supervisor/decide.mjs +0 -272
- package/esm/ai/src/supervisor/decide.mjs.map +0 -1
- package/esm/ai/src/supervisor/emitter.mjs +0 -47
- package/esm/ai/src/supervisor/emitter.mjs.map +0 -1
- package/esm/ai/src/supervisor/entries.mjs +0 -206
- package/esm/ai/src/supervisor/entries.mjs.map +0 -1
- package/esm/ai/src/supervisor/execution.mjs +0 -1921
- package/esm/ai/src/supervisor/execution.mjs.map +0 -1
- package/esm/ai/src/supervisor/fan-out.mjs +0 -65
- package/esm/ai/src/supervisor/fan-out.mjs.map +0 -1
- package/esm/ai/src/supervisor/index.mjs +0 -14
- package/esm/ai/src/supervisor/router-factory.mjs +0 -141
- package/esm/ai/src/supervisor/router-factory.mjs.map +0 -1
- package/esm/ai/src/supervisor/router-prompt.mjs +0 -52
- package/esm/ai/src/supervisor/router-prompt.mjs.map +0 -1
- package/esm/ai/src/supervisor/signature.mjs +0 -89
- package/esm/ai/src/supervisor/signature.mjs.map +0 -1
- package/esm/ai/src/supervisor/snapshot.mjs +0 -69
- package/esm/ai/src/supervisor/snapshot.mjs.map +0 -1
- package/esm/ai/src/supervisor/supervisor-stream.mjs +0 -89
- package/esm/ai/src/supervisor/supervisor-stream.mjs.map +0 -1
- package/esm/ai/src/supervisor/supervisor.mjs +0 -144
- package/esm/ai/src/supervisor/supervisor.mjs.map +0 -1
- package/esm/ai/src/system-prompt/index.mjs +0 -7
- package/esm/ai/src/system-prompt/instruction.mjs +0 -57
- package/esm/ai/src/system-prompt/instruction.mjs.map +0 -1
- package/esm/ai/src/system-prompt/persona.mjs +0 -57
- package/esm/ai/src/system-prompt/persona.mjs.map +0 -1
- package/esm/ai/src/system-prompt/refined-system-prompt.mjs +0 -461
- package/esm/ai/src/system-prompt/refined-system-prompt.mjs.map +0 -1
- package/esm/ai/src/system-prompt/render-placeholders.mjs +0 -58
- package/esm/ai/src/system-prompt/render-placeholders.mjs.map +0 -1
- package/esm/ai/src/system-prompt/system-prompt.mjs +0 -286
- package/esm/ai/src/system-prompt/system-prompt.mjs.map +0 -1
- package/esm/ai/src/team/gates.mjs +0 -48
- package/esm/ai/src/team/gates.mjs.map +0 -1
- package/esm/ai/src/team/index.mjs +0 -3
- package/esm/ai/src/team/team.mjs +0 -94
- package/esm/ai/src/team/team.mjs.map +0 -1
- package/esm/ai/src/tool/executable-as-tool.mjs +0 -81
- package/esm/ai/src/tool/executable-as-tool.mjs.map +0 -1
- package/esm/ai/src/tool/index.mjs +0 -4
- package/esm/ai/src/tool/tool.mjs +0 -185
- package/esm/ai/src/tool/tool.mjs.map +0 -1
- package/esm/ai/src/transcribe/audio-input.mjs +0 -84
- package/esm/ai/src/transcribe/audio-input.mjs.map +0 -1
- package/esm/ai/src/transcribe/index.mjs +0 -4
- package/esm/ai/src/transcribe/transcribe.mjs +0 -127
- package/esm/ai/src/transcribe/transcribe.mjs.map +0 -1
- package/esm/ai/src/utils/compute-cost.mjs +0 -112
- package/esm/ai/src/utils/compute-cost.mjs.map +0 -1
- package/esm/ai/src/utils/extract-json-lenient.mjs +0 -97
- package/esm/ai/src/utils/extract-json-lenient.mjs.map +0 -1
- package/esm/ai/src/utils/extract-json-payload.mjs +0 -39
- package/esm/ai/src/utils/extract-json-payload.mjs.map +0 -1
- package/esm/ai/src/utils/generate-run-id.mjs +0 -23
- package/esm/ai/src/utils/generate-run-id.mjs.map +0 -1
- package/esm/ai/src/utils/index.mjs +0 -12
- package/esm/ai/src/utils/json-schema.mjs +0 -89
- package/esm/ai/src/utils/json-schema.mjs.map +0 -1
- package/esm/ai/src/utils/prepare-attachment-part.mjs +0 -232
- package/esm/ai/src/utils/prepare-attachment-part.mjs.map +0 -1
- package/esm/ai/src/utils/resolve-attachment.mjs +0 -74
- package/esm/ai/src/utils/resolve-attachment.mjs.map +0 -1
- package/esm/ai/src/utils/run-context.mjs +0 -89
- package/esm/ai/src/utils/run-context.mjs.map +0 -1
- package/esm/ai/src/utils/safe-json-parse.mjs +0 -22
- package/esm/ai/src/utils/safe-json-parse.mjs.map +0 -1
- package/esm/ai/src/utils/stamp-report-lineage.mjs +0 -45
- package/esm/ai/src/utils/stamp-report-lineage.mjs.map +0 -1
- package/esm/ai/src/vcr/cassette-io.mjs +0 -57
- package/esm/ai/src/vcr/cassette-io.mjs.map +0 -1
- package/esm/ai/src/vcr/errors.mjs +0 -37
- package/esm/ai/src/vcr/errors.mjs.map +0 -1
- package/esm/ai/src/vcr/hash-request.mjs +0 -118
- package/esm/ai/src/vcr/hash-request.mjs.map +0 -1
- package/esm/ai/src/vcr/index.mjs +0 -5
- package/esm/ai/src/vcr/vcr.mjs +0 -248
- package/esm/ai/src/vcr/vcr.mjs.map +0 -1
- package/esm/ai/src/workflow/as-tool.mjs +0 -49
- package/esm/ai/src/workflow/as-tool.mjs.map +0 -1
- package/esm/ai/src/workflow/cancellation.mjs +0 -44
- package/esm/ai/src/workflow/cancellation.mjs.map +0 -1
- package/esm/ai/src/workflow/emitter.mjs +0 -40
- package/esm/ai/src/workflow/emitter.mjs.map +0 -1
- package/esm/ai/src/workflow/engine.mjs +0 -363
- package/esm/ai/src/workflow/engine.mjs.map +0 -1
- package/esm/ai/src/workflow/index.mjs +0 -5
- package/esm/ai/src/workflow/retry.mjs +0 -32
- package/esm/ai/src/workflow/retry.mjs.map +0 -1
- package/esm/ai/src/workflow/router.mjs +0 -56
- package/esm/ai/src/workflow/router.mjs.map +0 -1
- package/esm/ai/src/workflow/run-scoped-emitter.mjs +0 -32
- package/esm/ai/src/workflow/run-scoped-emitter.mjs.map +0 -1
- package/esm/ai/src/workflow/signature.mjs +0 -34
- package/esm/ai/src/workflow/signature.mjs.map +0 -1
- package/esm/ai/src/workflow/snapshot.mjs +0 -77
- package/esm/ai/src/workflow/snapshot.mjs.map +0 -1
- package/esm/ai/src/workflow/state.mjs +0 -37
- package/esm/ai/src/workflow/state.mjs.map +0 -1
- package/esm/ai/src/workflow/step-runner.mjs +0 -370
- package/esm/ai/src/workflow/step-runner.mjs.map +0 -1
- package/esm/ai/src/workflow/step.mjs +0 -37
- package/esm/ai/src/workflow/step.mjs.map +0 -1
- package/esm/ai/src/workflow/workflow.mjs +0 -122
- package/esm/ai/src/workflow/workflow.mjs.map +0 -1
- package/esm/ai-openai/src/embedder.mjs +0 -4
- package/esm/ai-openai/src/image.mjs +0 -5
- package/esm/ai-openai/src/index.mjs +0 -7
- package/esm/ai-openai/src/model.mjs +0 -5
- package/esm/ai-openai/src/sdk.mjs +0 -9
- package/esm/ai-openai/src/speech.mjs +0 -5
- package/esm/ai-openai/src/transcription.mjs +0 -6
- package/esm/ai-openai/src/utils/index.mjs +0 -5
- package/esm/ai-openai/src/utils/to-openai-messages.mjs +0 -3
- package/esm/ai-openai/src/utils/to-openai-tools.mjs +0 -3
- package/esm/ai-openai/src/utils/wrap-openai-error.mjs +0 -4
- package/esm/node_modules/langfuse/lib/index.mjs +0 -1827
- package/esm/node_modules/langfuse/lib/index.mjs.map +0 -1
- package/esm/node_modules/langfuse-core/lib/index.mjs +0 -1770
- package/esm/node_modules/langfuse-core/lib/index.mjs.map +0 -1
- package/esm/node_modules/mustache/mustache.mjs +0 -587
- package/esm/node_modules/mustache/mustache.mjs.map +0 -1
- package/esm/node_modules/openai/_vendor/partial-json-parser/parser.mjs +0 -180
- package/esm/node_modules/openai/_vendor/partial-json-parser/parser.mjs.map +0 -1
- package/esm/node_modules/openai/auth/workload-identity-auth.mjs +0 -80
- package/esm/node_modules/openai/auth/workload-identity-auth.mjs.map +0 -1
- package/esm/node_modules/openai/azure.mjs +0 -82
- package/esm/node_modules/openai/azure.mjs.map +0 -1
- package/esm/node_modules/openai/client.mjs +0 -638
- package/esm/node_modules/openai/client.mjs.map +0 -1
- package/esm/node_modules/openai/core/api-promise.mjs +0 -75
- package/esm/node_modules/openai/core/api-promise.mjs.map +0 -1
- package/esm/node_modules/openai/core/error.mjs +0 -110
- package/esm/node_modules/openai/core/error.mjs.map +0 -1
- package/esm/node_modules/openai/core/pagination.mjs +0 -160
- package/esm/node_modules/openai/core/pagination.mjs.map +0 -1
- package/esm/node_modules/openai/core/resource.mjs +0 -10
- package/esm/node_modules/openai/core/resource.mjs.map +0 -1
- package/esm/node_modules/openai/core/streaming.mjs +0 -238
- package/esm/node_modules/openai/core/streaming.mjs.map +0 -1
- package/esm/node_modules/openai/index.mjs +0 -8
- package/esm/node_modules/openai/internal/decoders/line.mjs +0 -91
- package/esm/node_modules/openai/internal/decoders/line.mjs.map +0 -1
- package/esm/node_modules/openai/internal/detect-platform.mjs +0 -123
- package/esm/node_modules/openai/internal/detect-platform.mjs.map +0 -1
- package/esm/node_modules/openai/internal/errors.mjs +0 -26
- package/esm/node_modules/openai/internal/errors.mjs.map +0 -1
- package/esm/node_modules/openai/internal/headers.mjs +0 -65
- package/esm/node_modules/openai/internal/headers.mjs.map +0 -1
- package/esm/node_modules/openai/internal/parse.mjs +0 -41
- package/esm/node_modules/openai/internal/parse.mjs.map +0 -1
- package/esm/node_modules/openai/internal/qs/formats.mjs +0 -12
- package/esm/node_modules/openai/internal/qs/formats.mjs.map +0 -1
- package/esm/node_modules/openai/internal/qs/stringify.mjs +0 -179
- package/esm/node_modules/openai/internal/qs/stringify.mjs.map +0 -1
- package/esm/node_modules/openai/internal/qs/utils.mjs +0 -65
- package/esm/node_modules/openai/internal/qs/utils.mjs.map +0 -1
- package/esm/node_modules/openai/internal/request-options.mjs +0 -11
- package/esm/node_modules/openai/internal/request-options.mjs.map +0 -1
- package/esm/node_modules/openai/internal/shims.mjs +0 -77
- package/esm/node_modules/openai/internal/shims.mjs.map +0 -1
- package/esm/node_modules/openai/internal/to-file.mjs +0 -63
- package/esm/node_modules/openai/internal/to-file.mjs.map +0 -1
- package/esm/node_modules/openai/internal/tslib.mjs +0 -16
- package/esm/node_modules/openai/internal/tslib.mjs.map +0 -1
- package/esm/node_modules/openai/internal/uploads.mjs +0 -94
- package/esm/node_modules/openai/internal/uploads.mjs.map +0 -1
- package/esm/node_modules/openai/internal/utils/base64.mjs +0 -22
- package/esm/node_modules/openai/internal/utils/base64.mjs.map +0 -1
- package/esm/node_modules/openai/internal/utils/bytes.mjs +0 -26
- package/esm/node_modules/openai/internal/utils/bytes.mjs.map +0 -1
- package/esm/node_modules/openai/internal/utils/env.mjs +0 -16
- package/esm/node_modules/openai/internal/utils/env.mjs.map +0 -1
- package/esm/node_modules/openai/internal/utils/log.mjs +0 -58
- package/esm/node_modules/openai/internal/utils/log.mjs.map +0 -1
- package/esm/node_modules/openai/internal/utils/path.mjs +0 -62
- package/esm/node_modules/openai/internal/utils/path.mjs.map +0 -1
- package/esm/node_modules/openai/internal/utils/query.mjs +0 -10
- package/esm/node_modules/openai/internal/utils/query.mjs.map +0 -1
- package/esm/node_modules/openai/internal/utils/sleep.mjs +0 -6
- package/esm/node_modules/openai/internal/utils/sleep.mjs.map +0 -1
- package/esm/node_modules/openai/internal/utils/uuid.mjs +0 -18
- package/esm/node_modules/openai/internal/utils/uuid.mjs.map +0 -1
- package/esm/node_modules/openai/internal/utils/values.mjs +0 -41
- package/esm/node_modules/openai/internal/utils/values.mjs.map +0 -1
- package/esm/node_modules/openai/lib/AbstractChatCompletionRunner.mjs +0 -247
- package/esm/node_modules/openai/lib/AbstractChatCompletionRunner.mjs.map +0 -1
- package/esm/node_modules/openai/lib/AssistantStream.mjs +0 -472
- package/esm/node_modules/openai/lib/AssistantStream.mjs.map +0 -1
- package/esm/node_modules/openai/lib/ChatCompletionRunner.mjs +0 -26
- package/esm/node_modules/openai/lib/ChatCompletionRunner.mjs.map +0 -1
- package/esm/node_modules/openai/lib/ChatCompletionStream.mjs +0 -423
- package/esm/node_modules/openai/lib/ChatCompletionStream.mjs.map +0 -1
- package/esm/node_modules/openai/lib/ChatCompletionStreamingRunner.mjs +0 -26
- package/esm/node_modules/openai/lib/ChatCompletionStreamingRunner.mjs.map +0 -1
- package/esm/node_modules/openai/lib/EventStream.mjs +0 -163
- package/esm/node_modules/openai/lib/EventStream.mjs.map +0 -1
- package/esm/node_modules/openai/lib/ResponsesParser.mjs +0 -94
- package/esm/node_modules/openai/lib/ResponsesParser.mjs.map +0 -1
- package/esm/node_modules/openai/lib/RunnableFunction.mjs +0 -8
- package/esm/node_modules/openai/lib/RunnableFunction.mjs.map +0 -1
- package/esm/node_modules/openai/lib/Util.mjs +0 -19
- package/esm/node_modules/openai/lib/Util.mjs.map +0 -1
- package/esm/node_modules/openai/lib/chatCompletionUtils.mjs +0 -11
- package/esm/node_modules/openai/lib/chatCompletionUtils.mjs.map +0 -1
- package/esm/node_modules/openai/lib/parser.mjs +0 -88
- package/esm/node_modules/openai/lib/parser.mjs.map +0 -1
- package/esm/node_modules/openai/lib/responses/ResponseStream.mjs +0 -231
- package/esm/node_modules/openai/lib/responses/ResponseStream.mjs.map +0 -1
- package/esm/node_modules/openai/resources/admin/admin.mjs +0 -15
- package/esm/node_modules/openai/resources/admin/admin.mjs.map +0 -1
- package/esm/node_modules/openai/resources/admin/organization/admin-api-keys.mjs +0 -81
- package/esm/node_modules/openai/resources/admin/organization/admin-api-keys.mjs.map +0 -1
- package/esm/node_modules/openai/resources/admin/organization/audit-logs.mjs +0 -31
- package/esm/node_modules/openai/resources/admin/organization/audit-logs.mjs.map +0 -1
- package/esm/node_modules/openai/resources/admin/organization/certificates.mjs +0 -153
- package/esm/node_modules/openai/resources/admin/organization/certificates.mjs.map +0 -1
- package/esm/node_modules/openai/resources/admin/organization/data-retention.mjs +0 -42
- package/esm/node_modules/openai/resources/admin/organization/data-retention.mjs.map +0 -1
- package/esm/node_modules/openai/resources/admin/organization/groups/groups.mjs +0 -106
- package/esm/node_modules/openai/resources/admin/organization/groups/groups.mjs.map +0 -1
- package/esm/node_modules/openai/resources/admin/organization/groups/roles.mjs +0 -88
- package/esm/node_modules/openai/resources/admin/organization/groups/roles.mjs.map +0 -1
- package/esm/node_modules/openai/resources/admin/organization/groups/users.mjs +0 -88
- package/esm/node_modules/openai/resources/admin/organization/groups/users.mjs.map +0 -1
- package/esm/node_modules/openai/resources/admin/organization/invites.mjs +0 -83
- package/esm/node_modules/openai/resources/admin/organization/invites.mjs.map +0 -1
- package/esm/node_modules/openai/resources/admin/organization/organization.mjs +0 -45
- package/esm/node_modules/openai/resources/admin/organization/organization.mjs.map +0 -1
- package/esm/node_modules/openai/resources/admin/organization/projects/api-keys.mjs +0 -72
- package/esm/node_modules/openai/resources/admin/organization/projects/api-keys.mjs.map +0 -1
- package/esm/node_modules/openai/resources/admin/organization/projects/certificates.mjs +0 -78
- package/esm/node_modules/openai/resources/admin/organization/projects/certificates.mjs.map +0 -1
- package/esm/node_modules/openai/resources/admin/organization/projects/data-retention.mjs +0 -46
- package/esm/node_modules/openai/resources/admin/organization/projects/data-retention.mjs.map +0 -1
- package/esm/node_modules/openai/resources/admin/organization/projects/groups/groups.mjs +0 -95
- package/esm/node_modules/openai/resources/admin/organization/projects/groups/groups.mjs.map +0 -1
- package/esm/node_modules/openai/resources/admin/organization/projects/groups/roles.mjs +0 -91
- package/esm/node_modules/openai/resources/admin/organization/projects/groups/roles.mjs.map +0 -1
- package/esm/node_modules/openai/resources/admin/organization/projects/hosted-tool-permissions.mjs +0 -45
- package/esm/node_modules/openai/resources/admin/organization/projects/hosted-tool-permissions.mjs.map +0 -1
- package/esm/node_modules/openai/resources/admin/organization/projects/model-permissions.mjs +0 -63
- package/esm/node_modules/openai/resources/admin/organization/projects/model-permissions.mjs.map +0 -1
- package/esm/node_modules/openai/resources/admin/organization/projects/projects.mjs +0 -137
- package/esm/node_modules/openai/resources/admin/organization/projects/projects.mjs.map +0 -1
- package/esm/node_modules/openai/resources/admin/organization/projects/rate-limits.mjs +0 -51
- package/esm/node_modules/openai/resources/admin/organization/projects/rate-limits.mjs.map +0 -1
- package/esm/node_modules/openai/resources/admin/organization/projects/roles.mjs +0 -108
- package/esm/node_modules/openai/resources/admin/organization/projects/roles.mjs.map +0 -1
- package/esm/node_modules/openai/resources/admin/organization/projects/service-accounts.mjs +0 -112
- package/esm/node_modules/openai/resources/admin/organization/projects/service-accounts.mjs.map +0 -1
- package/esm/node_modules/openai/resources/admin/organization/projects/spend-alerts.mjs +0 -106
- package/esm/node_modules/openai/resources/admin/organization/projects/spend-alerts.mjs.map +0 -1
- package/esm/node_modules/openai/resources/admin/organization/projects/users/roles.mjs +0 -91
- package/esm/node_modules/openai/resources/admin/organization/projects/users/roles.mjs.map +0 -1
- package/esm/node_modules/openai/resources/admin/organization/projects/users/users.mjs +0 -118
- package/esm/node_modules/openai/resources/admin/organization/projects/users/users.mjs.map +0 -1
- package/esm/node_modules/openai/resources/admin/organization/roles.mjs +0 -96
- package/esm/node_modules/openai/resources/admin/organization/roles.mjs.map +0 -1
- package/esm/node_modules/openai/resources/admin/organization/spend-alerts.mjs +0 -97
- package/esm/node_modules/openai/resources/admin/organization/spend-alerts.mjs.map +0 -1
- package/esm/node_modules/openai/resources/admin/organization/usage.mjs +0 -207
- package/esm/node_modules/openai/resources/admin/organization/usage.mjs.map +0 -1
- package/esm/node_modules/openai/resources/admin/organization/users/roles.mjs +0 -88
- package/esm/node_modules/openai/resources/admin/organization/users/roles.mjs.map +0 -1
- package/esm/node_modules/openai/resources/admin/organization/users/users.mjs +0 -82
- package/esm/node_modules/openai/resources/admin/organization/users/users.mjs.map +0 -1
- package/esm/node_modules/openai/resources/audio/audio.mjs +0 -21
- package/esm/node_modules/openai/resources/audio/audio.mjs.map +0 -1
- package/esm/node_modules/openai/resources/audio/speech.mjs +0 -39
- package/esm/node_modules/openai/resources/audio/speech.mjs.map +0 -1
- package/esm/node_modules/openai/resources/audio/transcriptions.mjs +0 -22
- package/esm/node_modules/openai/resources/audio/transcriptions.mjs.map +0 -1
- package/esm/node_modules/openai/resources/audio/translations.mjs +0 -21
- package/esm/node_modules/openai/resources/audio/translations.mjs.map +0 -1
- package/esm/node_modules/openai/resources/batches.mjs +0 -54
- package/esm/node_modules/openai/resources/batches.mjs.map +0 -1
- package/esm/node_modules/openai/resources/beta/assistants.mjs +0 -78
- package/esm/node_modules/openai/resources/beta/assistants.mjs.map +0 -1
- package/esm/node_modules/openai/resources/beta/beta.mjs +0 -24
- package/esm/node_modules/openai/resources/beta/beta.mjs.map +0 -1
- package/esm/node_modules/openai/resources/beta/chatkit/chatkit.mjs +0 -18
- package/esm/node_modules/openai/resources/beta/chatkit/chatkit.mjs.map +0 -1
- package/esm/node_modules/openai/resources/beta/chatkit/sessions.mjs +0 -49
- package/esm/node_modules/openai/resources/beta/chatkit/sessions.mjs.map +0 -1
- package/esm/node_modules/openai/resources/beta/chatkit/threads.mjs +0 -85
- package/esm/node_modules/openai/resources/beta/chatkit/threads.mjs.map +0 -1
- package/esm/node_modules/openai/resources/beta/realtime/realtime.mjs +0 -21
- package/esm/node_modules/openai/resources/beta/realtime/realtime.mjs.map +0 -1
- package/esm/node_modules/openai/resources/beta/realtime/sessions.mjs +0 -33
- package/esm/node_modules/openai/resources/beta/realtime/sessions.mjs.map +0 -1
- package/esm/node_modules/openai/resources/beta/realtime/transcription-sessions.mjs +0 -33
- package/esm/node_modules/openai/resources/beta/realtime/transcription-sessions.mjs.map +0 -1
- package/esm/node_modules/openai/resources/beta/threads/messages.mjs +0 -83
- package/esm/node_modules/openai/resources/beta/threads/messages.mjs.map +0 -1
- package/esm/node_modules/openai/resources/beta/threads/runs/runs.mjs +0 -183
- package/esm/node_modules/openai/resources/beta/threads/runs/runs.mjs.map +0 -1
- package/esm/node_modules/openai/resources/beta/threads/runs/steps.mjs +0 -45
- package/esm/node_modules/openai/resources/beta/threads/runs/steps.mjs.map +0 -1
- package/esm/node_modules/openai/resources/beta/threads/threads.mjs +0 -101
- package/esm/node_modules/openai/resources/beta/threads/threads.mjs.map +0 -1
- package/esm/node_modules/openai/resources/chat/chat.mjs +0 -15
- package/esm/node_modules/openai/resources/chat/chat.mjs.map +0 -1
- package/esm/node_modules/openai/resources/chat/completions/completions.mjs +0 -123
- package/esm/node_modules/openai/resources/chat/completions/completions.mjs.map +0 -1
- package/esm/node_modules/openai/resources/chat/completions/index.mjs +0 -7
- package/esm/node_modules/openai/resources/chat/completions/messages.mjs +0 -35
- package/esm/node_modules/openai/resources/chat/completions/messages.mjs.map +0 -1
- package/esm/node_modules/openai/resources/chat/index.mjs +0 -5
- package/esm/node_modules/openai/resources/completions.mjs +0 -20
- package/esm/node_modules/openai/resources/completions.mjs.map +0 -1
- package/esm/node_modules/openai/resources/containers/containers.mjs +0 -57
- package/esm/node_modules/openai/resources/containers/containers.mjs.map +0 -1
- package/esm/node_modules/openai/resources/containers/files/content.mjs +0 -23
- package/esm/node_modules/openai/resources/containers/files/content.mjs.map +0 -1
- package/esm/node_modules/openai/resources/containers/files/files.mjs +0 -63
- package/esm/node_modules/openai/resources/containers/files/files.mjs.map +0 -1
- package/esm/node_modules/openai/resources/conversations/conversations.mjs +0 -57
- package/esm/node_modules/openai/resources/conversations/conversations.mjs.map +0 -1
- package/esm/node_modules/openai/resources/conversations/items.mjs +0 -57
- package/esm/node_modules/openai/resources/conversations/items.mjs.map +0 -1
- package/esm/node_modules/openai/resources/embeddings.mjs +0 -48
- package/esm/node_modules/openai/resources/embeddings.mjs.map +0 -1
- package/esm/node_modules/openai/resources/evals/evals.mjs +0 -73
- package/esm/node_modules/openai/resources/evals/evals.mjs.map +0 -1
- package/esm/node_modules/openai/resources/evals/runs/output-items.mjs +0 -35
- package/esm/node_modules/openai/resources/evals/runs/output-items.mjs.map +0 -1
- package/esm/node_modules/openai/resources/evals/runs/runs.mjs +0 -72
- package/esm/node_modules/openai/resources/evals/runs/runs.mjs.map +0 -1
- package/esm/node_modules/openai/resources/files.mjs +0 -111
- package/esm/node_modules/openai/resources/files.mjs.map +0 -1
- package/esm/node_modules/openai/resources/fine-tuning/alpha/alpha.mjs +0 -15
- package/esm/node_modules/openai/resources/fine-tuning/alpha/alpha.mjs.map +0 -1
- package/esm/node_modules/openai/resources/fine-tuning/alpha/graders.mjs +0 -60
- package/esm/node_modules/openai/resources/fine-tuning/alpha/graders.mjs.map +0 -1
- package/esm/node_modules/openai/resources/fine-tuning/checkpoints/checkpoints.mjs +0 -15
- package/esm/node_modules/openai/resources/fine-tuning/checkpoints/checkpoints.mjs.map +0 -1
- package/esm/node_modules/openai/resources/fine-tuning/checkpoints/permissions.mjs +0 -102
- package/esm/node_modules/openai/resources/fine-tuning/checkpoints/permissions.mjs.map +0 -1
- package/esm/node_modules/openai/resources/fine-tuning/fine-tuning.mjs +0 -24
- package/esm/node_modules/openai/resources/fine-tuning/fine-tuning.mjs.map +0 -1
- package/esm/node_modules/openai/resources/fine-tuning/jobs/checkpoints.mjs +0 -34
- package/esm/node_modules/openai/resources/fine-tuning/jobs/checkpoints.mjs.map +0 -1
- package/esm/node_modules/openai/resources/fine-tuning/jobs/jobs.mjs +0 -148
- package/esm/node_modules/openai/resources/fine-tuning/jobs/jobs.mjs.map +0 -1
- package/esm/node_modules/openai/resources/fine-tuning/methods.mjs +0 -8
- package/esm/node_modules/openai/resources/fine-tuning/methods.mjs.map +0 -1
- package/esm/node_modules/openai/resources/graders/grader-models.mjs +0 -8
- package/esm/node_modules/openai/resources/graders/grader-models.mjs.map +0 -1
- package/esm/node_modules/openai/resources/graders/graders.mjs +0 -15
- package/esm/node_modules/openai/resources/graders/graders.mjs.map +0 -1
- package/esm/node_modules/openai/resources/images.mjs +0 -46
- package/esm/node_modules/openai/resources/images.mjs.map +0 -1
- package/esm/node_modules/openai/resources/index.mjs +0 -27
- package/esm/node_modules/openai/resources/models.mjs +0 -44
- package/esm/node_modules/openai/resources/models.mjs.map +0 -1
- package/esm/node_modules/openai/resources/moderations.mjs +0 -23
- package/esm/node_modules/openai/resources/moderations.mjs.map +0 -1
- package/esm/node_modules/openai/resources/realtime/calls.mjs +0 -79
- package/esm/node_modules/openai/resources/realtime/calls.mjs.map +0 -1
- package/esm/node_modules/openai/resources/realtime/client-secrets.mjs +0 -39
- package/esm/node_modules/openai/resources/realtime/client-secrets.mjs.map +0 -1
- package/esm/node_modules/openai/resources/realtime/realtime.mjs +0 -18
- package/esm/node_modules/openai/resources/realtime/realtime.mjs.map +0 -1
- package/esm/node_modules/openai/resources/responses/input-items.mjs +0 -31
- package/esm/node_modules/openai/resources/responses/input-items.mjs.map +0 -1
- package/esm/node_modules/openai/resources/responses/input-tokens.mjs +0 -27
- package/esm/node_modules/openai/resources/responses/input-tokens.mjs.map +0 -1
- package/esm/node_modules/openai/resources/responses/responses.mjs +0 -110
- package/esm/node_modules/openai/resources/responses/responses.mjs.map +0 -1
- package/esm/node_modules/openai/resources/skills/content.mjs +0 -22
- package/esm/node_modules/openai/resources/skills/content.mjs.map +0 -1
- package/esm/node_modules/openai/resources/skills/skills.mjs +0 -69
- package/esm/node_modules/openai/resources/skills/skills.mjs.map +0 -1
- package/esm/node_modules/openai/resources/skills/versions/content.mjs +0 -23
- package/esm/node_modules/openai/resources/skills/versions/content.mjs.map +0 -1
- package/esm/node_modules/openai/resources/skills/versions/versions.mjs +0 -58
- package/esm/node_modules/openai/resources/skills/versions/versions.mjs.map +0 -1
- package/esm/node_modules/openai/resources/uploads/parts.mjs +0 -34
- package/esm/node_modules/openai/resources/uploads/parts.mjs.map +0 -1
- package/esm/node_modules/openai/resources/uploads/uploads.mjs +0 -84
- package/esm/node_modules/openai/resources/uploads/uploads.mjs.map +0 -1
- package/esm/node_modules/openai/resources/vector-stores/file-batches.mjs +0 -126
- package/esm/node_modules/openai/resources/vector-stores/file-batches.mjs.map +0 -1
- package/esm/node_modules/openai/resources/vector-stores/files.mjs +0 -147
- package/esm/node_modules/openai/resources/vector-stores/files.mjs.map +0 -1
- package/esm/node_modules/openai/resources/vector-stores/vector-stores.mjs +0 -87
- package/esm/node_modules/openai/resources/vector-stores/vector-stores.mjs.map +0 -1
- package/esm/node_modules/openai/resources/videos.mjs +0 -115
- package/esm/node_modules/openai/resources/videos.mjs.map +0 -1
- package/esm/node_modules/openai/resources/webhooks/index.mjs +0 -3
- package/esm/node_modules/openai/resources/webhooks/webhooks.mjs +0 -69
- package/esm/node_modules/openai/resources/webhooks/webhooks.mjs.map +0 -1
- package/esm/node_modules/openai/resources/webhooks.mjs +0 -4
- package/esm/node_modules/openai/streaming.mjs +0 -3
- package/esm/node_modules/openai/version.mjs +0 -6
- package/esm/node_modules/openai/version.mjs.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"pg-vector-store.mjs","names":[],"sources":["../../../../../../../../../../@warlock.js/ai/src/rag/store/pg-vector-store.ts"],"sourcesContent":["import type { VectorStore } from \"./vector-store.contract\";\n\n/**\n * Minimal `pg`-compatible client surface the Postgres {@link VectorStore}\n * depends on. Both `pg.Pool` and `pg.Client` satisfy it — the store only\n * ever calls `query`.\n *\n * `@warlock.js/ai` takes **no** hard dependency on `pg`; the dev installs\n * it (an optional peer) and passes the client in. Structurally identical\n * to the snapshot / human-interrupt stores' `PgClientLike`, so a single\n * pool can back the orchestrator checkpoint/snapshot tables, the\n * interrupt table, and this vectors table alike.\n */\nexport interface PgClientLike {\n query(text: string, params?: unknown[]): Promise<{ rows: unknown[] }>;\n}\n\n/**\n * Options for the Postgres {@link VectorStore}.\n *\n * Two mutually-supportive ways to supply the connection (mirroring\n * `ai.human.interrupt.pg`):\n * - **`client`** — pass an already-built `pg.Pool` / `pg.Client` (anything\n * satisfying {@link PgClientLike}). The store only ever calls `query`\n * and never opens or closes it; one pool can back several stores.\n * - **`connectionString`** — let the store lazily `import(\"pg\")` and build\n * its own `Pool`. `@warlock.js/ai` takes **no** hard dependency on\n * `pg` (an optional peer); when it is absent the store throws a curated\n * install string at first use, never a raw module-resolution stack trace\n * at import.\n *\n * Exactly one of the two must be present.\n */\nexport interface PgVectorStoreOptions {\n /** An already-built `pg.Pool` / `pg.Client` — anything matching {@link PgClientLike}. */\n client?: PgClientLike;\n\n /** Connection string the store passes to a lazily-imported `pg.Pool`. */\n connectionString?: string;\n\n /**\n * Backing table name. Defaults to `warlock_ai_rag_vectors`. Must be a\n * safe SQL identifier — it is interpolated into DDL/DML.\n */\n table?: string;\n\n /**\n * Embedding dimensionality used in the `CREATE TABLE` DDL emitted by\n * {@link VectorStore.schema | ensureSchema}. Defaults to `1536`\n * (OpenAI `text-embedding-3-small`). The column is declared\n * `vector(N)`; queries and upserts never re-state it, so an existing\n * table provisioned at a different size is unaffected — only the DDL\n * helper reads this.\n */\n dimensions?: number;\n\n /**\n * Approximate-nearest-neighbour index strategy baked into the DDL\n * emitted by {@link VectorStore.schema | ensureSchema}. Defaults to\n * `\"hnsw\"` (better recall/latency on modern pgvector). Use `\"ivfflat\"`\n * for the classic list-partitioned index, or `\"none\"` to emit no ANN\n * index (exact scan — correct, but linear in row count).\n */\n index?: \"hnsw\" | \"ivfflat\" | \"none\";\n\n /**\n * `lists` parameter for an `ivfflat` index (ignored for `hnsw` / `none`).\n * Defaults to `100`. Tune toward `rows / 1000` for large tables.\n */\n ivfflatLists?: number;\n}\n\n/**\n * Default backing table — provisions the store with no extra config when\n * the dev runs {@link VectorStore.schema | ensureSchema} through their\n * migration tool.\n */\nconst DEFAULT_TABLE = \"warlock_ai_rag_vectors\";\n\n/** Default embedding width baked into the DDL (OpenAI `text-embedding-3-small`). */\nconst DEFAULT_DIMENSIONS = 1536;\n\n/** Default `ivfflat` list count when that index strategy is chosen. */\nconst DEFAULT_IVFFLAT_LISTS = 100;\n\n/**\n * Allowed characters in a Postgres identifier (table name). The table name\n * is interpolated into DDL/DML, so anything outside this conservative\n * ASCII subset is rejected — interpolating an arbitrary string would be a\n * SQL-injection footgun (mirrors the snapshot / human-interrupt pg stores\n * and `@warlock.js/cache`'s `PgCacheDriver`).\n */\nconst SAFE_IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_]*$/;\n\n/**\n * Module specifier for the optional `pg` driver. Held in a `string`\n * variable so the dynamic `import()` is not statically resolved at compile\n * time — `pg` is an optional peer that need not be installed for this\n * package to type-check or for a cache-only consumer to run.\n */\nconst PG_MODULE = \"pg\";\n\n/**\n * Curated install string surfaced (at use time) when a `connectionString`\n * is configured but the optional `pg` driver is absent. Never thrown at\n * import — a cache-only consumer must be able to load this module.\n */\nconst PG_INSTALL_INSTRUCTIONS = `\nThe @warlock.js/ai Postgres vector store requires the pg package and a\nPostgres database with the pgvector extension. Install the driver with:\n\n npm install pg\n\nOr with your preferred package manager:\n\n pnpm add pg\n yarn add pg\n`.trim();\n\n/**\n * Minimal structural view of a `pg.Pool` constructor — just enough of the\n * `pg` module surface for the store to build a client when handed a\n * `connectionString`. Declared locally (rather than `typeof import(\"pg\")`)\n * so this module type-checks even when `pg` is not installed.\n */\ninterface PgModuleLike {\n Pool: new (config: { connectionString: string }) => PgClientLike;\n}\n\n/**\n * Lazily import `pg` and return a `Pool` built from `connectionString`. A\n * bare `catch` rethrows the curated install string — a missing optional\n * peer surfaces as actionable guidance, never a raw resolution error.\n */\nasync function buildPgClient(connectionString: string): Promise<PgClientLike> {\n let sdk: PgModuleLike;\n\n try {\n sdk = (await import(PG_MODULE)) as unknown as PgModuleLike;\n } catch {\n throw new Error(PG_INSTALL_INSTRUCTIONS);\n }\n\n return new sdk.Pool({ connectionString });\n}\n\n/**\n * Serialize a JS `number[]` to the pgvector text literal: `[1,2,3]`.\n * pgvector accepts a vector either as this bracketed literal or via a\n * typed parameter; passing the literal string + an explicit `::vector`\n * cast keeps the store driver-agnostic (no dependency on a registered\n * `pg` type parser).\n *\n * Non-finite components (`NaN` / `±Infinity`) are rejected — pgvector\n * stores only finite floats, and silently coercing them would corrupt the\n * index. The check is cheap relative to the embed call that produced the\n * vector.\n *\n * @example\n * vectorLiteral([1, 0.5, -2]); // \"[1,0.5,-2]\"\n */\nexport function vectorLiteral(vector: number[]): string {\n let literal = \"[\";\n\n for (let index = 0; index < vector.length; index++) {\n const component = vector[index];\n\n if (!Number.isFinite(component)) {\n throw new TypeError(\n `pgVectorStore: embedding component at index ${index} is not finite (${component}); pgvector stores only finite floats.`,\n );\n }\n\n if (index > 0) {\n literal += \",\";\n }\n\n literal += String(component);\n }\n\n return literal + \"]\";\n}\n\n/**\n * Coerce a `value` JSONB column back into the stored payload. node-postgres\n * parses `JSONB` into a JS value already, but some pool wrappers hand back\n * the raw string — be defensive across both (mirrors the snapshot store's\n * `parsePayload`).\n */\nfunction parseValue<T>(value: unknown): T {\n if (typeof value === \"string\") {\n return JSON.parse(value) as T;\n }\n\n return value as T;\n}\n\n/**\n * Coerce a pgvector cosine **distance** (`<=>`, in `[0, 2]`, 0 = identical)\n * into the cosine **similarity** score the {@link VectorStore} contract\n * declares (`[0, 1]`, 1 = identical). `pg` returns the computed distance\n * column as a string for `double precision`; parse then map `1 - distance`,\n * clamped to `[0, 1]` so a tiny floating-point overshoot never yields a\n * score just outside the contract's range.\n */\nfunction distanceToScore(distance: unknown): number {\n const value = typeof distance === \"string\" ? Number(distance) : (distance as number);\n const score = 1 - value;\n\n if (score < 0) {\n return 0;\n }\n\n if (score > 1) {\n return 1;\n }\n\n return score;\n}\n\n/**\n * Postgres + pgvector-backed {@link VectorStore} — one durable row per\n * indexed chunk, keyed by the RAG pipeline's dotted `key`\n * (`ai.rag.<name>.<sourceId>.<chunkIndex>`), with the chunk payload in a\n * `value` JSONB column and the embedding in a `vector` column.\n *\n * Owns: the three RAG vector operations against a pgvector index —\n * `upsert` (INSERT … ON CONFLICT DO UPDATE), `query` (cosine\n * `ORDER BY embedding <=> $vec` with a `threshold` floor + optional `tags`\n * overlap filter, capped at `topK`), and `removeNamespace` (prefix DELETE).\n * Also emits the reference DDL via {@link PgVectorStore.schema} (alias\n * {@link PgVectorStore.ensureSchema}).\n *\n * Does NOT own: the connection lifecycle (a dev-supplied `client` is never\n * closed; a store-built `Pool` from a `connectionString` is also left open\n * for the process to reuse) or schema migration — the dev runs the DDL\n * through their own tool; the framework never auto-migrates.\n *\n * Front it with the {@link pgVectorStore} factory — callers never `new` it.\n */\nclass PgVectorStore implements VectorStore {\n /** Validated backing table name, safe to interpolate into SQL. */\n private readonly table: string;\n\n /** Embedding width baked into the DDL. */\n private readonly dimensions: number;\n\n /** ANN index strategy baked into the DDL. */\n private readonly index: \"hnsw\" | \"ivfflat\" | \"none\";\n\n /** `lists` parameter for an `ivfflat` index. */\n private readonly ivfflatLists: number;\n\n /**\n * A ready client, or a promise resolving to one the store builds lazily\n * from a `connectionString`. Resolved once and memoized so the optional\n * `pg` import happens at most once.\n */\n private readonly clientPromise: Promise<PgClientLike>;\n\n public constructor(options: PgVectorStoreOptions) {\n const table = options.table ?? DEFAULT_TABLE;\n\n if (!SAFE_IDENTIFIER.test(table)) {\n throw new TypeError(\n `pgVectorStore: invalid table name '${table}'. Allowed: [A-Za-z_][A-Za-z0-9_]*.`,\n );\n }\n\n this.table = table;\n this.dimensions = options.dimensions ?? DEFAULT_DIMENSIONS;\n this.index = options.index ?? \"hnsw\";\n this.ivfflatLists = options.ivfflatLists ?? DEFAULT_IVFFLAT_LISTS;\n\n if (options.client) {\n if (typeof options.client.query !== \"function\") {\n throw new TypeError(\n \"pgVectorStore requires a 'client' option implementing { query(text, params) } — pass a pg.Pool or pg.Client.\",\n );\n }\n\n this.clientPromise = Promise.resolve(options.client);\n\n return;\n }\n\n if (options.connectionString) {\n // Defer the optional `pg` import to first use — a curated install\n // string surfaces from `buildPgClient`, not at construction.\n this.clientPromise = buildPgClient(options.connectionString);\n\n return;\n }\n\n throw new TypeError(\n \"pgVectorStore requires either a 'client' or a 'connectionString' option.\",\n );\n }\n\n /**\n * Resolve the backing client, surfacing the lazy `pg` import's curated\n * install string on the first call that needs it.\n */\n private client(): Promise<PgClientLike> {\n return this.clientPromise;\n }\n\n /**\n * Index `value` under `key` with its embedding `vector`. Upserts on the\n * `key` primary key — re-indexing the same chunk overwrites its payload,\n * embedding, and tags rather than appending a duplicate row. Optional\n * `tags` ride a `text[]` column so {@link query} can restrict the\n * candidate set with an array-overlap filter.\n *\n * The embedding is sent as a pgvector text literal (`$3`) cast to\n * `::vector`, so the store needs no registered `pg` type parser. `tags`\n * defaults to an empty array (never `NULL`) to keep the overlap filter's\n * `&&` semantics simple.\n */\n public async upsert(\n key: string,\n value: unknown,\n vector: number[],\n tags?: string[],\n ): Promise<void> {\n const client = await this.client();\n\n await client.query(\n `INSERT INTO ${this.table} (key, value, embedding, tags)\n VALUES ($1, $2::jsonb, $3::vector, $4::text[])\n ON CONFLICT (key) DO UPDATE\n SET value = EXCLUDED.value,\n embedding = EXCLUDED.embedding,\n tags = EXCLUDED.tags`,\n [key, JSON.stringify(value), vectorLiteral(vector), tags ?? []],\n );\n }\n\n /**\n * Return the cosine-nearest rows to `vector`, mapped to the contract's\n * `{ key, value, score }` shape. The SQL:\n *\n * - computes `embedding <=> $1::vector` (cosine **distance**) once, aliased\n * `distance`, and `ORDER BY` it ascending (nearest first);\n * - applies the `threshold` floor as `distance <= 1 - threshold`\n * (similarity `>=` threshold), so the default `0.5` floor maps to a\n * `<= 0.5` distance bound — the filter runs in SQL, not in JS, so a\n * below-floor row never crosses the wire;\n * - when `tags` are given, restricts to rows whose `tags` array overlaps\n * the requested set via `tags && $tags::text[]` (one-of semantics,\n * matching the cache store);\n * - caps the result at `topK` with `LIMIT`.\n *\n * The returned `score` is `1 - distance`, clamped to `[0, 1]`, so callers\n * see the same cosine-similarity scale the cache store emits.\n */\n public async query<T>(\n vector: number[],\n options: { topK: number; threshold?: number; tags?: string[] },\n ): Promise<{ key: string; value: T; score: number }[]> {\n const client = await this.client();\n const queryVector = vectorLiteral(vector);\n\n // $1 = query vector, $2 = topK. Optional threshold + tags are appended\n // as $3 / $4 only when present, so the prepared statement carries no\n // unused placeholders.\n const params: unknown[] = [queryVector, options.topK];\n const conditions: string[] = [];\n\n if (options.threshold !== undefined) {\n params.push(1 - options.threshold);\n conditions.push(`(embedding <=> $1::vector) <= $${params.length}`);\n }\n\n if (options.tags !== undefined && options.tags.length > 0) {\n params.push(options.tags);\n conditions.push(`tags && $${params.length}::text[]`);\n }\n\n const where = conditions.length > 0 ? `WHERE ${conditions.join(\" AND \")}` : \"\";\n\n const { rows } = await client.query(\n `SELECT key, value, (embedding <=> $1::vector) AS distance\n FROM ${this.table}\n ${where}\n ORDER BY embedding <=> $1::vector\n LIMIT $2`,\n params,\n );\n\n return (rows as Record<string, unknown>[]).map((row) => ({\n key: row.key as string,\n value: parseValue<T>(row.value),\n score: distanceToScore(row.distance),\n }));\n }\n\n /**\n * Drop every entry written under `namespace`. The RAG pipeline keys\n * chunks as `<namespace>.<sourceId>.<chunkIndex>`, so a row belongs to\n * the namespace when its `key` equals it OR begins with `<namespace>.`\n * — deleting `ai.rag.docs` must not also catch `ai.rag.docs2`. The `_`\n * and `%` LIKE wildcards in the namespace are escaped so a namespace\n * that happens to contain them is matched literally.\n */\n public async removeNamespace(namespace: string): Promise<void> {\n const client = await this.client();\n\n const escaped = namespace\n .replace(/\\\\/g, \"\\\\\\\\\")\n .replace(/_/g, \"\\\\_\")\n .replace(/%/g, \"\\\\%\");\n\n await client.query(\n `DELETE FROM ${this.table}\n WHERE key = $1 OR key LIKE $2 ESCAPE '\\\\'`,\n [namespace, `${escaped}.%`],\n );\n }\n\n /**\n * Return the reference migration DDL for this store's backing table,\n * interpolating the configured table name, embedding width, and ANN\n * index strategy. The dev runs it once through their migration tool —\n * the framework never auto-migrates.\n *\n * The emitted statements:\n * 1. `CREATE EXTENSION IF NOT EXISTS vector;` — enables pgvector (needs\n * a superuser or a role with `CREATE` on the database the first time).\n * 2. `CREATE TABLE IF NOT EXISTS <table> (key TEXT PRIMARY KEY, value\n * JSONB NOT NULL, embedding vector(<dimensions>) NOT NULL, tags\n * text[] NOT NULL DEFAULT '{}');`\n * 3. A GIN index on `tags` so the array-overlap filter stays sargable.\n * 4. The chosen ANN index over `embedding` using `vector_cosine_ops`:\n * - `\"hnsw\"` → `USING hnsw (embedding vector_cosine_ops)`;\n * - `\"ivfflat\"` → `USING ivfflat (embedding vector_cosine_ops)\n * WITH (lists = <ivfflatLists>)`;\n * - `\"none\"` → emitted as a comment (exact scan, no ANN index).\n *\n * @example\n * const store = pgVectorStore({ client: pool, dimensions: 1536 });\n * await pool.query(store.ensureSchema());\n */\n public schema(): string {\n const lines = [\n `CREATE EXTENSION IF NOT EXISTS vector;`,\n `CREATE TABLE IF NOT EXISTS ${this.table} (`,\n ` key TEXT PRIMARY KEY,`,\n ` value JSONB NOT NULL,`,\n ` embedding vector(${this.dimensions}) NOT NULL,`,\n ` tags TEXT[] NOT NULL DEFAULT '{}'`,\n `);`,\n `CREATE INDEX IF NOT EXISTS idx_${this.table}_tags`,\n ` ON ${this.table} USING gin (tags);`,\n ];\n\n if (this.index === \"hnsw\") {\n lines.push(\n `CREATE INDEX IF NOT EXISTS idx_${this.table}_embedding`,\n ` ON ${this.table} USING hnsw (embedding vector_cosine_ops);`,\n );\n } else if (this.index === \"ivfflat\") {\n lines.push(\n `CREATE INDEX IF NOT EXISTS idx_${this.table}_embedding`,\n ` ON ${this.table} USING ivfflat (embedding vector_cosine_ops)`,\n ` WITH (lists = ${this.ivfflatLists});`,\n );\n } else {\n lines.push(\n `-- No ANN index requested (index: \"none\"): cosine queries fall back`,\n `-- to an exact sequential scan, which is correct but linear in rows.`,\n );\n }\n\n return lines.join(\"\\n\");\n }\n\n /**\n * Alias for {@link PgVectorStore.schema} — reads more naturally in a\n * migration script (`await pool.query(store.ensureSchema())`). Returns\n * the identical DDL string; it does NOT execute anything against the\n * database (the store never auto-migrates).\n */\n public ensureSchema(): string {\n return this.schema();\n }\n}\n\n/**\n * The {@link VectorStore} surface plus the pg store's extra DDL helpers.\n * `schema()` / `ensureSchema()` are not part of the base contract (the\n * cache store has no backing table), so the factory's return type widens\n * it for callers that want the migration SQL.\n */\nexport interface PgVectorStoreInstance extends VectorStore {\n /** Reference migration DDL (extension + table + indexes). Never executed. */\n schema(): string;\n /** Alias for {@link PgVectorStoreInstance.schema} — reads better in a migration script. */\n ensureSchema(): string;\n}\n\n/**\n * Create a Postgres + pgvector-backed {@link VectorStore} for the RAG\n * pipeline. Either pass a live `pg.Pool` / `pg.Client` (`{ client }`) —\n * `@warlock.js/ai` never imports `pg` in that case — or a\n * `{ connectionString }` and let the store lazily `import(\"pg\")` to build\n * its own pool. When `pg` is not installed, a curated install string\n * surfaces on first use, never at import.\n *\n * Run {@link PgVectorStoreInstance.ensureSchema} through your migration\n * tool once before use (it enables the `vector` extension, creates the\n * table, and builds the tag + ANN indexes); the store never auto-migrates.\n *\n * Index and query MUST use the same embedding model — the `vector(N)`\n * column width is fixed at table-creation time from `dimensions`.\n *\n * @example\n * import { Pool } from \"pg\";\n * import { ai } from \"@warlock.js/ai\";\n *\n * const pool = new Pool({ connectionString: process.env.DATABASE_URL });\n * const store = ai.rag.pgVectorStore({ client: pool, dimensions: 1536 });\n *\n * // Once, via your migration tooling:\n * // await pool.query(store.ensureSchema());\n *\n * const kb = ai.rag({\n * name: \"docs\",\n * embedder: openai.embedder({ name: \"text-embedding-3-small\" }),\n * store,\n * });\n *\n * @example\n * // Let the store build its own pool from a connection string:\n * const store = ai.rag.pgVectorStore({\n * connectionString: process.env.DATABASE_URL,\n * index: \"ivfflat\",\n * ivfflatLists: 200,\n * });\n */\nexport function pgVectorStore(options: PgVectorStoreOptions): PgVectorStoreInstance {\n return new PgVectorStore(options);\n}\n"],"mappings":"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"}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
//#region ../@warlock.js/ai/src/rag/transforms/multi-query.ts
|
|
2
|
-
/**
|
|
3
|
-
* Multi-query expansion (A4) — ask a model for several alternative
|
|
4
|
-
* phrasings of `query`, so retrieval covers vocabulary the original
|
|
5
|
-
* wording missed (synonyms, specificity, rephrasings). Pair the variants
|
|
6
|
-
* with {@link hybridRank} / a vector search and fuse the per-variant hits.
|
|
7
|
-
*
|
|
8
|
-
* Deterministic, dependency-light parsing: the model is asked for one
|
|
9
|
-
* query per line; bullets / numbering are stripped, blanks dropped, and
|
|
10
|
-
* the set is de-duplicated. Returns the original (unless opted out) plus
|
|
11
|
-
* up to `n` variants.
|
|
12
|
-
*
|
|
13
|
-
* @example
|
|
14
|
-
* const queries = await multiQuery(model, "how do I cancel?", { n: 3 });
|
|
15
|
-
* // → ["how do I cancel?", "cancel my subscription", "end my plan", ...]
|
|
16
|
-
*/
|
|
17
|
-
async function multiQuery(model, query, options = {}) {
|
|
18
|
-
const n = options.n ?? 3;
|
|
19
|
-
const includeOriginal = options.includeOriginal ?? true;
|
|
20
|
-
const prompt = `Rewrite the following search query into ${n} alternative phrasings that would retrieve relevant documents. Output ONE query per line, no numbering or commentary.\n\nQuery: ${query}`;
|
|
21
|
-
const variants = (await model.complete([{
|
|
22
|
-
role: "user",
|
|
23
|
-
content: prompt
|
|
24
|
-
}])).content.split("\n").map((line) => line.replace(/^\s*(?:[-*•]|\d+[.)])\s*/, "").trim()).filter(Boolean);
|
|
25
|
-
const seen = /* @__PURE__ */ new Set();
|
|
26
|
-
const out = [];
|
|
27
|
-
const add = (q) => {
|
|
28
|
-
const key = q.toLowerCase();
|
|
29
|
-
if (!seen.has(key)) {
|
|
30
|
-
seen.add(key);
|
|
31
|
-
out.push(q);
|
|
32
|
-
}
|
|
33
|
-
};
|
|
34
|
-
if (includeOriginal) add(query);
|
|
35
|
-
for (const variant of variants.slice(0, n)) add(variant);
|
|
36
|
-
return out;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
//#endregion
|
|
40
|
-
export { multiQuery };
|
|
41
|
-
//# sourceMappingURL=multi-query.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"multi-query.mjs","names":[],"sources":["../../../../../../../../../../@warlock.js/ai/src/rag/transforms/multi-query.ts"],"sourcesContent":["import type { ModelContract } from \"../../contracts/model.contract\";\n\n/** Options for {@link multiQuery}. */\nexport type MultiQueryOptions = {\n /** How many alternative phrasings to request. Default 3. */\n n?: number;\n /** Include the original query in the returned list. Default true. */\n includeOriginal?: boolean;\n};\n\n/**\n * Multi-query expansion (A4) — ask a model for several alternative\n * phrasings of `query`, so retrieval covers vocabulary the original\n * wording missed (synonyms, specificity, rephrasings). Pair the variants\n * with {@link hybridRank} / a vector search and fuse the per-variant hits.\n *\n * Deterministic, dependency-light parsing: the model is asked for one\n * query per line; bullets / numbering are stripped, blanks dropped, and\n * the set is de-duplicated. Returns the original (unless opted out) plus\n * up to `n` variants.\n *\n * @example\n * const queries = await multiQuery(model, \"how do I cancel?\", { n: 3 });\n * // → [\"how do I cancel?\", \"cancel my subscription\", \"end my plan\", ...]\n */\nexport async function multiQuery(\n model: ModelContract,\n query: string,\n options: MultiQueryOptions = {},\n): Promise<string[]> {\n const n = options.n ?? 3;\n const includeOriginal = options.includeOriginal ?? true;\n\n const prompt =\n `Rewrite the following search query into ${n} alternative phrasings that would ` +\n `retrieve relevant documents. Output ONE query per line, no numbering or commentary.\\n\\n` +\n `Query: ${query}`;\n\n const response = await model.complete([{ role: \"user\", content: prompt }]);\n\n const variants = response.content\n .split(\"\\n\")\n .map(line => line.replace(/^\\s*(?:[-*•]|\\d+[.)])\\s*/, \"\").trim())\n .filter(Boolean);\n\n const seen = new Set<string>();\n const out: string[] = [];\n\n const add = (q: string) => {\n const key = q.toLowerCase();\n if (!seen.has(key)) {\n seen.add(key);\n out.push(q);\n }\n };\n\n if (includeOriginal) add(query);\n for (const variant of variants.slice(0, n)) add(variant);\n\n return out;\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAyBA,eAAsB,WACpB,OACA,OACA,UAA6B,CAAC,GACX;CACnB,MAAM,IAAI,QAAQ,KAAK;CACvB,MAAM,kBAAkB,QAAQ,mBAAmB;CAEnD,MAAM,SACJ,2CAA2C,EAAE,kIAEnC;CAIZ,MAAM,YAAW,MAFM,MAAM,SAAS,CAAC;EAAE,MAAM;EAAQ,SAAS;CAAO,CAAC,CAAC,EAEhD,CAAC,QACvB,MAAM,IAAI,CAAC,CACX,KAAI,SAAQ,KAAK,QAAQ,4BAA4B,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAChE,OAAO,OAAO;CAEjB,MAAM,uBAAO,IAAI,IAAY;CAC7B,MAAM,MAAgB,CAAC;CAEvB,MAAM,OAAO,MAAc;EACzB,MAAM,MAAM,EAAE,YAAY;EAC1B,IAAI,CAAC,KAAK,IAAI,GAAG,GAAG;GAClB,KAAK,IAAI,GAAG;GACZ,IAAI,KAAK,CAAC;EACZ;CACF;CAEA,IAAI,iBAAiB,IAAI,KAAK;CAC9B,KAAK,MAAM,WAAW,SAAS,MAAM,GAAG,CAAC,GAAG,IAAI,OAAO;CAEvD,OAAO;AACT"}
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import { isPrivateOrReservedIp } from "./private-ip.mjs";
|
|
2
|
-
import { assertUrlAllowed, fetchTextWithPolicy, guardedFetch, readTextCapped, resolveOutboundPolicy } from "./outbound-policy.mjs";
|
|
3
|
-
import { DEFAULT_SENSITIVE_KEYS, redact } from "./redact.mjs";
|
|
4
|
-
|
|
5
|
-
export { };
|
|
@@ -1,187 +0,0 @@
|
|
|
1
|
-
import { OutboundPolicyError } from "../errors/outbound-policy-error.mjs";
|
|
2
|
-
import "../errors/index.mjs";
|
|
3
|
-
import { isPrivateOrReservedIp } from "./private-ip.mjs";
|
|
4
|
-
import { lookup } from "node:dns/promises";
|
|
5
|
-
import { isIP } from "node:net";
|
|
6
|
-
|
|
7
|
-
//#region ../@warlock.js/ai/src/security/outbound-policy.ts
|
|
8
|
-
/** 5 MiB — default cap on an outbound response body. */
|
|
9
|
-
const DEFAULT_MAX_BYTES = 5 * 1024 * 1024;
|
|
10
|
-
/** 10s — default per-request timeout. */
|
|
11
|
-
const DEFAULT_TIMEOUT_MS = 1e4;
|
|
12
|
-
/**
|
|
13
|
-
* Fill an {@link OutboundPolicy} with strict defaults: https-only,
|
|
14
|
-
* private-IP deny on, 10s timeout, 5 MiB cap, global `fetch`. Idempotent
|
|
15
|
-
* — resolving an already-resolved policy yields the same shape.
|
|
16
|
-
*/
|
|
17
|
-
function resolveOutboundPolicy(policy = {}) {
|
|
18
|
-
return {
|
|
19
|
-
allowedSchemes: policy.allowedSchemes ?? ["https"],
|
|
20
|
-
hostAllowlist: policy.hostAllowlist,
|
|
21
|
-
denyPrivateIPsAfterDNS: policy.denyPrivateIPsAfterDNS ?? true,
|
|
22
|
-
maxBytes: policy.maxBytes ?? DEFAULT_MAX_BYTES,
|
|
23
|
-
timeoutMs: policy.timeoutMs ?? DEFAULT_TIMEOUT_MS,
|
|
24
|
-
signal: policy.signal,
|
|
25
|
-
fetch: policy.fetch ?? globalThis.fetch
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
/** Strip the `[ ]` IPv6 brackets `URL.hostname` keeps. */
|
|
29
|
-
function stripBrackets(host) {
|
|
30
|
-
return host.startsWith("[") && host.endsWith("]") ? host.slice(1, -1) : host;
|
|
31
|
-
}
|
|
32
|
-
/** Whether `host` equals or is a subdomain of any allowlist entry. */
|
|
33
|
-
function hostAllowed(host, allowlist) {
|
|
34
|
-
const lower = host.toLowerCase();
|
|
35
|
-
return allowlist.some((entry) => {
|
|
36
|
-
const e = entry.toLowerCase();
|
|
37
|
-
return lower === e || lower.endsWith(`.${e}`);
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* Validate a URL against the policy BEFORE any network call: scheme
|
|
42
|
-
* allowlist, host allowlist, and (when enabled) a DNS resolution that
|
|
43
|
-
* rejects private / loopback / link-local / metadata addresses — the SSRF
|
|
44
|
-
* guard. Returns the parsed `URL` on success; throws
|
|
45
|
-
* {@link OutboundPolicyError} otherwise.
|
|
46
|
-
*/
|
|
47
|
-
async function assertUrlAllowed(rawUrl, policy) {
|
|
48
|
-
let url;
|
|
49
|
-
try {
|
|
50
|
-
url = new URL(rawUrl);
|
|
51
|
-
} catch {
|
|
52
|
-
throw new OutboundPolicyError(`outbound request blocked — invalid URL: ${rawUrl}`, { context: { url: rawUrl } });
|
|
53
|
-
}
|
|
54
|
-
const scheme = url.protocol.replace(/:$/, "").toLowerCase();
|
|
55
|
-
if (!policy.allowedSchemes.some((s) => s.toLowerCase() === scheme)) throw new OutboundPolicyError(`outbound request blocked — scheme "${scheme}" is not allowed (allowed: ${policy.allowedSchemes.join(", ")})`, { context: {
|
|
56
|
-
url: rawUrl,
|
|
57
|
-
scheme
|
|
58
|
-
} });
|
|
59
|
-
const host = stripBrackets(url.hostname);
|
|
60
|
-
if (policy.hostAllowlist && !hostAllowed(host, policy.hostAllowlist)) throw new OutboundPolicyError(`outbound request blocked — host "${host}" is not in the allowlist`, { context: {
|
|
61
|
-
url: rawUrl,
|
|
62
|
-
host
|
|
63
|
-
} });
|
|
64
|
-
if (policy.denyPrivateIPsAfterDNS) await assertHostNotPrivate(host, rawUrl);
|
|
65
|
-
return url;
|
|
66
|
-
}
|
|
67
|
-
/**
|
|
68
|
-
* Reject when `host` is — or resolves to — a private / reserved address.
|
|
69
|
-
* IP literals are checked directly; hostnames are resolved via DNS and
|
|
70
|
-
* every returned address is checked (a public name pointing inward is
|
|
71
|
-
* caught). A resolution failure fails closed.
|
|
72
|
-
*/
|
|
73
|
-
async function assertHostNotPrivate(host, rawUrl) {
|
|
74
|
-
if (isIP(host) !== 0) {
|
|
75
|
-
if (isPrivateOrReservedIp(host)) throw new OutboundPolicyError(`outbound request blocked — "${host}" is a private/reserved address`, { context: {
|
|
76
|
-
url: rawUrl,
|
|
77
|
-
address: host
|
|
78
|
-
} });
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
81
|
-
let addresses;
|
|
82
|
-
try {
|
|
83
|
-
addresses = await lookup(host, { all: true });
|
|
84
|
-
} catch (cause) {
|
|
85
|
-
throw new OutboundPolicyError(`outbound request blocked — could not resolve host "${host}" to verify it is public`, {
|
|
86
|
-
cause,
|
|
87
|
-
context: {
|
|
88
|
-
url: rawUrl,
|
|
89
|
-
host
|
|
90
|
-
}
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
for (const { address } of addresses) if (isPrivateOrReservedIp(address)) throw new OutboundPolicyError(`outbound request blocked — host "${host}" resolves to a private/reserved address (${address})`, { context: {
|
|
94
|
-
url: rawUrl,
|
|
95
|
-
host,
|
|
96
|
-
address
|
|
97
|
-
} });
|
|
98
|
-
}
|
|
99
|
-
/** Merge the internal timeout signal with an optional caller signal. */
|
|
100
|
-
function mergeSignals(timeout, external) {
|
|
101
|
-
if (!external) return timeout;
|
|
102
|
-
const controller = new AbortController();
|
|
103
|
-
const abort = (from) => controller.abort(from.reason);
|
|
104
|
-
if (timeout.aborted) abort(timeout);
|
|
105
|
-
else timeout.addEventListener("abort", () => abort(timeout), { once: true });
|
|
106
|
-
if (external.aborted) abort(external);
|
|
107
|
-
else external.addEventListener("abort", () => abort(external), { once: true });
|
|
108
|
-
return controller.signal;
|
|
109
|
-
}
|
|
110
|
-
/**
|
|
111
|
-
* Policy-guarded `fetch`: validates the URL ({@link assertUrlAllowed}),
|
|
112
|
-
* then performs the request with the policy's timeout and (optional)
|
|
113
|
-
* caller signal merged. Returns the raw `Response` — read its body via
|
|
114
|
-
* {@link readTextCapped} to enforce `maxBytes`. Throws
|
|
115
|
-
* {@link OutboundPolicyError} on a policy violation or timeout.
|
|
116
|
-
*/
|
|
117
|
-
async function guardedFetch(rawUrl, policyInput, init) {
|
|
118
|
-
const policy = resolveOutboundPolicy(policyInput);
|
|
119
|
-
const url = await assertUrlAllowed(rawUrl, policy);
|
|
120
|
-
const timeoutController = new AbortController();
|
|
121
|
-
const timer = setTimeout(() => {
|
|
122
|
-
timeoutController.abort(new OutboundPolicyError(`outbound request timed out after ${policy.timeoutMs}ms`, { context: {
|
|
123
|
-
url: rawUrl,
|
|
124
|
-
timeoutMs: policy.timeoutMs
|
|
125
|
-
} }));
|
|
126
|
-
}, policy.timeoutMs);
|
|
127
|
-
try {
|
|
128
|
-
return await policy.fetch(url, {
|
|
129
|
-
...init,
|
|
130
|
-
signal: mergeSignals(timeoutController.signal, policy.signal)
|
|
131
|
-
});
|
|
132
|
-
} finally {
|
|
133
|
-
clearTimeout(timer);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
/**
|
|
137
|
-
* Read a response body as UTF-8 text with a hard byte cap. A declared
|
|
138
|
-
* `content-length` over the cap fails fast; otherwise the stream is read
|
|
139
|
-
* chunk-by-chunk and aborted the moment the running total exceeds
|
|
140
|
-
* `maxBytes`. Throws {@link OutboundPolicyError} on overflow.
|
|
141
|
-
*/
|
|
142
|
-
async function readTextCapped(response, maxBytes) {
|
|
143
|
-
const declared = Number(response.headers.get("content-length"));
|
|
144
|
-
if (Number.isFinite(declared) && declared > maxBytes) throw new OutboundPolicyError(`outbound response body too large — declared ${declared} bytes exceeds the ${maxBytes}-byte cap`, { context: {
|
|
145
|
-
declared,
|
|
146
|
-
maxBytes
|
|
147
|
-
} });
|
|
148
|
-
if (!response.body) {
|
|
149
|
-
const text = await response.text();
|
|
150
|
-
if (Buffer.byteLength(text) > maxBytes) throw new OutboundPolicyError(`outbound response body exceeded the ${maxBytes}-byte cap`, { context: { maxBytes } });
|
|
151
|
-
return text;
|
|
152
|
-
}
|
|
153
|
-
const reader = response.body.getReader();
|
|
154
|
-
const chunks = [];
|
|
155
|
-
let total = 0;
|
|
156
|
-
for (;;) {
|
|
157
|
-
const { done, value } = await reader.read();
|
|
158
|
-
if (done) break;
|
|
159
|
-
if (!value) continue;
|
|
160
|
-
total += value.byteLength;
|
|
161
|
-
if (total > maxBytes) {
|
|
162
|
-
await reader.cancel();
|
|
163
|
-
throw new OutboundPolicyError(`outbound response body exceeded the ${maxBytes}-byte cap`, { context: { maxBytes } });
|
|
164
|
-
}
|
|
165
|
-
chunks.push(value);
|
|
166
|
-
}
|
|
167
|
-
return Buffer.concat(chunks).toString("utf8");
|
|
168
|
-
}
|
|
169
|
-
/**
|
|
170
|
-
* Convenience: {@link guardedFetch} + {@link readTextCapped}. Returns the
|
|
171
|
-
* response status alongside the (capped) body text so callers can shape
|
|
172
|
-
* their own not-OK error. The body is only read when the response is OK.
|
|
173
|
-
*/
|
|
174
|
-
async function fetchTextWithPolicy(rawUrl, policyInput, init) {
|
|
175
|
-
const policy = resolveOutboundPolicy(policyInput);
|
|
176
|
-
const response = await guardedFetch(rawUrl, policy, init);
|
|
177
|
-
return {
|
|
178
|
-
ok: response.ok,
|
|
179
|
-
status: response.status,
|
|
180
|
-
statusText: response.statusText,
|
|
181
|
-
text: response.ok ? await readTextCapped(response, policy.maxBytes) : ""
|
|
182
|
-
};
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
//#endregion
|
|
186
|
-
export { assertUrlAllowed, fetchTextWithPolicy, guardedFetch, readTextCapped, resolveOutboundPolicy };
|
|
187
|
-
//# sourceMappingURL=outbound-policy.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"outbound-policy.mjs","names":[],"sources":["../../../../../../../../../@warlock.js/ai/src/security/outbound-policy.ts"],"sourcesContent":["import { lookup } from \"node:dns/promises\";\nimport { isIP } from \"node:net\";\nimport { OutboundPolicyError } from \"../errors\";\nimport { isPrivateOrReservedIp } from \"./private-ip\";\nimport type {\n OutboundPolicy,\n ResolvedOutboundPolicy,\n} from \"./outbound-policy.type\";\n\n/** 5 MiB — default cap on an outbound response body. */\nconst DEFAULT_MAX_BYTES = 5 * 1024 * 1024;\n/** 10s — default per-request timeout. */\nconst DEFAULT_TIMEOUT_MS = 10_000;\n\n/**\n * Fill an {@link OutboundPolicy} with strict defaults: https-only,\n * private-IP deny on, 10s timeout, 5 MiB cap, global `fetch`. Idempotent\n * — resolving an already-resolved policy yields the same shape.\n */\nexport function resolveOutboundPolicy(\n policy: OutboundPolicy = {},\n): ResolvedOutboundPolicy {\n return {\n allowedSchemes: policy.allowedSchemes ?? [\"https\"],\n hostAllowlist: policy.hostAllowlist,\n denyPrivateIPsAfterDNS: policy.denyPrivateIPsAfterDNS ?? true,\n maxBytes: policy.maxBytes ?? DEFAULT_MAX_BYTES,\n timeoutMs: policy.timeoutMs ?? DEFAULT_TIMEOUT_MS,\n signal: policy.signal,\n fetch: policy.fetch ?? globalThis.fetch,\n };\n}\n\n/** Strip the `[ ]` IPv6 brackets `URL.hostname` keeps. */\nfunction stripBrackets(host: string): string {\n return host.startsWith(\"[\") && host.endsWith(\"]\") ? host.slice(1, -1) : host;\n}\n\n/** Whether `host` equals or is a subdomain of any allowlist entry. */\nfunction hostAllowed(host: string, allowlist: string[]): boolean {\n const lower = host.toLowerCase();\n return allowlist.some(entry => {\n const e = entry.toLowerCase();\n return lower === e || lower.endsWith(`.${e}`);\n });\n}\n\n/**\n * Validate a URL against the policy BEFORE any network call: scheme\n * allowlist, host allowlist, and (when enabled) a DNS resolution that\n * rejects private / loopback / link-local / metadata addresses — the SSRF\n * guard. Returns the parsed `URL` on success; throws\n * {@link OutboundPolicyError} otherwise.\n */\nexport async function assertUrlAllowed(\n rawUrl: string,\n policy: ResolvedOutboundPolicy,\n): Promise<URL> {\n let url: URL;\n try {\n url = new URL(rawUrl);\n } catch {\n throw new OutboundPolicyError(`outbound request blocked — invalid URL: ${rawUrl}`, {\n context: { url: rawUrl },\n });\n }\n\n const scheme = url.protocol.replace(/:$/, \"\").toLowerCase();\n if (!policy.allowedSchemes.some(s => s.toLowerCase() === scheme)) {\n throw new OutboundPolicyError(\n `outbound request blocked — scheme \"${scheme}\" is not allowed (allowed: ${policy.allowedSchemes.join(\", \")})`,\n { context: { url: rawUrl, scheme } },\n );\n }\n\n const host = stripBrackets(url.hostname);\n\n if (policy.hostAllowlist && !hostAllowed(host, policy.hostAllowlist)) {\n throw new OutboundPolicyError(\n `outbound request blocked — host \"${host}\" is not in the allowlist`,\n { context: { url: rawUrl, host } },\n );\n }\n\n if (policy.denyPrivateIPsAfterDNS) {\n await assertHostNotPrivate(host, rawUrl);\n }\n\n return url;\n}\n\n/**\n * Reject when `host` is — or resolves to — a private / reserved address.\n * IP literals are checked directly; hostnames are resolved via DNS and\n * every returned address is checked (a public name pointing inward is\n * caught). A resolution failure fails closed.\n */\nasync function assertHostNotPrivate(host: string, rawUrl: string): Promise<void> {\n if (isIP(host) !== 0) {\n if (isPrivateOrReservedIp(host)) {\n throw new OutboundPolicyError(\n `outbound request blocked — \"${host}\" is a private/reserved address`,\n { context: { url: rawUrl, address: host } },\n );\n }\n return;\n }\n\n let addresses: Array<{ address: string }>;\n try {\n addresses = await lookup(host, { all: true });\n } catch (cause) {\n throw new OutboundPolicyError(\n `outbound request blocked — could not resolve host \"${host}\" to verify it is public`,\n { cause, context: { url: rawUrl, host } },\n );\n }\n\n for (const { address } of addresses) {\n if (isPrivateOrReservedIp(address)) {\n throw new OutboundPolicyError(\n `outbound request blocked — host \"${host}\" resolves to a private/reserved address (${address})`,\n { context: { url: rawUrl, host, address } },\n );\n }\n }\n}\n\n/** Merge the internal timeout signal with an optional caller signal. */\nfunction mergeSignals(\n timeout: AbortSignal,\n external?: AbortSignal,\n): AbortSignal {\n if (!external) return timeout;\n\n const controller = new AbortController();\n const abort = (from: AbortSignal) => controller.abort(from.reason);\n\n if (timeout.aborted) abort(timeout);\n else timeout.addEventListener(\"abort\", () => abort(timeout), { once: true });\n\n if (external.aborted) abort(external);\n else external.addEventListener(\"abort\", () => abort(external), { once: true });\n\n return controller.signal;\n}\n\n/**\n * Policy-guarded `fetch`: validates the URL ({@link assertUrlAllowed}),\n * then performs the request with the policy's timeout and (optional)\n * caller signal merged. Returns the raw `Response` — read its body via\n * {@link readTextCapped} to enforce `maxBytes`. Throws\n * {@link OutboundPolicyError} on a policy violation or timeout.\n */\nexport async function guardedFetch(\n rawUrl: string,\n policyInput: OutboundPolicy,\n init?: RequestInit,\n): Promise<Response> {\n const policy = resolveOutboundPolicy(policyInput);\n const url = await assertUrlAllowed(rawUrl, policy);\n\n const timeoutController = new AbortController();\n const timer = setTimeout(() => {\n timeoutController.abort(\n new OutboundPolicyError(\n `outbound request timed out after ${policy.timeoutMs}ms`,\n { context: { url: rawUrl, timeoutMs: policy.timeoutMs } },\n ),\n );\n }, policy.timeoutMs);\n\n try {\n return await policy.fetch(url, {\n ...init,\n signal: mergeSignals(timeoutController.signal, policy.signal),\n });\n } finally {\n clearTimeout(timer);\n }\n}\n\n/**\n * Read a response body as UTF-8 text with a hard byte cap. A declared\n * `content-length` over the cap fails fast; otherwise the stream is read\n * chunk-by-chunk and aborted the moment the running total exceeds\n * `maxBytes`. Throws {@link OutboundPolicyError} on overflow.\n */\nexport async function readTextCapped(\n response: Response,\n maxBytes: number,\n): Promise<string> {\n const declared = Number(response.headers.get(\"content-length\"));\n if (Number.isFinite(declared) && declared > maxBytes) {\n throw new OutboundPolicyError(\n `outbound response body too large — declared ${declared} bytes exceeds the ${maxBytes}-byte cap`,\n { context: { declared, maxBytes } },\n );\n }\n\n if (!response.body) {\n const text = await response.text();\n if (Buffer.byteLength(text) > maxBytes) {\n throw new OutboundPolicyError(\n `outbound response body exceeded the ${maxBytes}-byte cap`,\n { context: { maxBytes } },\n );\n }\n return text;\n }\n\n const reader = response.body.getReader();\n const chunks: Uint8Array[] = [];\n let total = 0;\n\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n if (!value) continue;\n\n total += value.byteLength;\n if (total > maxBytes) {\n await reader.cancel();\n throw new OutboundPolicyError(\n `outbound response body exceeded the ${maxBytes}-byte cap`,\n { context: { maxBytes } },\n );\n }\n chunks.push(value);\n }\n\n return Buffer.concat(chunks).toString(\"utf8\");\n}\n\n/**\n * Convenience: {@link guardedFetch} + {@link readTextCapped}. Returns the\n * response status alongside the (capped) body text so callers can shape\n * their own not-OK error. The body is only read when the response is OK.\n */\nexport async function fetchTextWithPolicy(\n rawUrl: string,\n policyInput: OutboundPolicy,\n init?: RequestInit,\n): Promise<{ ok: boolean; status: number; statusText: string; text: string }> {\n const policy = resolveOutboundPolicy(policyInput);\n const response = await guardedFetch(rawUrl, policy, init);\n\n return {\n ok: response.ok,\n status: response.status,\n statusText: response.statusText,\n text: response.ok ? await readTextCapped(response, policy.maxBytes) : \"\",\n };\n}\n"],"mappings":"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"}
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { isIP } from "node:net";
|
|
2
|
-
|
|
3
|
-
//#region ../@warlock.js/ai/src/security/private-ip.ts
|
|
4
|
-
/**
|
|
5
|
-
* True when `ip` is a private, loopback, link-local, unique-local,
|
|
6
|
-
* carrier-grade-NAT, unspecified, or otherwise non-public address — the
|
|
7
|
-
* set an SSRF guard must refuse. Accepts IPv4 and IPv6 literals (including
|
|
8
|
-
* IPv4-mapped IPv6 like `::ffff:169.254.169.254`). A non-IP string returns
|
|
9
|
-
* `false` (the caller resolves hostnames via DNS first).
|
|
10
|
-
*
|
|
11
|
-
* The cloud-metadata endpoint `169.254.169.254` is covered by the IPv4
|
|
12
|
-
* link-local range `169.254.0.0/16`.
|
|
13
|
-
*/
|
|
14
|
-
function isPrivateOrReservedIp(ip) {
|
|
15
|
-
const family = isIP(ip);
|
|
16
|
-
if (family === 4) return isPrivateIpv4(ip);
|
|
17
|
-
if (family === 6) return isPrivateIpv6(ip);
|
|
18
|
-
return false;
|
|
19
|
-
}
|
|
20
|
-
/** Parse a dotted-quad into four octets, or `null` if malformed. */
|
|
21
|
-
function parseIpv4(ip) {
|
|
22
|
-
const parts = ip.split(".");
|
|
23
|
-
if (parts.length !== 4) return null;
|
|
24
|
-
const octets = parts.map((part) => Number(part));
|
|
25
|
-
if (octets.some((n) => !Number.isInteger(n) || n < 0 || n > 255)) return null;
|
|
26
|
-
return octets;
|
|
27
|
-
}
|
|
28
|
-
function isPrivateIpv4(ip) {
|
|
29
|
-
const octets = parseIpv4(ip);
|
|
30
|
-
if (!octets) return true;
|
|
31
|
-
const [a, b] = octets;
|
|
32
|
-
return a === 0 || a === 10 || a === 127 || a === 100 && b >= 64 && b <= 127 || a === 169 && b === 254 || a === 172 && b >= 16 && b <= 31 || a === 192 && b === 168 || a === 192 && b === 0 || a === 198 && (b === 18 || b === 19) || a === 198 && b === 51 || a === 203 && b === 0 || a >= 224;
|
|
33
|
-
}
|
|
34
|
-
function isPrivateIpv6(ip) {
|
|
35
|
-
const normalized = ip.toLowerCase().split("%")[0];
|
|
36
|
-
const v4 = normalized.match(/(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/);
|
|
37
|
-
if (v4) return isPrivateIpv4(v4[1]);
|
|
38
|
-
if (normalized === "::1" || normalized === "::") return true;
|
|
39
|
-
const firstGroup = normalized.split(":")[0];
|
|
40
|
-
const head = firstGroup === "" ? 0 : Number.parseInt(firstGroup, 16);
|
|
41
|
-
if ((head & 65024) === 64512) return true;
|
|
42
|
-
if ((head & 65472) === 65152) return true;
|
|
43
|
-
return false;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
//#endregion
|
|
47
|
-
export { isPrivateOrReservedIp };
|
|
48
|
-
//# sourceMappingURL=private-ip.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"private-ip.mjs","names":[],"sources":["../../../../../../../../../@warlock.js/ai/src/security/private-ip.ts"],"sourcesContent":["import { isIP } from \"node:net\";\n\n/**\n * True when `ip` is a private, loopback, link-local, unique-local,\n * carrier-grade-NAT, unspecified, or otherwise non-public address — the\n * set an SSRF guard must refuse. Accepts IPv4 and IPv6 literals (including\n * IPv4-mapped IPv6 like `::ffff:169.254.169.254`). A non-IP string returns\n * `false` (the caller resolves hostnames via DNS first).\n *\n * The cloud-metadata endpoint `169.254.169.254` is covered by the IPv4\n * link-local range `169.254.0.0/16`.\n */\nexport function isPrivateOrReservedIp(ip: string): boolean {\n const family = isIP(ip);\n if (family === 4) return isPrivateIpv4(ip);\n if (family === 6) return isPrivateIpv6(ip);\n return false;\n}\n\n/** Parse a dotted-quad into four octets, or `null` if malformed. */\nfunction parseIpv4(ip: string): [number, number, number, number] | null {\n const parts = ip.split(\".\");\n if (parts.length !== 4) return null;\n\n const octets = parts.map(part => Number(part));\n if (octets.some(n => !Number.isInteger(n) || n < 0 || n > 255)) return null;\n\n return octets as [number, number, number, number];\n}\n\nfunction isPrivateIpv4(ip: string): boolean {\n const octets = parseIpv4(ip);\n if (!octets) return true; // unparseable → refuse, fail closed\n\n const [a, b] = octets;\n\n return (\n a === 0 || // 0.0.0.0/8 \"this network\"\n a === 10 || // 10.0.0.0/8 private\n a === 127 || // 127.0.0.0/8 loopback\n (a === 100 && b >= 64 && b <= 127) || // 100.64.0.0/10 CGNAT\n (a === 169 && b === 254) || // 169.254.0.0/16 link-local + metadata\n (a === 172 && b >= 16 && b <= 31) || // 172.16.0.0/12 private\n (a === 192 && b === 168) || // 192.168.0.0/16 private\n (a === 192 && b === 0) || // 192.0.0.0/24 + 192.0.2.0/24 (IETF/test)\n (a === 198 && (b === 18 || b === 19)) || // 198.18.0.0/15 benchmarking\n (a === 198 && b === 51) || // 198.51.100.0/24 test-net-2\n (a === 203 && b === 0) || // 203.0.113.0/24 test-net-3\n a >= 224 // 224.0.0.0/4 multicast + 240.0.0.0/4 reserved + 255.255.255.255\n );\n}\n\nfunction isPrivateIpv6(ip: string): boolean {\n const normalized = ip.toLowerCase().split(\"%\")[0]; // drop zone id\n\n // IPv4-mapped / -embedded (::ffff:a.b.c.d, ::a.b.c.d) — defer to the v4\n // check on the trailing dotted-quad so an inward-mapped address is caught.\n const v4 = normalized.match(/(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})$/);\n if (v4) {\n return isPrivateIpv4(v4[1]);\n }\n\n if (normalized === \"::1\" || normalized === \"::\") {\n return true; // loopback / unspecified\n }\n\n // Expand only the leading group enough to classify the reserved blocks.\n const firstGroup = normalized.split(\":\")[0];\n const head = firstGroup === \"\" ? 0 : Number.parseInt(firstGroup, 16);\n\n // fc00::/7 unique-local (fc.. / fd..)\n if ((head & 0xfe00) === 0xfc00) return true;\n // fe80::/10 link-local\n if ((head & 0xffc0) === 0xfe80) return true;\n\n return false;\n}\n"],"mappings":";;;;;;;;;;;;;AAYA,SAAgB,sBAAsB,IAAqB;CACzD,MAAM,SAAS,KAAK,EAAE;CACtB,IAAI,WAAW,GAAG,OAAO,cAAc,EAAE;CACzC,IAAI,WAAW,GAAG,OAAO,cAAc,EAAE;CACzC,OAAO;AACT;;AAGA,SAAS,UAAU,IAAqD;CACtE,MAAM,QAAQ,GAAG,MAAM,GAAG;CAC1B,IAAI,MAAM,WAAW,GAAG,OAAO;CAE/B,MAAM,SAAS,MAAM,KAAI,SAAQ,OAAO,IAAI,CAAC;CAC7C,IAAI,OAAO,MAAK,MAAK,CAAC,OAAO,UAAU,CAAC,KAAK,IAAI,KAAK,IAAI,GAAG,GAAG,OAAO;CAEvE,OAAO;AACT;AAEA,SAAS,cAAc,IAAqB;CAC1C,MAAM,SAAS,UAAU,EAAE;CAC3B,IAAI,CAAC,QAAQ,OAAO;CAEpB,MAAM,CAAC,GAAG,KAAK;CAEf,OACE,MAAM,KACN,MAAM,MACN,MAAM,OACL,MAAM,OAAO,KAAK,MAAM,KAAK,OAC7B,MAAM,OAAO,MAAM,OACnB,MAAM,OAAO,KAAK,MAAM,KAAK,MAC7B,MAAM,OAAO,MAAM,OACnB,MAAM,OAAO,MAAM,KACnB,MAAM,QAAQ,MAAM,MAAM,MAAM,OAChC,MAAM,OAAO,MAAM,MACnB,MAAM,OAAO,MAAM,KACpB,KAAK;AAET;AAEA,SAAS,cAAc,IAAqB;CAC1C,MAAM,aAAa,GAAG,YAAY,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;CAI/C,MAAM,KAAK,WAAW,MAAM,uCAAuC;CACnE,IAAI,IACF,OAAO,cAAc,GAAG,EAAE;CAG5B,IAAI,eAAe,SAAS,eAAe,MACzC,OAAO;CAIT,MAAM,aAAa,WAAW,MAAM,GAAG,CAAC,CAAC;CACzC,MAAM,OAAO,eAAe,KAAK,IAAI,OAAO,SAAS,YAAY,EAAE;CAGnE,KAAK,OAAO,WAAY,OAAQ,OAAO;CAEvC,KAAK,OAAO,WAAY,OAAQ,OAAO;CAEvC,OAAO;AACT"}
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
//#region ../@warlock.js/ai/src/security/redact.ts
|
|
2
|
-
/**
|
|
3
|
-
* Default set of sensitive key fragments (matched case-insensitively as
|
|
4
|
-
* substrings of an object key). Covers the secrets that leak through
|
|
5
|
-
* recorded requests, error causes, and trace payloads: auth headers, API
|
|
6
|
-
* keys, cookies, tokens, passwords, and private keys.
|
|
7
|
-
*/
|
|
8
|
-
const DEFAULT_SENSITIVE_KEYS = [
|
|
9
|
-
"authorization",
|
|
10
|
-
"x-api-key",
|
|
11
|
-
"api-key",
|
|
12
|
-
"apikey",
|
|
13
|
-
"cookie",
|
|
14
|
-
"set-cookie",
|
|
15
|
-
"password",
|
|
16
|
-
"passwd",
|
|
17
|
-
"secret",
|
|
18
|
-
"token",
|
|
19
|
-
"access_token",
|
|
20
|
-
"refresh_token",
|
|
21
|
-
"client_secret",
|
|
22
|
-
"private_key",
|
|
23
|
-
"session"
|
|
24
|
-
];
|
|
25
|
-
const DEFAULT_PLACEHOLDER = "[redacted]";
|
|
26
|
-
const DEFAULT_MAX_DEPTH = 8;
|
|
27
|
-
function keyIsSensitive(key, fragments) {
|
|
28
|
-
const lower = key.toLowerCase();
|
|
29
|
-
return fragments.some((fragment) => lower.includes(fragment));
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* Deep-copy `value` with any property whose KEY matches a sensitive
|
|
33
|
-
* fragment replaced by the placeholder. Arrays are walked element-wise;
|
|
34
|
-
* circular references and over-deep trees collapse to the placeholder.
|
|
35
|
-
* Primitives pass through untouched (redaction is key-driven, not
|
|
36
|
-
* value-driven — it never guesses at a bare string being a secret).
|
|
37
|
-
*
|
|
38
|
-
* Shared by VCR cassettes (S2), Panoptic content capture, and the error /
|
|
39
|
-
* cause serializer (S4) so there is ONE redaction policy, not three.
|
|
40
|
-
*/
|
|
41
|
-
function redact(value, options = {}) {
|
|
42
|
-
const fragments = [...DEFAULT_SENSITIVE_KEYS, ...options.keys ?? []].map((k) => k.toLowerCase());
|
|
43
|
-
const placeholder = options.placeholder ?? DEFAULT_PLACEHOLDER;
|
|
44
|
-
const maxDepth = options.maxDepth ?? DEFAULT_MAX_DEPTH;
|
|
45
|
-
const seen = /* @__PURE__ */ new WeakSet();
|
|
46
|
-
const walk = (input, depth) => {
|
|
47
|
-
if (input === null || typeof input !== "object") return input;
|
|
48
|
-
if (depth >= maxDepth || seen.has(input)) return placeholder;
|
|
49
|
-
seen.add(input);
|
|
50
|
-
if (Array.isArray(input)) return input.map((item) => walk(item, depth + 1));
|
|
51
|
-
const out = {};
|
|
52
|
-
for (const [key, val] of Object.entries(input)) out[key] = keyIsSensitive(key, fragments) ? placeholder : walk(val, depth + 1);
|
|
53
|
-
return out;
|
|
54
|
-
};
|
|
55
|
-
return walk(value, 0);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
//#endregion
|
|
59
|
-
export { DEFAULT_SENSITIVE_KEYS, redact };
|
|
60
|
-
//# sourceMappingURL=redact.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"redact.mjs","names":[],"sources":["../../../../../../../../../@warlock.js/ai/src/security/redact.ts"],"sourcesContent":["/**\n * Default set of sensitive key fragments (matched case-insensitively as\n * substrings of an object key). Covers the secrets that leak through\n * recorded requests, error causes, and trace payloads: auth headers, API\n * keys, cookies, tokens, passwords, and private keys.\n */\nexport const DEFAULT_SENSITIVE_KEYS: readonly string[] = [\n \"authorization\",\n \"x-api-key\",\n \"api-key\",\n \"apikey\",\n \"cookie\",\n \"set-cookie\",\n \"password\",\n \"passwd\",\n \"secret\",\n \"token\",\n \"access_token\",\n \"refresh_token\",\n \"client_secret\",\n \"private_key\",\n \"session\",\n];\n\n/** HTTP header names always stripped from a serialized error/cause. */\nexport const SENSITIVE_HEADERS: readonly string[] = [\n \"authorization\",\n \"x-api-key\",\n \"api-key\",\n \"cookie\",\n \"set-cookie\",\n \"proxy-authorization\",\n];\n\nexport type RedactOptions = {\n /** Extra key fragments to redact, merged with {@link DEFAULT_SENSITIVE_KEYS}. */\n keys?: string[];\n /** Replacement for a redacted value. Default `\"[redacted]\"`. */\n placeholder?: string;\n /** Maximum recursion depth before bailing out. Default `8`. */\n maxDepth?: number;\n};\n\nconst DEFAULT_PLACEHOLDER = \"[redacted]\";\nconst DEFAULT_MAX_DEPTH = 8;\n\nfunction keyIsSensitive(key: string, fragments: string[]): boolean {\n const lower = key.toLowerCase();\n return fragments.some(fragment => lower.includes(fragment));\n}\n\n/**\n * Deep-copy `value` with any property whose KEY matches a sensitive\n * fragment replaced by the placeholder. Arrays are walked element-wise;\n * circular references and over-deep trees collapse to the placeholder.\n * Primitives pass through untouched (redaction is key-driven, not\n * value-driven — it never guesses at a bare string being a secret).\n *\n * Shared by VCR cassettes (S2), Panoptic content capture, and the error /\n * cause serializer (S4) so there is ONE redaction policy, not three.\n */\nexport function redact<T>(value: T, options: RedactOptions = {}): T {\n const fragments = [...DEFAULT_SENSITIVE_KEYS, ...(options.keys ?? [])].map(k =>\n k.toLowerCase(),\n );\n const placeholder = options.placeholder ?? DEFAULT_PLACEHOLDER;\n const maxDepth = options.maxDepth ?? DEFAULT_MAX_DEPTH;\n const seen = new WeakSet<object>();\n\n const walk = (input: unknown, depth: number): unknown => {\n if (input === null || typeof input !== \"object\") {\n return input;\n }\n if (depth >= maxDepth || seen.has(input)) {\n return placeholder;\n }\n seen.add(input as object);\n\n if (Array.isArray(input)) {\n return input.map(item => walk(item, depth + 1));\n }\n\n const out: Record<string, unknown> = {};\n for (const [key, val] of Object.entries(input as Record<string, unknown>)) {\n out[key] = keyIsSensitive(key, fragments)\n ? placeholder\n : walk(val, depth + 1);\n }\n return out;\n };\n\n return walk(value, 0) as T;\n}\n\n/**\n * Strip sensitive HTTP headers from a `Headers` instance or a plain\n * header record, returning a redacted plain object. Header names are\n * matched case-insensitively against {@link SENSITIVE_HEADERS}.\n */\nexport function redactHeaders(\n headers: Headers | Record<string, unknown> | undefined,\n placeholder: string = DEFAULT_PLACEHOLDER,\n): Record<string, unknown> {\n if (!headers) return {};\n\n const entries: Array<[string, unknown]> =\n headers instanceof Headers\n ? [...headers.entries()]\n : Object.entries(headers);\n\n const out: Record<string, unknown> = {};\n for (const [key, val] of entries) {\n out[key] = SENSITIVE_HEADERS.includes(key.toLowerCase()) ? placeholder : val;\n }\n return out;\n}\n\n/**\n * Patterns for secrets that hide in FREE TEXT (error messages, stack\n * traces, log lines) where the key-based {@link redact} can't reach them.\n * Each entry replaces the secret with `[redacted]` while keeping\n * surrounding context.\n */\nconst SECRET_PATTERNS: ReadonlyArray<readonly [RegExp, string]> = [\n [/\\bBearer\\s+[A-Za-z0-9._~+/-]+=*/gi, \"Bearer [redacted]\"],\n [/\\b(authorization|x-api-key|api[_-]?key|cookie)(\"?\\s*[:=]\\s*\"?)[^\\s\",}]+/gi, \"$1$2[redacted]\"],\n [/\\bsk-[A-Za-z0-9]{16,}\\b/g, \"[redacted]\"], // OpenAI-style keys\n [/\\bxox[baprs]-[A-Za-z0-9-]{8,}\\b/g, \"[redacted]\"], // Slack tokens\n [/\\bgh[pousr]_[A-Za-z0-9]{20,}\\b/g, \"[redacted]\"], // GitHub tokens\n [/\\bAKIA[0-9A-Z]{16}\\b/g, \"[redacted]\"], // AWS access key ids\n];\n\n/**\n * Scrub secrets that appear in free-form text — error messages, stack\n * traces, exported log lines. Complements {@link redact} (which is key-\n * driven and can't see a token embedded in a string). Used by the trace /\n * error serializer (S4) before a message or stack is stored or exported.\n */\nexport function scrubSecrets(text: string): string {\n let out = text;\n for (const [pattern, replacement] of SECRET_PATTERNS) {\n out = out.replace(pattern, replacement);\n }\n return out;\n}\n\n/**\n * Serialized, secret-free view of an error. `stack` is omitted by default\n * (it can embed local paths, endpoints, and tokens); pass\n * `includeStack: true` only for a trusted local sink. The retained\n * `cause` is deep-redacted via {@link redact}, so a raw provider SDK error\n * carrying `Authorization` / `x-api-key` on `cause.headers` is sanitized.\n */\nexport type RedactedError = {\n name: string;\n message: string;\n code?: string;\n cause?: unknown;\n stack?: string;\n};\n\nexport function redactError(\n error: unknown,\n options: { includeStack?: boolean } & RedactOptions = {},\n): RedactedError {\n const { includeStack, ...redactOptions } = options;\n\n if (error === null || typeof error !== \"object\") {\n return { name: \"Error\", message: String(error) };\n }\n\n const err = error as {\n name?: unknown;\n message?: unknown;\n code?: unknown;\n cause?: unknown;\n stack?: unknown;\n };\n\n const result: RedactedError = {\n name: typeof err.name === \"string\" ? err.name : \"Error\",\n message: typeof err.message === \"string\" ? err.message : String(error),\n };\n\n if (typeof err.code === \"string\") {\n result.code = err.code;\n }\n if (err.cause !== undefined) {\n result.cause =\n err.cause !== null && typeof err.cause === \"object\"\n ? redact(err.cause, redactOptions)\n : err.cause;\n }\n if (includeStack && typeof err.stack === \"string\") {\n result.stack = err.stack;\n }\n\n return result;\n}\n"],"mappings":";;;;;;;AAMA,MAAa,yBAA4C;CACvD;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;AAqBA,MAAM,sBAAsB;AAC5B,MAAM,oBAAoB;AAE1B,SAAS,eAAe,KAAa,WAA8B;CACjE,MAAM,QAAQ,IAAI,YAAY;CAC9B,OAAO,UAAU,MAAK,aAAY,MAAM,SAAS,QAAQ,CAAC;AAC5D;;;;;;;;;;;AAYA,SAAgB,OAAU,OAAU,UAAyB,CAAC,GAAM;CAClE,MAAM,YAAY,CAAC,GAAG,wBAAwB,GAAI,QAAQ,QAAQ,CAAC,CAAE,CAAC,CAAC,KAAI,MACzE,EAAE,YAAY,CAChB;CACA,MAAM,cAAc,QAAQ,eAAe;CAC3C,MAAM,WAAW,QAAQ,YAAY;CACrC,MAAM,uBAAO,IAAI,QAAgB;CAEjC,MAAM,QAAQ,OAAgB,UAA2B;EACvD,IAAI,UAAU,QAAQ,OAAO,UAAU,UACrC,OAAO;EAET,IAAI,SAAS,YAAY,KAAK,IAAI,KAAK,GACrC,OAAO;EAET,KAAK,IAAI,KAAe;EAExB,IAAI,MAAM,QAAQ,KAAK,GACrB,OAAO,MAAM,KAAI,SAAQ,KAAK,MAAM,QAAQ,CAAC,CAAC;EAGhD,MAAM,MAA+B,CAAC;EACtC,KAAK,MAAM,CAAC,KAAK,QAAQ,OAAO,QAAQ,KAAgC,GACtE,IAAI,OAAO,eAAe,KAAK,SAAS,IACpC,cACA,KAAK,KAAK,QAAQ,CAAC;EAEzB,OAAO;CACT;CAEA,OAAO,KAAK,OAAO,CAAC;AACtB"}
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
import { streamToSSE } from "./stream-to-sse.mjs";
|
|
2
|
-
|
|
3
|
-
//#region ../@warlock.js/ai/src/serve/serve.ts
|
|
4
|
-
const SECURITY_HEADERS = {
|
|
5
|
-
"x-content-type-options": "nosniff",
|
|
6
|
-
"x-frame-options": "DENY",
|
|
7
|
-
"referrer-policy": "no-referrer"
|
|
8
|
-
};
|
|
9
|
-
/**
|
|
10
|
-
* Turn an executable into a `node:http` request handler that streams its
|
|
11
|
-
* run to the client as Server-Sent Events (A3) — the production-serving
|
|
12
|
-
* primitive. POST a JSON body (`{ input, sessionId?, history? }`); the
|
|
13
|
-
* response is an `text/event-stream` of the primitive's events, the final
|
|
14
|
-
* `result`, then `[DONE]`. Absorbs the auth-token control; pair with a
|
|
15
|
-
* `sessionLock` + an orchestrator for durable multi-turn serving.
|
|
16
|
-
*
|
|
17
|
-
* @example
|
|
18
|
-
* import { createServer } from "node:http";
|
|
19
|
-
* createServer(ai.serve(myAgent, { authToken: process.env.TOKEN })).listen(8787);
|
|
20
|
-
*/
|
|
21
|
-
function serve(executable, options = {}) {
|
|
22
|
-
const toInput = options.toInput ?? ((body) => body.input);
|
|
23
|
-
const toOptions = options.toOptions ?? ((body) => {
|
|
24
|
-
const opts = {};
|
|
25
|
-
if (body.sessionId !== void 0) opts.sessionId = body.sessionId;
|
|
26
|
-
if (body.history !== void 0) opts.history = body.history;
|
|
27
|
-
return opts;
|
|
28
|
-
});
|
|
29
|
-
return function handle(req, res) {
|
|
30
|
-
(async () => {
|
|
31
|
-
if (req.method !== "POST") {
|
|
32
|
-
sendJson(res, 405, { error: "method_not_allowed" });
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
if (options.authToken && req.headers.authorization !== `Bearer ${options.authToken}`) {
|
|
36
|
-
sendJson(res, 401, { error: "unauthorized" });
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
let body;
|
|
40
|
-
try {
|
|
41
|
-
body = await readJsonBody(req);
|
|
42
|
-
} catch {
|
|
43
|
-
sendJson(res, 400, { error: "invalid_json" });
|
|
44
|
-
return;
|
|
45
|
-
}
|
|
46
|
-
res.writeHead(200, {
|
|
47
|
-
"content-type": "text/event-stream; charset=utf-8",
|
|
48
|
-
"cache-control": "no-cache",
|
|
49
|
-
connection: "keep-alive",
|
|
50
|
-
...SECURITY_HEADERS
|
|
51
|
-
});
|
|
52
|
-
try {
|
|
53
|
-
const stream = executable.stream(toInput(body), toOptions(body));
|
|
54
|
-
for await (const frame of streamToSSE(stream)) res.write(frame);
|
|
55
|
-
} catch (error) {
|
|
56
|
-
res.write(`event: error\ndata: ${JSON.stringify({ message: error instanceof Error ? error.message : String(error) })}\n\n`);
|
|
57
|
-
} finally {
|
|
58
|
-
res.end();
|
|
59
|
-
}
|
|
60
|
-
})();
|
|
61
|
-
};
|
|
62
|
-
}
|
|
63
|
-
/** Read and JSON-parse a request body. */
|
|
64
|
-
function readJsonBody(req) {
|
|
65
|
-
return new Promise((resolve, reject) => {
|
|
66
|
-
let raw = "";
|
|
67
|
-
req.on("data", (chunk) => {
|
|
68
|
-
raw += chunk.toString();
|
|
69
|
-
});
|
|
70
|
-
req.on("end", () => {
|
|
71
|
-
try {
|
|
72
|
-
resolve(raw ? JSON.parse(raw) : {});
|
|
73
|
-
} catch (error) {
|
|
74
|
-
reject(error);
|
|
75
|
-
}
|
|
76
|
-
});
|
|
77
|
-
req.on("error", reject);
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
function sendJson(res, status, body) {
|
|
81
|
-
res.writeHead(status, {
|
|
82
|
-
"content-type": "application/json; charset=utf-8",
|
|
83
|
-
...SECURITY_HEADERS
|
|
84
|
-
});
|
|
85
|
-
res.end(JSON.stringify(body));
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
//#endregion
|
|
89
|
-
export { serve };
|
|
90
|
-
//# sourceMappingURL=serve.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"serve.mjs","names":[],"sources":["../../../../../../../../../@warlock.js/ai/src/serve/serve.ts"],"sourcesContent":["import type { IncomingMessage, ServerResponse } from \"node:http\";\nimport { streamToSSE, type StreamLike } from \"./stream-to-sse\";\n\n/**\n * Anything `serve` can expose: a primitive whose `stream(input, options)`\n * returns a {@link StreamLike}. Agents, supervisors, and orchestrators all\n * satisfy it.\n */\nexport type ServableExecutable<TInput = unknown> = {\n stream(input: TInput, options?: Record<string, unknown>): StreamLike<{ type: string }, unknown>;\n};\n\n/** Options for {@link serve}. */\nexport type ServeOptions<TInput = unknown> = {\n /**\n * Bearer token required on every request. When set, a request must send\n * `Authorization: Bearer <token>`, else `401` (S4-style auth, the same\n * control the dashboard uses — fold this in for a production deploy).\n */\n authToken?: string;\n /**\n * Map the parsed JSON request body to the executable's input. Default:\n * `body.input`. Override to accept a different request shape.\n */\n toInput?: (body: Record<string, unknown>) => TInput;\n /**\n * Map the parsed body to per-call stream options (e.g. an orchestrator\n * `{ sessionId, history }` so a turn resumes the right session — A3\n * wiring). Default: pass `sessionId` / `history` straight through.\n */\n toOptions?: (body: Record<string, unknown>) => Record<string, unknown>;\n};\n\nconst SECURITY_HEADERS: Record<string, string> = {\n \"x-content-type-options\": \"nosniff\",\n \"x-frame-options\": \"DENY\",\n \"referrer-policy\": \"no-referrer\",\n};\n\n/**\n * Turn an executable into a `node:http` request handler that streams its\n * run to the client as Server-Sent Events (A3) — the production-serving\n * primitive. POST a JSON body (`{ input, sessionId?, history? }`); the\n * response is an `text/event-stream` of the primitive's events, the final\n * `result`, then `[DONE]`. Absorbs the auth-token control; pair with a\n * `sessionLock` + an orchestrator for durable multi-turn serving.\n *\n * @example\n * import { createServer } from \"node:http\";\n * createServer(ai.serve(myAgent, { authToken: process.env.TOKEN })).listen(8787);\n */\nexport function serve<TInput = unknown>(\n executable: ServableExecutable<TInput>,\n options: ServeOptions<TInput> = {},\n): (req: IncomingMessage, res: ServerResponse) => void {\n const toInput = options.toInput ?? ((body) => body.input as TInput);\n const toOptions =\n options.toOptions ??\n ((body) => {\n const opts: Record<string, unknown> = {};\n if (body.sessionId !== undefined) opts.sessionId = body.sessionId;\n if (body.history !== undefined) opts.history = body.history;\n return opts;\n });\n\n return function handle(req: IncomingMessage, res: ServerResponse): void {\n void (async () => {\n if (req.method !== \"POST\") {\n sendJson(res, 405, { error: \"method_not_allowed\" });\n return;\n }\n\n if (options.authToken && req.headers.authorization !== `Bearer ${options.authToken}`) {\n sendJson(res, 401, { error: \"unauthorized\" });\n return;\n }\n\n let body: Record<string, unknown>;\n try {\n body = await readJsonBody(req);\n } catch {\n sendJson(res, 400, { error: \"invalid_json\" });\n return;\n }\n\n res.writeHead(200, {\n \"content-type\": \"text/event-stream; charset=utf-8\",\n \"cache-control\": \"no-cache\",\n connection: \"keep-alive\",\n ...SECURITY_HEADERS,\n });\n\n try {\n const stream = executable.stream(toInput(body), toOptions(body));\n for await (const frame of streamToSSE(stream)) {\n res.write(frame);\n }\n } catch (error) {\n res.write(\n `event: error\\ndata: ${JSON.stringify({\n message: error instanceof Error ? error.message : String(error),\n })}\\n\\n`,\n );\n } finally {\n res.end();\n }\n })();\n };\n}\n\n/** Read and JSON-parse a request body. */\nfunction readJsonBody(req: IncomingMessage): Promise<Record<string, unknown>> {\n return new Promise((resolve, reject) => {\n let raw = \"\";\n req.on(\"data\", (chunk: Buffer | string) => {\n raw += chunk.toString();\n });\n req.on(\"end\", () => {\n try {\n resolve(raw ? (JSON.parse(raw) as Record<string, unknown>) : {});\n } catch (error) {\n reject(error);\n }\n });\n req.on(\"error\", reject);\n });\n}\n\nfunction sendJson(res: ServerResponse, status: number, body: unknown): void {\n res.writeHead(status, { \"content-type\": \"application/json; charset=utf-8\", ...SECURITY_HEADERS });\n res.end(JSON.stringify(body));\n}\n"],"mappings":";;;AAiCA,MAAM,mBAA2C;CAC/C,0BAA0B;CAC1B,mBAAmB;CACnB,mBAAmB;AACrB;;;;;;;;;;;;;AAcA,SAAgB,MACd,YACA,UAAgC,CAAC,GACoB;CACrD,MAAM,UAAU,QAAQ,aAAa,SAAS,KAAK;CACnD,MAAM,YACJ,QAAQ,eACN,SAAS;EACT,MAAM,OAAgC,CAAC;EACvC,IAAI,KAAK,cAAc,QAAW,KAAK,YAAY,KAAK;EACxD,IAAI,KAAK,YAAY,QAAW,KAAK,UAAU,KAAK;EACpD,OAAO;CACT;CAEF,OAAO,SAAS,OAAO,KAAsB,KAA2B;EACtE,CAAM,YAAY;GAChB,IAAI,IAAI,WAAW,QAAQ;IACzB,SAAS,KAAK,KAAK,EAAE,OAAO,qBAAqB,CAAC;IAClD;GACF;GAEA,IAAI,QAAQ,aAAa,IAAI,QAAQ,kBAAkB,UAAU,QAAQ,aAAa;IACpF,SAAS,KAAK,KAAK,EAAE,OAAO,eAAe,CAAC;IAC5C;GACF;GAEA,IAAI;GACJ,IAAI;IACF,OAAO,MAAM,aAAa,GAAG;GAC/B,QAAQ;IACN,SAAS,KAAK,KAAK,EAAE,OAAO,eAAe,CAAC;IAC5C;GACF;GAEA,IAAI,UAAU,KAAK;IACjB,gBAAgB;IAChB,iBAAiB;IACjB,YAAY;IACZ,GAAG;GACL,CAAC;GAED,IAAI;IACF,MAAM,SAAS,WAAW,OAAO,QAAQ,IAAI,GAAG,UAAU,IAAI,CAAC;IAC/D,WAAW,MAAM,SAAS,YAAY,MAAM,GAC1C,IAAI,MAAM,KAAK;GAEnB,SAAS,OAAO;IACd,IAAI,MACF,uBAAuB,KAAK,UAAU,EACpC,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,EAChE,CAAC,EAAE,KACL;GACF,UAAU;IACR,IAAI,IAAI;GACV;EACF,EAAC,CAAE;CACL;AACF;;AAGA,SAAS,aAAa,KAAwD;CAC5E,OAAO,IAAI,SAAS,SAAS,WAAW;EACtC,IAAI,MAAM;EACV,IAAI,GAAG,SAAS,UAA2B;GACzC,OAAO,MAAM,SAAS;EACxB,CAAC;EACD,IAAI,GAAG,aAAa;GAClB,IAAI;IACF,QAAQ,MAAO,KAAK,MAAM,GAAG,IAAgC,CAAC,CAAC;GACjE,SAAS,OAAO;IACd,OAAO,KAAK;GACd;EACF,CAAC;EACD,IAAI,GAAG,SAAS,MAAM;CACxB,CAAC;AACH;AAEA,SAAS,SAAS,KAAqB,QAAgB,MAAqB;CAC1E,IAAI,UAAU,QAAQ;EAAE,gBAAgB;EAAmC,GAAG;CAAiB,CAAC;CAChG,IAAI,IAAI,KAAK,UAAU,IAAI,CAAC;AAC9B"}
|
package/esm/ai/src/serve/sse.mjs
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
//#region ../@warlock.js/ai/src/serve/sse.ts
|
|
2
|
-
/**
|
|
3
|
-
* Encode one Server-Sent-Events frame. Multi-line `data` is split into
|
|
4
|
-
* multiple `data:` lines per the SSE spec, so JSON with embedded newlines
|
|
5
|
-
* still parses on the client.
|
|
6
|
-
*
|
|
7
|
-
* @example
|
|
8
|
-
* encodeSSE({ event: "agent.trip.streaming", data: { delta: "Hi" } });
|
|
9
|
-
* // "event: agent.trip.streaming\ndata: {\"delta\":\"Hi\"}\n\n"
|
|
10
|
-
*/
|
|
11
|
-
function encodeSSE(frame) {
|
|
12
|
-
let out = "";
|
|
13
|
-
if (frame.id) out += `id: ${frame.id}\n`;
|
|
14
|
-
if (frame.event) out += `event: ${frame.event}\n`;
|
|
15
|
-
const data = typeof frame.data === "string" ? frame.data : JSON.stringify(frame.data);
|
|
16
|
-
for (const line of data.split("\n")) out += `data: ${line}\n`;
|
|
17
|
-
out += "\n";
|
|
18
|
-
return out;
|
|
19
|
-
}
|
|
20
|
-
/** The terminal SSE frame a client watches for to stop reading. */
|
|
21
|
-
const SSE_DONE = "data: [DONE]\n\n";
|
|
22
|
-
|
|
23
|
-
//#endregion
|
|
24
|
-
export { SSE_DONE, encodeSSE };
|
|
25
|
-
//# sourceMappingURL=sse.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"sse.mjs","names":[],"sources":["../../../../../../../../../@warlock.js/ai/src/serve/sse.ts"],"sourcesContent":["/**\n * Encode one Server-Sent-Events frame. Multi-line `data` is split into\n * multiple `data:` lines per the SSE spec, so JSON with embedded newlines\n * still parses on the client.\n *\n * @example\n * encodeSSE({ event: \"agent.trip.streaming\", data: { delta: \"Hi\" } });\n * // \"event: agent.trip.streaming\\ndata: {\\\"delta\\\":\\\"Hi\\\"}\\n\\n\"\n */\nexport function encodeSSE(frame: { event?: string; data: unknown; id?: string }): string {\n let out = \"\";\n if (frame.id) out += `id: ${frame.id}\\n`;\n if (frame.event) out += `event: ${frame.event}\\n`;\n\n const data =\n typeof frame.data === \"string\" ? frame.data : JSON.stringify(frame.data);\n for (const line of data.split(\"\\n\")) {\n out += `data: ${line}\\n`;\n }\n\n out += \"\\n\";\n return out;\n}\n\n/** The terminal SSE frame a client watches for to stop reading. */\nexport const SSE_DONE = \"data: [DONE]\\n\\n\";\n"],"mappings":";;;;;;;;;;AASA,SAAgB,UAAU,OAA+D;CACvF,IAAI,MAAM;CACV,IAAI,MAAM,IAAI,OAAO,OAAO,MAAM,GAAG;CACrC,IAAI,MAAM,OAAO,OAAO,UAAU,MAAM,MAAM;CAE9C,MAAM,OACJ,OAAO,MAAM,SAAS,WAAW,MAAM,OAAO,KAAK,UAAU,MAAM,IAAI;CACzE,KAAK,MAAM,QAAQ,KAAK,MAAM,IAAI,GAChC,OAAO,SAAS,KAAK;CAGvB,OAAO;CACP,OAAO;AACT;;AAGA,MAAa,WAAW"}
|