@pikku/core 0.12.141 → 0.12.143

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.
Files changed (251) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/dist/errors/errors.d.ts +1 -1
  3. package/dist/errors/errors.js +1 -1
  4. package/dist/function/function-meta.types.d.ts +6 -6
  5. package/dist/function/functions.types.d.ts +2 -2
  6. package/dist/services/audit-service.d.ts +4 -4
  7. package/dist/services/feature-flag-service.d.ts +3 -3
  8. package/dist/services/{http-personas.d.ts → http-virtual-users.d.ts} +25 -47
  9. package/dist/services/{http-personas.js → http-virtual-users.js} +29 -53
  10. package/dist/services/in-memory-queue-service.d.ts +8 -1
  11. package/dist/services/in-memory-queue-service.js +67 -0
  12. package/dist/services/incoming-webhook-service.d.ts +2 -0
  13. package/dist/services/incoming-webhook-service.js +4 -0
  14. package/dist/services/index.d.ts +2 -2
  15. package/dist/services/index.js +1 -1
  16. package/dist/services/meta-service.d.ts +6 -6
  17. package/dist/services/meta-service.js +8 -8
  18. package/dist/{wirings/workflow → services}/scenario-cookie-jar.d.ts +2 -0
  19. package/dist/{wirings/workflow → services}/scenario-cookie-jar.js +18 -14
  20. package/dist/services/scheduler-service.d.ts +3 -0
  21. package/dist/services/scheduler-service.js +4 -0
  22. package/dist/services/system-role-guard.d.ts +1 -1
  23. package/dist/services/virtual-user-sign-in.d.ts +52 -0
  24. package/dist/services/virtual-user-sign-in.js +80 -0
  25. package/dist/services/virtual-user-statement.d.ts +31 -0
  26. package/dist/services/virtual-user-statement.js +24 -0
  27. package/dist/services/{personas-service.d.ts → virtual-users-service.d.ts} +25 -23
  28. package/dist/services/{personas-service.js → virtual-users-service.js} +3 -3
  29. package/dist/types/core.types.d.ts +11 -11
  30. package/dist/wirings/queue/index.d.ts +1 -1
  31. package/dist/wirings/queue/queue.types.d.ts +21 -0
  32. package/dist/wirings/queue/signed-queue-service.d.ts +4 -1
  33. package/dist/wirings/queue/signed-queue-service.js +3 -0
  34. package/dist/wirings/role/define-system-role.d.ts +1 -1
  35. package/dist/wirings/role/define-system-role.js +1 -1
  36. package/dist/wirings/scheduler/index.d.ts +1 -1
  37. package/dist/wirings/scheduler/scheduler.types.d.ts +12 -0
  38. package/dist/wirings/{actor-flow/actor-flow.types.d.ts → virtual-user/conversation/conversation.types.d.ts} +5 -5
  39. package/dist/wirings/virtual-user/conversation/index.d.ts +2 -0
  40. package/dist/wirings/virtual-user/conversation/run-conversation.d.ts +36 -0
  41. package/dist/wirings/{actor-flow → virtual-user/conversation}/run-conversation.js +30 -30
  42. package/dist/wirings/virtual-user/define-virtual-users.d.ts +32 -0
  43. package/dist/wirings/{persona/define-personas.js → virtual-user/define-virtual-users.js} +9 -9
  44. package/dist/wirings/virtual-user/index.d.ts +30 -7
  45. package/dist/wirings/virtual-user/index.js +23 -4
  46. package/dist/wirings/virtual-user/prepare-virtual-user-run.d.ts +8 -8
  47. package/dist/wirings/virtual-user/prepare-virtual-user-run.js +9 -9
  48. package/dist/wirings/virtual-user/run-virtual-user.d.ts +6 -6
  49. package/dist/wirings/virtual-user/run-virtual-user.js +10 -10
  50. package/dist/wirings/{persona/validate-personas.d.ts → virtual-user/validate-virtual-users.d.ts} +11 -11
  51. package/dist/wirings/{persona/validate-personas.js → virtual-user/validate-virtual-users.js} +24 -24
  52. package/dist/wirings/virtual-user/virtual-user-agents.d.ts +7 -7
  53. package/dist/wirings/virtual-user/virtual-user-agents.js +2 -2
  54. package/dist/wirings/{persona/persona-app-scopes.d.ts → virtual-user/virtual-user-app-scopes.d.ts} +10 -10
  55. package/dist/wirings/{persona/persona-app-scopes.js → virtual-user/virtual-user-app-scopes.js} +12 -12
  56. package/dist/wirings/virtual-user/virtual-user-catalogue.d.ts +3 -3
  57. package/dist/wirings/virtual-user/virtual-user-catalogue.js +2 -2
  58. package/dist/wirings/{persona/persona.types.d.ts → virtual-user/virtual-user-declaration.types.d.ts} +24 -24
  59. package/dist/wirings/virtual-user/virtual-user-derive.js +13 -7
  60. package/dist/wirings/virtual-user/virtual-user-dispositions.d.ts +1 -1
  61. package/dist/wirings/{persona/persona-email.d.ts → virtual-user/virtual-user-email.d.ts} +11 -11
  62. package/dist/wirings/{persona/persona-email.js → virtual-user/virtual-user-email.js} +19 -19
  63. package/dist/wirings/{persona/persona-environments.d.ts → virtual-user/virtual-user-environments.d.ts} +10 -10
  64. package/dist/wirings/{persona/persona-environments.js → virtual-user/virtual-user-environments.js} +21 -21
  65. package/dist/wirings/virtual-user/virtual-user-intents.d.ts +3 -3
  66. package/dist/wirings/virtual-user/virtual-user-intents.js +3 -3
  67. package/dist/wirings/{persona/persona-mailbox.d.ts → virtual-user/virtual-user-mailbox.d.ts} +4 -4
  68. package/dist/wirings/virtual-user/virtual-user-run-store.d.ts +4 -4
  69. package/dist/wirings/virtual-user/virtual-user-scaffold.d.ts +42 -61
  70. package/dist/wirings/virtual-user/virtual-user-scaffold.js +69 -117
  71. package/dist/wirings/virtual-user/virtual-user-schedule-store.d.ts +15 -15
  72. package/dist/wirings/virtual-user/virtual-user-schedule.d.ts +6 -6
  73. package/dist/wirings/virtual-user/virtual-user-schedule.js +11 -11
  74. package/dist/wirings/virtual-user/virtual-user-target.d.ts +6 -6
  75. package/dist/wirings/virtual-user/virtual-user-target.js +5 -5
  76. package/dist/wirings/virtual-user/virtual-user.types.d.ts +11 -11
  77. package/dist/wirings/virtual-user/virtual-user.types.js +1 -1
  78. package/dist/wirings/workflow/dsl/workflow-dsl.types.d.ts +9 -9
  79. package/dist/wirings/workflow/pikku-scenario-service.d.ts +28 -28
  80. package/dist/wirings/workflow/pikku-scenario-service.js +77 -77
  81. package/dist/wirings/workflow/pikku-workflow-service.d.ts +2 -2
  82. package/dist/wirings/workflow/pikku-workflow-service.js +4 -4
  83. package/dist/wirings/workflow/scenario-prose.d.ts +8 -8
  84. package/dist/wirings/workflow/scenario-prose.js +12 -8
  85. package/dist/wirings/workflow/scenario-run.types.d.ts +13 -13
  86. package/dist/wirings/workflow/scenario-step.types.d.ts +23 -23
  87. package/dist/wirings/workflow/workflow.types.d.ts +2 -2
  88. package/knowledge/decisions/index.md +0 -2
  89. package/knowledge/decisions/internals/a-credential-name-declared-twice-must-agree-on-schema-and-type.md +29 -0
  90. package/knowledge/decisions/internals/a-grant-can-name-a-scope-declared-without-its-addon.md +29 -0
  91. package/knowledge/decisions/internals/a-latency-budget-is-asserted-by-its-cause.md +32 -0
  92. package/knowledge/decisions/internals/a-scheduled-task-writes-its-caller-session-before-it-runs.md +22 -0
  93. package/knowledge/decisions/internals/a-secret-set-in-memory-shadows-the-variable-of-the-same-name.md +28 -0
  94. package/knowledge/decisions/internals/a-virtual-user-acts-through-invokeraw-so-a-refusal-is-data.md +32 -0
  95. package/knowledge/decisions/internals/a-virtual-user-cadence-is-a-row-not-a-timer.md +12 -12
  96. package/knowledge/decisions/internals/a-virtual-user-converse-signs-in-before-its-first-turn.md +24 -0
  97. package/knowledge/decisions/internals/a-virtual-user-email-is-computed-with-the-run-id-as-a-sub-address.md +34 -0
  98. package/knowledge/decisions/internals/a-virtual-user-run-is-not-a-workflow-but-it-needs-a-trigger.md +2 -2
  99. package/knowledge/decisions/internals/a-wall-clock-threshold-is-a-load-test-in-disguise.md +3 -0
  100. package/knowledge/decisions/internals/an-agent-is-offered-under-its-registry-key-and-only-within-the-virtual-users-scopes.md +27 -0
  101. package/knowledge/decisions/internals/an-oauth2-credential-implies-an-optional-app-secret.md +26 -0
  102. package/knowledge/decisions/internals/analytics-identity-resolvers-run-in-declared-order.md +22 -0
  103. package/knowledge/decisions/internals/feature-flag-declarations-refuse-an-empty-anyof-and-conflicting-scopes.md +22 -0
  104. package/knowledge/decisions/internals/feature-flags-fail-open-and-never-enforce-access.md +28 -0
  105. package/knowledge/decisions/internals/flag-sync-rewrites-only-the-declared-text.md +24 -0
  106. package/knowledge/decisions/internals/in-a-scenario-a-4xx-is-data-not-an-exception.md +3 -3
  107. package/knowledge/decisions/internals/index.md +47 -31
  108. package/knowledge/decisions/internals/one-project-shape-check-two-validators.md +10 -10
  109. package/knowledge/decisions/internals/role-names-cannot-contain-the-scope-separator.md +30 -0
  110. package/knowledge/decisions/internals/scenario-agent-calls-sign-in-on-401-only.md +23 -19
  111. package/knowledge/decisions/internals/scenario-steps-return-drained-response-records.md +2 -2
  112. package/knowledge/decisions/internals/scenarios-live-in-files-named-for-them.md +12 -12
  113. package/knowledge/decisions/internals/the-core-scope-validator-refuses-separator-wildcard-and-empty-segments.md +22 -0
  114. package/knowledge/decisions/internals/the-pikku-user-id-resolves-in-a-fixed-order.md +24 -0
  115. package/knowledge/decisions/internals/{the-actor-prompt-says-json-because-of-json-object-mode.md → the-virtual-user-prompt-says-json-because-of-json-object-mode.md} +4 -4
  116. package/knowledge/decisions/internals/{the-persona-runtime-is-exported-from-the-persona-entry-point.md → the-virtual-user-runtime-is-exported-from-the-virtual-user-entry-point.md} +8 -8
  117. package/knowledge/decisions/internals/validate-checks-virtual-users-through-a-shared-module.md +43 -0
  118. package/knowledge/decisions/internals/{actor-flow-drives-the-target-through-a-transport-seam.md → virtual-user-conversation-drives-the-target-through-a-transport-seam.md} +6 -6
  119. package/knowledge/decisions/internals/virtual-user-conversation-verdicts-are-llm-self-evaluations.md +25 -0
  120. package/knowledge/decisions/internals/virtual-user-conversations-seed-a-hidden-kickoff-message.md +23 -0
  121. package/knowledge/decisions/internals/virtual-users-are-declared-in-one-definevirtualusers-call-per-codebase.md +30 -0
  122. package/knowledge/decisions/internals/workflow-core-never-imports-a-browser-driver.md +5 -5
  123. package/knowledge/decisions/internals/workflow-run-capabilities-are-extensions-not-subclasses.md +2 -2
  124. package/knowledge/decisions/internals/workflow-scenario-assertions-never-retry-and-record-one-step.md +4 -4
  125. package/knowledge/decisions/internals/workflow-scenario-hooks-are-a-scenario-only-affordance.md +1 -1
  126. package/knowledge/decisions/internals/workflow-scenario-prose-is-rendered-from-typed-calls-not-parsed-from-english.md +2 -2
  127. package/knowledge/decisions/internals/workflow-scenario-step-targets-are-string-literals-for-the-inspector.md +1 -1
  128. package/knowledge/decisions/internals/workflow-suspended-runs-keep-their-in-process-context.md +1 -1
  129. package/knowledge/decisions/security/a-bearer-token-checked-against-a-secret-reads-it-per-request.md +26 -0
  130. package/knowledge/decisions/security/a-call-without-a-session-raises-missing-session-not-forbidden.md +20 -0
  131. package/knowledge/decisions/security/a-caller-cookie-wins-over-the-jar-for-the-same-name.md +23 -0
  132. package/knowledge/decisions/security/a-channel-lifecycle-acts-as-the-socket-upgrade-session.md +16 -0
  133. package/knowledge/decisions/security/a-channel-requires-a-session-unless-it-says-auth-false.md +26 -0
  134. package/knowledge/decisions/security/a-credential-read-path-follows-its-declared-type-not-absence.md +32 -0
  135. package/knowledge/decisions/security/a-credential-type-is-a-literal-the-inspector-checks-at-declaration.md +27 -0
  136. package/knowledge/decisions/security/a-first-party-cookie-is-written-only-after-its-purposes-consent.md +33 -0
  137. package/knowledge/decisions/security/a-readonly-session-reaches-only-readonly-functions.md +25 -0
  138. package/knowledge/decisions/security/a-scaffold-flag-says-a-surface-exists-not-who-may-call-it.md +10 -5
  139. package/knowledge/decisions/security/a-scheduled-virtual-user-run-needs-no-admin-at-run-time.md +27 -0
  140. package/knowledge/decisions/security/a-scoped-credential-view-is-limited-to-declared-names.md +26 -0
  141. package/knowledge/decisions/security/a-scoped-secret-view-reads-only-declared-keys-and-never-writes.md +25 -0
  142. package/knowledge/decisions/security/a-secret-is-sent-only-to-the-hosts-it-declares.md +29 -0
  143. package/knowledge/decisions/security/a-step-can-name-an-identity-no-virtual-user-holds-through-per-call-headers.md +25 -0
  144. package/knowledge/decisions/security/a-stopped-run-by-id-skips-the-ownership-check.md +24 -0
  145. package/knowledge/decisions/security/a-vault-secret-redacts-on-serialization-and-throws-on-coercion.md +29 -0
  146. package/knowledge/decisions/security/a-virtual-user-catalogue-entry-is-filtered-by-scope-and-approval-is-denied-by-default.md +30 -0
  147. package/knowledge/decisions/security/a-virtual-user-environment-fails-closed.md +38 -0
  148. package/knowledge/decisions/security/a-virtual-user-never-runs-against-production.md +23 -0
  149. package/knowledge/decisions/security/a-virtual-user-reads-its-roles-from-the-apps-own-rpc-before-better-auth.md +27 -0
  150. package/knowledge/decisions/security/a-virtual-user-run-treats-an-unresolved-environment-as-production.md +41 -0
  151. package/knowledge/decisions/security/a-virtual-user-scopes-are-expanded-from-its-roles-once-at-run-preparation.md +25 -0
  152. package/knowledge/decisions/security/a-virtual-user-whose-roles-drift-from-the-declaration-refuses-to-run.md +32 -0
  153. package/knowledge/decisions/security/addon-screen-scopes-hide-and-do-not-enforce.md +20 -0
  154. package/knowledge/decisions/security/an-addon-header-can-only-narrow-the-session.md +26 -0
  155. package/knowledge/decisions/security/an-addon-instance-reads-only-the-secrets-and-credentials-it-is-named.md +33 -0
  156. package/knowledge/decisions/security/an-addon-may-reach-only-itself-and-the-addons-it-uses.md +16 -0
  157. package/knowledge/decisions/security/an-api-key-is-jwt-decoded-into-the-session.md +26 -0
  158. package/knowledge/decisions/security/an-external-virtual-user-caller-presents-one-signed-statement.md +38 -0
  159. package/knowledge/decisions/security/an-inbound-webhook-source-dispatches-only-verified-requests.md +31 -0
  160. package/knowledge/decisions/security/an-mcp-call-with-no-http-request-stays-anonymous.md +18 -0
  161. package/knowledge/decisions/security/an-omitted-user-id-addresses-the-platform-credential.md +32 -0
  162. package/knowledge/decisions/security/analytics-identity-is-stamped-from-the-session-not-the-event.md +24 -0
  163. package/knowledge/decisions/security/app-access-is-a-scope-tree-synthesised-from-virtual-users.md +26 -0
  164. package/knowledge/decisions/security/approval-policy-decides-who-answers-a-tool-call.md +27 -0
  165. package/knowledge/decisions/security/auth-false-on-a-session-function-warns-and-still-requires-one.md +25 -0
  166. package/knowledge/decisions/security/bearer-token-hashes-are-unpeppered-sha256.md +18 -0
  167. package/knowledge/decisions/security/consent-is-read-from-a-cookie-and-a-recognised-denial-counts-as-refusal.md +29 -0
  168. package/knowledge/decisions/security/cors-defaults-to-any-origin-and-refuses-the-wildcard-with-credentials.md +22 -0
  169. package/knowledge/decisions/security/credential-backends-share-one-conformance-suite-for-per-user-isolation.md +29 -0
  170. package/knowledge/decisions/security/each-stage-has-one-virtual-user-key-pair.md +27 -0
  171. package/knowledge/decisions/security/hmac-verification-fails-closed-on-empty-inputs.md +25 -0
  172. package/knowledge/decisions/security/index.md +88 -24
  173. package/knowledge/decisions/security/local-content-refuses-private-buckets-under-the-public-segment.md +21 -0
  174. package/knowledge/decisions/security/mail-is-allowlisted-before-a-virtual-user-run-sees-it.md +38 -0
  175. package/knowledge/decisions/security/mcp-resources-tools-and-prompts-take-sessionless-functions.md +18 -0
  176. package/knowledge/decisions/security/origin-locked-routes-match-the-origin-exactly.md +22 -0
  177. package/knowledge/decisions/security/oss-auth-works-without-pikku-studio-cloud.md +26 -0
  178. package/knowledge/decisions/security/outbound-webhooks-use-an-allowlist-when-configured.md +24 -0
  179. package/knowledge/decisions/security/pikku-carries-virtual-user-scopes-as-data-and-the-app-grants-them.md +35 -0
  180. package/knowledge/decisions/security/scoped-content-access-is-a-root-folder-with-longest-prefix-grants.md +31 -0
  181. package/knowledge/decisions/security/services-without-secrets-get-a-throwing-secrets-accessor.md +22 -0
  182. package/knowledge/decisions/security/shared-guards-refuse-to-mutate-or-shadow-a-system-role.md +34 -0
  183. package/knowledge/decisions/security/signed-uploads-are-verified-by-the-same-check-as-signed-reads.md +26 -0
  184. package/knowledge/decisions/security/system-role-scopes-must-be-declared-with-define-scope.md +24 -0
  185. package/knowledge/decisions/security/system-roles-are-additive-and-immutable.md +16 -0
  186. package/knowledge/decisions/security/the-channel-rpc-does-not-send-the-callers-session.md +21 -0
  187. package/knowledge/decisions/security/the-remote-jobs-inbox-fails-closed-without-a-secret.md +24 -0
  188. package/knowledge/decisions/security/the-remote-rpc-gate-fails-closed-and-binds-the-token-to-its-function.md +34 -0
  189. package/knowledge/decisions/security/the-workflow-status-stream-rechecks-ownership-on-every-poll.md +16 -0
  190. package/knowledge/decisions/security/two-credentials-on-one-key-must-share-a-read-mode.md +29 -0
  191. package/knowledge/decisions/security/verified-bearer-claims-are-pass-through-data-that-core-never-fills.md +23 -0
  192. package/knowledge/decisions/security/virtual-user-catalogue-excludes-the-machinery-that-runs-virtual-users.md +25 -0
  193. package/knowledge/decisions/security/{actor-flow-missing-approval-decisions-default-to-denied.md → virtual-user-conversation-missing-approval-decisions-default-to-denied.md} +7 -7
  194. package/knowledge/decisions/security/virtual-user-run-records-are-gated-behind-a-read-scope.md +18 -0
  195. package/knowledge/decisions/security/virtual-user-sign-in-does-not-exist-in-production.md +25 -0
  196. package/knowledge/decisions/security/virtual-user-sign-in-has-one-door.md +42 -0
  197. package/knowledge/decisions/security/{actor-sign-in-is-proven-by-set-cookie-not-a-non-empty-jar.md → virtual-user-sign-in-is-proven-by-set-cookie-not-a-non-empty-jar.md} +10 -8
  198. package/knowledge/decisions/security/virtual-user-sign-in-only-works-for-virtual-user-flagged-users.md +29 -0
  199. package/knowledge/decisions/security/workflow-helper-functions-are-sessionless-by-declaration.md +18 -0
  200. package/knowledge/decisions/security/{workflow-scenario-sessions-are-isolated-per-actor-and-per-scenario.md → workflow-scenario-sessions-are-isolated-per-virtual-user-and-per-scenario.md} +6 -6
  201. package/knowledge/decisions/security/workflow-scenario-steps-are-never-network-invocable.md +5 -5
  202. package/knowledge/decisions/security/{workflow-actor-steps-always-use-the-real-transport.md → workflow-virtual-user-steps-always-use-the-real-transport.md} +11 -11
  203. package/knowledge/decisions/security/writing-a-virtual-user-schedule-is-gated-by-its-own-scope.md +18 -0
  204. package/knowledge/index.md +0 -2
  205. package/knowledge/questions/a-bearer-jwt-with-no-identity-becomes-a-session.md +24 -0
  206. package/knowledge/questions/dev-quick-login-as-impersonation.md +25 -0
  207. package/knowledge/questions/does-a-delayed-rpc-run-as-the-session-it-was-scheduled-with.md +26 -0
  208. package/knowledge/questions/does-a-user-id-with-a-colon-read-another-users-credentials.md +27 -0
  209. package/knowledge/questions/does-a-wirecli-command-need-a-session-by-default.md +26 -0
  210. package/knowledge/questions/does-an-adversarial-in-scope-success-count-as-a-finding.md +26 -0
  211. package/knowledge/questions/does-approve-step-need-the-run-owners-session-or-the-gates-approvers.md +34 -0
  212. package/knowledge/questions/does-cors-origin-true-reflect-any-origin-with-credentials.md +20 -0
  213. package/knowledge/questions/does-skip-user-session-do-anything-on-a-channel.md +24 -0
  214. package/knowledge/questions/does-the-store-session-match-the-other-two.md +19 -0
  215. package/knowledge/questions/index.md +25 -2
  216. package/knowledge/questions/is-the-agent-score-worker-reachable-without-a-session.md +21 -0
  217. package/knowledge/questions/live-scheduled-tests-may-write.md +19 -0
  218. package/knowledge/questions/provision-virtual-users-has-no-caller-in-this-repo.md +23 -0
  219. package/knowledge/questions/remote-secret-refuses-requests-without-a-remote-token-on-every-path.md +32 -0
  220. package/knowledge/questions/should-a-middleware-set-session-persist-to-the-store.md +25 -0
  221. package/knowledge/questions/should-a-scoped-secret-view-throw-from-has-secret-for-a-disallowed-key.md +23 -0
  222. package/knowledge/questions/should-a-wrong-bearer-token-be-anonymous-or-refused.md +35 -0
  223. package/knowledge/questions/should-an-empty-webhook-signing-secret-send-unsigned.md +23 -0
  224. package/knowledge/questions/should-http-virtual-user-sessions-reset-between-scenarios-in-one-run.md +27 -0
  225. package/knowledge/questions/should-the-cookie-jar-scope-cookies-to-the-api-origin.md +26 -0
  226. package/knowledge/questions/should-voice-input-fetch-audio-urls-without-a-host-allowlist.md +20 -0
  227. package/knowledge/questions/staging-impersonation-rules.md +27 -0
  228. package/knowledge/questions/virtual-user-keys-on-cloud-stages-are-pikku-studios-to-build.md +33 -0
  229. package/knowledge/questions/virtual-user-statement-replay-is-per-process.md +20 -0
  230. package/knowledge/questions/what-an-impersonated-session-carries.md +22 -0
  231. package/package.json +2 -3
  232. package/src/public-surface.json +38 -47
  233. package/dist/services/persona-actor-secret.d.ts +0 -38
  234. package/dist/services/persona-actor-secret.js +0 -39
  235. package/dist/services/persona-sign-in.d.ts +0 -117
  236. package/dist/services/persona-sign-in.js +0 -154
  237. package/dist/wirings/actor-flow/index.d.ts +0 -2
  238. package/dist/wirings/actor-flow/run-conversation.d.ts +0 -36
  239. package/dist/wirings/persona/define-personas.d.ts +0 -32
  240. package/dist/wirings/persona/index.d.ts +0 -23
  241. package/dist/wirings/persona/index.js +0 -19
  242. package/knowledge/decisions/internals/actor-flow-conversations-seed-a-hidden-kickoff-message.md +0 -23
  243. package/knowledge/decisions/internals/actor-flow-verdicts-are-llm-self-evaluations.md +0 -25
  244. package/knowledge/decisions/internals/validate-checks-personas-through-a-shared-module.md +0 -43
  245. package/knowledge/decisions/security/actor-sign-in-only-works-for-actor-flagged-users.md +0 -31
  246. package/knowledge/decisions/security/an-actor-credential-is-derived-per-persona.md +0 -42
  247. package/knowledge/decisions/security/pikku-carries-actor-scopes-as-data-and-the-app-grants-them.md +0 -26
  248. /package/dist/wirings/{actor-flow/actor-flow.types.js → virtual-user/conversation/conversation.types.js} +0 -0
  249. /package/dist/wirings/{actor-flow → virtual-user/conversation}/index.js +0 -0
  250. /package/dist/wirings/{persona/persona.types.js → virtual-user/virtual-user-declaration.types.js} +0 -0
  251. /package/dist/wirings/{persona/persona-mailbox.js → virtual-user/virtual-user-mailbox.js} +0 -0
