@selesai/code 0.1.18 → 0.2.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/dist/agents/architect.md +4 -3
- package/dist/agents/builder.md +5 -4
- package/dist/agents/commentator.md +3 -2
- package/dist/agents/explorer.md +4 -4
- package/dist/agents/recapper.md +4 -3
- package/dist/config.d.ts +6 -7
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +7 -9
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +3 -1
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +2 -0
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/types.d.ts +8 -1
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/skills.d.ts.map +1 -1
- package/dist/core/skills.js +25 -11
- package/dist/core/skills.js.map +1 -1
- package/dist/defaults/settings.json +2 -29
- package/dist/extensions/package.json +5 -4
- package/dist/extensions/pi-intercom/index.ts +12 -5
- package/dist/extensions/pi-powerline-footer/index.ts +4 -1
- package/dist/extensions/pi-powerline-footer/tps.ts +286 -0
- package/dist/extensions/pi-powerline-footer/welcome.ts +47 -46
- package/dist/extensions/pi-subagents/README.md +12 -5
- package/dist/extensions/pi-subagents/agents/context-builder.md +2 -2
- package/dist/extensions/pi-subagents/agents/researcher.md +4 -5
- package/dist/extensions/pi-subagents/package.json +8 -5
- package/dist/extensions/pi-subagents/prompts/parallel-context-build.md +1 -1
- package/dist/extensions/pi-subagents/prompts/parallel-handoff-plan.md +1 -1
- package/dist/extensions/pi-subagents/src/agents/agent-management.ts +1 -1
- package/dist/extensions/pi-subagents/src/agents/agents.ts +3 -3
- package/dist/extensions/pi-subagents/src/extension/control-notices.ts +1 -1
- package/dist/extensions/pi-subagents/src/extension/doctor.ts +3 -3
- package/dist/extensions/pi-subagents/src/extension/fanout-child.ts +1 -1
- package/dist/extensions/pi-subagents/src/extension/index.ts +29 -2
- package/dist/extensions/pi-subagents/src/profiles/profiles.ts +2 -2
- package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +72 -13
- package/dist/extensions/pi-subagents/src/runs/background/async-job-tracker.ts +1 -1
- package/dist/extensions/pi-subagents/src/runs/background/notify.ts +1 -1
- package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +85 -41
- package/dist/extensions/pi-subagents/src/runs/foreground/chain-clarify.ts +1 -1
- package/dist/extensions/pi-subagents/src/runs/foreground/chain-execution.ts +1 -1
- package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +46 -3
- package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +2 -2
- package/dist/extensions/pi-subagents/src/runs/shared/completion-guard.ts +1 -3
- package/dist/extensions/pi-subagents/src/runs/shared/nested-events.ts +2 -2
- package/dist/extensions/pi-subagents/src/runs/shared/pi-args.ts +18 -18
- package/dist/extensions/pi-subagents/src/runs/shared/pi-spawn.ts +24 -24
- package/dist/extensions/pi-subagents/src/runs/shared/spawn-timing.ts +46 -0
- package/dist/extensions/pi-subagents/src/runs/shared/structured-output.ts +2 -2
- package/dist/extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.ts +4 -4
- package/dist/extensions/pi-subagents/src/shared/fork-context.ts +1 -1
- package/dist/extensions/pi-subagents/src/shared/types.ts +6 -6
- package/dist/extensions/pi-subagents/src/shared/utils.ts +3 -3
- package/dist/extensions/pi-subagents/src/slash/slash-bridge.ts +1 -1
- package/dist/extensions/pi-subagents/src/slash/slash-commands.ts +1 -1
- package/dist/extensions/pi-subagents/src/tui/render-helpers.ts +1 -1
- package/dist/extensions/pi-subagents/src/tui/render.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/spawn-timing.test.ts +45 -0
- package/dist/extensions/pi-subagents/tsconfig.runner.json +17 -0
- package/dist/extensions/pi-web-agent/package.json +31 -0
- package/dist/extensions/pi-web-agent/src/backends/config.ts +205 -0
- package/dist/extensions/pi-web-agent/src/backends/doctor.ts +136 -0
- package/dist/extensions/pi-web-agent/src/backends/factory.ts +152 -0
- package/dist/extensions/pi-web-agent/src/backends/settings-reader.ts +25 -0
- package/dist/extensions/pi-web-agent/src/cache/ttl-cache.ts +28 -0
- package/dist/extensions/pi-web-agent/src/changelog-notice.ts +133 -0
- package/dist/extensions/pi-web-agent/src/commands/web-agent-config.ts +946 -0
- package/dist/extensions/pi-web-agent/src/extension.ts +126 -0
- package/dist/extensions/pi-web-agent/src/extract/readability.ts +118 -0
- package/dist/extensions/pi-web-agent/src/fetch/browser-resolution.ts +199 -0
- package/dist/extensions/pi-web-agent/src/fetch/firecrawl-fetch.ts +100 -0
- package/dist/extensions/pi-web-agent/src/fetch/headless-fetch.ts +117 -0
- package/dist/extensions/pi-web-agent/src/fetch/http-fetch.ts +67 -0
- package/dist/extensions/pi-web-agent/src/orchestration/answer-synthesizer.ts +60 -0
- package/dist/extensions/pi-web-agent/src/orchestration/candidate-selector.ts +50 -0
- package/dist/extensions/pi-web-agent/src/orchestration/direct-url.ts +52 -0
- package/dist/extensions/pi-web-agent/src/orchestration/evidence-quality.ts +105 -0
- package/dist/extensions/pi-web-agent/src/orchestration/evidence-ranker.ts +45 -0
- package/dist/extensions/pi-web-agent/src/orchestration/index.ts +28 -0
- package/dist/extensions/pi-web-agent/src/orchestration/query-planner.ts +47 -0
- package/dist/extensions/pi-web-agent/src/orchestration/research-orchestrator.ts +376 -0
- package/dist/extensions/pi-web-agent/src/orchestration/research-types.ts +64 -0
- package/dist/extensions/pi-web-agent/src/orchestration/research-worker.ts +181 -0
- package/dist/extensions/pi-web-agent/src/orchestration/source-profile.ts +101 -0
- package/dist/extensions/pi-web-agent/src/orchestration/stop-decider.ts +81 -0
- package/dist/extensions/pi-web-agent/src/presentation/config-store.ts +208 -0
- package/dist/extensions/pi-web-agent/src/presentation/config.ts +75 -0
- package/dist/extensions/pi-web-agent/src/presentation/explore-presentation.ts +61 -0
- package/dist/extensions/pi-web-agent/src/presentation/fetch-presentation.ts +54 -0
- package/dist/extensions/pi-web-agent/src/presentation/search-presentation.ts +41 -0
- package/dist/extensions/pi-web-agent/src/presentation/select-view.ts +20 -0
- package/dist/extensions/pi-web-agent/src/presentation/types.ts +63 -0
- package/dist/extensions/pi-web-agent/src/search/brave.ts +114 -0
- package/dist/extensions/pi-web-agent/src/search/duckduckgo.ts +72 -0
- package/dist/extensions/pi-web-agent/src/search/searxng.ts +96 -0
- package/dist/extensions/pi-web-agent/src/tools/web-explore.ts +71 -0
- package/dist/extensions/pi-web-agent/src/tools/web-fetch-headless.ts +31 -0
- package/dist/extensions/pi-web-agent/src/tools/web-fetch.ts +31 -0
- package/dist/extensions/pi-web-agent/src/tools/web-search.ts +157 -0
- package/dist/extensions/pi-web-agent/src/types.ts +88 -0
- package/dist/extensions/ponytail/index.js +189 -0
- package/dist/extensions/ponytail/package.json +8 -0
- package/dist/extensions/ponytail/ponytail-config.cjs +122 -0
- package/dist/extensions/ponytail/ponytail-instructions.cjs +94 -0
- package/dist/extensions/ponytail/test/extension.test.js +167 -0
- package/dist/extensions/ponytail/test/helpers.test.js +92 -0
- package/dist/extensions/question/constants.ts +38 -0
- package/dist/extensions/question/dialog-adapter.ts +74 -0
- package/dist/extensions/question/helpers.ts +102 -0
- package/dist/extensions/question/index.ts +671 -0
- package/dist/extensions/question/navigation.ts +14 -0
- package/dist/extensions/question/package.json +18 -0
- package/dist/extensions/question/question-list.ts +498 -0
- package/dist/extensions/question/row-layout.ts +162 -0
- package/dist/extensions/question/schemas.ts +69 -0
- package/dist/extensions/question/selection-mode.ts +49 -0
- package/dist/extensions/question/shortcuts.ts +53 -0
- package/dist/extensions/question/tests/helpers.test.ts +178 -0
- package/dist/extensions/question/tests/question-list.test.ts +230 -0
- package/dist/extensions/question/tests/row-layout.test.ts +136 -0
- package/dist/extensions/question/tests/shortcuts.test.ts +85 -0
- package/dist/extensions/question/tests/ui-protocol.test.ts +143 -0
- package/dist/extensions/question/tui-adapter.ts +33 -0
- package/dist/extensions/question/types.ts +102 -0
- package/dist/extensions/question/ui-protocol.ts +46 -0
- package/dist/extensions/tokenin-onboarding.ts +265 -2
- package/dist/extensions/web-agent-onboarding.ts +222 -0
- package/dist/extensions/workflow/adapter.ts +588 -0
- package/dist/extensions/workflow/extension.ts +24 -0
- package/dist/extensions/workflow/modes/prototype.ts +156 -0
- package/dist/extensions/workflow/modes/quick.ts +138 -0
- package/dist/extensions/workflow/package.json +17 -0
- package/dist/extensions/workflow/state-machine.ts +386 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/utils/mime.d.ts.map +1 -1
- package/dist/utils/mime.js +24 -1
- package/dist/utils/mime.js.map +1 -1
- package/docs/docs.json +4 -0
- package/docs/workflows.md +206 -0
- package/package.json +5 -1
- package/README.md +0 -198
|
@@ -6,7 +6,7 @@ import type { Message } from "@earendil-works/pi-ai";
|
|
|
6
6
|
import { writeAtomicJson } from "../../shared/atomic-json.ts";
|
|
7
7
|
import { consumeInterruptRequest, watchAsyncControlInbox } from "./control-channel.ts";
|
|
8
8
|
import { appendJsonl as appendRawJsonl, getArtifactPaths } from "../../shared/artifacts.ts";
|
|
9
|
-
import {
|
|
9
|
+
import { SELESAI_PACKAGE, getSelesaiSpawnCommand, resolveInstalledSelesaiPackageRoot } from "../shared/pi-spawn.ts";
|
|
10
10
|
import { captureSingleOutputSnapshot, finalizeSingleOutput, formatSavedOutputReference, resolveSingleOutput, type SingleOutputSnapshot } from "../shared/single-output.ts";
|
|
11
11
|
import {
|
|
12
12
|
type ActivityState,
|
|
@@ -81,6 +81,7 @@ import { resolveSubagentIntercomTarget } from "../../intercom/intercom-bridge.ts
|
|
|
81
81
|
import { acceptanceFailureMessage, aggregateAcceptanceReport, evaluateAcceptance, formatAcceptancePrompt, stripAcceptanceReport } from "../shared/acceptance.ts";
|
|
82
82
|
import { waitForImportedAsyncRoot } from "./chain-root-attachment.ts";
|
|
83
83
|
import { appendRunnerStepsToStatus, consumeChainAppendRequests, countPendingChainAppendRequests } from "./chain-append.ts";
|
|
84
|
+
import { createSpawnTimingMarkers, emitSpawnTiming, type SpawnTimingMarkers } from "../shared/spawn-timing.ts";
|
|
84
85
|
|
|
85
86
|
interface SubagentRunConfig {
|
|
86
87
|
id: string;
|
|
@@ -133,7 +134,7 @@ interface StepResult {
|
|
|
133
134
|
|
|
134
135
|
const ASYNC_INTERRUPT_SIGNAL: NodeJS.Signals = process.platform === "win32" ? "SIGBREAK" : "SIGUSR2";
|
|
135
136
|
const DEFAULT_MAX_ASYNC_EVENTS_BYTES = 50 * 1024 * 1024;
|
|
136
|
-
const ASYNC_EVENTS_MAX_BYTES_ENV = "
|
|
137
|
+
const ASYNC_EVENTS_MAX_BYTES_ENV = "SELESAI_SUBAGENT_ASYNC_EVENTS_MAX_BYTES";
|
|
137
138
|
const TRUNCATED_EVENT_TYPE = "subagent.events.truncated";
|
|
138
139
|
const TRUNCATION_MARKER_RESERVE_BYTES = 512;
|
|
139
140
|
|
|
@@ -261,6 +262,7 @@ interface ChildEventContext {
|
|
|
261
262
|
runId: string;
|
|
262
263
|
stepIndex: number;
|
|
263
264
|
agent: string;
|
|
265
|
+
markers?: SpawnTimingMarkers;
|
|
264
266
|
}
|
|
265
267
|
|
|
266
268
|
interface ChildUsage {
|
|
@@ -313,10 +315,17 @@ function runPiStreaming(
|
|
|
313
315
|
return new Promise((resolve) => {
|
|
314
316
|
const outputStream = fs.createWriteStream(outputFile, { flags: "w" });
|
|
315
317
|
const spawnEnv = { ...process.env, ...(env ?? {}), ...getSubagentDepthEnv(maxSubagentDepth) };
|
|
316
|
-
const
|
|
318
|
+
const markers = childEventContext ? createSpawnTimingMarkers() : undefined;
|
|
319
|
+
if (markers) {
|
|
320
|
+
emitSpawnTiming({ eventsPath: childEventContext.eventsPath, marker: "spawn_start", markers, runId: childEventContext.runId, stepIndex: childEventContext.stepIndex, agent: childEventContext.agent });
|
|
321
|
+
}
|
|
322
|
+
const spawnSpec = getSelesaiSpawnCommand(args, {
|
|
317
323
|
...(piPackageRoot ? { piPackageRoot } : {}),
|
|
318
324
|
...(piArgv1 ? { argv1: piArgv1 } : {}),
|
|
319
325
|
});
|
|
326
|
+
if (markers) {
|
|
327
|
+
emitSpawnTiming({ eventsPath: childEventContext.eventsPath, marker: "spawn_command_resolved", markers, runId: childEventContext.runId, stepIndex: childEventContext.stepIndex, agent: childEventContext.agent });
|
|
328
|
+
}
|
|
320
329
|
const child = spawn(spawnSpec.command, spawnSpec.args, {
|
|
321
330
|
cwd,
|
|
322
331
|
stdio: ["ignore", "pipe", "pipe"],
|
|
@@ -333,8 +342,22 @@ function runPiStreaming(
|
|
|
333
342
|
let assistantError: string | undefined;
|
|
334
343
|
let interrupted = false;
|
|
335
344
|
let observedMutationAttempt = false;
|
|
345
|
+
let firstEventEmitted = false;
|
|
346
|
+
let firstJsonlEventEmitted = false;
|
|
336
347
|
const rawStdoutLines: string[] = [];
|
|
337
348
|
|
|
349
|
+
const emitChildTiming = (marker: import("../shared/spawn-timing.ts").SpawnTimingMarker) => {
|
|
350
|
+
if (!markers || !childEventContext) return;
|
|
351
|
+
emitSpawnTiming({
|
|
352
|
+
eventsPath: childEventContext.eventsPath,
|
|
353
|
+
marker,
|
|
354
|
+
markers,
|
|
355
|
+
runId: childEventContext.runId,
|
|
356
|
+
stepIndex: childEventContext.stepIndex,
|
|
357
|
+
agent: childEventContext.agent,
|
|
358
|
+
});
|
|
359
|
+
};
|
|
360
|
+
|
|
338
361
|
const writeOutputLine = (line: string) => {
|
|
339
362
|
if (!line.trim()) return;
|
|
340
363
|
outputStream.write(`${line}\n`);
|
|
@@ -368,6 +391,10 @@ function runPiStreaming(
|
|
|
368
391
|
let event: ChildEvent;
|
|
369
392
|
try {
|
|
370
393
|
event = JSON.parse(line) as ChildEvent;
|
|
394
|
+
if (!firstJsonlEventEmitted) {
|
|
395
|
+
firstJsonlEventEmitted = true;
|
|
396
|
+
emitChildTiming("child_first_jsonl_event");
|
|
397
|
+
}
|
|
371
398
|
} catch {
|
|
372
399
|
rawStdoutLines.push(line);
|
|
373
400
|
writeOutputLine(line);
|
|
@@ -438,6 +465,10 @@ function runPiStreaming(
|
|
|
438
465
|
let settled = false;
|
|
439
466
|
const clearStdioGuard = attachPostExitStdioGuard(child, { idleMs: 2000, hardMs: 8000 });
|
|
440
467
|
child.stdout.on("data", (chunk: Buffer) => {
|
|
468
|
+
if (!firstEventEmitted) {
|
|
469
|
+
firstEventEmitted = true;
|
|
470
|
+
emitChildTiming("child_first_event");
|
|
471
|
+
}
|
|
441
472
|
const text = chunk.toString();
|
|
442
473
|
stdoutBuf += text;
|
|
443
474
|
const lines = stdoutBuf.split("\n");
|
|
@@ -446,6 +477,10 @@ function runPiStreaming(
|
|
|
446
477
|
});
|
|
447
478
|
|
|
448
479
|
child.stderr.on("data", (chunk: Buffer) => {
|
|
480
|
+
if (!firstEventEmitted) {
|
|
481
|
+
firstEventEmitted = true;
|
|
482
|
+
emitChildTiming("child_first_event");
|
|
483
|
+
}
|
|
449
484
|
processStderrText(chunk.toString());
|
|
450
485
|
});
|
|
451
486
|
registerInterrupt?.(() => {
|
|
@@ -526,14 +561,14 @@ function runPiStreaming(
|
|
|
526
561
|
});
|
|
527
562
|
}
|
|
528
563
|
|
|
529
|
-
function
|
|
530
|
-
const root =
|
|
564
|
+
function resolveSelesaiPackageRootFallback(): string {
|
|
565
|
+
const root = resolveInstalledSelesaiPackageRoot();
|
|
531
566
|
if (root) return root;
|
|
532
|
-
throw new Error(`Could not resolve ${
|
|
567
|
+
throw new Error(`Could not resolve ${SELESAI_PACKAGE} package root`);
|
|
533
568
|
}
|
|
534
569
|
|
|
535
570
|
async function exportSessionHtml(sessionFile: string, outputDir: string, piPackageRoot?: string): Promise<string> {
|
|
536
|
-
const pkgRoot = piPackageRoot ??
|
|
571
|
+
const pkgRoot = piPackageRoot ?? resolveSelesaiPackageRootFallback();
|
|
537
572
|
const exportModulePath = path.join(pkgRoot, "dist", "core", "export-html", "index.js");
|
|
538
573
|
const moduleUrl = pathToFileURL(exportModulePath).href;
|
|
539
574
|
const mod = await import(moduleUrl);
|
|
@@ -752,7 +787,7 @@ async function runSingleStep(
|
|
|
752
787
|
}
|
|
753
788
|
const { args, env, tempDir } = buildPiArgs({
|
|
754
789
|
parentSessionId: step.parentSessionId,
|
|
755
|
-
baseArgs: ["--mode", "json", "-p"],
|
|
790
|
+
baseArgs: ["--offline", "--mode", "json", "-p"],
|
|
756
791
|
task,
|
|
757
792
|
sessionEnabled,
|
|
758
793
|
sessionDir,
|
|
@@ -1056,7 +1091,7 @@ function ensureParallelProgressFile(cwd: string, group: Extract<RunnerStep, { pa
|
|
|
1056
1091
|
writeInitialProgressFile(cwd);
|
|
1057
1092
|
}
|
|
1058
1093
|
|
|
1059
|
-
async function runSubagent(config: SubagentRunConfig): Promise<void> {
|
|
1094
|
+
export async function runSubagent(config: SubagentRunConfig): Promise<void> {
|
|
1060
1095
|
const { id, steps, resultPath, cwd, placeholder, taskIndex, totalTasks, maxOutput, artifactsDir, artifactConfig } =
|
|
1061
1096
|
config;
|
|
1062
1097
|
let previousOutput = "";
|
|
@@ -2419,40 +2454,49 @@ async function runSubagent(config: SubagentRunConfig): Promise<void> {
|
|
|
2419
2454
|
}
|
|
2420
2455
|
}
|
|
2421
2456
|
|
|
2422
|
-
|
|
2423
|
-
|
|
2457
|
+
export async function runSubagentFromConfigFile(cfgPath: string): Promise<void> {
|
|
2458
|
+
const configJson = fs.readFileSync(cfgPath, "utf-8");
|
|
2459
|
+
const config = JSON.parse(configJson) as SubagentRunConfig;
|
|
2424
2460
|
try {
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
fs.unlinkSync(configArg);
|
|
2429
|
-
} catch {
|
|
2430
|
-
// Temp config cleanup is best effort.
|
|
2431
|
-
}
|
|
2432
|
-
runSubagent(config).catch((runErr) => {
|
|
2433
|
-
console.error("Subagent runner error:", runErr);
|
|
2434
|
-
process.exit(1);
|
|
2435
|
-
});
|
|
2436
|
-
} catch (err) {
|
|
2437
|
-
console.error("Subagent runner error:", err);
|
|
2438
|
-
process.exit(1);
|
|
2461
|
+
fs.unlinkSync(cfgPath);
|
|
2462
|
+
} catch {
|
|
2463
|
+
// Temp config cleanup is best effort.
|
|
2439
2464
|
}
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2465
|
+
await runSubagent(config);
|
|
2466
|
+
}
|
|
2467
|
+
|
|
2468
|
+
function isRunnerMainModule(): boolean {
|
|
2469
|
+
try {
|
|
2470
|
+
return import.meta.url === pathToFileURL(process.argv[1] ?? "").href;
|
|
2471
|
+
} catch {
|
|
2472
|
+
return false;
|
|
2473
|
+
}
|
|
2474
|
+
}
|
|
2475
|
+
|
|
2476
|
+
if (!runnerConfigPath && isRunnerMainModule()) {
|
|
2477
|
+
const configArg = process.argv[2];
|
|
2478
|
+
if (configArg) {
|
|
2479
|
+
runSubagentFromConfigFile(configArg).catch((err) => {
|
|
2454
2480
|
console.error("Subagent runner error:", err);
|
|
2455
2481
|
process.exit(1);
|
|
2456
|
-
}
|
|
2457
|
-
}
|
|
2482
|
+
});
|
|
2483
|
+
} else {
|
|
2484
|
+
let input = "";
|
|
2485
|
+
process.stdin.setEncoding("utf-8");
|
|
2486
|
+
process.stdin.on("data", (chunk) => {
|
|
2487
|
+
input += chunk;
|
|
2488
|
+
});
|
|
2489
|
+
process.stdin.on("end", () => {
|
|
2490
|
+
try {
|
|
2491
|
+
const config = JSON.parse(input) as SubagentRunConfig;
|
|
2492
|
+
runSubagent(config).catch((err) => {
|
|
2493
|
+
console.error("Subagent runner error:", err);
|
|
2494
|
+
process.exit(1);
|
|
2495
|
+
});
|
|
2496
|
+
} catch (err) {
|
|
2497
|
+
console.error("Subagent runner error:", err);
|
|
2498
|
+
process.exit(1);
|
|
2499
|
+
}
|
|
2500
|
+
});
|
|
2501
|
+
}
|
|
2458
2502
|
}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Supports runtime editing of templates, output paths, reads lists, and progress toggle.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import type { Theme } from "@
|
|
8
|
+
import type { Theme } from "@selesai/code";
|
|
9
9
|
import type { Component, TUI } from "@earendil-works/pi-tui";
|
|
10
10
|
import { matchesKey, visibleWidth, truncateToWidth } from "@earendil-works/pi-tui";
|
|
11
11
|
import type { AgentConfig } from "../../agents/agents.ts";
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import * as fs from "node:fs";
|
|
6
6
|
import * as path from "node:path";
|
|
7
7
|
import type { AgentToolResult } from "@earendil-works/pi-agent-core";
|
|
8
|
-
import type { ExtensionContext } from "@
|
|
8
|
+
import type { ExtensionContext } from "@selesai/code";
|
|
9
9
|
import type { AgentConfig } from "../../agents/agents.ts";
|
|
10
10
|
import { ChainClarifyComponent, type ChainClarifyResult, type BehaviorOverride } from "./chain-clarify.ts";
|
|
11
11
|
import { toModelInfo, type ModelInfo } from "../../shared/model-info.ts";
|
|
@@ -44,10 +44,11 @@ import {
|
|
|
44
44
|
} from "../../shared/utils.ts";
|
|
45
45
|
import { buildSkillInjection, resolveSkillsWithFallback } from "../../agents/skills.ts";
|
|
46
46
|
import { evaluateCompletionMutationGuard } from "../shared/completion-guard.ts";
|
|
47
|
-
import {
|
|
47
|
+
import { getSelesaiSpawnCommand } from "../shared/pi-spawn.ts";
|
|
48
48
|
import { createJsonlWriter } from "../../shared/jsonl-writer.ts";
|
|
49
49
|
import { attachPostExitStdioGuard, trySignalChild } from "../../shared/post-exit-stdio-guard.ts";
|
|
50
50
|
import { applyThinkingSuffix, buildPiArgs, cleanupTempDir } from "../shared/pi-args.ts";
|
|
51
|
+
import { createSpawnTimingMarkers, emitSpawnTiming } from "../shared/spawn-timing.ts";
|
|
51
52
|
import { readStructuredOutput } from "../shared/structured-output.ts";
|
|
52
53
|
import { captureSingleOutputSnapshot, formatSavedOutputReference, injectOutputPathSystemPrompt, resolveSingleOutput, validateFileOnlyOutputMode, type SingleOutputSnapshot } from "../shared/single-output.ts";
|
|
53
54
|
import {
|
|
@@ -182,7 +183,7 @@ async function runSingleAttempt(
|
|
|
182
183
|
): Promise<SingleResult> {
|
|
183
184
|
const modelArg = applyThinkingSuffix(model, agent.thinking);
|
|
184
185
|
const { args, env: sharedEnv, tempDir } = buildPiArgs({
|
|
185
|
-
baseArgs: ["--mode", "json", "-p"],
|
|
186
|
+
baseArgs: ["--offline", "--mode", "json", "-p"],
|
|
186
187
|
task,
|
|
187
188
|
sessionEnabled: shared.sessionEnabled,
|
|
188
189
|
sessionDir: options.sessionDir,
|
|
@@ -278,7 +279,24 @@ async function runSingleAttempt(
|
|
|
278
279
|
let observedMutationAttempt = false;
|
|
279
280
|
|
|
280
281
|
const exitCode = await new Promise<number>((resolve) => {
|
|
281
|
-
const
|
|
282
|
+
const markers = createSpawnTimingMarkers();
|
|
283
|
+
const spawnSpec = getSelesaiSpawnCommand(args);
|
|
284
|
+
emitSpawnTiming({
|
|
285
|
+
eventsPath: shared.jsonlPath,
|
|
286
|
+
marker: "spawn_start",
|
|
287
|
+
markers,
|
|
288
|
+
runId: options.runId,
|
|
289
|
+
stepIndex: options.index ?? 0,
|
|
290
|
+
agent: agent.name,
|
|
291
|
+
});
|
|
292
|
+
emitSpawnTiming({
|
|
293
|
+
eventsPath: shared.jsonlPath,
|
|
294
|
+
marker: "spawn_command_resolved",
|
|
295
|
+
markers,
|
|
296
|
+
runId: options.runId,
|
|
297
|
+
stepIndex: options.index ?? 0,
|
|
298
|
+
agent: agent.name,
|
|
299
|
+
});
|
|
282
300
|
const proc = spawn(spawnSpec.command, spawnSpec.args, {
|
|
283
301
|
cwd: options.cwd ?? runtimeCwd,
|
|
284
302
|
env: spawnEnv,
|
|
@@ -286,6 +304,8 @@ async function runSingleAttempt(
|
|
|
286
304
|
windowsHide: true,
|
|
287
305
|
});
|
|
288
306
|
const jsonlWriter = createJsonlWriter(shared.jsonlPath, proc.stdout);
|
|
307
|
+
let firstEventEmitted = false;
|
|
308
|
+
let firstJsonlEventEmitted = false;
|
|
289
309
|
let buf = "";
|
|
290
310
|
let processClosed = false;
|
|
291
311
|
let settled = false;
|
|
@@ -498,12 +518,27 @@ async function runSingleAttempt(
|
|
|
498
518
|
emitUpdateSnapshot(output || "(running...)");
|
|
499
519
|
};
|
|
500
520
|
|
|
521
|
+
const emitTiming = (marker: import("../shared/spawn-timing.ts").SpawnTimingMarker) => {
|
|
522
|
+
emitSpawnTiming({
|
|
523
|
+
eventsPath: shared.jsonlPath,
|
|
524
|
+
marker,
|
|
525
|
+
markers,
|
|
526
|
+
runId: options.runId,
|
|
527
|
+
stepIndex: options.index ?? 0,
|
|
528
|
+
agent: agent.name,
|
|
529
|
+
});
|
|
530
|
+
};
|
|
531
|
+
|
|
501
532
|
const processLine = (line: string) => {
|
|
502
533
|
if (!line.trim()) return;
|
|
503
534
|
jsonlWriter.writeLine(line);
|
|
504
535
|
let evt: { type?: string; message?: Message; toolName?: string; args?: unknown };
|
|
505
536
|
try {
|
|
506
537
|
evt = JSON.parse(line) as { type?: string; message?: Message; toolName?: string; args?: unknown };
|
|
538
|
+
if (!firstJsonlEventEmitted) {
|
|
539
|
+
firstJsonlEventEmitted = true;
|
|
540
|
+
emitTiming("child_first_jsonl_event");
|
|
541
|
+
}
|
|
507
542
|
} catch {
|
|
508
543
|
// Non-JSON stdout lines are expected; only structured events are parsed.
|
|
509
544
|
return;
|
|
@@ -650,12 +685,20 @@ async function runSingleAttempt(
|
|
|
650
685
|
|
|
651
686
|
const clearStdioGuard = attachPostExitStdioGuard(proc, { idleMs: 2000, hardMs: 8000 });
|
|
652
687
|
proc.stdout.on("data", (d) => {
|
|
688
|
+
if (!firstEventEmitted) {
|
|
689
|
+
firstEventEmitted = true;
|
|
690
|
+
emitTiming("child_first_event");
|
|
691
|
+
}
|
|
653
692
|
buf += d.toString();
|
|
654
693
|
const lines = buf.split("\n");
|
|
655
694
|
buf = lines.pop() || "";
|
|
656
695
|
lines.forEach(processLine);
|
|
657
696
|
});
|
|
658
697
|
proc.stderr.on("data", (d) => {
|
|
698
|
+
if (!firstEventEmitted) {
|
|
699
|
+
firstEventEmitted = true;
|
|
700
|
+
emitTiming("child_first_event");
|
|
701
|
+
}
|
|
659
702
|
stderrBuf += d.toString();
|
|
660
703
|
});
|
|
661
704
|
proc.on("exit", () => {
|
|
@@ -2,7 +2,7 @@ import { randomUUID } from "node:crypto";
|
|
|
2
2
|
import * as fs from "node:fs";
|
|
3
3
|
import * as path from "node:path";
|
|
4
4
|
import type { AgentToolResult } from "@earendil-works/pi-agent-core";
|
|
5
|
-
import type { ExtensionAPI, ExtensionContext } from "@
|
|
5
|
+
import type { ExtensionAPI, ExtensionContext } from "@selesai/code";
|
|
6
6
|
import { type AgentConfig, type AgentScope } from "../../agents/agents.ts";
|
|
7
7
|
import { getArtifactsDir } from "../../shared/artifacts.ts";
|
|
8
8
|
import { ChainClarifyComponent, type ChainClarifyResult } from "./chain-clarify.ts";
|
|
@@ -3035,7 +3035,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
3035
3035
|
parentStepIndex: nestedParentAddress.parentStepIndex,
|
|
3036
3036
|
depth: nestedParentAddress.depth,
|
|
3037
3037
|
path: nestedParentAddress.path,
|
|
3038
|
-
ownerIntercomTarget: process.env.
|
|
3038
|
+
ownerIntercomTarget: process.env.SELESAI_SUBAGENT_INTERCOM_SESSION_NAME,
|
|
3039
3039
|
leafIntercomTarget,
|
|
3040
3040
|
intercomTarget: leafIntercomTarget,
|
|
3041
3041
|
ownerState: state === "running" ? "live" : "gone",
|
|
@@ -802,8 +802,8 @@ export function nestedSummaryFromAsyncStatus(status: AsyncStatus, asyncDir: stri
|
|
|
802
802
|
|
|
803
803
|
export function nestedArtifactEnv(rootRunId: string, parentRunId: string): Record<string, string> {
|
|
804
804
|
return {
|
|
805
|
-
|
|
806
|
-
|
|
805
|
+
SELESAI_SUBAGENT_NESTED_ROOT_RUN_ID: rootRunId,
|
|
806
|
+
SELESAI_SUBAGENT_NESTED_PARENT_RUN_ID: parentRunId,
|
|
807
807
|
};
|
|
808
808
|
}
|
|
809
809
|
|
|
@@ -11,21 +11,21 @@ const THINKING_LEVELS = ["off", "minimal", "low", "medium", "high", "xhigh"];
|
|
|
11
11
|
const TASK_ARG_LIMIT = 8000;
|
|
12
12
|
const PROMPT_RUNTIME_EXTENSION_PATH = path.join(path.dirname(fileURLToPath(import.meta.url)), "subagent-prompt-runtime.ts");
|
|
13
13
|
const FANOUT_CHILD_EXTENSION_PATH = path.join(path.dirname(fileURLToPath(import.meta.url)), "..", "..", "extension", "fanout-child.ts");
|
|
14
|
-
export const SUBAGENT_CHILD_ENV = "
|
|
15
|
-
export const SUBAGENT_ORCHESTRATOR_TARGET_ENV = "
|
|
16
|
-
export const SUBAGENT_RUN_ID_ENV = "
|
|
17
|
-
export const SUBAGENT_CHILD_AGENT_ENV = "
|
|
18
|
-
export const SUBAGENT_CHILD_INDEX_ENV = "
|
|
19
|
-
export const SUBAGENT_FANOUT_CHILD_ENV = "
|
|
20
|
-
export const SUBAGENT_PARENT_EVENT_SINK_ENV = "
|
|
21
|
-
export const SUBAGENT_PARENT_CONTROL_INBOX_ENV = "
|
|
22
|
-
export const SUBAGENT_PARENT_ROOT_RUN_ID_ENV = "
|
|
23
|
-
export const SUBAGENT_PARENT_RUN_ID_ENV = "
|
|
24
|
-
export const SUBAGENT_PARENT_CHILD_INDEX_ENV = "
|
|
25
|
-
export const SUBAGENT_PARENT_DEPTH_ENV = "
|
|
26
|
-
export const SUBAGENT_PARENT_PATH_ENV = "
|
|
27
|
-
export const SUBAGENT_PARENT_CAPABILITY_TOKEN_ENV = "
|
|
28
|
-
export const SUBAGENT_PARENT_SESSION_ENV = "
|
|
14
|
+
export const SUBAGENT_CHILD_ENV = "SELESAI_SUBAGENT_CHILD";
|
|
15
|
+
export const SUBAGENT_ORCHESTRATOR_TARGET_ENV = "SELESAI_SUBAGENT_ORCHESTRATOR_TARGET";
|
|
16
|
+
export const SUBAGENT_RUN_ID_ENV = "SELESAI_SUBAGENT_RUN_ID";
|
|
17
|
+
export const SUBAGENT_CHILD_AGENT_ENV = "SELESAI_SUBAGENT_CHILD_AGENT";
|
|
18
|
+
export const SUBAGENT_CHILD_INDEX_ENV = "SELESAI_SUBAGENT_CHILD_INDEX";
|
|
19
|
+
export const SUBAGENT_FANOUT_CHILD_ENV = "SELESAI_SUBAGENT_FANOUT_CHILD";
|
|
20
|
+
export const SUBAGENT_PARENT_EVENT_SINK_ENV = "SELESAI_SUBAGENT_PARENT_EVENT_SINK";
|
|
21
|
+
export const SUBAGENT_PARENT_CONTROL_INBOX_ENV = "SELESAI_SUBAGENT_PARENT_CONTROL_INBOX";
|
|
22
|
+
export const SUBAGENT_PARENT_ROOT_RUN_ID_ENV = "SELESAI_SUBAGENT_PARENT_ROOT_RUN_ID";
|
|
23
|
+
export const SUBAGENT_PARENT_RUN_ID_ENV = "SELESAI_SUBAGENT_PARENT_RUN_ID";
|
|
24
|
+
export const SUBAGENT_PARENT_CHILD_INDEX_ENV = "SELESAI_SUBAGENT_PARENT_CHILD_INDEX";
|
|
25
|
+
export const SUBAGENT_PARENT_DEPTH_ENV = "SELESAI_SUBAGENT_PARENT_DEPTH";
|
|
26
|
+
export const SUBAGENT_PARENT_PATH_ENV = "SELESAI_SUBAGENT_PARENT_PATH";
|
|
27
|
+
export const SUBAGENT_PARENT_CAPABILITY_TOKEN_ENV = "SELESAI_SUBAGENT_PARENT_CAPABILITY_TOKEN";
|
|
28
|
+
export const SUBAGENT_PARENT_SESSION_ENV = "SELESAI_SUBAGENT_PARENT_SESSION";
|
|
29
29
|
|
|
30
30
|
interface BuildPiArgsInput {
|
|
31
31
|
parentSessionId?: string;
|
|
@@ -196,10 +196,10 @@ export function buildPiArgs(input: BuildPiArgsInput): BuildPiArgsResult {
|
|
|
196
196
|
env[SUBAGENT_PARENT_CAPABILITY_TOKEN_ENV] = fanoutAuthorized
|
|
197
197
|
? input.parentCapabilityToken ?? process.env[SUBAGENT_PARENT_CAPABILITY_TOKEN_ENV] ?? ""
|
|
198
198
|
: "";
|
|
199
|
-
env.
|
|
200
|
-
env.
|
|
199
|
+
env.SELESAI_SUBAGENT_INHERIT_PROJECT_CONTEXT = input.inheritProjectContext ? "1" : "0";
|
|
200
|
+
env.SELESAI_SUBAGENT_INHERIT_SKILLS = input.inheritSkills ? "1" : "0";
|
|
201
201
|
if (input.intercomSessionName) {
|
|
202
|
-
env.
|
|
202
|
+
env.SELESAI_SUBAGENT_INTERCOM_SESSION_NAME = input.intercomSessionName;
|
|
203
203
|
}
|
|
204
204
|
if (input.orchestratorIntercomTarget) {
|
|
205
205
|
env[SUBAGENT_ORCHESTRATOR_TARGET_ENV] = input.orchestratorIntercomTarget;
|
|
@@ -2,36 +2,36 @@ import * as fs from "node:fs";
|
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
4
|
|
|
5
|
-
export const
|
|
5
|
+
export const SELESAI_PACKAGE = "@selesai/code";
|
|
6
6
|
|
|
7
|
-
export function
|
|
7
|
+
export function findSelesaiPackageRootFromEntry(entryPoint: string): string | undefined {
|
|
8
8
|
let dir = path.dirname(entryPoint);
|
|
9
9
|
while (dir !== path.dirname(dir)) {
|
|
10
10
|
const packageJsonPath = path.join(dir, "package.json");
|
|
11
11
|
if (fs.existsSync(packageJsonPath)) {
|
|
12
12
|
const pkg = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8")) as { name?: unknown };
|
|
13
|
-
if (pkg.name ===
|
|
13
|
+
if (pkg.name === SELESAI_PACKAGE) return dir;
|
|
14
14
|
}
|
|
15
15
|
dir = path.dirname(dir);
|
|
16
16
|
}
|
|
17
17
|
return undefined;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
export function
|
|
21
|
-
return
|
|
20
|
+
export function resolveInstalledSelesaiPackageRoot(): string | undefined {
|
|
21
|
+
return findSelesaiPackageRootFromEntry(fileURLToPath(import.meta.resolve(SELESAI_PACKAGE)));
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
export function
|
|
24
|
+
export function resolveSelesaiPackageRoot(): string | undefined {
|
|
25
25
|
try {
|
|
26
26
|
const entry = process.argv[1];
|
|
27
|
-
return entry ?
|
|
27
|
+
return entry ? findSelesaiPackageRootFromEntry(fs.realpathSync(entry)) : undefined;
|
|
28
28
|
} catch {
|
|
29
29
|
// process.argv[1] probing is best-effort; callers can fall back to PATH/package resolution.
|
|
30
30
|
return undefined;
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
export interface
|
|
34
|
+
export interface SelesaiSpawnDeps {
|
|
35
35
|
platform?: NodeJS.Platform;
|
|
36
36
|
execPath?: string;
|
|
37
37
|
argv1?: string;
|
|
@@ -42,7 +42,7 @@ export interface PiSpawnDeps {
|
|
|
42
42
|
piPackageRoot?: string;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
interface
|
|
45
|
+
interface SelesaiSpawnCommand {
|
|
46
46
|
command: string;
|
|
47
47
|
args: string[];
|
|
48
48
|
}
|
|
@@ -56,7 +56,7 @@ function normalizePath(filePath: string): string {
|
|
|
56
56
|
return path.isAbsolute(filePath) ? filePath : path.resolve(filePath);
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
export function
|
|
59
|
+
export function resolveWindowsSelesaiCliScript(deps: SelesaiSpawnDeps = {}): string | undefined {
|
|
60
60
|
const existsSync = deps.existsSync ?? fs.existsSync;
|
|
61
61
|
const readFileSync = deps.readFileSync ?? ((filePath, encoding) => fs.readFileSync(filePath, encoding));
|
|
62
62
|
const argv1 = deps.argv1 ?? process.argv[1];
|
|
@@ -82,12 +82,12 @@ export function resolveWindowsPiCliScript(deps: PiSpawnDeps = {}): string | unde
|
|
|
82
82
|
|
|
83
83
|
try {
|
|
84
84
|
const resolvePackageJson = deps.resolvePackageJson ?? (() => {
|
|
85
|
-
const root = deps.piPackageRoot ??
|
|
85
|
+
const root = deps.piPackageRoot ?? resolveSelesaiPackageRoot();
|
|
86
86
|
if (root) return path.join(root, "package.json");
|
|
87
87
|
const packageRoot = deps.resolvePackageEntry
|
|
88
|
-
?
|
|
89
|
-
:
|
|
90
|
-
if (!packageRoot) throw new Error(`Could not resolve ${
|
|
88
|
+
? findSelesaiPackageRootFromEntry(deps.resolvePackageEntry())
|
|
89
|
+
: resolveInstalledSelesaiPackageRoot();
|
|
90
|
+
if (!packageRoot) throw new Error(`Could not resolve ${SELESAI_PACKAGE} package root`);
|
|
91
91
|
return path.join(packageRoot, "package.json");
|
|
92
92
|
});
|
|
93
93
|
const packageJsonPath = resolvePackageJson();
|
|
@@ -97,33 +97,33 @@ export function resolveWindowsPiCliScript(deps: PiSpawnDeps = {}): string | unde
|
|
|
97
97
|
const binField = packageJson.bin;
|
|
98
98
|
const binPath = typeof binField === "string"
|
|
99
99
|
? binField
|
|
100
|
-
: binField?.
|
|
100
|
+
: binField?.selesai ?? Object.values(binField ?? {})[0];
|
|
101
101
|
if (!binPath) return undefined;
|
|
102
102
|
const candidate = path.resolve(path.dirname(packageJsonPath), binPath);
|
|
103
103
|
if (isRunnableNodeScript(candidate, existsSync)) {
|
|
104
104
|
return candidate;
|
|
105
105
|
}
|
|
106
106
|
} catch {
|
|
107
|
-
// Windows CLI resolution is optional; falling back to `
|
|
107
|
+
// Windows CLI resolution is optional; falling back to `selesai` lets PATH handle execution.
|
|
108
108
|
return undefined;
|
|
109
109
|
}
|
|
110
110
|
|
|
111
111
|
return undefined;
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
-
export function
|
|
114
|
+
export function getSelesaiSpawnCommand(args: string[], deps: SelesaiSpawnDeps = {}): SelesaiSpawnCommand {
|
|
115
115
|
// On all platforms, prefer the running CLI script (process.argv[1]) so a
|
|
116
116
|
// renamed fork like "selesai" spawns its own binary instead of the upstream
|
|
117
|
-
// "
|
|
118
|
-
const
|
|
119
|
-
if (
|
|
117
|
+
// "selesai" from PATH (which has a different agent dir / providers / auth).
|
|
118
|
+
const selesaiCliPath = resolveWindowsSelesaiCliScript(deps);
|
|
119
|
+
if (selesaiCliPath) {
|
|
120
120
|
return {
|
|
121
121
|
command: deps.execPath ?? process.execPath,
|
|
122
|
-
args: [
|
|
122
|
+
args: [selesaiCliPath, ...args],
|
|
123
123
|
};
|
|
124
124
|
}
|
|
125
125
|
|
|
126
126
|
// Fall back to the upstream binary name only if the CLI script could not be
|
|
127
|
-
// resolved. "
|
|
128
|
-
return { command: "
|
|
129
|
-
}
|
|
127
|
+
// resolved. "selesai" is the default for selesai installs.
|
|
128
|
+
return { command: "selesai", args };
|
|
129
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { performance } from "node:perf_hooks";
|
|
4
|
+
import { appendJsonl } from "../../shared/artifacts.ts";
|
|
5
|
+
|
|
6
|
+
export type SpawnTimingMarker =
|
|
7
|
+
| "spawn_start"
|
|
8
|
+
| "spawn_command_resolved"
|
|
9
|
+
| "child_first_event"
|
|
10
|
+
| "child_first_jsonl_event";
|
|
11
|
+
|
|
12
|
+
export interface SpawnTimingMarkers {
|
|
13
|
+
spawnStart: number;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function createSpawnTimingMarkers(): SpawnTimingMarkers {
|
|
17
|
+
return { spawnStart: performance.now() };
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function emitSpawnTiming(options: {
|
|
21
|
+
eventsPath: string | undefined;
|
|
22
|
+
marker: SpawnTimingMarker;
|
|
23
|
+
markers: SpawnTimingMarkers;
|
|
24
|
+
runId?: string;
|
|
25
|
+
stepIndex?: number;
|
|
26
|
+
agent?: string;
|
|
27
|
+
}): void {
|
|
28
|
+
if (!options.eventsPath) return;
|
|
29
|
+
try {
|
|
30
|
+
fs.mkdirSync(path.dirname(options.eventsPath), { recursive: true });
|
|
31
|
+
appendJsonl(
|
|
32
|
+
options.eventsPath,
|
|
33
|
+
JSON.stringify({
|
|
34
|
+
type: "subagent.spawn.timing",
|
|
35
|
+
ts: Date.now(),
|
|
36
|
+
runId: options.runId ?? "",
|
|
37
|
+
stepIndex: options.stepIndex ?? 0,
|
|
38
|
+
agent: options.agent ?? "runner",
|
|
39
|
+
marker: options.marker,
|
|
40
|
+
elapsedMs: Math.round(performance.now() - options.markers.spawnStart),
|
|
41
|
+
}),
|
|
42
|
+
);
|
|
43
|
+
} catch {
|
|
44
|
+
// Timing diagnostics must never fail the run.
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -4,8 +4,8 @@ import * as path from "node:path";
|
|
|
4
4
|
import { Compile } from "typebox/compile";
|
|
5
5
|
import type { JsonSchemaObject } from "../../shared/types.ts";
|
|
6
6
|
|
|
7
|
-
export const STRUCTURED_OUTPUT_SCHEMA_ENV = "
|
|
8
|
-
export const STRUCTURED_OUTPUT_CAPTURE_ENV = "
|
|
7
|
+
export const STRUCTURED_OUTPUT_SCHEMA_ENV = "SELESAI_SUBAGENT_STRUCTURED_OUTPUT_SCHEMA";
|
|
8
|
+
export const STRUCTURED_OUTPUT_CAPTURE_ENV = "SELESAI_SUBAGENT_STRUCTURED_OUTPUT_CAPTURE";
|
|
9
9
|
|
|
10
10
|
export interface StructuredOutputRuntime {
|
|
11
11
|
schema: JsonSchemaObject;
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
|
-
import type { ExtensionAPI } from "@
|
|
3
|
+
import type { ExtensionAPI } from "@selesai/code";
|
|
4
4
|
import { SUBAGENT_FANOUT_CHILD_ENV } from "./pi-args.ts";
|
|
5
5
|
import { STRUCTURED_OUTPUT_CAPTURE_ENV, STRUCTURED_OUTPUT_SCHEMA_ENV, validateStructuredOutputValue } from "./structured-output.ts";
|
|
6
6
|
import type { JsonSchemaObject } from "../../shared/types.ts";
|
|
7
7
|
|
|
8
|
-
const SUBAGENT_INHERIT_PROJECT_CONTEXT_ENV = "
|
|
9
|
-
const SUBAGENT_INHERIT_SKILLS_ENV = "
|
|
10
|
-
export const SUBAGENT_INTERCOM_SESSION_NAME_ENV = "
|
|
8
|
+
const SUBAGENT_INHERIT_PROJECT_CONTEXT_ENV = "SELESAI_SUBAGENT_INHERIT_PROJECT_CONTEXT";
|
|
9
|
+
const SUBAGENT_INHERIT_SKILLS_ENV = "SELESAI_SUBAGENT_INHERIT_SKILLS";
|
|
10
|
+
export const SUBAGENT_INTERCOM_SESSION_NAME_ENV = "SELESAI_SUBAGENT_INTERCOM_SESSION_NAME";
|
|
11
11
|
|
|
12
12
|
const STRUCTURED_OUTPUT_INSTRUCTIONS = [
|
|
13
13
|
"This subagent step has a strict structured output contract.",
|