@pikku/core 0.12.79 → 0.12.82
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 +473 -0
- package/dist/dev/hot-reload.js +1 -6
- package/dist/ecosystem.d.ts +27 -0
- package/dist/ecosystem.js +26 -0
- package/dist/errors/error-handler.js +4 -2
- package/dist/errors/index.d.ts +1 -1
- package/dist/errors/index.js +1 -1
- package/dist/function/function-runner.js +22 -47
- package/dist/function/functions.types.d.ts +9 -5
- package/dist/function/index.d.ts +1 -1
- package/dist/index.d.ts +14 -19
- package/dist/index.js +6 -11
- package/dist/middleware/auth-cookie.d.ts +0 -4
- package/dist/middleware/auth-cookie.js +38 -2
- package/dist/middleware/cors.js +1 -0
- package/dist/middleware/index.d.ts +1 -1
- package/dist/middleware/index.js +1 -1
- package/dist/middleware/remote-auth.js +14 -3
- package/dist/permissions.d.ts +8 -10
- package/dist/permissions.js +0 -11
- package/dist/pikku-state.js +16 -5
- package/dist/schema.js +35 -1
- package/dist/services/ai-agent-runner-service.d.ts +7 -0
- package/dist/services/ai-run-state-service.d.ts +17 -1
- package/dist/services/in-memory-ai-run-state-service.d.ts +6 -2
- package/dist/services/in-memory-ai-run-state-service.js +11 -1
- package/dist/services/in-memory-workflow-service.js +2 -0
- package/dist/services/index.d.ts +15 -15
- package/dist/services/index.js +5 -5
- package/dist/services/local-content-request-handler.d.ts +21 -0
- package/dist/services/local-content-request-handler.js +72 -53
- package/dist/services/local-content.d.ts +6 -0
- package/dist/services/local-content.js +14 -1
- package/dist/services/scoped-credential-service.d.ts +21 -0
- package/dist/services/scoped-credential-service.js +53 -0
- package/dist/services/workflow-service.d.ts +4 -2
- package/dist/testing/service-tests/agent-run-service-tests.d.ts +10 -0
- package/dist/testing/service-tests/agent-run-service-tests.js +72 -0
- package/dist/testing/service-tests/ai-storage-service-tests.d.ts +3 -0
- package/dist/testing/service-tests/ai-storage-service-tests.js +302 -0
- package/dist/testing/service-tests/channel-store-tests.d.ts +3 -0
- package/dist/testing/service-tests/channel-store-tests.js +72 -0
- package/dist/testing/service-tests/credential-service-tests.d.ts +3 -0
- package/dist/testing/service-tests/credential-service-tests.js +109 -0
- package/dist/testing/service-tests/deployment-service-tests.d.ts +3 -0
- package/dist/testing/service-tests/deployment-service-tests.js +21 -0
- package/dist/testing/service-tests/event-hub-store-tests.d.ts +3 -0
- package/dist/testing/service-tests/event-hub-store-tests.js +34 -0
- package/dist/testing/service-tests/secret-service-tests.d.ts +3 -0
- package/dist/testing/service-tests/secret-service-tests.js +80 -0
- package/dist/testing/service-tests/session-store-tests.d.ts +3 -0
- package/dist/testing/service-tests/session-store-tests.js +43 -0
- package/dist/testing/service-tests/workflow-run-service-tests.d.ts +3 -0
- package/dist/testing/service-tests/workflow-run-service-tests.js +42 -0
- package/dist/testing/service-tests/workflow-service-tests.d.ts +3 -0
- package/dist/testing/service-tests/workflow-service-tests.js +150 -0
- package/dist/testing/service-tests.d.ts +6 -0
- package/dist/testing/service-tests.js +26 -791
- package/dist/types/core.types.d.ts +11 -3
- package/dist/types/state.types.d.ts +14 -1
- package/dist/wirings/actor-flow/index.d.ts +1 -1
- package/dist/wirings/actor-flow/run-conversation.js +1 -6
- package/dist/wirings/ai-agent/agent-rpc.d.ts +15 -0
- package/dist/wirings/ai-agent/agent-rpc.js +53 -0
- package/dist/wirings/ai-agent/ai-agent-agui.js +1 -5
- package/dist/wirings/ai-agent/ai-agent-finalize.d.ts +58 -0
- package/dist/wirings/ai-agent/ai-agent-finalize.js +138 -0
- package/dist/wirings/ai-agent/ai-agent-interrupt.js +1 -0
- package/dist/wirings/ai-agent/ai-agent-memory.d.ts +2 -8
- package/dist/wirings/ai-agent/ai-agent-memory.js +37 -18
- package/dist/wirings/ai-agent/ai-agent-model-config.d.ts +7 -0
- package/dist/wirings/ai-agent/ai-agent-model-config.js +44 -1
- package/dist/wirings/ai-agent/ai-agent-prepare.js +5 -9
- package/dist/wirings/ai-agent/ai-agent-runner.js +89 -147
- package/dist/wirings/ai-agent/ai-agent-stream.js +109 -97
- package/dist/wirings/ai-agent/ai-agent-turn.d.ts +57 -0
- package/dist/wirings/ai-agent/ai-agent-turn.js +82 -0
- package/dist/wirings/ai-agent/ai-agent.types.d.ts +47 -2
- package/dist/wirings/ai-agent/index.d.ts +8 -7
- package/dist/wirings/ai-agent/index.js +5 -4
- package/dist/wirings/ai-agent/voice-input.js +1 -6
- package/dist/wirings/ai-agent/voice-output.js +2 -12
- package/dist/wirings/ai-scorer/ai-scorer-grade.d.ts +26 -0
- package/dist/wirings/ai-scorer/ai-scorer-grade.js +33 -0
- package/dist/wirings/ai-scorer/ai-scorer-judge.d.ts +17 -0
- package/dist/wirings/ai-scorer/ai-scorer-judge.js +92 -0
- package/dist/wirings/ai-scorer/ai-scorer-live.d.ts +15 -0
- package/dist/wirings/ai-scorer/ai-scorer-live.js +38 -0
- package/dist/wirings/ai-scorer/ai-scorer-registry.d.ts +18 -0
- package/dist/wirings/ai-scorer/ai-scorer-registry.js +46 -0
- package/dist/wirings/ai-scorer/ai-scorer-sampling.d.ts +8 -0
- package/dist/wirings/ai-scorer/ai-scorer-sampling.js +31 -0
- package/dist/wirings/ai-scorer/ai-scorer-snapshots.d.ts +10 -0
- package/dist/wirings/ai-scorer/ai-scorer-snapshots.js +40 -0
- package/dist/wirings/ai-scorer/ai-scorer-worker.d.ts +15 -0
- package/dist/wirings/ai-scorer/ai-scorer-worker.js +58 -0
- package/dist/wirings/ai-scorer/ai-scorer.d.ts +39 -0
- package/dist/wirings/ai-scorer/ai-scorer.js +40 -0
- package/dist/wirings/ai-scorer/ai-scorer.types.d.ts +90 -0
- package/dist/wirings/ai-scorer/ai-scorer.types.js +4 -0
- package/dist/wirings/ai-scorer/index.d.ts +6 -0
- package/dist/wirings/ai-scorer/index.js +5 -0
- package/dist/wirings/channel/channel-common.js +1 -0
- package/dist/wirings/channel/channel-handler.js +3 -5
- package/dist/wirings/channel/channel-rpc-service.d.ts +0 -6
- package/dist/wirings/channel/channel-rpc-service.js +0 -8
- package/dist/wirings/channel/channel-rpc.types.d.ts +6 -0
- package/dist/wirings/channel/channel-rpc.types.js +8 -0
- package/dist/wirings/channel/channel-runner.d.ts +1 -3
- package/dist/wirings/channel/channel-runner.js +16 -8
- package/dist/wirings/channel/channel.types.d.ts +2 -0
- package/dist/wirings/channel/index.d.ts +5 -6
- package/dist/wirings/channel/index.js +3 -4
- package/dist/wirings/channel/local/local-channel-runner.js +8 -1
- package/dist/wirings/channel/pikku-abstract-channel-handler.js +1 -0
- package/dist/wirings/channel/serverless/serverless-channel-runner.js +3 -0
- package/dist/wirings/cli/channel/cli-channel-runner.js +2 -0
- package/dist/wirings/cli/channel/cli-raw-channel-runner.js +9 -1
- package/dist/wirings/cli/channel/index.d.ts +1 -2
- package/dist/wirings/cli/channel/index.js +0 -1
- package/dist/wirings/cli/cli-runner.js +17 -3
- package/dist/wirings/cli/cli.types.d.ts +0 -8
- package/dist/wirings/cli/command-parser.js +13 -0
- package/dist/wirings/credential/index.d.ts +1 -1
- package/dist/wirings/gateway/gateway-runner.js +9 -2
- package/dist/wirings/gateway/index.d.ts +1 -1
- package/dist/wirings/http/http-routes.js +2 -0
- package/dist/wirings/http/http-runner.d.ts +0 -10
- package/dist/wirings/http/http-runner.js +14 -15
- package/dist/wirings/http/http.types.d.ts +0 -10
- package/dist/wirings/http/index.d.ts +2 -3
- package/dist/wirings/http/index.js +1 -1
- package/dist/wirings/mcp/index.d.ts +1 -1
- package/dist/wirings/mcp/mcp-runner.d.ts +15 -7
- package/dist/wirings/mcp/mcp-runner.js +18 -11
- package/dist/wirings/persona/index.d.ts +3 -4
- package/dist/wirings/persona/index.js +2 -3
- package/dist/wirings/queue/index.d.ts +1 -3
- package/dist/wirings/queue/index.js +1 -3
- package/dist/wirings/rpc/addon-runner.d.ts +4 -0
- package/dist/wirings/rpc/addon-runner.js +19 -3
- package/dist/wirings/rpc/rpc-runner.d.ts +8 -51
- package/dist/wirings/rpc/rpc-runner.js +55 -86
- package/dist/wirings/rpc/rpc-types.d.ts +7 -0
- package/dist/wirings/rpc/wire-addon.d.ts +13 -0
- package/dist/wirings/rpc/wire-addon.js +4 -0
- package/dist/wirings/scheduler/index.d.ts +1 -1
- package/dist/wirings/secret/validate-secret-definitions.js +2 -2
- package/dist/wirings/trigger/index.d.ts +1 -1
- package/dist/wirings/trigger/pikku-trigger-service.d.ts +0 -4
- package/dist/wirings/trigger/trigger-runner.js +1 -0
- package/dist/wirings/virtual-user/index.d.ts +5 -6
- package/dist/wirings/virtual-user/index.js +2 -4
- package/dist/wirings/virtual-user/run-virtual-user.js +11 -11
- package/dist/wirings/virtual-user/virtual-user-derive.js +4 -25
- package/dist/wirings/virtual-user/virtual-user-dispositions.js +1 -4
- package/dist/wirings/workflow/dsl/workflow-dsl.types.d.ts +100 -3
- package/dist/wirings/workflow/feature.js +7 -4
- package/dist/wirings/workflow/graph/graph-runner.d.ts +1 -2
- package/dist/wirings/workflow/graph/graph-runner.js +8 -7
- package/dist/wirings/workflow/graph/workflow-graph.types.d.ts +0 -4
- package/dist/wirings/workflow/index.d.ts +12 -7
- package/dist/wirings/workflow/index.js +7 -3
- package/dist/wirings/workflow/pikku-scenario-service.d.ts +17 -3
- package/dist/wirings/workflow/pikku-scenario-service.js +64 -10
- package/dist/wirings/workflow/pikku-workflow-service.d.ts +28 -147
- package/dist/wirings/workflow/pikku-workflow-service.js +85 -493
- package/dist/wirings/workflow/scenario-step.types.d.ts +8 -0
- package/dist/wirings/workflow/workflow-approval-audit.d.ts +16 -0
- package/dist/wirings/workflow/workflow-approval-audit.js +40 -0
- package/dist/wirings/workflow/workflow-approval-policy.d.ts +20 -0
- package/dist/wirings/workflow/workflow-approval-policy.js +48 -0
- package/dist/wirings/workflow/workflow-approval.d.ts +67 -0
- package/dist/wirings/workflow/workflow-approval.js +177 -0
- package/dist/wirings/workflow/workflow-constants.d.ts +26 -0
- package/dist/wirings/workflow/workflow-constants.js +35 -0
- package/dist/wirings/workflow/workflow-errors.d.ts +58 -0
- package/dist/wirings/workflow/workflow-errors.js +112 -0
- package/dist/wirings/workflow/workflow-meta-resolver.d.ts +11 -0
- package/dist/wirings/workflow/workflow-meta-resolver.js +31 -0
- package/dist/wirings/workflow/workflow-queue-routing.d.ts +8 -0
- package/dist/wirings/workflow/workflow-queue-routing.js +38 -0
- package/dist/wirings/workflow/workflow-queue-wiring.d.ts +20 -0
- package/dist/wirings/workflow/workflow-queue-wiring.js +79 -0
- package/dist/wirings/workflow/workflow-recovery.d.ts +68 -0
- package/dist/wirings/workflow/workflow-recovery.js +101 -0
- package/dist/wirings/workflow/workflow-run-engine.types.d.ts +54 -0
- package/dist/wirings/workflow/workflow-run-ownership.d.ts +17 -0
- package/dist/wirings/workflow/workflow-run-ownership.js +30 -0
- package/dist/wirings/workflow/workflow-suspend.d.ts +12 -0
- package/dist/wirings/workflow/workflow-suspend.js +33 -0
- package/dist/wirings/workflow/workflow.types.d.ts +8 -1
- package/knowledge/decisions/internals/a-non-streaming-agent-run-registers-with-airunstate-too.md +22 -0
- package/knowledge/decisions/internals/a-resumed-agent-turn-is-as-interruptible-as-the-first.md +20 -0
- package/knowledge/decisions/internals/a-scenario-step-template-is-offered-unfilled.md +21 -0
- package/knowledge/decisions/internals/a-virtual-user-decides-whether-to-trust-memory-once-per-turn.md +21 -0
- package/knowledge/decisions/internals/a-wall-clock-threshold-is-a-load-test-in-disguise.md +46 -0
- package/knowledge/decisions/internals/a-workflow-wire-is-built-from-the-run-not-from-the-rpc-service.md +45 -0
- package/knowledge/decisions/internals/addon-pikku-meta-ships-at-the-package-root-or-under-dist.md +32 -0
- package/knowledge/decisions/internals/agent-context-waits-for-a-tool-result-still-being-written.md +21 -0
- package/knowledge/decisions/internals/agent-speech-travels-as-a-custom-agui-event.md +22 -0
- package/knowledge/decisions/internals/an-addon-scope-root-loses-to-a-root-the-host-already-declares.md +39 -0
- package/knowledge/decisions/internals/an-agent-interrupt-is-not-a-failure.md +23 -0
- package/knowledge/decisions/internals/an-agent-run-owned-by-another-instance-says-so.md +25 -0
- package/knowledge/decisions/internals/an-agent-stream-send-must-return-the-inner-sends-promise.md +22 -0
- package/knowledge/decisions/internals/an-empty-text-part-is-omitted-from-an-agent-message.md +20 -0
- package/knowledge/decisions/internals/an-empty-transcript-is-not-recorded.md +22 -0
- package/knowledge/decisions/internals/an-unref-d-timer-cannot-be-awaited-under-node-test.md +66 -0
- package/knowledge/decisions/internals/channel-state-accessors-are-unsound-generics-that-every-implementation-asserts.md +33 -0
- package/knowledge/decisions/internals/gateway-listener-middleware-runs-without-an-rpc-on-the-wire.md +43 -0
- package/knowledge/decisions/internals/hot-reload-writes-into-the-function-map-captured-at-startup.md +26 -0
- package/knowledge/decisions/internals/index.md +42 -3
- package/knowledge/decisions/internals/only-exposed-functions-enter-a-virtual-user-catalogue.md +21 -0
- package/knowledge/decisions/internals/scenario-given-and-when-are-sugar-but-then-is-not.md +24 -0
- package/knowledge/decisions/internals/side-effects-are-an-allowlist-not-a-boolean.md +34 -0
- package/knowledge/decisions/internals/speech-synthesis-picks-a-voice-per-sentence-and-warns-once.md +24 -0
- package/knowledge/decisions/internals/the-actor-prompt-says-json-because-of-json-object-mode.md +22 -0
- package/knowledge/decisions/internals/the-agent-done-event-goes-through-the-middleware-and-is-awaited.md +26 -0
- package/knowledge/decisions/internals/the-api-report-pins-members-not-just-names.md +43 -0
- package/knowledge/decisions/internals/the-ecosystem-entry-point-carries-the-adapter-surface.md +58 -0
- package/knowledge/decisions/internals/the-middleware-resolution-cache-is-deliberately-unbounded.md +40 -0
- package/knowledge/decisions/internals/the-per-invocation-rpc-view-is-a-class.md +40 -0
- package/knowledge/decisions/internals/the-persona-runtime-is-exported-from-the-persona-entry-point.md +28 -0
- package/knowledge/decisions/internals/the-transcript-event-is-sent-ahead-of-the-run.md +25 -0
- package/knowledge/decisions/internals/the-virtual-user-catalogue-is-the-only-gate-on-what-may-be-called.md +21 -0
- package/knowledge/decisions/internals/the-worker-disposition-is-the-one-that-is-not-testing.md +22 -0
- package/knowledge/decisions/internals/thread-history-records-the-transcript-not-the-audio.md +25 -0
- package/knowledge/decisions/internals/validate-runs-checks-by-precondition.md +115 -0
- package/knowledge/decisions/internals/virtual-user-step-order-comes-from-insertion-order.md +21 -0
- package/knowledge/decisions/internals/voice-output-speaks-unless-voice-input-explicitly-says-otherwise.md +24 -0
- package/knowledge/decisions/internals/wiring-registries-erase-the-generics-their-wire-functions-capture.md +35 -0
- package/knowledge/decisions/security/a-dropped-audit-write-is-always-logged.md +4 -2
- package/knowledge/decisions/security/a-function-never-receives-the-secret-service.md +37 -0
- package/knowledge/decisions/security/a-graph-run-starts-at-an-entry-node-the-graph-declared.md +33 -0
- package/knowledge/decisions/security/a-permission-gets-a-wire-it-cannot-reply-on.md +33 -0
- package/knowledge/decisions/security/a-step-runs-the-function-the-workflow-dispatched-it-with.md +37 -0
- package/knowledge/decisions/security/a-virtual-user-is-never-offered-a-step-that-would-forge-its-own-oracle.md +28 -0
- package/knowledge/decisions/security/a-workflow-run-is-read-and-approved-by-its-owner.md +50 -0
- package/knowledge/decisions/security/an-agent-approval-is-claimed-before-the-tool-runs.md +33 -0
- package/knowledge/decisions/security/an-approval-answer-outlives-the-run-it-answered.md +59 -0
- package/knowledge/decisions/security/an-upload-is-counted-as-it-arrives-not-buffered-then-measured.md +24 -0
- package/knowledge/decisions/security/index.md +9 -0
- package/knowledge/questions/channel-middleware-accepts-bare-factories-that-nothing-resolves.md +35 -0
- package/knowledge/questions/index.md +2 -1
- package/knowledge/questions/unauthorized-channel-replies-escape-the-declared-out-type.md +44 -0
- package/package.json +15 -3
- package/scripts/generate-api-report.d.mts +1 -0
- package/scripts/generate-api-report.mjs +89 -0
- package/scripts/generate-api-report.mts +343 -0
- package/src/api-report.test.ts +69 -0
- package/src/column-form.ts +1 -4
- package/src/crypto-utils.test.ts +15 -2
- package/src/dev/hot-reload.ts +2 -7
- package/src/ecosystem.ts +40 -0
- package/src/errors/error-handler.ts +5 -3
- package/src/errors/error.test.ts +4 -1
- package/src/errors/index.ts +1 -1
- package/src/function/function-runner.test.ts +53 -1
- package/src/function/function-runner.ts +33 -48
- package/src/function/functions.types.ts +15 -9
- package/src/function/index.ts +0 -2
- package/src/handle-error.ts +1 -1
- package/src/index.ts +3 -57
- package/src/middleware/auth-cookie.test.ts +50 -0
- package/src/middleware/auth-cookie.ts +38 -2
- package/src/middleware/cors.ts +2 -1
- package/src/middleware/index.ts +1 -1
- package/src/middleware/remote-auth.test.ts +43 -0
- package/src/middleware/remote-auth.ts +17 -3
- package/src/middleware-runner.ts +4 -2
- package/src/no-any-casts.test.ts +57 -0
- package/src/permissions.test.ts +3 -1
- package/src/permissions.ts +22 -24
- package/src/pikku-state.ts +22 -6
- package/src/public-surface.json +554 -0
- package/src/public-surface.json.README +25 -0
- package/src/public-surface.test.ts +105 -0
- package/src/removed-legacy-exports.test.ts +62 -0
- package/src/schema.test.ts +78 -0
- package/src/schema.ts +36 -1
- package/src/services/ai-agent-runner-service.ts +12 -1
- package/src/services/ai-run-state-service.ts +18 -1
- package/src/services/audit-service.ts +2 -2
- package/src/services/in-memory-ai-run-state-service.ts +16 -2
- package/src/services/in-memory-workflow-service.ts +2 -0
- package/src/services/index.ts +4 -47
- package/src/services/local-content-request-handler.test.ts +43 -5
- package/src/services/local-content-request-handler.ts +103 -74
- package/src/services/local-content.ts +15 -1
- package/src/services/local-email-service.ts +5 -1
- package/src/services/scoped-credential-service.test.ts +86 -0
- package/src/services/scoped-credential-service.ts +63 -0
- package/src/services/system-role-guard.test.ts +4 -1
- package/src/services/workflow-service.ts +9 -2
- package/src/side-effects-are-declared.test.ts +84 -0
- package/src/source-files-stay-composable.test.ts +41 -0
- package/src/testing/service-tests/agent-run-service-tests.ts +98 -0
- package/src/testing/service-tests/ai-storage-service-tests.ts +379 -0
- package/src/testing/service-tests/channel-store-tests.ts +98 -0
- package/src/testing/service-tests/credential-service-tests.ts +143 -0
- package/src/testing/service-tests/deployment-service-tests.ts +33 -0
- package/src/testing/service-tests/event-hub-store-tests.ts +48 -0
- package/src/testing/service-tests/secret-service-tests.ts +105 -0
- package/src/testing/service-tests/session-store-tests.ts +62 -0
- package/src/testing/service-tests/workflow-run-service-tests.ts +59 -0
- package/src/testing/service-tests/workflow-service-tests.ts +308 -0
- package/src/testing/service-tests.ts +31 -1111
- package/src/types/core.types.ts +14 -3
- package/src/types/state.types.ts +17 -1
- package/src/wirings/actor-flow/index.ts +0 -3
- package/src/wirings/actor-flow/run-conversation.ts +1 -6
- package/src/wirings/ai-agent/agent-rpc.ts +120 -0
- package/src/wirings/ai-agent/ai-agent-agui.ts +1 -5
- package/src/wirings/ai-agent/ai-agent-finalize.test.ts +186 -0
- package/src/wirings/ai-agent/ai-agent-finalize.ts +197 -0
- package/src/wirings/ai-agent/ai-agent-interrupt.test.ts +2 -1
- package/src/wirings/ai-agent/ai-agent-interrupt.ts +1 -0
- package/src/wirings/ai-agent/ai-agent-memory.ts +62 -39
- package/src/wirings/ai-agent/ai-agent-model-config.test.ts +72 -3
- package/src/wirings/ai-agent/ai-agent-model-config.ts +49 -1
- package/src/wirings/ai-agent/ai-agent-prepare.ts +12 -12
- package/src/wirings/ai-agent/ai-agent-resume-authorization.test.ts +1 -0
- package/src/wirings/ai-agent/ai-agent-runner.test.ts +82 -2
- package/src/wirings/ai-agent/ai-agent-runner.ts +120 -160
- package/src/wirings/ai-agent/ai-agent-stream-output-hooks.test.ts +353 -0
- package/src/wirings/ai-agent/ai-agent-stream.test.ts +2 -0
- package/src/wirings/ai-agent/ai-agent-stream.ts +152 -117
- package/src/wirings/ai-agent/ai-agent-thread-ownership.test.ts +1 -1
- package/src/wirings/ai-agent/ai-agent-turn.test.ts +67 -0
- package/src/wirings/ai-agent/ai-agent-turn.ts +122 -0
- package/src/wirings/ai-agent/ai-agent.types.ts +65 -5
- package/src/wirings/ai-agent/index.ts +2 -16
- package/src/wirings/ai-agent/voice-input.ts +1 -6
- package/src/wirings/ai-agent/voice-output.ts +2 -12
- package/src/wirings/ai-scorer/ai-scorer-grade.test.ts +106 -0
- package/src/wirings/ai-scorer/ai-scorer-grade.ts +55 -0
- package/src/wirings/ai-scorer/ai-scorer-judge.test.ts +143 -0
- package/src/wirings/ai-scorer/ai-scorer-judge.ts +120 -0
- package/src/wirings/ai-scorer/ai-scorer-live.test.ts +174 -0
- package/src/wirings/ai-scorer/ai-scorer-live.ts +56 -0
- package/src/wirings/ai-scorer/ai-scorer-registry.ts +63 -0
- package/src/wirings/ai-scorer/ai-scorer-sampling.test.ts +34 -0
- package/src/wirings/ai-scorer/ai-scorer-sampling.ts +36 -0
- package/src/wirings/ai-scorer/ai-scorer-snapshots.test.ts +49 -0
- package/src/wirings/ai-scorer/ai-scorer-snapshots.ts +46 -0
- package/src/wirings/ai-scorer/ai-scorer-worker.test.ts +122 -0
- package/src/wirings/ai-scorer/ai-scorer-worker.ts +69 -0
- package/src/wirings/ai-scorer/ai-scorer.ts +76 -0
- package/src/wirings/ai-scorer/ai-scorer.types.ts +107 -0
- package/src/wirings/ai-scorer/index.ts +24 -0
- package/src/wirings/channel/channel-common.ts +5 -2
- package/src/wirings/channel/channel-handler-shapes.test.ts +72 -0
- package/src/wirings/channel/channel-handler.ts +7 -7
- package/src/wirings/channel/channel-rpc-service.ts +0 -14
- package/src/wirings/channel/channel-rpc.test.ts +25 -4
- package/src/wirings/channel/channel-rpc.types.ts +14 -0
- package/src/wirings/channel/channel-runner.ts +33 -20
- package/src/wirings/channel/channel.types.ts +2 -0
- package/src/wirings/channel/index.ts +1 -20
- package/src/wirings/channel/local/local-channel-runner.test.ts +68 -0
- package/src/wirings/channel/local/local-channel-runner.ts +9 -2
- package/src/wirings/channel/pikku-abstract-channel-handler.ts +2 -1
- package/src/wirings/channel/serverless/serverless-channel-runner.ts +6 -3
- package/src/wirings/cli/channel/cli-channel-runner.ts +3 -1
- package/src/wirings/cli/channel/cli-raw-channel-runner.test.ts +23 -0
- package/src/wirings/cli/channel/cli-raw-channel-runner.ts +12 -1
- package/src/wirings/cli/channel/cli-raw-client-runner.ts +4 -1
- package/src/wirings/cli/channel/index.ts +0 -7
- package/src/wirings/cli/cli-runner.test.ts +68 -0
- package/src/wirings/cli/cli-runner.ts +25 -5
- package/src/wirings/cli/cli.types.ts +0 -39
- package/src/wirings/cli/command-parser.test.ts +19 -0
- package/src/wirings/cli/command-parser.ts +17 -1
- package/src/wirings/credential/index.ts +0 -1
- package/src/wirings/gateway/gateway-channel-meta.test.ts +44 -0
- package/src/wirings/gateway/gateway-runner.ts +27 -19
- package/src/wirings/gateway/index.ts +0 -3
- package/src/wirings/http/http-routes.ts +4 -1
- package/src/wirings/http/http-runner.test.ts +66 -0
- package/src/wirings/http/http-runner.ts +21 -28
- package/src/wirings/http/http.types.ts +0 -15
- package/src/wirings/http/index.ts +2 -8
- package/src/wirings/http/pikku-fetch-http-request.ts +2 -2
- package/src/wirings/http/web-request.ts +1 -1
- package/src/wirings/mcp/index.ts +0 -1
- package/src/wirings/mcp/mcp-runner.test.ts +181 -0
- package/src/wirings/mcp/mcp-runner.ts +37 -21
- package/src/wirings/persona/index.ts +0 -8
- package/src/wirings/persona/persona-environments.test.ts +14 -3
- package/src/wirings/persona/persona.test.ts +13 -3
- package/src/wirings/persona/validate-personas.ts +5 -1
- package/src/wirings/queue/index.ts +0 -14
- package/src/wirings/queue/queue-runner.ts +1 -1
- package/src/wirings/rpc/addon-auth-tags.test.ts +1 -5
- package/src/wirings/rpc/addon-runner.ts +34 -3
- package/src/wirings/rpc/addon-secrets.test.ts +261 -0
- package/src/wirings/rpc/rpc-runner.test.ts +2 -0
- package/src/wirings/rpc/rpc-runner.ts +60 -136
- package/src/wirings/rpc/rpc-types.ts +11 -0
- package/src/wirings/rpc/wire-addon.ts +20 -1
- package/src/wirings/scheduler/index.ts +0 -1
- package/src/wirings/secret/validate-secret-definitions.test.ts +22 -0
- package/src/wirings/secret/validate-secret-definitions.ts +2 -2
- package/src/wirings/trigger/index.ts +0 -1
- package/src/wirings/trigger/pikku-trigger-service.ts +0 -5
- package/src/wirings/trigger/trigger-runner.ts +7 -5
- package/src/wirings/virtual-user/index.ts +0 -16
- package/src/wirings/virtual-user/run-virtual-user.test.ts +18 -9
- package/src/wirings/virtual-user/run-virtual-user.ts +28 -15
- package/src/wirings/virtual-user/virtual-user-agents.test.ts +4 -1
- package/src/wirings/virtual-user/virtual-user-derive.ts +4 -25
- package/src/wirings/virtual-user/virtual-user-dispositions.test.ts +7 -2
- package/src/wirings/virtual-user/virtual-user-dispositions.ts +1 -4
- package/src/wirings/virtual-user/virtual-user-intents.test.ts +13 -3
- package/src/wirings/workflow/dsl/workflow-dsl.types.ts +117 -4
- package/src/wirings/workflow/feature.ts +7 -4
- package/src/wirings/workflow/graph/graph-node.ts +1 -1
- package/src/wirings/workflow/graph/graph-runner.test.ts +76 -2
- package/src/wirings/workflow/graph/graph-runner.ts +13 -16
- package/src/wirings/workflow/graph/workflow-graph.types.ts +0 -5
- package/src/wirings/workflow/index.ts +14 -24
- package/src/wirings/workflow/pikku-scenario-service.ts +101 -27
- package/src/wirings/workflow/pikku-workflow-service.test.ts +15 -14
- package/src/wirings/workflow/pikku-workflow-service.ts +214 -743
- package/src/wirings/workflow/scenario-expectations.test.ts +75 -0
- package/src/wirings/workflow/scenario-hooks.test.ts +52 -0
- package/src/wirings/workflow/scenario-step.types.ts +8 -0
- package/src/wirings/workflow/workflow-approval-audit.ts +47 -0
- package/src/wirings/workflow/workflow-approval-policy.test.ts +524 -0
- package/src/wirings/workflow/workflow-approval-policy.ts +68 -0
- package/src/wirings/workflow/workflow-approval.ts +289 -0
- package/src/wirings/workflow/workflow-child-run-session.test.ts +89 -0
- package/src/wirings/workflow/workflow-constants.ts +47 -0
- package/src/wirings/workflow/workflow-dispatch-durability.test.ts +1 -1
- package/src/wirings/workflow/workflow-errors.ts +128 -0
- package/src/wirings/workflow/workflow-inline-authority.test.ts +12 -6
- package/src/wirings/workflow/workflow-meta-resolver.ts +45 -0
- package/src/wirings/workflow/workflow-missing-meta.test.ts +92 -0
- package/src/wirings/workflow/workflow-queue-routing.ts +85 -0
- package/src/wirings/workflow/workflow-queue-wiring.ts +149 -0
- package/src/wirings/workflow/workflow-recovery.ts +162 -0
- package/src/wirings/workflow/workflow-retry-policy.test.ts +1 -1
- package/src/wirings/workflow/workflow-run-authority.test.ts +212 -0
- package/src/wirings/workflow/workflow-run-engine.types.ts +91 -0
- package/src/wirings/workflow/workflow-run-ownership.ts +37 -0
- package/src/wirings/workflow/workflow-suspend.ts +61 -0
- package/src/wirings/workflow/workflow.types.ts +7 -9
- package/src/wirings-stay-decoupled.test.ts +127 -0
- package/tsconfig.json +1 -1
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/internal.d.ts +0 -3
- package/dist/internal.js +0 -2
- package/dist/middleware/timeout.d.ts +0 -9
- package/dist/middleware/timeout.js +0 -15
- package/dist/pikku-response.d.ts +0 -6
- package/dist/pikku-response.js +0 -6
- package/dist/services/gopass-secrets.d.ts +0 -15
- package/dist/services/gopass-secrets.js +0 -76
- package/dist/services/http-scenario-actors.d.ts +0 -75
- package/dist/services/http-scenario-actors.js +0 -195
- package/dist/services/http-user-flow-actors.d.ts +0 -67
- package/dist/services/http-user-flow-actors.js +0 -193
- package/dist/services/scenario-actors-service.d.ts +0 -127
- package/dist/services/scenario-actors-service.js +0 -40
- package/dist/services/user-flow-actors-service.d.ts +0 -39
- package/dist/wirings/credential/wire-credential.d.ts +0 -48
- package/dist/wirings/credential/wire-credential.js +0 -47
- package/dist/wirings/oauth2/oauth2-client.d.ts +0 -47
- package/dist/wirings/oauth2/oauth2-client.js +0 -263
- package/dist/wirings/oauth2/oauth2-routes.d.ts +0 -35
- package/dist/wirings/oauth2/oauth2-routes.js +0 -146
- package/dist/wirings/scope/wire-scope.d.ts +0 -33
- package/dist/wirings/scope/wire-scope.js +0 -32
- package/dist/wirings/workflow/dsl/index.d.ts +0 -5
- package/dist/wirings/workflow/dsl/index.js +0 -4
- package/dist/wirings/workflow/graph/index.d.ts +0 -5
- package/dist/wirings/workflow/graph/index.js +0 -4
- package/src/internal.ts +0 -10
- /package/dist/{services/user-flow-actors-service.js → wirings/workflow/workflow-run-engine.types.js} +0 -0
|
@@ -142,8 +142,6 @@ export type FunctionRuntimeMeta = {
|
|
|
142
142
|
audit?: {
|
|
143
143
|
durability: AuditDurability;
|
|
144
144
|
};
|
|
145
|
-
/** Keeps the full `SecretService`. Set by the inspector, read by the runner. */
|
|
146
|
-
secretBroker?: boolean;
|
|
147
145
|
version?: number;
|
|
148
146
|
approvalRequired?: boolean;
|
|
149
147
|
approvalDescription?: string;
|
|
@@ -233,6 +231,11 @@ export interface CoreUserSession {
|
|
|
233
231
|
* Populated by whoever builds the session — core reads them, never fetches.
|
|
234
232
|
*/
|
|
235
233
|
scopes?: string[];
|
|
234
|
+
/**
|
|
235
|
+
* Restricts the session to functions declared `readonly`. The function runner
|
|
236
|
+
* throws `ReadonlySessionError` for anything else.
|
|
237
|
+
*/
|
|
238
|
+
readonly?: boolean;
|
|
236
239
|
}
|
|
237
240
|
/**
|
|
238
241
|
* Kept structural so core stays independent of any one auth package —
|
|
@@ -299,12 +302,17 @@ export interface CoreSingletonServices<Config extends CoreConfig = CoreConfig> {
|
|
|
299
302
|
*/
|
|
300
303
|
auth?: () => Promise<AuthInstance>;
|
|
301
304
|
}
|
|
302
|
-
export type PikkuWire<In = unknown, Out = unknown, HasInitialSession extends boolean = false, UserSession extends CoreUserSession = CoreUserSession, TypedRPC extends PikkuRPC = PikkuRPC, IsChannel extends true | null = null, MCPTools extends string | never = never, TypedWorkflow extends PikkuWorkflowWire | never = PikkuWorkflowWire, TriggerOutput = unknown, TypedScenario extends PikkuScenarioWire | never = PikkuScenarioWire
|
|
305
|
+
export type PikkuWire<In = unknown, Out = unknown, HasInitialSession extends boolean = false, UserSession extends CoreUserSession = CoreUserSession, TypedRPC extends PikkuRPC = PikkuRPC, IsChannel extends true | null = null, MCPTools extends string | never = never, TypedWorkflow extends PikkuWorkflowWire | never = PikkuWorkflowWire, TriggerOutput = unknown, TypedScenario extends PikkuScenarioWire<any> | never = PikkuScenarioWire<any>, TypedActors extends ScenarioPersonas = ScenarioPersonas> = {
|
|
303
306
|
/** Always present — lazily initialised on first access for every function invocation */
|
|
304
307
|
rpc: TypedRPC;
|
|
305
308
|
} & Partial<{
|
|
306
309
|
wireType: PikkuWiringTypes;
|
|
307
310
|
wireId: string;
|
|
311
|
+
/**
|
|
312
|
+
* A logger scoped to this invocation, when a host attaches one. Core never
|
|
313
|
+
* sets it; services that log fall back to the singleton logger.
|
|
314
|
+
*/
|
|
315
|
+
logger: Logger;
|
|
308
316
|
/** Trace ID for distributed tracing — propagated across remote RPC calls via x-trace-id header */
|
|
309
317
|
traceId: string;
|
|
310
318
|
functionId: string;
|
|
@@ -6,6 +6,7 @@ import type { CLIMeta, CLIProgramState } from '../wirings/cli/cli.types.js';
|
|
|
6
6
|
import type { HTTPMethod, CoreHTTPFunctionWiring, HTTPWiringsMeta } from '../wirings/http/http.types.js';
|
|
7
7
|
import type { CoreMCPResource, MCPResourceMeta, MCPToolMeta, CoreMCPPrompt, MCPPromptMeta } from '../wirings/mcp/mcp.types.js';
|
|
8
8
|
import type { CoreAIAgent, AIAgentMeta } from '../wirings/ai-agent/ai-agent.types.js';
|
|
9
|
+
import type { PikkuAIScorer, ScorerMeta } from '../wirings/ai-scorer/ai-scorer.types.js';
|
|
9
10
|
import type { CoreGateway, GatewaysMeta } from '../wirings/gateway/gateway.types.js';
|
|
10
11
|
import type { CoreQueueWorker, QueueWorkersMeta } from '../wirings/queue/queue.types.js';
|
|
11
12
|
import type { CoreScheduledTask, ScheduledTasksMeta } from '../wirings/scheduler/scheduler.types.js';
|
|
@@ -40,6 +41,10 @@ export interface PikkuPackageState {
|
|
|
40
41
|
variableOverrides?: Record<string, string>;
|
|
41
42
|
/** Per-instance name-aliases: logical name the addon reads -> actual project credential name */
|
|
42
43
|
credentialOverrides?: Record<string, string>;
|
|
44
|
+
/** Why this instance gets the whole `SecretService` rather than one scoped to its declared secrets */
|
|
45
|
+
globalSecrets?: string;
|
|
46
|
+
/** Why this instance gets the whole `CredentialService` rather than one scoped to its declared credentials */
|
|
47
|
+
globalCredentials?: string;
|
|
43
48
|
/** Set by `wireRemoteAddon`: this namespace is consumed remotely over HTTP, not bundled */
|
|
44
49
|
remote?: boolean;
|
|
45
50
|
/** Remote host base URL (wireRemoteAddon) — string or resolver over singleton services */
|
|
@@ -63,7 +68,7 @@ export interface PikkuPackageState {
|
|
|
63
68
|
meta: HTTPWiringsMeta;
|
|
64
69
|
};
|
|
65
70
|
channel: {
|
|
66
|
-
channels: Map<string, CoreChannel<any, any>>;
|
|
71
|
+
channels: Map<string, CoreChannel<any, any, any, any, any>>;
|
|
67
72
|
meta: ChannelsMeta;
|
|
68
73
|
};
|
|
69
74
|
scheduler: {
|
|
@@ -97,6 +102,10 @@ export interface PikkuPackageState {
|
|
|
97
102
|
agent: {
|
|
98
103
|
agents: Map<string, CoreAIAgent>;
|
|
99
104
|
agentsMeta: AIAgentMeta;
|
|
105
|
+
scorers: Map<string, PikkuAIScorer>;
|
|
106
|
+
scorersMeta: ScorerMeta;
|
|
107
|
+
/** Alias -> `provider/model`, from the `models` table in pikku.config.json. */
|
|
108
|
+
modelAliases: Record<string, string>;
|
|
100
109
|
};
|
|
101
110
|
gateway: {
|
|
102
111
|
gateways: Map<string, CoreGateway>;
|
|
@@ -141,5 +150,9 @@ export interface PikkuPackageState {
|
|
|
141
150
|
oauth2?: boolean;
|
|
142
151
|
}> | null;
|
|
143
152
|
requiredParentServices: string[] | null;
|
|
153
|
+
/** The secret keys this package is allowed to read, emitted by the CLI from
|
|
154
|
+
* what the package declares and is seen to read. `null` when the package
|
|
155
|
+
* was never analysed, which scopes it to nothing. */
|
|
156
|
+
declaredSecrets: string[] | null;
|
|
144
157
|
};
|
|
145
158
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export type {
|
|
1
|
+
export type { ActorFlowVerdict, ConverseOptions, TargetAgentDriver, } from './actor-flow.types.js';
|
|
2
2
|
export { runConversation, type RunConversationParams, type ActorLLM, } from './run-conversation.js';
|
|
@@ -70,12 +70,7 @@ function actorInstructions(persona, task) {
|
|
|
70
70
|
: '',
|
|
71
71
|
`Your goal in this conversation: ${task}.`,
|
|
72
72
|
`Send one message at a time. Set "done" to true only once your goal is clearly accomplished, or clearly impossible.`,
|
|
73
|
-
//
|
|
74
|
-
// that cannot take a JSON *schema* degrades to OpenAI's `json_object`
|
|
75
|
-
// mode — which refuses the request outright unless the word "json" appears
|
|
76
|
-
// somewhere in the prompt. Saying it once here covers all three call sites
|
|
77
|
-
// (turn, approvals, verdict), since each builds on these instructions, and
|
|
78
|
-
// it costs nothing on providers that never needed telling.
|
|
73
|
+
// knowledge: decisions/internals/the-actor-prompt-says-json-because-of-json-object-mode.md
|
|
79
74
|
`Reply with json matching the schema you are given, and nothing else.`,
|
|
80
75
|
]
|
|
81
76
|
.filter(Boolean)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { PikkuRawWire } from '../../types/core.types.js';
|
|
2
|
+
import type { SessionService } from '../../services/user-session-service.js';
|
|
3
|
+
import type { CoreUserSession } from '../../types/core.types.js';
|
|
4
|
+
import type { PikkuRPC } from '../rpc/rpc-types.js';
|
|
5
|
+
export type AgentRPCOptions = {
|
|
6
|
+
sessionService?: SessionService<CoreUserSession>;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* `wire.rpc.agent`, implemented.
|
|
10
|
+
*
|
|
11
|
+
* Lives here rather than in `rpc-runner` so the agent surface is one file next
|
|
12
|
+
* to the runner and stream code it delegates to, instead of a wing of the RPC
|
|
13
|
+
* primitive.
|
|
14
|
+
*/
|
|
15
|
+
export declare const createAgentRPC: (wire: PikkuRawWire, options: AgentRPCOptions) => PikkuRPC["agent"];
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { runAIAgent, resumeAIAgentSync } from './ai-agent-runner.js';
|
|
2
|
+
import { streamAIAgent, resumeAIAgent, interruptAIAgent, } from './ai-agent-stream.js';
|
|
3
|
+
import { wrapChannelWithAGUI } from './ai-agent-agui.js';
|
|
4
|
+
/**
|
|
5
|
+
* `wire.rpc.agent`, implemented.
|
|
6
|
+
*
|
|
7
|
+
* Lives here rather than in `rpc-runner` so the agent surface is one file next
|
|
8
|
+
* to the runner and stream code it delegates to, instead of a wing of the RPC
|
|
9
|
+
* primitive.
|
|
10
|
+
*/
|
|
11
|
+
export const createAgentRPC = (wire, options) => {
|
|
12
|
+
const params = () => ({
|
|
13
|
+
sessionService: options.sessionService,
|
|
14
|
+
getCredential: wire.getCredential?.bind(wire),
|
|
15
|
+
});
|
|
16
|
+
const streamingChannel = () => {
|
|
17
|
+
const channel = wire.channel;
|
|
18
|
+
if (!channel)
|
|
19
|
+
throw new Error('No channel available for streaming');
|
|
20
|
+
return channel;
|
|
21
|
+
};
|
|
22
|
+
/** `run` and `approve` return the same shape; only the call differs. */
|
|
23
|
+
const asRunResult = (result) => ({
|
|
24
|
+
runId: result.runId,
|
|
25
|
+
result: result.object ?? result.text,
|
|
26
|
+
usage: result.usage,
|
|
27
|
+
...(result.status === 'suspended' && {
|
|
28
|
+
status: 'suspended',
|
|
29
|
+
pendingApprovals: result.pendingApprovals,
|
|
30
|
+
}),
|
|
31
|
+
});
|
|
32
|
+
return {
|
|
33
|
+
run: async (agentName, input) => asRunResult(await runAIAgent(agentName, input, params())),
|
|
34
|
+
stream: async (agentName, input, streamOptions) => {
|
|
35
|
+
let currentRunId;
|
|
36
|
+
await streamAIAgent(agentName, input, wrapChannelWithAGUI(streamingChannel(), {
|
|
37
|
+
threadId: input.threadId,
|
|
38
|
+
getRunId: () => currentRunId,
|
|
39
|
+
}), params(), undefined, {
|
|
40
|
+
...streamOptions,
|
|
41
|
+
onRunCreated: (runId) => {
|
|
42
|
+
currentRunId = runId;
|
|
43
|
+
streamOptions?.onRunCreated?.(runId);
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
},
|
|
47
|
+
resume: async (runId, input, streamOptions) => {
|
|
48
|
+
await resumeAIAgent({ runId, ...input }, wrapChannelWithAGUI(streamingChannel(), { runId }), params(), streamOptions);
|
|
49
|
+
},
|
|
50
|
+
interrupt: async (runId, reason) => interruptAIAgent({ runId, ...(reason ? { reason } : {}) }, { sessionService: options.sessionService }),
|
|
51
|
+
approve: async (runId, approvals, expectedAgentName) => asRunResult(await resumeAIAgentSync(runId, approvals, { sessionService: options.sessionService }, expectedAgentName)),
|
|
52
|
+
};
|
|
53
|
+
};
|
|
@@ -296,11 +296,7 @@ export function wrapChannelWithAGUI(inner, options) {
|
|
|
296
296
|
});
|
|
297
297
|
break;
|
|
298
298
|
}
|
|
299
|
-
//
|
|
300
|
-
// pikku-specific ones. Dropping it instead — which is what this did —
|
|
301
|
-
// means a voice agent reached over HTTP is inaudible: `voiceOutput`
|
|
302
|
-
// synthesizes every sentence, the provider bills for it, and nothing
|
|
303
|
-
// gets past the mapper.
|
|
299
|
+
// knowledge: decisions/internals/agent-speech-travels-as-a-custom-agui-event.md
|
|
304
300
|
case 'audio-delta': {
|
|
305
301
|
send({
|
|
306
302
|
type: 'CUSTOM',
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { AIAgentStep, AIMessage, PikkuAIMiddlewareHooks } from './ai-agent.types.js';
|
|
2
|
+
import type { AIRunStateService } from '../../services/ai-run-state-service.js';
|
|
3
|
+
export type RunUsage = {
|
|
4
|
+
inputTokens: number;
|
|
5
|
+
outputTokens: number;
|
|
6
|
+
model?: string;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Everything a finished run produced, after all middleware has had its say.
|
|
10
|
+
*
|
|
11
|
+
* One snapshot feeds persistence and anything that grades the run, so that what
|
|
12
|
+
* a scorer is shown is exactly what was stored — including the redactions.
|
|
13
|
+
*/
|
|
14
|
+
export type FinalizedRun = {
|
|
15
|
+
runId: string;
|
|
16
|
+
agentName: string;
|
|
17
|
+
threadId: string;
|
|
18
|
+
resourceId?: string;
|
|
19
|
+
/** The prompt the run answered — what a scorer grades the answer against. */
|
|
20
|
+
input: string;
|
|
21
|
+
text: string;
|
|
22
|
+
steps: AIAgentStep[];
|
|
23
|
+
usage: RunUsage;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* The prompt a run answered: the most recent user turn, which is what the model
|
|
27
|
+
* was last asked. On a resumed run the earlier turns are context, not the ask.
|
|
28
|
+
*/
|
|
29
|
+
export declare const lastUserMessageText: (messages: AIMessage[]) => string;
|
|
30
|
+
/**
|
|
31
|
+
* Run the `modifyOutput` chain over a finished non-streaming run.
|
|
32
|
+
*
|
|
33
|
+
* Reverse order, matching the input chain: the middleware registered first
|
|
34
|
+
* wraps the others, so it sees the output last.
|
|
35
|
+
*/
|
|
36
|
+
export declare const applyOutputMiddleware: (aiMiddlewares: PikkuAIMiddlewareHooks[], singletonServices: any, input: {
|
|
37
|
+
text: string;
|
|
38
|
+
messages: AIMessage[];
|
|
39
|
+
steps: AIAgentStep[];
|
|
40
|
+
usage: {
|
|
41
|
+
inputTokens: number;
|
|
42
|
+
outputTokens: number;
|
|
43
|
+
};
|
|
44
|
+
}) => Promise<{
|
|
45
|
+
text: string;
|
|
46
|
+
messages: AIMessage[];
|
|
47
|
+
steps: AIAgentStep[];
|
|
48
|
+
}>;
|
|
49
|
+
/**
|
|
50
|
+
* The one place a run ends successfully.
|
|
51
|
+
*
|
|
52
|
+
* Every path that completes a run — streamed, non-streamed, and resumed after a
|
|
53
|
+
* tool approval — goes through here, so that anything terminal is reachable
|
|
54
|
+
* from all of them and cannot be reordered by a middleware author. Nothing here
|
|
55
|
+
* may rewrite the run: by this point the output middleware has resolved and, on
|
|
56
|
+
* the streaming path, the client already has the reply.
|
|
57
|
+
*/
|
|
58
|
+
export declare const finalizeAgentRun: (aiRunState: AIRunStateService, run: FinalizedRun) => Promise<void>;
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { pikkuState } from '../../pikku-state.js';
|
|
2
|
+
import { scoreFinishedRun } from '../ai-scorer/ai-scorer-live.js';
|
|
3
|
+
import { recordScoreSnapshot } from '../ai-scorer/ai-scorer-snapshots.js';
|
|
4
|
+
/**
|
|
5
|
+
* The prompt a run answered: the most recent user turn, which is what the model
|
|
6
|
+
* was last asked. On a resumed run the earlier turns are context, not the ask.
|
|
7
|
+
*/
|
|
8
|
+
export const lastUserMessageText = (messages) => {
|
|
9
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
10
|
+
const message = messages[i];
|
|
11
|
+
if (message?.role !== 'user')
|
|
12
|
+
continue;
|
|
13
|
+
if (typeof message.content === 'string')
|
|
14
|
+
return message.content;
|
|
15
|
+
if (Array.isArray(message.content)) {
|
|
16
|
+
return message.content
|
|
17
|
+
.filter((part) => part.type === 'text')
|
|
18
|
+
.map((part) => part.text)
|
|
19
|
+
.join('\n');
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return '';
|
|
23
|
+
};
|
|
24
|
+
const flattenToolCalls = (steps) => steps.flatMap((step) => step.toolCalls ?? []);
|
|
25
|
+
/**
|
|
26
|
+
* Push a rewritten flat tool-call list back onto the steps it came from,
|
|
27
|
+
* preserving the step boundaries. A hook that adds or drops calls would make
|
|
28
|
+
* the boundaries meaningless, so a length change collapses them into the last
|
|
29
|
+
* step rather than silently mis-attributing calls to the wrong step.
|
|
30
|
+
*/
|
|
31
|
+
const distributeToolCalls = (steps, toolCalls) => {
|
|
32
|
+
if (toolCalls.length !== flattenToolCalls(steps).length) {
|
|
33
|
+
return steps.map((step, index) => ({
|
|
34
|
+
...step,
|
|
35
|
+
toolCalls: index === steps.length - 1 ? toolCalls : [],
|
|
36
|
+
}));
|
|
37
|
+
}
|
|
38
|
+
let cursor = 0;
|
|
39
|
+
return steps.map((step) => {
|
|
40
|
+
if (!step.toolCalls)
|
|
41
|
+
return step;
|
|
42
|
+
const next = toolCalls.slice(cursor, cursor + step.toolCalls.length);
|
|
43
|
+
cursor += step.toolCalls.length;
|
|
44
|
+
return { ...step, toolCalls: next };
|
|
45
|
+
});
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Run the `modifyOutput` chain over a finished non-streaming run.
|
|
49
|
+
*
|
|
50
|
+
* Reverse order, matching the input chain: the middleware registered first
|
|
51
|
+
* wraps the others, so it sees the output last.
|
|
52
|
+
*/
|
|
53
|
+
export const applyOutputMiddleware = async (aiMiddlewares, singletonServices, input) => {
|
|
54
|
+
let text = input.text;
|
|
55
|
+
let messages = input.messages;
|
|
56
|
+
let steps = input.steps;
|
|
57
|
+
let toolCalls = flattenToolCalls(steps);
|
|
58
|
+
for (let i = aiMiddlewares.length - 1; i >= 0; i--) {
|
|
59
|
+
const mw = aiMiddlewares[i];
|
|
60
|
+
if (!mw.modifyOutput)
|
|
61
|
+
continue;
|
|
62
|
+
const result = await mw.modifyOutput(singletonServices, {
|
|
63
|
+
text,
|
|
64
|
+
messages,
|
|
65
|
+
usage: {
|
|
66
|
+
inputTokens: input.usage.inputTokens,
|
|
67
|
+
outputTokens: input.usage.outputTokens,
|
|
68
|
+
},
|
|
69
|
+
toolCalls,
|
|
70
|
+
});
|
|
71
|
+
text = result.text;
|
|
72
|
+
messages = result.messages;
|
|
73
|
+
if (result.toolCalls) {
|
|
74
|
+
toolCalls = result.toolCalls;
|
|
75
|
+
steps = distributeToolCalls(steps, toolCalls);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return { text, messages, steps };
|
|
79
|
+
};
|
|
80
|
+
/**
|
|
81
|
+
* The one place a run ends successfully.
|
|
82
|
+
*
|
|
83
|
+
* Every path that completes a run — streamed, non-streamed, and resumed after a
|
|
84
|
+
* tool approval — goes through here, so that anything terminal is reachable
|
|
85
|
+
* from all of them and cannot be reordered by a middleware author. Nothing here
|
|
86
|
+
* may rewrite the run: by this point the output middleware has resolved and, on
|
|
87
|
+
* the streaming path, the client already has the reply.
|
|
88
|
+
*/
|
|
89
|
+
export const finalizeAgentRun = async (aiRunState, run) => {
|
|
90
|
+
await aiRunState.updateRun(run.runId, {
|
|
91
|
+
status: 'completed',
|
|
92
|
+
...(run.usage.model
|
|
93
|
+
? {
|
|
94
|
+
usage: {
|
|
95
|
+
inputTokens: run.usage.inputTokens,
|
|
96
|
+
outputTokens: run.usage.outputTokens,
|
|
97
|
+
model: run.usage.model,
|
|
98
|
+
},
|
|
99
|
+
}
|
|
100
|
+
: {}),
|
|
101
|
+
});
|
|
102
|
+
// Read rather than `getSingletonServices()`: a process that never registered
|
|
103
|
+
// them grades nothing, which is not an error at the point a run has already
|
|
104
|
+
// succeeded.
|
|
105
|
+
const services = pikkuState(null, 'package', 'singletonServices');
|
|
106
|
+
if (!services)
|
|
107
|
+
return;
|
|
108
|
+
const snapshot = {
|
|
109
|
+
runId: run.runId,
|
|
110
|
+
agentName: run.agentName,
|
|
111
|
+
threadId: run.threadId,
|
|
112
|
+
...(run.resourceId !== undefined ? { resourceId: run.resourceId } : {}),
|
|
113
|
+
input: run.input,
|
|
114
|
+
output: run.text,
|
|
115
|
+
toolCalls: run.steps.flatMap((step) => (step.toolCalls ?? []).map((call) => ({
|
|
116
|
+
name: call.name,
|
|
117
|
+
args: call.args,
|
|
118
|
+
result: call.result,
|
|
119
|
+
...(call.error !== undefined ? { error: call.error } : {}),
|
|
120
|
+
}))),
|
|
121
|
+
usage: {
|
|
122
|
+
inputTokens: run.usage.inputTokens,
|
|
123
|
+
outputTokens: run.usage.outputTokens,
|
|
124
|
+
...(run.usage.model !== undefined ? { model: run.usage.model } : {}),
|
|
125
|
+
},
|
|
126
|
+
};
|
|
127
|
+
// The same object a scenario grades, so an asserted score and a sampled one
|
|
128
|
+
// are the same measurement. A no-op unless a dev server turned retention on.
|
|
129
|
+
recordScoreSnapshot(snapshot);
|
|
130
|
+
// Best-effort and last: the client already has its answer, so a grading
|
|
131
|
+
// failure must not surface as a failed run.
|
|
132
|
+
try {
|
|
133
|
+
await scoreFinishedRun(snapshot, services);
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
services.logger?.error(`[pikku] Live scoring failed for run ${run.runId}`, error);
|
|
137
|
+
}
|
|
138
|
+
};
|
|
@@ -240,6 +240,7 @@ export const persistOrphanedToolResults = async (handle, storage, threadId) => {
|
|
|
240
240
|
: typeof entry.result === 'string'
|
|
241
241
|
? entry.result
|
|
242
242
|
: JSON.stringify(entry.result),
|
|
243
|
+
...(entry.error ? { error: entry.error } : {}),
|
|
243
244
|
})),
|
|
244
245
|
undelivered: true,
|
|
245
246
|
createdAt: new Date(),
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { CoreSingletonServices } from '../../types/core.types.js';
|
|
2
|
-
import type { CoreAIAgent, AIAgentMemoryConfig, AIAgentInput, AIMessage } from './ai-agent.types.js';
|
|
2
|
+
import type { CoreAIAgent, AIAgentMemoryConfig, AIAgentInput, AIAgentStep, AIMessage } from './ai-agent.types.js';
|
|
3
3
|
import type { AIStorageService } from '../../services/ai-storage-service.js';
|
|
4
4
|
import type { Logger } from '../../services/logger.js';
|
|
5
5
|
import type { SchemaService } from '../../services/schema-service.js';
|
|
@@ -14,13 +14,7 @@ export declare function loadContextMessages(memoryConfig: AIAgentMemoryConfig |
|
|
|
14
14
|
export declare function saveMessages(storage: AIStorageService | undefined, threadId: string, resourceId: string, memoryConfig: AIAgentMemoryConfig | undefined, userMessage: AIMessage | null | undefined, result: {
|
|
15
15
|
text: string;
|
|
16
16
|
uiSpec?: unknown;
|
|
17
|
-
steps:
|
|
18
|
-
toolCalls?: {
|
|
19
|
-
name: string;
|
|
20
|
-
args: Record<string, unknown>;
|
|
21
|
-
result: string;
|
|
22
|
-
}[];
|
|
23
|
-
}[];
|
|
17
|
+
steps: Pick<AIAgentStep, 'toolCalls'>[];
|
|
24
18
|
}): Promise<string>;
|
|
25
19
|
export declare function trimMessages(messages: AIMessage[], maxTokenBudget?: number): AIMessage[];
|
|
26
20
|
export declare function parseWorkingMemory(text: string): Record<string, unknown> | null;
|
|
@@ -2,7 +2,9 @@ import { randomUUID } from 'crypto';
|
|
|
2
2
|
export function resolveMemoryServices(agent, singletonServices) {
|
|
3
3
|
const memoryConfig = agent.memory;
|
|
4
4
|
const storage = memoryConfig?.storage
|
|
5
|
-
?
|
|
5
|
+
? // The service is named by string in agent config, so the lookup cannot be
|
|
6
|
+
// checked — only the shape it is required to have.
|
|
7
|
+
singletonServices[memoryConfig.storage]
|
|
6
8
|
: singletonServices.aiStorage;
|
|
7
9
|
return { storage };
|
|
8
10
|
}
|
|
@@ -100,6 +102,7 @@ export async function saveMessages(storage, threadId, resourceId, memoryConfig,
|
|
|
100
102
|
id: toolCallIds[i],
|
|
101
103
|
name: tc.name,
|
|
102
104
|
result: tc.result,
|
|
105
|
+
...(tc.error ? { error: tc.error } : {}),
|
|
103
106
|
})),
|
|
104
107
|
createdAt: new Date(),
|
|
105
108
|
});
|
|
@@ -254,9 +257,39 @@ export function stripWorkingMemoryForStreaming(text) {
|
|
|
254
257
|
}
|
|
255
258
|
return output;
|
|
256
259
|
}
|
|
260
|
+
async function persistWorkingMemory(options, workingMemory) {
|
|
261
|
+
if (!options.storage)
|
|
262
|
+
return;
|
|
263
|
+
const existing = (await options.storage.getWorkingMemory(options.threadId, 'thread')) ?? {};
|
|
264
|
+
const merged = deepMergeWorkingMemory(existing, workingMemory);
|
|
265
|
+
if (options.schemaService && options.workingMemorySchemaName) {
|
|
266
|
+
try {
|
|
267
|
+
await options.schemaService.validateSchema(options.workingMemorySchemaName, merged);
|
|
268
|
+
}
|
|
269
|
+
catch (err) {
|
|
270
|
+
options.logger?.warn(`Working memory validation failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
await options.storage.saveWorkingMemory(options.threadId, 'thread', merged);
|
|
275
|
+
}
|
|
257
276
|
export function createWorkingMemoryMiddleware(options) {
|
|
258
277
|
return {
|
|
259
278
|
modifyOutputStream: async (_services, { event, state }) => {
|
|
279
|
+
// A streamed step ends at its `usage` event, or at `done` for a model
|
|
280
|
+
// that reports no usage. That is the last moment the unstripped text is
|
|
281
|
+
// still reachable: it lives only in `state.rawText`, because the strip
|
|
282
|
+
// below runs before anything downstream — including the channel that
|
|
283
|
+
// accumulates what `modifyOutput` would later be handed.
|
|
284
|
+
if (event.type === 'usage' || event.type === 'done') {
|
|
285
|
+
const { workingMemory } = extractWorkingMemory(state.rawText ?? '');
|
|
286
|
+
state.rawText = '';
|
|
287
|
+
state.emittedVisibleText = '';
|
|
288
|
+
if (workingMemory) {
|
|
289
|
+
await persistWorkingMemory(options, workingMemory);
|
|
290
|
+
}
|
|
291
|
+
return event;
|
|
292
|
+
}
|
|
260
293
|
if (event.type !== 'text-delta')
|
|
261
294
|
return event;
|
|
262
295
|
const rawText = `${state.rawText ?? ''}${event.text}`;
|
|
@@ -273,24 +306,10 @@ export function createWorkingMemoryMiddleware(options) {
|
|
|
273
306
|
return null;
|
|
274
307
|
return { ...event, text: delta };
|
|
275
308
|
},
|
|
276
|
-
modifyOutput: async (_services, { text, messages
|
|
309
|
+
modifyOutput: async (_services, { text, messages }) => {
|
|
277
310
|
const { workingMemory, cleanedText } = extractWorkingMemory(text);
|
|
278
|
-
if (workingMemory
|
|
279
|
-
|
|
280
|
-
const merged = deepMergeWorkingMemory(existing, workingMemory);
|
|
281
|
-
let valid = true;
|
|
282
|
-
if (options.schemaService && options.workingMemorySchemaName) {
|
|
283
|
-
try {
|
|
284
|
-
await options.schemaService.validateSchema(options.workingMemorySchemaName, merged);
|
|
285
|
-
}
|
|
286
|
-
catch (err) {
|
|
287
|
-
valid = false;
|
|
288
|
-
options.logger?.warn(`Working memory validation failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
if (valid) {
|
|
292
|
-
await options.storage.saveWorkingMemory(options.threadId, 'thread', merged);
|
|
293
|
-
}
|
|
311
|
+
if (workingMemory) {
|
|
312
|
+
await persistWorkingMemory(options, workingMemory);
|
|
294
313
|
}
|
|
295
314
|
return {
|
|
296
315
|
text: cleanedText,
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolves a model name to a concrete `provider/model`. Aliases come from the
|
|
3
|
+
* `models` table in pikku.config.json; a name containing `/` is already
|
|
4
|
+
* concrete. Read from the main package, not the calling addon's — which model
|
|
5
|
+
* a tier points at is the hosting app's decision.
|
|
6
|
+
*/
|
|
7
|
+
export declare const resolveModelAlias: (model: string) => string;
|
|
1
8
|
export declare function resolveModelConfig(_agentName: string, agent: {
|
|
2
9
|
model: string;
|
|
3
10
|
temperature?: number;
|
|
@@ -1,7 +1,50 @@
|
|
|
1
1
|
// knowledge: decisions/internals/ai-agent-model-config-stays-a-single-resolution-seam.md
|
|
2
|
+
import { pikkuState } from '../../pikku-state.js';
|
|
3
|
+
const isProviderQualified = (model) => model.includes('/');
|
|
4
|
+
/** `PIKKU_MODEL_ALIASES=cheap:openai/gpt-5-mini,tool:anthropic/claude-sonnet-5` */
|
|
5
|
+
const envAliases = () => {
|
|
6
|
+
const raw = process.env.PIKKU_MODEL_ALIASES;
|
|
7
|
+
if (!raw)
|
|
8
|
+
return {};
|
|
9
|
+
const aliases = {};
|
|
10
|
+
for (const entry of raw.split(',')) {
|
|
11
|
+
// First colon only — a model id may contain its own.
|
|
12
|
+
const separator = entry.indexOf(':');
|
|
13
|
+
if (separator === -1)
|
|
14
|
+
continue;
|
|
15
|
+
const alias = entry.slice(0, separator).trim();
|
|
16
|
+
const model = entry.slice(separator + 1).trim();
|
|
17
|
+
if (alias && model)
|
|
18
|
+
aliases[alias] = model;
|
|
19
|
+
}
|
|
20
|
+
return aliases;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Resolves a model name to a concrete `provider/model`. Aliases come from the
|
|
24
|
+
* `models` table in pikku.config.json; a name containing `/` is already
|
|
25
|
+
* concrete. Read from the main package, not the calling addon's — which model
|
|
26
|
+
* a tier points at is the hosting app's decision.
|
|
27
|
+
*/
|
|
28
|
+
export const resolveModelAlias = (model) => {
|
|
29
|
+
if (isProviderQualified(model))
|
|
30
|
+
return model;
|
|
31
|
+
const generated = pikkuState(null, 'agent', 'modelAliases');
|
|
32
|
+
const override = envAliases()[model];
|
|
33
|
+
const resolved = override ?? generated[model];
|
|
34
|
+
if (!resolved) {
|
|
35
|
+
const known = Object.keys({ ...generated, ...envAliases() }).sort();
|
|
36
|
+
throw new Error(`Unknown model alias '${model}'. ` +
|
|
37
|
+
(known.length
|
|
38
|
+
? `Known aliases: ${known.join(', ')}. `
|
|
39
|
+
: `No aliases are configured. `) +
|
|
40
|
+
`Add it to the "models" table in pikku.config.json, or name a ` +
|
|
41
|
+
`provider-qualified model such as 'openai/gpt-5-mini'.`);
|
|
42
|
+
}
|
|
43
|
+
return resolved;
|
|
44
|
+
};
|
|
2
45
|
export function resolveModelConfig(_agentName, agent) {
|
|
3
46
|
return {
|
|
4
|
-
model: agent.model,
|
|
47
|
+
model: resolveModelAlias(agent.model),
|
|
5
48
|
temperature: agent.temperature,
|
|
6
49
|
maxSteps: agent.maxSteps,
|
|
7
50
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { PikkuError } from '../../errors/error-handler.js';
|
|
2
|
-
import { checkAuthPermissions, runPermissions } from '../../permissions.js';
|
|
2
|
+
import { checkAuthPermissions, runPermissions, } from '../../permissions.js';
|
|
3
3
|
import { AIProviderNotConfiguredError } from '../../errors/errors.js';
|
|
4
4
|
import { ForbiddenError } from '../../errors/errors.js';
|
|
5
5
|
import { verifyScopes } from '../../scopes.js';
|
|
@@ -357,6 +357,8 @@ export async function buildToolDefs(params, agentSessionMap, resourceId, agentNa
|
|
|
357
357
|
secretOverrides: capturedAddonConfig?.secretOverrides,
|
|
358
358
|
variableOverrides: capturedAddonConfig?.variableOverrides,
|
|
359
359
|
credentialOverrides: capturedAddonConfig?.credentialOverrides,
|
|
360
|
+
globalSecrets: capturedAddonConfig?.globalSecrets,
|
|
361
|
+
globalCredentials: capturedAddonConfig?.globalCredentials,
|
|
360
362
|
}
|
|
361
363
|
: undefined;
|
|
362
364
|
services = await getOrCreatePackageSingletonServices(capturedPkg, singletonServices, addonInstance);
|
|
@@ -648,10 +650,7 @@ export async function prepareAgentRun(agentName, input, params, agentSessionMap,
|
|
|
648
650
|
}
|
|
649
651
|
let messages = [];
|
|
650
652
|
if (storage) {
|
|
651
|
-
//
|
|
652
|
-
// thread. In voice the next turn lands within a second or two, so without
|
|
653
|
-
// this the model would load context that is missing the very thing it is
|
|
654
|
-
// about to be asked about.
|
|
653
|
+
// knowledge: decisions/internals/agent-context-waits-for-a-tool-result-still-being-written.md
|
|
655
654
|
await awaitPendingInterruptNote(threadId);
|
|
656
655
|
messages = await storage.getMessages(threadId, {
|
|
657
656
|
lastN: memoryConfig?.lastMessages ?? 20,
|
|
@@ -660,10 +659,7 @@ export async function prepareAgentRun(agentName, input, params, agentSessionMap,
|
|
|
660
659
|
const contextMessages = await loadContextMessages(memoryConfig, storage, input, workingMemoryJsonSchema);
|
|
661
660
|
const userContent = input.attachments?.length
|
|
662
661
|
? [
|
|
663
|
-
//
|
|
664
|
-
// real turn — a spoken one carries audio and no text at all — and an
|
|
665
|
-
// empty text part alongside it is a part providers are entitled to
|
|
666
|
-
// reject, for a caller who never wrote one.
|
|
662
|
+
// knowledge: decisions/internals/an-empty-text-part-is-omitted-from-an-agent-message.md
|
|
667
663
|
...(input.message
|
|
668
664
|
? [{ type: 'text', text: input.message }]
|
|
669
665
|
: []),
|