@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.
- package/CHANGELOG.md +368 -0
- package/dist/dev/hot-reload.js +13 -55
- package/dist/dev/module-runner.d.ts +14 -0
- package/dist/dev/module-runner.js +59 -0
- package/dist/dev/reload-meta.d.ts +13 -0
- package/dist/dev/reload-meta.js +22 -0
- package/dist/errors/errors.d.ts +12 -0
- package/dist/errors/errors.js +19 -0
- package/dist/function/function-runner.d.ts +5 -5
- package/dist/function/function-runner.js +39 -111
- package/dist/function/functions.types.d.ts +17 -7
- package/dist/index.d.ts +5 -1
- package/dist/index.js +3 -1
- package/dist/middleware/auth-apikey.d.ts +1 -0
- package/dist/middleware/auth-bearer.d.ts +1 -0
- package/dist/middleware/auth-cookie.d.ts +1 -0
- package/dist/middleware/cors.d.ts +1 -0
- package/dist/middleware/index.d.ts +1 -1
- package/dist/middleware/index.js +1 -1
- package/dist/middleware/remote-auth.d.ts +1 -0
- package/dist/middleware/telemetry.d.ts +2 -0
- package/dist/middleware/timeout.d.ts +1 -0
- package/dist/permissions.d.ts +42 -27
- package/dist/permissions.js +101 -203
- package/dist/pikku-state.js +0 -2
- package/dist/scopes.d.ts +17 -0
- package/dist/scopes.js +59 -0
- package/dist/services/ai-embedding-service.d.ts +31 -0
- package/dist/services/ai-embedding-service.js +1 -0
- package/dist/services/credential-wire-service.d.ts +3 -1
- package/dist/services/credential-wire-service.js +10 -4
- package/dist/services/index.d.ts +4 -0
- package/dist/services/index.js +2 -0
- package/dist/services/meta-service.d.ts +15 -2
- package/dist/services/meta-service.js +51 -1
- package/dist/services/queue-webhook-service.d.ts +55 -0
- package/dist/services/queue-webhook-service.js +136 -0
- package/dist/services/scope-service.d.ts +67 -0
- package/dist/services/scope-service.js +1 -0
- package/dist/services/typed-secret-service.d.ts +8 -0
- package/dist/services/typed-secret-service.js +39 -4
- package/dist/services/webhook-service.d.ts +140 -0
- package/dist/services/webhook-service.js +44 -0
- package/dist/services/workflow-service.d.ts +7 -0
- package/dist/testing/service-tests.js +37 -0
- package/dist/types/core.types.d.ts +34 -6
- package/dist/types/state.types.d.ts +20 -2
- package/dist/utils/hmac.d.ts +16 -0
- package/dist/utils/hmac.js +26 -0
- package/dist/utils/safe-fetch.d.ts +51 -0
- package/dist/utils/safe-fetch.js +192 -0
- package/dist/wirings/ai-agent/ai-agent-agui.d.ts +84 -0
- package/dist/wirings/ai-agent/ai-agent-agui.js +305 -0
- package/dist/wirings/ai-agent/ai-agent-prepare.d.ts +105 -1
- package/dist/wirings/ai-agent/ai-agent-prepare.js +249 -11
- package/dist/wirings/ai-agent/ai-agent-runner.js +10 -1
- package/dist/wirings/ai-agent/ai-agent-stream.js +88 -16
- package/dist/wirings/ai-agent/ai-agent.types.d.ts +56 -2
- package/dist/wirings/ai-agent/index.d.ts +2 -1
- package/dist/wirings/ai-agent/index.js +2 -1
- package/dist/wirings/ai-agent/voice-input.d.ts +1 -0
- package/dist/wirings/ai-agent/voice-input.js +5 -41
- package/dist/wirings/ai-agent/voice-output.d.ts +1 -0
- package/dist/wirings/channel/channel-common.js +0 -1
- package/dist/wirings/channel/channel-handler.js +1 -4
- package/dist/wirings/channel/channel-middleware-runner.d.ts +12 -0
- package/dist/wirings/channel/channel-middleware-runner.js +34 -19
- package/dist/wirings/channel/channel.types.d.ts +2 -6
- package/dist/wirings/cli/cli-runner.js +3 -2
- package/dist/wirings/cli/cli.types.d.ts +1 -2
- package/dist/wirings/cli/command-parser.d.ts +2 -0
- package/dist/wirings/cli/command-parser.js +59 -2
- package/dist/wirings/credential/credential.types.d.ts +14 -0
- package/dist/wirings/credential/validate-credential-definitions.js +1 -0
- package/dist/wirings/gateway/gateway-runner.js +100 -50
- package/dist/wirings/gateway/gateway.types.d.ts +8 -5
- package/dist/wirings/http/http-routes.js +0 -3
- package/dist/wirings/http/http-runner.d.ts +9 -29
- package/dist/wirings/http/http-runner.js +9 -34
- package/dist/wirings/http/http.types.d.ts +4 -12
- package/dist/wirings/mcp/mcp-runner.js +0 -2
- package/dist/wirings/mcp/mcp.types.d.ts +5 -11
- package/dist/wirings/oauth2/index.d.ts +0 -3
- package/dist/wirings/oauth2/index.js +1 -2
- package/dist/wirings/rpc/addon-runner.d.ts +28 -0
- package/dist/wirings/rpc/addon-runner.js +173 -0
- package/dist/wirings/rpc/index.d.ts +5 -1
- package/dist/wirings/rpc/index.js +3 -1
- package/dist/wirings/rpc/remote-addon-auth.d.ts +26 -0
- package/dist/wirings/rpc/remote-addon-auth.js +43 -0
- package/dist/wirings/rpc/rpc-runner.d.ts +19 -0
- package/dist/wirings/rpc/rpc-runner.js +109 -3
- package/dist/wirings/rpc/rpc-types.d.ts +15 -1
- package/dist/wirings/rpc/wire-addon.js +9 -0
- package/dist/wirings/rpc/wire-remote-addon.d.ts +47 -0
- package/dist/wirings/rpc/wire-remote-addon.js +19 -0
- package/dist/wirings/scope/index.d.ts +3 -0
- package/dist/wirings/scope/index.js +2 -0
- package/dist/wirings/scope/scope.types.d.ts +39 -0
- package/dist/wirings/scope/scope.types.js +1 -0
- package/dist/wirings/scope/validate-scope-definitions.d.ts +16 -0
- package/dist/wirings/scope/validate-scope-definitions.js +76 -0
- package/dist/wirings/scope/wire-scope.d.ts +33 -0
- package/dist/wirings/scope/wire-scope.js +32 -0
- package/dist/wirings/secret/secret.types.d.ts +14 -0
- package/dist/wirings/secret/validate-secret-definitions.js +2 -0
- package/dist/wirings/variable/validate-variable-definitions.js +2 -0
- package/dist/wirings/variable/variable.types.d.ts +14 -0
- package/dist/wirings/workflow/dsl/index.d.ts +1 -1
- package/dist/wirings/workflow/dsl/workflow-dsl.types.d.ts +89 -7
- package/dist/wirings/workflow/graph/graph-node.d.ts +2 -0
- package/dist/wirings/workflow/graph/graph-runner.js +3 -0
- package/dist/wirings/workflow/graph/wire-workflow-graph.d.ts +6 -0
- package/dist/wirings/workflow/graph/wire-workflow-graph.js +1 -0
- package/dist/wirings/workflow/graph/workflow-graph.types.d.ts +5 -0
- package/dist/wirings/workflow/index.d.ts +2 -2
- package/dist/wirings/workflow/index.js +1 -1
- package/dist/wirings/workflow/pikku-workflow-service.d.ts +59 -1
- package/dist/wirings/workflow/pikku-workflow-service.js +187 -0
- package/dist/wirings/workflow/workflow.types.d.ts +1 -3
- package/package.json +6 -1
- package/run-tests.sh +1 -0
- package/src/dev/hot-reload.ts +13 -68
- package/src/dev/module-runner.test.ts +169 -0
- package/src/dev/module-runner.ts +103 -0
- package/src/dev/reload-meta.test.ts +31 -2
- package/src/dev/reload-meta.ts +26 -0
- package/src/errors/errors.ts +24 -0
- package/src/function/function-runner.test.ts +276 -142
- package/src/function/function-runner.ts +52 -145
- package/src/function/functions.types.ts +28 -38
- package/src/index.ts +8 -6
- package/src/middleware/index.ts +1 -5
- package/src/permissions.test.ts +160 -373
- package/src/permissions.ts +137 -279
- package/src/pikku-state.ts +0 -2
- package/src/scopes.test.ts +167 -0
- package/src/scopes.ts +69 -0
- package/src/services/ai-embedding-service.ts +31 -0
- package/src/services/credential-wire-service.ts +10 -4
- package/src/services/index.ts +20 -0
- package/src/services/meta-service.ts +68 -3
- package/src/services/queue-webhook-service.test.ts +408 -0
- package/src/services/queue-webhook-service.ts +182 -0
- package/src/services/scope-service.ts +75 -0
- package/src/services/typed-secret-service.test.ts +35 -0
- package/src/services/typed-secret-service.ts +39 -4
- package/src/services/webhook-service.ts +180 -0
- package/src/services/workflow-service.ts +7 -0
- package/src/testing/service-tests.ts +49 -0
- package/src/types/core.types.ts +42 -14
- package/src/types/state.types.ts +23 -3
- package/src/utils/hmac.ts +27 -0
- package/src/utils/safe-fetch.test.ts +373 -0
- package/src/utils/safe-fetch.ts +213 -0
- package/src/wirings/ai-agent/ai-agent-agui.test.ts +1127 -0
- package/src/wirings/ai-agent/ai-agent-agui.ts +386 -0
- package/src/wirings/ai-agent/ai-agent-authorization.test.ts +204 -0
- package/src/wirings/ai-agent/ai-agent-prepare.test.ts +483 -0
- package/src/wirings/ai-agent/ai-agent-prepare.ts +324 -13
- package/src/wirings/ai-agent/ai-agent-resume-authorization.test.ts +207 -0
- package/src/wirings/ai-agent/ai-agent-runner.test.ts +48 -1
- package/src/wirings/ai-agent/ai-agent-runner.ts +28 -0
- package/src/wirings/ai-agent/ai-agent-stream.test.ts +301 -10
- package/src/wirings/ai-agent/ai-agent-stream.ts +122 -16
- package/src/wirings/ai-agent/ai-agent.types.ts +57 -0
- package/src/wirings/ai-agent/index.ts +5 -0
- package/src/wirings/ai-agent/voice-input.test.ts +90 -0
- package/src/wirings/ai-agent/voice-input.ts +9 -40
- package/src/wirings/channel/channel-common.ts +0 -1
- package/src/wirings/channel/channel-handler.ts +1 -9
- package/src/wirings/channel/channel-middleware-runner.test.ts +28 -2
- package/src/wirings/channel/channel-middleware-runner.ts +39 -27
- package/src/wirings/channel/channel.types.ts +0 -6
- package/src/wirings/cli/cli-runner.ts +4 -2
- package/src/wirings/cli/cli.types.ts +0 -2
- package/src/wirings/cli/command-parser.test.ts +130 -0
- package/src/wirings/cli/command-parser.ts +80 -2
- package/src/wirings/credential/credential.types.ts +14 -0
- package/src/wirings/credential/validate-credential-definitions.ts +1 -0
- package/src/wirings/gateway/gateway-authorization.test.ts +444 -0
- package/src/wirings/gateway/gateway-runner.ts +114 -68
- package/src/wirings/gateway/gateway.types.ts +7 -9
- package/src/wirings/http/http-routes.ts +0 -3
- package/src/wirings/http/http-runner.test.ts +1 -11
- package/src/wirings/http/http-runner.ts +16 -39
- package/src/wirings/http/http.types.ts +7 -14
- package/src/wirings/mcp/mcp-runner.ts +0 -2
- package/src/wirings/mcp/mcp.types.ts +3 -11
- package/src/wirings/oauth2/index.ts +0 -3
- package/src/wirings/rpc/addon-runner.ts +233 -0
- package/src/wirings/rpc/index.ts +17 -1
- package/src/wirings/rpc/remote-addon-auth.ts +69 -0
- package/src/wirings/rpc/rpc-runner.test.ts +319 -16
- package/src/wirings/rpc/rpc-runner.ts +155 -3
- package/src/wirings/rpc/rpc-types.ts +16 -5
- package/src/wirings/rpc/wire-addon.test.ts +6 -3
- package/src/wirings/rpc/wire-addon.ts +9 -0
- package/src/wirings/rpc/wire-remote-addon.ts +57 -0
- package/src/wirings/scope/index.ts +14 -0
- package/src/wirings/scope/scope.test.ts +135 -0
- package/src/wirings/scope/scope.types.ts +44 -0
- package/src/wirings/scope/validate-scope-definitions.ts +110 -0
- package/src/wirings/scope/wire-scope.ts +34 -0
- package/src/wirings/secret/secret.types.ts +14 -0
- package/src/wirings/secret/validate-secret-definitions.ts +2 -0
- package/src/wirings/variable/validate-variable-definitions.ts +2 -0
- package/src/wirings/variable/variable.types.ts +14 -0
- package/src/wirings/workflow/dsl/index.ts +4 -0
- package/src/wirings/workflow/dsl/workflow-dsl.types.ts +97 -6
- package/src/wirings/workflow/graph/graph-node.ts +2 -0
- package/src/wirings/workflow/graph/graph-runner.test.ts +58 -0
- package/src/wirings/workflow/graph/graph-runner.ts +3 -0
- package/src/wirings/workflow/graph/wire-workflow-graph.ts +7 -0
- package/src/wirings/workflow/graph/workflow-graph.types.ts +5 -0
- package/src/wirings/workflow/index.ts +5 -0
- package/src/wirings/workflow/pikku-workflow-service.test.ts +341 -0
- package/src/wirings/workflow/pikku-workflow-service.ts +272 -0
- package/src/wirings/workflow/workflow-on-error.test.ts +154 -0
- package/src/wirings/workflow/workflow-step-session.test.ts +21 -5
- package/src/wirings/workflow/workflow.types.ts +4 -2
- package/tsconfig.tsbuildinfo +1 -1
- package/src/wirings/oauth2/oauth2-client.test.ts +0 -930
- package/src/wirings/oauth2/oauth2-client.ts +0 -331
- 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
|
};
|