@mduan/paseo-cli 0.11.0-fork.35 → 0.11.0-fork.36
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/dist/commands/agent/send.d.ts +2 -0
- package/dist/commands/agent/send.js +8 -1
- package/node_modules/@getpaseo/client/dist/daemon-client.d.ts +2 -0
- package/node_modules/@getpaseo/client/dist/daemon-client.js +1 -0
- package/node_modules/@getpaseo/client/package.json +3 -3
- package/node_modules/@getpaseo/highlight/package.json +1 -1
- package/node_modules/@getpaseo/plugin/package.json +3 -3
- package/node_modules/@getpaseo/protocol/dist/messages.d.ts +4 -0
- package/node_modules/@getpaseo/protocol/dist/messages.js +2 -0
- package/node_modules/@getpaseo/protocol/package.json +1 -1
- package/node_modules/@getpaseo/relay/package.json +1 -1
- package/node_modules/@getpaseo/server/dist/server/builtin-plugins/package.json +1 -1
- package/node_modules/@getpaseo/server/dist/server/server/agent/agent-prompt.d.ts +7 -0
- package/node_modules/@getpaseo/server/dist/server/server/agent/agent-prompt.js +82 -16
- package/node_modules/@getpaseo/server/dist/server/server/agent/tools/paseo-tools.js +20 -8
- package/node_modules/@getpaseo/server/dist/server/server/session.js +2 -1
- package/node_modules/@getpaseo/server/dist/server/skills/paseo/SKILL.md +1 -1
- package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/{index-c5f0ae884c9004e9301096d186baee98.js → index-906d2f4f5f6cb670ae516f04dd636fc3.js} +3 -3
- package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/index-906d2f4f5f6cb670ae516f04dd636fc3.js.br +0 -0
- package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/{index-c5f0ae884c9004e9301096d186baee98.js.gz → index-906d2f4f5f6cb670ae516f04dd636fc3.js.gz} +0 -0
- package/node_modules/@getpaseo/server/dist/server/web-ui/index.html +1 -1
- package/node_modules/@getpaseo/server/dist/server/web-ui/index.html.br +0 -0
- package/node_modules/@getpaseo/server/dist/server/web-ui/index.html.gz +0 -0
- package/node_modules/@getpaseo/server/package.json +6 -6
- package/package.json +7 -7
- package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/index-c5f0ae884c9004e9301096d186baee98.js.br +0 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type Command } from "commander";
|
|
2
|
+
import type { ActiveTurnBehavior } from "@getpaseo/protocol/messages";
|
|
2
3
|
import type { CommandOptions, SingleResult, OutputSchema } from "../../output/index.js";
|
|
3
4
|
/** Result type for agent send command */
|
|
4
5
|
export interface AgentSendResult {
|
|
@@ -9,6 +10,7 @@ export interface AgentSendResult {
|
|
|
9
10
|
/** Schema for agent send output */
|
|
10
11
|
export declare const agentSendSchema: OutputSchema<AgentSendResult>;
|
|
11
12
|
export interface AgentSendOptions extends CommandOptions {
|
|
13
|
+
behavior?: ActiveTurnBehavior;
|
|
12
14
|
wait?: boolean;
|
|
13
15
|
image?: string[];
|
|
14
16
|
prompt?: string;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Option } from "commander";
|
|
1
2
|
import { collectMultiple } from "../../utils/command-options.js";
|
|
2
3
|
import { connectToDaemon } from "../../utils/client.js";
|
|
3
4
|
import { readFile } from "node:fs/promises";
|
|
@@ -19,6 +20,7 @@ export function addSendOptions(cmd) {
|
|
|
19
20
|
.option("--prompt <text>", "Provide the message inline as a flag")
|
|
20
21
|
.option("--prompt-file <path>", "Read the message from a UTF-8 text file")
|
|
21
22
|
.option("--image <path>", "Attach image(s) to the message", collectMultiple, [])
|
|
23
|
+
.addOption(new Option("--behavior <behavior>", "How to send into a running turn (default: steer from an agent, interrupt otherwise)").choices(["interrupt", "steer"]))
|
|
22
24
|
.option("--no-wait", "Return immediately without waiting for completion");
|
|
23
25
|
}
|
|
24
26
|
/**
|
|
@@ -139,7 +141,12 @@ export async function runSendCommand(agentIdArg, prompt, options, _command) {
|
|
|
139
141
|
// Read image files if provided
|
|
140
142
|
const images = options.image && options.image.length > 0 ? await readImageFiles(options.image) : undefined;
|
|
141
143
|
// Send the message
|
|
142
|
-
|
|
144
|
+
const sourceAgentId = process.env.PASEO_AGENT_ID?.trim() || undefined;
|
|
145
|
+
await client.sendAgentMessage(agentIdArg, promptInput, {
|
|
146
|
+
images,
|
|
147
|
+
sourceAgentId,
|
|
148
|
+
activeTurnBehavior: options.behavior ?? (sourceAgentId ? "steer" : "interrupt"),
|
|
149
|
+
});
|
|
143
150
|
// If --no-wait, return immediately
|
|
144
151
|
if (options.wait === false) {
|
|
145
152
|
await client.close();
|
|
@@ -162,6 +162,8 @@ export interface SendMessageOptions {
|
|
|
162
162
|
mimeType: string;
|
|
163
163
|
}>;
|
|
164
164
|
attachments?: SendAgentMessageRequest["attachments"];
|
|
165
|
+
/** The sending agent, when an agent rather than a person sends the message. */
|
|
166
|
+
sourceAgentId?: string;
|
|
165
167
|
}
|
|
166
168
|
export interface AgentAttentionRequiredNotification {
|
|
167
169
|
agentId: string;
|
|
@@ -2276,6 +2276,7 @@ export class DaemonClient {
|
|
|
2276
2276
|
...(options?.activeTurnBehavior ? { activeTurnBehavior: options.activeTurnBehavior } : {}),
|
|
2277
2277
|
...(options?.images ? { images: options.images } : {}),
|
|
2278
2278
|
...(options?.attachments ? { attachments: options.attachments } : {}),
|
|
2279
|
+
...(options?.sourceAgentId ? { sourceAgentId: options.sourceAgentId } : {}),
|
|
2279
2280
|
});
|
|
2280
2281
|
const payload = await this.sendRequest({
|
|
2281
2282
|
requestId,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@getpaseo/client",
|
|
3
|
-
"version": "0.11.0-fork.
|
|
3
|
+
"version": "0.11.0-fork.36",
|
|
4
4
|
"description": "Paseo client SDK package",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"vitest": "^4.1.6"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"@getpaseo/protocol": "0.11.0-fork.
|
|
48
|
-
"@getpaseo/relay": "0.11.0-fork.
|
|
47
|
+
"@getpaseo/protocol": "0.11.0-fork.36",
|
|
48
|
+
"@getpaseo/relay": "0.11.0-fork.36"
|
|
49
49
|
}
|
|
50
50
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@getpaseo/plugin",
|
|
3
|
-
"version": "0.11.0-fork.
|
|
3
|
+
"version": "0.11.0-fork.36",
|
|
4
4
|
"description": "Paseo plugin SDK package",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist",
|
|
@@ -66,8 +66,8 @@
|
|
|
66
66
|
"test": "vitest run"
|
|
67
67
|
},
|
|
68
68
|
"devDependencies": {
|
|
69
|
-
"@getpaseo/client": "0.11.0-fork.
|
|
70
|
-
"@getpaseo/protocol": "0.11.0-fork.
|
|
69
|
+
"@getpaseo/client": "0.11.0-fork.36",
|
|
70
|
+
"@getpaseo/protocol": "0.11.0-fork.36",
|
|
71
71
|
"@types/node": "^20.9.0",
|
|
72
72
|
"@types/react": "~19.2.0",
|
|
73
73
|
"react": "19.1.0",
|
|
@@ -1586,6 +1586,7 @@ export declare const SendAgentMessageRequestSchema: z.ZodObject<{
|
|
|
1586
1586
|
size: number;
|
|
1587
1587
|
path: string;
|
|
1588
1588
|
})[], unknown>>>;
|
|
1589
|
+
sourceAgentId: z.ZodOptional<z.ZodString>;
|
|
1589
1590
|
}, z.core.$strip>;
|
|
1590
1591
|
export declare const WaitForFinishRequestSchema: z.ZodObject<{
|
|
1591
1592
|
type: z.ZodLiteral<"wait_for_finish_request">;
|
|
@@ -5592,6 +5593,7 @@ export declare const SessionInboundMessageSchema: z.ZodDiscriminatedUnion<[z.Zod
|
|
|
5592
5593
|
size: number;
|
|
5593
5594
|
path: string;
|
|
5594
5595
|
})[], unknown>>>;
|
|
5596
|
+
sourceAgentId: z.ZodOptional<z.ZodString>;
|
|
5595
5597
|
}, z.core.$strip>, z.ZodObject<{
|
|
5596
5598
|
type: z.ZodLiteral<"wait_for_finish_request">;
|
|
5597
5599
|
requestId: z.ZodString;
|
|
@@ -39179,6 +39181,7 @@ export declare const WSSessionInboundSchema: z.ZodObject<{
|
|
|
39179
39181
|
size: number;
|
|
39180
39182
|
path: string;
|
|
39181
39183
|
})[], unknown>>>;
|
|
39184
|
+
sourceAgentId: z.ZodOptional<z.ZodString>;
|
|
39182
39185
|
}, z.core.$strip>, z.ZodObject<{
|
|
39183
39186
|
type: z.ZodLiteral<"wait_for_finish_request">;
|
|
39184
39187
|
requestId: z.ZodString;
|
|
@@ -55890,6 +55893,7 @@ export declare const WSInboundMessageSchema: z.ZodDiscriminatedUnion<[z.ZodObjec
|
|
|
55890
55893
|
size: number;
|
|
55891
55894
|
path: string;
|
|
55892
55895
|
})[], unknown>>>;
|
|
55896
|
+
sourceAgentId: z.ZodOptional<z.ZodString>;
|
|
55893
55897
|
}, z.core.$strip>, z.ZodObject<{
|
|
55894
55898
|
type: z.ZodLiteral<"wait_for_finish_request">;
|
|
55895
55899
|
requestId: z.ZodString;
|
|
@@ -1265,6 +1265,8 @@ export const SendAgentMessageRequestSchema = z.object({
|
|
|
1265
1265
|
activeTurnBehavior: ActiveTurnBehaviorSchema.optional(),
|
|
1266
1266
|
images: z.array(ImageAttachmentSchema).optional(),
|
|
1267
1267
|
attachments: AgentAttachmentsSchema,
|
|
1268
|
+
/** Set when an agent sends this, such as `paseo send` from an agent's shell; not a human prompt. */
|
|
1269
|
+
sourceAgentId: z.string().optional(),
|
|
1268
1270
|
});
|
|
1269
1271
|
export const WaitForFinishRequestSchema = z.object({
|
|
1270
1272
|
type: z.literal("wait_for_finish_request"),
|
|
@@ -85,6 +85,13 @@ export interface SetupFinishNotificationParams {
|
|
|
85
85
|
childAgentId: string;
|
|
86
86
|
callerAgentId: string;
|
|
87
87
|
requireParentOwnership?: boolean;
|
|
88
|
+
/**
|
|
89
|
+
* Dispatch this observation is armed ahead of — catches a turn finishing during steering
|
|
90
|
+
* admission. Notifications wait for it and are dropped if it fails.
|
|
91
|
+
*/
|
|
92
|
+
dispatch?: Promise<unknown>;
|
|
93
|
+
/** How the armed prompt meets a running turn; a steer can be answered after that turn ends. */
|
|
94
|
+
activeTurnBehavior?: ActiveTurnBehavior;
|
|
88
95
|
logger: Logger;
|
|
89
96
|
}
|
|
90
97
|
export declare function setupFinishNotification(params: SetupFinishNotificationParams): void;
|
|
@@ -213,6 +213,11 @@ export async function startCreatedAgentInitialPrompt(params) {
|
|
|
213
213
|
}
|
|
214
214
|
return refreshedSnapshot;
|
|
215
215
|
}
|
|
216
|
+
/**
|
|
217
|
+
* Claude answers a steer that arrives after its last tool call in a follow-up turn, started
|
|
218
|
+
* once the steered turn ends. Keep observing that long so the follow-up's finish is reported.
|
|
219
|
+
*/
|
|
220
|
+
const STEER_FOLLOW_UP_WINDOW_MS = 10000;
|
|
216
221
|
const FINISH_NOTIFICATION_MESSAGE_LIMIT = 4000;
|
|
217
222
|
function formatFinishNotificationBody(params) {
|
|
218
223
|
const statusLine = `Agent ${params.childAgentId} (${params.title}) ${params.reason}.`;
|
|
@@ -232,34 +237,77 @@ function formatFinishNotificationBody(params) {
|
|
|
232
237
|
}
|
|
233
238
|
sections.push(`<agent-response>\n${lastAssistantMessage}\n</agent-response>`);
|
|
234
239
|
}
|
|
240
|
+
if (params.followUpPossible) {
|
|
241
|
+
sections.push("If this response does not answer the message you steered into this agent's turn, the agent may still be answering it. A follow-up report will arrive when it finishes.");
|
|
242
|
+
}
|
|
235
243
|
return sections.join("\n\n");
|
|
236
244
|
}
|
|
237
|
-
//
|
|
238
|
-
//
|
|
239
|
-
// next finish reaches the caller once.
|
|
245
|
+
// One observation per caller/child pair. Re-arming (e.g. a follow-up while the child runs)
|
|
246
|
+
// joins it, so the next finish notifies once even when sends overlap or fail.
|
|
240
247
|
const armedFinishNotifications = new WeakMap();
|
|
241
248
|
export function setupFinishNotification(params) {
|
|
242
|
-
const { agentManager, agentStorage, childAgentId, callerAgentId,
|
|
249
|
+
const { agentManager, agentStorage, childAgentId, callerAgentId, logger } = params;
|
|
250
|
+
const armedByManager = armedFinishNotifications.get(agentManager) ?? new Map();
|
|
251
|
+
armedFinishNotifications.set(agentManager, armedByManager);
|
|
252
|
+
const armedKey = JSON.stringify([childAgentId, callerAgentId]);
|
|
253
|
+
const armed = armedByManager.get(armedKey);
|
|
254
|
+
if (armed) {
|
|
255
|
+
armed(params);
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
armedByManager.set(armedKey, arm);
|
|
243
259
|
let hasSeenRunning = false;
|
|
244
260
|
let stopped = false;
|
|
245
261
|
const notifiedPermissionRequestIds = new Set();
|
|
246
262
|
let unsubscribe = null;
|
|
247
263
|
let notificationQueue = Promise.resolve();
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
264
|
+
let requireParentOwnership = false;
|
|
265
|
+
// Accepted once any arming is not tied to a dispatch, or any tracked dispatch succeeds.
|
|
266
|
+
let accepted = false;
|
|
267
|
+
let steeredIntoRunningTurn = false;
|
|
268
|
+
let followUpWindow;
|
|
269
|
+
const dispatches = [];
|
|
270
|
+
arm(params);
|
|
271
|
+
function arm(next) {
|
|
272
|
+
requireParentOwnership = next.requireParentOwnership ?? false;
|
|
273
|
+
if (next.activeTurnBehavior === "steer" &&
|
|
274
|
+
agentManager.getAgent(childAgentId)?.lifecycle === "running") {
|
|
275
|
+
steeredIntoRunningTurn = true;
|
|
276
|
+
}
|
|
277
|
+
const { dispatch } = next;
|
|
278
|
+
if (!dispatch) {
|
|
279
|
+
accepted = true;
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
dispatches.push(dispatch);
|
|
283
|
+
void (async () => {
|
|
284
|
+
if (!(await dispatchAccepted()))
|
|
285
|
+
stop();
|
|
286
|
+
})();
|
|
287
|
+
}
|
|
288
|
+
/** Resolves once a tracked dispatch succeeds, or false when every one has failed. */
|
|
289
|
+
async function dispatchAccepted() {
|
|
290
|
+
let tracked = 0;
|
|
291
|
+
while (!accepted && tracked < dispatches.length) {
|
|
292
|
+
tracked = dispatches.length;
|
|
293
|
+
if (await Promise.any(dispatches).then(() => true, () => false)) {
|
|
294
|
+
accepted = true;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
return accepted;
|
|
298
|
+
}
|
|
253
299
|
function stop() {
|
|
254
300
|
if (stopped)
|
|
255
301
|
return;
|
|
256
302
|
stopped = true;
|
|
303
|
+
clearTimeout(followUpWindow);
|
|
257
304
|
unsubscribe?.();
|
|
258
|
-
|
|
259
|
-
armedByManager.delete(armedKey);
|
|
260
|
-
}
|
|
305
|
+
armedByManager.delete(armedKey);
|
|
261
306
|
}
|
|
262
|
-
async function notify(reason,
|
|
307
|
+
async function notify(reason, options) {
|
|
308
|
+
if (!(await dispatchAccepted())) {
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
263
311
|
const callerRecord = await agentStorage.get(callerAgentId);
|
|
264
312
|
if (callerRecord?.archivedAt) {
|
|
265
313
|
return;
|
|
@@ -275,7 +323,8 @@ export function setupFinishNotification(params) {
|
|
|
275
323
|
title,
|
|
276
324
|
reason,
|
|
277
325
|
lastAssistantMessage,
|
|
278
|
-
permissionRequest,
|
|
326
|
+
permissionRequest: options.permissionRequest,
|
|
327
|
+
followUpPossible: options.followUpPossible,
|
|
279
328
|
});
|
|
280
329
|
await sendPromptToAgent({
|
|
281
330
|
agentManager,
|
|
@@ -293,11 +342,22 @@ export function setupFinishNotification(params) {
|
|
|
293
342
|
if (options.terminal ?? true)
|
|
294
343
|
stop();
|
|
295
344
|
notificationQueue = notificationQueue
|
|
296
|
-
.then(() => notify(reason, options
|
|
345
|
+
.then(() => notify(reason, options))
|
|
297
346
|
.catch((error) => {
|
|
298
347
|
logger.error({ err: error, childAgentId, callerAgentId, reason }, "Failed to notify caller agent");
|
|
299
348
|
});
|
|
300
349
|
}
|
|
350
|
+
function notifyFinished() {
|
|
351
|
+
if (!steeredIntoRunningTurn) {
|
|
352
|
+
notifySafely("finished");
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
steeredIntoRunningTurn = false;
|
|
356
|
+
hasSeenRunning = false;
|
|
357
|
+
notifySafely("finished", { terminal: false, followUpPossible: true });
|
|
358
|
+
followUpWindow = setTimeout(stop, STEER_FOLLOW_UP_WINDOW_MS);
|
|
359
|
+
followUpWindow.unref?.();
|
|
360
|
+
}
|
|
301
361
|
unsubscribe = agentManager.subscribe((event) => {
|
|
302
362
|
if (stopped) {
|
|
303
363
|
return;
|
|
@@ -309,6 +369,7 @@ export function setupFinishNotification(params) {
|
|
|
309
369
|
}
|
|
310
370
|
}
|
|
311
371
|
if (event.agent.lifecycle === "running") {
|
|
372
|
+
clearTimeout(followUpWindow);
|
|
312
373
|
if (event.agent.pendingPermissions.size === 0) {
|
|
313
374
|
hasSeenRunning = true;
|
|
314
375
|
}
|
|
@@ -319,7 +380,7 @@ export function setupFinishNotification(params) {
|
|
|
319
380
|
return;
|
|
320
381
|
}
|
|
321
382
|
if (event.agent.lifecycle === "idle" && hasSeenRunning) {
|
|
322
|
-
|
|
383
|
+
notifyFinished();
|
|
323
384
|
return;
|
|
324
385
|
}
|
|
325
386
|
if (event.agent.lifecycle === "closed") {
|
|
@@ -359,6 +420,11 @@ export function setupFinishNotification(params) {
|
|
|
359
420
|
// not have started yet (streamAgent sets a pending run before
|
|
360
421
|
// transitioning to "running").
|
|
361
422
|
const childSnapshot = agentManager.getAgent(childAgentId);
|
|
423
|
+
if (params.dispatch) {
|
|
424
|
+
// The dispatch may still load the child or start a turn that clears a stale error.
|
|
425
|
+
hasSeenRunning = childSnapshot?.lifecycle === "running";
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
362
428
|
if (!childSnapshot || childSnapshot.lifecycle === "closed") {
|
|
363
429
|
stop();
|
|
364
430
|
return;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { stat } from "node:fs/promises";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { ensureValidJson } from "../../json-utils.js";
|
|
4
|
-
import { AgentProfileSchema } from "@getpaseo/protocol/messages";
|
|
4
|
+
import { ActiveTurnBehaviorSchema, AgentProfileSchema } from "@getpaseo/protocol/messages";
|
|
5
5
|
import { AgentFeatureSchema, AgentPermissionRequestPayloadSchema, AgentListItemPayloadSchema, AgentPermissionResponseSchema, AgentSnapshotPayloadSchema, WorkspaceScriptPayloadSchema, } from "../../messages.js";
|
|
6
6
|
import { buildStoredAgentPayload, toAgentListItemPayload, toAgentPayload, } from "../agent-projections.js";
|
|
7
7
|
import { curateAgentActivity } from "../activity-curator.js";
|
|
@@ -797,6 +797,7 @@ export function createPaseoToolCatalog(options) {
|
|
|
797
797
|
.object(legacyTopLevelCreateAgentInputSchema)
|
|
798
798
|
.strict();
|
|
799
799
|
const commonSendAgentPromptInputSchema = {
|
|
800
|
+
activeTurnBehavior: ActiveTurnBehaviorSchema.optional().describe('How to send into a running turn: "steer" joins it, falling back to interrupt when steering is unavailable; "interrupt" replaces it. Defaults to steer for agent callers and interrupt otherwise.'),
|
|
800
801
|
agentId: z.string(),
|
|
801
802
|
prompt: z.string(),
|
|
802
803
|
sessionMode: z.string().optional().describe("Optional mode to set before running the prompt."),
|
|
@@ -1394,10 +1395,11 @@ export function createPaseoToolCatalog(options) {
|
|
|
1394
1395
|
throw new Error("unreachable");
|
|
1395
1396
|
}
|
|
1396
1397
|
}
|
|
1398
|
+
const STEERED_BLOCKING_GUIDANCE = "If lastMessage does not answer your message, the agent may still be answering it in a follow-up turn. Check get_agent_activity before acting on this result.";
|
|
1397
1399
|
const PROMPTED_AGENT_NOTIFICATION_GUIDANCE = "You will get notified when the prompted agent finishes, errors, or needs permission. Do not poll for status; continue with other work until the notification arrives.";
|
|
1398
1400
|
registerTool("send_agent_prompt", {
|
|
1399
1401
|
title: "Send agent prompt",
|
|
1400
|
-
description: "Send a task to a running agent. Agent-scoped callers run in background by default; top-level callers wait by default.",
|
|
1402
|
+
description: "Send a task to a running agent. Agent-scoped callers run in background and steer a running turn by default; top-level callers wait and interrupt by default.",
|
|
1401
1403
|
inputSchema: sendAgentPromptInputSchema,
|
|
1402
1404
|
outputSchema: {
|
|
1403
1405
|
success: z.boolean(),
|
|
@@ -1406,8 +1408,8 @@ export function createPaseoToolCatalog(options) {
|
|
|
1406
1408
|
permission: AgentPermissionRequestPayloadSchema.nullable().optional(),
|
|
1407
1409
|
guidance: z.string().optional(),
|
|
1408
1410
|
},
|
|
1409
|
-
}, async ({ agentId, prompt, sessionMode, background = Boolean(callerAgentId), notifyOnFinish = Boolean(callerAgentId), }) => {
|
|
1410
|
-
function armFinishNotification() {
|
|
1411
|
+
}, async ({ agentId, prompt, sessionMode, background = Boolean(callerAgentId), notifyOnFinish = Boolean(callerAgentId), activeTurnBehavior = callerAgentId ? "steer" : "interrupt", }) => {
|
|
1412
|
+
function armFinishNotification(dispatched) {
|
|
1411
1413
|
if (!callerAgentId || !notifyOnFinish) {
|
|
1412
1414
|
return false;
|
|
1413
1415
|
}
|
|
@@ -1416,18 +1418,24 @@ export function createPaseoToolCatalog(options) {
|
|
|
1416
1418
|
agentStorage,
|
|
1417
1419
|
childAgentId: agentId,
|
|
1418
1420
|
callerAgentId,
|
|
1421
|
+
...dispatched,
|
|
1419
1422
|
logger: childLogger,
|
|
1420
1423
|
});
|
|
1421
1424
|
return true;
|
|
1422
1425
|
}
|
|
1423
|
-
const
|
|
1426
|
+
const steersRunningTurn = activeTurnBehavior === "steer" && agentManager.getAgent(agentId)?.lifecycle === "running";
|
|
1427
|
+
const dispatch = sendPromptToAgent({
|
|
1424
1428
|
agentManager,
|
|
1425
1429
|
agentStorage,
|
|
1426
1430
|
agentId,
|
|
1427
1431
|
prompt,
|
|
1428
1432
|
sessionMode,
|
|
1433
|
+
activeTurnBehavior,
|
|
1429
1434
|
logger: childLogger,
|
|
1430
1435
|
});
|
|
1436
|
+
// Background callers observe before dispatch; blocking callers arm only if the wait runs out.
|
|
1437
|
+
const notifying = background && armFinishNotification({ dispatch, activeTurnBehavior });
|
|
1438
|
+
const { disposition } = await dispatch;
|
|
1431
1439
|
// If not running in background, wait for completion
|
|
1432
1440
|
if (!background) {
|
|
1433
1441
|
const result = await waitForAgentWithTimeout(agentManager, agentId, {
|
|
@@ -1435,15 +1443,20 @@ export function createPaseoToolCatalog(options) {
|
|
|
1435
1443
|
});
|
|
1436
1444
|
// The wait ran out while the agent keeps working, so its result arrives as a
|
|
1437
1445
|
// finish notification instead of in this response.
|
|
1438
|
-
const
|
|
1446
|
+
const notifyingAfterWait = result.timedOut &&
|
|
1439
1447
|
agentManager.getAgent(agentId)?.lifecycle === "running" &&
|
|
1440
1448
|
armFinishNotification();
|
|
1449
|
+
let guidance;
|
|
1450
|
+
if (notifyingAfterWait)
|
|
1451
|
+
guidance = PROMPTED_AGENT_NOTIFICATION_GUIDANCE;
|
|
1452
|
+
else if (steersRunningTurn)
|
|
1453
|
+
guidance = STEERED_BLOCKING_GUIDANCE;
|
|
1441
1454
|
const responseData = {
|
|
1442
1455
|
success: true,
|
|
1443
1456
|
status: result.status,
|
|
1444
1457
|
lastMessage: result.lastMessage,
|
|
1445
1458
|
permission: sanitizePermissionRequest(result.permission),
|
|
1446
|
-
...(
|
|
1459
|
+
...(guidance ? { guidance } : {}),
|
|
1447
1460
|
};
|
|
1448
1461
|
const validJson = ensureValidJson(responseData);
|
|
1449
1462
|
const response = {
|
|
@@ -1452,7 +1465,6 @@ export function createPaseoToolCatalog(options) {
|
|
|
1452
1465
|
};
|
|
1453
1466
|
return response;
|
|
1454
1467
|
}
|
|
1455
|
-
const notifying = armFinishNotification();
|
|
1456
1468
|
// Return once the provider has accepted the turn, so the status reports it running.
|
|
1457
1469
|
if (disposition === "turn_started") {
|
|
1458
1470
|
await waitForAgentRunStartWithTimeout(agentManager, agentId);
|
|
@@ -6692,7 +6692,8 @@ export class Session {
|
|
|
6692
6692
|
textPrefix: msg.text.slice(0, 80),
|
|
6693
6693
|
}, "agent.session.send_agent_message");
|
|
6694
6694
|
const send = async () => {
|
|
6695
|
-
|
|
6695
|
+
if (!msg.sourceAgentId)
|
|
6696
|
+
await this.recordHumanPrompt({ agentId });
|
|
6696
6697
|
const result = await sendPromptToAgent({
|
|
6697
6698
|
agentManager: this.agentManager,
|
|
6698
6699
|
agentStorage: this.agentStorage,
|
|
@@ -61,7 +61,7 @@ Detach is an explicit user action in the subagents track, not an agent tool. A c
|
|
|
61
61
|
|
|
62
62
|
Agent-scoped `create_agent` defaults `notifyOnFinish` to true. Set it to `false` only for truly fire-and-forget agents.
|
|
63
63
|
|
|
64
|
-
**`send_agent_prompt`** — `{ agentId, prompt }`. Use for follow-ups to an existing agent. Agent-scoped prompt calls default to `background: true` and `
|
|
64
|
+
**`send_agent_prompt`** — `{ agentId, prompt, activeTurnBehavior? }`. Use for follow-ups to an existing agent. Agent-scoped prompt calls default to `background: true`, `notifyOnFinish: true`, and `activeTurnBehavior: "steer"`; top-level calls default to blocking, no callback, and `"interrupt"`. Steering falls back to interrupting when the provider can't steer. CLI sends from an agent use the same default and accept `--behavior steer|interrupt`. For a synchronous follow-up, pass `background: false` and use the returned result.
|
|
65
65
|
|
|
66
66
|
**`update_agent`** — `{ agentId, name?, labels?, settings? }`. Use `settings` for runtime changes on an existing agent: `modeId`, `model`, `thinkingOptionId`, and provider-specific `features`. For Codex fast mode, pass `settings: { features: { "fast_mode": true } }`.
|
|
67
67
|
|