@pikku/core 0.12.137 → 0.12.139
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 +40 -0
- package/dist/dev/hot-reload.js +5 -2
- package/dist/env.d.ts +18 -0
- package/dist/env.js +60 -1
- package/dist/function/abort-scope.d.ts +6 -5
- package/dist/function/abort-scope.js +6 -17
- package/dist/function/function-runner.js +2 -1
- package/dist/middleware/addon-scope-cap.d.ts +19 -0
- package/dist/middleware/addon-scope-cap.js +34 -0
- package/dist/middleware/auth-apikey.js +1 -1
- package/dist/middleware/auth-bearer.js +1 -1
- package/dist/middleware/auth-cookie.js +1 -1
- package/dist/middleware/index.d.ts +1 -0
- package/dist/middleware/index.js +1 -0
- package/dist/schema.js +3 -1
- package/dist/scopes.d.ts +8 -0
- package/dist/scopes.js +23 -0
- package/dist/services/content-service.d.ts +13 -1
- package/dist/services/in-memory-queue-service.js +4 -2
- package/dist/services/in-memory-workflow-service.js +7 -6
- package/dist/services/index.d.ts +2 -2
- package/dist/services/index.js +1 -1
- package/dist/services/local-content-request-handler.js +21 -60
- package/dist/services/local-content.d.ts +45 -1
- package/dist/services/local-content.js +202 -18
- package/dist/services/local-variables.d.ts +5 -0
- package/dist/services/local-variables.js +7 -2
- package/dist/services/queue-webhook-service.js +1 -1
- package/dist/services/scoped-content-service.d.ts +35 -0
- package/dist/services/scoped-content-service.js +171 -0
- package/dist/services/webhook-service.d.ts +2 -2
- package/dist/services/webhook-service.js +6 -4
- package/dist/types/core.types.d.ts +10 -1
- package/dist/types/state.types.d.ts +8 -0
- package/dist/utils/hmac.d.ts +25 -10
- package/dist/utils/hmac.js +202 -24
- package/dist/wirings/addon/addon-reach.d.ts +3 -0
- package/dist/wirings/addon/addon-reach.js +21 -0
- package/dist/wirings/addon/addon-runner.d.ts +6 -0
- package/dist/wirings/addon/addon-runner.js +13 -0
- package/dist/wirings/addon/define-screens.d.ts +32 -0
- package/dist/wirings/addon/define-screens.js +5 -0
- package/dist/wirings/addon/index.d.ts +2 -0
- package/dist/wirings/addon/index.js +1 -0
- package/dist/wirings/addon/wire-addon.d.ts +27 -0
- package/dist/wirings/addon/wire-addon.js +4 -0
- package/dist/wirings/agent/agent-agui.js +65 -62
- package/dist/wirings/agent/agent-interrupt.d.ts +4 -1
- package/dist/wirings/agent/agent-interrupt.js +3 -3
- package/dist/wirings/agent/agent-memory.js +5 -6
- package/dist/wirings/agent/agent-model-config.js +2 -1
- package/dist/wirings/agent/agent-prepare.js +24 -13
- package/dist/wirings/agent/agent-stream.js +38 -34
- package/dist/wirings/agent/agent.types.d.ts +8 -1
- package/dist/wirings/channel/channel-handler.js +1 -1
- package/dist/wirings/channel/local/local-channel-handler.js +5 -1
- package/dist/wirings/channel/local/local-channel-runner.js +6 -4
- package/dist/wirings/channel/local/local-eventhub-service.d.ts +1 -0
- package/dist/wirings/channel/local/local-eventhub-service.js +4 -1
- package/dist/wirings/cli/channel/cli-channel-runner.js +7 -2
- package/dist/wirings/cli/channel/cli-raw-client-runner.js +8 -4
- package/dist/wirings/cli/cli-runner.js +1 -1
- package/dist/wirings/gateway/gateway-runner.js +3 -3
- package/dist/wirings/http/http-runner.js +6 -6
- package/dist/wirings/rpc/rpc-runner.d.ts +4 -0
- package/dist/wirings/rpc/rpc-runner.js +41 -2
- package/dist/wirings/rpc/rpc-types.d.ts +6 -0
- package/dist/wirings/scheduler/scheduler-runner.js +1 -1
- package/dist/wirings/scope/define-scope.d.ts +19 -0
- package/dist/wirings/scope/define-scope.js +19 -0
- package/dist/wirings/scope/index.d.ts +2 -2
- package/dist/wirings/scope/index.js +2 -2
- package/dist/wirings/trigger/trigger-runner.js +3 -1
- package/dist/wirings/trigger/webhook-source-runner.js +5 -2
- package/dist/wirings/virtual-user/virtual-user-scaffold.js +3 -2
- package/dist/wirings/workflow/workflow-invocation-id.js +85 -8
- package/package.json +3 -1
- package/src/public-surface.json +65 -18
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export { wireAddon } from './wire-addon.js';
|
|
2
2
|
export type { WireAddonConfig } from './wire-addon.js';
|
|
3
|
+
export { defineScreens } from './define-screens.js';
|
|
4
|
+
export type { ScreensManifest, AddonScreen, AddonComponentScreen, AddonAppScreen, } from './define-screens.js';
|
|
3
5
|
export { wireRemoteAddon } from './wire-remote-addon.js';
|
|
4
6
|
export type { WireRemoteAddonConfig, RemoteAddonAuth, } from './wire-remote-addon.js';
|
|
5
7
|
export { resolveRemoteAddonToken, RemoteAddonAuthError, } from './remote-addon-auth.js';
|
|
@@ -41,8 +41,21 @@ export type WireAddonConfig = {
|
|
|
41
41
|
mcpEndpoint?: boolean | string;
|
|
42
42
|
/** Filters this addon in and out of a build — see the `tags` option on `pikku all`. It has no effect at runtime. */
|
|
43
43
|
tags?: string[];
|
|
44
|
+
/**
|
|
45
|
+
* Mounts the screens the addon ships (see `defineScreens`) in the host under
|
|
46
|
+
* `/addons/<name>`. Without it the addon's screens are ignored. The package
|
|
47
|
+
* must declare at least one, or `pikku all` rejects the wiring.
|
|
48
|
+
*/
|
|
49
|
+
ui?: boolean;
|
|
44
50
|
/** Required of every function in the addon, on top of the function's own. */
|
|
45
51
|
scopes?: string[];
|
|
52
|
+
/**
|
|
53
|
+
* The other addons this one may call, as `{ '<package>': '<name>' }`: the
|
|
54
|
+
* package it was written against, and the name that package is wired under
|
|
55
|
+
* in this app. The addon calls `'<package>:<function>'`; anything it did not
|
|
56
|
+
* list is refused, whatever else the app has wired.
|
|
57
|
+
*/
|
|
58
|
+
uses?: Record<string, string>;
|
|
46
59
|
/** Points a secret the addon reads at a different key in this deployment, so two instances can hold different credentials. */
|
|
47
60
|
secretOverrides?: Record<string, string>;
|
|
48
61
|
/** Points a variable the addon reads at a different key in this deployment. */
|
|
@@ -65,6 +78,20 @@ export type WireAddonConfig = {
|
|
|
65
78
|
* deploy manifest, and only the consuming app can grant it.
|
|
66
79
|
*/
|
|
67
80
|
globalCredentials?: string;
|
|
81
|
+
/**
|
|
82
|
+
* The folder of the content store this instance owns. Everything it stores
|
|
83
|
+
* lands under it and it cannot see past it. Defaults to `name`.
|
|
84
|
+
*/
|
|
85
|
+
contentBucket?: string;
|
|
86
|
+
/**
|
|
87
|
+
* Paths outside its own folder this instance may use, by path prefix:
|
|
88
|
+
* `read` allows reads and signed downloads, `write` adds uploads, writes and
|
|
89
|
+
* deletes. The longest matching prefix decides. The addon names a granted
|
|
90
|
+
* path by starting its bucket with `@`.
|
|
91
|
+
*/
|
|
92
|
+
contentGrants?: Record<string, 'read' | 'write'>;
|
|
93
|
+
/** Hands over the whole `ContentService` unscoped. The value is the reason, recorded in the deploy manifest. */
|
|
94
|
+
globalContent?: string;
|
|
68
95
|
};
|
|
69
96
|
/**
|
|
70
97
|
* Installs an addon into this project: its functions, wirings and scopes become
|
|
@@ -14,6 +14,7 @@ export const wireAddon = (config) => {
|
|
|
14
14
|
tags: config.tags,
|
|
15
15
|
...(config.expose !== undefined ? { expose: config.expose } : {}),
|
|
16
16
|
...(config.scopes ? { scopes: config.scopes } : {}),
|
|
17
|
+
...(config.uses ? { uses: config.uses } : {}),
|
|
17
18
|
...(config.secretOverrides
|
|
18
19
|
? { secretOverrides: config.secretOverrides }
|
|
19
20
|
: {}),
|
|
@@ -31,6 +32,9 @@ export const wireAddon = (config) => {
|
|
|
31
32
|
...(config.globalCredentials
|
|
32
33
|
? { globalCredentials: config.globalCredentials }
|
|
33
34
|
: {}),
|
|
35
|
+
...(config.contentBucket ? { contentBucket: config.contentBucket } : {}),
|
|
36
|
+
...(config.contentGrants ? { contentGrants: config.contentGrants } : {}),
|
|
37
|
+
...(config.globalContent ? { globalContent: config.globalContent } : {}),
|
|
34
38
|
});
|
|
35
39
|
};
|
|
36
40
|
/**
|
|
@@ -27,59 +27,62 @@ export function wrapChannelWithAGUI(inner, options) {
|
|
|
27
27
|
let sawUsage = false;
|
|
28
28
|
let usageModel;
|
|
29
29
|
const usageTotals = { input: 0, output: 0 };
|
|
30
|
-
function send(event) {
|
|
30
|
+
async function send(event) {
|
|
31
31
|
if (!runStartedSent) {
|
|
32
32
|
runStartedSent = true;
|
|
33
|
-
inner.send({
|
|
33
|
+
await inner.send({
|
|
34
34
|
type: 'RUN_STARTED',
|
|
35
35
|
threadId,
|
|
36
36
|
runId: resolveRunId(),
|
|
37
37
|
});
|
|
38
38
|
}
|
|
39
|
-
inner.send(event);
|
|
39
|
+
await inner.send(event);
|
|
40
40
|
}
|
|
41
|
-
function endTextMessage() {
|
|
41
|
+
async function endTextMessage() {
|
|
42
42
|
if (textMessageId) {
|
|
43
|
-
send({ type: 'TEXT_MESSAGE_END', messageId: textMessageId });
|
|
43
|
+
await send({ type: 'TEXT_MESSAGE_END', messageId: textMessageId });
|
|
44
44
|
textMessageId = null;
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
|
-
function endThinkingMessage() {
|
|
47
|
+
async function endThinkingMessage() {
|
|
48
48
|
if (thinkingMessageId) {
|
|
49
|
-
send({
|
|
50
|
-
|
|
49
|
+
await send({
|
|
50
|
+
type: 'THINKING_TEXT_MESSAGE_END',
|
|
51
|
+
messageId: thinkingMessageId,
|
|
52
|
+
});
|
|
53
|
+
await send({ type: 'THINKING_END' });
|
|
51
54
|
thinkingMessageId = null;
|
|
52
55
|
}
|
|
53
56
|
}
|
|
54
|
-
function endStep() {
|
|
57
|
+
async function endStep() {
|
|
55
58
|
if (openStepName) {
|
|
56
|
-
send({ type: 'STEP_FINISHED', stepName: openStepName });
|
|
59
|
+
await send({ type: 'STEP_FINISHED', stepName: openStepName });
|
|
57
60
|
openStepName = null;
|
|
58
61
|
}
|
|
59
62
|
}
|
|
60
|
-
function ensureTextMessage() {
|
|
63
|
+
async function ensureTextMessage() {
|
|
61
64
|
if (!textMessageId) {
|
|
62
65
|
textMessageId = randomUUID();
|
|
63
|
-
send({ type: 'TEXT_MESSAGE_START', messageId: textMessageId });
|
|
66
|
+
await send({ type: 'TEXT_MESSAGE_START', messageId: textMessageId });
|
|
64
67
|
}
|
|
65
68
|
return textMessageId;
|
|
66
69
|
}
|
|
67
|
-
function ensureThinkingMessage() {
|
|
70
|
+
async function ensureThinkingMessage() {
|
|
68
71
|
if (!thinkingMessageId) {
|
|
69
72
|
thinkingMessageId = randomUUID();
|
|
70
|
-
send({ type: 'THINKING_START' });
|
|
71
|
-
send({
|
|
73
|
+
await send({ type: 'THINKING_START' });
|
|
74
|
+
await send({
|
|
72
75
|
type: 'THINKING_TEXT_MESSAGE_START',
|
|
73
76
|
messageId: thinkingMessageId,
|
|
74
77
|
});
|
|
75
78
|
}
|
|
76
79
|
return thinkingMessageId;
|
|
77
80
|
}
|
|
78
|
-
function finishRun() {
|
|
79
|
-
endTextMessage();
|
|
80
|
-
endThinkingMessage();
|
|
81
|
-
endStep();
|
|
82
|
-
send({
|
|
81
|
+
async function finishRun() {
|
|
82
|
+
await endTextMessage();
|
|
83
|
+
await endThinkingMessage();
|
|
84
|
+
await endStep();
|
|
85
|
+
await send({
|
|
83
86
|
type: 'RUN_FINISHED',
|
|
84
87
|
threadId,
|
|
85
88
|
runId: resolveRunId(),
|
|
@@ -110,14 +113,14 @@ export function wrapChannelWithAGUI(inner, options) {
|
|
|
110
113
|
remote: (funcName, data) => inner.remote(funcName, data),
|
|
111
114
|
sendBinary: (data) => inner.sendBinary(data),
|
|
112
115
|
close: () => inner.close(),
|
|
113
|
-
send: (event) => {
|
|
116
|
+
send: async (event) => {
|
|
114
117
|
if (terminal)
|
|
115
118
|
return;
|
|
116
119
|
switch (event.type) {
|
|
117
120
|
case 'text-delta': {
|
|
118
|
-
endThinkingMessage();
|
|
119
|
-
const id = ensureTextMessage();
|
|
120
|
-
send({
|
|
121
|
+
await endThinkingMessage();
|
|
122
|
+
const id = await ensureTextMessage();
|
|
123
|
+
await send({
|
|
121
124
|
type: 'TEXT_MESSAGE_CONTENT',
|
|
122
125
|
messageId: id,
|
|
123
126
|
delta: event.text,
|
|
@@ -125,9 +128,9 @@ export function wrapChannelWithAGUI(inner, options) {
|
|
|
125
128
|
break;
|
|
126
129
|
}
|
|
127
130
|
case 'reasoning-delta': {
|
|
128
|
-
endTextMessage();
|
|
129
|
-
const id = ensureThinkingMessage();
|
|
130
|
-
send({
|
|
131
|
+
await endTextMessage();
|
|
132
|
+
const id = await ensureThinkingMessage();
|
|
133
|
+
await send({
|
|
131
134
|
type: 'THINKING_TEXT_MESSAGE_CONTENT',
|
|
132
135
|
messageId: id,
|
|
133
136
|
delta: event.text,
|
|
@@ -135,19 +138,19 @@ export function wrapChannelWithAGUI(inner, options) {
|
|
|
135
138
|
break;
|
|
136
139
|
}
|
|
137
140
|
case 'tool-call': {
|
|
138
|
-
endTextMessage();
|
|
139
|
-
endThinkingMessage();
|
|
140
|
-
send({
|
|
141
|
+
await endTextMessage();
|
|
142
|
+
await endThinkingMessage();
|
|
143
|
+
await send({
|
|
141
144
|
type: 'TOOL_CALL_START',
|
|
142
145
|
toolCallId: event.toolCallId,
|
|
143
146
|
toolCallName: event.toolName,
|
|
144
147
|
});
|
|
145
|
-
send({
|
|
148
|
+
await send({
|
|
146
149
|
type: 'TOOL_CALL_ARGS',
|
|
147
150
|
toolCallId: event.toolCallId,
|
|
148
151
|
delta: resultToString(event.args) || '{}',
|
|
149
152
|
});
|
|
150
|
-
send({
|
|
153
|
+
await send({
|
|
151
154
|
type: 'TOOL_CALL_END',
|
|
152
155
|
toolCallId: event.toolCallId,
|
|
153
156
|
toolCallName: event.toolName,
|
|
@@ -155,7 +158,7 @@ export function wrapChannelWithAGUI(inner, options) {
|
|
|
155
158
|
break;
|
|
156
159
|
}
|
|
157
160
|
case 'tool-result': {
|
|
158
|
-
send({
|
|
161
|
+
await send({
|
|
159
162
|
type: 'TOOL_CALL_RESULT',
|
|
160
163
|
messageId: randomUUID(),
|
|
161
164
|
toolCallId: event.toolCallId,
|
|
@@ -165,8 +168,8 @@ export function wrapChannelWithAGUI(inner, options) {
|
|
|
165
168
|
break;
|
|
166
169
|
}
|
|
167
170
|
case 'usage': {
|
|
168
|
-
endTextMessage();
|
|
169
|
-
endThinkingMessage();
|
|
171
|
+
await endTextMessage();
|
|
172
|
+
await endThinkingMessage();
|
|
170
173
|
sawUsage = true;
|
|
171
174
|
usageTotals.input += event.tokens.input;
|
|
172
175
|
usageTotals.output += event.tokens.output;
|
|
@@ -175,30 +178,30 @@ export function wrapChannelWithAGUI(inner, options) {
|
|
|
175
178
|
break;
|
|
176
179
|
}
|
|
177
180
|
case 'error': {
|
|
178
|
-
endTextMessage();
|
|
179
|
-
endThinkingMessage();
|
|
180
|
-
endStep();
|
|
181
|
-
send({ type: 'RUN_ERROR', message: event.message });
|
|
181
|
+
await endTextMessage();
|
|
182
|
+
await endThinkingMessage();
|
|
183
|
+
await endStep();
|
|
184
|
+
await send({ type: 'RUN_ERROR', message: event.message });
|
|
182
185
|
terminal = true;
|
|
183
186
|
break;
|
|
184
187
|
}
|
|
185
188
|
case 'done': {
|
|
186
|
-
finishRun();
|
|
189
|
+
await finishRun();
|
|
187
190
|
break;
|
|
188
191
|
}
|
|
189
192
|
case 'step-start': {
|
|
190
|
-
endTextMessage();
|
|
191
|
-
endThinkingMessage();
|
|
192
|
-
endStep();
|
|
193
|
+
await endTextMessage();
|
|
194
|
+
await endThinkingMessage();
|
|
195
|
+
await endStep();
|
|
193
196
|
stepSeq += 1;
|
|
194
197
|
openStepName = `${event.agent ?? 'step'}#${stepSeq}`;
|
|
195
|
-
send({ type: 'STEP_STARTED', stepName: openStepName });
|
|
198
|
+
await send({ type: 'STEP_STARTED', stepName: openStepName });
|
|
196
199
|
break;
|
|
197
200
|
}
|
|
198
201
|
case 'approval-request': {
|
|
199
|
-
endTextMessage();
|
|
200
|
-
endThinkingMessage();
|
|
201
|
-
send({
|
|
202
|
+
await endTextMessage();
|
|
203
|
+
await endThinkingMessage();
|
|
204
|
+
await send({
|
|
202
205
|
type: 'CUSTOM',
|
|
203
206
|
name: 'pikku:approval-request',
|
|
204
207
|
value: {
|
|
@@ -214,9 +217,9 @@ export function wrapChannelWithAGUI(inner, options) {
|
|
|
214
217
|
break;
|
|
215
218
|
}
|
|
216
219
|
case 'credential-request': {
|
|
217
|
-
endTextMessage();
|
|
218
|
-
endThinkingMessage();
|
|
219
|
-
send({
|
|
220
|
+
await endTextMessage();
|
|
221
|
+
await endThinkingMessage();
|
|
222
|
+
await send({
|
|
220
223
|
type: 'CUSTOM',
|
|
221
224
|
name: 'pikku:credential-request',
|
|
222
225
|
value: {
|
|
@@ -234,7 +237,7 @@ export function wrapChannelWithAGUI(inner, options) {
|
|
|
234
237
|
break;
|
|
235
238
|
}
|
|
236
239
|
case 'generative-ui': {
|
|
237
|
-
send({
|
|
240
|
+
await send({
|
|
238
241
|
type: 'CUSTOM',
|
|
239
242
|
name: 'pikku:generative-ui',
|
|
240
243
|
value: { spec: event.spec },
|
|
@@ -242,7 +245,7 @@ export function wrapChannelWithAGUI(inner, options) {
|
|
|
242
245
|
break;
|
|
243
246
|
}
|
|
244
247
|
case 'data': {
|
|
245
|
-
send({
|
|
248
|
+
await send({
|
|
246
249
|
type: 'CUSTOM',
|
|
247
250
|
name: 'pikku:data',
|
|
248
251
|
value: { name: event.name, data: event.data },
|
|
@@ -250,7 +253,7 @@ export function wrapChannelWithAGUI(inner, options) {
|
|
|
250
253
|
break;
|
|
251
254
|
}
|
|
252
255
|
case 'agent-call': {
|
|
253
|
-
send({
|
|
256
|
+
await send({
|
|
254
257
|
type: 'CUSTOM',
|
|
255
258
|
name: 'pikku:agent-call',
|
|
256
259
|
value: {
|
|
@@ -262,7 +265,7 @@ export function wrapChannelWithAGUI(inner, options) {
|
|
|
262
265
|
break;
|
|
263
266
|
}
|
|
264
267
|
case 'agent-result': {
|
|
265
|
-
send({
|
|
268
|
+
await send({
|
|
266
269
|
type: 'CUSTOM',
|
|
267
270
|
name: 'pikku:agent-result',
|
|
268
271
|
value: {
|
|
@@ -274,7 +277,7 @@ export function wrapChannelWithAGUI(inner, options) {
|
|
|
274
277
|
break;
|
|
275
278
|
}
|
|
276
279
|
case 'suspended': {
|
|
277
|
-
send({
|
|
280
|
+
await send({
|
|
278
281
|
type: 'CUSTOM',
|
|
279
282
|
name: 'pikku:suspended',
|
|
280
283
|
value: { reason: event.reason, missingRpcs: event.missingRpcs },
|
|
@@ -282,10 +285,10 @@ export function wrapChannelWithAGUI(inner, options) {
|
|
|
282
285
|
break;
|
|
283
286
|
}
|
|
284
287
|
case 'interrupted': {
|
|
285
|
-
endTextMessage();
|
|
286
|
-
endThinkingMessage();
|
|
287
|
-
endStep();
|
|
288
|
-
send({
|
|
288
|
+
await endTextMessage();
|
|
289
|
+
await endThinkingMessage();
|
|
290
|
+
await endStep();
|
|
291
|
+
await send({
|
|
289
292
|
type: 'CUSTOM',
|
|
290
293
|
name: 'pikku:interrupted',
|
|
291
294
|
value: {
|
|
@@ -298,7 +301,7 @@ export function wrapChannelWithAGUI(inner, options) {
|
|
|
298
301
|
}
|
|
299
302
|
// knowledge: decisions/internals/agent-speech-travels-as-a-custom-agui-event.md
|
|
300
303
|
case 'audio-delta': {
|
|
301
|
-
send({
|
|
304
|
+
await send({
|
|
302
305
|
type: 'CUSTOM',
|
|
303
306
|
name: 'pikku:audio-delta',
|
|
304
307
|
value: {
|
|
@@ -310,11 +313,11 @@ export function wrapChannelWithAGUI(inner, options) {
|
|
|
310
313
|
break;
|
|
311
314
|
}
|
|
312
315
|
case 'audio-done': {
|
|
313
|
-
send({ type: 'CUSTOM', name: 'pikku:audio-done', value: {} });
|
|
316
|
+
await send({ type: 'CUSTOM', name: 'pikku:audio-done', value: {} });
|
|
314
317
|
break;
|
|
315
318
|
}
|
|
316
319
|
case 'transcript': {
|
|
317
|
-
send({
|
|
320
|
+
await send({
|
|
318
321
|
type: 'CUSTOM',
|
|
319
322
|
name: 'pikku:transcript',
|
|
320
323
|
value: { text: event.text },
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type AbortScope } from '../../function/abort-scope.js';
|
|
1
2
|
import type { AgentStorageService } from '../../services/agent-storage-service.js';
|
|
2
3
|
/**
|
|
3
4
|
* Why an in-flight agent run was cut short.
|
|
@@ -126,7 +127,9 @@ export declare const getInFlightTools: (runId: string) => string[];
|
|
|
126
127
|
export declare const trackToolExecution: <T extends {
|
|
127
128
|
name: string;
|
|
128
129
|
readonly?: boolean;
|
|
129
|
-
execute: (input: any
|
|
130
|
+
execute: (input: any, options?: {
|
|
131
|
+
abortScope?: AbortScope;
|
|
132
|
+
}) => Promise<any>;
|
|
130
133
|
}>(tools: T[], handle: InterruptibleRunHandle) => T[];
|
|
131
134
|
export declare const trackInterruptNote: (threadId: string, write: Promise<void>) => void;
|
|
132
135
|
/** Await an interrupted tool result still being written to this thread. */
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { randomUUID } from './agent-utils.js';
|
|
2
|
-
import { AbandonedError
|
|
2
|
+
import { AbandonedError } from '../../function/abort-scope.js';
|
|
3
3
|
/**
|
|
4
4
|
* Thrown out of the step loop when a run is interrupted, so an interruption is
|
|
5
5
|
* distinguishable from a genuine failure at the one `catch` that would
|
|
@@ -162,7 +162,7 @@ export const trackToolExecution = (tools, handle) => tools.map((tool) => {
|
|
|
162
162
|
}
|
|
163
163
|
return {
|
|
164
164
|
...tool,
|
|
165
|
-
execute: (input) => {
|
|
165
|
+
execute: (input, options) => {
|
|
166
166
|
// Assumed to have changed something unless it says otherwise — the tool
|
|
167
167
|
// that never declares its checkpoint is the one that cannot be assumed
|
|
168
168
|
// harmless. `beginChanges()` can only ever make this more precise.
|
|
@@ -178,7 +178,7 @@ export const trackToolExecution = (tools, handle) => tools.map((tool) => {
|
|
|
178
178
|
call.mutating = true;
|
|
179
179
|
},
|
|
180
180
|
};
|
|
181
|
-
return handle.trackTool(tool.name, randomUUID(), () =>
|
|
181
|
+
return handle.trackTool(tool.name, randomUUID(), () => tool.execute(input, { ...options, abortScope: scope }), {
|
|
182
182
|
get collectResult() {
|
|
183
183
|
return call.mutating;
|
|
184
184
|
},
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { randomUUID } from 'crypto';
|
|
2
1
|
export function resolveMemoryServices(agent, singletonServices) {
|
|
3
2
|
const memoryConfig = agent.memory;
|
|
4
3
|
const storage = memoryConfig?.storage
|
|
@@ -83,7 +82,7 @@ export async function loadContextMessages(memoryConfig, storage, input, workingM
|
|
|
83
82
|
const workingMem = await workingMemoryStorage.getWorkingMemory(input.threadId, 'thread');
|
|
84
83
|
const prompt = buildWorkingMemoryPrompt(workingMem, workingMemoryJsonSchema);
|
|
85
84
|
contextMessages.push({
|
|
86
|
-
id: `wm-${randomUUID()}`,
|
|
85
|
+
id: `wm-${globalThis.crypto.randomUUID()}`,
|
|
87
86
|
role: 'system',
|
|
88
87
|
content: prompt,
|
|
89
88
|
createdAt: new Date(),
|
|
@@ -99,9 +98,9 @@ export async function saveMessages(storage, threadId, resourceId, memoryConfig,
|
|
|
99
98
|
const newMessages = userMessage ? [userMessage] : [];
|
|
100
99
|
for (const step of result.steps) {
|
|
101
100
|
if (step.toolCalls?.length) {
|
|
102
|
-
const toolCallIds = step.toolCalls.map(() => randomUUID());
|
|
101
|
+
const toolCallIds = step.toolCalls.map(() => globalThis.crypto.randomUUID());
|
|
103
102
|
newMessages.push({
|
|
104
|
-
id: randomUUID(),
|
|
103
|
+
id: globalThis.crypto.randomUUID(),
|
|
105
104
|
role: 'assistant',
|
|
106
105
|
toolCalls: step.toolCalls.map((tc, i) => ({
|
|
107
106
|
id: toolCallIds[i],
|
|
@@ -111,7 +110,7 @@ export async function saveMessages(storage, threadId, resourceId, memoryConfig,
|
|
|
111
110
|
createdAt: new Date(),
|
|
112
111
|
});
|
|
113
112
|
newMessages.push({
|
|
114
|
-
id: randomUUID(),
|
|
113
|
+
id: globalThis.crypto.randomUUID(),
|
|
115
114
|
role: 'tool',
|
|
116
115
|
toolResults: step.toolCalls.map((tc, i) => ({
|
|
117
116
|
id: toolCallIds[i],
|
|
@@ -132,7 +131,7 @@ export async function saveMessages(storage, threadId, resourceId, memoryConfig,
|
|
|
132
131
|
]
|
|
133
132
|
: responseText;
|
|
134
133
|
newMessages.push({
|
|
135
|
-
id: randomUUID(),
|
|
134
|
+
id: globalThis.crypto.randomUUID(),
|
|
136
135
|
role: 'assistant',
|
|
137
136
|
content: assistantContent || undefined,
|
|
138
137
|
createdAt: new Date(),
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
// knowledge: decisions/internals/agent-model-config-stays-a-single-resolution-seam.md
|
|
2
2
|
import { pikkuState } from '../../pikku-state.js';
|
|
3
|
+
import { readEnvVariable } from '../../env.js';
|
|
3
4
|
const isProviderQualified = (model) => model.includes('/');
|
|
4
5
|
/** `PIKKU_MODEL_ALIASES=cheap:openai/gpt-5-mini,tool:anthropic/claude-sonnet-5` */
|
|
5
6
|
const envAliases = () => {
|
|
6
|
-
const raw =
|
|
7
|
+
const raw = readEnvVariable('PIKKU_MODEL_ALIASES');
|
|
7
8
|
if (!raw)
|
|
8
9
|
return {};
|
|
9
10
|
const aliases = {};
|
|
@@ -247,7 +247,7 @@ export function createScopedChannel(parent, agentName, session) {
|
|
|
247
247
|
},
|
|
248
248
|
close: () => { },
|
|
249
249
|
sendBinary: (data) => parent.sendBinary(data),
|
|
250
|
-
send: (event) => {
|
|
250
|
+
send: async (event) => {
|
|
251
251
|
if (event.type === 'done')
|
|
252
252
|
return;
|
|
253
253
|
if (event.type === 'approval-request') {
|
|
@@ -267,10 +267,14 @@ export function createScopedChannel(parent, agentName, session) {
|
|
|
267
267
|
event.type === 'tool-result' ||
|
|
268
268
|
event.type === 'usage' ||
|
|
269
269
|
event.type === 'error') {
|
|
270
|
-
parent.send({
|
|
270
|
+
await parent.send({
|
|
271
|
+
...event,
|
|
272
|
+
agent: agentName,
|
|
273
|
+
session,
|
|
274
|
+
});
|
|
271
275
|
}
|
|
272
276
|
else {
|
|
273
|
-
parent.send(event);
|
|
277
|
+
await parent.send(event);
|
|
274
278
|
}
|
|
275
279
|
},
|
|
276
280
|
setState: (s) => parent.setState(s),
|
|
@@ -385,6 +389,9 @@ export async function buildToolDefs(params, agentSessionMap, resourceId, agentNa
|
|
|
385
389
|
credentialGrants: capturedAddonConfig?.credentialGrants,
|
|
386
390
|
globalSecrets: capturedAddonConfig?.globalSecrets,
|
|
387
391
|
globalCredentials: capturedAddonConfig?.globalCredentials,
|
|
392
|
+
contentBucket: capturedAddonConfig?.contentBucket,
|
|
393
|
+
contentGrants: capturedAddonConfig?.contentGrants,
|
|
394
|
+
globalContent: capturedAddonConfig?.globalContent,
|
|
388
395
|
}
|
|
389
396
|
: undefined;
|
|
390
397
|
services = await getOrCreatePackageSingletonServices(capturedPkg, singletonServices, addonInstance);
|
|
@@ -402,10 +409,12 @@ export async function buildToolDefs(params, agentSessionMap, resourceId, agentNa
|
|
|
402
409
|
needsApproval: needsApproval || undefined,
|
|
403
410
|
approvalDescriptionFn,
|
|
404
411
|
readonly: fnMeta?.readonly || undefined,
|
|
405
|
-
execute: async (toolInput) => {
|
|
412
|
+
execute: async (toolInput, options) => {
|
|
406
413
|
const wire = params.sessionService
|
|
407
414
|
? { ...createMiddlewareSessionWireProps(params.sessionService) }
|
|
408
415
|
: {};
|
|
416
|
+
if (options?.abortScope)
|
|
417
|
+
wire.abortScope = options.abortScope;
|
|
409
418
|
const rpcService = new ContextAwareRPCService(singletonServices, wire, { sessionService: params.sessionService });
|
|
410
419
|
return rpcService.rpc(toolName, toolInput);
|
|
411
420
|
},
|
|
@@ -457,7 +466,7 @@ export async function buildToolDefs(params, agentSessionMap, resourceId, agentNa
|
|
|
457
466
|
streamContext.delegateState.delegated = true;
|
|
458
467
|
}
|
|
459
468
|
const { channel } = streamContext;
|
|
460
|
-
channel.send({
|
|
469
|
+
await channel.send({
|
|
461
470
|
type: 'agent-call',
|
|
462
471
|
agentName: subAgentName,
|
|
463
472
|
session,
|
|
@@ -468,11 +477,11 @@ export async function buildToolDefs(params, agentSessionMap, resourceId, agentNa
|
|
|
468
477
|
? subChannel
|
|
469
478
|
: {
|
|
470
479
|
...subChannel,
|
|
471
|
-
send: (event) => {
|
|
480
|
+
send: async (event) => {
|
|
472
481
|
if (event.type === 'text-delta' ||
|
|
473
482
|
event.type === 'reasoning-delta')
|
|
474
483
|
return;
|
|
475
|
-
subChannel.send(event);
|
|
484
|
+
await subChannel.send(event);
|
|
476
485
|
},
|
|
477
486
|
};
|
|
478
487
|
const resultText = await streamAgent(subAgentName, buildSubAgentRunInput(message, threadId, resourceId, parentContext), effectiveChannel, params, agentSessionMap, streamContext.options);
|
|
@@ -486,7 +495,7 @@ export async function buildToolDefs(params, agentSessionMap, resourceId, agentNa
|
|
|
486
495
|
subApprovals: subChannel.approvals,
|
|
487
496
|
};
|
|
488
497
|
}
|
|
489
|
-
channel.send({
|
|
498
|
+
await channel.send({
|
|
490
499
|
type: 'agent-result',
|
|
491
500
|
agentName: subAgentName,
|
|
492
501
|
session,
|
|
@@ -544,7 +553,7 @@ export async function buildToolDefs(params, agentSessionMap, resourceId, agentNa
|
|
|
544
553
|
name: workflowName,
|
|
545
554
|
description: wfMeta.description || workflowName,
|
|
546
555
|
inputSchema,
|
|
547
|
-
execute: async (toolInput) => {
|
|
556
|
+
execute: async (toolInput, options) => {
|
|
548
557
|
const workflowService = singletonServices.workflowService;
|
|
549
558
|
if (!workflowService) {
|
|
550
559
|
throw new Error(`workflowService is not configured — cannot run workflow tool '${workflowName}'`);
|
|
@@ -552,6 +561,8 @@ export async function buildToolDefs(params, agentSessionMap, resourceId, agentNa
|
|
|
552
561
|
const wire = params.sessionService
|
|
553
562
|
? { ...createMiddlewareSessionWireProps(params.sessionService) }
|
|
554
563
|
: {};
|
|
564
|
+
if (options?.abortScope)
|
|
565
|
+
wire.abortScope = options.abortScope;
|
|
555
566
|
const rpcService = new ContextAwareRPCService(singletonServices, wire, { sessionService: params.sessionService });
|
|
556
567
|
return workflowService.runToCompletion(workflowName, toolInput, rpcService, { wire: { type: 'internal' } });
|
|
557
568
|
},
|
|
@@ -560,9 +571,9 @@ export async function buildToolDefs(params, agentSessionMap, resourceId, agentNa
|
|
|
560
571
|
}
|
|
561
572
|
for (const tool of tools) {
|
|
562
573
|
const originalExecute = tool.execute;
|
|
563
|
-
tool.execute = async (toolInput) => {
|
|
574
|
+
tool.execute = async (toolInput, options) => {
|
|
564
575
|
try {
|
|
565
|
-
return await originalExecute(toolInput);
|
|
576
|
+
return await originalExecute(toolInput, options);
|
|
566
577
|
}
|
|
567
578
|
catch (err) {
|
|
568
579
|
if (err?.payload?.error === 'missing_credential') {
|
|
@@ -581,7 +592,7 @@ export async function buildToolDefs(params, agentSessionMap, resourceId, agentNa
|
|
|
581
592
|
if (hasToolHooks) {
|
|
582
593
|
for (const tool of tools) {
|
|
583
594
|
const originalExecute = tool.execute;
|
|
584
|
-
tool.execute = async (toolInput) => {
|
|
595
|
+
tool.execute = async (toolInput, options) => {
|
|
585
596
|
const toolCallId = randomUUID();
|
|
586
597
|
let args = (toolInput ?? {});
|
|
587
598
|
for (const mw of agentMiddlewares) {
|
|
@@ -600,7 +611,7 @@ export async function buildToolDefs(params, agentSessionMap, resourceId, agentNa
|
|
|
600
611
|
let result;
|
|
601
612
|
let execError;
|
|
602
613
|
try {
|
|
603
|
-
result = await originalExecute(args);
|
|
614
|
+
result = await originalExecute(args, options);
|
|
604
615
|
}
|
|
605
616
|
catch (err) {
|
|
606
617
|
execError = err;
|