pi-subagents 0.57.0 → 0.59.0
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 +104 -0
- package/docs/agents.md +18 -9
- package/docs/configuration.md +4 -4
- package/docs/extension-api.md +40 -1
- package/docs/models.md +27 -4
- package/docs/observability.md +1 -1
- package/docs/tool-reference.md +92 -6
- package/docs/workflows.md +115 -0
- package/package.json +3 -1
- package/prompts/review-loop.md +2 -2
- package/skills/council-mode/SKILL.md +1 -1
- package/skills/pi-subagents/SKILL.md +3 -1
- package/skills/pi-subagents/references/execution-controls.md +6 -2
- package/skills/pi-subagents/references/management-authoring-rpc.md +2 -2
- package/skills/pi-subagents/references/prompting-and-roles.md +26 -5
- package/src/agents/agent-management.ts +28 -17
- package/src/agents/agent-serializer.ts +9 -2
- package/src/agents/agents.ts +103 -27
- package/src/agents/runtime-agent-events.ts +70 -0
- package/src/agents/runtime-agent-registry.ts +19 -18
- package/src/api/agents.ts +10 -5
- package/src/api/background-work.ts +5 -1
- package/src/api/delegation.ts +0 -7
- package/src/api/preflight.ts +32 -10
- package/src/extension/fanout-child.ts +5 -3
- package/src/extension/index.ts +66 -27
- package/src/extension/public-execution.ts +15 -2
- package/src/extension/rpc.ts +35 -14
- package/src/extension/schemas.ts +37 -12
- package/src/extension/tool-description.ts +25 -6
- package/src/integrations/herdr-status.ts +5 -0
- package/src/intercom/result-intercom.ts +2 -0
- package/src/profiles/profiles.ts +5 -6
- package/src/runs/background/active-async-capacity.ts +2 -2
- package/src/runs/background/async-execution.ts +78 -46
- package/src/runs/background/async-job-tracker.ts +14 -12
- package/src/runs/background/async-resume.ts +29 -27
- package/src/runs/background/async-status-snapshot.ts +23 -261
- package/src/runs/background/async-status.ts +68 -7
- package/src/runs/background/chain-append.ts +8 -3
- package/src/runs/background/chain-root-attachment.ts +60 -8
- package/src/runs/background/fleet-view.ts +21 -11
- package/src/runs/background/notify.ts +184 -9
- package/src/runs/background/result-delivery-ownership.ts +45 -0
- package/src/runs/background/result-files.ts +2 -1
- package/src/runs/background/result-watcher.ts +29 -10
- package/src/runs/background/resume-guidance.ts +1 -1
- package/src/runs/background/retained-children.ts +1 -1
- package/src/runs/background/run-status.ts +18 -8
- package/src/runs/background/scheduled-runs.ts +86 -7
- package/src/runs/background/stale-run-reconciler.ts +10 -4
- package/src/runs/background/steering.ts +4 -14
- package/src/runs/background/subagent-runner.ts +389 -350
- package/src/runs/background/subagent-wait.ts +58 -10
- package/src/runs/background/terminal-run-index.ts +1 -1
- package/src/runs/background/wait-completions.ts +22 -1
- package/src/runs/background/wait-config.ts +23 -9
- package/src/runs/background/wait-tool.ts +9 -2
- package/src/runs/foreground/async-steering-action.ts +2 -2
- package/src/runs/foreground/execution.ts +134 -121
- package/src/runs/foreground/foreground-control.ts +3 -0
- package/src/runs/foreground/foreground-history.ts +1 -0
- package/src/runs/foreground/subagent-executor.ts +527 -257
- package/src/runs/foreground/workflow-detach-reconcile.ts +130 -120
- package/src/runs/shared/abort-recovery.ts +119 -0
- package/src/runs/shared/async-status-projection.ts +463 -0
- package/src/runs/shared/child-identity.ts +19 -4
- package/src/runs/shared/child-launch-plan.ts +151 -0
- package/src/runs/shared/completion-evidence.ts +89 -0
- package/src/runs/shared/completion-guard.ts +5 -4
- package/src/runs/shared/dynamic-fanout.ts +3 -3
- package/src/runs/shared/fast-mode-extension.ts +5 -5
- package/src/runs/shared/host-step-status.ts +230 -0
- package/src/runs/shared/lane-metadata.ts +105 -0
- package/src/runs/shared/launch-cwd.ts +16 -0
- package/src/runs/shared/long-running-guard.ts +2 -1
- package/src/runs/shared/mcp-config-sources.ts +422 -0
- package/src/runs/shared/mcp-direct-tool-allowlist.ts +221 -158
- package/src/runs/shared/mcp-direct-tool-grant.ts +197 -0
- package/src/runs/shared/model-exclusions.ts +12 -0
- package/src/runs/shared/model-fallback.ts +25 -6
- package/src/runs/shared/nested-events.ts +6 -2
- package/src/runs/shared/nested-render.ts +7 -3
- package/src/runs/shared/parallel-handoff.ts +419 -7
- package/src/runs/shared/parallel-utils.ts +15 -1
- package/src/runs/shared/pi-args.ts +81 -8
- package/src/runs/shared/single-output.ts +44 -4
- package/src/runs/shared/subagent-prompt-runtime.ts +98 -13
- package/src/runs/shared/worktree-cleanup-plan.ts +847 -0
- package/src/runs/shared/worktree.ts +18 -0
- package/src/shared/child-session-name.ts +46 -0
- package/src/shared/extension-context.ts +24 -0
- package/src/shared/formatters.ts +11 -2
- package/src/shared/launch-contract.ts +5 -1
- package/src/shared/settings.ts +9 -103
- package/src/shared/types.ts +240 -30
- package/src/shared/utils.ts +41 -84
- package/src/slash/delegation-adapters.ts +1 -8
- package/src/slash/delegation-request.ts +0 -4
- package/src/slash/slash-bridge.ts +1 -2
- package/src/slash/slash-commands.ts +369 -90
- package/src/slash/slash-live-state.ts +22 -11
- package/src/slash/subagents-admin.ts +3 -0
- package/src/tui/fleet-status.ts +125 -74
- package/src/tui/fleet.ts +11 -5
- package/src/tui/render.ts +330 -33
- package/src/watchdog/turn-delta.ts +1 -1
- package/src/workflows/chat-progress.ts +6 -3
- package/src/workflows/host-command.ts +230 -0
- package/src/workflows/scripted-workflow.ts +496 -35
- package/src/workflows/workflow-child-summary.ts +9 -5
- package/src/workflows/workflow-preflight.ts +270 -0
- package/src/workflows/workflow-receipt.ts +79 -5
- package/src/workflows/workflow-settlement.ts +246 -0
- package/src/runs/shared/turn-budget.ts +0 -98
package/src/shared/utils.ts
CHANGED
|
@@ -1,18 +1,11 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* General utility functions for the subagent extension
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
1
|
import * as fs from "node:fs";
|
|
6
2
|
import * as os from "node:os";
|
|
7
3
|
import * as path from "node:path";
|
|
8
|
-
import type { Message } from "@earendil-works/pi-ai";
|
|
4
|
+
import type { Message, Usage as PiUsage } from "@earendil-works/pi-ai";
|
|
9
5
|
import { previewDisplayText, sanitizeDisplayText, truncateDisplayText } from "./display-text.ts";
|
|
10
6
|
import { formatToolCall } from "./formatters.ts";
|
|
11
7
|
import type { AgentProgress, AsyncStatus, Details, DisplayItem, ErrorInfo, NestedRunSummary, SingleResult, ToolCallSummary, Usage } from "./types.ts";
|
|
12
|
-
|
|
13
|
-
// ============================================================================
|
|
14
|
-
// File System Utilities
|
|
15
|
-
// ============================================================================
|
|
8
|
+
import { validateAsyncStatusLaneMetadata } from "../runs/shared/lane-metadata.ts";
|
|
16
9
|
|
|
17
10
|
const DEFAULT_CONFIG_DIR_NAME = ".pi";
|
|
18
11
|
const PI_CODING_AGENT_PACKAGE_NAME = "@earendil-works/pi-coding-agent";
|
|
@@ -96,9 +89,10 @@ export function getProjectConfigDir(projectRoot: string): string {
|
|
|
96
89
|
|
|
97
90
|
export function getAgentDir(): string {
|
|
98
91
|
const configured = process.env.PI_CODING_AGENT_DIR;
|
|
99
|
-
|
|
100
|
-
if (configured
|
|
101
|
-
|
|
92
|
+
const home = process.env.HOME || process.env.USERPROFILE || os.homedir();
|
|
93
|
+
if (configured === "~") return home;
|
|
94
|
+
if (configured?.startsWith("~/") || configured?.startsWith("~\\")) return path.join(home, configured.slice(2));
|
|
95
|
+
return configured || path.join(home, getConfigDirName(), "agent");
|
|
102
96
|
}
|
|
103
97
|
|
|
104
98
|
const statusCache = new Map<string, { mtime: number; ctime: number; size: number; ino: number; status: AsyncStatus }>();
|
|
@@ -190,6 +184,13 @@ export function readStatus(asyncDir: string): AsyncStatus | null {
|
|
|
190
184
|
cause: error instanceof Error ? error : undefined,
|
|
191
185
|
});
|
|
192
186
|
}
|
|
187
|
+
try {
|
|
188
|
+
validateAsyncStatusLaneMetadata(status, `Invalid async status '${statusPath}'`);
|
|
189
|
+
} catch (error) {
|
|
190
|
+
throw new Error(`Failed to validate async status file '${statusPath}': ${getErrorMessage(error)}`, {
|
|
191
|
+
cause: error instanceof Error ? error : undefined,
|
|
192
|
+
});
|
|
193
|
+
}
|
|
193
194
|
|
|
194
195
|
statusCache.set(statusPath, {
|
|
195
196
|
mtime: stat.mtimeMs,
|
|
@@ -206,57 +207,7 @@ export function readStatus(asyncDir: string): AsyncStatus | null {
|
|
|
206
207
|
return status;
|
|
207
208
|
}
|
|
208
209
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
/**
|
|
212
|
-
* Get the last N lines from an output file (with mtime/size-based caching)
|
|
213
|
-
*/
|
|
214
|
-
function getOutputTail(outputFile: string | undefined, maxLines: number = 3): string[] {
|
|
215
|
-
if (!outputFile) return [];
|
|
216
|
-
let fd: number | null = null;
|
|
217
|
-
try {
|
|
218
|
-
const stat = fs.statSync(outputFile);
|
|
219
|
-
if (stat.size === 0) return [];
|
|
220
|
-
|
|
221
|
-
const cached = outputTailCache.get(outputFile);
|
|
222
|
-
if (cached && cached.mtime === stat.mtimeMs && cached.size === stat.size) {
|
|
223
|
-
return cached.lines;
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
const tailBytes = 4096;
|
|
227
|
-
const start = Math.max(0, stat.size - tailBytes);
|
|
228
|
-
fd = fs.openSync(outputFile, "r");
|
|
229
|
-
const buffer = Buffer.alloc(Math.min(tailBytes, stat.size));
|
|
230
|
-
fs.readSync(fd, buffer, 0, buffer.length, start);
|
|
231
|
-
const content = buffer.toString("utf-8");
|
|
232
|
-
const allLines = content.split("\n").filter((l) => l.trim());
|
|
233
|
-
const lines = allLines.slice(-maxLines).map((l) => l.slice(0, 120) + (l.length > 120 ? "..." : ""));
|
|
234
|
-
|
|
235
|
-
outputTailCache.set(outputFile, { mtime: stat.mtimeMs, size: stat.size, lines });
|
|
236
|
-
if (outputTailCache.size > 20) {
|
|
237
|
-
const firstKey = outputTailCache.keys().next().value;
|
|
238
|
-
if (firstKey) outputTailCache.delete(firstKey);
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
return lines;
|
|
242
|
-
} catch {
|
|
243
|
-
// Output tails are UI-only hints; unreadable or missing files should render as no tail.
|
|
244
|
-
return [];
|
|
245
|
-
} finally {
|
|
246
|
-
if (fd !== null) {
|
|
247
|
-
try {
|
|
248
|
-
fs.closeSync(fd);
|
|
249
|
-
} catch {
|
|
250
|
-
// Closing the best-effort tail file handle should not surface over the main status view.
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
/**
|
|
257
|
-
* Get human-readable last activity time for a file
|
|
258
|
-
*/
|
|
259
|
-
export function getLastActivity(outputFile: string | undefined): string {
|
|
210
|
+
export function getLastActivity(outputFile: string | undefined): string {
|
|
260
211
|
if (!outputFile) return "";
|
|
261
212
|
try {
|
|
262
213
|
const stat = fs.statSync(outputFile);
|
|
@@ -265,14 +216,11 @@ function getOutputTail(outputFile: string | undefined, maxLines: number = 3): st
|
|
|
265
216
|
if (ago < 60000) return `active ${Math.floor(ago / 1000)}s ago`;
|
|
266
217
|
return `active ${Math.floor(ago / 60000)}m ago`;
|
|
267
218
|
} catch {
|
|
268
|
-
// Last-activity text is best effort; missing files should
|
|
219
|
+
// Last-activity text is best effort; missing files should omit the hint.
|
|
269
220
|
return "";
|
|
270
221
|
}
|
|
271
222
|
}
|
|
272
223
|
|
|
273
|
-
/**
|
|
274
|
-
* Find the latest session file in a directory
|
|
275
|
-
*/
|
|
276
224
|
export function findLatestSessionFile(sessionDir: string): string | null {
|
|
277
225
|
if (!fs.existsSync(sessionDir)) return null;
|
|
278
226
|
const files = fs.readdirSync(sessionDir)
|
|
@@ -289,23 +237,6 @@ export function findLatestSessionFile(sessionDir: string): string | null {
|
|
|
289
237
|
return latest ? latest.path : null;
|
|
290
238
|
}
|
|
291
239
|
|
|
292
|
-
/**
|
|
293
|
-
* Write a prompt to a temporary file
|
|
294
|
-
*/
|
|
295
|
-
function writePrompt(agent: string, prompt: string): { dir: string; path: string } {
|
|
296
|
-
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "pi-subagent-"));
|
|
297
|
-
const p = path.join(dir, `${agent.replace(/[^\w.-]/g, "_")}.md`);
|
|
298
|
-
fs.writeFileSync(p, prompt, { mode: 0o600 });
|
|
299
|
-
return { dir, path: p };
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
// ============================================================================
|
|
303
|
-
// Message Parsing Utilities
|
|
304
|
-
// ============================================================================
|
|
305
|
-
|
|
306
|
-
/**
|
|
307
|
-
* Get the final text output from a list of messages
|
|
308
|
-
*/
|
|
309
240
|
export function getFinalOutput(messages: Message[]): string {
|
|
310
241
|
const validTextParts: string[] = [];
|
|
311
242
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
@@ -361,6 +292,7 @@ function compactCompletedProgress(progress: AgentProgress): AgentProgress {
|
|
|
361
292
|
return {
|
|
362
293
|
index: progress.index,
|
|
363
294
|
agent: progress.agent,
|
|
295
|
+
...(progress.sessionName ? { sessionName: progress.sessionName } : {}),
|
|
364
296
|
status: progress.status,
|
|
365
297
|
activityState: progress.activityState,
|
|
366
298
|
task: "[prompt redacted]",
|
|
@@ -407,6 +339,17 @@ export function sumResultsUsage(results: SingleResult[]): Usage {
|
|
|
407
339
|
return usage;
|
|
408
340
|
}
|
|
409
341
|
|
|
342
|
+
export function toAgentToolUsage(usage: Usage): PiUsage {
|
|
343
|
+
return {
|
|
344
|
+
input: usage.input,
|
|
345
|
+
output: usage.output,
|
|
346
|
+
cacheRead: usage.cacheRead,
|
|
347
|
+
cacheWrite: usage.cacheWrite,
|
|
348
|
+
totalTokens: usage.input + usage.output + usage.cacheRead + usage.cacheWrite,
|
|
349
|
+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: usage.cost },
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
|
|
410
353
|
function addNestedCost(total: NonNullable<Details["totalCost"]>, children: NestedRunSummary[] | undefined): void {
|
|
411
354
|
for (const child of children ?? []) {
|
|
412
355
|
if (child.totalCost) {
|
|
@@ -505,6 +448,20 @@ export function hasEmptyTerminalAssistantResponse(messages: Message[]): boolean
|
|
|
505
448
|
&& lastAssistant.usage.output === 0;
|
|
506
449
|
}
|
|
507
450
|
|
|
451
|
+
export function formatEmptyTerminalAssistantResponseError(messages: Message[]): string {
|
|
452
|
+
const lastAssistant = messages.findLast((message) => message.role === "assistant");
|
|
453
|
+
const errorMessage = lastAssistant && "errorMessage" in lastAssistant && typeof lastAssistant.errorMessage === "string" && lastAssistant.errorMessage.trim()
|
|
454
|
+
? lastAssistant.errorMessage.trim()
|
|
455
|
+
: undefined;
|
|
456
|
+
if (errorMessage) return errorMessage;
|
|
457
|
+
const stopReason = lastAssistant && "stopReason" in lastAssistant && typeof lastAssistant.stopReason === "string" && lastAssistant.stopReason.trim()
|
|
458
|
+
? lastAssistant.stopReason.trim()
|
|
459
|
+
: undefined;
|
|
460
|
+
return stopReason && stopReason !== "stop"
|
|
461
|
+
? `Subagent produced no output after terminal assistant stopReason "${stopReason}".`
|
|
462
|
+
: "Subagent produced no output (possible model cold-start or empty response).";
|
|
463
|
+
}
|
|
464
|
+
|
|
508
465
|
/**
|
|
509
466
|
* Detect errors in subagent execution from messages (only errors with no subsequent success)
|
|
510
467
|
*/
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
type SubagentDelegationUpdate,
|
|
7
7
|
type SubagentDelegationValue,
|
|
8
8
|
} from "../api/delegation.ts";
|
|
9
|
-
import type { AcceptanceInput, AgentContract, EffectsProjection, ExecutionProjection, JsonSchemaObject, ReviewProjection, ToolBudgetConfig,
|
|
9
|
+
import type { AcceptanceInput, AgentContract, EffectsProjection, ExecutionProjection, JsonSchemaObject, ReviewProjection, ToolBudgetConfig, Usage } from "../shared/types.ts";
|
|
10
10
|
import { cloneJsonWithinByteLimit } from "./delegation-json.ts";
|
|
11
11
|
|
|
12
12
|
export interface PromptTemplateDelegationRequest {
|
|
@@ -82,7 +82,6 @@ export interface PromptTemplateBridgeResult {
|
|
|
82
82
|
interrupted?: boolean;
|
|
83
83
|
timedOut?: boolean;
|
|
84
84
|
stopped?: boolean;
|
|
85
|
-
turnBudgetExceeded?: boolean;
|
|
86
85
|
toolBudgetBlocked?: boolean;
|
|
87
86
|
structuredOutputFailed?: boolean;
|
|
88
87
|
savedOutputPath?: string;
|
|
@@ -120,9 +119,6 @@ export interface DelegatedSubagentExecutionParams {
|
|
|
120
119
|
model?: string;
|
|
121
120
|
cwd: string;
|
|
122
121
|
timeoutMs?: number;
|
|
123
|
-
turnBudget?: TurnBudgetConfig;
|
|
124
|
-
/** Internal-only strict turn-boundary enforcement for structured foreground delegation. */
|
|
125
|
-
enforceHardTurnLimit?: boolean;
|
|
126
122
|
toolBudget?: ToolBudgetConfig;
|
|
127
123
|
skill?: string | string[] | boolean;
|
|
128
124
|
output?: string | boolean;
|
|
@@ -294,8 +290,6 @@ export function toSubagentDelegationExecutionParams(request: SubagentDelegationR
|
|
|
294
290
|
cwd: request.cwd,
|
|
295
291
|
model: request.model,
|
|
296
292
|
timeoutMs: request.timeoutMs,
|
|
297
|
-
turnBudget: request.turnBudget,
|
|
298
|
-
enforceHardTurnLimit: true,
|
|
299
293
|
toolBudget: request.toolBudget,
|
|
300
294
|
skill: request.skill,
|
|
301
295
|
...(request.result.kind === "structured" ? { outputSchema: request.result.schema } : {}),
|
|
@@ -341,7 +335,6 @@ function resolveSubagentDelegationStatus(
|
|
|
341
335
|
if (!child) return "failed";
|
|
342
336
|
if (result.details?.timedOut || child.timedOut) return "timed_out";
|
|
343
337
|
if (child?.structuredOutputFailed) return "structured_output_failed";
|
|
344
|
-
if (child?.turnBudgetExceeded) return "turn_budget_exhausted";
|
|
345
338
|
if (child?.toolBudgetBlocked) return "tool_budget_exhausted";
|
|
346
339
|
if (child?.acceptance?.status === "rejected" && child.acceptance.explicit) return "acceptance_failed";
|
|
347
340
|
if (result.details?.stopped || child?.stopped || child?.interrupted) return "interrupted";
|
|
@@ -2,7 +2,6 @@ import {
|
|
|
2
2
|
type SubagentDelegationRequest,
|
|
3
3
|
} from "../api/delegation.ts";
|
|
4
4
|
import { validateToolBudgetConfig } from "../runs/shared/tool-budget.ts";
|
|
5
|
-
import { resolveTurnBudgetConfig } from "../runs/shared/turn-budget.ts";
|
|
6
5
|
import { cloneJsonWithinByteLimit } from "./delegation-json.ts";
|
|
7
6
|
|
|
8
7
|
export type SubagentDelegationParseResult =
|
|
@@ -20,7 +19,6 @@ const supportedFields = new Set([
|
|
|
20
19
|
"model",
|
|
21
20
|
"thinking",
|
|
22
21
|
"timeoutMs",
|
|
23
|
-
"turnBudget",
|
|
24
22
|
"toolBudget",
|
|
25
23
|
"skill",
|
|
26
24
|
"artifacts",
|
|
@@ -80,8 +78,6 @@ export function parseSubagentDelegationRequest(data: unknown): SubagentDelegatio
|
|
|
80
78
|
if (timeoutMs !== undefined && timeoutMs > 2_147_483_647) {
|
|
81
79
|
return { ok: false, ...identity, error: "timeoutMs must be <= 2147483647." };
|
|
82
80
|
}
|
|
83
|
-
const turnBudget = resolveTurnBudgetConfig(value.turnBudget);
|
|
84
|
-
if (turnBudget.error) return { ok: false, ...identity, error: turnBudget.error };
|
|
85
81
|
if (value.toolBudget && typeof value.toolBudget === "object" && !Array.isArray(value.toolBudget)) {
|
|
86
82
|
const unsupportedToolBudgetField = Object.keys(value.toolBudget).find((key) => key !== "soft" && key !== "hard" && key !== "block");
|
|
87
83
|
if (unsupportedToolBudgetField) {
|
|
@@ -39,7 +39,6 @@ interface EventBus {
|
|
|
39
39
|
|
|
40
40
|
interface SlashBridgeOptions {
|
|
41
41
|
events: EventBus;
|
|
42
|
-
asyncByDefault: boolean;
|
|
43
42
|
getContext: () => ExtensionContext | null;
|
|
44
43
|
execute: (
|
|
45
44
|
id: string,
|
|
@@ -80,7 +79,7 @@ export function registerSlashSubagentBridge(options: SlashBridgeOptions): {
|
|
|
80
79
|
const request = data as Partial<SlashSubagentRequest>;
|
|
81
80
|
if (typeof request.requestId !== "string" || !request.params) return;
|
|
82
81
|
const { requestId } = request as SlashSubagentRequest;
|
|
83
|
-
const normalized = normalizePublicSubagentExecution((request as SlashSubagentRequest).params
|
|
82
|
+
const normalized = normalizePublicSubagentExecution((request as SlashSubagentRequest).params);
|
|
84
83
|
if (!normalized.ok) {
|
|
85
84
|
options.events.emit(SLASH_SUBAGENT_RESPONSE_EVENT, {
|
|
86
85
|
requestId,
|