@pikku/core 0.12.63 → 0.12.66

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 (225) hide show
  1. package/CHANGELOG.md +368 -0
  2. package/dist/dev/hot-reload.js +13 -55
  3. package/dist/dev/module-runner.d.ts +14 -0
  4. package/dist/dev/module-runner.js +59 -0
  5. package/dist/dev/reload-meta.d.ts +13 -0
  6. package/dist/dev/reload-meta.js +22 -0
  7. package/dist/errors/errors.d.ts +12 -0
  8. package/dist/errors/errors.js +19 -0
  9. package/dist/function/function-runner.d.ts +5 -5
  10. package/dist/function/function-runner.js +39 -111
  11. package/dist/function/functions.types.d.ts +17 -7
  12. package/dist/index.d.ts +5 -1
  13. package/dist/index.js +3 -1
  14. package/dist/middleware/auth-apikey.d.ts +1 -0
  15. package/dist/middleware/auth-bearer.d.ts +1 -0
  16. package/dist/middleware/auth-cookie.d.ts +1 -0
  17. package/dist/middleware/cors.d.ts +1 -0
  18. package/dist/middleware/index.d.ts +1 -1
  19. package/dist/middleware/index.js +1 -1
  20. package/dist/middleware/remote-auth.d.ts +1 -0
  21. package/dist/middleware/telemetry.d.ts +2 -0
  22. package/dist/middleware/timeout.d.ts +1 -0
  23. package/dist/permissions.d.ts +42 -27
  24. package/dist/permissions.js +101 -203
  25. package/dist/pikku-state.js +0 -2
  26. package/dist/scopes.d.ts +17 -0
  27. package/dist/scopes.js +59 -0
  28. package/dist/services/ai-embedding-service.d.ts +31 -0
  29. package/dist/services/ai-embedding-service.js +1 -0
  30. package/dist/services/credential-wire-service.d.ts +3 -1
  31. package/dist/services/credential-wire-service.js +10 -4
  32. package/dist/services/index.d.ts +4 -0
  33. package/dist/services/index.js +2 -0
  34. package/dist/services/meta-service.d.ts +15 -2
  35. package/dist/services/meta-service.js +51 -1
  36. package/dist/services/queue-webhook-service.d.ts +55 -0
  37. package/dist/services/queue-webhook-service.js +136 -0
  38. package/dist/services/scope-service.d.ts +67 -0
  39. package/dist/services/scope-service.js +1 -0
  40. package/dist/services/typed-secret-service.d.ts +8 -0
  41. package/dist/services/typed-secret-service.js +39 -4
  42. package/dist/services/webhook-service.d.ts +140 -0
  43. package/dist/services/webhook-service.js +44 -0
  44. package/dist/services/workflow-service.d.ts +7 -0
  45. package/dist/testing/service-tests.js +37 -0
  46. package/dist/types/core.types.d.ts +34 -6
  47. package/dist/types/state.types.d.ts +20 -2
  48. package/dist/utils/hmac.d.ts +16 -0
  49. package/dist/utils/hmac.js +26 -0
  50. package/dist/utils/safe-fetch.d.ts +51 -0
  51. package/dist/utils/safe-fetch.js +192 -0
  52. package/dist/wirings/ai-agent/ai-agent-agui.d.ts +84 -0
  53. package/dist/wirings/ai-agent/ai-agent-agui.js +305 -0
  54. package/dist/wirings/ai-agent/ai-agent-prepare.d.ts +105 -1
  55. package/dist/wirings/ai-agent/ai-agent-prepare.js +249 -11
  56. package/dist/wirings/ai-agent/ai-agent-runner.js +10 -1
  57. package/dist/wirings/ai-agent/ai-agent-stream.js +88 -16
  58. package/dist/wirings/ai-agent/ai-agent.types.d.ts +56 -2
  59. package/dist/wirings/ai-agent/index.d.ts +2 -1
  60. package/dist/wirings/ai-agent/index.js +2 -1
  61. package/dist/wirings/ai-agent/voice-input.d.ts +1 -0
  62. package/dist/wirings/ai-agent/voice-input.js +5 -41
  63. package/dist/wirings/ai-agent/voice-output.d.ts +1 -0
  64. package/dist/wirings/channel/channel-common.js +0 -1
  65. package/dist/wirings/channel/channel-handler.js +1 -4
  66. package/dist/wirings/channel/channel-middleware-runner.d.ts +12 -0
  67. package/dist/wirings/channel/channel-middleware-runner.js +34 -19
  68. package/dist/wirings/channel/channel.types.d.ts +2 -6
  69. package/dist/wirings/cli/cli-runner.js +3 -2
  70. package/dist/wirings/cli/cli.types.d.ts +1 -2
  71. package/dist/wirings/cli/command-parser.d.ts +2 -0
  72. package/dist/wirings/cli/command-parser.js +59 -2
  73. package/dist/wirings/credential/credential.types.d.ts +14 -0
  74. package/dist/wirings/credential/validate-credential-definitions.js +1 -0
  75. package/dist/wirings/gateway/gateway-runner.js +100 -50
  76. package/dist/wirings/gateway/gateway.types.d.ts +8 -5
  77. package/dist/wirings/http/http-routes.js +0 -3
  78. package/dist/wirings/http/http-runner.d.ts +9 -29
  79. package/dist/wirings/http/http-runner.js +9 -34
  80. package/dist/wirings/http/http.types.d.ts +4 -12
  81. package/dist/wirings/mcp/mcp-runner.js +0 -2
  82. package/dist/wirings/mcp/mcp.types.d.ts +5 -11
  83. package/dist/wirings/oauth2/index.d.ts +0 -3
  84. package/dist/wirings/oauth2/index.js +1 -2
  85. package/dist/wirings/rpc/addon-runner.d.ts +28 -0
  86. package/dist/wirings/rpc/addon-runner.js +173 -0
  87. package/dist/wirings/rpc/index.d.ts +5 -1
  88. package/dist/wirings/rpc/index.js +3 -1
  89. package/dist/wirings/rpc/remote-addon-auth.d.ts +26 -0
  90. package/dist/wirings/rpc/remote-addon-auth.js +43 -0
  91. package/dist/wirings/rpc/rpc-runner.d.ts +19 -0
  92. package/dist/wirings/rpc/rpc-runner.js +109 -3
  93. package/dist/wirings/rpc/rpc-types.d.ts +15 -1
  94. package/dist/wirings/rpc/wire-addon.js +9 -0
  95. package/dist/wirings/rpc/wire-remote-addon.d.ts +47 -0
  96. package/dist/wirings/rpc/wire-remote-addon.js +19 -0
  97. package/dist/wirings/scope/index.d.ts +3 -0
  98. package/dist/wirings/scope/index.js +2 -0
  99. package/dist/wirings/scope/scope.types.d.ts +39 -0
  100. package/dist/wirings/scope/scope.types.js +1 -0
  101. package/dist/wirings/scope/validate-scope-definitions.d.ts +16 -0
  102. package/dist/wirings/scope/validate-scope-definitions.js +76 -0
  103. package/dist/wirings/scope/wire-scope.d.ts +33 -0
  104. package/dist/wirings/scope/wire-scope.js +32 -0
  105. package/dist/wirings/secret/secret.types.d.ts +14 -0
  106. package/dist/wirings/secret/validate-secret-definitions.js +2 -0
  107. package/dist/wirings/variable/validate-variable-definitions.js +2 -0
  108. package/dist/wirings/variable/variable.types.d.ts +14 -0
  109. package/dist/wirings/workflow/dsl/index.d.ts +1 -1
  110. package/dist/wirings/workflow/dsl/workflow-dsl.types.d.ts +89 -7
  111. package/dist/wirings/workflow/graph/graph-node.d.ts +2 -0
  112. package/dist/wirings/workflow/graph/graph-runner.js +3 -0
  113. package/dist/wirings/workflow/graph/wire-workflow-graph.d.ts +6 -0
  114. package/dist/wirings/workflow/graph/wire-workflow-graph.js +1 -0
  115. package/dist/wirings/workflow/graph/workflow-graph.types.d.ts +5 -0
  116. package/dist/wirings/workflow/index.d.ts +2 -2
  117. package/dist/wirings/workflow/index.js +1 -1
  118. package/dist/wirings/workflow/pikku-workflow-service.d.ts +59 -1
  119. package/dist/wirings/workflow/pikku-workflow-service.js +187 -0
  120. package/dist/wirings/workflow/workflow.types.d.ts +1 -3
  121. package/package.json +6 -1
  122. package/run-tests.sh +1 -0
  123. package/src/dev/hot-reload.ts +13 -68
  124. package/src/dev/module-runner.test.ts +169 -0
  125. package/src/dev/module-runner.ts +103 -0
  126. package/src/dev/reload-meta.test.ts +31 -2
  127. package/src/dev/reload-meta.ts +26 -0
  128. package/src/errors/errors.ts +24 -0
  129. package/src/function/function-runner.test.ts +276 -142
  130. package/src/function/function-runner.ts +52 -145
  131. package/src/function/functions.types.ts +28 -38
  132. package/src/index.ts +8 -6
  133. package/src/middleware/index.ts +1 -5
  134. package/src/permissions.test.ts +160 -373
  135. package/src/permissions.ts +137 -279
  136. package/src/pikku-state.ts +0 -2
  137. package/src/scopes.test.ts +167 -0
  138. package/src/scopes.ts +69 -0
  139. package/src/services/ai-embedding-service.ts +31 -0
  140. package/src/services/credential-wire-service.ts +10 -4
  141. package/src/services/index.ts +20 -0
  142. package/src/services/meta-service.ts +68 -3
  143. package/src/services/queue-webhook-service.test.ts +408 -0
  144. package/src/services/queue-webhook-service.ts +182 -0
  145. package/src/services/scope-service.ts +75 -0
  146. package/src/services/typed-secret-service.test.ts +35 -0
  147. package/src/services/typed-secret-service.ts +39 -4
  148. package/src/services/webhook-service.ts +180 -0
  149. package/src/services/workflow-service.ts +7 -0
  150. package/src/testing/service-tests.ts +49 -0
  151. package/src/types/core.types.ts +42 -14
  152. package/src/types/state.types.ts +23 -3
  153. package/src/utils/hmac.ts +27 -0
  154. package/src/utils/safe-fetch.test.ts +373 -0
  155. package/src/utils/safe-fetch.ts +213 -0
  156. package/src/wirings/ai-agent/ai-agent-agui.test.ts +1127 -0
  157. package/src/wirings/ai-agent/ai-agent-agui.ts +386 -0
  158. package/src/wirings/ai-agent/ai-agent-authorization.test.ts +204 -0
  159. package/src/wirings/ai-agent/ai-agent-prepare.test.ts +483 -0
  160. package/src/wirings/ai-agent/ai-agent-prepare.ts +324 -13
  161. package/src/wirings/ai-agent/ai-agent-resume-authorization.test.ts +207 -0
  162. package/src/wirings/ai-agent/ai-agent-runner.test.ts +48 -1
  163. package/src/wirings/ai-agent/ai-agent-runner.ts +28 -0
  164. package/src/wirings/ai-agent/ai-agent-stream.test.ts +301 -10
  165. package/src/wirings/ai-agent/ai-agent-stream.ts +122 -16
  166. package/src/wirings/ai-agent/ai-agent.types.ts +57 -0
  167. package/src/wirings/ai-agent/index.ts +5 -0
  168. package/src/wirings/ai-agent/voice-input.test.ts +90 -0
  169. package/src/wirings/ai-agent/voice-input.ts +9 -40
  170. package/src/wirings/channel/channel-common.ts +0 -1
  171. package/src/wirings/channel/channel-handler.ts +1 -9
  172. package/src/wirings/channel/channel-middleware-runner.test.ts +28 -2
  173. package/src/wirings/channel/channel-middleware-runner.ts +39 -27
  174. package/src/wirings/channel/channel.types.ts +0 -6
  175. package/src/wirings/cli/cli-runner.ts +4 -2
  176. package/src/wirings/cli/cli.types.ts +0 -2
  177. package/src/wirings/cli/command-parser.test.ts +130 -0
  178. package/src/wirings/cli/command-parser.ts +80 -2
  179. package/src/wirings/credential/credential.types.ts +14 -0
  180. package/src/wirings/credential/validate-credential-definitions.ts +1 -0
  181. package/src/wirings/gateway/gateway-authorization.test.ts +444 -0
  182. package/src/wirings/gateway/gateway-runner.ts +114 -68
  183. package/src/wirings/gateway/gateway.types.ts +7 -9
  184. package/src/wirings/http/http-routes.ts +0 -3
  185. package/src/wirings/http/http-runner.test.ts +1 -11
  186. package/src/wirings/http/http-runner.ts +16 -39
  187. package/src/wirings/http/http.types.ts +7 -14
  188. package/src/wirings/mcp/mcp-runner.ts +0 -2
  189. package/src/wirings/mcp/mcp.types.ts +3 -11
  190. package/src/wirings/oauth2/index.ts +0 -3
  191. package/src/wirings/rpc/addon-runner.ts +233 -0
  192. package/src/wirings/rpc/index.ts +17 -1
  193. package/src/wirings/rpc/remote-addon-auth.ts +69 -0
  194. package/src/wirings/rpc/rpc-runner.test.ts +319 -16
  195. package/src/wirings/rpc/rpc-runner.ts +155 -3
  196. package/src/wirings/rpc/rpc-types.ts +16 -5
  197. package/src/wirings/rpc/wire-addon.test.ts +6 -3
  198. package/src/wirings/rpc/wire-addon.ts +9 -0
  199. package/src/wirings/rpc/wire-remote-addon.ts +57 -0
  200. package/src/wirings/scope/index.ts +14 -0
  201. package/src/wirings/scope/scope.test.ts +135 -0
  202. package/src/wirings/scope/scope.types.ts +44 -0
  203. package/src/wirings/scope/validate-scope-definitions.ts +110 -0
  204. package/src/wirings/scope/wire-scope.ts +34 -0
  205. package/src/wirings/secret/secret.types.ts +14 -0
  206. package/src/wirings/secret/validate-secret-definitions.ts +2 -0
  207. package/src/wirings/variable/validate-variable-definitions.ts +2 -0
  208. package/src/wirings/variable/variable.types.ts +14 -0
  209. package/src/wirings/workflow/dsl/index.ts +4 -0
  210. package/src/wirings/workflow/dsl/workflow-dsl.types.ts +97 -6
  211. package/src/wirings/workflow/graph/graph-node.ts +2 -0
  212. package/src/wirings/workflow/graph/graph-runner.test.ts +58 -0
  213. package/src/wirings/workflow/graph/graph-runner.ts +3 -0
  214. package/src/wirings/workflow/graph/wire-workflow-graph.ts +7 -0
  215. package/src/wirings/workflow/graph/workflow-graph.types.ts +5 -0
  216. package/src/wirings/workflow/index.ts +5 -0
  217. package/src/wirings/workflow/pikku-workflow-service.test.ts +341 -0
  218. package/src/wirings/workflow/pikku-workflow-service.ts +272 -0
  219. package/src/wirings/workflow/workflow-on-error.test.ts +154 -0
  220. package/src/wirings/workflow/workflow-step-session.test.ts +21 -5
  221. package/src/wirings/workflow/workflow.types.ts +4 -2
  222. package/tsconfig.tsbuildinfo +1 -1
  223. package/src/wirings/oauth2/oauth2-client.test.ts +0 -930
  224. package/src/wirings/oauth2/oauth2-client.ts +0 -331
  225. package/src/wirings/oauth2/oauth2-routes.ts +0 -234
