@pikku/core 0.12.84 → 0.12.86
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 +424 -0
- package/dist/bootstrap-compat/root.d.ts +20 -0
- package/dist/classification/column-form.d.ts +32 -0
- package/dist/classification/column-form.js +42 -0
- package/dist/classification/data-classification.d.ts +64 -0
- package/dist/classification/index.d.ts +13 -0
- package/dist/classification/index.js +2 -0
- package/dist/classification/secret-value.d.ts +56 -0
- package/dist/classification/secret-value.js +46 -0
- package/dist/crypto-utils.d.ts +1 -1
- package/dist/ecosystem/agent-scorer.d.ts +1 -1
- package/dist/ecosystem/agent.d.ts +4 -1
- package/dist/ecosystem/channel/local.d.ts +2 -0
- package/dist/ecosystem/channel/local.js +2 -0
- package/dist/ecosystem/channel/serverless.d.ts +9 -0
- package/dist/ecosystem/channel/serverless.js +1 -0
- package/dist/ecosystem/channel.d.ts +3 -0
- package/dist/ecosystem/channel.js +1 -0
- package/dist/ecosystem/cli.d.ts +1 -1
- package/dist/ecosystem/cli.js +1 -1
- package/dist/ecosystem/credential.d.ts +1 -0
- package/dist/ecosystem/crypto-utils.d.ts +8 -0
- package/dist/ecosystem/crypto-utils.js +1 -0
- package/dist/ecosystem/dev.d.ts +1 -0
- package/dist/ecosystem/dev.js +1 -0
- package/{src/ecosystem/testing.ts → dist/ecosystem/errors.d.ts} +3 -3
- package/dist/ecosystem/errors.js +2 -0
- package/dist/ecosystem/function.d.ts +1 -1
- package/dist/ecosystem/function.js +1 -1
- package/dist/ecosystem/http.d.ts +3 -1
- package/dist/ecosystem/http.js +3 -1
- package/dist/ecosystem/mcp.d.ts +1 -1
- package/dist/ecosystem/mcp.js +1 -1
- package/dist/ecosystem/middleware.d.ts +2 -1
- package/dist/ecosystem/middleware.js +2 -1
- package/dist/ecosystem/persona.d.ts +4 -2
- package/dist/ecosystem/persona.js +2 -1
- package/dist/ecosystem/queue.d.ts +4 -2
- package/dist/ecosystem/queue.js +3 -1
- package/dist/ecosystem/role.d.ts +1 -0
- package/dist/ecosystem/rpc.d.ts +2 -0
- package/dist/ecosystem/rpc.js +1 -0
- package/dist/ecosystem/scenario.d.ts +8 -2
- package/dist/ecosystem/scenario.js +5 -1
- package/dist/ecosystem/scheduler.d.ts +2 -1
- package/dist/ecosystem/scheduler.js +2 -1
- package/dist/ecosystem/schema.d.ts +2 -1
- package/dist/ecosystem/schema.js +1 -1
- package/dist/ecosystem/scope.d.ts +2 -0
- package/dist/ecosystem/scope.js +1 -0
- package/dist/ecosystem/secret.d.ts +2 -0
- package/dist/ecosystem/secret.js +1 -0
- package/dist/ecosystem/services/local-content.d.ts +2 -1
- package/dist/ecosystem/services/local-content.js +1 -1
- package/dist/ecosystem/services/local-meta.d.ts +1 -0
- package/dist/ecosystem/services/local-meta.js +1 -0
- package/dist/ecosystem/services.d.ts +11 -3
- package/dist/ecosystem/services.js +7 -1
- package/dist/ecosystem/trigger.d.ts +1 -0
- package/dist/ecosystem/trigger.js +1 -1
- package/dist/ecosystem/types.d.ts +6 -3
- package/dist/ecosystem/types.js +3 -2
- package/dist/ecosystem/variable.d.ts +1 -0
- package/dist/ecosystem/virtual-user.d.ts +3 -0
- package/dist/ecosystem/virtual-user.js +3 -0
- package/dist/ecosystem/workflow.d.ts +2 -0
- package/dist/ecosystem/workflow.js +2 -0
- package/dist/errors/index.d.ts +8 -0
- package/dist/errors/index.js +1 -0
- package/dist/errors/serialized-error.d.ts +7 -0
- package/dist/function/function-meta.types.d.ts +139 -0
- package/dist/function/function-runner.d.ts +3 -2
- package/dist/function/function-runner.js +31 -11
- package/dist/function/functions.types.d.ts +10 -2
- package/dist/function/index.d.ts +8 -2
- package/dist/function/index.js +4 -1
- package/dist/function/pikku-request.d.ts +8 -0
- package/dist/function/pikku-request.js +15 -0
- package/dist/middleware/auth-apikey.d.ts +2 -10
- package/dist/middleware/auth-apikey.js +1 -1
- package/dist/middleware/auth-bearer.d.ts +2 -10
- package/dist/middleware/auth-bearer.js +1 -1
- package/dist/middleware/auth-cookie.d.ts +2 -10
- package/dist/middleware/auth-cookie.js +1 -1
- package/dist/middleware/cors.d.ts +5 -11
- package/dist/middleware/cors.js +13 -6
- package/dist/middleware/index.d.ts +3 -0
- package/dist/middleware/index.js +1 -0
- package/dist/middleware/middleware-factories.d.ts +9 -0
- package/dist/middleware/middleware-factories.js +19 -0
- package/dist/middleware/middleware.types.d.ts +27 -0
- package/dist/middleware/middleware.types.js +1 -0
- package/dist/middleware/remote-auth.d.ts +2 -2
- package/dist/middleware/remote-auth.js +1 -1
- package/dist/middleware/telemetry.d.ts +4 -20
- package/dist/middleware/telemetry.js +1 -1
- package/dist/middleware-runner.d.ts +2 -1
- package/dist/pikku-state.d.ts +2 -1
- package/dist/services/audit-service.d.ts +1 -1
- package/dist/services/credential-wire-service.js +1 -1
- package/dist/services/email-service.d.ts +1 -1
- package/dist/services/file-scenario-run-store.d.ts +58 -0
- package/dist/services/file-scenario-run-store.js +214 -0
- package/dist/services/in-memory-workflow-service.d.ts +1 -1
- package/dist/services/index.d.ts +5 -1
- package/dist/services/index.js +3 -0
- package/dist/services/local-secrets.d.ts +1 -1
- package/dist/services/local-secrets.js +1 -1
- package/dist/services/logger.d.ts +7 -7
- package/dist/services/meta-service.d.ts +2 -1
- package/dist/services/scoped-secret-service.d.ts +1 -1
- package/dist/services/secret-service.d.ts +1 -1
- package/dist/services/typed-secret-service.d.ts +16 -2
- package/dist/services/typed-secret-service.js +5 -0
- package/dist/services/webhook-service.d.ts +1 -1
- package/dist/services/workflow-service.d.ts +2 -1
- package/dist/testing/index.d.ts +1 -0
- package/dist/testing/index.js +1 -0
- package/dist/types/core.types.d.ts +30 -180
- package/dist/types/core.types.js +1 -19
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.js +1 -0
- package/dist/types/state.types.d.ts +3 -1
- package/dist/utils.d.ts +13 -0
- package/dist/utils.js +2 -0
- package/dist/wirings/addon/addon-runner.d.ts +17 -0
- package/dist/wirings/addon/addon-runner.js +150 -0
- package/dist/wirings/addon/index.d.ts +6 -0
- package/dist/wirings/addon/index.js +3 -0
- package/dist/wirings/addon/remote-addon-auth.d.ts +16 -0
- package/dist/wirings/addon/remote-addon-auth.js +39 -0
- package/dist/wirings/addon/wire-addon.d.ts +80 -0
- package/dist/wirings/addon/wire-addon.js +120 -0
- package/dist/wirings/addon/wire-remote-addon.d.ts +22 -0
- package/dist/wirings/addon/wire-remote-addon.js +11 -0
- package/dist/wirings/agent/agent-prepare.d.ts +3 -3
- package/dist/wirings/agent/agent-prepare.js +1 -1
- package/dist/wirings/agent/agent-runner.js +2 -3
- package/dist/wirings/agent/agent-stream.js +2 -2
- package/dist/wirings/agent/agent-utils.d.ts +13 -0
- package/dist/wirings/agent/agent-utils.js +16 -0
- package/dist/wirings/agent/agent.types.d.ts +3 -2
- package/dist/wirings/agent/index.d.ts +1 -1
- package/dist/wirings/agent/voice-input.js +1 -1
- package/dist/wirings/agent/voice-output.js +1 -1
- package/dist/wirings/agent-scorer/agent-scorer-judge.d.ts +13 -0
- package/dist/wirings/agent-scorer/agent-scorer-judge.js +52 -0
- package/dist/wirings/agent-scorer/agent-scorer.d.ts +7 -1
- package/dist/wirings/agent-scorer/agent-scorer.js +1 -0
- package/dist/wirings/agent-scorer/agent-scorer.types.d.ts +20 -0
- package/dist/wirings/agent-scorer/index.d.ts +1 -1
- package/dist/wirings/channel/channel-common.d.ts +2 -1
- package/dist/wirings/channel/channel-middleware-runner.d.ts +2 -1
- package/dist/wirings/channel/channel.types.d.ts +1 -1
- package/dist/wirings/channel/serverless/index.d.ts +1 -0
- package/dist/wirings/cli/channel/index.d.ts +1 -1
- package/dist/wirings/cli/cli-runner.d.ts +2 -1
- package/dist/wirings/cli/cli-runner.js +4 -1
- package/dist/wirings/cli/cli.types.d.ts +21 -2
- package/dist/wirings/cli/command-parser.js +157 -23
- package/dist/wirings/gateway/gateway.types.d.ts +2 -1
- package/dist/wirings/http/http-runner.d.ts +1 -1
- package/dist/wirings/http/http-runner.js +1 -1
- package/dist/wirings/http/http.types.d.ts +2 -2
- package/dist/wirings/http/index.d.ts +1 -0
- package/dist/wirings/http/index.js +1 -0
- package/dist/wirings/http/pikku-fetch-http-request.js +1 -1
- package/dist/wirings/http/pikku-fetch-http-response.js +2 -2
- package/dist/wirings/mcp/mcp.types.d.ts +1 -1
- package/dist/wirings/persona/index.d.ts +1 -1
- package/dist/wirings/persona/index.js +1 -1
- package/dist/wirings/persona/persona.types.d.ts +14 -0
- package/dist/wirings/queue/queue.types.d.ts +1 -1
- package/dist/wirings/queue/signed-queue-service.d.ts +1 -1
- package/dist/wirings/rpc/index.d.ts +0 -6
- package/dist/wirings/rpc/index.js +0 -3
- package/dist/wirings/rpc/remote-addon-auth.d.ts +1 -1
- package/dist/wirings/rpc/remote-addon-auth.js +1 -1
- package/dist/wirings/rpc/rpc-runner.js +2 -2
- package/dist/wirings/rpc/wire-addon.d.ts +1 -1
- package/dist/wirings/scheduler/scheduler.types.d.ts +2 -1
- package/dist/wirings/scope/index.d.ts +1 -0
- package/dist/wirings/scope/index.js +1 -0
- package/dist/wirings/secret/secret.types.d.ts +10 -0
- package/dist/wirings/secret/validate-secret-definitions.js +2 -0
- package/dist/wirings/variable/validate-variable-definitions.js +2 -0
- package/dist/wirings/variable/variable.types.d.ts +9 -0
- package/dist/wirings/virtual-user/index.d.ts +1 -1
- package/dist/wirings/virtual-user/index.js +1 -1
- package/dist/wirings/virtual-user/prepare-virtual-user-run.d.ts +1 -1
- package/dist/wirings/virtual-user/virtual-user-derive.d.ts +1 -1
- package/dist/wirings/workflow/graph/graph-node.d.ts +9 -2
- package/dist/wirings/workflow/graph/graph-node.js +2 -0
- package/dist/wirings/workflow/graph/graph-runner.d.ts +1 -0
- package/dist/wirings/workflow/graph/graph-runner.js +283 -31
- package/dist/wirings/workflow/graph/workflow-graph.types.d.ts +16 -1
- package/dist/wirings/workflow/index.d.ts +2 -0
- package/dist/wirings/workflow/index.js +1 -0
- package/dist/wirings/workflow/pikku-scenario-service.d.ts +14 -4
- package/dist/wirings/workflow/pikku-scenario-service.js +44 -16
- package/dist/wirings/workflow/pikku-workflow-service.d.ts +2 -1
- package/dist/wirings/workflow/pikku-workflow-service.js +3 -4
- package/dist/wirings/workflow/run-timeline.d.ts +1 -1
- package/dist/wirings/workflow/scenario-run.types.d.ts +171 -0
- package/dist/wirings/workflow/scenario-run.types.js +1 -0
- package/dist/wirings/workflow/scenario-step-guards.d.ts +1 -2
- package/dist/wirings/workflow/scenario-step-guards.js +0 -8
- package/dist/wirings/workflow/scenario-step.types.d.ts +27 -12
- package/dist/wirings/workflow/workflow-approval.js +2 -1
- package/dist/wirings/workflow/workflow-run-engine.types.d.ts +2 -1
- package/dist/wirings/workflow/workflow.types.d.ts +2 -1
- package/knowledge/decisions/index.md +2 -0
- package/knowledge/decisions/internals/a-scenario-step-template-is-offered-unfilled.md +1 -1
- package/knowledge/decisions/internals/a-secret-that-fails-to-decrypt-fails-the-whole-read.md +1 -1
- package/knowledge/decisions/internals/a-virtual-user-run-is-not-a-workflow-and-not-a-queued-job.md +2 -2
- package/knowledge/decisions/internals/a-wall-clock-threshold-is-a-load-test-in-disguise.md +6 -6
- package/knowledge/decisions/internals/a-workflow-wire-is-built-from-the-run-not-from-the-rpc-service.md +1 -1
- package/knowledge/decisions/internals/addon-singleton-services-are-cached-per-namespace-not-per-package.md +1 -1
- package/knowledge/decisions/internals/addon-workflow-names-are-prefixed-with-the-consumer-namespace.md +1 -1
- package/knowledge/decisions/internals/an-addon-scope-root-loses-to-a-root-the-host-already-declares.md +1 -1
- package/knowledge/decisions/internals/channel-message-handlers-accept-three-config-shapes.md +1 -1
- package/knowledge/decisions/internals/channel-middleware-caches-only-statically-resolved-middleware.md +1 -1
- package/knowledge/decisions/internals/channel-user-id-is-persisted-after-onconnect-middleware-runs.md +1 -1
- package/knowledge/decisions/internals/cli-option-names-are-camelcase-in-state-and-kebab-on-the-command-line.md +1 -1
- package/knowledge/decisions/internals/cli-parse-errors-are-routed-by-message-prefix.md +1 -1
- package/knowledge/decisions/internals/cli-unknown-long-options-warn-instead-of-failing.md +1 -1
- package/knowledge/decisions/internals/core-column-form-is-an-axis-of-its-own.md +4 -4
- package/knowledge/decisions/internals/core-data-classification-brand-is-an-optional-property.md +1 -1
- package/knowledge/decisions/internals/core-function-runner-restores-the-wire-fields-it-overwrites.md +3 -3
- package/knowledge/decisions/internals/core-hot-reload-merges-generated-meta-never-replaces-it.md +2 -2
- package/knowledge/decisions/internals/core-hot-reload-owns-its-module-registry.md +2 -2
- package/knowledge/decisions/internals/core-middleware-order-is-scope-then-priority.md +1 -1
- package/knowledge/decisions/internals/core-schema-defaults-apply-on-every-transport.md +1 -1
- package/knowledge/decisions/internals/core-scopes-are-an-and-gate-separate-from-permissions.md +3 -3
- package/knowledge/decisions/internals/gateway-adapters-resolve-lazily-and-are-promise-cached.md +1 -1
- package/knowledge/decisions/internals/gateway-listener-middleware-runs-without-an-rpc-on-the-wire.md +4 -4
- package/knowledge/decisions/internals/gateway-wiring-is-a-meta-wiring-over-http-and-channels.md +1 -1
- package/knowledge/decisions/internals/http-router-matches-normalized-paths-but-returns-registered-ones.md +1 -1
- package/knowledge/decisions/internals/in-a-scenario-a-4xx-is-data-not-an-exception.md +1 -1
- package/knowledge/decisions/internals/in-memory-workflow-history-aliases-the-live-step-object.md +1 -1
- package/knowledge/decisions/internals/index.md +4 -2
- package/knowledge/decisions/internals/istanbul-statement-counts-attach-to-the-start-line-only.md +1 -1
- package/knowledge/decisions/internals/one-project-shape-check-two-validators.md +1 -1
- package/knowledge/decisions/internals/queue-jobs-always-carry-an-explicit-attempts-count.md +1 -1
- package/knowledge/decisions/internals/remote-addons-dispatch-over-http-instead-of-local-meta.md +1 -1
- package/knowledge/decisions/internals/rpc-names-resolve-through-package-scope-before-root.md +1 -1
- package/knowledge/decisions/internals/scenario-given-and-when-are-sugar-but-then-is-not.md +2 -2
- package/knowledge/decisions/internals/scenarios-live-in-files-named-for-them.md +5 -5
- package/knowledge/decisions/internals/the-actor-prompt-says-json-because-of-json-object-mode.md +1 -1
- package/knowledge/decisions/internals/the-api-report-pins-members-not-just-names.md +1 -1
- package/knowledge/decisions/internals/the-ecosystem-entry-point-carries-the-adapter-surface.md +43 -19
- package/knowledge/decisions/internals/the-persona-runtime-is-exported-from-the-persona-entry-point.md +1 -1
- package/knowledge/decisions/internals/the-worker-disposition-is-the-one-that-is-not-testing.md +1 -1
- package/knowledge/decisions/internals/validate-runs-checks-by-precondition.md +3 -3
- package/knowledge/decisions/internals/virtual-user-step-order-comes-from-insertion-order.md +1 -1
- package/knowledge/decisions/internals/webhook-delivery-history-records-every-attempt-best-effort.md +1 -1
- package/knowledge/decisions/internals/wiring-registries-erase-the-generics-their-wire-functions-capture.md +1 -1
- package/knowledge/decisions/internals/workflow-approval-expiry-is-decided-from-a-recorded-deadline.md +1 -1
- package/knowledge/decisions/internals/workflow-core-never-imports-a-browser-driver.md +1 -1
- package/knowledge/decisions/internals/workflow-inline-runs-report-their-run-id-before-they-can-fail.md +1 -1
- package/knowledge/decisions/internals/workflow-invocation-id-is-the-dedupe-key-not-step-id.md +1 -1
- package/knowledge/decisions/internals/workflow-run-capabilities-are-extensions-not-subclasses.md +1 -1
- package/knowledge/decisions/internals/workflow-run-timeline-is-a-pure-fold-over-durable-history.md +1 -1
- package/knowledge/decisions/internals/workflow-scenario-assertions-never-retry-and-record-one-step.md +9 -5
- package/knowledge/decisions/internals/workflow-scenario-hooks-are-a-scenario-only-affordance.md +1 -1
- package/knowledge/decisions/internals/workflow-step-rpc-name-is-provenance-only.md +2 -2
- package/knowledge/decisions/internals/workflow-suspend-and-approval-reasons-are-durable-step-identities.md +1 -1
- package/knowledge/decisions/security/a-function-never-receives-the-secret-service.md +1 -1
- package/knowledge/decisions/security/a-step-runs-the-function-the-workflow-dispatched-it-with.md +1 -1
- package/knowledge/decisions/security/a-virtual-user-is-never-offered-a-step-that-would-forge-its-own-oracle.md +2 -3
- package/knowledge/decisions/security/actor-sign-in-is-proven-by-set-cookie-not-a-non-empty-jar.md +1 -1
- package/knowledge/decisions/security/addon-auth-and-tags-only-tighten.md +1 -1
- package/knowledge/decisions/security/agent-gate-requires-a-session-only-when-auth-is-true.md +1 -1
- package/knowledge/decisions/security/an-approval-answer-outlives-the-run-it-answered.md +3 -3
- package/knowledge/decisions/security/console-addon-privileged-functions-gate-themselves.md +4 -3
- package/knowledge/decisions/security/core-safe-fetch-blocks-ssrf-by-host-literal-not-dns.md +1 -1
- package/knowledge/decisions/security/gateway-middleware-sessions-must-be-bridged-onto-the-wire.md +2 -2
- package/knowledge/decisions/security/global-permissions-and-function-permissions-are-independent-gates.md +1 -1
- package/knowledge/decisions/security/http-request-bodies-are-bounded-before-they-are-buffered.md +2 -2
- package/knowledge/decisions/security/index.md +2 -0
- package/knowledge/decisions/security/mcp-internal-error-details-are-double-gated-on-production.md +1 -1
- package/knowledge/decisions/security/queue-jobs-carry-the-producers-pikku-user-id.md +3 -3
- package/knowledge/decisions/security/remote-addon-tokens-are-client-credentials-not-mesh-trust.md +1 -1
- package/knowledge/decisions/security/scaffold-features-are-authenticated-unless-opted-out.md +2 -2
- package/knowledge/decisions/security/self-authentication-is-declared-not-detected.md +1 -1
- package/knowledge/decisions/security/signed-content-urls-bind-the-request-path.md +2 -2
- package/knowledge/index.md +3 -1
- package/knowledge/questions/channel-middleware-accepts-bare-factories-that-nothing-resolves.md +1 -1
- package/knowledge/questions/index.md +2 -0
- package/package.json +14 -13
- package/run-tests.sh +0 -0
- package/scripts/generate-api-report.d.mts +1 -1
- package/scripts/generate-api-report.mjs +67 -60
- package/scripts/generate-api-report.mts +11 -45
- package/src/api-report.test.ts +70 -1
- package/src/app-alias-surface.test.ts +179 -0
- package/src/app-leaf-surface.test.ts +217 -0
- package/src/bootstrap-compat/root.ts +20 -0
- package/src/{column-form.test.ts → classification/column-form.test.ts} +2 -2
- package/src/{data-classification.ts → classification/data-classification.ts} +1 -5
- package/src/classification/index.ts +38 -0
- package/src/{secret-value.test.ts → classification/secret-value.test.ts} +2 -2
- package/src/{secret-value.ts → classification/secret-value.ts} +1 -6
- package/src/crypto-utils.ts +1 -1
- package/src/dev/reload-meta.test.ts +1 -1
- package/src/errors/index.ts +9 -0
- package/src/errors/serialized-error.ts +9 -0
- package/src/factory-functions.test.ts +4 -2
- package/src/function/function-meta.types.ts +151 -0
- package/src/function/function-runner.test.ts +4 -2
- package/src/function/function-runner.ts +47 -14
- package/src/function/functions.types.ts +11 -7
- package/src/function/index.ts +24 -5
- package/src/function/list.types.ts +1 -3
- package/src/middleware/auth-apikey.ts +4 -2
- package/src/middleware/auth-bearer.test.ts +1 -1
- package/src/middleware/auth-bearer.ts +4 -2
- package/src/middleware/auth-cookie.ts +4 -1
- package/src/middleware/cors.test.ts +126 -5
- package/src/middleware/cors.ts +19 -8
- package/src/middleware/index.ts +16 -0
- package/src/middleware/middleware-factories.ts +62 -0
- package/src/middleware/middleware.types.ts +61 -0
- package/src/middleware/remote-auth.test.ts +1 -1
- package/src/middleware/remote-auth.ts +1 -1
- package/src/middleware/telemetry.ts +4 -2
- package/src/middleware-runner.test.ts +2 -3
- package/src/middleware-runner.ts +2 -2
- package/src/no-root-barrel.test.ts +114 -0
- package/src/permissions.ts +2 -4
- package/src/pikku-state.ts +3 -1
- package/src/public-surface.json +56 -241
- package/src/public-surface.json.README +3 -3
- package/src/public-surface.test.ts +5 -5
- package/src/remote.test.ts +1 -1
- package/src/removed-legacy-exports.test.ts +5 -1
- package/src/services/audit-service.ts +1 -1
- package/src/services/credential-wire-service.ts +1 -1
- package/src/services/email-service.ts +2 -4
- package/src/services/file-scenario-run-store.test.ts +349 -0
- package/src/services/file-scenario-run-store.ts +282 -0
- package/src/services/in-memory-workflow-service.ts +1 -1
- package/src/services/index.ts +13 -1
- package/src/services/local-content-request-handler.ts +1 -2
- package/src/services/local-secrets.ts +1 -1
- package/src/services/logger.ts +7 -7
- package/src/services/meta-service.ts +2 -2
- package/src/services/queue-webhook-service.test.ts +1 -1
- package/src/services/scoped-secret-service.ts +1 -1
- package/src/services/secret-service.ts +1 -1
- package/src/services/typed-secret-service.test.ts +52 -0
- package/src/services/typed-secret-service.ts +26 -2
- package/src/services/webhook-service.ts +1 -1
- package/src/services/workflow-service.ts +2 -1
- package/src/template-alias-surface.test.ts +240 -0
- package/src/testing/index.ts +1 -0
- package/src/types/core.types.ts +33 -285
- package/src/types/index.ts +2 -0
- package/src/types/state.types.ts +6 -5
- package/src/types/typed-credentials.test.ts +72 -0
- package/src/utils.ts +34 -0
- package/src/wirings/{rpc → addon}/addon-scopes.test.ts +1 -1
- package/src/wirings/addon/index.ts +12 -0
- package/src/wirings/{rpc → addon}/remote-addon-auth.ts +4 -1
- package/src/wirings/{rpc → addon}/wire-addon.ts +37 -2
- package/src/wirings/agent/agent-prepare.ts +8 -5
- package/src/wirings/agent/agent-runner.ts +2 -3
- package/src/wirings/agent/agent-stream.ts +2 -3
- package/src/wirings/agent/agent-utils.ts +19 -0
- package/src/wirings/agent/agent.types.ts +3 -3
- package/src/wirings/agent/index.ts +1 -0
- package/src/wirings/agent/voice-input.ts +1 -1
- package/src/wirings/agent/voice-output.test.ts +2 -4
- package/src/wirings/agent/voice-output.ts +1 -1
- package/src/wirings/agent-scorer/agent-scorer-judge.test.ts +145 -0
- package/src/wirings/agent-scorer/agent-scorer-judge.ts +60 -0
- package/src/wirings/agent-scorer/agent-scorer.ts +8 -0
- package/src/wirings/agent-scorer/agent-scorer.types.ts +21 -0
- package/src/wirings/agent-scorer/index.ts +1 -0
- package/src/wirings/channel/channel-common.ts +4 -2
- package/src/wirings/channel/channel-handler.ts +2 -5
- package/src/wirings/channel/channel-middleware-runner.ts +1 -1
- package/src/wirings/channel/channel-rpc.types.ts +1 -5
- package/src/wirings/channel/channel.types.ts +1 -2
- package/src/wirings/channel/local/local-channel-runner.test.ts +1 -2
- package/src/wirings/channel/serverless/index.ts +1 -0
- package/src/wirings/cli/channel/cli-raw-channel-runner.ts +2 -2
- package/src/wirings/cli/channel/index.ts +1 -3
- package/src/wirings/cli/cli-runner.test.ts +1 -1
- package/src/wirings/cli/cli-runner.ts +11 -7
- package/src/wirings/cli/cli.types.ts +24 -3
- package/src/wirings/cli/command-parser.test.ts +388 -1
- package/src/wirings/cli/command-parser.ts +189 -29
- package/src/wirings/gateway/gateway-runner.test.ts +1 -2
- package/src/wirings/gateway/gateway-runner.ts +3 -6
- package/src/wirings/gateway/gateway.types.ts +5 -4
- package/src/wirings/http/http-routes.test.ts +1 -2
- package/src/wirings/http/http-runner-addon-ref.test.ts +238 -0
- package/src/wirings/http/http-runner.test.ts +3 -8
- package/src/wirings/http/http-runner.ts +9 -3
- package/src/wirings/http/http.types.ts +3 -12
- package/src/wirings/http/index.ts +1 -0
- package/src/wirings/http/pikku-fetch-http-request.ts +1 -1
- package/src/wirings/http/pikku-fetch-http-response.ts +3 -2
- package/src/wirings/mcp/mcp-runner.test.ts +1 -1
- package/src/wirings/mcp/mcp.types.ts +1 -2
- package/src/wirings/persona/index.ts +1 -4
- package/src/wirings/persona/persona.types.ts +14 -0
- package/src/wirings/queue/queue-identity.test.ts +1 -1
- package/src/wirings/queue/queue.types.ts +2 -6
- package/src/wirings/queue/signed-queue-service.ts +1 -1
- package/src/wirings/rpc/index.ts +0 -12
- package/src/wirings/rpc/rpc-runner.test.ts +4 -4
- package/src/wirings/rpc/rpc-runner.ts +3 -3
- package/src/wirings/scheduler/scheduler.types.ts +2 -5
- package/src/wirings/scope/index.ts +1 -0
- package/src/wirings/secret/secret.types.ts +10 -0
- package/src/wirings/secret/validate-secret-definitions.test.ts +23 -0
- package/src/wirings/secret/validate-secret-definitions.ts +2 -0
- package/src/wirings/variable/validate-variable-definitions.test.ts +23 -0
- package/src/wirings/variable/validate-variable-definitions.ts +2 -0
- package/src/wirings/variable/variable.types.ts +9 -0
- package/src/wirings/virtual-user/index.ts +1 -4
- package/src/wirings/virtual-user/prepare-virtual-user-run.ts +1 -1
- package/src/wirings/virtual-user/virtual-user-derive.test.ts +1 -1
- package/src/wirings/virtual-user/virtual-user-derive.ts +1 -1
- package/src/wirings/virtual-user/virtual-user.types.ts +1 -5
- package/src/wirings/workflow/graph/graph-foreach-queued.test.ts +569 -0
- package/src/wirings/workflow/graph/graph-foreach.test.ts +626 -0
- package/src/wirings/workflow/graph/graph-node.ts +16 -1
- package/src/wirings/workflow/graph/graph-runner.ts +387 -61
- package/src/wirings/workflow/graph/workflow-graph.types.ts +28 -3
- package/src/wirings/workflow/index.ts +8 -0
- package/src/wirings/workflow/pikku-scenario-service.ts +59 -19
- package/src/wirings/workflow/pikku-workflow-service.ts +6 -8
- package/src/wirings/workflow/run-timeline.ts +1 -1
- package/src/wirings/workflow/scenario-expectations.test.ts +28 -13
- package/src/wirings/workflow/scenario-run.types.ts +186 -0
- package/src/wirings/workflow/scenario-step-guards.ts +1 -14
- package/src/wirings/workflow/scenario-step.test.ts +32 -7
- package/src/wirings/workflow/scenario-step.types.ts +27 -12
- package/src/wirings/workflow/workflow-approval-policy.test.ts +117 -47
- package/src/wirings/workflow/workflow-approval.ts +2 -1
- package/src/wirings/workflow/workflow-run-engine.types.ts +2 -1
- package/src/wirings/workflow/workflow.types.ts +4 -12
- package/src/wirings-stay-decoupled.test.ts +6 -3
- package/tsconfig.tsbuildinfo +1 -1
- package/tsconfig.type-tests.json +3 -2
- package/dist/ecosystem/ai-agent.d.ts +0 -18
- package/dist/ecosystem/ai-agent.js +0 -6
- package/dist/ecosystem/ai-scorer.d.ts +0 -12
- package/dist/ecosystem/ai-scorer.js +0 -5
- package/dist/services/ai-agent-runner-service.d.ts +0 -220
- package/dist/services/ai-run-state-service.d.ts +0 -29
- package/dist/services/ai-storage-service.d.ts +0 -18
- package/dist/services/in-memory-ai-run-state-service.d.ts +0 -19
- package/dist/services/in-memory-ai-run-state-service.js +0 -54
- package/dist/testing/service-tests/ai-storage-service-tests.d.ts +0 -3
- package/dist/testing/service-tests/ai-storage-service-tests.js +0 -302
- package/dist/wirings/ai-agent/agent-rpc.d.ts +0 -15
- package/dist/wirings/ai-agent/agent-rpc.js +0 -53
- package/dist/wirings/ai-agent/ai-agent-agui.d.ts +0 -79
- package/dist/wirings/ai-agent/ai-agent-agui.js +0 -327
- package/dist/wirings/ai-agent/ai-agent-finalize.d.ts +0 -58
- package/dist/wirings/ai-agent/ai-agent-finalize.js +0 -138
- package/dist/wirings/ai-agent/ai-agent-helpers.d.ts +0 -35
- package/dist/wirings/ai-agent/ai-agent-helpers.js +0 -47
- package/dist/wirings/ai-agent/ai-agent-interrupt.d.ts +0 -153
- package/dist/wirings/ai-agent/ai-agent-interrupt.js +0 -257
- package/dist/wirings/ai-agent/ai-agent-memory.d.ts +0 -42
- package/dist/wirings/ai-agent/ai-agent-memory.js +0 -333
- package/dist/wirings/ai-agent/ai-agent-model-config.d.ts +0 -16
- package/dist/wirings/ai-agent/ai-agent-model-config.js +0 -51
- package/dist/wirings/ai-agent/ai-agent-prepare.d.ts +0 -117
- package/dist/wirings/ai-agent/ai-agent-prepare.js +0 -728
- package/dist/wirings/ai-agent/ai-agent-registry.d.ts +0 -16
- package/dist/wirings/ai-agent/ai-agent-registry.js +0 -51
- package/dist/wirings/ai-agent/ai-agent-runner.d.ts +0 -7
- package/dist/wirings/ai-agent/ai-agent-runner.js +0 -580
- package/dist/wirings/ai-agent/ai-agent-stream.d.ts +0 -41
- package/dist/wirings/ai-agent/ai-agent-stream.js +0 -1029
- package/dist/wirings/ai-agent/ai-agent-turn.d.ts +0 -57
- package/dist/wirings/ai-agent/ai-agent-turn.js +0 -82
- package/dist/wirings/ai-agent/ai-agent-utils.d.ts +0 -1
- package/dist/wirings/ai-agent/ai-agent-utils.js +0 -1
- package/dist/wirings/ai-agent/ai-agent.types.d.ts +0 -625
- package/dist/wirings/ai-agent/index.d.ts +0 -12
- package/dist/wirings/ai-agent/index.js +0 -10
- package/dist/wirings/ai-agent/voice-input.d.ts +0 -69
- package/dist/wirings/ai-agent/voice-input.js +0 -150
- package/dist/wirings/ai-agent/voice-output.d.ts +0 -85
- package/dist/wirings/ai-agent/voice-output.js +0 -196
- package/dist/wirings/ai-scorer/ai-scorer-grade.d.ts +0 -26
- package/dist/wirings/ai-scorer/ai-scorer-grade.js +0 -33
- package/dist/wirings/ai-scorer/ai-scorer-judge.d.ts +0 -17
- package/dist/wirings/ai-scorer/ai-scorer-judge.js +0 -92
- package/dist/wirings/ai-scorer/ai-scorer-live.d.ts +0 -15
- package/dist/wirings/ai-scorer/ai-scorer-live.js +0 -38
- package/dist/wirings/ai-scorer/ai-scorer-registry.d.ts +0 -18
- package/dist/wirings/ai-scorer/ai-scorer-registry.js +0 -46
- package/dist/wirings/ai-scorer/ai-scorer-sampling.d.ts +0 -8
- package/dist/wirings/ai-scorer/ai-scorer-sampling.js +0 -31
- package/dist/wirings/ai-scorer/ai-scorer-snapshots.d.ts +0 -10
- package/dist/wirings/ai-scorer/ai-scorer-snapshots.js +0 -40
- package/dist/wirings/ai-scorer/ai-scorer-worker.d.ts +0 -15
- package/dist/wirings/ai-scorer/ai-scorer-worker.js +0 -58
- package/dist/wirings/ai-scorer/ai-scorer.d.ts +0 -39
- package/dist/wirings/ai-scorer/ai-scorer.js +0 -40
- package/dist/wirings/ai-scorer/ai-scorer.types.d.ts +0 -90
- package/dist/wirings/ai-scorer/ai-scorer.types.js +0 -4
- package/dist/wirings/ai-scorer/index.d.ts +0 -6
- package/dist/wirings/ai-scorer/index.js +0 -5
- package/src/ecosystem/agent-scorer.ts +0 -24
- package/src/ecosystem/agent.ts +0 -42
- package/src/ecosystem/channel/local.ts +0 -1
- package/src/ecosystem/channel.ts +0 -22
- package/src/ecosystem/cli/channel.ts +0 -25
- package/src/ecosystem/cli.ts +0 -21
- package/src/ecosystem/credential.ts +0 -10
- package/src/ecosystem/dev.ts +0 -12
- package/src/ecosystem/function.ts +0 -28
- package/src/ecosystem/gateway.ts +0 -4
- package/src/ecosystem/hmac.ts +0 -1
- package/src/ecosystem/http.ts +0 -22
- package/src/ecosystem/mcp.ts +0 -17
- package/src/ecosystem/middleware.ts +0 -27
- package/src/ecosystem/node-host-resolver.ts +0 -1
- package/src/ecosystem/node.ts +0 -5
- package/src/ecosystem/oauth2.ts +0 -4
- package/src/ecosystem/persona.ts +0 -30
- package/src/ecosystem/queue.ts +0 -23
- package/src/ecosystem/remote.ts +0 -9
- package/src/ecosystem/role.ts +0 -13
- package/src/ecosystem/rpc.ts +0 -7
- package/src/ecosystem/safe-fetch.ts +0 -8
- package/src/ecosystem/scenario.ts +0 -32
- package/src/ecosystem/scheduler.ts +0 -5
- package/src/ecosystem/schema.ts +0 -1
- package/src/ecosystem/scope.ts +0 -14
- package/src/ecosystem/secret.ts +0 -15
- package/src/ecosystem/services/istanbul-coverage.ts +0 -1
- package/src/ecosystem/services/local-content-request-handler.ts +0 -16
- package/src/ecosystem/services/local-content.ts +0 -1
- package/src/ecosystem/services/v8-coverage.ts +0 -1
- package/src/ecosystem/services.ts +0 -82
- package/src/ecosystem/trigger.ts +0 -7
- package/src/ecosystem/types.ts +0 -34
- package/src/ecosystem/variable.ts +0 -14
- package/src/ecosystem/virtual-user.ts +0 -48
- package/src/ecosystem/workflow.ts +0 -68
- package/src/ecosystem.ts +0 -40
- package/src/index.ts +0 -244
- /package/dist/{services/ai-agent-runner-service.js → bootstrap-compat/root.js} +0 -0
- /package/dist/{services/ai-run-state-service.js → classification/data-classification.js} +0 -0
- /package/dist/{services/ai-storage-service.js → errors/serialized-error.js} +0 -0
- /package/dist/{wirings/ai-agent/ai-agent.types.js → function/function-meta.types.js} +0 -0
- /package/src/{column-form.ts → classification/column-form.ts} +0 -0
- /package/src/{pikku-request.test.ts → function/pikku-request.test.ts} +0 -0
- /package/src/{pikku-request.ts → function/pikku-request.ts} +0 -0
- /package/src/wirings/{rpc → addon}/addon-auth-tags.test.ts +0 -0
- /package/src/wirings/{rpc → addon}/addon-runner.ts +0 -0
- /package/src/wirings/{rpc → addon}/addon-secrets.test.ts +0 -0
- /package/src/wirings/{rpc → addon}/wire-addon.test.ts +0 -0
- /package/src/wirings/{rpc → addon}/wire-remote-addon.ts +0 -0
|
@@ -29,10 +29,28 @@ function buildTemplateRegex(nodeId: string): RegExp | null {
|
|
|
29
29
|
return new RegExp(`^${escaped}$`)
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
return
|
|
32
|
+
const FANOUT_INSTANCE = /^(.+)\[(\d+)\]$/
|
|
33
|
+
|
|
34
|
+
function fanoutInstanceKey(base: string, index: number): string {
|
|
35
|
+
return `${base}[${index}]`
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function splitFanoutInstance(
|
|
39
|
+
name: string
|
|
40
|
+
): { base: string; index: number } | null {
|
|
41
|
+
const match = FANOUT_INSTANCE.exec(name)
|
|
42
|
+
if (!match) return null
|
|
43
|
+
return { base: match[1]!, index: Number(match[2]!) }
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function stripInstanceOrdinal(name: string): string {
|
|
47
|
+
const fanout = splitFanoutInstance(name)
|
|
48
|
+
const withoutItem = fanout ? fanout.base : name
|
|
49
|
+
const hash = withoutItem.lastIndexOf('#')
|
|
50
|
+
if (hash <= 0) return withoutItem
|
|
51
|
+
return /^\d+$/.test(withoutItem.slice(hash + 1))
|
|
52
|
+
? withoutItem.slice(0, hash)
|
|
53
|
+
: withoutItem
|
|
36
54
|
}
|
|
37
55
|
|
|
38
56
|
function remapStepNamesToNodeIds(
|
|
@@ -84,14 +102,22 @@ function closesCycle(
|
|
|
84
102
|
return false
|
|
85
103
|
}
|
|
86
104
|
|
|
105
|
+
interface GraphFireInstruction {
|
|
106
|
+
logical: string
|
|
107
|
+
instanceKey: string
|
|
108
|
+
fromStepName?: string
|
|
109
|
+
itemIndex?: number
|
|
110
|
+
}
|
|
111
|
+
|
|
87
112
|
function planGraphTransitions(
|
|
88
113
|
nodes: Record<string, any>,
|
|
89
114
|
instances: Array<{ stepName: string; status: string; fromStepName?: string }>,
|
|
90
115
|
branchByStep: Record<string, string>,
|
|
91
116
|
entryNodeIds: string[],
|
|
92
|
-
graphName: string
|
|
117
|
+
graphName: string,
|
|
118
|
+
fanoutWidths: Record<string, number> = {}
|
|
93
119
|
): {
|
|
94
|
-
toFire:
|
|
120
|
+
toFire: GraphFireInstruction[]
|
|
95
121
|
hasInFlight: boolean
|
|
96
122
|
blockedWaiting: boolean
|
|
97
123
|
} {
|
|
@@ -99,15 +125,37 @@ function planGraphTransitions(
|
|
|
99
125
|
remapStepNamesToNodeIds([name], nodes, graphName)[0]!
|
|
100
126
|
|
|
101
127
|
const countByLogical: Record<string, number> = {}
|
|
128
|
+
const instancesByLogical: Record<
|
|
129
|
+
string,
|
|
130
|
+
Array<{ stepName: string; status: string }>
|
|
131
|
+
> = {}
|
|
102
132
|
const consumed = new Set<string>()
|
|
103
133
|
for (const inst of instances) {
|
|
104
134
|
const logical = toLogical(inst.stepName)
|
|
105
135
|
countByLogical[logical] = (countByLogical[logical] ?? 0) + 1
|
|
136
|
+
;(instancesByLogical[logical] ??= []).push(inst)
|
|
106
137
|
consumed.add(`${inst.fromStepName ?? ENTRY_FROM}->${logical}`)
|
|
107
138
|
}
|
|
108
139
|
|
|
140
|
+
const isFanned = (nodeId: string) => Boolean(nodes[nodeId]?.forEach)
|
|
141
|
+
const fanoutComplete = (nodeId: string) => {
|
|
142
|
+
const width = fanoutWidths[nodeId]
|
|
143
|
+
if (width === undefined) return false
|
|
144
|
+
const succeeded = (instancesByLogical[nodeId] ?? []).filter(
|
|
145
|
+
(i) => i.status === 'succeeded'
|
|
146
|
+
).length
|
|
147
|
+
return succeeded >= width
|
|
148
|
+
}
|
|
149
|
+
|
|
109
150
|
const completed = instances.filter((i) => i.status === 'succeeded')
|
|
110
|
-
const completedLogical = new Set(
|
|
151
|
+
const completedLogical = new Set<string>()
|
|
152
|
+
for (const inst of completed) {
|
|
153
|
+
const logical = toLogical(inst.stepName)
|
|
154
|
+
if (!isFanned(logical)) completedLogical.add(logical)
|
|
155
|
+
}
|
|
156
|
+
for (const nodeId of Object.keys(fanoutWidths)) {
|
|
157
|
+
if (isFanned(nodeId) && fanoutComplete(nodeId)) completedLogical.add(nodeId)
|
|
158
|
+
}
|
|
111
159
|
|
|
112
160
|
const edges: Array<{
|
|
113
161
|
from?: string
|
|
@@ -118,32 +166,88 @@ function planGraphTransitions(
|
|
|
118
166
|
for (const entryId of entryNodeIds) {
|
|
119
167
|
edges.push({ fromKey: ENTRY_FROM, target: entryId })
|
|
120
168
|
}
|
|
169
|
+
const fannedEdgesEmitted = new Set<string>()
|
|
121
170
|
for (const inst of completed) {
|
|
122
171
|
const fromLogical = toLogical(inst.stepName)
|
|
123
172
|
const node = nodes[fromLogical]
|
|
124
173
|
if (!node?.next) continue
|
|
174
|
+
let from = inst.stepName
|
|
175
|
+
let branchKey = branchByStep[inst.stepName]
|
|
176
|
+
if (isFanned(fromLogical)) {
|
|
177
|
+
if (!completedLogical.has(fromLogical)) continue
|
|
178
|
+
if (fannedEdgesEmitted.has(fromLogical)) continue
|
|
179
|
+
fannedEdgesEmitted.add(fromLogical)
|
|
180
|
+
from = fromLogical
|
|
181
|
+
branchKey = branchByStep[fromLogical] ?? branchByStep[inst.stepName]
|
|
182
|
+
}
|
|
183
|
+
for (const target of resolveNextFromConfig(node.next, branchKey)) {
|
|
184
|
+
edges.push({ from, fromKey: from, fromLogical, target })
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
// A zero-width fanout produces no instances at all, so its outgoing edges
|
|
188
|
+
// have no completed instance to hang off — emit them from the logical node.
|
|
189
|
+
for (const [nodeId, width] of Object.entries(fanoutWidths)) {
|
|
190
|
+
if (width !== 0 || fannedEdgesEmitted.has(nodeId)) continue
|
|
191
|
+
const node = nodes[nodeId]
|
|
192
|
+
if (!node?.next) continue
|
|
193
|
+
fannedEdgesEmitted.add(nodeId)
|
|
125
194
|
for (const target of resolveNextFromConfig(
|
|
126
195
|
node.next,
|
|
127
|
-
branchByStep[
|
|
196
|
+
branchByStep[nodeId]
|
|
128
197
|
)) {
|
|
129
|
-
edges.push({
|
|
130
|
-
from: inst.stepName,
|
|
131
|
-
fromKey: inst.stepName,
|
|
132
|
-
fromLogical,
|
|
133
|
-
target,
|
|
134
|
-
})
|
|
198
|
+
edges.push({ from: nodeId, fromKey: nodeId, fromLogical: nodeId, target })
|
|
135
199
|
}
|
|
136
200
|
}
|
|
137
201
|
|
|
138
|
-
const toFire:
|
|
139
|
-
|
|
140
|
-
instanceKey: string
|
|
141
|
-
fromStepName?: string
|
|
142
|
-
}> = []
|
|
202
|
+
const toFire: GraphFireInstruction[] = []
|
|
203
|
+
const plannedFanout = new Set<string>()
|
|
143
204
|
let blockedWaiting = false
|
|
144
205
|
for (const edge of edges) {
|
|
145
206
|
const target = edge.target
|
|
146
207
|
const edgeKey = `${edge.fromKey}->${target}`
|
|
208
|
+
|
|
209
|
+
if (isFanned(target)) {
|
|
210
|
+
if (plannedFanout.has(target)) continue
|
|
211
|
+
plannedFanout.add(target)
|
|
212
|
+
if (!areDependenciesSatisfied(nodes[target] ?? {}, completedLogical)) {
|
|
213
|
+
blockedWaiting = true
|
|
214
|
+
continue
|
|
215
|
+
}
|
|
216
|
+
const width = fanoutWidths[target]
|
|
217
|
+
if (width === undefined) {
|
|
218
|
+
blockedWaiting = true
|
|
219
|
+
continue
|
|
220
|
+
}
|
|
221
|
+
const existing = instancesByLogical[target] ?? []
|
|
222
|
+
const existingIndexes = new Set(
|
|
223
|
+
existing
|
|
224
|
+
.map((i) => splitFanoutInstance(i.stepName)?.index)
|
|
225
|
+
.filter((index): index is number => index !== undefined)
|
|
226
|
+
)
|
|
227
|
+
const pending: number[] = []
|
|
228
|
+
for (let index = 0; index < width; index++) {
|
|
229
|
+
if (!existingIndexes.has(index)) pending.push(index)
|
|
230
|
+
}
|
|
231
|
+
if (pending.length === 0) continue
|
|
232
|
+
const sequential = nodes[target]?.mode === 'sequential'
|
|
233
|
+
const anyInFlight = existing.some((i) => i.status !== 'succeeded')
|
|
234
|
+
const emit = sequential
|
|
235
|
+
? anyInFlight
|
|
236
|
+
? []
|
|
237
|
+
: pending.slice(0, 1)
|
|
238
|
+
: pending
|
|
239
|
+
for (const index of emit) {
|
|
240
|
+
toFire.push({
|
|
241
|
+
logical: target,
|
|
242
|
+
instanceKey: fanoutInstanceKey(target, index),
|
|
243
|
+
fromStepName: edge.from,
|
|
244
|
+
itemIndex: index,
|
|
245
|
+
})
|
|
246
|
+
}
|
|
247
|
+
if (emit.length === 0) blockedWaiting = true
|
|
248
|
+
continue
|
|
249
|
+
}
|
|
250
|
+
|
|
147
251
|
if (consumed.has(edgeKey)) continue
|
|
148
252
|
const visits = countByLogical[target] ?? 0
|
|
149
253
|
const isBackEdge =
|
|
@@ -298,7 +402,7 @@ function resolveTemplate(
|
|
|
298
402
|
|
|
299
403
|
function resolveValue(value: unknown, nodeResults: Record<string, any>): any {
|
|
300
404
|
if (isDataRef(value)) {
|
|
301
|
-
if (value.$ref === '$item') {
|
|
405
|
+
if (value.$ref === '$item' && !('$item' in nodeResults)) {
|
|
302
406
|
return value
|
|
303
407
|
}
|
|
304
408
|
const source = nodeResults[value.$ref]
|
|
@@ -364,6 +468,8 @@ function extractReferencedNodeIds(
|
|
|
364
468
|
|
|
365
469
|
const IGNORED_REFS = new Set(['trigger', '$item', 'unknown'])
|
|
366
470
|
|
|
471
|
+
const FOREACH_MODES = new Set(['parallel', 'sequential'])
|
|
472
|
+
|
|
367
473
|
function normalizeNodeTargets(value: unknown): string[] {
|
|
368
474
|
if (!value) return []
|
|
369
475
|
if (typeof value === 'string') return [value]
|
|
@@ -407,6 +513,29 @@ function validateGraphReferences(
|
|
|
407
513
|
}
|
|
408
514
|
}
|
|
409
515
|
|
|
516
|
+
if (node.forEach !== undefined) {
|
|
517
|
+
const source = forEachSource(node)
|
|
518
|
+
if (!source) {
|
|
519
|
+
throw new Error(
|
|
520
|
+
`Workflow graph '${graphName}': node '${nodeId}' forEach must reference a node`
|
|
521
|
+
)
|
|
522
|
+
}
|
|
523
|
+
if (!IGNORED_REFS.has(source.$ref) && !nodeIds.has(source.$ref)) {
|
|
524
|
+
throw new Error(
|
|
525
|
+
`Workflow graph '${graphName}': node '${nodeId}' references unknown node '${source.$ref}' in forEach`
|
|
526
|
+
)
|
|
527
|
+
}
|
|
528
|
+
if (node.mode !== undefined && !FOREACH_MODES.has(node.mode)) {
|
|
529
|
+
throw new Error(
|
|
530
|
+
`Workflow graph '${graphName}': node '${nodeId}' has an unknown forEach mode '${node.mode}'`
|
|
531
|
+
)
|
|
532
|
+
}
|
|
533
|
+
} else if (node.mode !== undefined) {
|
|
534
|
+
throw new Error(
|
|
535
|
+
`Workflow graph '${graphName}': node '${nodeId}' sets mode '${node.mode}' without a forEach`
|
|
536
|
+
)
|
|
537
|
+
}
|
|
538
|
+
|
|
410
539
|
const nextTargets = normalizeNodeTargets(node.next)
|
|
411
540
|
for (const nextId of nextTargets) {
|
|
412
541
|
if (!nodeIds.has(nextId)) {
|
|
@@ -427,14 +556,145 @@ function validateGraphReferences(
|
|
|
427
556
|
}
|
|
428
557
|
}
|
|
429
558
|
|
|
559
|
+
function forEachSource(node: {
|
|
560
|
+
forEach?: unknown
|
|
561
|
+
}): { $ref: string; path?: string } | undefined {
|
|
562
|
+
return isDataRef(node.forEach) ? node.forEach : undefined
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
function nodeDependencies(node: {
|
|
566
|
+
input?: Record<string, unknown>
|
|
567
|
+
forEach?: unknown
|
|
568
|
+
}): string[] {
|
|
569
|
+
const deps = extractReferencedNodeIds(node.input)
|
|
570
|
+
const source = forEachSource(node)
|
|
571
|
+
if (source) deps.push(source.$ref)
|
|
572
|
+
return [...new Set(deps)].filter((id) => !IGNORED_REFS.has(id))
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
function describeValue(value: unknown): string {
|
|
576
|
+
if (value === null) return 'null'
|
|
577
|
+
if (value === undefined) return 'undefined'
|
|
578
|
+
return typeof value
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
function resolveForEachItems(
|
|
582
|
+
graphName: string,
|
|
583
|
+
nodeId: string,
|
|
584
|
+
node: { forEach?: unknown },
|
|
585
|
+
nodeResults: Record<string, any>
|
|
586
|
+
): unknown[] {
|
|
587
|
+
const source = forEachSource(node)
|
|
588
|
+
if (!source) {
|
|
589
|
+
throw new Error(
|
|
590
|
+
`Workflow graph '${graphName}': node '${nodeId}' has an unusable forEach configuration`
|
|
591
|
+
)
|
|
592
|
+
}
|
|
593
|
+
const raw = nodeResults[source.$ref]
|
|
594
|
+
const value = source.path ? getValueAtPath(raw, source.path) : raw
|
|
595
|
+
if (!Array.isArray(value)) {
|
|
596
|
+
const label = source.path ? `${source.$ref}.${source.path}` : source.$ref
|
|
597
|
+
throw new Error(
|
|
598
|
+
`Workflow graph '${graphName}': node '${nodeId}' forEach source '${label}' resolved to ${describeValue(
|
|
599
|
+
value
|
|
600
|
+
)}, expected an array`
|
|
601
|
+
)
|
|
602
|
+
}
|
|
603
|
+
return value
|
|
604
|
+
}
|
|
605
|
+
|
|
430
606
|
function areDependenciesSatisfied(
|
|
431
|
-
node: { input?: Record<string, unknown
|
|
607
|
+
node: { input?: Record<string, unknown>; forEach?: unknown },
|
|
432
608
|
completedNodeIds: Set<string>
|
|
433
609
|
): boolean {
|
|
434
|
-
|
|
435
|
-
|
|
610
|
+
return nodeDependencies(node).every((dep) => completedNodeIds.has(dep))
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
interface GraphResultReader {
|
|
614
|
+
/** Per-item source arrays, keyed by fanned node id, for every ready fanout. */
|
|
615
|
+
fanoutItems: Record<string, unknown[]>
|
|
616
|
+
fanoutWidths: Record<string, number>
|
|
617
|
+
/** Reads node results, aggregating a fanned node into its ordered item array. */
|
|
618
|
+
read: (nodeIds: string[]) => Promise<Record<string, any>>
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
async function createGraphResultReader(
|
|
622
|
+
workflowService: PikkuWorkflowService,
|
|
623
|
+
runId: string,
|
|
624
|
+
graphName: string,
|
|
625
|
+
nodes: Record<string, any>,
|
|
626
|
+
triggerInput: any,
|
|
627
|
+
instances: Array<{ stepName: string; status: string }>
|
|
628
|
+
): Promise<GraphResultReader> {
|
|
629
|
+
const succeeded = new Set(
|
|
630
|
+
instances.filter((i) => i.status === 'succeeded').map((i) => i.stepName)
|
|
436
631
|
)
|
|
437
|
-
|
|
632
|
+
const fanoutItems: Record<string, unknown[]> = {}
|
|
633
|
+
const fanoutWidths: Record<string, number> = {}
|
|
634
|
+
const resultCache = new Map<string, any>()
|
|
635
|
+
const resolving = new Set<string>()
|
|
636
|
+
|
|
637
|
+
const readResult = async (nodeId: string): Promise<any> => {
|
|
638
|
+
if (nodeId === 'trigger') return triggerInput
|
|
639
|
+
if (resultCache.has(nodeId)) return resultCache.get(nodeId)
|
|
640
|
+
if (resolving.has(nodeId)) return undefined
|
|
641
|
+
resolving.add(nodeId)
|
|
642
|
+
try {
|
|
643
|
+
let value: any
|
|
644
|
+
if (nodes[nodeId]?.forEach) {
|
|
645
|
+
const items = await readFanoutItems(nodeId)
|
|
646
|
+
if (items === undefined) return undefined
|
|
647
|
+
const keys = items.map((_, index) => fanoutInstanceKey(nodeId, index))
|
|
648
|
+
if (keys.some((key) => !succeeded.has(key))) return undefined
|
|
649
|
+
const fetched = keys.length
|
|
650
|
+
? await workflowService.getNodeResults(runId, keys)
|
|
651
|
+
: {}
|
|
652
|
+
value = keys.map((key) => fetched[key])
|
|
653
|
+
} else {
|
|
654
|
+
if (!succeeded.has(nodeId)) return undefined
|
|
655
|
+
const fetched = await workflowService.getNodeResults(runId, [nodeId])
|
|
656
|
+
value = fetched[nodeId]
|
|
657
|
+
}
|
|
658
|
+
resultCache.set(nodeId, value)
|
|
659
|
+
return value
|
|
660
|
+
} finally {
|
|
661
|
+
resolving.delete(nodeId)
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
const readFanoutItems = async (
|
|
666
|
+
nodeId: string
|
|
667
|
+
): Promise<unknown[] | undefined> => {
|
|
668
|
+
if (fanoutItems[nodeId]) return fanoutItems[nodeId]
|
|
669
|
+
const node = nodes[nodeId]
|
|
670
|
+
const source = forEachSource(node)
|
|
671
|
+
if (!source) return undefined
|
|
672
|
+
const sourceValue = await readResult(source.$ref)
|
|
673
|
+
if (sourceValue === undefined) return undefined
|
|
674
|
+
const items = resolveForEachItems(graphName, nodeId, node, {
|
|
675
|
+
[source.$ref]: sourceValue,
|
|
676
|
+
})
|
|
677
|
+
fanoutItems[nodeId] = items
|
|
678
|
+
fanoutWidths[nodeId] = items.length
|
|
679
|
+
return items
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
for (const nodeId of Object.keys(nodes)) {
|
|
683
|
+
if (nodes[nodeId]?.forEach) await readFanoutItems(nodeId)
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
return {
|
|
687
|
+
fanoutItems,
|
|
688
|
+
fanoutWidths,
|
|
689
|
+
read: async (nodeIds: string[]) => {
|
|
690
|
+
const results: Record<string, any> = {}
|
|
691
|
+
for (const nodeId of nodeIds) {
|
|
692
|
+
const value = await readResult(nodeId)
|
|
693
|
+
if (value !== undefined) results[nodeId] = value
|
|
694
|
+
}
|
|
695
|
+
return results
|
|
696
|
+
},
|
|
697
|
+
}
|
|
438
698
|
}
|
|
439
699
|
|
|
440
700
|
async function queueGraphNode(
|
|
@@ -508,12 +768,22 @@ export async function continueGraph(
|
|
|
508
768
|
}
|
|
509
769
|
|
|
510
770
|
const instances = await workflowService.getStepInstances(runId)
|
|
771
|
+
const triggerInput = currentRun?.input
|
|
772
|
+
const reader = await createGraphResultReader(
|
|
773
|
+
workflowService,
|
|
774
|
+
runId,
|
|
775
|
+
graphName,
|
|
776
|
+
nodes,
|
|
777
|
+
triggerInput,
|
|
778
|
+
instances
|
|
779
|
+
)
|
|
511
780
|
const plan = planGraphTransitions(
|
|
512
781
|
nodes,
|
|
513
782
|
instances,
|
|
514
783
|
branchByStep,
|
|
515
784
|
meta.entryNodeIds ?? [],
|
|
516
|
-
graphName
|
|
785
|
+
graphName,
|
|
786
|
+
reader.fanoutWidths
|
|
517
787
|
)
|
|
518
788
|
|
|
519
789
|
if (plan.toFire.length === 0) {
|
|
@@ -523,8 +793,6 @@ export async function continueGraph(
|
|
|
523
793
|
return
|
|
524
794
|
}
|
|
525
795
|
|
|
526
|
-
const triggerInput = currentRun?.input
|
|
527
|
-
|
|
528
796
|
for (const fire of plan.toFire) {
|
|
529
797
|
const node = nodes[fire.logical]
|
|
530
798
|
if (!node?.rpcName) continue
|
|
@@ -532,11 +800,14 @@ export async function continueGraph(
|
|
|
532
800
|
const referencedNodeIds = extractReferencedNodeIds(node.input).filter(
|
|
533
801
|
(id) => !IGNORED_REFS.has(id)
|
|
534
802
|
)
|
|
535
|
-
const fetchedResults = await
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
803
|
+
const fetchedResults = await reader.read(referencedNodeIds)
|
|
804
|
+
const nodeResults: Record<string, any> = {
|
|
805
|
+
trigger: triggerInput,
|
|
806
|
+
...fetchedResults,
|
|
807
|
+
}
|
|
808
|
+
if (fire.itemIndex !== undefined) {
|
|
809
|
+
nodeResults['$item'] = reader.fanoutItems[fire.logical]?.[fire.itemIndex]
|
|
810
|
+
}
|
|
540
811
|
const resolvedInput = resolveSerializedInput(node.input, nodeResults)
|
|
541
812
|
|
|
542
813
|
await queueGraphNode(
|
|
@@ -855,12 +1126,21 @@ async function continueGraphInline(
|
|
|
855
1126
|
}
|
|
856
1127
|
|
|
857
1128
|
const instances = await workflowService.getStepInstances(runId)
|
|
1129
|
+
const reader = await createGraphResultReader(
|
|
1130
|
+
workflowService,
|
|
1131
|
+
runId,
|
|
1132
|
+
graphName,
|
|
1133
|
+
nodes,
|
|
1134
|
+
triggerInput,
|
|
1135
|
+
instances
|
|
1136
|
+
)
|
|
858
1137
|
const plan = planGraphTransitions(
|
|
859
1138
|
nodes,
|
|
860
1139
|
instances,
|
|
861
1140
|
branchByStep,
|
|
862
1141
|
entryNodeIds,
|
|
863
|
-
graphName
|
|
1142
|
+
graphName,
|
|
1143
|
+
reader.fanoutWidths
|
|
864
1144
|
)
|
|
865
1145
|
|
|
866
1146
|
if (plan.toFire.length === 0) {
|
|
@@ -879,11 +1159,15 @@ async function continueGraphInline(
|
|
|
879
1159
|
const referencedNodeIds = extractReferencedNodeIds(node.input).filter(
|
|
880
1160
|
(id) => !IGNORED_REFS.has(id)
|
|
881
1161
|
)
|
|
882
|
-
const fetchedResults = await
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
1162
|
+
const fetchedResults = await reader.read(referencedNodeIds)
|
|
1163
|
+
const nodeResults: Record<string, any> = {
|
|
1164
|
+
trigger: triggerInput,
|
|
1165
|
+
...fetchedResults,
|
|
1166
|
+
}
|
|
1167
|
+
if (fire.itemIndex !== undefined) {
|
|
1168
|
+
nodeResults['$item'] =
|
|
1169
|
+
reader.fanoutItems[fire.logical]?.[fire.itemIndex]
|
|
1170
|
+
}
|
|
887
1171
|
const resolvedInput = resolveSerializedInput(node.input, nodeResults)
|
|
888
1172
|
|
|
889
1173
|
executed++
|
|
@@ -904,6 +1188,36 @@ async function continueGraphInline(
|
|
|
904
1188
|
}
|
|
905
1189
|
}
|
|
906
1190
|
|
|
1191
|
+
function planEntryFirings(
|
|
1192
|
+
graphName: string,
|
|
1193
|
+
nodeId: string,
|
|
1194
|
+
node: Record<string, any>,
|
|
1195
|
+
triggerNodeResults: Record<string, any>,
|
|
1196
|
+
triggerInput: any
|
|
1197
|
+
): Array<{ instanceKey: string; input: any }> {
|
|
1198
|
+
if (!node.forEach) {
|
|
1199
|
+
const input =
|
|
1200
|
+
node.input && Object.keys(node.input).length > 0
|
|
1201
|
+
? resolveSerializedInput(node.input, triggerNodeResults)
|
|
1202
|
+
: triggerInput
|
|
1203
|
+
return [{ instanceKey: nodeId, input }]
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1206
|
+
const items = resolveForEachItems(graphName, nodeId, node, triggerNodeResults)
|
|
1207
|
+
const width = node.mode === 'sequential' ? Math.min(items.length, 1) : items.length
|
|
1208
|
+
const firings: Array<{ instanceKey: string; input: any }> = []
|
|
1209
|
+
for (let index = 0; index < width; index++) {
|
|
1210
|
+
firings.push({
|
|
1211
|
+
instanceKey: fanoutInstanceKey(nodeId, index),
|
|
1212
|
+
input: resolveSerializedInput(node.input, {
|
|
1213
|
+
...triggerNodeResults,
|
|
1214
|
+
$item: items[index],
|
|
1215
|
+
}),
|
|
1216
|
+
})
|
|
1217
|
+
}
|
|
1218
|
+
return firings
|
|
1219
|
+
}
|
|
1220
|
+
|
|
907
1221
|
export async function runWorkflowGraph(
|
|
908
1222
|
workflowService: PikkuWorkflowService,
|
|
909
1223
|
graphName: string,
|
|
@@ -977,20 +1291,27 @@ export async function runWorkflowGraph(
|
|
|
977
1291
|
const node = nodes[nodeId]
|
|
978
1292
|
if (!node?.rpcName) return
|
|
979
1293
|
|
|
980
|
-
const
|
|
981
|
-
node.input && Object.keys(node.input).length > 0
|
|
982
|
-
? resolveSerializedInput(node.input, triggerNodeResults)
|
|
983
|
-
: triggerInput
|
|
984
|
-
|
|
985
|
-
await executeGraphNodeInline(
|
|
986
|
-
workflowService,
|
|
987
|
-
rpcService,
|
|
988
|
-
runId,
|
|
1294
|
+
const firings = planEntryFirings(
|
|
989
1295
|
graphName,
|
|
990
1296
|
nodeId,
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
1297
|
+
node,
|
|
1298
|
+
triggerNodeResults,
|
|
1299
|
+
triggerInput
|
|
1300
|
+
)
|
|
1301
|
+
|
|
1302
|
+
await Promise.all(
|
|
1303
|
+
firings.map((firing) =>
|
|
1304
|
+
executeGraphNodeInline(
|
|
1305
|
+
workflowService,
|
|
1306
|
+
rpcService,
|
|
1307
|
+
runId,
|
|
1308
|
+
graphName,
|
|
1309
|
+
nodeId,
|
|
1310
|
+
firing.instanceKey,
|
|
1311
|
+
firing.input,
|
|
1312
|
+
nodes
|
|
1313
|
+
)
|
|
1314
|
+
)
|
|
994
1315
|
)
|
|
995
1316
|
})
|
|
996
1317
|
)
|
|
@@ -1026,20 +1347,25 @@ export async function runWorkflowGraph(
|
|
|
1026
1347
|
const node = nodes[nodeId]
|
|
1027
1348
|
if (!node?.rpcName) continue
|
|
1028
1349
|
|
|
1029
|
-
const
|
|
1030
|
-
node.input && Object.keys(node.input).length > 0
|
|
1031
|
-
? resolveSerializedInput(node.input, triggerNodeResults)
|
|
1032
|
-
: triggerInput
|
|
1033
|
-
|
|
1034
|
-
await queueGraphNode(
|
|
1035
|
-
workflowService,
|
|
1036
|
-
runId,
|
|
1350
|
+
const firings = planEntryFirings(
|
|
1037
1351
|
graphName,
|
|
1038
1352
|
nodeId,
|
|
1039
|
-
node
|
|
1040
|
-
|
|
1041
|
-
|
|
1353
|
+
node,
|
|
1354
|
+
triggerNodeResults,
|
|
1355
|
+
triggerInput
|
|
1042
1356
|
)
|
|
1357
|
+
|
|
1358
|
+
for (const firing of firings) {
|
|
1359
|
+
await queueGraphNode(
|
|
1360
|
+
workflowService,
|
|
1361
|
+
runId,
|
|
1362
|
+
graphName,
|
|
1363
|
+
firing.instanceKey,
|
|
1364
|
+
node.rpcName,
|
|
1365
|
+
firing.input,
|
|
1366
|
+
node
|
|
1367
|
+
)
|
|
1368
|
+
}
|
|
1043
1369
|
}
|
|
1044
1370
|
if (inline) {
|
|
1045
1371
|
workflowService.unregisterInlineRun(runId)
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { TemplateString } from './template.js'
|
|
2
|
+
|
|
1
3
|
export interface RefValue {
|
|
2
4
|
__isRef: true
|
|
3
5
|
nodeId: string
|
|
@@ -22,13 +24,36 @@ export type RefFn<NodeIds extends string = string> = (
|
|
|
22
24
|
) => RefValue
|
|
23
25
|
|
|
24
26
|
export type NextConfig<NodeIds extends string = string> =
|
|
27
|
+
NodeIds | NodeIds[] | Record<string, NodeIds | NodeIds[]>
|
|
28
|
+
|
|
29
|
+
export type TemplateFn = (
|
|
30
|
+
templateStr: string,
|
|
31
|
+
refs: Array<{ $ref: string; path?: string }>
|
|
32
|
+
) => TemplateString
|
|
33
|
+
|
|
34
|
+
export type ItemFn = (path?: string) => RefValue
|
|
35
|
+
|
|
36
|
+
export type ForEachConfig<NodeIds extends string = string> =
|
|
25
37
|
| NodeIds
|
|
26
|
-
|
|
|
27
|
-
|
|
|
38
|
+
| RefValue
|
|
39
|
+
| ((ref: RefFn<NodeIds>) => RefValue)
|
|
40
|
+
|
|
41
|
+
export type ForEachMode = 'parallel' | 'sequential'
|
|
28
42
|
|
|
29
43
|
export interface GraphNodeConfig<NodeIds extends string = string> {
|
|
30
44
|
func: string
|
|
31
|
-
|
|
45
|
+
/**
|
|
46
|
+
* Run this node once per element of an upstream array. The node's own result
|
|
47
|
+
* becomes the ordered array of per-item results.
|
|
48
|
+
*/
|
|
49
|
+
forEach?: ForEachConfig<NodeIds>
|
|
50
|
+
/** How the per-item instances of a `forEach` node run. Defaults to 'parallel'. */
|
|
51
|
+
mode?: ForEachMode
|
|
52
|
+
input?: (
|
|
53
|
+
ref: RefFn<NodeIds>,
|
|
54
|
+
template: TemplateFn,
|
|
55
|
+
$item: ItemFn
|
|
56
|
+
) => Record<string, unknown>
|
|
32
57
|
next?: NextConfig<NodeIds>
|
|
33
58
|
onError?: NodeIds | NodeIds[]
|
|
34
59
|
retries?: number
|
|
@@ -93,3 +93,11 @@ export type {
|
|
|
93
93
|
WorkflowStepWire,
|
|
94
94
|
PikkuWorkflowWire,
|
|
95
95
|
} from './workflow.types.js'
|
|
96
|
+
export { createGraph } from './graph/graph-node.js'
|
|
97
|
+
export type {
|
|
98
|
+
GraphNodeConfig,
|
|
99
|
+
ForEachConfig,
|
|
100
|
+
ForEachMode,
|
|
101
|
+
ItemFn,
|
|
102
|
+
TemplateFn,
|
|
103
|
+
} from './graph/workflow-graph.types.js'
|