@theokit/sdk 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1571 -0
- package/LICENSE +201 -0
- package/README.md +80 -0
- package/bin/theokit-migrate-config.mjs +269 -0
- package/bin/theokit-migrate-memory.mjs +116 -0
- package/dist/agent-builder.d.ts +52 -0
- package/dist/agent-factory.d.ts +39 -0
- package/dist/agent.d.ts +175 -0
- package/dist/batch.d.ts +11 -0
- package/dist/budget.d.ts +48 -0
- package/dist/cache.d.ts +74 -0
- package/dist/cron-1yxL3K2S.d.cts +221 -0
- package/dist/cron-BYVdYzob.d.ts +221 -0
- package/dist/cron.cjs +14655 -0
- package/dist/cron.cjs.map +1 -0
- package/dist/cron.d.cts +3 -0
- package/dist/cron.d.ts +71 -0
- package/dist/cron.js +14652 -0
- package/dist/cron.js.map +1 -0
- package/dist/define-tool.d.ts +35 -0
- package/dist/errors-CK8brCJ1.d.cts +448 -0
- package/dist/errors-CvAeEWgE.d.ts +448 -0
- package/dist/errors.cjs +255 -0
- package/dist/errors.cjs.map +1 -0
- package/dist/errors.d.cts +3 -0
- package/dist/errors.d.ts +356 -0
- package/dist/errors.js +238 -0
- package/dist/errors.js.map +1 -0
- package/dist/eval.cjs +14826 -0
- package/dist/eval.cjs.map +1 -0
- package/dist/eval.d.cts +35 -0
- package/dist/eval.d.ts +35 -0
- package/dist/eval.js +14821 -0
- package/dist/eval.js.map +1 -0
- package/dist/generate-object.d.ts +67 -0
- package/dist/handoff.d.ts +55 -0
- package/dist/index.cjs +17127 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1878 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.js +17095 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/agent-loop/loop-types.d.ts +29 -0
- package/dist/internal/agent-loop/loop.d.ts +2 -0
- package/dist/internal/agent-loop/message-builders.d.ts +6 -0
- package/dist/internal/agent-loop/tool-dispatch.d.ts +4 -0
- package/dist/internal/agent-loop/usage-and-cost.d.ts +25 -0
- package/dist/internal/budget/calendar-window.d.ts +19 -0
- package/dist/internal/budget/compute-cost.d.ts +28 -0
- package/dist/internal/budget/enforcement.d.ts +32 -0
- package/dist/internal/budget/ledger.d.ts +25 -0
- package/dist/internal/budget/normalize-usage.d.ts +27 -0
- package/dist/internal/budget/pricing-registry.d.ts +36 -0
- package/dist/internal/budget/registry.d.ts +16 -0
- package/dist/internal/budget/usage-accumulator.d.ts +31 -0
- package/dist/internal/cache/cosine.d.ts +14 -0
- package/dist/internal/cache/embed-helper.d.ts +15 -0
- package/dist/internal/cache/key.d.ts +15 -0
- package/dist/internal/cache/lookup.d.ts +28 -0
- package/dist/internal/cache/store-handler.d.ts +24 -0
- package/dist/internal/cache/store-json.d.ts +48 -0
- package/dist/internal/cache/store.d.ts +54 -0
- package/dist/internal/cache/telemetry.d.ts +20 -0
- package/dist/internal/cache/ttl.d.ts +11 -0
- package/dist/internal/catalog/fixtures.d.ts +16 -0
- package/dist/internal/catalog/local-models.d.ts +24 -0
- package/dist/internal/cron/run-job.d.ts +1 -0
- package/dist/internal/cron/scheduler.d.ts +1 -0
- package/dist/internal/cron/store.d.ts +1 -0
- package/dist/internal/cron/validate.d.ts +1 -0
- package/dist/internal/env.d.ts +1 -0
- package/dist/internal/errors/mappers/anthropic.d.ts +30 -0
- package/dist/internal/errors/mappers/bedrock.d.ts +16 -0
- package/dist/internal/errors/mappers/ollama.d.ts +41 -0
- package/dist/internal/errors/mappers/openai-compatible.d.ts +25 -0
- package/dist/internal/errors/mappers/shared.d.ts +10 -0
- package/dist/internal/errors/mappers/vertex.d.ts +15 -0
- package/dist/internal/eval/aggregate.d.ts +9 -0
- package/dist/internal/eval/dataset-iter.d.ts +9 -0
- package/dist/internal/eval/runner.d.ts +9 -0
- package/dist/internal/eval/single-flight.d.ts +16 -0
- package/dist/internal/eval/telemetry.d.ts +23 -0
- package/dist/internal/fixture-mode.d.ts +16 -0
- package/dist/internal/handoff/dispatcher.d.ts +29 -0
- package/dist/internal/handoff/registry.d.ts +23 -0
- package/dist/internal/handoff/telemetry.d.ts +18 -0
- package/dist/internal/handoff/tool-injector.d.ts +34 -0
- package/dist/internal/http.d.ts +1 -0
- package/dist/internal/ids.d.ts +1 -0
- package/dist/internal/judge/judge-call.d.ts +35 -0
- package/dist/internal/judge/parse-verdict.d.ts +11 -0
- package/dist/internal/judge/types.d.ts +17 -0
- package/dist/internal/llm/anthropic-shared.d.ts +89 -0
- package/dist/internal/llm/anthropic.d.ts +9 -0
- package/dist/internal/llm/bedrock-anthropic.d.ts +36 -0
- package/dist/internal/llm/bedrock-token-cache.d.ts +18 -0
- package/dist/internal/llm/credential-pool-context.d.ts +11 -0
- package/dist/internal/llm/credential-pool-types.d.ts +22 -0
- package/dist/internal/llm/credential-pool.d.ts +18 -0
- package/dist/internal/llm/fallback-client.d.ts +1 -0
- package/dist/internal/llm/fault-injection.d.ts +50 -0
- package/dist/internal/llm/finish.d.ts +1 -0
- package/dist/internal/llm/model-identifier.d.ts +24 -0
- package/dist/internal/llm/ollama-native.d.ts +27 -0
- package/dist/internal/llm/openai.d.ts +9 -0
- package/dist/internal/llm/pool-aware-client.d.ts +16 -0
- package/dist/internal/llm/router.d.ts +17 -0
- package/dist/internal/llm/sse.d.ts +9 -0
- package/dist/internal/llm/stream-relay.d.ts +17 -0
- package/dist/internal/llm/types.d.ts +70 -0
- package/dist/internal/llm/vertex-anthropic.d.ts +40 -0
- package/dist/internal/llm/vertex-auth.d.ts +30 -0
- package/dist/internal/llm/vertex-gemini.d.ts +28 -0
- package/dist/internal/llm/vertex-router.d.ts +21 -0
- package/dist/internal/mcp/client.d.ts +16 -0
- package/dist/internal/memory/active-memory-cache.d.ts +10 -0
- package/dist/internal/memory/active-memory.d.ts +45 -0
- package/dist/internal/memory/adapters/catalog.d.ts +1 -0
- package/dist/internal/memory/adapters/deepinfra-embedding.d.ts +2 -0
- package/dist/internal/memory/adapters/mistral-embedding.d.ts +2 -0
- package/dist/internal/memory/adapters/ollama-embedding.d.ts +34 -0
- package/dist/internal/memory/adapters/openai-compatible.d.ts +23 -0
- package/dist/internal/memory/adapters/openai-embedding.d.ts +2 -0
- package/dist/internal/memory/adapters/openrouter-embedding.d.ts +2 -0
- package/dist/internal/memory/adapters/voyage-embedding.d.ts +2 -0
- package/dist/internal/memory/atomic-write.d.ts +7 -0
- package/dist/internal/memory/chunk-markdown.d.ts +2 -0
- package/dist/internal/memory/circuit-breaker.d.ts +22 -0
- package/dist/internal/memory/cwd-mutex.d.ts +1 -0
- package/dist/internal/memory/dreaming/diary.d.ts +4 -0
- package/dist/internal/memory/dreaming/phases.d.ts +15 -0
- package/dist/internal/memory/dreaming/run.d.ts +10 -0
- package/dist/internal/memory/embedding-adapter.d.ts +42 -0
- package/dist/internal/memory/embedding-cache.d.ts +1 -0
- package/dist/internal/memory/index-db.d.ts +10 -0
- package/dist/internal/memory/index-manager-dispatch.d.ts +23 -0
- package/dist/internal/memory/index-manager.d.ts +68 -0
- package/dist/internal/memory/index-schema.d.ts +21 -0
- package/dist/internal/memory/lance-index.d.ts +32 -0
- package/dist/internal/memory/lance-memory-adapter.d.ts +43 -0
- package/dist/internal/memory/markdown-store.d.ts +16 -0
- package/dist/internal/memory/memory-index.d.ts +52 -0
- package/dist/internal/memory/migrate-sqlite-to-lance.d.ts +15 -0
- package/dist/internal/memory/migration.d.ts +9 -0
- package/dist/internal/memory/reader.d.ts +8 -0
- package/dist/internal/memory/session-loader.d.ts +1 -0
- package/dist/internal/memory/session-summary-writer.d.ts +2 -0
- package/dist/internal/memory/sqlite-vec-loader.d.ts +3 -0
- package/dist/internal/memory/tools.d.ts +14 -0
- package/dist/internal/memory/transcript-store.d.ts +1 -0
- package/dist/internal/memory/types.d.ts +17 -0
- package/dist/internal/memory/vec-index.d.ts +28 -0
- package/dist/internal/memory/wiki-loader.d.ts +2 -0
- package/dist/internal/observability/tracer-loader.d.ts +20 -0
- package/dist/internal/persistence/atomic-write.d.ts +1 -0
- package/dist/internal/persistence/conversation-storage-fs.d.ts +37 -0
- package/dist/internal/persistence/conversation-storage-memory.d.ts +24 -0
- package/dist/internal/persistence/cwd-mutex.d.ts +1 -0
- package/dist/internal/persistence/file-lock.d.ts +14 -0
- package/dist/internal/persistence/fts5-sanitize.d.ts +16 -0
- package/dist/internal/persistence/markdown-config-loader.d.ts +35 -0
- package/dist/internal/persistence/paths.d.ts +19 -0
- package/dist/internal/persistence/persistence-schema.d.ts +17 -0
- package/dist/internal/persistence/schema-version.d.ts +13 -0
- package/dist/internal/persistence/sqlite-wal.d.ts +10 -0
- package/dist/internal/personality/context.d.ts +17 -0
- package/dist/internal/personality/registry.d.ts +17 -0
- package/dist/internal/personality/store.d.ts +27 -0
- package/dist/internal/personality/switch.d.ts +36 -0
- package/dist/internal/personality/types.d.ts +18 -0
- package/dist/internal/plugins/context.d.ts +31 -0
- package/dist/internal/plugins/manager.d.ts +37 -0
- package/dist/internal/plugins/types.d.ts +102 -0
- package/dist/internal/providers/builtin/anthropic.d.ts +2 -0
- package/dist/internal/providers/builtin/bedrock.d.ts +25 -0
- package/dist/internal/providers/builtin/gemini.d.ts +10 -0
- package/dist/internal/providers/builtin/index.d.ts +19 -0
- package/dist/internal/providers/builtin/llamacpp.d.ts +1 -0
- package/dist/internal/providers/builtin/lmstudio.d.ts +1 -0
- package/dist/internal/providers/builtin/ollama.d.ts +17 -0
- package/dist/internal/providers/builtin/openai.d.ts +2 -0
- package/dist/internal/providers/builtin/openrouter.d.ts +2 -0
- package/dist/internal/providers/builtin/vertex.d.ts +27 -0
- package/dist/internal/providers/discovery.d.ts +14 -0
- package/dist/internal/providers/index.d.ts +8 -0
- package/dist/internal/providers/registry.d.ts +12 -0
- package/dist/internal/providers/types.d.ts +27 -0
- package/dist/internal/runtime/abort-utils.d.ts +21 -0
- package/dist/internal/runtime/agent-factory-registry.d.ts +16 -0
- package/dist/internal/runtime/agent-registry-store.d.ts +61 -0
- package/dist/internal/runtime/agent-registry.d.ts +34 -0
- package/dist/internal/runtime/agent-session-store.d.ts +3 -0
- package/dist/internal/runtime/agent-session.d.ts +2 -0
- package/dist/internal/runtime/async-local-storage.d.ts +20 -0
- package/dist/internal/runtime/async-semaphore.d.ts +24 -0
- package/dist/internal/runtime/budget.d.ts +36 -0
- package/dist/internal/runtime/cloud-agent.d.ts +1 -0
- package/dist/internal/runtime/cloud-config-serializer.d.ts +3 -0
- package/dist/internal/runtime/cloud-payload-types.d.ts +56 -0
- package/dist/internal/runtime/cloud-run.d.ts +1 -0
- package/dist/internal/runtime/cloud-tool-parity.d.ts +1 -0
- package/dist/internal/runtime/context-aggregator.d.ts +26 -0
- package/dist/internal/runtime/context-discovery-runner.d.ts +27 -0
- package/dist/internal/runtime/context-discovery.d.ts +21 -0
- package/dist/internal/runtime/context-frontmatter.d.ts +16 -0
- package/dist/internal/runtime/context-import-resolver.d.ts +24 -0
- package/dist/internal/runtime/context-loaders.d.ts +42 -0
- package/dist/internal/runtime/context-manager.d.ts +11 -0
- package/dist/internal/runtime/context-mdc-parser.d.ts +24 -0
- package/dist/internal/runtime/default-model.d.ts +1 -0
- package/dist/internal/runtime/fixture-events.d.ts +12 -0
- package/dist/internal/runtime/fixture-responder.d.ts +1 -0
- package/dist/internal/runtime/fixture-run-base.d.ts +45 -0
- package/dist/internal/runtime/fixture-scripts.d.ts +21 -0
- package/dist/internal/runtime/fixture-types.d.ts +1 -0
- package/dist/internal/runtime/fork-agent.d.ts +15 -0
- package/dist/internal/runtime/hooks-executor.d.ts +35 -0
- package/dist/internal/runtime/hooks-frontmatter.d.ts +26 -0
- package/dist/internal/runtime/hooks-source.d.ts +22 -0
- package/dist/internal/runtime/live-agent-registry.d.ts +87 -0
- package/dist/internal/runtime/local-agent-bootstrap.d.ts +37 -0
- package/dist/internal/runtime/local-agent-dispatch.d.ts +57 -0
- package/dist/internal/runtime/local-agent-invalidate.d.ts +8 -0
- package/dist/internal/runtime/local-agent-memory-direct.d.ts +12 -0
- package/dist/internal/runtime/local-agent-memory-hooks.d.ts +41 -0
- package/dist/internal/runtime/local-agent-memory.d.ts +1 -0
- package/dist/internal/runtime/local-agent-personality-extensions.d.ts +19 -0
- package/dist/internal/runtime/local-agent-plugins.d.ts +13 -0
- package/dist/internal/runtime/local-agent-runtime-extensions.d.ts +13 -0
- package/dist/internal/runtime/local-agent-task-wrap.d.ts +11 -0
- package/dist/internal/runtime/local-agent.d.ts +1 -0
- package/dist/internal/runtime/local-run.d.ts +1 -0
- package/dist/internal/runtime/memory-store.d.ts +4 -0
- package/dist/internal/runtime/plugin-frontmatter.d.ts +17 -0
- package/dist/internal/runtime/plugins-manager.d.ts +1 -0
- package/dist/internal/runtime/post-run-lifecycle.d.ts +1 -0
- package/dist/internal/runtime/providers-manager.d.ts +1 -0
- package/dist/internal/runtime/real-cloud-run.d.ts +2 -0
- package/dist/internal/runtime/real-local-run.d.ts +2 -0
- package/dist/internal/runtime/run-registry.d.ts +5 -0
- package/dist/internal/runtime/run-until.d.ts +22 -0
- package/dist/internal/runtime/shell-tool.d.ts +7 -0
- package/dist/internal/runtime/skill-frontmatter.d.ts +1 -0
- package/dist/internal/runtime/skills-manager.d.ts +1 -0
- package/dist/internal/runtime/spawn-collect.d.ts +8 -0
- package/dist/internal/runtime/subagents-loader.d.ts +1 -0
- package/dist/internal/runtime/system-prompt/escape.d.ts +1 -0
- package/dist/internal/runtime/system-prompt/local-assembly.d.ts +1 -0
- package/dist/internal/runtime/system-prompt/pipeline.d.ts +1 -0
- package/dist/internal/runtime/system-prompt/providers/active-memory-provider.d.ts +1 -0
- package/dist/internal/runtime/system-prompt/providers/base-provider.d.ts +1 -0
- package/dist/internal/runtime/system-prompt/providers/context-provider.d.ts +1 -0
- package/dist/internal/runtime/system-prompt/providers/memory-provider.d.ts +1 -0
- package/dist/internal/runtime/system-prompt/providers/skills-provider.d.ts +1 -0
- package/dist/internal/runtime/system-prompt/safe-call.d.ts +1 -0
- package/dist/internal/runtime/system-prompt/types.d.ts +5 -0
- package/dist/internal/runtime/system-prompt.d.ts +1 -0
- package/dist/internal/runtime/validate-agent-options.d.ts +1 -0
- package/dist/internal/runtime/workspace-dir.d.ts +9 -0
- package/dist/internal/runtime/yaml-frontmatter.d.ts +20 -0
- package/dist/internal/scorers/llm-judge.d.ts +24 -0
- package/dist/internal/security/index.d.ts +11 -0
- package/dist/internal/security/path-guard.d.ts +56 -0
- package/dist/internal/security/redact.d.ts +21 -0
- package/dist/internal/structured-output-helpers.d.ts +54 -0
- package/dist/internal/task/registry.d.ts +61 -0
- package/dist/internal/task/ring-buffer.d.ts +10 -0
- package/dist/internal/task/store.d.ts +59 -0
- package/dist/internal/task/subscribe.d.ts +15 -0
- package/dist/internal/task/telemetry.d.ts +27 -0
- package/dist/internal/telemetry/adapter-registry.d.ts +2 -0
- package/dist/internal/telemetry/adapters/langfuse.d.ts +2 -0
- package/dist/internal/telemetry/adapters/posthog.d.ts +2 -0
- package/dist/internal/telemetry/adapters/sentry.d.ts +2 -0
- package/dist/internal/telemetry/safe-require.d.ts +1 -0
- package/dist/internal/telemetry/tracer.d.ts +18 -0
- package/dist/internal/tool-dispatch/repair-middleware.d.ts +34 -0
- package/dist/internal/tool-dispatch/strip-think.d.ts +22 -0
- package/dist/internal/tool-registry/personality-filter.d.ts +37 -0
- package/dist/internal/workflow/ctx.d.ts +19 -0
- package/dist/internal/workflow/error-shape.d.ts +7 -0
- package/dist/internal/workflow/executor.d.ts +15 -0
- package/dist/internal/workflow/index.d.ts +12 -0
- package/dist/internal/workflow/retry-policy.d.ts +14 -0
- package/dist/internal/workflow/run-id.d.ts +9 -0
- package/dist/internal/workflow/single-flight.d.ts +18 -0
- package/dist/internal/workflow/snapshot-store.d.ts +23 -0
- package/dist/internal/workflow/step-agent.d.ts +12 -0
- package/dist/internal/workflow/step-branch.d.ts +10 -0
- package/dist/internal/workflow/step-dowhile.d.ts +8 -0
- package/dist/internal/workflow/step-fn.d.ts +10 -0
- package/dist/internal/workflow/step-foreach.d.ts +11 -0
- package/dist/internal/workflow/step-parallel.d.ts +17 -0
- package/dist/internal/workflow/step-sleep.d.ts +7 -0
- package/dist/internal/workflow/telemetry.d.ts +23 -0
- package/dist/internal/zod/to-json-schema.d.ts +21 -0
- package/dist/memory-adapter-helpers.d.ts +28 -0
- package/dist/memory.d.ts +123 -0
- package/dist/migrate.d.ts +33 -0
- package/dist/path-safety.cjs +126 -0
- package/dist/path-safety.cjs.map +1 -0
- package/dist/path-safety.d.cts +15 -0
- package/dist/path-safety.d.ts +15 -0
- package/dist/path-safety.js +120 -0
- package/dist/path-safety.js.map +1 -0
- package/dist/run-DkCD5DeO.d.cts +2181 -0
- package/dist/run-DkCD5DeO.d.ts +2181 -0
- package/dist/scorers.d.ts +75 -0
- package/dist/security.d.ts +67 -0
- package/dist/stream-object.d.ts +74 -0
- package/dist/task-store.cjs +237 -0
- package/dist/task-store.cjs.map +1 -0
- package/dist/task-store.d.cts +8 -0
- package/dist/task-store.d.ts +8 -0
- package/dist/task-store.js +233 -0
- package/dist/task-store.js.map +1 -0
- package/dist/task.d.ts +87 -0
- package/dist/theokit.d.ts +84 -0
- package/dist/tools/_path-scope.d.cts +8 -0
- package/dist/tools/_path-scope.d.ts +8 -0
- package/dist/tools/_subprocess.d.cts +28 -0
- package/dist/tools/_subprocess.d.ts +28 -0
- package/dist/tools/git-diff.d.cts +22 -0
- package/dist/tools/git-diff.d.ts +22 -0
- package/dist/tools/index.d.cts +29 -0
- package/dist/tools/index.d.ts +29 -0
- package/dist/tools/list-dir.d.cts +26 -0
- package/dist/tools/list-dir.d.ts +26 -0
- package/dist/tools/read-file.d.cts +31 -0
- package/dist/tools/read-file.d.ts +31 -0
- package/dist/tools/run-vitest.d.cts +46 -0
- package/dist/tools/run-vitest.d.ts +46 -0
- package/dist/tools/search-text.d.cts +32 -0
- package/dist/tools/search-text.d.ts +32 -0
- package/dist/tools.cjs +690 -0
- package/dist/tools.cjs.map +1 -0
- package/dist/tools.js +683 -0
- package/dist/tools.js.map +1 -0
- package/dist/trajectory-helpers.d.ts +31 -0
- package/dist/types/agent.d.ts +771 -0
- package/dist/types/batch.d.ts +112 -0
- package/dist/types/budget.d.ts +88 -0
- package/dist/types/cache.d.ts +76 -0
- package/dist/types/context.d.ts +93 -0
- package/dist/types/conversation-storage.d.ts +76 -0
- package/dist/types/conversation.d.ts +90 -0
- package/dist/types/cron.d.ts +150 -0
- package/dist/types/eval.d.ts +132 -0
- package/dist/types/goal-events.d.ts +95 -0
- package/dist/types/handoff.d.ts +135 -0
- package/dist/types/index.d.ts +20 -0
- package/dist/types/mcp.d.ts +64 -0
- package/dist/types/memory-adapter.d.ts +175 -0
- package/dist/types/messages.d.ts +154 -0
- package/dist/types/providers.d.ts +102 -0
- package/dist/types/run.d.ts +215 -0
- package/dist/types/task.d.ts +131 -0
- package/dist/types/theokit.d.ts +61 -0
- package/dist/types/trajectory.d.ts +49 -0
- package/dist/types/updates.d.ts +148 -0
- package/dist/types/usage.d.ts +61 -0
- package/dist/types/workflow.d.ts +217 -0
- package/dist/workflow.cjs +2405 -0
- package/dist/workflow.cjs.map +1 -0
- package/dist/workflow.d.cts +97 -0
- package/dist/workflow.d.ts +97 -0
- package/dist/workflow.js +2398 -0
- package/dist/workflow.js.map +1 -0
- package/package.json +183 -0
|
@@ -0,0 +1,2405 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var promises = require('fs/promises');
|
|
4
|
+
var path = require('path');
|
|
5
|
+
var module$1 = require('module');
|
|
6
|
+
var fs = require('fs');
|
|
7
|
+
var async_hooks = require('async_hooks');
|
|
8
|
+
var crypto = require('crypto');
|
|
9
|
+
var zod = require('zod');
|
|
10
|
+
|
|
11
|
+
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
12
|
+
var __defProp = Object.defineProperty;
|
|
13
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
14
|
+
var __esm = (fn2, res) => function __init() {
|
|
15
|
+
return fn2 && (res = (0, fn2[__getOwnPropNames(fn2)[0]])(fn2 = 0)), res;
|
|
16
|
+
};
|
|
17
|
+
var __export = (target, all) => {
|
|
18
|
+
for (var name in all)
|
|
19
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
// src/errors.ts
|
|
23
|
+
var TheokitAgentError, ConfigurationError, UnsupportedRunOperationError, InvalidTaskIdError, TaskNotFoundError;
|
|
24
|
+
var init_errors = __esm({
|
|
25
|
+
"src/errors.ts"() {
|
|
26
|
+
TheokitAgentError = class extends Error {
|
|
27
|
+
name = "TheokitAgentError";
|
|
28
|
+
isRetryable;
|
|
29
|
+
code;
|
|
30
|
+
protoErrorCode;
|
|
31
|
+
metadata;
|
|
32
|
+
constructor(message, options = {}) {
|
|
33
|
+
super(message, options.cause !== void 0 ? { cause: options.cause } : void 0);
|
|
34
|
+
this.isRetryable = options.isRetryable ?? false;
|
|
35
|
+
if (options.code !== void 0) this.code = options.code;
|
|
36
|
+
if (options.protoErrorCode !== void 0) this.protoErrorCode = options.protoErrorCode;
|
|
37
|
+
if (options.metadata !== void 0) this.metadata = options.metadata;
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
ConfigurationError = class extends TheokitAgentError {
|
|
41
|
+
name = "ConfigurationError";
|
|
42
|
+
constructor(message, options = {}) {
|
|
43
|
+
super(message, { ...options, isRetryable: false });
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
UnsupportedRunOperationError = class extends TheokitAgentError {
|
|
47
|
+
name = "UnsupportedRunOperationError";
|
|
48
|
+
operation;
|
|
49
|
+
constructor(message, operation, options = {}) {
|
|
50
|
+
super(message, {
|
|
51
|
+
...options,
|
|
52
|
+
isRetryable: false,
|
|
53
|
+
code: options.code ?? "unsupported_run_operation"
|
|
54
|
+
});
|
|
55
|
+
this.operation = operation;
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
InvalidTaskIdError = class extends TheokitAgentError {
|
|
59
|
+
name = "InvalidTaskIdError";
|
|
60
|
+
taskId;
|
|
61
|
+
constructor(message, taskId, options = {}) {
|
|
62
|
+
super(message, {
|
|
63
|
+
...options,
|
|
64
|
+
isRetryable: false,
|
|
65
|
+
code: "invalid_task_id"
|
|
66
|
+
});
|
|
67
|
+
this.taskId = taskId;
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
TaskNotFoundError = class extends TheokitAgentError {
|
|
71
|
+
name = "TaskNotFoundError";
|
|
72
|
+
taskId;
|
|
73
|
+
constructor(taskId, options = {}) {
|
|
74
|
+
super(`Task not found: ${taskId}`, {
|
|
75
|
+
...options,
|
|
76
|
+
isRetryable: false,
|
|
77
|
+
code: "task_not_found"
|
|
78
|
+
});
|
|
79
|
+
this.taskId = taskId;
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
// src/types/workflow.ts
|
|
86
|
+
exports.WorkflowDuplicateStepIdError = void 0; exports.WorkflowAlreadyRunningError = void 0; exports.WorkflowSnapshotNotFoundError = void 0; exports.WorkflowMaxIterationsExceededError = void 0; exports.WorkflowNotSerializableError = void 0; exports.WorkflowResumeStepNotFoundError = void 0; exports.WorkflowParallelError = void 0; exports.WorkflowCompensateNotImplementedError = void 0;
|
|
87
|
+
var init_workflow = __esm({
|
|
88
|
+
"src/types/workflow.ts"() {
|
|
89
|
+
exports.WorkflowDuplicateStepIdError = class extends Error {
|
|
90
|
+
constructor(stepId) {
|
|
91
|
+
super(`Duplicate step id "${stepId}" in workflow.`);
|
|
92
|
+
this.stepId = stepId;
|
|
93
|
+
}
|
|
94
|
+
stepId;
|
|
95
|
+
name = "WorkflowDuplicateStepIdError";
|
|
96
|
+
};
|
|
97
|
+
exports.WorkflowAlreadyRunningError = class extends Error {
|
|
98
|
+
constructor(workflowName, runId) {
|
|
99
|
+
super(`Workflow "${workflowName}" run "${runId}" already in-flight.`);
|
|
100
|
+
this.workflowName = workflowName;
|
|
101
|
+
this.runId = runId;
|
|
102
|
+
}
|
|
103
|
+
workflowName;
|
|
104
|
+
runId;
|
|
105
|
+
name = "WorkflowAlreadyRunningError";
|
|
106
|
+
};
|
|
107
|
+
exports.WorkflowSnapshotNotFoundError = class extends Error {
|
|
108
|
+
constructor(runId) {
|
|
109
|
+
super(`No snapshot found for runId "${runId}". Configure persistence to enable resume.`);
|
|
110
|
+
this.runId = runId;
|
|
111
|
+
}
|
|
112
|
+
runId;
|
|
113
|
+
name = "WorkflowSnapshotNotFoundError";
|
|
114
|
+
};
|
|
115
|
+
exports.WorkflowMaxIterationsExceededError = class extends Error {
|
|
116
|
+
constructor(stepId, maxIterations) {
|
|
117
|
+
super(`Step "${stepId}" exceeded max iterations (${maxIterations}).`);
|
|
118
|
+
this.stepId = stepId;
|
|
119
|
+
this.maxIterations = maxIterations;
|
|
120
|
+
}
|
|
121
|
+
stepId;
|
|
122
|
+
maxIterations;
|
|
123
|
+
name = "WorkflowMaxIterationsExceededError";
|
|
124
|
+
};
|
|
125
|
+
exports.WorkflowNotSerializableError = class extends Error {
|
|
126
|
+
constructor(stepId, underlying) {
|
|
127
|
+
super(
|
|
128
|
+
`Workflow snapshot at step "${stepId}" failed to serialize as JSON: ${underlying.message}. Persisted snapshots support only JSON-serializable values (no BigInt, no circular refs, no class instances with cycles).`
|
|
129
|
+
);
|
|
130
|
+
this.stepId = stepId;
|
|
131
|
+
this.underlying = underlying;
|
|
132
|
+
}
|
|
133
|
+
stepId;
|
|
134
|
+
underlying;
|
|
135
|
+
name = "WorkflowNotSerializableError";
|
|
136
|
+
};
|
|
137
|
+
exports.WorkflowResumeStepNotFoundError = class extends Error {
|
|
138
|
+
constructor(stepId, workflowName) {
|
|
139
|
+
super(
|
|
140
|
+
`Cannot resume: step "${stepId}" not found in workflow "${workflowName}". The Workflow definition diverged from the snapshot.`
|
|
141
|
+
);
|
|
142
|
+
this.stepId = stepId;
|
|
143
|
+
this.workflowName = workflowName;
|
|
144
|
+
}
|
|
145
|
+
stepId;
|
|
146
|
+
workflowName;
|
|
147
|
+
name = "WorkflowResumeStepNotFoundError";
|
|
148
|
+
};
|
|
149
|
+
exports.WorkflowParallelError = class extends AggregateError {
|
|
150
|
+
constructor(errors, stepId) {
|
|
151
|
+
super(errors, `${errors.length} branch(es) failed in parallel step "${stepId}".`);
|
|
152
|
+
this.stepId = stepId;
|
|
153
|
+
}
|
|
154
|
+
stepId;
|
|
155
|
+
name = "WorkflowParallelError";
|
|
156
|
+
};
|
|
157
|
+
exports.WorkflowCompensateNotImplementedError = class extends Error {
|
|
158
|
+
constructor(stepId) {
|
|
159
|
+
super(
|
|
160
|
+
`Step "${stepId}" defines compensate, but saga engine is deferred to v1.2. Remove compensate or implement rollback manually.`
|
|
161
|
+
);
|
|
162
|
+
this.stepId = stepId;
|
|
163
|
+
}
|
|
164
|
+
stepId;
|
|
165
|
+
name = "WorkflowCompensateNotImplementedError";
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
async function replaceFileAtomic(filePath, content) {
|
|
170
|
+
const tmp = `${filePath}.${process.pid}.${Math.random().toString(36).slice(2, 10)}.tmp`;
|
|
171
|
+
const handle = await promises.open(tmp, "w");
|
|
172
|
+
try {
|
|
173
|
+
await handle.writeFile(content, "utf8");
|
|
174
|
+
await handle.sync();
|
|
175
|
+
} finally {
|
|
176
|
+
await handle.close();
|
|
177
|
+
}
|
|
178
|
+
try {
|
|
179
|
+
await promises.rename(tmp, filePath);
|
|
180
|
+
} catch (cause) {
|
|
181
|
+
await promises.unlink(tmp).catch(() => void 0);
|
|
182
|
+
throw cause;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
async function atomicWriteText(filePath, content) {
|
|
186
|
+
await promises.mkdir(path.dirname(filePath), { recursive: true });
|
|
187
|
+
await replaceFileAtomic(filePath, content);
|
|
188
|
+
}
|
|
189
|
+
var init_atomic_write = __esm({
|
|
190
|
+
"src/internal/persistence/atomic-write.ts"() {
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
function getSnapshotStoreFor(options) {
|
|
194
|
+
if (options.persistence?.backend === "json") {
|
|
195
|
+
const dir = options.persistence.dir;
|
|
196
|
+
let store = jsonStores.get(dir);
|
|
197
|
+
if (store === void 0) {
|
|
198
|
+
store = new JsonFileWorkflowSnapshotStore(dir);
|
|
199
|
+
jsonStores.set(dir, store);
|
|
200
|
+
}
|
|
201
|
+
return store;
|
|
202
|
+
}
|
|
203
|
+
return memoryStore;
|
|
204
|
+
}
|
|
205
|
+
function __resetSnapshotStoresForTests() {
|
|
206
|
+
jsonStores.clear();
|
|
207
|
+
memoryStore.map.clear();
|
|
208
|
+
}
|
|
209
|
+
var InMemoryWorkflowSnapshotStore, JsonFileWorkflowSnapshotStore, memoryStore, jsonStores;
|
|
210
|
+
var init_snapshot_store = __esm({
|
|
211
|
+
"src/internal/workflow/snapshot-store.ts"() {
|
|
212
|
+
init_workflow();
|
|
213
|
+
init_atomic_write();
|
|
214
|
+
InMemoryWorkflowSnapshotStore = class {
|
|
215
|
+
map = /* @__PURE__ */ new Map();
|
|
216
|
+
async save(snapshot) {
|
|
217
|
+
try {
|
|
218
|
+
JSON.stringify(snapshot);
|
|
219
|
+
} catch (err) {
|
|
220
|
+
throw new exports.WorkflowNotSerializableError(
|
|
221
|
+
snapshot.currentStepId,
|
|
222
|
+
err instanceof Error ? err : new Error(String(err))
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
this.map.set(snapshot.runId, snapshot);
|
|
226
|
+
}
|
|
227
|
+
async load(runId) {
|
|
228
|
+
return this.map.get(runId);
|
|
229
|
+
}
|
|
230
|
+
async delete(runId) {
|
|
231
|
+
this.map.delete(runId);
|
|
232
|
+
}
|
|
233
|
+
async list(workflowName) {
|
|
234
|
+
return [...this.map.values()].filter((s) => workflowName === void 0 || s.workflowName === workflowName).map((s) => ({
|
|
235
|
+
runId: s.runId,
|
|
236
|
+
workflowName: s.workflowName,
|
|
237
|
+
suspendedAt: s.suspendedAt
|
|
238
|
+
}));
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
JsonFileWorkflowSnapshotStore = class {
|
|
242
|
+
constructor(dir) {
|
|
243
|
+
this.dir = dir;
|
|
244
|
+
}
|
|
245
|
+
dir;
|
|
246
|
+
filePath(runId) {
|
|
247
|
+
return path.join(this.dir, `${runId}.json`);
|
|
248
|
+
}
|
|
249
|
+
async save(snapshot) {
|
|
250
|
+
let serialized;
|
|
251
|
+
try {
|
|
252
|
+
serialized = JSON.stringify(snapshot);
|
|
253
|
+
} catch (err) {
|
|
254
|
+
throw new exports.WorkflowNotSerializableError(
|
|
255
|
+
snapshot.currentStepId,
|
|
256
|
+
err instanceof Error ? err : new Error(String(err))
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
await promises.mkdir(this.dir, { recursive: true });
|
|
260
|
+
await atomicWriteText(this.filePath(snapshot.runId), serialized);
|
|
261
|
+
}
|
|
262
|
+
async load(runId) {
|
|
263
|
+
try {
|
|
264
|
+
const raw = await promises.readFile(this.filePath(runId), "utf8");
|
|
265
|
+
return JSON.parse(raw);
|
|
266
|
+
} catch (err) {
|
|
267
|
+
if (err.code === "ENOENT") return void 0;
|
|
268
|
+
throw err;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
async delete(runId) {
|
|
272
|
+
try {
|
|
273
|
+
await (await import('fs/promises')).unlink(this.filePath(runId));
|
|
274
|
+
} catch (err) {
|
|
275
|
+
if (err.code !== "ENOENT") throw err;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
async readEntriesOrEmpty() {
|
|
279
|
+
try {
|
|
280
|
+
return await promises.readdir(this.dir);
|
|
281
|
+
} catch (err) {
|
|
282
|
+
if (err.code === "ENOENT") return [];
|
|
283
|
+
throw err;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
async readSnapshotSafe(file) {
|
|
287
|
+
try {
|
|
288
|
+
const raw = await promises.readFile(path.join(this.dir, file), "utf8");
|
|
289
|
+
return JSON.parse(raw);
|
|
290
|
+
} catch {
|
|
291
|
+
return void 0;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
async list(workflowName) {
|
|
295
|
+
const entries = await this.readEntriesOrEmpty();
|
|
296
|
+
const results = [];
|
|
297
|
+
for (const file of entries) {
|
|
298
|
+
if (!file.endsWith(".json")) continue;
|
|
299
|
+
const snap = await this.readSnapshotSafe(file);
|
|
300
|
+
if (snap === void 0) continue;
|
|
301
|
+
if (workflowName !== void 0 && snap.workflowName !== workflowName) continue;
|
|
302
|
+
results.push({
|
|
303
|
+
runId: snap.runId,
|
|
304
|
+
workflowName: snap.workflowName,
|
|
305
|
+
suspendedAt: snap.suspendedAt
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
return results;
|
|
309
|
+
}
|
|
310
|
+
};
|
|
311
|
+
memoryStore = new InMemoryWorkflowSnapshotStore();
|
|
312
|
+
jsonStores = /* @__PURE__ */ new Map();
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
// src/internal/workflow/ctx.ts
|
|
317
|
+
function makeStepContext(runId, signal) {
|
|
318
|
+
return {
|
|
319
|
+
runId,
|
|
320
|
+
signal,
|
|
321
|
+
log: {
|
|
322
|
+
debug: (msg, attrs) => emit("debug", runId, msg, attrs),
|
|
323
|
+
info: (msg, attrs) => emit("info", runId, msg, attrs),
|
|
324
|
+
warn: (msg, attrs) => emit("warn", runId, msg, attrs)
|
|
325
|
+
},
|
|
326
|
+
suspend: async (payload) => {
|
|
327
|
+
throw new WorkflowSuspendedSentinel(payload);
|
|
328
|
+
}
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
function emit(level, runId, msg, attrs) {
|
|
332
|
+
const tag = `[workflow ${runId}]`;
|
|
333
|
+
if (attrs !== void 0) {
|
|
334
|
+
if (level === "warn") console.warn(tag, msg, attrs);
|
|
335
|
+
else console.log(tag, msg, attrs);
|
|
336
|
+
} else {
|
|
337
|
+
if (level === "warn") console.warn(tag, msg);
|
|
338
|
+
else console.log(tag, msg);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
function combineSignals(...signals) {
|
|
342
|
+
const valid = signals.filter((s) => s !== void 0);
|
|
343
|
+
if (valid.length === 0) return new AbortController().signal;
|
|
344
|
+
if (valid.length === 1) return valid[0];
|
|
345
|
+
const ctrl = new AbortController();
|
|
346
|
+
for (const s of valid) {
|
|
347
|
+
if (s.aborted) {
|
|
348
|
+
ctrl.abort(s.reason);
|
|
349
|
+
break;
|
|
350
|
+
}
|
|
351
|
+
s.addEventListener("abort", () => ctrl.abort(s.reason), { once: true });
|
|
352
|
+
}
|
|
353
|
+
return ctrl.signal;
|
|
354
|
+
}
|
|
355
|
+
var WorkflowSuspendedSentinel;
|
|
356
|
+
var init_ctx = __esm({
|
|
357
|
+
"src/internal/workflow/ctx.ts"() {
|
|
358
|
+
WorkflowSuspendedSentinel = class extends Error {
|
|
359
|
+
constructor(payload) {
|
|
360
|
+
super("__workflow_suspended__");
|
|
361
|
+
this.payload = payload;
|
|
362
|
+
}
|
|
363
|
+
payload;
|
|
364
|
+
name = "WorkflowSuspendedSentinel";
|
|
365
|
+
};
|
|
366
|
+
}
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
// src/internal/workflow/error-shape.ts
|
|
370
|
+
function errToShape(err) {
|
|
371
|
+
if (err instanceof Error) {
|
|
372
|
+
return { name: err.name, message: err.message };
|
|
373
|
+
}
|
|
374
|
+
return { name: "Error", message: String(err) };
|
|
375
|
+
}
|
|
376
|
+
var init_error_shape = __esm({
|
|
377
|
+
"src/internal/workflow/error-shape.ts"() {
|
|
378
|
+
}
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
// src/internal/workflow/run-id.ts
|
|
382
|
+
function mintRunId() {
|
|
383
|
+
return `wfr-${globalThis.crypto.randomUUID().replace(/-/g, "").slice(0, 8)}`;
|
|
384
|
+
}
|
|
385
|
+
var init_run_id = __esm({
|
|
386
|
+
"src/internal/workflow/run-id.ts"() {
|
|
387
|
+
}
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
// src/internal/workflow/single-flight.ts
|
|
391
|
+
function key(workflowId, runId) {
|
|
392
|
+
return `${workflowId}:${runId}`;
|
|
393
|
+
}
|
|
394
|
+
function acquireSingleFlight(workflowId, runId, workflowName) {
|
|
395
|
+
const k = key(workflowId, runId);
|
|
396
|
+
if (registry.has(k)) {
|
|
397
|
+
throw new exports.WorkflowAlreadyRunningError(workflowName, runId);
|
|
398
|
+
}
|
|
399
|
+
const controller = new AbortController();
|
|
400
|
+
registry.set(k, { controller });
|
|
401
|
+
return {
|
|
402
|
+
signal: controller.signal,
|
|
403
|
+
release: () => {
|
|
404
|
+
registry.delete(k);
|
|
405
|
+
}
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
var registry;
|
|
409
|
+
var init_single_flight = __esm({
|
|
410
|
+
"src/internal/workflow/single-flight.ts"() {
|
|
411
|
+
init_workflow();
|
|
412
|
+
registry = /* @__PURE__ */ new Map();
|
|
413
|
+
}
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
// src/internal/workflow/retry-policy.ts
|
|
417
|
+
function backoffConfigFromPolicy(policy) {
|
|
418
|
+
return {
|
|
419
|
+
max: policy.maxAttempts,
|
|
420
|
+
init: policy.initialBackoffMs ?? 1e3,
|
|
421
|
+
coef: policy.backoffCoefficient ?? 2,
|
|
422
|
+
cap: policy.maximumBackoffMs ?? 3e4,
|
|
423
|
+
nonRetryable: new Set(policy.nonRetryableErrors ?? DEFAULT_NON_RETRYABLE)
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
function throwIfAborted(signal) {
|
|
427
|
+
if (signal.aborted) {
|
|
428
|
+
throw new DOMException(String(signal.reason ?? "Aborted"), "AbortError");
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
function shouldRethrow(err, attempt, cfg) {
|
|
432
|
+
const errName = err instanceof Error ? err.name : "Error";
|
|
433
|
+
return cfg.nonRetryable.has(errName) || attempt === cfg.max;
|
|
434
|
+
}
|
|
435
|
+
async function tryOnce(fn2, attempt, cfg, signal) {
|
|
436
|
+
try {
|
|
437
|
+
const value = await fn2();
|
|
438
|
+
return { value, attempts: attempt };
|
|
439
|
+
} catch (err) {
|
|
440
|
+
if (shouldRethrow(err, attempt, cfg)) throw err;
|
|
441
|
+
await abortableSleep(Math.min(cfg.init * cfg.coef ** (attempt - 1), cfg.cap), signal);
|
|
442
|
+
return { kind: "retry" };
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
async function withRetry(fn2, policy, signal) {
|
|
446
|
+
const cfg = backoffConfigFromPolicy(policy);
|
|
447
|
+
for (let attempt = 1; attempt <= cfg.max; attempt += 1) {
|
|
448
|
+
throwIfAborted(signal);
|
|
449
|
+
const result = await tryOnce(fn2, attempt, cfg, signal);
|
|
450
|
+
if ("value" in result) return result;
|
|
451
|
+
}
|
|
452
|
+
throw new Error("withRetry: exhausted attempts without throwing");
|
|
453
|
+
}
|
|
454
|
+
async function abortableSleep(ms, signal) {
|
|
455
|
+
if (signal.aborted) {
|
|
456
|
+
throw new DOMException(String(signal.reason ?? "Aborted"), "AbortError");
|
|
457
|
+
}
|
|
458
|
+
return new Promise((resolve2, reject) => {
|
|
459
|
+
const timer = setTimeout(() => {
|
|
460
|
+
cleanup();
|
|
461
|
+
resolve2();
|
|
462
|
+
}, ms);
|
|
463
|
+
const onAbort = () => {
|
|
464
|
+
clearTimeout(timer);
|
|
465
|
+
cleanup();
|
|
466
|
+
reject(new DOMException(String(signal.reason ?? "Aborted"), "AbortError"));
|
|
467
|
+
};
|
|
468
|
+
const cleanup = () => {
|
|
469
|
+
signal.removeEventListener("abort", onAbort);
|
|
470
|
+
};
|
|
471
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
472
|
+
});
|
|
473
|
+
}
|
|
474
|
+
var DEFAULT_NON_RETRYABLE;
|
|
475
|
+
var init_retry_policy = __esm({
|
|
476
|
+
"src/internal/workflow/retry-policy.ts"() {
|
|
477
|
+
DEFAULT_NON_RETRYABLE = ["AbortError", "WorkflowSnapshotNotFoundError", "ConfigurationError"];
|
|
478
|
+
}
|
|
479
|
+
});
|
|
480
|
+
|
|
481
|
+
// src/internal/workflow/step-agent.ts
|
|
482
|
+
async function runAgentStep(step, input, ctx) {
|
|
483
|
+
const startedAt = Date.now();
|
|
484
|
+
const agentId = step.agent.agentId;
|
|
485
|
+
if (typeof agentId === "string" && agentId.startsWith("bc-")) {
|
|
486
|
+
return {
|
|
487
|
+
stepId: step.id,
|
|
488
|
+
kind: "agent",
|
|
489
|
+
status: "failed",
|
|
490
|
+
attempts: 0,
|
|
491
|
+
durationMs: Date.now() - startedAt,
|
|
492
|
+
error: errToShape(
|
|
493
|
+
new UnsupportedRunOperationError(
|
|
494
|
+
`Workflow agent steps not supported on CloudAgent yet (D244). agent="${agentId}", step="${step.id}"`,
|
|
495
|
+
"workflow"
|
|
496
|
+
)
|
|
497
|
+
)
|
|
498
|
+
};
|
|
499
|
+
}
|
|
500
|
+
let prompt;
|
|
501
|
+
try {
|
|
502
|
+
prompt = typeof step.promptTemplate === "string" ? step.promptTemplate : step.promptTemplate(input);
|
|
503
|
+
} catch (err) {
|
|
504
|
+
return {
|
|
505
|
+
stepId: step.id,
|
|
506
|
+
kind: "agent",
|
|
507
|
+
status: "failed",
|
|
508
|
+
attempts: 0,
|
|
509
|
+
durationMs: Date.now() - startedAt,
|
|
510
|
+
error: errToShape(err)
|
|
511
|
+
};
|
|
512
|
+
}
|
|
513
|
+
if (typeof prompt !== "string" || prompt.length === 0) {
|
|
514
|
+
return {
|
|
515
|
+
stepId: step.id,
|
|
516
|
+
kind: "agent",
|
|
517
|
+
status: "failed",
|
|
518
|
+
attempts: 0,
|
|
519
|
+
durationMs: Date.now() - startedAt,
|
|
520
|
+
error: errToShape(
|
|
521
|
+
new Error(`agentStep "${step.id}": rendered prompt must be a non-empty string`)
|
|
522
|
+
)
|
|
523
|
+
};
|
|
524
|
+
}
|
|
525
|
+
const exec = async () => {
|
|
526
|
+
const run = await step.agent.send(prompt);
|
|
527
|
+
const result = await run.wait();
|
|
528
|
+
if (result.status === "finished") {
|
|
529
|
+
return result.result ?? "";
|
|
530
|
+
}
|
|
531
|
+
if (result.status === "error") {
|
|
532
|
+
throw result.error ?? new Error("agent.send errored");
|
|
533
|
+
}
|
|
534
|
+
throw new Error(`Unexpected agent status: ${result.status}`);
|
|
535
|
+
};
|
|
536
|
+
try {
|
|
537
|
+
const { value, attempts } = step.retry !== void 0 ? await withRetry(exec, step.retry, ctx.signal) : { value: await exec(), attempts: 1 };
|
|
538
|
+
return {
|
|
539
|
+
stepId: step.id,
|
|
540
|
+
kind: "agent",
|
|
541
|
+
status: "completed",
|
|
542
|
+
attempts,
|
|
543
|
+
durationMs: Date.now() - startedAt,
|
|
544
|
+
output: value
|
|
545
|
+
};
|
|
546
|
+
} catch (err) {
|
|
547
|
+
if (err instanceof WorkflowSuspendedSentinel) throw err;
|
|
548
|
+
return {
|
|
549
|
+
stepId: step.id,
|
|
550
|
+
kind: "agent",
|
|
551
|
+
status: "failed",
|
|
552
|
+
attempts: 1,
|
|
553
|
+
durationMs: Date.now() - startedAt,
|
|
554
|
+
error: errToShape(err)
|
|
555
|
+
};
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
var init_step_agent = __esm({
|
|
559
|
+
"src/internal/workflow/step-agent.ts"() {
|
|
560
|
+
init_errors();
|
|
561
|
+
init_ctx();
|
|
562
|
+
init_error_shape();
|
|
563
|
+
init_retry_policy();
|
|
564
|
+
}
|
|
565
|
+
});
|
|
566
|
+
|
|
567
|
+
// src/internal/security/redact.ts
|
|
568
|
+
function readEnvOnce() {
|
|
569
|
+
const raw = process.env.THEOKIT_REDACT_SECRETS;
|
|
570
|
+
if (raw === void 0) return true;
|
|
571
|
+
return ["1", "true", "yes", "on"].includes(raw.toLowerCase());
|
|
572
|
+
}
|
|
573
|
+
function maskToken(token) {
|
|
574
|
+
if (token.length < 18) return "***";
|
|
575
|
+
return `${token.slice(0, 6)}...${token.slice(-4)}`;
|
|
576
|
+
}
|
|
577
|
+
function coerceToString(value) {
|
|
578
|
+
if (typeof value === "string") return value;
|
|
579
|
+
if (value === null || value === void 0) return null;
|
|
580
|
+
if (typeof value === "object") {
|
|
581
|
+
try {
|
|
582
|
+
const s = JSON.stringify(value);
|
|
583
|
+
return s === void 0 ? null : s;
|
|
584
|
+
} catch {
|
|
585
|
+
return "[unredactable: circular]";
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
return String(value);
|
|
589
|
+
}
|
|
590
|
+
function redactSecrets(text, opts) {
|
|
591
|
+
const coerced = coerceToString(text);
|
|
592
|
+
if (coerced === null) return "";
|
|
593
|
+
if (!REDACT_ENABLED) return coerced;
|
|
594
|
+
let s = coerced;
|
|
595
|
+
for (const re of BUILTIN_PATTERNS) {
|
|
596
|
+
s = s.replace(re, (m) => maskToken(m));
|
|
597
|
+
}
|
|
598
|
+
for (const re of _extraPatterns) {
|
|
599
|
+
s = s.replace(re, (m) => maskToken(m));
|
|
600
|
+
}
|
|
601
|
+
{
|
|
602
|
+
s = s.replace(BEARER_PATTERN, (_, prefix) => `${prefix}***`);
|
|
603
|
+
s = s.replace(PARAM_PATTERN, (_, prefix) => `${prefix}***`);
|
|
604
|
+
}
|
|
605
|
+
return s;
|
|
606
|
+
}
|
|
607
|
+
var REDACT_ENABLED, warnedOptOut, BUILTIN_PATTERNS, BEARER_PATTERN, PARAM_PATTERN, _extraPatterns;
|
|
608
|
+
var init_redact = __esm({
|
|
609
|
+
"src/internal/security/redact.ts"() {
|
|
610
|
+
REDACT_ENABLED = readEnvOnce();
|
|
611
|
+
warnedOptOut = false;
|
|
612
|
+
if (!REDACT_ENABLED && !warnedOptOut) {
|
|
613
|
+
process.stderr.write(
|
|
614
|
+
"[theokit-sdk] Secret redaction is DISABLED via THEOKIT_REDACT_SECRETS. Credentials may leak into errors, telemetry, logs, transcripts.\n"
|
|
615
|
+
);
|
|
616
|
+
warnedOptOut = true;
|
|
617
|
+
}
|
|
618
|
+
BUILTIN_PATTERNS = [
|
|
619
|
+
/sk-ant-[A-Za-z0-9_-]{10,}/g,
|
|
620
|
+
// Anthropic
|
|
621
|
+
/sk-proj-[A-Za-z0-9_-]{10,}/g,
|
|
622
|
+
// OpenAI project key (must precede sk- generic)
|
|
623
|
+
/sk-[A-Za-z0-9_-]{10,}/g,
|
|
624
|
+
// OpenAI / OpenRouter / DeepInfra. {10,} body floor —
|
|
625
|
+
// real keys are 40+ chars; 10-char floor still skips `sk-test` (4) and
|
|
626
|
+
// `sk-test-key` (8). codeFile mode protects placeholders/examples.
|
|
627
|
+
/ghp_[A-Za-z0-9]{36}/g,
|
|
628
|
+
// GitHub PAT classic (exact length)
|
|
629
|
+
/github_pat_[A-Za-z0-9_]{82}/g,
|
|
630
|
+
// GitHub PAT fine-grained
|
|
631
|
+
/glpat-[A-Za-z0-9_-]{20}/g,
|
|
632
|
+
// GitLab PAT
|
|
633
|
+
/AKIA[A-Z0-9]{16}/g,
|
|
634
|
+
// AWS access key
|
|
635
|
+
/AIza[A-Za-z0-9_-]{35}/g,
|
|
636
|
+
// Google API key
|
|
637
|
+
/xox[bpasr]-[A-Za-z0-9-]{10,}/g,
|
|
638
|
+
//Slack tokens
|
|
639
|
+
/sntrys_[A-Za-z0-9]{40,}/g,
|
|
640
|
+
// Sentry user auth
|
|
641
|
+
/sk_live_[A-Za-z0-9]{20,}/g,
|
|
642
|
+
// Stripe secret
|
|
643
|
+
/rk_live_[A-Za-z0-9]{20,}/g
|
|
644
|
+
// Stripe restricted
|
|
645
|
+
];
|
|
646
|
+
BEARER_PATTERN = /\b(Bearer\s+)([A-Za-z0-9_\-.+/=]{8,})/g;
|
|
647
|
+
PARAM_PATTERN = /(\b(?:access_token|api_key|api-key|password|secret|x-api-key)\b["']?\s*[:=]\s*["']?)([A-Za-z0-9_\-.+/]+)/gi;
|
|
648
|
+
_extraPatterns = [];
|
|
649
|
+
}
|
|
650
|
+
});
|
|
651
|
+
|
|
652
|
+
// src/internal/workflow/step-branch.ts
|
|
653
|
+
async function runBranchStep(step, input, ctx, options, prevStepResults, dispatch) {
|
|
654
|
+
const startedAt = Date.now();
|
|
655
|
+
for (let i = 0; i < step.predicates.length; i += 1) {
|
|
656
|
+
const pair = step.predicates[i];
|
|
657
|
+
const [predicate, branch] = pair;
|
|
658
|
+
let matched = false;
|
|
659
|
+
try {
|
|
660
|
+
matched = await Promise.resolve(predicate(input));
|
|
661
|
+
} catch (err) {
|
|
662
|
+
const errText = err instanceof Error ? err.message : String(err);
|
|
663
|
+
console.warn(
|
|
664
|
+
redactSecrets(
|
|
665
|
+
`[workflow] branch "${step.id}" predicate ${i} threw, treating as no-match: ${errText}`
|
|
666
|
+
)
|
|
667
|
+
);
|
|
668
|
+
}
|
|
669
|
+
if (matched) {
|
|
670
|
+
const r = await runInnerSequence(branch, input, ctx, options, prevStepResults, dispatch);
|
|
671
|
+
return {
|
|
672
|
+
...r,
|
|
673
|
+
stepId: step.id,
|
|
674
|
+
kind: "branch",
|
|
675
|
+
durationMs: Date.now() - startedAt
|
|
676
|
+
};
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
if (step.fallback !== void 0) {
|
|
680
|
+
const r = await runInnerSequence(step.fallback, input, ctx, options, prevStepResults, dispatch);
|
|
681
|
+
return {
|
|
682
|
+
...r,
|
|
683
|
+
stepId: step.id,
|
|
684
|
+
kind: "branch",
|
|
685
|
+
durationMs: Date.now() - startedAt
|
|
686
|
+
};
|
|
687
|
+
}
|
|
688
|
+
return {
|
|
689
|
+
stepId: step.id,
|
|
690
|
+
kind: "branch",
|
|
691
|
+
status: "skipped",
|
|
692
|
+
attempts: 0,
|
|
693
|
+
durationMs: Date.now() - startedAt,
|
|
694
|
+
output: input
|
|
695
|
+
};
|
|
696
|
+
}
|
|
697
|
+
async function runInnerSequence(branch, input, ctx, options, prevStepResults, dispatch) {
|
|
698
|
+
let acc = input;
|
|
699
|
+
let lastAttempts = 1;
|
|
700
|
+
for (const inner of branch) {
|
|
701
|
+
const r = await dispatch(inner, acc, ctx, options, prevStepResults);
|
|
702
|
+
lastAttempts = r.attempts;
|
|
703
|
+
if (r.status === "failed") {
|
|
704
|
+
return {
|
|
705
|
+
stepId: inner.id,
|
|
706
|
+
kind: "branch",
|
|
707
|
+
status: "failed",
|
|
708
|
+
attempts: r.attempts,
|
|
709
|
+
durationMs: 0,
|
|
710
|
+
error: r.error ?? errToShape(new Error("branch inner step failed"))
|
|
711
|
+
};
|
|
712
|
+
}
|
|
713
|
+
acc = r.output;
|
|
714
|
+
}
|
|
715
|
+
return {
|
|
716
|
+
stepId: "__branch-completed__",
|
|
717
|
+
kind: "branch",
|
|
718
|
+
status: "completed",
|
|
719
|
+
attempts: lastAttempts,
|
|
720
|
+
durationMs: 0,
|
|
721
|
+
output: acc
|
|
722
|
+
};
|
|
723
|
+
}
|
|
724
|
+
var init_step_branch = __esm({
|
|
725
|
+
"src/internal/workflow/step-branch.ts"() {
|
|
726
|
+
init_redact();
|
|
727
|
+
init_error_shape();
|
|
728
|
+
}
|
|
729
|
+
});
|
|
730
|
+
|
|
731
|
+
// src/internal/workflow/step-dowhile.ts
|
|
732
|
+
async function runDowhileStep(step, input, ctx, options, prevStepResults, dispatch) {
|
|
733
|
+
const startedAt = Date.now();
|
|
734
|
+
const maxIter = step.maxIterations ?? 100;
|
|
735
|
+
let acc = input;
|
|
736
|
+
let i = 0;
|
|
737
|
+
while (true) {
|
|
738
|
+
if (i >= maxIter) {
|
|
739
|
+
return {
|
|
740
|
+
stepId: step.id,
|
|
741
|
+
kind: "dowhile",
|
|
742
|
+
status: "failed",
|
|
743
|
+
attempts: i,
|
|
744
|
+
durationMs: Date.now() - startedAt,
|
|
745
|
+
error: errToShape(new exports.WorkflowMaxIterationsExceededError(step.id, maxIter))
|
|
746
|
+
};
|
|
747
|
+
}
|
|
748
|
+
const r = await dispatch(step.step, acc, ctx, options, prevStepResults);
|
|
749
|
+
if (r.status === "failed") {
|
|
750
|
+
return {
|
|
751
|
+
stepId: step.id,
|
|
752
|
+
kind: "dowhile",
|
|
753
|
+
status: "failed",
|
|
754
|
+
attempts: i + 1,
|
|
755
|
+
durationMs: Date.now() - startedAt,
|
|
756
|
+
error: r.error
|
|
757
|
+
};
|
|
758
|
+
}
|
|
759
|
+
acc = r.output;
|
|
760
|
+
i += 1;
|
|
761
|
+
let shouldContinue = false;
|
|
762
|
+
try {
|
|
763
|
+
shouldContinue = await Promise.resolve(step.condFn(acc, i));
|
|
764
|
+
} catch (err) {
|
|
765
|
+
return {
|
|
766
|
+
stepId: step.id,
|
|
767
|
+
kind: "dowhile",
|
|
768
|
+
status: "failed",
|
|
769
|
+
attempts: i,
|
|
770
|
+
durationMs: Date.now() - startedAt,
|
|
771
|
+
error: errToShape(err)
|
|
772
|
+
};
|
|
773
|
+
}
|
|
774
|
+
if (!shouldContinue) break;
|
|
775
|
+
}
|
|
776
|
+
return {
|
|
777
|
+
stepId: step.id,
|
|
778
|
+
kind: "dowhile",
|
|
779
|
+
status: "completed",
|
|
780
|
+
attempts: i,
|
|
781
|
+
durationMs: Date.now() - startedAt,
|
|
782
|
+
output: acc
|
|
783
|
+
};
|
|
784
|
+
}
|
|
785
|
+
var init_step_dowhile = __esm({
|
|
786
|
+
"src/internal/workflow/step-dowhile.ts"() {
|
|
787
|
+
init_workflow();
|
|
788
|
+
init_error_shape();
|
|
789
|
+
}
|
|
790
|
+
});
|
|
791
|
+
|
|
792
|
+
// src/internal/workflow/step-fn.ts
|
|
793
|
+
function failedFnResult(stepId, attempts, startedAt, err) {
|
|
794
|
+
return {
|
|
795
|
+
stepId,
|
|
796
|
+
kind: "fn",
|
|
797
|
+
status: "failed",
|
|
798
|
+
attempts,
|
|
799
|
+
durationMs: Date.now() - startedAt,
|
|
800
|
+
error: errToShape(err)
|
|
801
|
+
};
|
|
802
|
+
}
|
|
803
|
+
function validate(schema, value) {
|
|
804
|
+
if (schema === void 0) return void 0;
|
|
805
|
+
schema.parse(value);
|
|
806
|
+
return void 0;
|
|
807
|
+
}
|
|
808
|
+
async function execWithRetry(step, input, ctx) {
|
|
809
|
+
const exec = async () => step.fn(input, ctx);
|
|
810
|
+
if (step.retry !== void 0) return withRetry(exec, step.retry, ctx.signal);
|
|
811
|
+
return { value: await exec(), attempts: 1 };
|
|
812
|
+
}
|
|
813
|
+
async function runFnStep(step, input, ctx) {
|
|
814
|
+
const startedAt = Date.now();
|
|
815
|
+
if (step.compensate !== void 0) {
|
|
816
|
+
return failedFnResult(
|
|
817
|
+
step.id,
|
|
818
|
+
0,
|
|
819
|
+
startedAt,
|
|
820
|
+
new exports.WorkflowCompensateNotImplementedError(step.id)
|
|
821
|
+
);
|
|
822
|
+
}
|
|
823
|
+
try {
|
|
824
|
+
validate(step.inputSchema, input);
|
|
825
|
+
} catch (err) {
|
|
826
|
+
return failedFnResult(step.id, 0, startedAt, err);
|
|
827
|
+
}
|
|
828
|
+
try {
|
|
829
|
+
const { value, attempts } = await execWithRetry(step, input, ctx);
|
|
830
|
+
try {
|
|
831
|
+
validate(step.outputSchema, value);
|
|
832
|
+
} catch (err) {
|
|
833
|
+
return failedFnResult(step.id, attempts, startedAt, err);
|
|
834
|
+
}
|
|
835
|
+
return {
|
|
836
|
+
stepId: step.id,
|
|
837
|
+
kind: "fn",
|
|
838
|
+
status: "completed",
|
|
839
|
+
attempts,
|
|
840
|
+
durationMs: Date.now() - startedAt,
|
|
841
|
+
output: value
|
|
842
|
+
};
|
|
843
|
+
} catch (err) {
|
|
844
|
+
if (err instanceof WorkflowSuspendedSentinel) throw err;
|
|
845
|
+
return failedFnResult(step.id, 1, startedAt, err);
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
var init_step_fn = __esm({
|
|
849
|
+
"src/internal/workflow/step-fn.ts"() {
|
|
850
|
+
init_workflow();
|
|
851
|
+
init_ctx();
|
|
852
|
+
init_error_shape();
|
|
853
|
+
init_retry_policy();
|
|
854
|
+
}
|
|
855
|
+
});
|
|
856
|
+
|
|
857
|
+
// src/internal/runtime/async-semaphore.ts
|
|
858
|
+
function createSemaphore(permits) {
|
|
859
|
+
if (!Number.isInteger(permits) || permits < 1) {
|
|
860
|
+
throw new ConfigurationError(
|
|
861
|
+
`async-semaphore: permits must be a positive integer, got ${permits}`,
|
|
862
|
+
{ code: "invalid_concurrency" }
|
|
863
|
+
);
|
|
864
|
+
}
|
|
865
|
+
let active = 0;
|
|
866
|
+
const queue = [];
|
|
867
|
+
function tryGrant() {
|
|
868
|
+
if (active < permits && queue.length > 0) {
|
|
869
|
+
const resolve2 = queue.shift();
|
|
870
|
+
if (resolve2 !== void 0) {
|
|
871
|
+
active += 1;
|
|
872
|
+
resolve2();
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
return {
|
|
877
|
+
inFlight: () => active,
|
|
878
|
+
pending: () => queue.length + active,
|
|
879
|
+
async acquire() {
|
|
880
|
+
await new Promise((resolve2) => {
|
|
881
|
+
queue.push(resolve2);
|
|
882
|
+
tryGrant();
|
|
883
|
+
});
|
|
884
|
+
let released = false;
|
|
885
|
+
return () => {
|
|
886
|
+
if (released) return;
|
|
887
|
+
released = true;
|
|
888
|
+
active -= 1;
|
|
889
|
+
tryGrant();
|
|
890
|
+
};
|
|
891
|
+
}
|
|
892
|
+
};
|
|
893
|
+
}
|
|
894
|
+
var init_async_semaphore = __esm({
|
|
895
|
+
"src/internal/runtime/async-semaphore.ts"() {
|
|
896
|
+
init_errors();
|
|
897
|
+
}
|
|
898
|
+
});
|
|
899
|
+
|
|
900
|
+
// src/internal/workflow/step-foreach.ts
|
|
901
|
+
async function runForeachStep(step, _input, ctx, options, prevStepResults, dispatch) {
|
|
902
|
+
const startedAt = Date.now();
|
|
903
|
+
const sourceResult = prevStepResults.find((r) => r.stepId === step.iterableFrom);
|
|
904
|
+
if (sourceResult === void 0) {
|
|
905
|
+
return {
|
|
906
|
+
stepId: step.id,
|
|
907
|
+
kind: "foreach",
|
|
908
|
+
status: "failed",
|
|
909
|
+
attempts: 0,
|
|
910
|
+
durationMs: Date.now() - startedAt,
|
|
911
|
+
error: errToShape(
|
|
912
|
+
new Error(
|
|
913
|
+
`foreach.iterableFrom "${step.iterableFrom}" not found in top-level steps. It must reference an earlier top-level step ID \u2014 nested step IDs inside parallel/branch/foreach blocks are not visible here.`
|
|
914
|
+
)
|
|
915
|
+
)
|
|
916
|
+
};
|
|
917
|
+
}
|
|
918
|
+
const items = sourceResult.output;
|
|
919
|
+
if (!Array.isArray(items)) {
|
|
920
|
+
return {
|
|
921
|
+
stepId: step.id,
|
|
922
|
+
kind: "foreach",
|
|
923
|
+
status: "failed",
|
|
924
|
+
attempts: 0,
|
|
925
|
+
durationMs: Date.now() - startedAt,
|
|
926
|
+
error: errToShape(
|
|
927
|
+
new Error(
|
|
928
|
+
`foreach.iterableFrom "${step.iterableFrom}" output must be Array, got ${typeof items}.`
|
|
929
|
+
)
|
|
930
|
+
)
|
|
931
|
+
};
|
|
932
|
+
}
|
|
933
|
+
if (items.length === 0) {
|
|
934
|
+
return {
|
|
935
|
+
stepId: step.id,
|
|
936
|
+
kind: "foreach",
|
|
937
|
+
status: "completed",
|
|
938
|
+
attempts: 1,
|
|
939
|
+
durationMs: Date.now() - startedAt,
|
|
940
|
+
output: []
|
|
941
|
+
};
|
|
942
|
+
}
|
|
943
|
+
const concurrency = step.concurrency ?? 4;
|
|
944
|
+
const sem = createSemaphore(Math.max(1, Math.min(concurrency, items.length)));
|
|
945
|
+
const failures = [];
|
|
946
|
+
const outputs = new Array(items.length);
|
|
947
|
+
await Promise.all(
|
|
948
|
+
items.map(async (item, idx) => {
|
|
949
|
+
const release = await sem.acquire();
|
|
950
|
+
try {
|
|
951
|
+
const r = await dispatch(step.step, item, ctx, options, prevStepResults);
|
|
952
|
+
if (r.status === "failed") {
|
|
953
|
+
failures.push(new Error(`foreach item ${idx} failed: ${r.error?.message ?? "unknown"}`));
|
|
954
|
+
} else {
|
|
955
|
+
outputs[idx] = r.output;
|
|
956
|
+
}
|
|
957
|
+
} finally {
|
|
958
|
+
release();
|
|
959
|
+
}
|
|
960
|
+
})
|
|
961
|
+
);
|
|
962
|
+
if (failures.length > 0) {
|
|
963
|
+
return {
|
|
964
|
+
stepId: step.id,
|
|
965
|
+
kind: "foreach",
|
|
966
|
+
status: "failed",
|
|
967
|
+
attempts: 1,
|
|
968
|
+
durationMs: Date.now() - startedAt,
|
|
969
|
+
error: errToShape(
|
|
970
|
+
new AggregateError(failures, `foreach "${step.id}" had ${failures.length} failure(s)`)
|
|
971
|
+
)
|
|
972
|
+
};
|
|
973
|
+
}
|
|
974
|
+
return {
|
|
975
|
+
stepId: step.id,
|
|
976
|
+
kind: "foreach",
|
|
977
|
+
status: "completed",
|
|
978
|
+
attempts: 1,
|
|
979
|
+
durationMs: Date.now() - startedAt,
|
|
980
|
+
output: outputs
|
|
981
|
+
};
|
|
982
|
+
}
|
|
983
|
+
var init_step_foreach = __esm({
|
|
984
|
+
"src/internal/workflow/step-foreach.ts"() {
|
|
985
|
+
init_async_semaphore();
|
|
986
|
+
init_error_shape();
|
|
987
|
+
}
|
|
988
|
+
});
|
|
989
|
+
|
|
990
|
+
// src/internal/workflow/step-parallel.ts
|
|
991
|
+
async function runParallelStep(step, input, ctx, options, _prevStepResults, dispatch) {
|
|
992
|
+
const startedAt = Date.now();
|
|
993
|
+
const policy = step.errorPolicy ?? "fail-fast";
|
|
994
|
+
const branchCount = step.branches.length;
|
|
995
|
+
if (branchCount === 0) {
|
|
996
|
+
return {
|
|
997
|
+
stepId: step.id,
|
|
998
|
+
kind: "parallel",
|
|
999
|
+
status: "completed",
|
|
1000
|
+
attempts: 1,
|
|
1001
|
+
durationMs: Date.now() - startedAt,
|
|
1002
|
+
output: []
|
|
1003
|
+
};
|
|
1004
|
+
}
|
|
1005
|
+
const concurrency = step.concurrency ?? branchCount;
|
|
1006
|
+
const sem = createSemaphore(Math.max(1, Math.min(concurrency, branchCount)));
|
|
1007
|
+
const failFastCtrl = policy === "fail-fast" ? new AbortController() : void 0;
|
|
1008
|
+
const branchSignal = policy === "fail-fast" ? mergeSignals(ctx.signal, failFastCtrl.signal) : ctx.signal;
|
|
1009
|
+
const semBranchPromises = step.branches.map(async (branch, branchIdx) => {
|
|
1010
|
+
const release = await sem.acquire();
|
|
1011
|
+
try {
|
|
1012
|
+
return await runBranch(
|
|
1013
|
+
branch,
|
|
1014
|
+
input,
|
|
1015
|
+
{ ...ctx, signal: branchSignal },
|
|
1016
|
+
options,
|
|
1017
|
+
dispatch,
|
|
1018
|
+
branchIdx
|
|
1019
|
+
);
|
|
1020
|
+
} finally {
|
|
1021
|
+
release();
|
|
1022
|
+
}
|
|
1023
|
+
});
|
|
1024
|
+
if (policy === "fail-fast") {
|
|
1025
|
+
try {
|
|
1026
|
+
const outputs2 = await Promise.all(semBranchPromises);
|
|
1027
|
+
return {
|
|
1028
|
+
stepId: step.id,
|
|
1029
|
+
kind: "parallel",
|
|
1030
|
+
status: "completed",
|
|
1031
|
+
attempts: 1,
|
|
1032
|
+
durationMs: Date.now() - startedAt,
|
|
1033
|
+
output: outputs2
|
|
1034
|
+
};
|
|
1035
|
+
} catch (err) {
|
|
1036
|
+
failFastCtrl?.abort(err);
|
|
1037
|
+
const settled2 = await Promise.allSettled(semBranchPromises);
|
|
1038
|
+
const errors = settled2.filter((s) => s.status === "rejected").map((s) => s.reason instanceof Error ? s.reason : new Error(String(s.reason)));
|
|
1039
|
+
return {
|
|
1040
|
+
stepId: step.id,
|
|
1041
|
+
kind: "parallel",
|
|
1042
|
+
status: "failed",
|
|
1043
|
+
attempts: 1,
|
|
1044
|
+
durationMs: Date.now() - startedAt,
|
|
1045
|
+
error: errToShape(new exports.WorkflowParallelError(errors, step.id)),
|
|
1046
|
+
output: void 0
|
|
1047
|
+
};
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
const settled = await Promise.allSettled(semBranchPromises);
|
|
1051
|
+
const outputs = settled.map(
|
|
1052
|
+
(s) => s.status === "fulfilled" ? { ok: true, value: s.value } : { ok: false, error: errToShape(s.reason) }
|
|
1053
|
+
);
|
|
1054
|
+
return {
|
|
1055
|
+
stepId: step.id,
|
|
1056
|
+
kind: "parallel",
|
|
1057
|
+
status: "completed",
|
|
1058
|
+
attempts: 1,
|
|
1059
|
+
durationMs: Date.now() - startedAt,
|
|
1060
|
+
output: outputs
|
|
1061
|
+
};
|
|
1062
|
+
}
|
|
1063
|
+
async function runBranch(branch, input, ctx, options, dispatch, branchIdx) {
|
|
1064
|
+
let acc = input;
|
|
1065
|
+
for (const inner of branch) {
|
|
1066
|
+
const r = await dispatch(inner, acc, ctx, options, []);
|
|
1067
|
+
if (r.status === "failed") {
|
|
1068
|
+
throw new Error(
|
|
1069
|
+
`parallel branch ${branchIdx} step "${inner.id}" failed: ${r.error?.message ?? "unknown"}`
|
|
1070
|
+
);
|
|
1071
|
+
}
|
|
1072
|
+
acc = r.output;
|
|
1073
|
+
}
|
|
1074
|
+
return acc;
|
|
1075
|
+
}
|
|
1076
|
+
function mergeSignals(a, b) {
|
|
1077
|
+
if (a.aborted) return a;
|
|
1078
|
+
if (b.aborted) return b;
|
|
1079
|
+
const ctrl = new AbortController();
|
|
1080
|
+
const onAbortA = () => ctrl.abort(a.reason);
|
|
1081
|
+
const onAbortB = () => ctrl.abort(b.reason);
|
|
1082
|
+
a.addEventListener("abort", onAbortA, { once: true });
|
|
1083
|
+
b.addEventListener("abort", onAbortB, { once: true });
|
|
1084
|
+
return ctrl.signal;
|
|
1085
|
+
}
|
|
1086
|
+
var init_step_parallel = __esm({
|
|
1087
|
+
"src/internal/workflow/step-parallel.ts"() {
|
|
1088
|
+
init_workflow();
|
|
1089
|
+
init_async_semaphore();
|
|
1090
|
+
init_error_shape();
|
|
1091
|
+
}
|
|
1092
|
+
});
|
|
1093
|
+
|
|
1094
|
+
// src/internal/workflow/step-sleep.ts
|
|
1095
|
+
async function runSleepStep(step, input, ctx) {
|
|
1096
|
+
const startedAt = Date.now();
|
|
1097
|
+
try {
|
|
1098
|
+
await abortableSleep(step.durationMs, ctx.signal);
|
|
1099
|
+
return {
|
|
1100
|
+
stepId: step.id,
|
|
1101
|
+
kind: "sleep",
|
|
1102
|
+
status: "completed",
|
|
1103
|
+
attempts: 1,
|
|
1104
|
+
durationMs: Date.now() - startedAt,
|
|
1105
|
+
output: input
|
|
1106
|
+
// sleep is a pass-through
|
|
1107
|
+
};
|
|
1108
|
+
} catch (err) {
|
|
1109
|
+
return {
|
|
1110
|
+
stepId: step.id,
|
|
1111
|
+
kind: "sleep",
|
|
1112
|
+
status: "failed",
|
|
1113
|
+
attempts: 1,
|
|
1114
|
+
durationMs: Date.now() - startedAt,
|
|
1115
|
+
error: errToShape(err)
|
|
1116
|
+
};
|
|
1117
|
+
}
|
|
1118
|
+
}
|
|
1119
|
+
var init_step_sleep = __esm({
|
|
1120
|
+
"src/internal/workflow/step-sleep.ts"() {
|
|
1121
|
+
init_error_shape();
|
|
1122
|
+
init_retry_policy();
|
|
1123
|
+
}
|
|
1124
|
+
});
|
|
1125
|
+
function getTracer(name, version = "1.0.0") {
|
|
1126
|
+
const cached = tracerCache.get(name);
|
|
1127
|
+
if (cached !== void 0) return cached.tracer ?? void 0;
|
|
1128
|
+
try {
|
|
1129
|
+
const r = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('workflow.cjs', document.baseURI).href)));
|
|
1130
|
+
const otel = r("@opentelemetry/api");
|
|
1131
|
+
if (otel.trace?.getTracer === void 0) {
|
|
1132
|
+
tracerCache.set(name, { tracer: null });
|
|
1133
|
+
return void 0;
|
|
1134
|
+
}
|
|
1135
|
+
const tracer = otel.trace.getTracer(name, version);
|
|
1136
|
+
tracerCache.set(name, { tracer });
|
|
1137
|
+
return tracer;
|
|
1138
|
+
} catch {
|
|
1139
|
+
tracerCache.set(name, { tracer: null });
|
|
1140
|
+
return void 0;
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1143
|
+
var noopSpan, tracerCache;
|
|
1144
|
+
var init_tracer_loader = __esm({
|
|
1145
|
+
"src/internal/observability/tracer-loader.ts"() {
|
|
1146
|
+
noopSpan = {
|
|
1147
|
+
setAttribute: () => noopSpan,
|
|
1148
|
+
end: () => void 0
|
|
1149
|
+
};
|
|
1150
|
+
tracerCache = /* @__PURE__ */ new Map();
|
|
1151
|
+
}
|
|
1152
|
+
});
|
|
1153
|
+
|
|
1154
|
+
// src/internal/workflow/telemetry.ts
|
|
1155
|
+
function startWorkflowRunSpan(info) {
|
|
1156
|
+
const tracer = getTracer(TRACER_NAME);
|
|
1157
|
+
if (tracer === void 0) return noopSpan;
|
|
1158
|
+
return tracer.startSpan("workflow.run", {
|
|
1159
|
+
attributes: {
|
|
1160
|
+
"workflow.name": info.workflowName,
|
|
1161
|
+
"workflow.run_id": info.runId
|
|
1162
|
+
}
|
|
1163
|
+
});
|
|
1164
|
+
}
|
|
1165
|
+
function startWorkflowStepSpan(info) {
|
|
1166
|
+
const tracer = getTracer(TRACER_NAME);
|
|
1167
|
+
if (tracer === void 0) return noopSpan;
|
|
1168
|
+
return tracer.startSpan(`workflow.step.${info.stepId}`, {
|
|
1169
|
+
attributes: {
|
|
1170
|
+
"step.id": info.stepId,
|
|
1171
|
+
"step.kind": info.kind,
|
|
1172
|
+
"step.attempt": info.attempt
|
|
1173
|
+
}
|
|
1174
|
+
});
|
|
1175
|
+
}
|
|
1176
|
+
var TRACER_NAME;
|
|
1177
|
+
var init_telemetry = __esm({
|
|
1178
|
+
"src/internal/workflow/telemetry.ts"() {
|
|
1179
|
+
init_tracer_loader();
|
|
1180
|
+
TRACER_NAME = "@theokit/sdk/workflow";
|
|
1181
|
+
}
|
|
1182
|
+
});
|
|
1183
|
+
|
|
1184
|
+
// src/internal/workflow/executor.ts
|
|
1185
|
+
var executor_exports = {};
|
|
1186
|
+
__export(executor_exports, {
|
|
1187
|
+
dispatchStep: () => dispatchStep,
|
|
1188
|
+
executeWorkflow: () => executeWorkflow,
|
|
1189
|
+
resumeWorkflow: () => resumeWorkflow
|
|
1190
|
+
});
|
|
1191
|
+
async function handleSuspend(err, ctx) {
|
|
1192
|
+
try {
|
|
1193
|
+
await saveSnapshot({
|
|
1194
|
+
runId: ctx.runId,
|
|
1195
|
+
workflowName: ctx.options.name,
|
|
1196
|
+
currentStepId: ctx.step.id,
|
|
1197
|
+
suspendedPayload: err.payload,
|
|
1198
|
+
stepResults: ctx.stepResults,
|
|
1199
|
+
accumulatedInput: ctx.acc,
|
|
1200
|
+
options: ctx.options
|
|
1201
|
+
});
|
|
1202
|
+
} catch (snapErr) {
|
|
1203
|
+
ctx.stepSpan.setAttribute("step.status", "failed");
|
|
1204
|
+
ctx.stepSpan.end();
|
|
1205
|
+
return {
|
|
1206
|
+
kind: "failed",
|
|
1207
|
+
run: assembleRun({
|
|
1208
|
+
runId: ctx.runId,
|
|
1209
|
+
name: ctx.name,
|
|
1210
|
+
status: "failed",
|
|
1211
|
+
stepResults: ctx.stepResults,
|
|
1212
|
+
startedAt: ctx.startedAt,
|
|
1213
|
+
error: errToShape(snapErr)
|
|
1214
|
+
})
|
|
1215
|
+
};
|
|
1216
|
+
}
|
|
1217
|
+
ctx.stepSpan.setAttribute("step.status", "suspended");
|
|
1218
|
+
ctx.stepSpan.end();
|
|
1219
|
+
return {
|
|
1220
|
+
kind: "suspended",
|
|
1221
|
+
run: assembleRun({
|
|
1222
|
+
runId: ctx.runId,
|
|
1223
|
+
name: ctx.name,
|
|
1224
|
+
status: "suspended",
|
|
1225
|
+
stepResults: [
|
|
1226
|
+
...ctx.stepResults,
|
|
1227
|
+
{
|
|
1228
|
+
stepId: ctx.step.id,
|
|
1229
|
+
kind: ctx.step.kind,
|
|
1230
|
+
status: "suspended",
|
|
1231
|
+
attempts: 1,
|
|
1232
|
+
durationMs: 0,
|
|
1233
|
+
output: void 0
|
|
1234
|
+
}
|
|
1235
|
+
],
|
|
1236
|
+
startedAt: ctx.startedAt
|
|
1237
|
+
})
|
|
1238
|
+
};
|
|
1239
|
+
}
|
|
1240
|
+
async function runOneStep(args) {
|
|
1241
|
+
const stepSpan = startWorkflowStepSpan({
|
|
1242
|
+
stepId: args.step.id,
|
|
1243
|
+
kind: args.step.kind,
|
|
1244
|
+
attempt: 1
|
|
1245
|
+
});
|
|
1246
|
+
let result;
|
|
1247
|
+
try {
|
|
1248
|
+
result = await dispatchStep(args.step, args.acc, args.ctx, args.options, args.stepResults);
|
|
1249
|
+
} catch (err) {
|
|
1250
|
+
if (err instanceof WorkflowSuspendedSentinel) {
|
|
1251
|
+
const outcome = await handleSuspend(err, { ...args, stepSpan });
|
|
1252
|
+
return { kind: "terminal", run: outcome.run };
|
|
1253
|
+
}
|
|
1254
|
+
result = {
|
|
1255
|
+
stepId: args.step.id,
|
|
1256
|
+
kind: args.step.kind,
|
|
1257
|
+
status: "failed",
|
|
1258
|
+
attempts: 1,
|
|
1259
|
+
durationMs: 0,
|
|
1260
|
+
error: errToShape(err)
|
|
1261
|
+
};
|
|
1262
|
+
}
|
|
1263
|
+
stepSpan.setAttribute("step.status", result.status);
|
|
1264
|
+
stepSpan.setAttribute("step.attempts", result.attempts);
|
|
1265
|
+
stepSpan.end();
|
|
1266
|
+
return { kind: "ok", result };
|
|
1267
|
+
}
|
|
1268
|
+
function abortRun(name, runId, startedAt, stepResults, signal) {
|
|
1269
|
+
return assembleRun({
|
|
1270
|
+
runId,
|
|
1271
|
+
name,
|
|
1272
|
+
status: "cancelled",
|
|
1273
|
+
stepResults,
|
|
1274
|
+
startedAt,
|
|
1275
|
+
error: { name: "AbortError", message: String(signal.reason ?? "Aborted") }
|
|
1276
|
+
});
|
|
1277
|
+
}
|
|
1278
|
+
async function runStepsLoop(params) {
|
|
1279
|
+
const { options, steps, ctx, runId, startedAt, signal } = params;
|
|
1280
|
+
const stepResults = [];
|
|
1281
|
+
let acc = params.input;
|
|
1282
|
+
for (const step of steps) {
|
|
1283
|
+
if (signal.aborted) return abortRun(options.name, runId, startedAt, stepResults, signal);
|
|
1284
|
+
const outcome = await runOneStep({
|
|
1285
|
+
step,
|
|
1286
|
+
acc,
|
|
1287
|
+
ctx,
|
|
1288
|
+
options,
|
|
1289
|
+
stepResults,
|
|
1290
|
+
runId,
|
|
1291
|
+
name: options.name,
|
|
1292
|
+
startedAt
|
|
1293
|
+
});
|
|
1294
|
+
if (outcome.kind === "terminal") return outcome.run;
|
|
1295
|
+
stepResults.push(outcome.result);
|
|
1296
|
+
if (outcome.result.status === "failed") {
|
|
1297
|
+
return assembleRun({
|
|
1298
|
+
runId,
|
|
1299
|
+
name: options.name,
|
|
1300
|
+
status: "failed",
|
|
1301
|
+
stepResults,
|
|
1302
|
+
startedAt,
|
|
1303
|
+
error: outcome.result.error
|
|
1304
|
+
});
|
|
1305
|
+
}
|
|
1306
|
+
acc = outcome.result.output;
|
|
1307
|
+
}
|
|
1308
|
+
return assembleRun({
|
|
1309
|
+
runId,
|
|
1310
|
+
name: options.name,
|
|
1311
|
+
status: "completed",
|
|
1312
|
+
output: acc,
|
|
1313
|
+
stepResults,
|
|
1314
|
+
startedAt
|
|
1315
|
+
});
|
|
1316
|
+
}
|
|
1317
|
+
async function executeWorkflow(options, steps, input, runOpts) {
|
|
1318
|
+
const runId = runOpts?.runId ?? mintRunId();
|
|
1319
|
+
const workflowId = options.workflowId ?? `wf-anon`;
|
|
1320
|
+
const flight = acquireSingleFlight(workflowId, runId, options.name);
|
|
1321
|
+
const startedAt = Date.now();
|
|
1322
|
+
const signal = combineSignals(runOpts?.signal, flight.signal);
|
|
1323
|
+
const runSpan = startWorkflowRunSpan({ workflowName: options.name, runId });
|
|
1324
|
+
if (signal.aborted) {
|
|
1325
|
+
flight.release();
|
|
1326
|
+
runSpan.setAttribute("workflow.status", "cancelled");
|
|
1327
|
+
runSpan.end();
|
|
1328
|
+
return abortRun(options.name, runId, startedAt, [], signal);
|
|
1329
|
+
}
|
|
1330
|
+
const ctx = makeStepContext(runId, signal);
|
|
1331
|
+
try {
|
|
1332
|
+
return await runStepsLoop({
|
|
1333
|
+
options,
|
|
1334
|
+
steps,
|
|
1335
|
+
input,
|
|
1336
|
+
ctx,
|
|
1337
|
+
runId,
|
|
1338
|
+
startedAt,
|
|
1339
|
+
signal
|
|
1340
|
+
});
|
|
1341
|
+
} finally {
|
|
1342
|
+
runSpan.end();
|
|
1343
|
+
flight.release();
|
|
1344
|
+
}
|
|
1345
|
+
}
|
|
1346
|
+
async function dispatchStep(step, input, ctx, options, prevStepResults) {
|
|
1347
|
+
switch (step.kind) {
|
|
1348
|
+
case "fn":
|
|
1349
|
+
return runFnStep(step, input, ctx);
|
|
1350
|
+
case "agent":
|
|
1351
|
+
return runAgentStep(step, input, ctx);
|
|
1352
|
+
case "parallel":
|
|
1353
|
+
return runParallelStep(step, input, ctx, options, prevStepResults, dispatchStep);
|
|
1354
|
+
case "branch":
|
|
1355
|
+
return runBranchStep(step, input, ctx, options, prevStepResults, dispatchStep);
|
|
1356
|
+
case "foreach":
|
|
1357
|
+
return runForeachStep(step, input, ctx, options, prevStepResults, dispatchStep);
|
|
1358
|
+
case "dowhile":
|
|
1359
|
+
return runDowhileStep(step, input, ctx, options, prevStepResults, dispatchStep);
|
|
1360
|
+
case "sleep":
|
|
1361
|
+
return runSleepStep(step, input, ctx);
|
|
1362
|
+
case "suspend":
|
|
1363
|
+
throw new WorkflowSuspendedSentinel(void 0);
|
|
1364
|
+
default: {
|
|
1365
|
+
const _exhaustive = step;
|
|
1366
|
+
throw new Error(`Unknown step kind: ${_exhaustive.kind}`);
|
|
1367
|
+
}
|
|
1368
|
+
}
|
|
1369
|
+
}
|
|
1370
|
+
function assembleRun(params) {
|
|
1371
|
+
const endedAt = Date.now();
|
|
1372
|
+
return {
|
|
1373
|
+
id: params.runId,
|
|
1374
|
+
name: params.name,
|
|
1375
|
+
status: params.status,
|
|
1376
|
+
startedAt: params.startedAt,
|
|
1377
|
+
endedAt,
|
|
1378
|
+
stepResults: params.stepResults,
|
|
1379
|
+
...params.output !== void 0 ? { output: params.output } : {},
|
|
1380
|
+
...params.error !== void 0 ? { error: params.error } : {}
|
|
1381
|
+
};
|
|
1382
|
+
}
|
|
1383
|
+
async function saveSnapshot(p) {
|
|
1384
|
+
const snapshot = {
|
|
1385
|
+
_schemaVersion: 1,
|
|
1386
|
+
runId: p.runId,
|
|
1387
|
+
workflowName: p.workflowName,
|
|
1388
|
+
currentStepId: p.currentStepId,
|
|
1389
|
+
suspendedPayload: p.suspendedPayload,
|
|
1390
|
+
stepResults: p.stepResults,
|
|
1391
|
+
accumulatedInput: p.accumulatedInput,
|
|
1392
|
+
suspendedAt: Date.now()
|
|
1393
|
+
};
|
|
1394
|
+
const store = getSnapshotStoreFor(p.options);
|
|
1395
|
+
await store.save(snapshot);
|
|
1396
|
+
}
|
|
1397
|
+
async function resumeWorkflow(opts) {
|
|
1398
|
+
const wfInternal = opts.workflow;
|
|
1399
|
+
const options = wfInternal.__options;
|
|
1400
|
+
const steps = wfInternal.__steps;
|
|
1401
|
+
if (options === void 0 || steps === void 0) {
|
|
1402
|
+
throw new Error("Workflow.resume requires an instance from Workflow.create().commit()");
|
|
1403
|
+
}
|
|
1404
|
+
const store = getSnapshotStoreFor(options);
|
|
1405
|
+
const snapshot = await store.load(opts.runId);
|
|
1406
|
+
if (snapshot === void 0) {
|
|
1407
|
+
throw new exports.WorkflowSnapshotNotFoundError(opts.runId);
|
|
1408
|
+
}
|
|
1409
|
+
const stepIdx = steps.findIndex((s) => s.id === snapshot.currentStepId);
|
|
1410
|
+
if (stepIdx < 0) {
|
|
1411
|
+
throw new exports.WorkflowResumeStepNotFoundError(snapshot.currentStepId, snapshot.workflowName);
|
|
1412
|
+
}
|
|
1413
|
+
const suspendStep = steps[stepIdx];
|
|
1414
|
+
if (suspendStep !== void 0 && suspendStep.kind === "suspend" && suspendStep.payloadSchema !== void 0) {
|
|
1415
|
+
suspendStep.payloadSchema.parse(opts.payload);
|
|
1416
|
+
}
|
|
1417
|
+
const resumeInput = opts.payload !== void 0 ? opts.payload : snapshot.accumulatedInput;
|
|
1418
|
+
const remainingSteps = steps.slice(stepIdx + 1);
|
|
1419
|
+
await store.delete(opts.runId);
|
|
1420
|
+
return executeWorkflow(options, remainingSteps, resumeInput, {
|
|
1421
|
+
signal: opts.signal,
|
|
1422
|
+
runId: opts.runId
|
|
1423
|
+
});
|
|
1424
|
+
}
|
|
1425
|
+
var init_executor = __esm({
|
|
1426
|
+
"src/internal/workflow/executor.ts"() {
|
|
1427
|
+
init_workflow();
|
|
1428
|
+
init_ctx();
|
|
1429
|
+
init_error_shape();
|
|
1430
|
+
init_run_id();
|
|
1431
|
+
init_single_flight();
|
|
1432
|
+
init_snapshot_store();
|
|
1433
|
+
init_step_agent();
|
|
1434
|
+
init_step_branch();
|
|
1435
|
+
init_step_dowhile();
|
|
1436
|
+
init_step_fn();
|
|
1437
|
+
init_step_foreach();
|
|
1438
|
+
init_step_parallel();
|
|
1439
|
+
init_step_sleep();
|
|
1440
|
+
init_telemetry();
|
|
1441
|
+
}
|
|
1442
|
+
});
|
|
1443
|
+
|
|
1444
|
+
// src/types/task.ts
|
|
1445
|
+
function isValidTaskId(id, allowReserved) {
|
|
1446
|
+
if (!TASK_ID_GRAMMAR.test(id)) return false;
|
|
1447
|
+
if (allowReserved) return true;
|
|
1448
|
+
for (const prefix of RESERVED_PREFIXES) {
|
|
1449
|
+
if (id.startsWith(prefix)) return false;
|
|
1450
|
+
}
|
|
1451
|
+
return true;
|
|
1452
|
+
}
|
|
1453
|
+
var TASK_ID_GRAMMAR, RESERVED_PREFIXES;
|
|
1454
|
+
var init_task = __esm({
|
|
1455
|
+
"src/types/task.ts"() {
|
|
1456
|
+
TASK_ID_GRAMMAR = /^[a-z0-9][a-z0-9_-]*$/;
|
|
1457
|
+
RESERVED_PREFIXES = ["wf-", "b-", "cron-"];
|
|
1458
|
+
}
|
|
1459
|
+
});
|
|
1460
|
+
|
|
1461
|
+
// src/internal/task/ring-buffer.ts
|
|
1462
|
+
var RingBuffer;
|
|
1463
|
+
var init_ring_buffer = __esm({
|
|
1464
|
+
"src/internal/task/ring-buffer.ts"() {
|
|
1465
|
+
RingBuffer = class {
|
|
1466
|
+
constructor(cap) {
|
|
1467
|
+
this.cap = cap;
|
|
1468
|
+
if (!Number.isInteger(cap) || cap < 1) {
|
|
1469
|
+
throw new Error(`RingBuffer capacity must be a positive integer, got ${cap}`);
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
cap;
|
|
1473
|
+
buf = [];
|
|
1474
|
+
truncated = false;
|
|
1475
|
+
push(item) {
|
|
1476
|
+
if (this.buf.length >= this.cap) {
|
|
1477
|
+
this.buf.shift();
|
|
1478
|
+
this.truncated = true;
|
|
1479
|
+
}
|
|
1480
|
+
this.buf.push(item);
|
|
1481
|
+
}
|
|
1482
|
+
drain() {
|
|
1483
|
+
return { items: this.buf.slice(), truncated: this.truncated };
|
|
1484
|
+
}
|
|
1485
|
+
size() {
|
|
1486
|
+
return this.buf.length;
|
|
1487
|
+
}
|
|
1488
|
+
wasTruncated() {
|
|
1489
|
+
return this.truncated;
|
|
1490
|
+
}
|
|
1491
|
+
};
|
|
1492
|
+
}
|
|
1493
|
+
});
|
|
1494
|
+
function assertValidIdForStore(id) {
|
|
1495
|
+
if (!isValidTaskId(
|
|
1496
|
+
id,
|
|
1497
|
+
/* allowReserved */
|
|
1498
|
+
true
|
|
1499
|
+
)) {
|
|
1500
|
+
throw new InvalidTaskIdError(`store rejects invalid task id: ${id}`, id);
|
|
1501
|
+
}
|
|
1502
|
+
}
|
|
1503
|
+
function terminalTimestamp(h) {
|
|
1504
|
+
if (h.state === "finished") return h.finishedAt;
|
|
1505
|
+
if (h.state === "error") return h.erroredAt;
|
|
1506
|
+
if (h.state === "cancelled") return h.cancelledAt;
|
|
1507
|
+
return void 0;
|
|
1508
|
+
}
|
|
1509
|
+
function isTerminal(state2) {
|
|
1510
|
+
return state2 === "finished" || state2 === "error" || state2 === "cancelled";
|
|
1511
|
+
}
|
|
1512
|
+
function matchesState(h, filter) {
|
|
1513
|
+
if (filter.state === void 0) return true;
|
|
1514
|
+
const states = Array.isArray(filter.state) ? filter.state : [filter.state];
|
|
1515
|
+
return states.includes(h.state);
|
|
1516
|
+
}
|
|
1517
|
+
function matchesKind(h, filter) {
|
|
1518
|
+
if (filter.kind === void 0) return true;
|
|
1519
|
+
const kinds = Array.isArray(filter.kind) ? filter.kind : [filter.kind];
|
|
1520
|
+
return kinds.includes(h.kind);
|
|
1521
|
+
}
|
|
1522
|
+
function matchesTime(h, filter) {
|
|
1523
|
+
if (filter.submittedAfter !== void 0 && h.submittedAt <= filter.submittedAfter) return false;
|
|
1524
|
+
if (filter.submittedBefore !== void 0 && h.submittedAt >= filter.submittedBefore) return false;
|
|
1525
|
+
return true;
|
|
1526
|
+
}
|
|
1527
|
+
function matchesFilter(h, filter) {
|
|
1528
|
+
return matchesState(h, filter) && matchesKind(h, filter) && matchesTime(h, filter);
|
|
1529
|
+
}
|
|
1530
|
+
function applyFilter(values, filter) {
|
|
1531
|
+
const limit = filter.limit ?? DEFAULT_LIST_LIMIT;
|
|
1532
|
+
const out = [];
|
|
1533
|
+
for (const h of values) {
|
|
1534
|
+
if (matchesFilter(h, filter)) {
|
|
1535
|
+
out.push(h);
|
|
1536
|
+
if (out.length >= limit) break;
|
|
1537
|
+
}
|
|
1538
|
+
}
|
|
1539
|
+
return out;
|
|
1540
|
+
}
|
|
1541
|
+
function getTaskStoreFor(options) {
|
|
1542
|
+
if (options.backend === "memory") return new InMemoryTaskStore();
|
|
1543
|
+
return new JsonFileTaskStore(options.dir);
|
|
1544
|
+
}
|
|
1545
|
+
var JSON_LOAD_CAP, DEFAULT_LIST_LIMIT, InMemoryTaskStore, JsonFileTaskStore;
|
|
1546
|
+
var init_store = __esm({
|
|
1547
|
+
"src/internal/task/store.ts"() {
|
|
1548
|
+
init_errors();
|
|
1549
|
+
init_task();
|
|
1550
|
+
init_atomic_write();
|
|
1551
|
+
JSON_LOAD_CAP = 256;
|
|
1552
|
+
DEFAULT_LIST_LIMIT = 100;
|
|
1553
|
+
InMemoryTaskStore = class {
|
|
1554
|
+
map = /* @__PURE__ */ new Map();
|
|
1555
|
+
async insert(handle) {
|
|
1556
|
+
assertValidIdForStore(handle.id);
|
|
1557
|
+
this.map.set(handle.id, handle);
|
|
1558
|
+
}
|
|
1559
|
+
async update(id, mutate) {
|
|
1560
|
+
assertValidIdForStore(id);
|
|
1561
|
+
const existing = this.map.get(id);
|
|
1562
|
+
if (existing === void 0) return void 0;
|
|
1563
|
+
const next = mutate(existing);
|
|
1564
|
+
this.map.set(id, next);
|
|
1565
|
+
return next;
|
|
1566
|
+
}
|
|
1567
|
+
async get(id) {
|
|
1568
|
+
assertValidIdForStore(id);
|
|
1569
|
+
return this.map.get(id);
|
|
1570
|
+
}
|
|
1571
|
+
async list(filter) {
|
|
1572
|
+
return applyFilter(this.map.values(), filter);
|
|
1573
|
+
}
|
|
1574
|
+
async delete(id) {
|
|
1575
|
+
assertValidIdForStore(id);
|
|
1576
|
+
return this.map.delete(id);
|
|
1577
|
+
}
|
|
1578
|
+
async evictTerminalOlderThan(epochMs) {
|
|
1579
|
+
let count = 0;
|
|
1580
|
+
for (const [id, h] of this.map.entries()) {
|
|
1581
|
+
if (!isTerminal(h.state)) continue;
|
|
1582
|
+
const ts = terminalTimestamp(h);
|
|
1583
|
+
if (ts !== void 0 && ts < epochMs) {
|
|
1584
|
+
this.map.delete(id);
|
|
1585
|
+
count++;
|
|
1586
|
+
}
|
|
1587
|
+
}
|
|
1588
|
+
return count;
|
|
1589
|
+
}
|
|
1590
|
+
};
|
|
1591
|
+
JsonFileTaskStore = class {
|
|
1592
|
+
constructor(dir) {
|
|
1593
|
+
this.dir = dir;
|
|
1594
|
+
try {
|
|
1595
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
1596
|
+
} catch (err) {
|
|
1597
|
+
if (err.code !== "EEXIST") throw err;
|
|
1598
|
+
}
|
|
1599
|
+
}
|
|
1600
|
+
dir;
|
|
1601
|
+
filePath(id) {
|
|
1602
|
+
return path.join(this.dir, `${id}.json`);
|
|
1603
|
+
}
|
|
1604
|
+
async insert(handle) {
|
|
1605
|
+
assertValidIdForStore(handle.id);
|
|
1606
|
+
await atomicWriteText(this.filePath(handle.id), JSON.stringify(handle));
|
|
1607
|
+
}
|
|
1608
|
+
async update(id, mutate) {
|
|
1609
|
+
assertValidIdForStore(id);
|
|
1610
|
+
const existing = await this.get(id);
|
|
1611
|
+
if (existing === void 0) return void 0;
|
|
1612
|
+
const next = mutate(existing);
|
|
1613
|
+
await atomicWriteText(this.filePath(id), JSON.stringify(next));
|
|
1614
|
+
return next;
|
|
1615
|
+
}
|
|
1616
|
+
async get(id) {
|
|
1617
|
+
assertValidIdForStore(id);
|
|
1618
|
+
try {
|
|
1619
|
+
const raw = await promises.readFile(this.filePath(id), "utf8");
|
|
1620
|
+
return JSON.parse(raw);
|
|
1621
|
+
} catch (err) {
|
|
1622
|
+
const code = err.code;
|
|
1623
|
+
if (code === "ENOENT") return void 0;
|
|
1624
|
+
process.stderr.write(`[task-store] failed to read ${id}: ${err.message}
|
|
1625
|
+
`);
|
|
1626
|
+
return void 0;
|
|
1627
|
+
}
|
|
1628
|
+
}
|
|
1629
|
+
async list(filter) {
|
|
1630
|
+
let entries;
|
|
1631
|
+
try {
|
|
1632
|
+
entries = fs.readdirSync(this.dir);
|
|
1633
|
+
} catch (err) {
|
|
1634
|
+
if (err.code === "ENOENT") return [];
|
|
1635
|
+
throw err;
|
|
1636
|
+
}
|
|
1637
|
+
const candidates = entries.filter((name) => name.endsWith(".json") && !name.includes(".tmp")).slice(0, JSON_LOAD_CAP);
|
|
1638
|
+
const loaded = await Promise.all(
|
|
1639
|
+
candidates.map(async (name) => {
|
|
1640
|
+
const id = name.slice(0, -".json".length);
|
|
1641
|
+
if (!isValidTaskId(id, true)) return void 0;
|
|
1642
|
+
return this.get(id);
|
|
1643
|
+
})
|
|
1644
|
+
);
|
|
1645
|
+
const handles = loaded.filter((h) => h !== void 0);
|
|
1646
|
+
return applyFilter(handles, filter);
|
|
1647
|
+
}
|
|
1648
|
+
async delete(id) {
|
|
1649
|
+
assertValidIdForStore(id);
|
|
1650
|
+
try {
|
|
1651
|
+
await promises.unlink(this.filePath(id));
|
|
1652
|
+
return true;
|
|
1653
|
+
} catch (err) {
|
|
1654
|
+
if (err.code === "ENOENT") return false;
|
|
1655
|
+
throw err;
|
|
1656
|
+
}
|
|
1657
|
+
}
|
|
1658
|
+
async evictTerminalOlderThan(epochMs) {
|
|
1659
|
+
const handles = await this.list({ state: ["finished", "error", "cancelled"], limit: 256 });
|
|
1660
|
+
let count = 0;
|
|
1661
|
+
for (const h of handles) {
|
|
1662
|
+
const ts = terminalTimestamp(h);
|
|
1663
|
+
if (ts !== void 0 && ts < epochMs) {
|
|
1664
|
+
if (await this.delete(h.id)) count++;
|
|
1665
|
+
}
|
|
1666
|
+
}
|
|
1667
|
+
return count;
|
|
1668
|
+
}
|
|
1669
|
+
};
|
|
1670
|
+
}
|
|
1671
|
+
});
|
|
1672
|
+
|
|
1673
|
+
// src/internal/task/subscribe.ts
|
|
1674
|
+
function isTerminalEvent(event) {
|
|
1675
|
+
return event.type === "finished" || event.type === "errored" || event.type === "cancelled";
|
|
1676
|
+
}
|
|
1677
|
+
function drainBuffered(buffer) {
|
|
1678
|
+
const { items, truncated } = buffer.drain();
|
|
1679
|
+
const queue = items.slice();
|
|
1680
|
+
if (truncated && queue.length > 0) {
|
|
1681
|
+
const first = queue[0];
|
|
1682
|
+
if (first !== void 0 && first.type === "submitted") {
|
|
1683
|
+
queue[0] = { ...first, truncated: true };
|
|
1684
|
+
}
|
|
1685
|
+
}
|
|
1686
|
+
return queue;
|
|
1687
|
+
}
|
|
1688
|
+
function buildSubscribe(deps) {
|
|
1689
|
+
return function subscribe2(id) {
|
|
1690
|
+
if (!isValidTaskId(id, true)) throw new TaskNotFoundError(id);
|
|
1691
|
+
const buffer = deps.getBuffer(id);
|
|
1692
|
+
if (buffer === void 0) throw new TaskNotFoundError(id);
|
|
1693
|
+
return {
|
|
1694
|
+
[Symbol.asyncIterator]() {
|
|
1695
|
+
return new TaskIterator(buffer, id, deps);
|
|
1696
|
+
}
|
|
1697
|
+
};
|
|
1698
|
+
};
|
|
1699
|
+
}
|
|
1700
|
+
var TaskIterator;
|
|
1701
|
+
var init_subscribe = __esm({
|
|
1702
|
+
"src/internal/task/subscribe.ts"() {
|
|
1703
|
+
init_errors();
|
|
1704
|
+
init_task();
|
|
1705
|
+
TaskIterator = class {
|
|
1706
|
+
constructor(buffer, id, deps) {
|
|
1707
|
+
this.id = id;
|
|
1708
|
+
this.deps = deps;
|
|
1709
|
+
this.queue = drainBuffered(buffer);
|
|
1710
|
+
this.callback = (e) => this.deliver(e);
|
|
1711
|
+
deps.getOrCreateSubscriberSet(id).add(this.callback);
|
|
1712
|
+
}
|
|
1713
|
+
id;
|
|
1714
|
+
deps;
|
|
1715
|
+
queue;
|
|
1716
|
+
pendingResolve;
|
|
1717
|
+
done = false;
|
|
1718
|
+
callback;
|
|
1719
|
+
deliver(e) {
|
|
1720
|
+
if (this.done) return;
|
|
1721
|
+
if (this.pendingResolve !== void 0) {
|
|
1722
|
+
const r = this.pendingResolve;
|
|
1723
|
+
this.pendingResolve = void 0;
|
|
1724
|
+
r({ value: e, done: false });
|
|
1725
|
+
} else {
|
|
1726
|
+
this.queue.push(e);
|
|
1727
|
+
}
|
|
1728
|
+
}
|
|
1729
|
+
cleanup() {
|
|
1730
|
+
if (this.done) return;
|
|
1731
|
+
this.done = true;
|
|
1732
|
+
this.deps.removeSubscriber(this.id, this.callback);
|
|
1733
|
+
if (this.pendingResolve !== void 0) {
|
|
1734
|
+
const r = this.pendingResolve;
|
|
1735
|
+
this.pendingResolve = void 0;
|
|
1736
|
+
r({ value: void 0, done: true });
|
|
1737
|
+
}
|
|
1738
|
+
}
|
|
1739
|
+
dequeue() {
|
|
1740
|
+
const event = this.queue.shift();
|
|
1741
|
+
if (event === void 0) return void 0;
|
|
1742
|
+
if (isTerminalEvent(event)) queueMicrotask(() => this.cleanup());
|
|
1743
|
+
return { value: event, done: false };
|
|
1744
|
+
}
|
|
1745
|
+
next() {
|
|
1746
|
+
if (this.done) return Promise.resolve({ value: void 0, done: true });
|
|
1747
|
+
const queued = this.dequeue();
|
|
1748
|
+
if (queued !== void 0) return Promise.resolve(queued);
|
|
1749
|
+
return new Promise((resolve2) => {
|
|
1750
|
+
this.pendingResolve = resolve2;
|
|
1751
|
+
});
|
|
1752
|
+
}
|
|
1753
|
+
return() {
|
|
1754
|
+
this.cleanup();
|
|
1755
|
+
return Promise.resolve({ value: void 0, done: true });
|
|
1756
|
+
}
|
|
1757
|
+
};
|
|
1758
|
+
}
|
|
1759
|
+
});
|
|
1760
|
+
|
|
1761
|
+
// src/internal/task/telemetry.ts
|
|
1762
|
+
function startTaskSubmitSpan(info) {
|
|
1763
|
+
const tracer = getTracer(TRACER_NAME2);
|
|
1764
|
+
if (tracer === void 0) return noopSpan;
|
|
1765
|
+
return tracer.startSpan("task.submit", {
|
|
1766
|
+
attributes: {
|
|
1767
|
+
"task.id": info.taskId,
|
|
1768
|
+
"task.kind": info.kind
|
|
1769
|
+
}
|
|
1770
|
+
});
|
|
1771
|
+
}
|
|
1772
|
+
function startTaskTransitionSpan(info) {
|
|
1773
|
+
const tracer = getTracer(TRACER_NAME2);
|
|
1774
|
+
if (tracer === void 0) return noopSpan;
|
|
1775
|
+
return tracer.startSpan("task.transition", {
|
|
1776
|
+
attributes: {
|
|
1777
|
+
"task.id": info.taskId,
|
|
1778
|
+
"task.state.from": info.from,
|
|
1779
|
+
"task.state.to": info.to
|
|
1780
|
+
}
|
|
1781
|
+
});
|
|
1782
|
+
}
|
|
1783
|
+
function startTaskCancelSpan(info) {
|
|
1784
|
+
const tracer = getTracer(TRACER_NAME2);
|
|
1785
|
+
if (tracer === void 0) return noopSpan;
|
|
1786
|
+
return tracer.startSpan("task.cancel", {
|
|
1787
|
+
attributes: {
|
|
1788
|
+
"task.id": info.taskId,
|
|
1789
|
+
"task.cancel.via": info.via,
|
|
1790
|
+
...info.reason !== void 0 ? { "task.cancel.reason": info.reason } : {}
|
|
1791
|
+
}
|
|
1792
|
+
});
|
|
1793
|
+
}
|
|
1794
|
+
var TRACER_NAME2;
|
|
1795
|
+
var init_telemetry2 = __esm({
|
|
1796
|
+
"src/internal/task/telemetry.ts"() {
|
|
1797
|
+
init_tracer_loader();
|
|
1798
|
+
TRACER_NAME2 = "@theokit/sdk/task";
|
|
1799
|
+
}
|
|
1800
|
+
});
|
|
1801
|
+
|
|
1802
|
+
// src/internal/task/registry.ts
|
|
1803
|
+
var registry_exports = {};
|
|
1804
|
+
__export(registry_exports, {
|
|
1805
|
+
__getCancelRequestedForTests: () => __getCancelRequestedForTests,
|
|
1806
|
+
__getSubscribersCountForTests: () => __getSubscribersCountForTests,
|
|
1807
|
+
__resetTaskRegistryForTests: () => __resetTaskRegistryForTests,
|
|
1808
|
+
cancel: () => cancel,
|
|
1809
|
+
configure: () => configure,
|
|
1810
|
+
evictNow: () => evictNow,
|
|
1811
|
+
get: () => get,
|
|
1812
|
+
list: () => list,
|
|
1813
|
+
submit: () => submit,
|
|
1814
|
+
subscribe: () => subscribe
|
|
1815
|
+
});
|
|
1816
|
+
function buildState(opts) {
|
|
1817
|
+
const store = opts.store === void 0 ? new InMemoryTaskStore() : getTaskStoreFor(opts.store);
|
|
1818
|
+
return {
|
|
1819
|
+
store,
|
|
1820
|
+
semaphore: createSemaphore(opts.maxConcurrent ?? DEFAULT_CONCURRENCY),
|
|
1821
|
+
aborters: /* @__PURE__ */ new Map(),
|
|
1822
|
+
buffers: /* @__PURE__ */ new Map(),
|
|
1823
|
+
subscribers: /* @__PURE__ */ new Map(),
|
|
1824
|
+
retentionMs: opts.retentionMs ?? DEFAULT_RETENTION_MS,
|
|
1825
|
+
firstSubmitSeen: false
|
|
1826
|
+
};
|
|
1827
|
+
}
|
|
1828
|
+
function __resetTaskRegistryForTests() {
|
|
1829
|
+
if (state.evictTimer !== void 0) clearInterval(state.evictTimer);
|
|
1830
|
+
state = buildState({});
|
|
1831
|
+
}
|
|
1832
|
+
function __getSubscribersCountForTests(taskId) {
|
|
1833
|
+
return state.subscribers.get(taskId)?.size ?? 0;
|
|
1834
|
+
}
|
|
1835
|
+
function __getCancelRequestedForTests(_taskId) {
|
|
1836
|
+
return void 0;
|
|
1837
|
+
}
|
|
1838
|
+
function configure(opts) {
|
|
1839
|
+
if (state.firstSubmitSeen) {
|
|
1840
|
+
process.stderr.write(
|
|
1841
|
+
"[task] configure() ignored \u2014 registry already in use; reset via __resetTaskRegistryForTests()\n"
|
|
1842
|
+
);
|
|
1843
|
+
return;
|
|
1844
|
+
}
|
|
1845
|
+
if (state.evictTimer !== void 0) clearInterval(state.evictTimer);
|
|
1846
|
+
state = buildState(opts);
|
|
1847
|
+
}
|
|
1848
|
+
function emitToSubscribers(taskId, event) {
|
|
1849
|
+
const buffer = state.buffers.get(taskId);
|
|
1850
|
+
if (buffer !== void 0) buffer.push(event);
|
|
1851
|
+
const subs = state.subscribers.get(taskId);
|
|
1852
|
+
if (subs === void 0) return;
|
|
1853
|
+
for (const cb of subs) {
|
|
1854
|
+
try {
|
|
1855
|
+
cb(event);
|
|
1856
|
+
} catch (err) {
|
|
1857
|
+
process.stderr.write(`[task] subscriber threw: ${err.message}
|
|
1858
|
+
`);
|
|
1859
|
+
}
|
|
1860
|
+
}
|
|
1861
|
+
}
|
|
1862
|
+
async function safeUpdate(taskId, mutate) {
|
|
1863
|
+
try {
|
|
1864
|
+
return await state.store.update(taskId, mutate);
|
|
1865
|
+
} catch (err) {
|
|
1866
|
+
process.stderr.write(`[task] store.update failed for ${taskId}: ${err.message}
|
|
1867
|
+
`);
|
|
1868
|
+
return void 0;
|
|
1869
|
+
}
|
|
1870
|
+
}
|
|
1871
|
+
function startEvictTimerIfNeeded() {
|
|
1872
|
+
if (state.evictTimer !== void 0) return;
|
|
1873
|
+
state.evictTimer = setInterval(() => {
|
|
1874
|
+
const cutoff = Date.now() - state.retentionMs;
|
|
1875
|
+
void state.store.evictTerminalOlderThan(cutoff).then((count) => {
|
|
1876
|
+
if (count === 0) return;
|
|
1877
|
+
for (const id of state.buffers.keys()) {
|
|
1878
|
+
void state.store.get(id).then((h) => {
|
|
1879
|
+
if (h === void 0) {
|
|
1880
|
+
state.buffers.delete(id);
|
|
1881
|
+
state.subscribers.delete(id);
|
|
1882
|
+
state.aborters.delete(id);
|
|
1883
|
+
}
|
|
1884
|
+
});
|
|
1885
|
+
}
|
|
1886
|
+
}).catch(() => {
|
|
1887
|
+
});
|
|
1888
|
+
}, EVICTION_INTERVAL_MS).unref();
|
|
1889
|
+
}
|
|
1890
|
+
function buildSubmittedEvent(handle) {
|
|
1891
|
+
return {
|
|
1892
|
+
type: "submitted",
|
|
1893
|
+
taskId: handle.id,
|
|
1894
|
+
kind: handle.kind,
|
|
1895
|
+
submittedAt: handle.submittedAt,
|
|
1896
|
+
...handle.meta !== void 0 ? { meta: handle.meta } : {}
|
|
1897
|
+
};
|
|
1898
|
+
}
|
|
1899
|
+
async function shortCircuitAborted(handle, signal) {
|
|
1900
|
+
const cancelled = {
|
|
1901
|
+
...handle,
|
|
1902
|
+
state: "cancelled",
|
|
1903
|
+
cancelledAt: Date.now()
|
|
1904
|
+
};
|
|
1905
|
+
await state.store.insert(cancelled);
|
|
1906
|
+
state.buffers.set(handle.id, new RingBuffer(RING_CAP));
|
|
1907
|
+
emitToSubscribers(handle.id, buildSubmittedEvent(cancelled));
|
|
1908
|
+
emitToSubscribers(handle.id, {
|
|
1909
|
+
type: "cancelled",
|
|
1910
|
+
taskId: handle.id,
|
|
1911
|
+
cancelledAt: cancelled.cancelledAt ?? Date.now(),
|
|
1912
|
+
reason: signal.reason instanceof Error ? signal.reason.message : "pre-aborted"
|
|
1913
|
+
});
|
|
1914
|
+
return cancelled;
|
|
1915
|
+
}
|
|
1916
|
+
async function transition(taskId, next, patch) {
|
|
1917
|
+
const before = await state.store.get(taskId);
|
|
1918
|
+
const span = startTaskTransitionSpan({
|
|
1919
|
+
taskId,
|
|
1920
|
+
from: before?.state ?? "unknown",
|
|
1921
|
+
to: next
|
|
1922
|
+
});
|
|
1923
|
+
try {
|
|
1924
|
+
await safeUpdate(taskId, (h) => ({ ...h, state: next, ...patch }));
|
|
1925
|
+
} finally {
|
|
1926
|
+
span.end();
|
|
1927
|
+
}
|
|
1928
|
+
}
|
|
1929
|
+
async function buildAndInsertQueued(internal, resolvedId) {
|
|
1930
|
+
const submittedAt = Date.now();
|
|
1931
|
+
const handle = {
|
|
1932
|
+
id: resolvedId,
|
|
1933
|
+
kind: internal.kind,
|
|
1934
|
+
state: "queued",
|
|
1935
|
+
submittedAt,
|
|
1936
|
+
...internal.meta !== void 0 ? { meta: internal.meta } : {}
|
|
1937
|
+
};
|
|
1938
|
+
await state.store.insert(handle);
|
|
1939
|
+
state.buffers.set(resolvedId, new RingBuffer(RING_CAP));
|
|
1940
|
+
emitToSubscribers(resolvedId, buildSubmittedEvent(handle));
|
|
1941
|
+
return handle;
|
|
1942
|
+
}
|
|
1943
|
+
function resolveIdInternal(internal) {
|
|
1944
|
+
if (internal.id === void 0) return crypto.randomUUID();
|
|
1945
|
+
if (!isValidTaskId(internal.id, internal.allowReservedPrefix ?? false)) {
|
|
1946
|
+
throw new InvalidTaskIdError(`invalid task id: ${internal.id}`, internal.id);
|
|
1947
|
+
}
|
|
1948
|
+
return internal.id;
|
|
1949
|
+
}
|
|
1950
|
+
async function runWorkAndFinalize(taskId, aborter, work) {
|
|
1951
|
+
const ctx = {
|
|
1952
|
+
signal: aborter.signal,
|
|
1953
|
+
emit(payload) {
|
|
1954
|
+
void checkCancelRequestedAt(taskId, aborter);
|
|
1955
|
+
emitToSubscribers(taskId, {
|
|
1956
|
+
type: "progress",
|
|
1957
|
+
taskId,
|
|
1958
|
+
at: Date.now(),
|
|
1959
|
+
payload
|
|
1960
|
+
});
|
|
1961
|
+
}
|
|
1962
|
+
};
|
|
1963
|
+
try {
|
|
1964
|
+
const result = await reentryAls.run(true, () => Promise.resolve().then(() => work(ctx)));
|
|
1965
|
+
if (aborter.signal.aborted) {
|
|
1966
|
+
const cancelledAt = Date.now();
|
|
1967
|
+
await transition(taskId, "cancelled", { cancelledAt });
|
|
1968
|
+
emitToSubscribers(taskId, { type: "cancelled", taskId, cancelledAt });
|
|
1969
|
+
return;
|
|
1970
|
+
}
|
|
1971
|
+
const finishedAt = Date.now();
|
|
1972
|
+
await transition(taskId, "finished", { finishedAt, result });
|
|
1973
|
+
emitToSubscribers(taskId, { type: "finished", taskId, finishedAt, result });
|
|
1974
|
+
} catch (err) {
|
|
1975
|
+
if (aborter.signal.aborted) {
|
|
1976
|
+
const cancelledAt = Date.now();
|
|
1977
|
+
await transition(taskId, "cancelled", { cancelledAt });
|
|
1978
|
+
emitToSubscribers(taskId, { type: "cancelled", taskId, cancelledAt });
|
|
1979
|
+
return;
|
|
1980
|
+
}
|
|
1981
|
+
const erroredAt = Date.now();
|
|
1982
|
+
const error = err instanceof Error ? { code: err.code ?? "work_threw", message: err.message } : { code: "work_threw", message: String(err) };
|
|
1983
|
+
await transition(taskId, "error", { erroredAt, error });
|
|
1984
|
+
emitToSubscribers(taskId, { type: "errored", taskId, erroredAt, error });
|
|
1985
|
+
}
|
|
1986
|
+
}
|
|
1987
|
+
async function checkCancelRequestedAt(taskId, aborter) {
|
|
1988
|
+
if (aborter.signal.aborted) return;
|
|
1989
|
+
try {
|
|
1990
|
+
const handle = await state.store.get(taskId);
|
|
1991
|
+
if (handle?.cancelRequested === true) {
|
|
1992
|
+
aborter.abort("cancelRequested");
|
|
1993
|
+
}
|
|
1994
|
+
} catch {
|
|
1995
|
+
}
|
|
1996
|
+
}
|
|
1997
|
+
async function acquireSlot() {
|
|
1998
|
+
if (reentryAls.getStore() === true) {
|
|
1999
|
+
return () => {
|
|
2000
|
+
};
|
|
2001
|
+
}
|
|
2002
|
+
return state.semaphore.acquire();
|
|
2003
|
+
}
|
|
2004
|
+
async function submit(internal) {
|
|
2005
|
+
state.firstSubmitSeen = true;
|
|
2006
|
+
startEvictTimerIfNeeded();
|
|
2007
|
+
const resolvedId = resolveIdInternal(internal);
|
|
2008
|
+
const submitSpan = startTaskSubmitSpan({ taskId: resolvedId, kind: internal.kind });
|
|
2009
|
+
const existing = await state.store.get(resolvedId);
|
|
2010
|
+
if (existing !== void 0) {
|
|
2011
|
+
submitSpan.end();
|
|
2012
|
+
return existing;
|
|
2013
|
+
}
|
|
2014
|
+
const queuedHandle = await buildAndInsertQueued(internal, resolvedId);
|
|
2015
|
+
submitSpan.end();
|
|
2016
|
+
if (internal.signal?.aborted === true) {
|
|
2017
|
+
return shortCircuitAborted(queuedHandle, internal.signal);
|
|
2018
|
+
}
|
|
2019
|
+
const aborter = new AbortController();
|
|
2020
|
+
state.aborters.set(resolvedId, aborter);
|
|
2021
|
+
if (internal.signal !== void 0) {
|
|
2022
|
+
internal.signal.addEventListener("abort", () => aborter.abort(internal.signal?.reason), {
|
|
2023
|
+
once: true
|
|
2024
|
+
});
|
|
2025
|
+
}
|
|
2026
|
+
const release = await acquireSlot();
|
|
2027
|
+
void (async () => {
|
|
2028
|
+
try {
|
|
2029
|
+
await checkCancelRequestedAt(resolvedId, aborter);
|
|
2030
|
+
if (aborter.signal.aborted) {
|
|
2031
|
+
const cancelledAt = Date.now();
|
|
2032
|
+
await transition(resolvedId, "cancelled", { cancelledAt });
|
|
2033
|
+
emitToSubscribers(resolvedId, { type: "cancelled", taskId: resolvedId, cancelledAt });
|
|
2034
|
+
return;
|
|
2035
|
+
}
|
|
2036
|
+
const startedAt = Date.now();
|
|
2037
|
+
await transition(resolvedId, "running", { startedAt });
|
|
2038
|
+
emitToSubscribers(resolvedId, { type: "started", taskId: resolvedId, startedAt });
|
|
2039
|
+
await runWorkAndFinalize(resolvedId, aborter, internal.work);
|
|
2040
|
+
} finally {
|
|
2041
|
+
release();
|
|
2042
|
+
state.aborters.delete(resolvedId);
|
|
2043
|
+
}
|
|
2044
|
+
})();
|
|
2045
|
+
return queuedHandle;
|
|
2046
|
+
}
|
|
2047
|
+
async function list(filter = {}) {
|
|
2048
|
+
return state.store.list(filter);
|
|
2049
|
+
}
|
|
2050
|
+
async function get(id) {
|
|
2051
|
+
if (!isValidTaskId(id, true)) return void 0;
|
|
2052
|
+
return state.store.get(id);
|
|
2053
|
+
}
|
|
2054
|
+
async function cancel(id, reason) {
|
|
2055
|
+
if (!isValidTaskId(id, true)) return { cancelled: false, alreadyTerminal: false };
|
|
2056
|
+
const handle = await state.store.get(id);
|
|
2057
|
+
if (handle === void 0) return { cancelled: false, alreadyTerminal: false };
|
|
2058
|
+
if (handle.state === "finished" || handle.state === "error" || handle.state === "cancelled") {
|
|
2059
|
+
return { cancelled: false, alreadyTerminal: true };
|
|
2060
|
+
}
|
|
2061
|
+
const span = startTaskCancelSpan({
|
|
2062
|
+
taskId: id,
|
|
2063
|
+
...reason !== void 0 ? { reason } : {},
|
|
2064
|
+
via: "api"
|
|
2065
|
+
});
|
|
2066
|
+
try {
|
|
2067
|
+
return await cancelInternal(id, handle.state, reason);
|
|
2068
|
+
} finally {
|
|
2069
|
+
span.end();
|
|
2070
|
+
}
|
|
2071
|
+
}
|
|
2072
|
+
async function cancelInternal(id, currentState, reason) {
|
|
2073
|
+
if (currentState === "queued") {
|
|
2074
|
+
const cancelledAt = Date.now();
|
|
2075
|
+
await transition(id, "cancelled", { cancelledAt });
|
|
2076
|
+
emitToSubscribers(id, {
|
|
2077
|
+
type: "cancelled",
|
|
2078
|
+
taskId: id,
|
|
2079
|
+
cancelledAt,
|
|
2080
|
+
...reason !== void 0 ? { reason } : {}
|
|
2081
|
+
});
|
|
2082
|
+
state.aborters.delete(id);
|
|
2083
|
+
return { cancelled: true, alreadyTerminal: false };
|
|
2084
|
+
}
|
|
2085
|
+
const aborter = state.aborters.get(id);
|
|
2086
|
+
if (aborter !== void 0) aborter.abort(reason ?? "cancelled");
|
|
2087
|
+
return { cancelled: true, alreadyTerminal: false };
|
|
2088
|
+
}
|
|
2089
|
+
async function evictNow(now = Date.now()) {
|
|
2090
|
+
return state.store.evictTerminalOlderThan(now - state.retentionMs);
|
|
2091
|
+
}
|
|
2092
|
+
var DEFAULT_CONCURRENCY, DEFAULT_RETENTION_MS, EVICTION_INTERVAL_MS, RING_CAP, reentryAls, state, subscribe;
|
|
2093
|
+
var init_registry = __esm({
|
|
2094
|
+
"src/internal/task/registry.ts"() {
|
|
2095
|
+
init_errors();
|
|
2096
|
+
init_task();
|
|
2097
|
+
init_async_semaphore();
|
|
2098
|
+
init_ring_buffer();
|
|
2099
|
+
init_store();
|
|
2100
|
+
init_subscribe();
|
|
2101
|
+
init_telemetry2();
|
|
2102
|
+
DEFAULT_CONCURRENCY = 8;
|
|
2103
|
+
DEFAULT_RETENTION_MS = 60 * 60 * 1e3;
|
|
2104
|
+
EVICTION_INTERVAL_MS = 5 * 60 * 1e3;
|
|
2105
|
+
RING_CAP = 64;
|
|
2106
|
+
reentryAls = new async_hooks.AsyncLocalStorage();
|
|
2107
|
+
state = buildState({});
|
|
2108
|
+
subscribe = buildSubscribe({
|
|
2109
|
+
getBuffer: (id) => state.buffers.get(id),
|
|
2110
|
+
getOrCreateSubscriberSet: (id) => {
|
|
2111
|
+
let subs = state.subscribers.get(id);
|
|
2112
|
+
if (subs === void 0) {
|
|
2113
|
+
subs = /* @__PURE__ */ new Set();
|
|
2114
|
+
state.subscribers.set(id, subs);
|
|
2115
|
+
}
|
|
2116
|
+
return subs;
|
|
2117
|
+
},
|
|
2118
|
+
removeSubscriber: (id, cb) => {
|
|
2119
|
+
const set = state.subscribers.get(id);
|
|
2120
|
+
set?.delete(cb);
|
|
2121
|
+
if (set !== void 0 && set.size === 0) state.subscribers.delete(id);
|
|
2122
|
+
}
|
|
2123
|
+
});
|
|
2124
|
+
}
|
|
2125
|
+
});
|
|
2126
|
+
var PersistenceSchema = zod.z.object({
|
|
2127
|
+
backend: zod.z.enum(["memory", "json"]),
|
|
2128
|
+
dir: zod.z.string().optional()
|
|
2129
|
+
}).refine((p) => p.backend !== "json" || typeof p.dir === "string" && p.dir.length > 0, {
|
|
2130
|
+
message: 'persistence.dir is required when backend = "json"'
|
|
2131
|
+
}).optional();
|
|
2132
|
+
|
|
2133
|
+
// src/internal/security/path-guard.ts
|
|
2134
|
+
init_errors();
|
|
2135
|
+
var IDENTIFIER_PATTERN = /^[a-z0-9][a-z0-9\-_]*$/i;
|
|
2136
|
+
function sanitizeIdentifier(input, options) {
|
|
2137
|
+
const maxLen = options?.maxLen;
|
|
2138
|
+
if (input.length === 0 || input.length > maxLen) {
|
|
2139
|
+
throw new ConfigurationError(`Identifier length out of range (1-${maxLen}): "${input}"`, {
|
|
2140
|
+
code: "invalid_identifier"
|
|
2141
|
+
});
|
|
2142
|
+
}
|
|
2143
|
+
if (!IDENTIFIER_PATTERN.test(input)) {
|
|
2144
|
+
throw new ConfigurationError(`Identifier contains invalid characters: "${input}"`, {
|
|
2145
|
+
code: "invalid_identifier"
|
|
2146
|
+
});
|
|
2147
|
+
}
|
|
2148
|
+
return input.toLowerCase();
|
|
2149
|
+
}
|
|
2150
|
+
|
|
2151
|
+
// src/workflow.ts
|
|
2152
|
+
init_workflow();
|
|
2153
|
+
init_snapshot_store();
|
|
2154
|
+
init_workflow();
|
|
2155
|
+
var RetryPolicySchema = zod.z.object({
|
|
2156
|
+
// EC-3 absorbed: maxAttempts MUST be a finite int in [1, 20].
|
|
2157
|
+
maxAttempts: zod.z.number().int("retry.maxAttempts must be integer").min(1, "retry.maxAttempts must be >= 1").max(20, "retry.maxAttempts must be <= 20"),
|
|
2158
|
+
initialBackoffMs: zod.z.number().int().min(0).optional(),
|
|
2159
|
+
backoffCoefficient: zod.z.number().min(1).optional(),
|
|
2160
|
+
maximumBackoffMs: zod.z.number().int().min(0).optional(),
|
|
2161
|
+
nonRetryableErrors: zod.z.array(zod.z.string()).optional()
|
|
2162
|
+
});
|
|
2163
|
+
var WorkflowOptionsSchema = zod.z.object({
|
|
2164
|
+
name: zod.z.string().min(1).max(128),
|
|
2165
|
+
persistence: PersistenceSchema
|
|
2166
|
+
});
|
|
2167
|
+
var WorkflowBuilder = class {
|
|
2168
|
+
/** @internal */
|
|
2169
|
+
constructor(options) {
|
|
2170
|
+
this.options = options;
|
|
2171
|
+
}
|
|
2172
|
+
options;
|
|
2173
|
+
_steps = [];
|
|
2174
|
+
_committed = false;
|
|
2175
|
+
/** @internal — only the executor reads this. */
|
|
2176
|
+
get __steps() {
|
|
2177
|
+
return this._steps;
|
|
2178
|
+
}
|
|
2179
|
+
// biome-ignore lint/suspicious/noThenProperty: D233 locks the Mastra-style `.then(step)` builder DSL. The method is fluent, never awaited.
|
|
2180
|
+
then(step) {
|
|
2181
|
+
this.assertNotCommitted();
|
|
2182
|
+
validateStepId(step.id);
|
|
2183
|
+
this._steps.push(step);
|
|
2184
|
+
return this;
|
|
2185
|
+
}
|
|
2186
|
+
parallel(branches, opts) {
|
|
2187
|
+
this.assertNotCommitted();
|
|
2188
|
+
const id = opts?.id ?? `parallel_${this._steps.length}`;
|
|
2189
|
+
validateStepId(id);
|
|
2190
|
+
for (const branch of branches) {
|
|
2191
|
+
for (const inner of branch) validateStepId(inner.id);
|
|
2192
|
+
}
|
|
2193
|
+
const step = {
|
|
2194
|
+
kind: "parallel",
|
|
2195
|
+
id,
|
|
2196
|
+
branches,
|
|
2197
|
+
...opts?.concurrency !== void 0 ? { concurrency: opts.concurrency } : {},
|
|
2198
|
+
...opts?.errorPolicy !== void 0 ? { errorPolicy: opts.errorPolicy } : {}
|
|
2199
|
+
};
|
|
2200
|
+
this._steps.push(step);
|
|
2201
|
+
return this;
|
|
2202
|
+
}
|
|
2203
|
+
branch(predicates, opts) {
|
|
2204
|
+
this.assertNotCommitted();
|
|
2205
|
+
const id = opts?.id ?? `branch_${this._steps.length}`;
|
|
2206
|
+
validateStepId(id);
|
|
2207
|
+
const step = {
|
|
2208
|
+
kind: "branch",
|
|
2209
|
+
id,
|
|
2210
|
+
predicates,
|
|
2211
|
+
...opts?.fallback !== void 0 ? { fallback: opts.fallback } : {}
|
|
2212
|
+
};
|
|
2213
|
+
this._steps.push(step);
|
|
2214
|
+
return this;
|
|
2215
|
+
}
|
|
2216
|
+
foreach(iterableFrom, step, opts) {
|
|
2217
|
+
this.assertNotCommitted();
|
|
2218
|
+
const id = opts?.id ?? `foreach_${this._steps.length}`;
|
|
2219
|
+
validateStepId(id);
|
|
2220
|
+
validateStepId(iterableFrom);
|
|
2221
|
+
validateStepId(step.id);
|
|
2222
|
+
const node = {
|
|
2223
|
+
kind: "foreach",
|
|
2224
|
+
id,
|
|
2225
|
+
iterableFrom,
|
|
2226
|
+
step,
|
|
2227
|
+
...opts?.concurrency !== void 0 ? { concurrency: opts.concurrency } : {}
|
|
2228
|
+
};
|
|
2229
|
+
this._steps.push(node);
|
|
2230
|
+
return this;
|
|
2231
|
+
}
|
|
2232
|
+
dowhile(step, condFn, opts) {
|
|
2233
|
+
this.assertNotCommitted();
|
|
2234
|
+
const id = opts?.id ?? `dowhile_${this._steps.length}`;
|
|
2235
|
+
validateStepId(id);
|
|
2236
|
+
validateStepId(step.id);
|
|
2237
|
+
const node = {
|
|
2238
|
+
kind: "dowhile",
|
|
2239
|
+
id,
|
|
2240
|
+
step,
|
|
2241
|
+
condFn,
|
|
2242
|
+
...opts?.maxIterations !== void 0 ? { maxIterations: opts.maxIterations } : {}
|
|
2243
|
+
};
|
|
2244
|
+
this._steps.push(node);
|
|
2245
|
+
return this;
|
|
2246
|
+
}
|
|
2247
|
+
sleep(durationMs, id) {
|
|
2248
|
+
this.assertNotCommitted();
|
|
2249
|
+
const stepId = id ?? `sleep_${this._steps.length}`;
|
|
2250
|
+
validateStepId(stepId);
|
|
2251
|
+
if (!Number.isFinite(durationMs) || durationMs < 0) {
|
|
2252
|
+
throw new Error(`sleep durationMs must be finite non-negative: ${durationMs}`);
|
|
2253
|
+
}
|
|
2254
|
+
const step = { kind: "sleep", id: stepId, durationMs };
|
|
2255
|
+
this._steps.push(step);
|
|
2256
|
+
return this;
|
|
2257
|
+
}
|
|
2258
|
+
suspend(opts) {
|
|
2259
|
+
this.assertNotCommitted();
|
|
2260
|
+
const id = opts?.id ?? `suspend_${this._steps.length}`;
|
|
2261
|
+
validateStepId(id);
|
|
2262
|
+
const step = {
|
|
2263
|
+
kind: "suspend",
|
|
2264
|
+
id,
|
|
2265
|
+
...opts?.payloadSchema !== void 0 ? { payloadSchema: opts.payloadSchema } : {}
|
|
2266
|
+
};
|
|
2267
|
+
this._steps.push(step);
|
|
2268
|
+
return this;
|
|
2269
|
+
}
|
|
2270
|
+
commit() {
|
|
2271
|
+
this.assertNotCommitted();
|
|
2272
|
+
this.validateUniqueIds();
|
|
2273
|
+
this._committed = true;
|
|
2274
|
+
const workflowId = `wf-${mintShortId()}`;
|
|
2275
|
+
return new Workflow({ ...this.options, workflowId }, [...this._steps]);
|
|
2276
|
+
}
|
|
2277
|
+
validateUniqueIds() {
|
|
2278
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2279
|
+
walkStepsValidating(this._steps, seen);
|
|
2280
|
+
}
|
|
2281
|
+
assertNotCommitted() {
|
|
2282
|
+
if (this._committed) {
|
|
2283
|
+
throw new Error("Workflow already committed; create a fresh Workflow.create(...) call.");
|
|
2284
|
+
}
|
|
2285
|
+
}
|
|
2286
|
+
};
|
|
2287
|
+
var Workflow = class {
|
|
2288
|
+
/** @internal */
|
|
2289
|
+
constructor(_options, _steps) {
|
|
2290
|
+
this._options = _options;
|
|
2291
|
+
this._steps = _steps;
|
|
2292
|
+
}
|
|
2293
|
+
_options;
|
|
2294
|
+
_steps;
|
|
2295
|
+
/** @internal — only the executor reads these. */
|
|
2296
|
+
get __options() {
|
|
2297
|
+
return this._options;
|
|
2298
|
+
}
|
|
2299
|
+
/** @internal */
|
|
2300
|
+
get __steps() {
|
|
2301
|
+
return this._steps;
|
|
2302
|
+
}
|
|
2303
|
+
/**
|
|
2304
|
+
* Construct a workflow builder. Validate options via Zod and return a
|
|
2305
|
+
* `WorkflowBuilder` for fluent chaining. Call `.commit()` to obtain the
|
|
2306
|
+
* immutable `Workflow`.
|
|
2307
|
+
*/
|
|
2308
|
+
static create(options) {
|
|
2309
|
+
WorkflowOptionsSchema.parse(options);
|
|
2310
|
+
return new WorkflowBuilder(options);
|
|
2311
|
+
}
|
|
2312
|
+
/**
|
|
2313
|
+
* Run this workflow with the given input. Returns a populated
|
|
2314
|
+
* `WorkflowRun`. Errors inside a step DO NOT throw — they propagate via
|
|
2315
|
+
* `run.status === "failed"`.
|
|
2316
|
+
*/
|
|
2317
|
+
async run(input, opts) {
|
|
2318
|
+
const { executeWorkflow: executeWorkflow2 } = await Promise.resolve().then(() => (init_executor(), executor_exports));
|
|
2319
|
+
const result = await executeWorkflow2(this._options, this._steps, input, opts);
|
|
2320
|
+
if (opts?.task !== void 0) {
|
|
2321
|
+
const { submit: taskSubmit } = await Promise.resolve().then(() => (init_registry(), registry_exports));
|
|
2322
|
+
const taskOpts = opts.task === true ? {} : opts.task;
|
|
2323
|
+
const id = taskOpts.id ?? `wf-${result.id}`;
|
|
2324
|
+
await taskSubmit({
|
|
2325
|
+
kind: "workflow",
|
|
2326
|
+
work: async (ctx) => {
|
|
2327
|
+
ctx.emit({ status: result.status, runId: result.id });
|
|
2328
|
+
return { status: result.status, runId: result.id, output: result.output };
|
|
2329
|
+
},
|
|
2330
|
+
id,
|
|
2331
|
+
meta: {
|
|
2332
|
+
workflowName: this._options.name,
|
|
2333
|
+
runId: result.id,
|
|
2334
|
+
status: result.status,
|
|
2335
|
+
...taskOpts.meta ?? {}
|
|
2336
|
+
},
|
|
2337
|
+
allowReservedPrefix: true
|
|
2338
|
+
});
|
|
2339
|
+
}
|
|
2340
|
+
return result;
|
|
2341
|
+
}
|
|
2342
|
+
/**
|
|
2343
|
+
* Resume a suspended workflow from its snapshot. Throws
|
|
2344
|
+
* `WorkflowSnapshotNotFoundError` if `runId` is unknown.
|
|
2345
|
+
*/
|
|
2346
|
+
static async resume(opts) {
|
|
2347
|
+
const { resumeWorkflow: resumeWorkflow2 } = await Promise.resolve().then(() => (init_executor(), executor_exports));
|
|
2348
|
+
return resumeWorkflow2(opts);
|
|
2349
|
+
}
|
|
2350
|
+
};
|
|
2351
|
+
function fn(id, step, opts) {
|
|
2352
|
+
validateStepId(id);
|
|
2353
|
+
if (opts?.retry !== void 0) RetryPolicySchema.parse(opts.retry);
|
|
2354
|
+
return {
|
|
2355
|
+
kind: "fn",
|
|
2356
|
+
id,
|
|
2357
|
+
fn: step,
|
|
2358
|
+
...opts?.inputSchema !== void 0 ? { inputSchema: opts.inputSchema } : {},
|
|
2359
|
+
...opts?.outputSchema !== void 0 ? { outputSchema: opts.outputSchema } : {},
|
|
2360
|
+
...opts?.retry !== void 0 ? { retry: opts.retry } : {}
|
|
2361
|
+
};
|
|
2362
|
+
}
|
|
2363
|
+
function agentStep(id, agent, promptTemplate, opts) {
|
|
2364
|
+
validateStepId(id);
|
|
2365
|
+
if (opts?.retry !== void 0) RetryPolicySchema.parse(opts.retry);
|
|
2366
|
+
return {
|
|
2367
|
+
kind: "agent",
|
|
2368
|
+
id,
|
|
2369
|
+
agent,
|
|
2370
|
+
promptTemplate,
|
|
2371
|
+
...opts?.retry !== void 0 ? { retry: opts.retry } : {}
|
|
2372
|
+
};
|
|
2373
|
+
}
|
|
2374
|
+
function validateStepId(id) {
|
|
2375
|
+
sanitizeIdentifier(id, { maxLen: 64 });
|
|
2376
|
+
}
|
|
2377
|
+
function mintShortId() {
|
|
2378
|
+
return globalThis.crypto.randomUUID().replace(/-/g, "").slice(0, 8);
|
|
2379
|
+
}
|
|
2380
|
+
function nestedStepsOf(s) {
|
|
2381
|
+
if (s.kind === "parallel") return s.branches;
|
|
2382
|
+
if (s.kind === "branch") {
|
|
2383
|
+
const groups = s.predicates.map(([, branch]) => branch);
|
|
2384
|
+
return s.fallback !== void 0 ? [...groups, s.fallback] : groups;
|
|
2385
|
+
}
|
|
2386
|
+
if (s.kind === "foreach" || s.kind === "dowhile") return [[s.step]];
|
|
2387
|
+
return [];
|
|
2388
|
+
}
|
|
2389
|
+
function walkStepsValidating(steps, seen) {
|
|
2390
|
+
for (const s of steps) {
|
|
2391
|
+
if (seen.has(s.id)) throw new exports.WorkflowDuplicateStepIdError(s.id);
|
|
2392
|
+
seen.add(s.id);
|
|
2393
|
+
for (const nested of nestedStepsOf(s)) {
|
|
2394
|
+
walkStepsValidating(nested, seen);
|
|
2395
|
+
}
|
|
2396
|
+
}
|
|
2397
|
+
}
|
|
2398
|
+
|
|
2399
|
+
exports.Workflow = Workflow;
|
|
2400
|
+
exports.WorkflowBuilder = WorkflowBuilder;
|
|
2401
|
+
exports.__resetSnapshotStoresForTests = __resetSnapshotStoresForTests;
|
|
2402
|
+
exports.agentStep = agentStep;
|
|
2403
|
+
exports.fn = fn;
|
|
2404
|
+
//# sourceMappingURL=workflow.cjs.map
|
|
2405
|
+
//# sourceMappingURL=workflow.cjs.map
|