@@ -0,0 +1,305 @@
1
+ import { randomUUID } from './ai-agent-utils.js';
2
+ function resultToString(result) {
3
+ if (typeof result === 'string')
4
+ return result;
5
+ try {
6
+ return JSON.stringify(result, (_key, val) => typeof val === 'bigint' ? val.toString() : val);
7
+ }
8
+ catch {
9
+ return String(result);
10
+ }
11
+ }
12
+ export function wrapChannelWithAGUI(inner, options) {
13
+ const threadId = options?.threadId ?? randomUUID();
14
+ let runId = options?.runId ?? null;
15
+ function resolveRunId() {
16
+ if (!runId) {
17
+ runId = options?.getRunId?.() ?? randomUUID();
18
+ }
19
+ return runId;
20
+ }
21
+ let textMessageId = null;
22
+ let thinkingMessageId = null;
23
+ let openStepName = null;
24
+ let stepSeq = 0;
25
+ let runStartedSent = false;
26
+ let terminal = false;
27
+ let sawUsage = false;
28
+ let usageModel;
29
+ const usageTotals = { input: 0, output: 0 };
30
+ // The AG-UI client rejects any event arriving before RUN_STARTED, so the
31
+ // run is opened lazily with the first translated event.
32
+ function send(event) {
33
+ if (!runStartedSent) {
34
+ runStartedSent = true;
35
+ inner.send({
36
+ type: 'RUN_STARTED',
37
+ threadId,
38
+ runId: resolveRunId(),
39
+ });
40
+ }
41
+ inner.send(event);
42
+ }
43
+ function endTextMessage() {
44
+ if (textMessageId) {
45
+ send({ type: 'TEXT_MESSAGE_END', messageId: textMessageId });
46
+ textMessageId = null;
47
+ }
48
+ }
49
+ function endThinkingMessage() {
50
+ if (thinkingMessageId) {
51
+ send({ type: 'THINKING_TEXT_MESSAGE_END', messageId: thinkingMessageId });
52
+ send({ type: 'THINKING_END' });
53
+ thinkingMessageId = null;
54
+ }
55
+ }
56
+ function endStep() {
57
+ if (openStepName) {
58
+ send({ type: 'STEP_FINISHED', stepName: openStepName });
59
+ openStepName = null;
60
+ }
61
+ }
62
+ function ensureTextMessage() {
63
+ if (!textMessageId) {
64
+ textMessageId = randomUUID();
65
+ send({ type: 'TEXT_MESSAGE_START', messageId: textMessageId });
66
+ }
67
+ return textMessageId;
68
+ }
69
+ function ensureThinkingMessage() {
70
+ if (!thinkingMessageId) {
71
+ thinkingMessageId = randomUUID();
72
+ send({ type: 'THINKING_START' });
73
+ send({
74
+ type: 'THINKING_TEXT_MESSAGE_START',
75
+ messageId: thinkingMessageId,
76
+ });
77
+ }
78
+ return thinkingMessageId;
79
+ }
80
+ // The AG-UI client treats RUN_FINISHED as terminal and rejects everything
81
+ // after it, so it is emitted exactly once — on 'done' — with the usage
82
+ // accumulated across all steps (per-step 'usage' events must NOT finish
83
+ // the run: on multi-step tool runs later steps would arrive after
84
+ // RUN_FINISHED and the client would drop the whole stream).
85
+ function finishRun() {
86
+ endTextMessage();
87
+ endThinkingMessage();
88
+ endStep();
89
+ send({
90
+ type: 'RUN_FINISHED',
91
+ threadId,
92
+ runId: resolveRunId(),
93
+ ...(usageModel ? { model: usageModel } : {}),
94
+ ...(sawUsage
95
+ ? {
96
+ usage: {
97
+ promptTokens: usageTotals.input,
98
+ completionTokens: usageTotals.output,
99
+ totalTokens: usageTotals.input + usageTotals.output,
100
+ },
101
+ }
102
+ : {}),
103
+ });
104
+ terminal = true;
105
+ }
106
+ return {
107
+ channelId: inner.channelId,
108
+ openingData: inner.openingData,
109
+ get state() {
110
+ return inner.state;
111
+ },
112
+ setState: (s) => inner.setState(s),
113
+ getState: () => inner.getState(),
114
+ clearState: () => inner.clearState(),
115
+ sendBinary: (data) => inner.sendBinary(data),
116
+ close: () => inner.close(),
117
+ send: (event) => {
118
+ if (terminal)
119
+ return;
120
+ switch (event.type) {
121
+ case 'text-delta': {
122
+ endThinkingMessage();
123
+ const id = ensureTextMessage();
124
+ send({
125
+ type: 'TEXT_MESSAGE_CONTENT',
126
+ messageId: id,
127
+ delta: event.text,
128
+ });
129
+ break;
130
+ }
131
+ case 'reasoning-delta': {
132
+ endTextMessage();
133
+ const id = ensureThinkingMessage();
134
+ send({
135
+ type: 'THINKING_TEXT_MESSAGE_CONTENT',
136
+ messageId: id,
137
+ delta: event.text,
138
+ });
139
+ break;
140
+ }
141
+ case 'tool-call': {
142
+ endTextMessage();
143
+ endThinkingMessage();
144
+ send({
145
+ type: 'TOOL_CALL_START',
146
+ toolCallId: event.toolCallId,
147
+ toolCallName: event.toolName,
148
+ });
149
+ send({
150
+ type: 'TOOL_CALL_ARGS',
151
+ toolCallId: event.toolCallId,
152
+ delta: resultToString(event.args) || '{}',
153
+ });
154
+ send({
155
+ type: 'TOOL_CALL_END',
156
+ toolCallId: event.toolCallId,
157
+ toolCallName: event.toolName,
158
+ });
159
+ break;
160
+ }
161
+ case 'tool-result': {
162
+ send({
163
+ type: 'TOOL_CALL_RESULT',
164
+ messageId: randomUUID(),
165
+ toolCallId: event.toolCallId,
166
+ role: 'tool',
167
+ content: resultToString(event.result),
168
+ });
169
+ break;
170
+ }
171
+ case 'usage': {
172
+ endTextMessage();
173
+ endThinkingMessage();
174
+ sawUsage = true;
175
+ usageTotals.input += event.tokens.input;
176
+ usageTotals.output += event.tokens.output;
177
+ if (event.model)
178
+ usageModel = event.model;
179
+ break;
180
+ }
181
+ case 'error': {
182
+ endTextMessage();
183
+ endThinkingMessage();
184
+ endStep();
185
+ send({ type: 'RUN_ERROR', message: event.message });
186
+ terminal = true;
187
+ break;
188
+ }
189
+ case 'done': {
190
+ finishRun();
191
+ break;
192
+ }
193
+ // Step names must be unique among active steps on the client and
194
+ // sub-agents reuse step numbers on the shared channel, so each
195
+ // step-start closes the previous step and gets a sequential name.
196
+ case 'step-start': {
197
+ endTextMessage();
198
+ endThinkingMessage();
199
+ endStep();
200
+ stepSeq += 1;
201
+ openStepName = `${event.agent ?? 'step'}#${stepSeq}`;
202
+ send({ type: 'STEP_STARTED', stepName: openStepName });
203
+ break;
204
+ }
205
+ case 'approval-request': {
206
+ endTextMessage();
207
+ endThinkingMessage();
208
+ send({
209
+ type: 'CUSTOM',
210
+ name: 'pikku:approval-request',
211
+ value: {
212
+ toolCallId: event.toolCallId,
213
+ toolName: event.toolName,
214
+ args: event.args,
215
+ reason: event.reason,
216
+ runId: event.runId,
217
+ agent: event.agent,
218
+ session: event.session,
219
+ },
220
+ });
221
+ break;
222
+ }
223
+ case 'credential-request': {
224
+ endTextMessage();
225
+ endThinkingMessage();
226
+ send({
227
+ type: 'CUSTOM',
228
+ name: 'pikku:credential-request',
229
+ value: {
230
+ toolCallId: event.toolCallId,
231
+ toolName: event.toolName,
232
+ args: event.args,
233
+ credentialName: event.credentialName,
234
+ credentialType: event.credentialType,
235
+ connectUrl: event.connectUrl,
236
+ runId: event.runId,
237
+ agent: event.agent,
238
+ session: event.session,
239
+ },
240
+ });
241
+ break;
242
+ }
243
+ case 'generative-ui': {
244
+ send({
245
+ type: 'CUSTOM',
246
+ name: 'pikku:generative-ui',
247
+ value: { spec: event.spec },
248
+ });
249
+ break;
250
+ }
251
+ case 'data': {
252
+ send({
253
+ type: 'CUSTOM',
254
+ name: 'pikku:data',
255
+ value: { name: event.name, data: event.data },
256
+ });
257
+ break;
258
+ }
259
+ case 'workflow-created': {
260
+ send({
261
+ type: 'CUSTOM',
262
+ name: 'pikku:workflow-created',
263
+ value: { workflowName: event.workflowName, graph: event.graph },
264
+ });
265
+ break;
266
+ }
267
+ case 'agent-call': {
268
+ send({
269
+ type: 'CUSTOM',
270
+ name: 'pikku:agent-call',
271
+ value: {
272
+ agentName: event.agentName,
273
+ session: event.session,
274
+ input: event.input,
275
+ },
276
+ });
277
+ break;
278
+ }
279
+ case 'agent-result': {
280
+ send({
281
+ type: 'CUSTOM',
282
+ name: 'pikku:agent-result',
283
+ value: {
284
+ agentName: event.agentName,
285
+ session: event.session,
286
+ result: event.result,
287
+ },
288
+ });
289
+ break;
290
+ }
291
+ case 'suspended': {
292
+ send({
293
+ type: 'CUSTOM',
294
+ name: 'pikku:suspended',
295
+ value: { reason: event.reason, missingRpcs: event.missingRpcs },
296
+ });
297
+ break;
298
+ }
299
+ case 'audio-delta':
300
+ case 'audio-done':
301
+ break;
302
+ }
303
+ },
304
+ };
305
+ }
@@ -1,5 +1,5 @@
1
1
  import type { CoreUserSession } from '../../types/core.types.js';
