@pikku/core 0.12.83 → 0.12.84
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 +68 -0
- package/README.md +1 -1
- package/dist/ecosystem/agent-scorer.d.ts +12 -0
- package/dist/ecosystem/agent-scorer.js +5 -0
- package/dist/ecosystem/agent.d.ts +18 -0
- package/dist/ecosystem/agent.js +6 -0
- package/dist/ecosystem/ai-agent.d.ts +18 -0
- package/dist/ecosystem/ai-agent.js +6 -0
- package/dist/ecosystem/ai-scorer.d.ts +12 -0
- package/dist/ecosystem/ai-scorer.js +5 -0
- package/dist/ecosystem/channel/local.d.ts +1 -0
- package/dist/ecosystem/channel/local.js +1 -0
- package/dist/ecosystem/channel.d.ts +12 -0
- package/dist/ecosystem/channel.js +4 -0
- package/dist/ecosystem/cli/channel.d.ts +16 -0
- package/dist/ecosystem/cli/channel.js +2 -0
- package/dist/ecosystem/cli.d.ts +9 -0
- package/dist/ecosystem/cli.js +2 -0
- package/dist/ecosystem/credential.d.ts +9 -0
- package/dist/ecosystem/credential.js +1 -0
- package/dist/ecosystem/dev.d.ts +8 -0
- package/dist/ecosystem/dev.js +1 -0
- package/dist/ecosystem/function.d.ts +13 -0
- package/dist/ecosystem/function.js +2 -0
- package/dist/ecosystem/gateway.d.ts +1 -0
- package/dist/ecosystem/gateway.js +1 -0
- package/dist/ecosystem/hmac.d.ts +1 -0
- package/dist/ecosystem/hmac.js +1 -0
- package/dist/ecosystem/http.d.ts +11 -0
- package/dist/ecosystem/http.js +3 -0
- package/dist/ecosystem/mcp.d.ts +3 -0
- package/dist/ecosystem/mcp.js +2 -0
- package/dist/ecosystem/middleware.d.ts +17 -0
- package/dist/ecosystem/middleware.js +6 -0
- package/dist/ecosystem/node-host-resolver.d.ts +1 -0
- package/dist/ecosystem/node-host-resolver.js +1 -0
- package/dist/ecosystem/node.d.ts +1 -0
- package/dist/ecosystem/node.js +1 -0
- package/dist/ecosystem/oauth2.d.ts +1 -0
- package/dist/ecosystem/oauth2.js +1 -0
- package/dist/ecosystem/persona.d.ts +15 -0
- package/dist/ecosystem/persona.js +4 -0
- package/dist/ecosystem/queue.d.ts +11 -0
- package/dist/ecosystem/queue.js +2 -0
- package/dist/ecosystem/remote.d.ts +8 -0
- package/dist/ecosystem/remote.js +1 -0
- package/dist/ecosystem/role.d.ts +3 -0
- package/dist/ecosystem/role.js +2 -0
- package/dist/ecosystem/rpc.d.ts +4 -0
- package/dist/ecosystem/rpc.js +2 -0
- package/dist/ecosystem/safe-fetch.d.ts +7 -0
- package/dist/ecosystem/safe-fetch.js +1 -0
- package/dist/ecosystem/scenario.d.ts +15 -0
- package/dist/ecosystem/scenario.js +4 -0
- package/dist/ecosystem/scheduler.d.ts +2 -0
- package/dist/ecosystem/scheduler.js +1 -0
- package/dist/ecosystem/schema.d.ts +1 -0
- package/dist/ecosystem/schema.js +1 -0
- package/dist/ecosystem/scope.d.ts +3 -0
- package/dist/ecosystem/scope.js +2 -0
- package/dist/ecosystem/secret.d.ts +9 -0
- package/dist/ecosystem/secret.js +1 -0
- package/dist/ecosystem/services/istanbul-coverage.d.ts +1 -0
- package/dist/ecosystem/services/istanbul-coverage.js +1 -0
- package/dist/ecosystem/services/local-content-request-handler.d.ts +9 -0
- package/dist/ecosystem/services/local-content-request-handler.js +1 -0
- package/dist/ecosystem/services/local-content.d.ts +1 -0
- package/dist/ecosystem/services/local-content.js +1 -0
- package/dist/ecosystem/services/v8-coverage.d.ts +1 -0
- package/dist/ecosystem/services/v8-coverage.js +1 -0
- package/dist/ecosystem/services.d.ts +28 -0
- package/dist/ecosystem/services.js +6 -0
- package/dist/ecosystem/testing.d.ts +7 -0
- package/dist/ecosystem/testing.js +1 -0
- package/dist/ecosystem/trigger.d.ts +1 -0
- package/dist/ecosystem/trigger.js +1 -0
- package/dist/ecosystem/types.d.ts +9 -0
- package/dist/ecosystem/types.js +5 -0
- package/dist/ecosystem/variable.d.ts +8 -0
- package/dist/ecosystem/variable.js +1 -0
- package/dist/ecosystem/virtual-user.d.ts +21 -0
- package/dist/ecosystem/virtual-user.js +5 -0
- package/dist/ecosystem/workflow.d.ts +18 -0
- package/dist/ecosystem/workflow.js +4 -0
- package/dist/index.d.ts +8 -8
- package/dist/index.js +3 -3
- package/dist/middleware/auth-apikey.d.ts +1 -1
- package/dist/middleware/auth-bearer.d.ts +1 -1
- package/dist/middleware/auth-cookie.d.ts +1 -1
- package/dist/middleware/cors.d.ts +1 -1
- package/dist/middleware/remote-auth.d.ts +1 -1
- package/dist/middleware/telemetry.d.ts +2 -2
- package/dist/services/agent-run-state-service.d.ts +29 -0
- package/dist/services/agent-run-state-service.js +1 -0
- package/dist/services/agent-runner-service.d.ts +220 -0
- package/dist/services/agent-runner-service.js +1 -0
- package/dist/services/agent-storage-service.d.ts +18 -0
- package/dist/services/agent-storage-service.js +1 -0
- package/dist/services/http-personas.d.ts +1 -1
- package/dist/services/http-personas.js +3 -3
- package/dist/services/in-memory-agent-run-state-service.d.ts +19 -0
- package/dist/services/in-memory-agent-run-state-service.js +54 -0
- package/dist/services/index.d.ts +4 -4
- package/dist/services/index.js +1 -1
- package/dist/services/meta-service.d.ts +3 -3
- package/dist/testing/service-tests/agent-run-service-tests.d.ts +1 -1
- package/dist/testing/service-tests/agent-run-service-tests.js +3 -3
- package/dist/testing/service-tests/agent-storage-service-tests.d.ts +3 -0
- package/dist/testing/service-tests/agent-storage-service-tests.js +302 -0
- package/dist/testing/service-tests.d.ts +4 -4
- package/dist/testing/service-tests.js +4 -4
- package/dist/types/core.types.d.ts +10 -10
- package/dist/types/core.types.js +1 -1
- package/dist/types/state.types.d.ts +5 -5
- package/dist/wirings/actor-flow/run-conversation.d.ts +2 -2
- package/dist/wirings/agent/agent-agui.d.ts +79 -0
- package/dist/wirings/agent/agent-agui.js +327 -0
- package/dist/wirings/agent/agent-finalize.d.ts +58 -0
- package/dist/wirings/agent/agent-finalize.js +138 -0
- package/dist/wirings/agent/agent-helpers.d.ts +35 -0
- package/dist/wirings/agent/agent-helpers.js +47 -0
- package/dist/wirings/agent/agent-interrupt.d.ts +153 -0
- package/dist/wirings/agent/agent-interrupt.js +257 -0
- package/dist/wirings/agent/agent-memory.d.ts +42 -0
- package/dist/wirings/agent/agent-memory.js +333 -0
- package/dist/wirings/agent/agent-model-config.d.ts +16 -0
- package/dist/wirings/agent/agent-model-config.js +51 -0
- package/dist/wirings/agent/agent-prepare.d.ts +117 -0
- package/dist/wirings/agent/agent-prepare.js +728 -0
- package/dist/wirings/agent/agent-registry.d.ts +16 -0
- package/dist/wirings/agent/agent-registry.js +51 -0
- package/dist/wirings/agent/agent-rpc.d.ts +15 -0
- package/dist/wirings/agent/agent-rpc.js +53 -0
- package/dist/wirings/agent/agent-runner.d.ts +7 -0
- package/dist/wirings/agent/agent-runner.js +580 -0
- package/dist/wirings/agent/agent-stream.d.ts +41 -0
- package/dist/wirings/agent/agent-stream.js +1029 -0
- package/dist/wirings/agent/agent-turn.d.ts +57 -0
- package/dist/wirings/agent/agent-turn.js +82 -0
- package/dist/wirings/agent/agent-utils.d.ts +1 -0
- package/dist/wirings/agent/agent-utils.js +1 -0
- package/dist/wirings/agent/agent.types.d.ts +625 -0
- package/dist/wirings/agent/agent.types.js +1 -0
- package/dist/wirings/agent/index.d.ts +12 -0
- package/dist/wirings/agent/index.js +10 -0
- package/dist/wirings/agent/voice-input.d.ts +69 -0
- package/dist/wirings/agent/voice-input.js +150 -0
- package/dist/wirings/agent/voice-output.d.ts +85 -0
- package/dist/wirings/agent/voice-output.js +196 -0
- package/dist/wirings/agent-scorer/agent-scorer-grade.d.ts +26 -0
- package/dist/wirings/agent-scorer/agent-scorer-grade.js +33 -0
- package/dist/wirings/agent-scorer/agent-scorer-judge.d.ts +17 -0
- package/dist/wirings/agent-scorer/agent-scorer-judge.js +92 -0
- package/dist/wirings/agent-scorer/agent-scorer-live.d.ts +15 -0
- package/dist/wirings/agent-scorer/agent-scorer-live.js +38 -0
- package/dist/wirings/agent-scorer/agent-scorer-registry.d.ts +18 -0
- package/dist/wirings/agent-scorer/agent-scorer-registry.js +46 -0
- package/dist/wirings/agent-scorer/agent-scorer-sampling.d.ts +8 -0
- package/dist/wirings/agent-scorer/agent-scorer-sampling.js +31 -0
- package/dist/wirings/agent-scorer/agent-scorer-snapshots.d.ts +10 -0
- package/dist/wirings/agent-scorer/agent-scorer-snapshots.js +40 -0
- package/dist/wirings/agent-scorer/agent-scorer-worker.d.ts +15 -0
- package/dist/wirings/agent-scorer/agent-scorer-worker.js +60 -0
- package/dist/wirings/agent-scorer/agent-scorer.d.ts +39 -0
- package/dist/wirings/agent-scorer/agent-scorer.js +40 -0
- package/dist/wirings/agent-scorer/agent-scorer.types.d.ts +90 -0
- package/dist/wirings/agent-scorer/agent-scorer.types.js +4 -0
- package/dist/wirings/agent-scorer/index.d.ts +6 -0
- package/dist/wirings/agent-scorer/index.js +5 -0
- package/dist/wirings/ai-agent/voice-output.d.ts +1 -2
- package/dist/wirings/channel/channel-rpc.types.d.ts +2 -2
- package/dist/wirings/rpc/rpc-runner.d.ts +1 -1
- package/dist/wirings/rpc/rpc-runner.js +2 -2
- package/dist/wirings/rpc/rpc-types.d.ts +1 -1
- package/dist/wirings/virtual-user/prepare-virtual-user-run.js +1 -1
- package/dist/wirings/virtual-user/virtual-user-agents.d.ts +1 -1
- package/dist/wirings/workflow/run-timeline.d.ts +1 -2
- package/knowledge/decisions/internals/{a-non-streaming-agent-run-registers-with-airunstate-too.md → a-non-streaming-agent-run-registers-with-agentrunstate-too.md} +6 -6
- package/knowledge/decisions/internals/a-resumed-agent-turn-is-as-interruptible-as-the-first.md +1 -1
- package/knowledge/decisions/internals/actor-flow-drives-the-target-through-a-transport-seam.md +1 -1
- package/knowledge/decisions/internals/{ai-agent-agui-bridge-obeys-the-client-ordering-contract.md → agent-agui-bridge-obeys-the-client-ordering-contract.md} +5 -5
- package/knowledge/decisions/internals/{ai-agent-audio-chunks-carry-the-format-the-provider-returned.md → agent-audio-chunks-carry-the-format-the-provider-returned.md} +2 -2
- package/knowledge/decisions/internals/agent-context-waits-for-a-tool-result-still-being-written.md +1 -1
- package/knowledge/decisions/internals/{ai-agent-credential-suspensions-hide-the-tool-result.md → agent-credential-suspensions-hide-the-tool-result.md} +2 -2
- package/knowledge/decisions/internals/{ai-agent-delegate-and-supervise-hide-different-text.md → agent-delegate-and-supervise-hide-different-text.md} +4 -4
- package/knowledge/decisions/internals/{ai-agent-llm-tool-arguments-have-nulls-stripped.md → agent-llm-tool-arguments-have-nulls-stripped.md} +3 -3
- package/knowledge/decisions/internals/{ai-agent-model-config-stays-a-single-resolution-seam.md → agent-model-config-stays-a-single-resolution-seam.md} +3 -3
- package/knowledge/decisions/internals/{ai-agent-onerror-hooks-cannot-change-the-failure.md → agent-onerror-hooks-cannot-change-the-failure.md} +6 -6
- package/knowledge/decisions/internals/{ai-agent-runner-methods-must-keep-their-receiver.md → agent-runner-methods-must-keep-their-receiver.md} +4 -4
- package/knowledge/decisions/internals/agent-speech-travels-as-a-custom-agui-event.md +1 -1
- package/knowledge/decisions/internals/{ai-agent-stream-persistence-is-best-effort.md → agent-stream-persistence-is-best-effort.md} +4 -4
- package/knowledge/decisions/internals/{ai-agent-sub-agents-inherit-the-parent-context-block.md → agent-sub-agents-inherit-the-parent-context-block.md} +3 -3
- package/knowledge/decisions/internals/{ai-agent-tool-execute-failures-are-logged-unconditionally.md → agent-tool-execute-failures-are-logged-unconditionally.md} +3 -3
- package/knowledge/decisions/internals/{ai-agent-voice-input-transcribes-audio-parts-in-place.md → agent-voice-input-transcribes-audio-parts-in-place.md} +2 -2
- package/knowledge/decisions/internals/{ai-agent-working-memory-is-persisted-only-when-valid.md → agent-working-memory-is-persisted-only-when-valid.md} +2 -2
- package/knowledge/decisions/internals/an-agent-interrupt-is-not-a-failure.md +2 -2
- package/knowledge/decisions/internals/an-agent-run-owned-by-another-instance-says-so.md +3 -3
- package/knowledge/decisions/internals/an-agent-stream-send-must-return-the-inner-sends-promise.md +2 -2
- package/knowledge/decisions/internals/an-empty-text-part-is-omitted-from-an-agent-message.md +1 -1
- package/knowledge/decisions/internals/an-empty-transcript-is-not-recorded.md +1 -1
- package/knowledge/decisions/internals/speech-synthesis-picks-a-voice-per-sentence-and-warns-once.md +1 -1
- package/knowledge/decisions/internals/the-agent-done-event-goes-through-the-middleware-and-is-awaited.md +1 -1
- package/knowledge/decisions/internals/the-embedding-model-is-pinned-per-service-and-doc-query-embedding-is-split.md +1 -1
- package/knowledge/decisions/internals/the-per-invocation-rpc-view-is-a-class.md +5 -5
- package/knowledge/decisions/internals/the-transcript-event-is-sent-ahead-of-the-run.md +2 -2
- package/knowledge/decisions/internals/thread-history-records-the-transcript-not-the-audio.md +2 -2
- package/knowledge/decisions/internals/voice-output-speaks-unless-voice-input-explicitly-says-otherwise.md +1 -1
- package/knowledge/decisions/security/{ai-agent-approval-forwarding-requires-a-symbol-brand.md → agent-approval-forwarding-requires-a-symbol-brand.md} +3 -3
- package/knowledge/decisions/security/{ai-agent-credential-requests-are-symbol-branded.md → agent-credential-requests-are-symbol-branded.md} +4 -4
- package/knowledge/decisions/security/{ai-agent-gate-requires-a-session-only-when-auth-is-true.md → agent-gate-requires-a-session-only-when-auth-is-true.md} +3 -3
- package/knowledge/decisions/security/{ai-agent-ownership-failures-never-echo-the-resource.md → agent-ownership-failures-never-echo-the-resource.md} +2 -2
- package/knowledge/decisions/security/{ai-agent-resume-re-runs-the-authorization-gate.md → agent-resume-re-runs-the-authorization-gate.md} +4 -4
- package/knowledge/decisions/security/{ai-agent-sessionless-deployments-have-no-thread-ownership.md → agent-sessionless-deployments-have-no-thread-ownership.md} +5 -5
- package/knowledge/decisions/security/{ai-agent-thread-ownership-composes-the-session-principal.md → agent-thread-ownership-composes-the-session-principal.md} +2 -2
- package/knowledge/decisions/security/{ai-agent-tool-filtering-reads-the-live-function-config.md → agent-tool-filtering-reads-the-live-function-config.md} +2 -2
- package/knowledge/decisions/security/an-agent-approval-is-claimed-before-the-tool-runs.md +3 -3
- package/knowledge/decisions/security/an-empty-owners-constraint-matches-nothing.md +3 -3
- package/knowledge/decisions/security/console-addon-privileged-functions-gate-themselves.md +20 -13
- package/knowledge/decisions/security/index.md +1 -2
- package/package.json +4 -3
- package/scripts/generate-api-report.mts +32 -8
- package/src/agent-naming.test.ts +68 -0
- package/src/ecosystem/agent-scorer.ts +24 -0
- package/src/ecosystem/agent.ts +42 -0
- package/src/ecosystem/channel/local.ts +1 -0
- package/src/ecosystem/channel.ts +22 -0
- package/src/ecosystem/cli/channel.ts +25 -0
- package/src/ecosystem/cli.ts +21 -0
- package/src/ecosystem/credential.ts +10 -0
- package/src/ecosystem/dev.ts +12 -0
- package/src/ecosystem/function.ts +28 -0
- package/src/ecosystem/gateway.ts +4 -0
- package/src/ecosystem/hmac.ts +1 -0
- package/src/ecosystem/http.ts +22 -0
- package/src/ecosystem/mcp.ts +17 -0
- package/src/ecosystem/middleware.ts +27 -0
- package/src/ecosystem/node-host-resolver.ts +1 -0
- package/src/ecosystem/node.ts +5 -0
- package/src/ecosystem/oauth2.ts +4 -0
- package/src/ecosystem/persona.ts +30 -0
- package/src/ecosystem/queue.ts +23 -0
- package/src/ecosystem/remote.ts +9 -0
- package/src/ecosystem/role.ts +13 -0
- package/src/ecosystem/rpc.ts +7 -0
- package/src/ecosystem/safe-fetch.ts +8 -0
- package/src/ecosystem/scenario.ts +32 -0
- package/src/ecosystem/scheduler.ts +5 -0
- package/src/ecosystem/schema.ts +1 -0
- package/src/ecosystem/scope.ts +14 -0
- package/src/ecosystem/secret.ts +15 -0
- package/src/ecosystem/services/istanbul-coverage.ts +1 -0
- package/src/ecosystem/services/local-content-request-handler.ts +16 -0
- package/src/ecosystem/services/local-content.ts +1 -0
- package/src/ecosystem/services/v8-coverage.ts +1 -0
- package/src/ecosystem/services.ts +82 -0
- package/src/ecosystem/testing.ts +8 -0
- package/src/ecosystem/trigger.ts +7 -0
- package/src/ecosystem/types.ts +34 -0
- package/src/ecosystem/variable.ts +14 -0
- package/src/ecosystem/virtual-user.ts +48 -0
- package/src/ecosystem/workflow.ts +68 -0
- package/src/index.ts +8 -19
- package/src/pikku-state.ts +3 -3
- package/src/public-surface.json +173 -68
- package/src/public-surface.json.README +20 -2
- package/src/public-surface.test.ts +31 -3
- package/src/services/{ai-run-state-service.ts → agent-run-state-service.ts} +5 -5
- package/src/services/{ai-agent-runner-service.ts → agent-runner-service.ts} +18 -18
- package/src/services/{ai-storage-service.ts → agent-storage-service.ts} +7 -7
- package/src/services/http-personas-converse.test.ts +3 -3
- package/src/services/http-personas.ts +4 -4
- package/src/services/{in-memory-ai-run-state-service.ts → in-memory-agent-run-state-service.ts} +7 -7
- package/src/services/index.ts +9 -9
- package/src/services/meta-service.ts +3 -3
- package/src/testing/service-tests/agent-run-service-tests.ts +4 -4
- package/src/testing/service-tests/{ai-storage-service-tests.ts → agent-storage-service-tests.ts} +8 -8
- package/src/testing/service-tests.ts +10 -8
- package/src/types/core.types.ts +12 -12
- package/src/types/state.types.ts +6 -9
- package/src/wirings/actor-flow/run-conversation.test.ts +2 -2
- package/src/wirings/actor-flow/run-conversation.ts +7 -9
- package/src/wirings/{ai-agent/ai-agent-agui.test.ts → agent/agent-agui.test.ts} +126 -105
- package/src/wirings/{ai-agent/ai-agent-agui.ts → agent/agent-agui.ts} +7 -7
- package/src/wirings/{ai-agent/ai-agent-authorization.test.ts → agent/agent-authorization.test.ts} +6 -6
- package/src/wirings/{ai-agent/ai-agent-finalize.test.ts → agent/agent-finalize.test.ts} +17 -16
- package/src/wirings/{ai-agent/ai-agent-finalize.ts → agent/agent-finalize.ts} +22 -22
- package/src/wirings/{ai-agent/ai-agent-helpers.test.ts → agent/agent-helpers.test.ts} +1 -1
- package/src/wirings/{ai-agent/ai-agent-helpers.ts → agent/agent-helpers.ts} +1 -1
- package/src/wirings/{ai-agent/ai-agent-interrupt.test.ts → agent/agent-interrupt.test.ts} +67 -77
- package/src/wirings/{ai-agent/ai-agent-interrupt.ts → agent/agent-interrupt.ts} +5 -5
- package/src/wirings/{ai-agent/ai-agent-memory.test.ts → agent/agent-memory.test.ts} +12 -12
- package/src/wirings/{ai-agent/ai-agent-memory.ts → agent/agent-memory.ts} +36 -36
- package/src/wirings/{ai-agent/ai-agent-model-config.test.ts → agent/agent-model-config.test.ts} +2 -5
- package/src/wirings/{ai-agent/ai-agent-model-config.ts → agent/agent-model-config.ts} +1 -1
- package/src/wirings/{ai-agent/ai-agent-prepare.test.ts → agent/agent-prepare.test.ts} +18 -18
- package/src/wirings/{ai-agent/ai-agent-prepare.ts → agent/agent-prepare.ts} +52 -51
- package/src/wirings/{ai-agent/ai-agent-registry.test.ts → agent/agent-registry.test.ts} +49 -43
- package/src/wirings/{ai-agent/ai-agent-registry.ts → agent/agent-registry.ts} +14 -14
- package/src/wirings/{ai-agent/ai-agent-resume-authorization.test.ts → agent/agent-resume-authorization.test.ts} +18 -18
- package/src/wirings/{ai-agent → agent}/agent-rpc.ts +16 -20
- package/src/wirings/{ai-agent/ai-agent-runner.test.ts → agent/agent-runner.test.ts} +105 -106
- package/src/wirings/{ai-agent/ai-agent-runner.ts → agent/agent-runner.ts} +90 -80
- package/src/wirings/{ai-agent/ai-agent-stream-output-hooks.test.ts → agent/agent-stream-output-hooks.test.ts} +25 -25
- package/src/wirings/{ai-agent/ai-agent-stream.test.ts → agent/agent-stream.test.ts} +147 -143
- package/src/wirings/{ai-agent/ai-agent-stream.ts → agent/agent-stream.ts} +147 -146
- package/src/wirings/{ai-agent/ai-agent-thread-ownership.test.ts → agent/agent-thread-ownership.test.ts} +24 -28
- package/src/wirings/{ai-agent/ai-agent-turn.test.ts → agent/agent-turn.test.ts} +3 -5
- package/src/wirings/{ai-agent/ai-agent-turn.ts → agent/agent-turn.ts} +7 -7
- package/src/wirings/{ai-agent/ai-agent.types.ts → agent/agent.types.ts} +51 -48
- package/src/wirings/agent/index.ts +56 -0
- package/src/wirings/{ai-agent → agent}/voice-input.test.ts +15 -15
- package/src/wirings/{ai-agent → agent}/voice-input.ts +11 -11
- package/src/wirings/{ai-agent → agent}/voice-output.test.ts +23 -23
- package/src/wirings/{ai-agent → agent}/voice-output.ts +11 -11
- package/src/wirings/{ai-scorer/ai-scorer-grade.test.ts → agent-scorer/agent-scorer-grade.test.ts} +8 -8
- package/src/wirings/{ai-scorer/ai-scorer-grade.ts → agent-scorer/agent-scorer-grade.ts} +9 -9
- package/src/wirings/{ai-scorer/ai-scorer-judge.test.ts → agent-scorer/agent-scorer-judge.test.ts} +11 -14
- package/src/wirings/{ai-scorer/ai-scorer-judge.ts → agent-scorer/agent-scorer-judge.ts} +11 -11
- package/src/wirings/{ai-scorer/ai-scorer-live.test.ts → agent-scorer/agent-scorer-live.test.ts} +11 -11
- package/src/wirings/{ai-scorer/ai-scorer-live.ts → agent-scorer/agent-scorer-live.ts} +3 -3
- package/src/wirings/{ai-scorer/ai-scorer-registry.ts → agent-scorer/agent-scorer-registry.ts} +11 -8
- package/src/wirings/{ai-scorer/ai-scorer-sampling.test.ts → agent-scorer/agent-scorer-sampling.test.ts} +1 -1
- package/src/wirings/{ai-scorer/ai-scorer-snapshots.test.ts → agent-scorer/agent-scorer-snapshots.test.ts} +2 -2
- package/src/wirings/{ai-scorer/ai-scorer-snapshots.ts → agent-scorer/agent-scorer-snapshots.ts} +1 -1
- package/src/wirings/{ai-scorer/ai-scorer-worker.test.ts → agent-scorer/agent-scorer-worker.test.ts} +15 -15
- package/src/wirings/{ai-scorer/ai-scorer-worker.ts → agent-scorer/agent-scorer-worker.ts} +9 -7
- package/src/wirings/{ai-scorer/ai-scorer.ts → agent-scorer/agent-scorer.ts} +7 -7
- package/src/wirings/{ai-scorer/ai-scorer.types.ts → agent-scorer/agent-scorer.types.ts} +6 -6
- package/src/wirings/agent-scorer/index.ts +22 -0
- package/src/wirings/channel/channel-rpc.types.ts +2 -2
- package/src/wirings/rpc/rpc-runner.ts +2 -2
- package/src/wirings/rpc/rpc-types.ts +1 -1
- package/src/wirings/virtual-user/prepare-virtual-user-run.ts +1 -1
- package/src/wirings/virtual-user/run-virtual-user.test.ts +2 -2
- package/src/wirings/virtual-user/run-virtual-user.ts +3 -3
- package/src/wirings/virtual-user/virtual-user-agents.ts +1 -1
- package/src/wirings/workflow/run-timeline.ts +1 -1
- package/src/wirings-stay-decoupled.test.ts +3 -3
- package/tsconfig.tsbuildinfo +1 -1
- package/src/wirings/ai-agent/index.ts +0 -65
- package/src/wirings/ai-scorer/index.ts +0 -24
- /package/src/wirings/{ai-agent/ai-agent-utils.ts → agent/agent-utils.ts} +0 -0
- /package/src/wirings/{ai-scorer/ai-scorer-sampling.ts → agent-scorer/agent-scorer-sampling.ts} +0 -0
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
SPOKEN_TURN,
|
|
9
9
|
SPOKEN_TRANSCRIPT,
|
|
10
10
|
} from './voice-input.js'
|
|
11
|
-
import type {
|
|
11
|
+
import type { AgentContentPart, AgentMessage } from './agent.types.js'
|
|
12
12
|
|
|
13
13
|
class ThisDependentRunner {
|
|
14
14
|
private readonly transcript = 'the transcribed spoken words'
|
|
@@ -24,19 +24,19 @@ class ThisDependentRunner {
|
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
const audioMessage = ():
|
|
27
|
+
const audioMessage = (): AgentMessage => ({
|
|
28
28
|
id: 'm1',
|
|
29
29
|
role: 'user',
|
|
30
30
|
content: [
|
|
31
31
|
{ type: 'file', mediaType: 'audio/wav', data: 'AAAA' },
|
|
32
|
-
] as
|
|
32
|
+
] as AgentContentPart[],
|
|
33
33
|
createdAt: new Date(0),
|
|
34
34
|
})
|
|
35
35
|
|
|
36
36
|
describe('voiceInput', () => {
|
|
37
37
|
test('transcribes an audio part by calling the runner with its receiver intact', async () => {
|
|
38
38
|
const mw = voiceInput({ model: 'mock/whisper' })
|
|
39
|
-
const services = {
|
|
39
|
+
const services = { agentRunner: new ThisDependentRunner() }
|
|
40
40
|
|
|
41
41
|
const result = await mw.modifyInput!(services as any, {
|
|
42
42
|
messages: [audioMessage()],
|
|
@@ -45,7 +45,7 @@ describe('voiceInput', () => {
|
|
|
45
45
|
})
|
|
46
46
|
|
|
47
47
|
const last = result.messages[result.messages.length - 1]!
|
|
48
|
-
const parts = last.content as
|
|
48
|
+
const parts = last.content as AgentContentPart[]
|
|
49
49
|
assert.equal(parts.length, 1)
|
|
50
50
|
assert.equal(parts[0]!.type, 'text')
|
|
51
51
|
assert.equal(
|
|
@@ -57,8 +57,8 @@ describe('voiceInput', () => {
|
|
|
57
57
|
|
|
58
58
|
test('leaves the message untouched when there is no audio part', async () => {
|
|
59
59
|
const mw = voiceInput({ model: 'mock/whisper' })
|
|
60
|
-
const services = {
|
|
61
|
-
const messages:
|
|
60
|
+
const services = { agentRunner: new ThisDependentRunner() }
|
|
61
|
+
const messages: AgentMessage[] = [
|
|
62
62
|
{
|
|
63
63
|
id: 'm1',
|
|
64
64
|
role: 'user',
|
|
@@ -78,7 +78,7 @@ describe('voiceInput', () => {
|
|
|
78
78
|
|
|
79
79
|
test('throws when an audio part is present but no model is configured', async () => {
|
|
80
80
|
const mw = voiceInput({})
|
|
81
|
-
const services = {
|
|
81
|
+
const services = { agentRunner: new ThisDependentRunner() }
|
|
82
82
|
|
|
83
83
|
await assert.rejects(
|
|
84
84
|
() =>
|
|
@@ -107,7 +107,7 @@ describe('voiceInput', () => {
|
|
|
107
107
|
|
|
108
108
|
await assert.rejects(
|
|
109
109
|
() =>
|
|
110
|
-
mw.modifyInput!({
|
|
110
|
+
mw.modifyInput!({ agentRunner: silent } as any, {
|
|
111
111
|
messages: [audioMessage()],
|
|
112
112
|
instructions: 'sys',
|
|
113
113
|
shared: {},
|
|
@@ -130,13 +130,13 @@ describe('voiceInput', () => {
|
|
|
130
130
|
}
|
|
131
131
|
const mw = voiceInput({ model: 'mock/asr' })
|
|
132
132
|
|
|
133
|
-
const result = await mw.modifyInput!({
|
|
133
|
+
const result = await mw.modifyInput!({ agentRunner: spaced } as any, {
|
|
134
134
|
messages: [audioMessage()],
|
|
135
135
|
instructions: 'sys',
|
|
136
136
|
shared: {},
|
|
137
137
|
})
|
|
138
138
|
|
|
139
|
-
const parts = result.messages.at(-1)!.content as
|
|
139
|
+
const parts = result.messages.at(-1)!.content as AgentContentPart[]
|
|
140
140
|
assert.equal(
|
|
141
141
|
(parts[0] as { text: string }).text,
|
|
142
142
|
' spacing the provider chose '
|
|
@@ -166,7 +166,7 @@ describe('readsAsNonSpeech', () => {
|
|
|
166
166
|
const mw = voiceInput({ model: 'mock/whisper' })
|
|
167
167
|
const shared: Record<string, unknown> = {}
|
|
168
168
|
|
|
169
|
-
await mw.modifyInput!({
|
|
169
|
+
await mw.modifyInput!({ agentRunner: new ThisDependentRunner() } as any, {
|
|
170
170
|
messages: [audioMessage()],
|
|
171
171
|
instructions: 'sys',
|
|
172
172
|
shared,
|
|
@@ -179,7 +179,7 @@ describe('readsAsNonSpeech', () => {
|
|
|
179
179
|
const mw = voiceInput({ model: 'mock/whisper' })
|
|
180
180
|
const shared: Record<string, unknown> = {}
|
|
181
181
|
|
|
182
|
-
await mw.modifyInput!({
|
|
182
|
+
await mw.modifyInput!({ agentRunner: new ThisDependentRunner() } as any, {
|
|
183
183
|
messages: [{ role: 'user', content: 'typed' } as any],
|
|
184
184
|
instructions: 'sys',
|
|
185
185
|
shared,
|
|
@@ -194,7 +194,7 @@ describe('readsAsNonSpeech', () => {
|
|
|
194
194
|
const mw = voiceInput({ model: 'mock/whisper' })
|
|
195
195
|
const shared: Record<string, unknown> = {}
|
|
196
196
|
|
|
197
|
-
await mw.modifyInput!({
|
|
197
|
+
await mw.modifyInput!({ agentRunner: new ThisDependentRunner() } as any, {
|
|
198
198
|
messages: [audioMessage()],
|
|
199
199
|
instructions: 'sys',
|
|
200
200
|
shared,
|
|
@@ -209,7 +209,7 @@ describe('readsAsNonSpeech', () => {
|
|
|
209
209
|
const mw = voiceInput({ model: 'mock/whisper' })
|
|
210
210
|
const shared: Record<string, unknown> = {}
|
|
211
211
|
|
|
212
|
-
await mw.modifyInput!({
|
|
212
|
+
await mw.modifyInput!({ agentRunner: new ThisDependentRunner() } as any, {
|
|
213
213
|
messages: [{ role: 'user', content: 'typed' } as any],
|
|
214
214
|
instructions: 'sys',
|
|
215
215
|
shared,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import {
|
|
1
|
+
import type { AgentRunnerService } from '../../services/agent-runner-service.js'
|
|
2
|
+
import { pikkuAgentMiddleware } from '../../types/core.types.js'
|
|
3
3
|
import { safeFetch } from '../../utils/safe-fetch.js'
|
|
4
|
-
import type {
|
|
4
|
+
import type { AgentContentPart } from './agent.types.js'
|
|
5
5
|
|
|
6
6
|
function base64ToUint8Array(base64: string): Uint8Array {
|
|
7
7
|
const binary = atob(base64)
|
|
@@ -97,19 +97,19 @@ export const voiceInput = (config?: {
|
|
|
97
97
|
model?: string
|
|
98
98
|
allowedAudioHosts?: string[]
|
|
99
99
|
}) =>
|
|
100
|
-
|
|
100
|
+
pikkuAgentMiddleware({
|
|
101
101
|
modifyInput: async (services, { messages, instructions, shared }) => {
|
|
102
|
-
const
|
|
102
|
+
const agentRunner = (
|
|
103
103
|
services as {
|
|
104
|
-
|
|
104
|
+
agentRunner?: AgentRunnerService
|
|
105
105
|
}
|
|
106
|
-
).
|
|
107
|
-
if (!
|
|
106
|
+
).agentRunner
|
|
107
|
+
if (!agentRunner?.transcribe) return { messages, instructions }
|
|
108
108
|
|
|
109
109
|
const last = messages[messages.length - 1]
|
|
110
110
|
const parts =
|
|
111
111
|
last?.role === 'user' && typeof last.content !== 'string'
|
|
112
|
-
? (last.content as
|
|
112
|
+
? (last.content as AgentContentPart[] | undefined)
|
|
113
113
|
: undefined
|
|
114
114
|
|
|
115
115
|
const hasAudio = !!parts?.some(
|
|
@@ -121,7 +121,7 @@ export const voiceInput = (config?: {
|
|
|
121
121
|
shared[SPOKEN_TURN] = hasAudio
|
|
122
122
|
if (!hasAudio || !parts) return { messages, instructions }
|
|
123
123
|
|
|
124
|
-
const updatedContent:
|
|
124
|
+
const updatedContent: AgentContentPart[] = []
|
|
125
125
|
const heard: string[] = []
|
|
126
126
|
for (const p of parts) {
|
|
127
127
|
if (!(p.type === 'file' && p.mediaType?.startsWith('audio/'))) {
|
|
@@ -139,7 +139,7 @@ export const voiceInput = (config?: {
|
|
|
139
139
|
if (audioData.byteLength > MAX_AUDIO_SIZE) {
|
|
140
140
|
throw new Error('Audio file exceeds maximum size')
|
|
141
141
|
}
|
|
142
|
-
const result = await
|
|
142
|
+
const result = await agentRunner.transcribe({
|
|
143
143
|
model: config.model,
|
|
144
144
|
audio: audioData,
|
|
145
145
|
...(config.language
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
unspeakableScripts,
|
|
7
7
|
voiceForText,
|
|
8
8
|
} from './voice-output.js'
|
|
9
|
-
import type {
|
|
9
|
+
import type { AgentStreamEvent } from './agent.types.js'
|
|
10
10
|
import { SPOKEN_TURN } from './voice-input.js'
|
|
11
11
|
|
|
12
12
|
const KOKORO_SCRIPTS = ['latin', 'devanagari', 'han', 'kana']
|
|
@@ -28,7 +28,7 @@ const deferred = () => {
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
/**
|
|
31
|
-
* Drives the hook exactly as `
|
|
31
|
+
* Drives the hook exactly as `agent-stream` does, so `out` is the order the
|
|
32
32
|
* client actually sees — returned events and `emit`ed ones interleaved on the
|
|
33
33
|
* one channel.
|
|
34
34
|
*/
|
|
@@ -38,9 +38,9 @@ const createStream = (
|
|
|
38
38
|
shared: Record<string, unknown> = {}
|
|
39
39
|
) => {
|
|
40
40
|
const state: Record<string, unknown> = {}
|
|
41
|
-
const allEvents:
|
|
42
|
-
const out:
|
|
43
|
-
const next = async (event:
|
|
41
|
+
const allEvents: AgentStreamEvent[] = []
|
|
42
|
+
const out: AgentStreamEvent[] = []
|
|
43
|
+
const next = async (event: AgentStreamEvent) => {
|
|
44
44
|
out.push(event)
|
|
45
45
|
}
|
|
46
46
|
return {
|
|
@@ -50,7 +50,7 @@ const createStream = (
|
|
|
50
50
|
out
|
|
51
51
|
.filter((event) => event.type === 'audio-delta')
|
|
52
52
|
.map((event) => atob((event as { data: string }).data)),
|
|
53
|
-
send: async (event:
|
|
53
|
+
send: async (event: AgentStreamEvent) => {
|
|
54
54
|
allEvents.push(event)
|
|
55
55
|
const result = await mw.modifyOutputStream!(services as any, {
|
|
56
56
|
event,
|
|
@@ -81,7 +81,7 @@ describe('voiceOutput', () => {
|
|
|
81
81
|
// provider takes.
|
|
82
82
|
const gate = deferred()
|
|
83
83
|
const services = {
|
|
84
|
-
|
|
84
|
+
agentRunner: {
|
|
85
85
|
generateSpeech: async ({ text }: { text: string }) => {
|
|
86
86
|
await gate.promise
|
|
87
87
|
return speechFor(text)
|
|
@@ -99,7 +99,7 @@ describe('voiceOutput', () => {
|
|
|
99
99
|
test('speaks sentences in order even when the later one is ready first', async () => {
|
|
100
100
|
const slow = deferred()
|
|
101
101
|
const services = {
|
|
102
|
-
|
|
102
|
+
agentRunner: {
|
|
103
103
|
generateSpeech: async ({ text }: { text: string }) => {
|
|
104
104
|
// A short sentence after a long one routinely finishes first.
|
|
105
105
|
if (text.includes('first')) await slow.promise
|
|
@@ -120,7 +120,7 @@ describe('voiceOutput', () => {
|
|
|
120
120
|
test('holds done until everything queued has been spoken', async () => {
|
|
121
121
|
const gate = deferred()
|
|
122
122
|
const services = {
|
|
123
|
-
|
|
123
|
+
agentRunner: {
|
|
124
124
|
generateSpeech: async ({ text }: { text: string }) => {
|
|
125
125
|
await gate.promise
|
|
126
126
|
return speechFor(text)
|
|
@@ -148,7 +148,7 @@ describe('voiceOutput', () => {
|
|
|
148
148
|
|
|
149
149
|
test('speaks a trailing fragment the model never punctuated', async () => {
|
|
150
150
|
const services = {
|
|
151
|
-
|
|
151
|
+
agentRunner: {
|
|
152
152
|
generateSpeech: async ({ text }: { text: string }) => speechFor(text),
|
|
153
153
|
},
|
|
154
154
|
}
|
|
@@ -162,7 +162,7 @@ describe('voiceOutput', () => {
|
|
|
162
162
|
|
|
163
163
|
test('says nothing extra when the reply ended on a boundary', async () => {
|
|
164
164
|
const services = {
|
|
165
|
-
|
|
165
|
+
agentRunner: {
|
|
166
166
|
generateSpeech: async ({ text }: { text: string }) => speechFor(text),
|
|
167
167
|
},
|
|
168
168
|
}
|
|
@@ -178,7 +178,7 @@ describe('voiceOutput', () => {
|
|
|
178
178
|
const errors: string[] = []
|
|
179
179
|
const services = {
|
|
180
180
|
logger: { error: (message: string) => errors.push(message) },
|
|
181
|
-
|
|
181
|
+
agentRunner: {
|
|
182
182
|
generateSpeech: async ({ text }: { text: string }) => {
|
|
183
183
|
if (text.includes('boom')) throw new Error('provider exploded')
|
|
184
184
|
return speechFor(text)
|
|
@@ -200,7 +200,7 @@ describe('voiceOutput', () => {
|
|
|
200
200
|
|
|
201
201
|
test('stays out of the way when the runner cannot speak at all', async () => {
|
|
202
202
|
const stream = createStream(voiceOutput({ model: 'mock/tts' }), {
|
|
203
|
-
|
|
203
|
+
agentRunner: {},
|
|
204
204
|
})
|
|
205
205
|
await stream.send({ type: 'text-delta', text: 'Hello.' } as any)
|
|
206
206
|
await stream.send({ type: 'done' } as any)
|
|
@@ -216,7 +216,7 @@ describe('voiceOutput', () => {
|
|
|
216
216
|
// is the only honest option.
|
|
217
217
|
const asked: string[] = []
|
|
218
218
|
const services = {
|
|
219
|
-
|
|
219
|
+
agentRunner: {
|
|
220
220
|
generateSpeech: async ({ text }: { text: string }) => {
|
|
221
221
|
asked.push(text)
|
|
222
222
|
return speechFor(text)
|
|
@@ -241,7 +241,7 @@ describe('voiceOutput', () => {
|
|
|
241
241
|
|
|
242
242
|
test('a reply says it once, however many sentences it is', async () => {
|
|
243
243
|
const services = {
|
|
244
|
-
|
|
244
|
+
agentRunner: {
|
|
245
245
|
generateSpeech: async ({ text }: { text: string }) => speechFor(text),
|
|
246
246
|
},
|
|
247
247
|
}
|
|
@@ -264,7 +264,7 @@ describe('voiceOutput', () => {
|
|
|
264
264
|
test('a bilingual reply still speaks the half it can', async () => {
|
|
265
265
|
const asked: string[] = []
|
|
266
266
|
const services = {
|
|
267
|
-
|
|
267
|
+
agentRunner: {
|
|
268
268
|
generateSpeech: async ({ text }: { text: string }) => {
|
|
269
269
|
asked.push(text.trim())
|
|
270
270
|
return speechFor(text)
|
|
@@ -289,7 +289,7 @@ describe('voiceOutput', () => {
|
|
|
289
289
|
// characters out for three times the duration.
|
|
290
290
|
const asked: Array<{ text: string; voice?: string }> = []
|
|
291
291
|
const services = {
|
|
292
|
-
|
|
292
|
+
agentRunner: {
|
|
293
293
|
generateSpeech: async ({
|
|
294
294
|
text,
|
|
295
295
|
voice,
|
|
@@ -323,7 +323,7 @@ describe('voiceOutput', () => {
|
|
|
323
323
|
// — it is billed per sentence, on every turn.
|
|
324
324
|
const asked: string[] = []
|
|
325
325
|
const services = {
|
|
326
|
-
|
|
326
|
+
agentRunner: {
|
|
327
327
|
generateSpeech: async ({ text }: { text: string }) => {
|
|
328
328
|
asked.push(text)
|
|
329
329
|
return speechFor(text)
|
|
@@ -344,7 +344,7 @@ describe('voiceOutput', () => {
|
|
|
344
344
|
test('a spoken turn is answered aloud', async () => {
|
|
345
345
|
const asked: string[] = []
|
|
346
346
|
const services = {
|
|
347
|
-
|
|
347
|
+
agentRunner: {
|
|
348
348
|
generateSpeech: async ({ text }: { text: string }) => {
|
|
349
349
|
asked.push(text)
|
|
350
350
|
return speechFor(text)
|
|
@@ -365,7 +365,7 @@ describe('voiceOutput', () => {
|
|
|
365
365
|
// Read-aloud modes exist, and for them speech is not a reply to speech.
|
|
366
366
|
const asked: string[] = []
|
|
367
367
|
const services = {
|
|
368
|
-
|
|
368
|
+
agentRunner: {
|
|
369
369
|
generateSpeech: async ({ text }: { text: string }) => {
|
|
370
370
|
asked.push(text)
|
|
371
371
|
return speechFor(text)
|
|
@@ -389,7 +389,7 @@ describe('voiceOutput', () => {
|
|
|
389
389
|
// evidence the turn was typed and the pre-existing behaviour stands.
|
|
390
390
|
const asked: string[] = []
|
|
391
391
|
const services = {
|
|
392
|
-
|
|
392
|
+
agentRunner: {
|
|
393
393
|
generateSpeech: async ({ text }: { text: string }) => {
|
|
394
394
|
asked.push(text)
|
|
395
395
|
return speechFor(text)
|
|
@@ -407,7 +407,7 @@ describe('voiceOutput', () => {
|
|
|
407
407
|
test('a script with no voice mapped is still refused, not mis-voiced', async () => {
|
|
408
408
|
const asked: string[] = []
|
|
409
409
|
const services = {
|
|
410
|
-
|
|
410
|
+
agentRunner: {
|
|
411
411
|
generateSpeech: async ({ text }: { text: string }) => {
|
|
412
412
|
asked.push(text)
|
|
413
413
|
return speechFor(text)
|
|
@@ -432,7 +432,7 @@ describe('voiceOutput', () => {
|
|
|
432
432
|
test('no declared scripts means every model is trusted with everything', async () => {
|
|
433
433
|
const asked: string[] = []
|
|
434
434
|
const services = {
|
|
435
|
-
|
|
435
|
+
agentRunner: {
|
|
436
436
|
generateSpeech: async ({ text }: { text: string }) => {
|
|
437
437
|
asked.push(text.trim())
|
|
438
438
|
return speechFor(text)
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import {
|
|
1
|
+
import type { AgentRunnerService } from '../../services/agent-runner-service.js'
|
|
2
|
+
import { pikkuAgentMiddleware } from '../../types/core.types.js'
|
|
3
3
|
import { SPOKEN_TURN } from './voice-input.js'
|
|
4
4
|
|
|
5
|
-
type VoiceOutputState = {
|
|
5
|
+
export type VoiceOutputState = {
|
|
6
6
|
textBuffer?: string
|
|
7
7
|
/**
|
|
8
8
|
* The audio emitted so far, as a chain.
|
|
@@ -129,7 +129,7 @@ export const voiceForText = (
|
|
|
129
129
|
}
|
|
130
130
|
|
|
131
131
|
async function synthesizeAudio(
|
|
132
|
-
|
|
132
|
+
agentRunner: AgentRunnerService,
|
|
133
133
|
input: {
|
|
134
134
|
model: string
|
|
135
135
|
text: string
|
|
@@ -141,7 +141,7 @@ async function synthesizeAudio(
|
|
|
141
141
|
abortSignal?: AbortSignal
|
|
142
142
|
}
|
|
143
143
|
): Promise<{ bytes: Uint8Array; format: string }> {
|
|
144
|
-
const result = await
|
|
144
|
+
const result = await agentRunner.generateSpeech?.({
|
|
145
145
|
model: input.model,
|
|
146
146
|
text: input.text,
|
|
147
147
|
voice: input.voice,
|
|
@@ -153,7 +153,7 @@ async function synthesizeAudio(
|
|
|
153
153
|
})
|
|
154
154
|
if (!result) {
|
|
155
155
|
throw new Error(
|
|
156
|
-
'voiceOutput requires an
|
|
156
|
+
'voiceOutput requires an agentRunner with generateSpeech support'
|
|
157
157
|
)
|
|
158
158
|
}
|
|
159
159
|
return {
|
|
@@ -195,16 +195,16 @@ export const voiceOutput = (config?: {
|
|
|
195
195
|
*/
|
|
196
196
|
always?: boolean
|
|
197
197
|
}) =>
|
|
198
|
-
|
|
198
|
+
pikkuAgentMiddleware<VoiceOutputState>({
|
|
199
199
|
modifyOutputStream: async (
|
|
200
200
|
services,
|
|
201
201
|
{ event, state, shared, emit, signal }
|
|
202
202
|
) => {
|
|
203
|
-
const {
|
|
204
|
-
|
|
203
|
+
const { agentRunner, logger } = services as {
|
|
204
|
+
agentRunner?: AgentRunnerService
|
|
205
205
|
logger?: { error: (message: string) => void }
|
|
206
206
|
}
|
|
207
|
-
if (!
|
|
207
|
+
if (!agentRunner?.generateSpeech) return event
|
|
208
208
|
|
|
209
209
|
// knowledge: decisions/internals/voice-output-speaks-unless-voice-input-explicitly-says-otherwise.md
|
|
210
210
|
if (!config?.always && shared[SPOKEN_TURN] === false) return event
|
|
@@ -246,7 +246,7 @@ export const voiceOutput = (config?: {
|
|
|
246
246
|
// Settled into a value rather than left as a rejectable promise: it
|
|
247
247
|
// sits unobserved until the chain reaches it, and an unhandled
|
|
248
248
|
// rejection in that window would take the process down.
|
|
249
|
-
const synthesis = synthesizeAudio(
|
|
249
|
+
const synthesis = synthesizeAudio(agentRunner, {
|
|
250
250
|
model: config.model,
|
|
251
251
|
text,
|
|
252
252
|
voice,
|
package/src/wirings/{ai-scorer/ai-scorer-grade.test.ts → agent-scorer/agent-scorer-grade.test.ts}
RENAMED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { beforeEach, describe, test } from 'node:test'
|
|
2
2
|
import assert from 'node:assert/strict'
|
|
3
3
|
import { pikkuState, resetPikkuState } from '../../pikku-state.js'
|
|
4
|
-
import { gradeRun } from './
|
|
5
|
-
import {
|
|
6
|
-
import type { ScoreJob } from './
|
|
4
|
+
import { gradeRun } from './agent-scorer-grade.js'
|
|
5
|
+
import { pikkuAgentJudge, pikkuAgentScorer } from './agent-scorer.js'
|
|
6
|
+
import type { ScoreJob } from './agent-scorer.types.js'
|
|
7
7
|
|
|
8
8
|
const job = (overrides: Partial<ScoreJob> = {}): ScoreJob => ({
|
|
9
9
|
scorerName: 'correctness',
|
|
@@ -22,7 +22,7 @@ describe('gradeRun', () => {
|
|
|
22
22
|
test('a scenario grade is returned and not written to the live record', async () => {
|
|
23
23
|
pikkuState(null, 'agent', 'scorers').set(
|
|
24
24
|
'correctness',
|
|
25
|
-
|
|
25
|
+
pikkuAgentScorer({
|
|
26
26
|
name: 'correctness',
|
|
27
27
|
description: 'Matches the answer key',
|
|
28
28
|
requiresReference: true,
|
|
@@ -36,7 +36,7 @@ describe('gradeRun', () => {
|
|
|
36
36
|
const result = await gradeRun(
|
|
37
37
|
job({ reference: 'Paris' }),
|
|
38
38
|
{
|
|
39
|
-
|
|
39
|
+
agentRunState: {
|
|
40
40
|
saveScore: async () => {
|
|
41
41
|
saves++
|
|
42
42
|
},
|
|
@@ -52,7 +52,7 @@ describe('gradeRun', () => {
|
|
|
52
52
|
test('a reference-based scorer sees the answer key it was given', async () => {
|
|
53
53
|
pikkuState(null, 'agent', 'scorers').set(
|
|
54
54
|
'correctness',
|
|
55
|
-
|
|
55
|
+
pikkuAgentScorer({
|
|
56
56
|
name: 'correctness',
|
|
57
57
|
description: 'Matches the answer key',
|
|
58
58
|
requiresReference: true,
|
|
@@ -76,7 +76,7 @@ describe('gradeRun', () => {
|
|
|
76
76
|
test('a judge grades without a score function, and reports the model it used', async () => {
|
|
77
77
|
pikkuState(null, 'agent', 'scorers').set(
|
|
78
78
|
'helpfulness',
|
|
79
|
-
|
|
79
|
+
pikkuAgentJudge({
|
|
80
80
|
name: 'helpfulness',
|
|
81
81
|
description: 'Is the answer useful',
|
|
82
82
|
model: 'claude-opus-5',
|
|
@@ -87,7 +87,7 @@ describe('gradeRun', () => {
|
|
|
87
87
|
const result = await gradeRun(
|
|
88
88
|
job({ scorerName: 'helpfulness' }),
|
|
89
89
|
{
|
|
90
|
-
|
|
90
|
+
agentRunner: {
|
|
91
91
|
run: async () => ({
|
|
92
92
|
object: { score: 0.75, reason: 'Correct but terse.' },
|
|
93
93
|
usage: { inputTokens: 80, outputTokens: 20 },
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { runJudge } from './
|
|
2
|
-
import {
|
|
3
|
-
import type { ScoreJob, ScorerOutput } from './
|
|
1
|
+
import { runJudge } from './agent-scorer-judge.js'
|
|
2
|
+
import { resolveAgentScorer } from './agent-scorer-registry.js'
|
|
3
|
+
import type { ScoreJob, ScorerOutput } from './agent-scorer.types.js'
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Grade one run with one scorer.
|
|
@@ -16,8 +16,8 @@ import type { ScoreJob, ScorerOutput } from './ai-scorer.types.js'
|
|
|
16
16
|
export const gradeRun = async (
|
|
17
17
|
job: ScoreJob,
|
|
18
18
|
services: {
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
agentRunner?: unknown
|
|
20
|
+
agentRunState?: {
|
|
21
21
|
saveScore: (score: {
|
|
22
22
|
runId: string
|
|
23
23
|
scorerName: string
|
|
@@ -30,19 +30,19 @@ export const gradeRun = async (
|
|
|
30
30
|
options: { persist: boolean }
|
|
31
31
|
): Promise<ScorerOutput> => {
|
|
32
32
|
const { scorerName, ...input } = job
|
|
33
|
-
const scorer =
|
|
33
|
+
const scorer = resolveAgentScorer(scorerName)
|
|
34
34
|
|
|
35
35
|
const result = scorer.score
|
|
36
36
|
? await scorer.score(input, services)
|
|
37
|
-
: await runJudge(scorer, input, services.
|
|
37
|
+
: await runJudge(scorer, input, services.agentRunner as never)
|
|
38
38
|
|
|
39
39
|
if (options.persist) {
|
|
40
|
-
if (!services.
|
|
40
|
+
if (!services.agentRunState) {
|
|
41
41
|
throw new Error(
|
|
42
42
|
`AI run state service not initialized: cannot record the '${scorerName}' grade of run ${job.runId}`
|
|
43
43
|
)
|
|
44
44
|
}
|
|
45
|
-
await services.
|
|
45
|
+
await services.agentRunState.saveScore({
|
|
46
46
|
runId: job.runId,
|
|
47
47
|
scorerName,
|
|
48
48
|
score: result.score,
|
package/src/wirings/{ai-scorer/ai-scorer-judge.test.ts → agent-scorer/agent-scorer-judge.test.ts}
RENAMED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { describe, test } from 'node:test'
|
|
2
2
|
import assert from 'node:assert/strict'
|
|
3
|
-
import { buildJudgePrompt, runJudge } from './
|
|
4
|
-
import {
|
|
5
|
-
import type { ScorerInput } from './
|
|
6
|
-
import type {
|
|
3
|
+
import { buildJudgePrompt, runJudge } from './agent-scorer-judge.js'
|
|
4
|
+
import { pikkuAgentJudge } from './agent-scorer.js'
|
|
5
|
+
import type { ScorerInput } from './agent-scorer.types.js'
|
|
6
|
+
import type { AgentRunnerService } from '../../services/agent-runner-service.js'
|
|
7
7
|
|
|
8
8
|
const input = (overrides: Partial<ScorerInput> = {}): ScorerInput => ({
|
|
9
9
|
runId: 'run-1',
|
|
@@ -15,20 +15,17 @@ const input = (overrides: Partial<ScorerInput> = {}): ScorerInput => ({
|
|
|
15
15
|
...overrides,
|
|
16
16
|
})
|
|
17
17
|
|
|
18
|
-
const runner = (
|
|
19
|
-
object: unknown,
|
|
20
|
-
seen?: { params: any }
|
|
21
|
-
): AIAgentRunnerService =>
|
|
18
|
+
const runner = (object: unknown, seen?: { params: any }): AgentRunnerService =>
|
|
22
19
|
({
|
|
23
20
|
run: async (params: any) => {
|
|
24
21
|
if (seen) seen.params = params
|
|
25
22
|
return { object, usage: { inputTokens: 100, outputTokens: 20 } }
|
|
26
23
|
},
|
|
27
|
-
}) as unknown as
|
|
24
|
+
}) as unknown as AgentRunnerService
|
|
28
25
|
|
|
29
26
|
describe('buildJudgePrompt', () => {
|
|
30
27
|
test('shows the answer key to a reference-based judge', () => {
|
|
31
|
-
const scorer =
|
|
28
|
+
const scorer = pikkuAgentJudge({
|
|
32
29
|
name: 'correctness',
|
|
33
30
|
description: 'Is the answer right',
|
|
34
31
|
model: 'claude-opus-5',
|
|
@@ -45,7 +42,7 @@ describe('buildJudgePrompt', () => {
|
|
|
45
42
|
})
|
|
46
43
|
|
|
47
44
|
test('withholds a reference section when there is no answer key', () => {
|
|
48
|
-
const scorer =
|
|
45
|
+
const scorer = pikkuAgentJudge({
|
|
49
46
|
name: 'helpfulness',
|
|
50
47
|
description: 'Is the answer useful',
|
|
51
48
|
model: 'claude-opus-5',
|
|
@@ -59,7 +56,7 @@ describe('buildJudgePrompt', () => {
|
|
|
59
56
|
})
|
|
60
57
|
|
|
61
58
|
test('a scorer that supplies its own prompt replaces the framing entirely', () => {
|
|
62
|
-
const scorer =
|
|
59
|
+
const scorer = pikkuAgentJudge({
|
|
63
60
|
name: 'custom',
|
|
64
61
|
description: 'Custom framing',
|
|
65
62
|
model: 'claude-opus-5',
|
|
@@ -72,7 +69,7 @@ describe('buildJudgePrompt', () => {
|
|
|
72
69
|
})
|
|
73
70
|
|
|
74
71
|
describe('runJudge', () => {
|
|
75
|
-
const helpfulness =
|
|
72
|
+
const helpfulness = pikkuAgentJudge({
|
|
76
73
|
name: 'helpfulness',
|
|
77
74
|
description: 'Is the answer useful',
|
|
78
75
|
model: 'claude-opus-5',
|
|
@@ -127,7 +124,7 @@ describe('runJudge', () => {
|
|
|
127
124
|
})
|
|
128
125
|
|
|
129
126
|
test('refuses to grade a reference-based judge with no answer key', async () => {
|
|
130
|
-
const correctness =
|
|
127
|
+
const correctness = pikkuAgentJudge({
|
|
131
128
|
name: 'correctness',
|
|
132
129
|
description: 'Is the answer right',
|
|
133
130
|
model: 'claude-opus-5',
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {
|
|
3
|
-
import { randomUUID } from '../
|
|
1
|
+
import type { AgentRunnerService } from '../../services/agent-runner-service.js'
|
|
2
|
+
import type { AgentMessage } from '../agent/agent.types.js'
|
|
3
|
+
import { randomUUID } from '../agent/agent-utils.js'
|
|
4
4
|
import type {
|
|
5
|
-
|
|
5
|
+
PikkuAgentScorer,
|
|
6
6
|
ScorerInput,
|
|
7
7
|
ScorerJudgeConfig,
|
|
8
8
|
ScorerOutput,
|
|
9
|
-
} from './
|
|
9
|
+
} from './agent-scorer.types.js'
|
|
10
10
|
|
|
11
11
|
const JUDGE_OUTPUT_SCHEMA = {
|
|
12
12
|
type: 'object',
|
|
@@ -69,17 +69,17 @@ const normalizeScore = (scorerName: string, value: unknown): number => {
|
|
|
69
69
|
* reliably honoured.
|
|
70
70
|
*/
|
|
71
71
|
export const runJudge = async (
|
|
72
|
-
scorer:
|
|
72
|
+
scorer: PikkuAgentScorer<any>,
|
|
73
73
|
input: ScorerInput,
|
|
74
|
-
|
|
74
|
+
agentRunner: AgentRunnerService | undefined
|
|
75
75
|
): Promise<ScorerOutput> => {
|
|
76
76
|
const judge = scorer.judge
|
|
77
77
|
if (!judge) {
|
|
78
78
|
throw new Error(`Scorer '${scorer.name}' is not a judge`)
|
|
79
79
|
}
|
|
80
|
-
if (!
|
|
80
|
+
if (!agentRunner) {
|
|
81
81
|
throw new Error(
|
|
82
|
-
`Judge '${scorer.name}' needs an AI provider, but no
|
|
82
|
+
`Judge '${scorer.name}' needs an AI provider, but no agentRunner is registered in this process. ` +
|
|
83
83
|
`A worker deployed apart from the API has to register one to run the slow scoring lane.`
|
|
84
84
|
)
|
|
85
85
|
}
|
|
@@ -89,7 +89,7 @@ export const runJudge = async (
|
|
|
89
89
|
)
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
-
const messages:
|
|
92
|
+
const messages: AgentMessage[] = [
|
|
93
93
|
{
|
|
94
94
|
id: randomUUID(),
|
|
95
95
|
role: 'user',
|
|
@@ -98,7 +98,7 @@ export const runJudge = async (
|
|
|
98
98
|
},
|
|
99
99
|
]
|
|
100
100
|
|
|
101
|
-
const result = await
|
|
101
|
+
const result = await agentRunner.run({
|
|
102
102
|
model: judge.model,
|
|
103
103
|
instructions: judge.goal,
|
|
104
104
|
messages,
|