package/CHANGELOG.md CHANGED
@@ -1,3 +1,53 @@
1
+ ## 0.12.143
2
+
3
+ ### Patch Changes
4
+
5
+ - de9af6a: RPCs for Pikku Studio's migrated screens. Runtime state that must be visible on a deployed app lives in `@pikku/addon-admin`; local-copy tools stay in `@pikku/addon-console`.
6
+
7
+ `@pikku/addon-admin`:
8
+
9
+ - `admin:getSchedulerHistory` returns each scheduled task's last run, next run and recent runs, from a new `SchedulerService.getTaskRuns()` (empty by default). `InMemorySchedulerService` records the last 50 runs per cron task with status, duration and error. Scope `admin:schedules:read`.
10
+ - `admin:getQueueHistory({ queueNames?, limit? })` returns live counts and recent jobs per queue, from a new optional `QueueService.inspect(queueName, { limit })`, implemented by `InMemoryQueueService` and `BullQueueService` and forwarded by `SignedQueueService`. Scope `admin:queues:read`.
11
+ - `admin:listIncomingWebhookReceipts` / `admin:getIncomingWebhookReceipt` expose received webhooks, backed by a new `IncomingWebhookService.getReceipt(receiptId)` (null by default; implemented by `KyselyIncomingWebhookService`). Scope `admin:webhooks:read`.
12
+
13
+ `@pikku/addon-console`:
14
+
15
+ - `console:variableGet` / `console:variableSet` read and write a project variable, gated on `pikku:console:variables:read` / `:write`.
16
+ - `console:runScenarios({ names?, environment? })` starts `pikku scenario run` as a detached child process and returns `{ runId }` to follow through `listScenarioRuns` / `getScenarioRun`, gated on the new `pikku:console:scenarios:run` scope. `pikku scenario run` takes `--run-id <id>` to record under a caller-chosen id.
17
+
18
+ ## 0.12.142
19
+
20
+ ### Patch Changes
21
+
22
+ - fdcc821: Fabric is gone from the open toolchain. The previous names are removed with no aliases.
23
+
24
+ The CLI group is `pikku cloud …` and the export is `@pikku/cli/cloud`. The project link is the `cloud` key of `pikku.config.json` (`cloud.projectId`), the CLI keeps its local state in `~/.pikkustudio` (run `pikku cloud login` again), and the project config file is `pikkustudio.config.json`.
25
+
26
+ Every environment variable drops the `FABRIC_` prefix for `PIKKUSTUDIO_` with the same suffix: `PIKKUSTUDIO_API_URL`, `PIKKUSTUDIO_PROJECT_ID`, `PIKKUSTUDIO_TOKEN`, `PIKKUSTUDIO_OPERATOR_TOKEN`, `PIKKUSTUDIO_AUTH_PUBLIC_KEY`, `PIKKUSTUDIO_STAGE_ID` and the rest. Rename them wherever you set them.
27
+
28
+ Wire ids: the operator sign-in route is `/sign-in/cloud`, the plugin and mode literal is `'cloud'`, the Better Auth plugin is `pikkuCloud`, its session field is `pikkustudioadmin`, and the signature header is `x-cloud-sig`. The cloud API calls are `getCloudLogs`, `getCloudLogsByStageKind`, `cloudCliProjects`, `cloudCliDeployments`, `providedByCloud` and `recordCloudAnalyticsEvents`. Addon packages are `@pikkustudio/*`, scaffolded files live under `scaffold/cloud` and `__cloud_*__`, and the API hosts are the `pikkustudio.app` and `pikkustudio.dev` domains.
29
+
30
+ `pikku skills install --fabric` is `--cloud`, the install group is `cloud`, and the skills are `pikku-cloud`, `pikku-cloud-debug`, `pikku-admin-to-cloud` and `pikku-blueprint-to-cloud`.
31
+
32
+ The stale analytics forwarder copies are removed from the online-shop example and the starter template.
33
+
34
+ The sealed-box salt stays `pikkufabric/sealed-box/v1`: it is a cryptographic constant that already-sealed secrets depend on.
35
+
36
+ - 33b102d: Virtual users now have one name everywhere. The id column of `virtual_user_run` and `virtual_user_schedule` is `virtual_user_id` (a migration renames it in place), the CLI group is `pikku virtual-user …`, and the declarations and imports live under `@pikku/core/virtual-user`. The previous names are removed with no aliases.
37
+
38
+ The default virtual user email domain is now `virtualuser.invalid`: apps that rely on the default domain get new accounts at the next provisioning (`pikku virtual-user sync`, deploy, or `pikku dev` start), and the old rows stay unused.
39
+
40
+ The sign-in surface carries the same name. The route is `/sign-in/virtual-user`, the environment variables are `PIKKU_ALLOW_VIRTUAL_USER_SIGN_IN` and the `PIKKU_DEV_VIRTUAL_USER_SIGN_IN` / `VITE_*` equivalents, the Better Auth plugin is `pikkuVirtualUser`, the scenario step option and wire member are `virtualUser` and `virtualUsers`, and the Better Auth user flag column is `virtual_user`. Rename the environment variables wherever you set them, and add a migration that renames the flag column on the `user` table. Nothing is aliased.
41
+
42
+ The conversation runner is now `@pikku/core/virtual-user/conversation`, replacing the old `-flow` subpath. Update the import; the old subpath is gone.
43
+
44
+ - 6a25c70: Virtual users no longer run against production. Starting a run, and enabling a schedule, is refused with a 403 in a production environment for every disposition, including `accountable`, which was the one disposition production used to accept. Turning a schedule off or editing a disabled one is still allowed, so a leftover schedule can be stopped.
45
+ - a084c3b: Virtual users sign themselves in. A scheduled run signs in from inside the app through a server-only Better Auth endpoint, then drives the app over HTTP with the cookie. Outside callers (`pikku dev`, `pikku scenario run`, `pikku virtual-user run` and `rpc`, `pikku pages screenshot --as`, the Playwright provider) present one signed, short-lived, single-use EdDSA statement, which the app checks against `VIRTUAL_USER_VERIFY_KEY`; `pikku dev` generates the key pair, and a deployed stage's deployer holds `VIRTUAL_USER_SIGNING_KEY`. `@pikku/jose` gains `JoseVirtualUserStatementVerifier` and `@pikku/better-auth` takes `verifyKey`. Removed with no aliases: the operator token and `OperatorSignIn`, derived per-virtual-user secrets, `SCENARIO_VIRTUAL_USER_SECRET`, `PIKKU_VIRTUAL_USER_SECRETS`, `pikku virtual-user secret`, and `wireVirtualUserSignIn`. In production neither sign-in endpoint is registered.
46
+
47
+ The scenario cookie jar moved to `services` and `createCookieJar` is exported from `@pikku/core/virtual-user`, which removes the wire-to-wire import cycles; `VirtualUserSignIn.headers` is now optional.
48
+
49
+ Migration for apps: pass `verifyKey: await variables.get('VIRTUAL_USER_VERIFY_KEY')` to `pikkuVirtualUser` instead of `secret`, declare that variable as optional, delete any `SCENARIO_VIRTUAL_USER_SECRET` secret and any `wireVirtualUserSignIn` call, and stop passing `secret` or `operator` to `createHttpVirtualUsers`. A stage that must run scenarios still opts in with `PIKKU_ALLOW_VIRTUAL_USER_SIGN_IN`.
50
+
1
51
  ## 0.12.141