2
- import type { CoreAIAgent, AIAgentInput, AIAgentToolDef, AIMessage, AIStreamChannel, PikkuAIMiddlewareHooks } from './ai-agent.types.js';
2
+ import type { CoreAIAgent, AIAgentInput, AIAgentToolDef, AIMessage, AIStreamChannel, PikkuAIMiddlewareHooks, SessionScope } from './ai-agent.types.js';
3
3
  import type { AIAgentRunnerParams } from '../../services/ai-agent-runner-service.js';
4
4
  import { PikkuError } from '../../errors/error-handler.js';
5
5
  import type { SessionService } from '../../services/user-session-service.js';
@@ -8,9 +8,91 @@ export type RunAIAgentParams = {
8
8
  /** Credential accessor for the current request — used to read per-user overrides (e.g. AI_API_KEY). */
9
9
  getCredential?: <T = unknown>(name: string) => T | null | Promise<T | null>;
10
10
  };
11
+ /**
12
+ * The ownership key for a thread/run: the trusted principal (the authenticated
13
+ * `session.userId` for `'user'` scope, or `session.orgId` for `'org'` scope)
14
+ * composed with the client-supplied `resourceId` as a sub-partition —
15
+ * `principal:resourceId`. Because the principal is always the prefix, a client
16
+ * `resourceId` can sub-divide within the caller's own boundary but can never
17
+ * widen access to another user's or org's threads.
18
+ *
19
+ * Idempotent: a value that is already within the caller's namespace (top-level
20
+ * re-entry, sub-agent recursion, or resume, which all pass an already-composite
21
+ * `resourceId`) is returned unchanged rather than double-composed.
22
+ *
23
+ * `'org'` scope with no session org throws {@link ForbiddenError} — falling back
24
+ * to a bare/shared key would leak across organizations. Sessionless `'user'`
25
+ * wirings have no trusted principal and fall back to the requested `resourceId`
26
+ * as a best-effort partition key.
27
+ */
28
+ export declare function resolveOwnerResourceId(params: RunAIAgentParams, sessionScope: SessionScope | undefined, requestedResourceId: string): string;
29
+ /** The declared {@link SessionScope} for an agent, defaulting to `'user'`. */
30
+ export declare function agentSessionScope(agentName: string): SessionScope;
31
+ /**
32
+ * Enforce that a stored thread/run belongs to the caller's owner resource,
33
+ * throwing {@link ForbiddenError} (without echoing the id, to avoid an
34
+ * existence oracle) on a mismatch.
35
+ */
36
+ export declare function assertResourceOwner(ownerResourceId: string, storedResourceId: string, kind: 'thread' | 'run'): void;
37
+ /** A session's trusted principals, in the order they may be read as. */
38
+ export declare function sessionPrincipals(session: {
39
+ userId?: string;
40
+ orgId?: string;
41
+ } | undefined): string[];
42
+ /**
43
+ * Whether `storedResourceId` belongs to `principal` under the composition
44
+ * {@link resolveOwnerResourceId} performs — either the bare principal or one of
45
+ * its `principal:` sub-partitions. The `:` is required so that `alice` does not
46
+ * match a `alice-evil:…` lookalike.
47
+ */
48
+ export declare function isOwnedByPrincipal(storedResourceId: string, principal: string): boolean;
49
+ /**
50
+ * The `owners` constraint to pass to `AgentRunService.listThreads` for a caller.
51
+ *
52
+ * Returns `undefined` — not `[]` — for a session with no principal, because an
53
+ * empty list means "match nothing" whereas a sessionless deployment (agent
54
+ * `no-auth`) has no ownership model to constrain by. Keeping that carve-out here
55
+ * rather than at each call site stops it from being re-derived inconsistently.
56
+ */
57
+ export declare function threadOwnerConstraint(session: {
58
+ userId?: string;
59
+ orgId?: string;
60
+ } | undefined): string[] | undefined;
61
+ /**
62
+ * Whether a stored thread/run may be read by the caller. Shaped as a predicate
63
+ * so it can back a `pikkuPermission` — authorization belongs in a function's
64
+ * `permissions` field, never in its body.
65
+ *
66
+ * Unlike {@link assertResourceOwner}, which compares against a single composed
67
+ * owner key on the run path, this guards the thread-management reads where the
68
+ * caller supplies only a `threadId` — so ownership has to be derived from the
69
+ * session rather than from the request.
70
+ *
71
+ * A session with no principal means the deployment opted out of authorization
72
+ * (agent `no-auth`), so there is no ownership model to enforce and access is not
73
+ * gated — mirroring {@link resolveOwnerResourceId}'s sessionless fallback to a
74
+ * bare resourceId.
75
+ */
76
+ export declare function canAccessThread(storedResourceId: string, session: {
77
+ userId?: string;
78
+ orgId?: string;
79
+ } | undefined): boolean;
11
80
  export type StreamAIAgentOptions = {
12
81
  requiresToolApproval?: 'all' | 'explicit' | false;
82
+ /**
83
+ * Invoked as soon as the run's AIRunStateService id exists, so transport
84
+ * wrappers (e.g. the AG-UI bridge) can stamp the real runId on RUN_STARTED.
85
+ */
86
+ onRunCreated?: (runId: string) => void;
13
87
  };
88
+ /**
89
+ * Non-forgeable brand for the sub-agent approval marker. Only framework code
90
+ * (the delegating sub-agent tools below) sets this Symbol on a tool result; a
91
+ * sub-agent's LLM-shaped `result.object` — plain JSON — cannot carry a Symbol,
92
+ * so `checkForApprovals` trusts the brand rather than the `__approvalRequired`
93
+ * string key to decide an approval must be surfaced.
94
+ */
95
+ export declare const APPROVAL_REQUIRED: unique symbol;
14
96
  export declare class ToolApprovalRequired extends PikkuError {
15
97
  readonly toolCallId: string;
16
98
  readonly toolName: string;
@@ -54,12 +136,34 @@ export declare const resolveAgent: (agentName: string) => {
54
136
  packageName: string | null;
55
137
  resolvedName: string;
56
138
  };
139
+ /**
140
+ * Enforces an agent's own authorization before it runs: session presence
141
+ * (`auth`), then `scopes`, then `permissions`.
142
+ *
143
+ * The ordering mirrors the function runner — scopes are an AND gate checked
144
+ * first, so they can only ever narrow access, and a missing scope short-circuits
145
+ * before any permission function does I/O.
146
+ *
147
+ * `auth` follows `pikkuSessionlessFunc` rather than `pikkuFunc`: a session is
148
+ * required only when `auth: true` is set explicitly. An agent is normally
149
+ * reached from a function that has already enforced its own auth, and agents are
150
+ * also run from genuinely sessionless contexts (crons, queue workers), so
151
+ * requiring a session by default would reject those without adding a meaningful
152
+ * gate. `scopes` and `permissions` are always enforced when declared.
153
+ *
154
+ * Globals are evaluated here too (via {@link runPermissions}) rather than being
155
+ * assumed to have already run: an agent is reachable from entry points that do
156
+ * not go through the function runner, and re-evaluating an AND gate of
157
+ * side-effect-free predicates is idempotent.
158
+ */
159
+ export declare function assertAgentAuthorized(agent: CoreAIAgent, params: RunAIAgentParams, packageName: string | null): Promise<void>;
57
160
  export declare function buildInstructions(agentName: string, packageName: string | null): Promise<string>;
58
161
  export type ScopedChannel = AIStreamChannel & {
59
162
  approvals: Array<{
60
163
  toolCallId: string;
61
164
  toolName: string;
62
165
  args: unknown;
166
+ reason?: string;
63
167
  runId: string;
64
168
  }>;
65
169
  };