2
52
 
3
53
  ### Patch Changes
@@ -118,7 +118,7 @@ export declare class AIProviderAuthError extends PikkuError {
118
118
  *
119
119
  * System roles ship with the product: the console may show and grant them, but
120
120
  * renaming, re-scoping or deleting one would let a UI action silently change
121
- * what a declared persona means, and what every scenario written against that
121
+ * what a declared virtual user means, and what every scenario written against that
122
122
  * role is actually testing.
123
123
  * @group Error
124
124
  */
@@ -314,7 +314,7 @@ addError(AIProviderAuthError, {
314
314
  *
315
315
  * System roles ship with the product: the console may show and grant them, but
316
316
  * renaming, re-scoping or deleting one would let a UI action silently change
317
- * what a declared persona means, and what every scenario written against that
317
+ * what a declared virtual user means, and what every scenario written against that
318
318
  * role is actually testing.
319
319
  * @group Error
320
320
  */
@@ -80,17 +80,17 @@ export type FunctionRuntimeMeta = {
80
80
  */
81
81
  scenarioStepSurfaces?: ScenarioSurface[];
82
82
  /**
83
- * Scenario steps only: this step runs as a persona, so every call site must
84
- * pass one and the runner injects it as `wire.actor`.
83
+ * Scenario steps only: this step runs as a virtual user, so every call site must
84
+ * pass one and the runner injects it as `wire.virtualUser`.
85
85
  *
86
- * Declared by `actor: true`, or implied by a `browser` binding — a window is
86
+ * Declared by `virtualUser: true`, or implied by a `browser` binding — a window is
87
87
  * opened as somebody. Absent on a step with nobody to be: an assertion over
88
88
  * what an earlier step returned, or one posting credentials precisely because
89
- * it must not reuse an actor's session.
89
+ * it must not reuse a virtual user's session.
90
90
  */
91
- scenarioStepRequiresActor?: boolean;
91
+ scenarioStepRequiresVirtualUser?: boolean;
92
92
  /**
93
- * Scenario steps only: who acts. Absent means `persona` — the ordinary step,
93
+ * Scenario steps only: who acts. Absent means `virtualUser` — the ordinary step,
94
94
  * and the only kind that existed before the other two.
95
95
  *
96
96
  * A `platform` or `addon` step is the app or a third-party system acting, and
@@ -111,8 +111,8 @@ export type CorePikkuFunctionConfig<PikkuFunction extends CorePikkuFunction<any,
111
111
  * and report how much of the flow each surface actually covers.
112
112
  */
113
113
  surfaces?: ScenarioSurface[];
114
- /** Scenario steps only, and set by the definer rather than by hand: this step needs a persona, so the runner injects `wire.actor`. */
115
- requiresActor?: boolean;
114
+ /** Scenario steps only, and set by the definer rather than by hand: this step needs a virtual user, so the runner injects `wire.virtualUser`. */
115
+ requiresVirtualUser?: boolean;
116
116
  /**
117
117
  * Records every call in the audit log. `transactional` durability writes the
118
118
  * entry in the same transaction as the work, so the two cannot disagree;
@@ -13,10 +13,10 @@ export type ResolvedAuditConfig = {
13
13
  /**
14
14
  * Who an event happened under.
15
15
  *
16
- * A user, not an "actor": in pikku an actor is a synthetic person a scenario
17
- * drives, flagged `actor` on the user row, and the overwhelming majority of
18
- * audited events are caused by ordinary customers. Naming this `actor` made the
19
- * synthetic case unsayable — `actor.actor === true` — and implied every
16
+ * A user, not an "virtualUser": in pikku a virtual user is a synthetic person a scenario
17
+ * drives, flagged `virtualUser` on the user row, and the overwhelming majority of
18
+ * audited events are caused by ordinary customers. Naming this `virtualUser` made the
19
+ * synthetic case unsayable — `virtualUser.virtualUser === true` — and implied every
20
20
  * recorded action was a test.
21
21
  *
22
22
  * `pikkuUserId` is the identity pikku resolves for every wire, so it is the one
@@ -88,10 +88,10 @@ export interface FeatureFlagStore extends FeatureFlagSource {
88
88
  * every flag to render a board would grow with the wrong number.
89
89
  */
90
90
  listOverrides(key: string): Promise<FlagOverrideRow[]>;
91
- setEnabled(key: string, enabled: boolean, actor?: string, note?: string): Promise<void>;
91
+ setEnabled(key: string, enabled: boolean, virtualUser?: string, note?: string): Promise<void>;
92
92
  /** `percent` is 0–100, or null to remove the rollout constraint. */
93
- setRollout(key: string, percent: number | null, actor?: string): Promise<void>;
94
- setOverride(key: string, subject: FlagSubject, enabled: boolean, actor?: string): Promise<void>;
93
+ setRollout(key: string, percent: number | null, virtualUser?: string): Promise<void>;
94
+ setOverride(key: string, subject: FlagSubject, enabled: boolean, virtualUser?: string): Promise<void>;
95
95
  clearOverride(key: string, subject: FlagSubject): Promise<void>;
96
96
  /** Flags in the store with no declaration left in code; powers `pikku flags audit`. */
97
97
  findStaleFlags(): Promise<string[]>;
@@ -1,7 +1,7 @@
1
- import type { ScenarioPersona, ResolvedPersona, ScenarioPersonas, ScenarioInvokeOptions, ScenarioHttpResponse } from './personas-service.js';
2
- import type { ConverseOptions, ActorFlowVerdict } from '../wirings/actor-flow/actor-flow.types.js';
3
- import { type ActorSecretResolver, type OperatorSignInOptions } from './persona-sign-in.js';
4
- export interface HttpPersonasConfig {
1
+ import type { ScenarioVirtualUser, ResolvedVirtualUser, ScenarioVirtualUsers, ScenarioInvokeOptions, ScenarioHttpResponse } from './virtual-users-service.js';
2
+ import type { ConverseOptions, ConversationVerdict } from '../wirings/virtual-user/conversation/conversation.types.js';
3
+ import { type VirtualUserSignIn } from './virtual-user-sign-in.js';
4
+ export interface HttpVirtualUsersConfig {
5
5
  /**
6
6
  * Base API URL of the target app, INCLUDING the HTTP prefix — e.g.
7
7
  * `https://app.example.com/api` or `http://localhost:4000/api`. Sign-in is
@@ -10,39 +10,21 @@ export interface HttpPersonasConfig {
10
10
  */
11
11
  apiUrl: string;
12
12
  /**
13
- * The ROOT actor secret, from which each persona's own credential is derived
14
- * and bound to their address. Sign-in only ever works for user rows flagged
15
- * `actor: true`, and a derived credential only ever works for the one address
16
- * it was derived for.
17
- *
18
- * Pass an {@link ActorSecretResolver} instead to drive personas whose
19
- * credentials were minted elsewhere — a caller entitled to one persona then
20
- * never holds the root.
21
- *
22
- * The local-development credential. A deployed stage has none, and passes
23
- * {@link HttpPersonasConfig.operator} instead.
24
- */
25
- secret?: string | ActorSecretResolver;
26
- /**
27
- * Fabric operator credentials, for signing personas into a DEPLOYED stage.
28
- *
29
- * Mutually exclusive with {@link HttpPersonasConfig.secret}: the operator
30
- * path acts as the persona through an admin session rather than logging in as
31
- * them, so no test credential has to exist on the target at all.
13
+ * How each virtual user obtains a session: {@link inProcessSignIn} from inside
14
+ * the app, {@link statementSignIn} from outside it.
32
15
  */
33
- operator?: OperatorSignInOptions;
34
- /** Persona id → the declaration with its address filled in. */
35
- personas: Record<string, ResolvedPersona>;
16
+ signIn: VirtualUserSignIn;
17
+ /** Virtual user id → the declaration with its address filled in. */
18
+ virtualUsers: Record<string, ResolvedVirtualUser>;
36
19
  /**
37
- * Sign-in path under apiUrl, for whichever of the two paths is in use — an
38
- * app that mounts auth under `/api` moves both. Default: the actor plugin's
39
- * `/auth/sign-in/actor`, or `/auth/sign-in/fabric` for an operator.
40
- * {@link OperatorSignInOptions.signInPath} overrides it.
20
+ * The sign-in path, when the app mounts auth somewhere other than `/auth`.
21
+ * Only the mount is used here, to find `get-session`; signing in itself is
22
+ * the job of {@link HttpVirtualUsersConfig.signIn}.
41
23
  */
42
24
  signInPath?: string;
43
25
  /**
44
26
  * Where the session (and its roles) is read back. Defaults to `get-session`
45
- * under the same auth mount as {@link HttpPersonasConfig.signInPath}, so an
27
+ * under the same auth mount as {@link HttpVirtualUsersConfig.signInPath}, so an
46
28
  * app that moved auth under `/api` moves this with it and does not have to
47
29
  * say so twice.
48
30
  */
@@ -57,28 +39,24 @@ export interface HttpPersonasConfig {
57
39
  * on scopes that column is a projection rather than the model — it exists so
58
40
  * better-auth's own admin endpoints have something to read, is written by
59
41
  * whatever keeps it in step, and is absent entirely from an app that declares
60
- * no such field. A persona verified against it is verified against a copy.
42
+ * no such field. A virtual user verified against it is verified against a copy.
61
43
  */
62
44
  rolesRpc?: string | false;
63
45
  /**
64
- * Default model a persona thinks with when `converse(...)` is called without
46
+ * Default model a virtual user thinks with when `converse(...)` is called without
65
47
  * an explicit `model`. Its own turns/approvals/evaluation run in-process via
66
48
  * the configured `agentRunner`.
67
49
  */
68
50
  model?: string;
69
51
  }
70
52
  /**
71
- * Default HTTP-backed persona. Signs in lazily on first invoke, holds the
53
+ * Default HTTP-backed virtual user. Signs in lazily on first invoke, holds the
72
54
  * session cookies for its lifetime, and re-logs-in once on a 401 mid-run (long
73
55
  * health-check runs can outlive a session).
74
- *
75
- * How it signs in depends on the target, and the two ways are not
76
- * interchangeable — see {@link ActorSignIn} for local development and
77
- * {@link OperatorSignIn} for a deployed stage.
78
56
  */
79
- export declare class HttpPersona implements ScenarioPersona {
57
+ export declare class HttpVirtualUser implements ScenarioVirtualUser {
80
58
  readonly name: string;
81
- private persona;
59
+ private virtualUser;
82
60
  private config;
83
61
  private jar;
84
62
  /**
@@ -89,15 +67,15 @@ export declare class HttpPersona implements ScenarioPersona {
89
67
  */
90
68
  private signedIn;
91
69
  private signIn;
92
- constructor(name: string, persona: ResolvedPersona, config: HttpPersonasConfig);
70
+ constructor(name: string, virtualUser: ResolvedVirtualUser, config: HttpVirtualUsersConfig);
93
71
  get email(): string;
94
72
  invoke(rpcName: string, data: unknown): Promise<unknown>;
95
73
  invokeRaw(rpcName: string, data: unknown, options?: ScenarioInvokeOptions): Promise<ScenarioHttpResponse>;
96
- converse(options: ConverseOptions): Promise<ActorFlowVerdict>;
74
+ converse(options: ConverseOptions): Promise<ConversationVerdict>;
97
75
  /**
98
76
  * The roles the stage says this session holds.
99
77
  *
100
- * {@link HttpPersonasConfig.rolesRpc} first, then better-auth's
78
+ * {@link HttpVirtualUsersConfig.rolesRpc} first, then better-auth's
101
79
  * `get-session` — where its admin plugin puts `role` on the user, as a
102
80
  * comma-separated list. A target that answers neither returns `null` rather
103
81
  * than an empty list, because "this stage does not report roles" and "this
@@ -112,7 +90,7 @@ export declare class HttpPersona implements ScenarioPersona {
112
90
  private rolesFromRpc;
113
91
  private rolesFromSession;
114
92
  /**
115
- * Start/continue the target agent's run over HTTP as this persona.
93
+ * Start/continue the target agent's run over HTTP as this virtual user.
116
94
  *
117
95
  * The SSE route, not the plain one. `POST /rpc/agent/:name` buffers the whole
118
96
  * run before it sends a single byte, so a run longer than the client's
@@ -134,7 +112,7 @@ export declare class HttpPersona implements ScenarioPersona {
134
112
  private login;
135
113
  }
136
114
  /**
137
- * Build the injected `personas` service from the declared personas: id → lazy
138
- * HTTP persona. Wire the result as the `personas` singleton service.
115
+ * Build the injected `virtualUsers` service from the declared virtual users: id → lazy
116
+ * HTTP virtual user. Wire the result as the `virtualUsers` singleton service.
139
117
  */
140
- export declare function createHttpPersonas(config: HttpPersonasConfig): ScenarioPersonas;
118
+ export declare function createHttpVirtualUsers(config: HttpVirtualUsersConfig): ScenarioVirtualUsers;
@@ -1,21 +1,17 @@
1
- import { readScenarioHttpResponse } from './personas-service.js';
2
- import { runConversation } from '../wirings/actor-flow/run-conversation.js';
3
- import { createCookieJar, } from '../wirings/workflow/scenario-cookie-jar.js';
4
- import { ActorSignIn, OperatorSignIn, authMount, } from './persona-sign-in.js';
1
+ import { readScenarioHttpResponse } from './virtual-users-service.js';
2
+ import { runConversation } from '../wirings/virtual-user/conversation/run-conversation.js';
3
+ import { createCookieJar, } from './scenario-cookie-jar.js';
4
+ import { authMount } from './virtual-user-sign-in.js';
5
5
  import { getSingletonServices } from '../pikku-state.js';
6
6
  import { AIProviderNotConfiguredError } from '../errors/errors.js';
7
7
  /**
8
- * Default HTTP-backed persona. Signs in lazily on first invoke, holds the
8
+ * Default HTTP-backed virtual user. Signs in lazily on first invoke, holds the
9
9
  * session cookies for its lifetime, and re-logs-in once on a 401 mid-run (long
10
10
  * health-check runs can outlive a session).
11
- *
12
- * How it signs in depends on the target, and the two ways are not
13
- * interchangeable — see {@link ActorSignIn} for local development and
14
- * {@link OperatorSignIn} for a deployed stage.
15
11
  */
16
- export class HttpPersona {
12
+ export class HttpVirtualUser {
17
13
  name;
18
- persona;
14
+ virtualUser;
19
15
  config;
20
16
  jar;
21
17
  /**
@@ -26,29 +22,15 @@ export class HttpPersona {
26
22
  */
27
23
  signedIn = false;
28
24
  signIn;
29
- constructor(name, persona, config) {
25
+ constructor(name, virtualUser, config) {
30
26
  this.name = name;
31
- this.persona = persona;
27
+ this.virtualUser = virtualUser;
32
28
  this.config = config;
33
29
  this.jar = createCookieJar(config.apiUrl);
34
- if (config.operator) {
35
- this.signIn = new OperatorSignIn(config.apiUrl, {
36
- ...config.operator,
37
- signInPath: config.operator.signInPath ??
38
- (authMount(config.signInPath)
39
- ? `${authMount(config.signInPath)}/sign-in/fabric`
40
- : undefined),
41
- });
42
- }
43
- else if (config.secret) {
44
- this.signIn = new ActorSignIn(config.apiUrl, config.secret, config.signInPath ?? '/auth/sign-in/actor');
45
- }
46
- else {
47
- throw new Error(`[scenario] persona '${name}' has no way to sign in — set 'secret' for a dev target or 'operator' for a deployed one`);
48
- }
30
+ this.signIn = config.signIn;
49
31
  }
50
32
  get email() {
51
- return this.persona.email;
33
+ return this.virtualUser.email;
52
34
  }
53
35
  async invoke(rpcName, data) {
54
36
  const res = await this.invokeRaw(rpcName, data);
@@ -78,20 +60,20 @@ export class HttpPersona {
78
60
  // Signed in here rather than left to postAgent's 401 retry, which a public
79
61
  // agent route never triggers. An unowned thread is minted under a fresh
80
62
  // anonymous id per request, so turn one succeeds and turn two is refused as
81
- // somebody else's — and a persona is a real account with real credentials,
63
+ // somebody else's — and a virtual user is a real account with real credentials,
82
64
  // so there is no case where conversing as nobody is the intent.
83
65
  if (!this.signedIn) {
84
66
  await this.login();
85
67
  }
86
68
  const model = options.model ?? this.config.model;
87
69
  if (!model) {
88
- throw new Error(`[scenario] persona '${this.name}' converse needs a model — pass options.model or set 'model' on the personas service`);
70
+ throw new Error(`[scenario] virtual user '${this.name}' converse needs a model — pass options.model or set 'model' on the virtual users service`);
89
71
  }
90
72
  const threadId = globalThis.crypto.randomUUID();
91
- const resourceId = `persona:${this.name}`;
73
+ const resourceId = `virtualUser:${this.name}`;
92
74
  return runConversation({
93
- persona: this.persona,
94
- personaId: this.name,
75
+ virtualUser: this.virtualUser,
76
+ virtualUserId: this.name,
95
77
  agentName: options.agent,
96
78
  task: options.task,
97
79
  evaluate: options.evaluate,
@@ -108,7 +90,7 @@ export class HttpPersona {
108
90
  /**
109
91
  * The roles the stage says this session holds.
110
92
  *
111
- * {@link HttpPersonasConfig.rolesRpc} first, then better-auth's
93
+ * {@link HttpVirtualUsersConfig.rolesRpc} first, then better-auth's
112
94
  * `get-session` — where its admin plugin puts `role` on the user, as a
113
95
  * comma-separated list. A target that answers neither returns `null` rather
114
96
  * than an empty list, because "this stage does not report roles" and "this
@@ -148,11 +130,9 @@ export class HttpPersona {
148
130
  return roles.filter((name) => typeof name === 'string');
149
131
  }
150
132
  async rolesFromSession() {
151
- const mount = authMount(this.config.operator?.signInPath ?? this.config.signInPath);
133
+ const mount = authMount(this.config.signInPath);
152
134
  const sessionPath = this.config.sessionPath ?? `${mount ?? '/auth'}/get-session`;
153
- const res = await this.jar.fetch(`${this.config.apiUrl}${sessionPath}`, {
154
- headers: this.signIn.headers(),
155
- });
135
+ const res = await this.jar.fetch(`${this.config.apiUrl}${sessionPath}`);
156
136
  if (!res.ok) {
157
137
  return null;
158
138
  }
@@ -183,7 +163,7 @@ export class HttpPersona {
183
163
  return user ? [] : null;
184
164
  }
185
165
  /**
186
- * Start/continue the target agent's run over HTTP as this persona.
166
+ * Start/continue the target agent's run over HTTP as this virtual user.
187
167
  *
188
168
  * The SSE route, not the plain one. `POST /rpc/agent/:name` buffers the whole
189
169
  * run before it sends a single byte, so a run longer than the client's
@@ -216,10 +196,7 @@ export class HttpPersona {
216
196
  const url = `${this.config.apiUrl}${rpcPath}/${subPath}`;
217
197
  const send = () => this.jar.fetch(url, {
218
198
  method: 'POST',
219
- headers: {
220
- 'content-type': 'application/json',
221
- ...this.signIn.headers(),
222
- },
199
+ headers: { 'content-type': 'application/json' },
223
200
  body: JSON.stringify(body),
224
201
  });
225
202
  let res = await send();
@@ -247,7 +224,6 @@ export class HttpPersona {
247
224
  method: 'POST',
248
225
  headers: {
249
226
  'content-type': 'application/json',
250
- ...this.signIn.headers(),
251
227
  ...extraHeaders,
252
228
  },
253
229
  body: JSON.stringify({ data }),
@@ -259,7 +235,7 @@ export class HttpPersona {
259
235
  this.signedIn = false;
260
236
  }
261
237
  async login() {
262
- await this.signIn.login(this.jar, this.persona);
238
+ await this.signIn.login(this.jar, this.virtualUser);
263
239
  this.signedIn = true;
264
240
  }
265
241
  }
@@ -358,13 +334,13 @@ function normalizeAgentReply(raw) {
358
334
  };
359
335
  }
360
336
  /**
361
- * Build the injected `personas` service from the declared personas: id → lazy
362
- * HTTP persona. Wire the result as the `personas` singleton service.
337
+ * Build the injected `virtualUsers` service from the declared virtual users: id → lazy
338
+ * HTTP virtual user. Wire the result as the `virtualUsers` singleton service.
363
339
  */
364
- export function createHttpPersonas(config) {
365
- const personas = {};
366
- for (const [id, persona] of Object.entries(config.personas)) {
367
- personas[id] = new HttpPersona(id, persona, config);
340
+ export function createHttpVirtualUsers(config) {
341
+ const virtualUsers = {};
342
+ for (const [id, virtualUser] of Object.entries(config.virtualUsers)) {
343
+ virtualUsers[id] = new HttpVirtualUser(id, virtualUser, config);
368
344
  }
369
- return personas;
345
+ return virtualUsers;
370
346
  }
@@ -1,8 +1,15 @@
1
- import type { QueueService, JobOptions } from '../wirings/queue/queue.types.js';
1
+ import type { QueueService, JobOptions, QueueInspection } from '../wirings/queue/queue.types.js';
2
2
  export declare class InMemoryQueueService implements QueueService {
3
3
  readonly supportsResults = false;
4
4
  private jobCounter;
5
+ private jobs;
6
+ private finishedTotals;
5
7
  add<T>(queueName: string, data: T, options?: JobOptions): Promise<string>;
6
8
  private backoffDelay;
7
9
  getJob(): Promise<null>;
10
+ inspect(queueName: string, opts?: {
11
+ limit?: number;
12
+ }): Promise<QueueInspection>;
13
+ private track;
14
+ private finish;
8
15
  }
@@ -1,16 +1,34 @@
1
1
  import { runQueueJob } from '../wirings/queue/queue-runner.js';
2
+ const FINISHED_JOBS_KEPT = 100;
2
3
  // knowledge: decisions/internals/the-dev-queue-copies-prod-timing-and-serialization-semantics.md
3
4
  export class InMemoryQueueService {
4
5
  supportsResults = false;
5
6
  jobCounter = 0;
7
+ jobs = new Map();
8
+ finishedTotals = new Map();
6
9
  async add(queueName, data, options) {
7
10
  const jobId = `inmem-${++this.jobCounter}`;
8
11
  const maxAttempts = Math.max(1, options?.attempts ?? 1);
9
12
  let attemptsMade = 0;
10
13
  const createdAt = new Date();
11
14
  const payload = data === undefined ? data : JSON.parse(JSON.stringify(data));
15
+ const record = {
16
+ jobId,
17
+ status: options?.delay ? 'delayed' : 'waiting',
18
+ attemptsMade: 0,
19
+ maxAttempts,
20
+ createdAt,
21
+ processedAt: null,
22
+ finishedAt: null,
23
+ durationMs: null,
24
+ error: null,
25
+ };
26
+ this.track(queueName, record);
12
27
  const runAttempt = async () => {
13
28
  attemptsMade++;
29
+ record.attemptsMade = attemptsMade;
30
+ record.status = 'active';
31
+ record.processedAt = new Date();
14
32
  const job = {
15
33
  id: jobId,
16
34
  queueName,
@@ -21,13 +39,17 @@ export class InMemoryQueueService {
21
39
  };
22
40
  try {
23
41
  await runQueueJob({ job });
42
+ this.finish(queueName, record, 'completed', null);
24
43
  }
25
44
  catch (e) {
45
+ record.error = e?.message ?? String(e);
26
46
  if (attemptsMade < maxAttempts) {
47
+ record.status = 'delayed';
27
48
  // Fire-and-forget retry: runAttempt catches every error itself.
28
49
  setTimeout(() => void runAttempt(), this.backoffDelay(options?.backoff, attemptsMade));
29
50
  }
30
51
  else {
52
+ this.finish(queueName, record, 'failed', record.error);
31
53
  console.error(`[InMemoryQueue] Job ${jobId} on ${queueName} failed after ${attemptsMade} attempt(s):`, e.message);
32
54
  }
33
55
  }
@@ -51,4 +73,49 @@ export class InMemoryQueueService {
51
73
  async getJob() {
52
74
  return null;
53
75
  }
76
+ async inspect(queueName, opts) {
77
+ const records = this.jobs.get(queueName) ?? [];
78
+ const totals = this.finishedTotals.get(queueName);
79
+ const counts = {
80
+ waiting: 0,
81
+ active: 0,
82
+ delayed: 0,
83
+ completed: totals?.completed ?? 0,
84
+ failed: totals?.failed ?? 0,
85
+ };
86
+ for (const record of records) {
87
+ if (record.status !== 'completed' && record.status !== 'failed') {
88
+ counts[record.status]++;
89
+ }
90
+ }
91
+ return {
92
+ counts,
93
+ recent: records
94
+ .slice(0, opts?.limit ?? 50)
95
+ .map((record) => ({ ...record })),
96
+ };
97
+ }
98
+ track(queueName, record) {
99
+ const records = this.jobs.get(queueName) ?? [];
100
+ records.unshift(record);
101
+ this.jobs.set(queueName, records);
102
+ }
103
+ finish(queueName, record, status, error) {
104
+ record.status = status;
105
+ record.error = error;
106
+ record.finishedAt = new Date();
107
+ record.durationMs =
108
+ record.finishedAt.getTime() -
109
+ (record.processedAt ?? record.createdAt).getTime();
110
+ const totals = this.finishedTotals.get(queueName) ?? {
111
+ completed: 0,
112
+ failed: 0,
113
+ };
114
+ totals[status]++;
115
+ this.finishedTotals.set(queueName, totals);
116
+ const records = this.jobs.get(queueName) ?? [];
117
+ let finished = 0;
118
+ this.jobs.set(queueName, records.filter((r) => (r.status !== 'completed' && r.status !== 'failed') ||
119
+ ++finished <= FINISHED_JOBS_KEPT));
120
+ }
54
121
  }
@@ -45,4 +45,6 @@ export declare class IncomingWebhookService {
45
45
  source?: string;
46
46
  limit?: number;
47
47
  }): Promise<IncomingWebhookReceiptRecord[]>;
48
+ /** Null when nothing is stored or no receipt has this id. */
49
+ getReceipt(_receiptId: string): Promise<IncomingWebhookReceiptRecord | null>;
48
50
  }
@@ -43,4 +43,8 @@ export class IncomingWebhookService {
43
43
  async listReceipts(_opts) {
44
44
  return [];
45
45
  }
46
+ /** Null when nothing is stored or no receipt has this id. */
47
+ async getReceipt(_receiptId) {
48
+ return null;
49
+ }
46
50
  }
@@ -23,12 +23,12 @@ export { InMemoryLeaseService } from './in-memory-lease-service.js';
23
23
  export { InMemoryAgentRunStateService } from './in-memory-agent-run-state-service.js';
24
24
  export { LocalGatewayService } from './local-gateway-service.js';
25
25
  export type { ContentService, ContentVisibility, GetDownloadURLArgs, SignContentKeyArgs, SignURLArgs, GetUploadURLArgs, UploadURLResult, BucketKeyArgs, WriteFileArgs, CopyFileArgs, } from './content-service.js';
26
- export type { ScenarioPersona, ResolvedPersona, ScenarioPersonas, } from './personas-service.js';
26
+ export type { ScenarioVirtualUser, ResolvedVirtualUser, ScenarioVirtualUsers, } from './virtual-users-service.js';
27
27
  export type { JWTService } from './jwt-service.js';
28
28
  export type { EmailAttachment, EmailService, SendEmailInput, SendEmailResult, SendHTMLEmailInput, SendTemplateEmailInput, SendTextEmailInput, } from './email-service.js';
29
29
  export { renderEmail, type EmailAssets, type EmailTemplateAssets, type EmailTemplateHashes, type RenderEmailRequest, type RenderedEmailResult, } from './email-template.js';
30
30
  export { DEFAULT_WEBHOOK_RETRIES, PIKKU_OUTGOING_WEBHOOK_QUEUE_NAME, WebhookService, type SendWebhookInput, type SendWebhookResult, type WebhookAttemptResult, type WebhookDeliveryRecord, type WebhookDeliveryWithAttempts, type WebhookJobData, type WebhookServiceConfig, } from './webhook-service.js';
31
- export { ACTOR_ROOT_SECRET_MIN_LENGTH, ACTOR_SECRET_INFO, ACTOR_SECRET_NAME, actorSecretSubject, deriveActorSecret, verifyActorSecret, } from './persona-actor-secret.js';
31
+ export { VIRTUAL_USER_IN_PROCESS_ENDPOINT, VIRTUAL_USER_STATEMENT_ALGORITHM, VIRTUAL_USER_STATEMENT_MAX_TTL_SECONDS, VIRTUAL_USER_STATEMENT_TTL_SECONDS, VIRTUAL_USER_SIGNING_KEY_VARIABLE, VIRTUAL_USER_VERIFY_KEY_VARIABLE, VirtualUserStatementError, type VirtualUserStatementVerifier, } from './virtual-user-statement.js';
32
32
  export type { Logger } from './logger.js';
33
33
  export type { SecretService, SecretValues } from './secret-service.js';
34
34
  export type { VariablesService } from './variables-service.js';
@@ -24,7 +24,7 @@ export { InMemoryAgentRunStateService } from './in-memory-agent-run-state-servic
24
24
  export { LocalGatewayService } from './local-gateway-service.js';
25
25
  export { renderEmail, } from './email-template.js';
26
26
  export { DEFAULT_WEBHOOK_RETRIES, PIKKU_OUTGOING_WEBHOOK_QUEUE_NAME, WebhookService, } from './webhook-service.js';
27
- export { ACTOR_ROOT_SECRET_MIN_LENGTH, ACTOR_SECRET_INFO, ACTOR_SECRET_NAME, actorSecretSubject, deriveActorSecret, verifyActorSecret, } from './persona-actor-secret.js';
27
+ export { VIRTUAL_USER_IN_PROCESS_ENDPOINT, VIRTUAL_USER_STATEMENT_ALGORITHM, VIRTUAL_USER_STATEMENT_MAX_TTL_SECONDS, VIRTUAL_USER_STATEMENT_TTL_SECONDS, VIRTUAL_USER_SIGNING_KEY_VARIABLE, VIRTUAL_USER_VERIFY_KEY_VARIABLE, VirtualUserStatementError, } from './virtual-user-statement.js';
28
28
  export { SchedulerService } from './scheduler-service.js';
29
29
  export { TypedCredentialService } from './typed-credential-service.js';
30
30
  export { NoopAuditService, createInvocationAudit } from './audit-service.js';