@a5c-ai/babysitter-sdk 0.0.183-staging.dd5dc0db → 0.0.183-staging.e7446f7c
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/cli/commands/harnessInstall.d.ts +8 -0
- package/dist/cli/commands/harnessInstall.d.ts.map +1 -0
- package/dist/cli/commands/harnessInstall.js +94 -0
- package/dist/cli/commands/sessionCreate.d.ts.map +1 -1
- package/dist/cli/commands/sessionCreate.js +333 -35
- package/dist/cli/commands/sessionCreatePrompts.d.ts +37 -3
- package/dist/cli/commands/sessionCreatePrompts.d.ts.map +1 -1
- package/dist/cli/commands/sessionCreatePrompts.js +130 -6
- package/dist/cli/commands/templates/process-generation-prompt.md +8 -0
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/main.js +29 -1
- package/dist/harness/claudeCode.d.ts.map +1 -1
- package/dist/harness/claudeCode.js +112 -6
- package/dist/harness/codex.d.ts.map +1 -1
- package/dist/harness/codex.js +122 -0
- package/dist/harness/geminiCli.d.ts.map +1 -1
- package/dist/harness/geminiCli.js +30 -0
- package/dist/harness/index.d.ts +1 -1
- package/dist/harness/index.d.ts.map +1 -1
- package/dist/harness/installSupport.d.ts +34 -0
- package/dist/harness/installSupport.d.ts.map +1 -0
- package/dist/harness/installSupport.js +194 -0
- package/dist/harness/ohMyPi.d.ts.map +1 -1
- package/dist/harness/ohMyPi.js +16 -0
- package/dist/harness/pi.d.ts +5 -1
- package/dist/harness/pi.d.ts.map +1 -1
- package/dist/harness/pi.js +61 -0
- package/dist/harness/piWrapper.d.ts.map +1 -1
- package/dist/harness/piWrapper.js +49 -4
- package/dist/harness/types.d.ts +20 -1
- package/dist/harness/types.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { HarnessInstallOptions } from "../../harness";
|
|
2
|
+
export interface HarnessInstallCommandArgs extends HarnessInstallOptions {
|
|
3
|
+
harnessName?: string;
|
|
4
|
+
}
|
|
5
|
+
export declare function handleHarnessInstall(args: HarnessInstallCommandArgs): Promise<number>;
|
|
6
|
+
export declare function handleHarnessInstallPlugin(args: HarnessInstallCommandArgs): Promise<number>;
|
|
7
|
+
export declare function formatHarnessInstallError(error: unknown, json: boolean): number;
|
|
8
|
+
//# sourceMappingURL=harnessInstall.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"harnessInstall.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/harnessInstall.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAEV,qBAAqB,EAEtB,MAAM,eAAe,CAAC;AAQvB,MAAM,WAAW,yBAA0B,SAAQ,qBAAqB;IACtE,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AA0FD,wBAAsB,oBAAoB,CAAC,IAAI,EAAE,yBAAyB,GAAG,OAAO,CAAC,MAAM,CAAC,CAM3F;AAED,wBAAsB,0BAA0B,CAAC,IAAI,EAAE,yBAAyB,GAAG,OAAO,CAAC,MAAM,CAAC,CAMjG;AAED,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,GAAG,MAAM,CAW/E"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.handleHarnessInstall = handleHarnessInstall;
|
|
4
|
+
exports.handleHarnessInstallPlugin = handleHarnessInstallPlugin;
|
|
5
|
+
exports.formatHarnessInstallError = formatHarnessInstallError;
|
|
6
|
+
const harness_1 = require("../../harness");
|
|
7
|
+
const exceptions_1 = require("../../runtime/exceptions");
|
|
8
|
+
function supportsColors() {
|
|
9
|
+
if (process.env.NO_COLOR !== undefined)
|
|
10
|
+
return false;
|
|
11
|
+
if (process.env.FORCE_COLOR !== undefined)
|
|
12
|
+
return true;
|
|
13
|
+
return Boolean(process.stderr?.isTTY);
|
|
14
|
+
}
|
|
15
|
+
function formatInstallResult(payload, json) {
|
|
16
|
+
if (json) {
|
|
17
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
if (payload.warning) {
|
|
21
|
+
console.log(`Warning: ${payload.warning}`);
|
|
22
|
+
}
|
|
23
|
+
if (payload.summary) {
|
|
24
|
+
console.log(payload.summary);
|
|
25
|
+
}
|
|
26
|
+
if (payload.command) {
|
|
27
|
+
console.log(`Command: ${payload.command}`);
|
|
28
|
+
}
|
|
29
|
+
if (payload.output) {
|
|
30
|
+
console.log(payload.output);
|
|
31
|
+
}
|
|
32
|
+
if (payload.location) {
|
|
33
|
+
console.log(`Location: ${payload.location}`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function requireHarnessName(harnessName, commandName) {
|
|
37
|
+
if (!harnessName) {
|
|
38
|
+
throw new exceptions_1.BabysitterRuntimeError("MissingArgument", `${commandName} requires a harness name as the first argument`, {
|
|
39
|
+
category: exceptions_1.ErrorCategory.Validation,
|
|
40
|
+
suggestions: [`babysitter ${commandName} codex`],
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
return harnessName;
|
|
44
|
+
}
|
|
45
|
+
function requireInstallMethod(harnessName, commandName, kind) {
|
|
46
|
+
const adapter = (0, harness_1.getAdapterByName)(harnessName);
|
|
47
|
+
if (!adapter) {
|
|
48
|
+
throw new exceptions_1.BabysitterRuntimeError("UnsupportedHarnessInstall", `${commandName} does not support "${harnessName}" yet.`, {
|
|
49
|
+
category: exceptions_1.ErrorCategory.Validation,
|
|
50
|
+
suggestions: [
|
|
51
|
+
"Supported harnesses: claude-code, codex, gemini-cli, pi, oh-my-pi",
|
|
52
|
+
],
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
const run = adapter[kind];
|
|
56
|
+
if (!run) {
|
|
57
|
+
throw new exceptions_1.BabysitterRuntimeError("UnsupportedHarnessInstall", `${commandName} does not support "${harnessName}" yet.`, {
|
|
58
|
+
category: exceptions_1.ErrorCategory.Validation,
|
|
59
|
+
suggestions: [
|
|
60
|
+
"Supported harnesses: claude-code, codex, gemini-cli, pi, oh-my-pi",
|
|
61
|
+
],
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
return {
|
|
65
|
+
adapter,
|
|
66
|
+
run: run.bind(adapter),
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
async function handleHarnessInstall(args) {
|
|
70
|
+
const harnessName = requireHarnessName(args.harnessName, "harness:install");
|
|
71
|
+
const { run } = requireInstallMethod(harnessName, "harness:install", "installHarness");
|
|
72
|
+
const result = await run(args);
|
|
73
|
+
formatInstallResult(result, args.json);
|
|
74
|
+
return 0;
|
|
75
|
+
}
|
|
76
|
+
async function handleHarnessInstallPlugin(args) {
|
|
77
|
+
const harnessName = requireHarnessName(args.harnessName, "harness:install-plugin");
|
|
78
|
+
const { run } = requireInstallMethod(harnessName, "harness:install-plugin", "installPlugin");
|
|
79
|
+
const result = await run(args);
|
|
80
|
+
formatInstallResult(result, args.json);
|
|
81
|
+
return 0;
|
|
82
|
+
}
|
|
83
|
+
function formatHarnessInstallError(error, json) {
|
|
84
|
+
const err = error instanceof Error
|
|
85
|
+
? error
|
|
86
|
+
: new Error(String(error));
|
|
87
|
+
if (json) {
|
|
88
|
+
console.error(JSON.stringify((0, exceptions_1.toStructuredError)(err), null, 2));
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
console.error((0, exceptions_1.formatErrorWithContext)(err, { colors: supportsColors() }));
|
|
92
|
+
}
|
|
93
|
+
return 1;
|
|
94
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sessionCreate.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/sessionCreate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAWH,OAAO,KAAK,EACV,sBAAsB,
|
|
1
|
+
{"version":3,"file":"sessionCreate.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/sessionCreate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAWH,OAAO,KAAK,EACV,sBAAsB,EAIvB,MAAM,qBAAqB,CAAC;AA0B7B,MAAM,WAAW,iBAAiB;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AA+ID,wBAAgB,aAAa,CAC3B,UAAU,EAAE,sBAAsB,EAAE,EACpC,SAAS,CAAC,EAAE,MAAM,GACjB,sBAAsB,GAAG,SAAS,CAYpC;AA2hDD,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,iBAAiB,GACxB,OAAO,CAAC,MAAM,CAAC,CAiFjB"}
|
|
@@ -91,6 +91,38 @@ function compressInternalHarnessPrompt(text, compressionConfig, taskKind = "agen
|
|
|
91
91
|
const targetReduction = layer.perTaskKind?.[taskKind] ?? layer.targetReduction;
|
|
92
92
|
return (0, density_filter_1.densityFilterText)(text, targetReduction);
|
|
93
93
|
}
|
|
94
|
+
function buildPromptContext(args) {
|
|
95
|
+
const envNames = [
|
|
96
|
+
"CI",
|
|
97
|
+
"BABYSITTER_COMPRESSION_ENABLED",
|
|
98
|
+
"BABYSITTER_PI_SANDBOX_IMAGE",
|
|
99
|
+
"AZURE_OPENAI_API_KEY",
|
|
100
|
+
"AZURE_OPENAI_PROJECT_NAME",
|
|
101
|
+
"AZURE_OPENAI_DEPLOYMENT",
|
|
102
|
+
"OPENAI_API_KEY",
|
|
103
|
+
"ANTHROPIC_API_KEY",
|
|
104
|
+
];
|
|
105
|
+
return {
|
|
106
|
+
platform: process.platform,
|
|
107
|
+
arch: process.arch,
|
|
108
|
+
nodeVersion: process.version,
|
|
109
|
+
cwd: process.cwd(),
|
|
110
|
+
workspace: path.resolve(args.workspace ?? process.cwd()),
|
|
111
|
+
selectedHarnessName: args.selectedHarnessName,
|
|
112
|
+
discoveredHarnesses: args.discovered,
|
|
113
|
+
compressionEnabled: Boolean(args.compressionConfig?.enabled &&
|
|
114
|
+
args.compressionConfig.layers.sdkContextHook.enabled),
|
|
115
|
+
secureSandboxImage: process.env.BABYSITTER_PI_SANDBOX_IMAGE || "node:22-bookworm",
|
|
116
|
+
piDefaultBashSandbox: "local",
|
|
117
|
+
piIsolationDefault: false,
|
|
118
|
+
envFlags: envNames.map((name) => ({
|
|
119
|
+
name,
|
|
120
|
+
value: process.env[name]
|
|
121
|
+
? (name.endsWith("_API_KEY") ? "set" : process.env[name])
|
|
122
|
+
: "unset",
|
|
123
|
+
})),
|
|
124
|
+
};
|
|
125
|
+
}
|
|
94
126
|
const HARNESS_PRIORITY = [
|
|
95
127
|
"pi",
|
|
96
128
|
"oh-my-pi",
|
|
@@ -134,6 +166,66 @@ function buildMetaPrompt(userPrompt, workDir) {
|
|
|
134
166
|
template = template.replace("{{INTERVIEW_CONTEXT}}", "");
|
|
135
167
|
return template;
|
|
136
168
|
}
|
|
169
|
+
function buildFallbackProcessDefinitionSource(userPrompt) {
|
|
170
|
+
const serializedPrompt = JSON.stringify(userPrompt);
|
|
171
|
+
return `import { defineTask } from "@a5c-ai/babysitter-sdk";
|
|
172
|
+
|
|
173
|
+
const implementRequest = defineTask("implement-request", (args) => ({
|
|
174
|
+
kind: "agent",
|
|
175
|
+
title: "Implement the requested work",
|
|
176
|
+
agent: {
|
|
177
|
+
prompt: {
|
|
178
|
+
role: "delivery engineer",
|
|
179
|
+
task: "Implement the user's request in the current workspace.",
|
|
180
|
+
context: {
|
|
181
|
+
request: args.request,
|
|
182
|
+
},
|
|
183
|
+
instructions: [
|
|
184
|
+
"Create or update the necessary project files in the current workspace.",
|
|
185
|
+
"Keep the implementation as small and direct as possible while still satisfying the request.",
|
|
186
|
+
"Run lightweight verification where practical and include what you verified in the result.",
|
|
187
|
+
"Return JSON with summary, changedFiles, and verificationNotes."
|
|
188
|
+
],
|
|
189
|
+
outputFormat: "JSON with summary, changedFiles, verificationNotes"
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}));
|
|
193
|
+
|
|
194
|
+
const verifyRequest = defineTask("verify-request", (args) => ({
|
|
195
|
+
kind: "agent",
|
|
196
|
+
title: "Verify the requested work",
|
|
197
|
+
agent: {
|
|
198
|
+
prompt: {
|
|
199
|
+
role: "verification engineer",
|
|
200
|
+
task: "Verify that the user's request was completed and identify any remaining gaps.",
|
|
201
|
+
context: {
|
|
202
|
+
request: args.request,
|
|
203
|
+
implementation: args.implementation
|
|
204
|
+
},
|
|
205
|
+
instructions: [
|
|
206
|
+
"Inspect the workspace state produced by the implementation step.",
|
|
207
|
+
"Confirm whether the requested work exists and is usable.",
|
|
208
|
+
"If there are remaining issues, describe them precisely.",
|
|
209
|
+
"Return JSON with success, findings, and recommendedNextSteps."
|
|
210
|
+
],
|
|
211
|
+
outputFormat: "JSON with success, findings, recommendedNextSteps"
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}));
|
|
215
|
+
|
|
216
|
+
export async function process(inputs, ctx) {
|
|
217
|
+
const request = inputs?.prompt || ${serializedPrompt};
|
|
218
|
+
const implementation = await ctx.task(implementRequest, { request });
|
|
219
|
+
const verification = await ctx.task(verifyRequest, { request, implementation });
|
|
220
|
+
return {
|
|
221
|
+
request,
|
|
222
|
+
implementation,
|
|
223
|
+
verification,
|
|
224
|
+
success: verification?.success !== false,
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
`;
|
|
228
|
+
}
|
|
137
229
|
const POLL_INTERVAL_MS = 1_000;
|
|
138
230
|
const POLL_TIMEOUT_MS = 60_000;
|
|
139
231
|
async function waitForProcessFile(filePath, timeoutMs = POLL_TIMEOUT_MS) {
|
|
@@ -258,6 +350,43 @@ function resolveTaskHarness(action, defaultHarness, discovered) {
|
|
|
258
350
|
}
|
|
259
351
|
return defaultHarness;
|
|
260
352
|
}
|
|
353
|
+
function isPiHarness(harnessName) {
|
|
354
|
+
return harnessName === "pi" || harnessName === "oh-my-pi";
|
|
355
|
+
}
|
|
356
|
+
function readBooleanMetadata(metadata, key) {
|
|
357
|
+
const value = metadata?.[key];
|
|
358
|
+
if (typeof value === "boolean") {
|
|
359
|
+
return value;
|
|
360
|
+
}
|
|
361
|
+
if (value === "true") {
|
|
362
|
+
return true;
|
|
363
|
+
}
|
|
364
|
+
if (value === "false") {
|
|
365
|
+
return false;
|
|
366
|
+
}
|
|
367
|
+
return undefined;
|
|
368
|
+
}
|
|
369
|
+
function readBashSandboxMetadata(metadata) {
|
|
370
|
+
const value = metadata?.bashSandbox;
|
|
371
|
+
return value === "auto" || value === "secure" || value === "local"
|
|
372
|
+
? value
|
|
373
|
+
: undefined;
|
|
374
|
+
}
|
|
375
|
+
function buildPiWorkerSessionOptions(args) {
|
|
376
|
+
const metadata = args.action.taskDef?.metadata;
|
|
377
|
+
const isolated = readBooleanMetadata(metadata, "isolated");
|
|
378
|
+
const enableCompaction = readBooleanMetadata(metadata, "enableCompaction");
|
|
379
|
+
const bashSandbox = readBashSandboxMetadata(metadata);
|
|
380
|
+
return {
|
|
381
|
+
workspace: args.workspace,
|
|
382
|
+
model: args.model,
|
|
383
|
+
toolsMode: "coding",
|
|
384
|
+
ephemeral: true,
|
|
385
|
+
...(isolated !== undefined ? { isolated } : {}),
|
|
386
|
+
...(enableCompaction !== undefined ? { enableCompaction } : {}),
|
|
387
|
+
...(bashSandbox ? { bashSandbox } : {}),
|
|
388
|
+
};
|
|
389
|
+
}
|
|
261
390
|
async function resolveEffect(action, harnessName, options, piSession, discovered, rl, json) {
|
|
262
391
|
const kind = action.kind;
|
|
263
392
|
if (kind === "node" || kind === "orchestrator_task") {
|
|
@@ -526,6 +655,11 @@ function emitProgress(payload, json, verbose) {
|
|
|
526
655
|
break;
|
|
527
656
|
}
|
|
528
657
|
}
|
|
658
|
+
function writeVerboseProcessDefinitionRecovery(json) {
|
|
659
|
+
if (!json) {
|
|
660
|
+
process.stderr.write(`${DIM}Phase 1 recovery: the agent did not report the process file, retrying with an explicit write-and-report instruction...${RESET}\n`);
|
|
661
|
+
}
|
|
662
|
+
}
|
|
529
663
|
async function runProcessDefinitionPhase(args) {
|
|
530
664
|
const state = {};
|
|
531
665
|
const customTools = [
|
|
@@ -568,11 +702,8 @@ async function runProcessDefinitionPhase(args) {
|
|
|
568
702
|
model: args.model,
|
|
569
703
|
toolsMode: "coding",
|
|
570
704
|
customTools,
|
|
571
|
-
appendSystemPrompt: [(0, sessionCreatePrompts_1.buildProcessDefinitionSystemPrompt)(args.outputPath)],
|
|
572
|
-
isolated: true,
|
|
705
|
+
appendSystemPrompt: [(0, sessionCreatePrompts_1.buildProcessDefinitionSystemPrompt)(args.outputPath, args.promptContext)],
|
|
573
706
|
ephemeral: true,
|
|
574
|
-
bashSandbox: "secure",
|
|
575
|
-
enableCompaction: true,
|
|
576
707
|
});
|
|
577
708
|
try {
|
|
578
709
|
await session.initialize();
|
|
@@ -596,7 +727,38 @@ async function runProcessDefinitionPhase(args) {
|
|
|
596
727
|
throw new exceptions_1.BabysitterRuntimeError("ProcessDefinitionFailed", result.output, { category: exceptions_1.ErrorCategory.External });
|
|
597
728
|
}
|
|
598
729
|
if (!state.report?.processPath) {
|
|
599
|
-
|
|
730
|
+
writeVerboseProcessDefinitionRecovery(args.json);
|
|
731
|
+
const recovery = await session.prompt(compressInternalHarnessPrompt([
|
|
732
|
+
"Recovery step:",
|
|
733
|
+
`- Write the full process file now to ${args.outputPath}`,
|
|
734
|
+
"- Then call babysitter_report_process_definition exactly once.",
|
|
735
|
+
"- Do not just describe the process in plain text.",
|
|
736
|
+
].join("\n"), args.compressionConfig, "agent"), 180_000);
|
|
737
|
+
if (!recovery.success) {
|
|
738
|
+
throw new exceptions_1.BabysitterRuntimeError("ProcessDefinitionFailed", recovery.output, { category: exceptions_1.ErrorCategory.External });
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
if (!state.report?.processPath) {
|
|
742
|
+
try {
|
|
743
|
+
await waitForProcessFile(args.outputPath, 5_000);
|
|
744
|
+
state.report = {
|
|
745
|
+
processPath: args.outputPath,
|
|
746
|
+
summary: "Recovered from missing process-definition tool report by using the expected output path.",
|
|
747
|
+
};
|
|
748
|
+
}
|
|
749
|
+
catch {
|
|
750
|
+
if (!args.interactive) {
|
|
751
|
+
const fallbackSource = buildFallbackProcessDefinitionSource(args.prompt);
|
|
752
|
+
await node_fs_1.promises.writeFile(args.outputPath, fallbackSource, "utf8");
|
|
753
|
+
state.report = {
|
|
754
|
+
processPath: args.outputPath,
|
|
755
|
+
summary: "Recovered from phase-1 tool failure by writing a generic multi-step fallback process definition.",
|
|
756
|
+
};
|
|
757
|
+
}
|
|
758
|
+
else {
|
|
759
|
+
throw new exceptions_1.BabysitterRuntimeError("ProcessDefinitionReportMissing", "The process-definition agent finished without calling babysitter_report_process_definition.", { category: exceptions_1.ErrorCategory.Runtime });
|
|
760
|
+
}
|
|
761
|
+
}
|
|
600
762
|
}
|
|
601
763
|
await waitForProcessFile(state.report.processPath);
|
|
602
764
|
await validateProcessExport(state.report.processPath);
|
|
@@ -629,6 +791,33 @@ async function runOrchestrationPhase(args) {
|
|
|
629
791
|
pendingEffectResults: new Map(),
|
|
630
792
|
};
|
|
631
793
|
let orchestrationSession = null;
|
|
794
|
+
const writeVerbose = (message) => {
|
|
795
|
+
if (!args.json && args.verbose) {
|
|
796
|
+
process.stderr.write(`${DIM}${message}${RESET}\n`);
|
|
797
|
+
}
|
|
798
|
+
};
|
|
799
|
+
const summarizeAgentText = (text) => {
|
|
800
|
+
const normalized = text.replace(/\s+/g, " ").trim();
|
|
801
|
+
if (!normalized) {
|
|
802
|
+
return "(no summary emitted)";
|
|
803
|
+
}
|
|
804
|
+
return normalized.length > 240 ? `${normalized.slice(0, 237)}...` : normalized;
|
|
805
|
+
};
|
|
806
|
+
const describePendingActions = () => Array.from(state.pendingActions.values()).map((action) => ({
|
|
807
|
+
effectId: action.effectId,
|
|
808
|
+
kind: action.kind,
|
|
809
|
+
title: action.taskDef?.title,
|
|
810
|
+
harness: resolveTaskHarness(action, args.selectedHarnessName, args.discovered),
|
|
811
|
+
}));
|
|
812
|
+
const ensureTerminalResult = () => {
|
|
813
|
+
if (state.lastIterationResult?.status === "completed") {
|
|
814
|
+
return 0;
|
|
815
|
+
}
|
|
816
|
+
if (state.lastIterationResult?.status === "failed") {
|
|
817
|
+
return 1;
|
|
818
|
+
}
|
|
819
|
+
return null;
|
|
820
|
+
};
|
|
632
821
|
const customTools = [
|
|
633
822
|
{
|
|
634
823
|
name: "AskUserQuestion",
|
|
@@ -818,16 +1007,12 @@ async function runOrchestrationPhase(args) {
|
|
|
818
1007
|
}
|
|
819
1008
|
const taskHarness = resolveTaskHarness(action, args.selectedHarnessName, args.discovered);
|
|
820
1009
|
let workerSession = null;
|
|
821
|
-
if (action.kind === "shell" || taskHarness
|
|
822
|
-
workerSession = (0, piWrapper_1.createPiSession)({
|
|
1010
|
+
if (action.kind === "shell" || isPiHarness(taskHarness)) {
|
|
1011
|
+
workerSession = (0, piWrapper_1.createPiSession)(buildPiWorkerSessionOptions({
|
|
1012
|
+
action,
|
|
823
1013
|
workspace: args.workspace,
|
|
824
1014
|
model: args.model,
|
|
825
|
-
|
|
826
|
-
isolated: true,
|
|
827
|
-
ephemeral: true,
|
|
828
|
-
bashSandbox: "secure",
|
|
829
|
-
enableCompaction: true,
|
|
830
|
-
});
|
|
1015
|
+
}));
|
|
831
1016
|
}
|
|
832
1017
|
try {
|
|
833
1018
|
const effectResult = await resolveEffect(action, args.selectedHarnessName, {
|
|
@@ -935,22 +1120,69 @@ async function runOrchestrationPhase(args) {
|
|
|
935
1120
|
},
|
|
936
1121
|
},
|
|
937
1122
|
];
|
|
1123
|
+
const tools = customTools;
|
|
1124
|
+
const getTool = (name) => tools.find((tool) => tool.name === name);
|
|
1125
|
+
const runCreateTool = getTool("babysitter_run_create");
|
|
1126
|
+
const bindSessionTool = getTool("babysitter_bind_session");
|
|
1127
|
+
const runIterateTool = getTool("babysitter_run_iterate");
|
|
1128
|
+
const executeEffectTool = getTool("babysitter_execute_effect");
|
|
1129
|
+
const taskPostTool = getTool("babysitter_task_post_result");
|
|
1130
|
+
const finishTool = getTool("babysitter_finish_orchestration");
|
|
1131
|
+
const invokeTool = async (tool, name, params = {}) => {
|
|
1132
|
+
if (!tool?.execute) {
|
|
1133
|
+
throw new exceptions_1.BabysitterRuntimeError("MissingSessionCreateTool", `Required orchestration tool is unavailable: ${name}`, { category: exceptions_1.ErrorCategory.Internal });
|
|
1134
|
+
}
|
|
1135
|
+
const result = tool.execute(`host-${name}`, params);
|
|
1136
|
+
return await Promise.resolve(result);
|
|
1137
|
+
};
|
|
1138
|
+
const runDeterministicPendingEffects = async (reason) => {
|
|
1139
|
+
const pending = describePendingActions();
|
|
1140
|
+
if (pending.length === 0) {
|
|
1141
|
+
return;
|
|
1142
|
+
}
|
|
1143
|
+
writeVerbose(`[phase2 fallback] ${reason}`);
|
|
1144
|
+
for (const effect of pending) {
|
|
1145
|
+
writeVerbose(`[phase2 fallback] resolving ${effect.effectId} (${effect.kind}) via ${effect.harness ?? args.selectedHarnessName}`);
|
|
1146
|
+
const action = state.pendingActions.get(effect.effectId);
|
|
1147
|
+
if (!action) {
|
|
1148
|
+
continue;
|
|
1149
|
+
}
|
|
1150
|
+
if (action.kind !== "breakpoint") {
|
|
1151
|
+
await invokeTool(executeEffectTool, "babysitter_execute_effect", { effectId: effect.effectId });
|
|
1152
|
+
}
|
|
1153
|
+
await invokeTool(taskPostTool, "babysitter_task_post_result", { effectId: effect.effectId });
|
|
1154
|
+
}
|
|
1155
|
+
};
|
|
1156
|
+
const promptOrchestrationAgent = async (message, options) => {
|
|
1157
|
+
if (!orchestrationSession) {
|
|
1158
|
+
throw new exceptions_1.BabysitterRuntimeError("OrchestrationSessionMissing", "The orchestration PI session has not been created.", { category: exceptions_1.ErrorCategory.Runtime });
|
|
1159
|
+
}
|
|
1160
|
+
if (!args.json && args.verbose) {
|
|
1161
|
+
const label = options?.label ?? "phase2";
|
|
1162
|
+
process.stderr.write(`\n${DIM}[${label}] agent turn${RESET}\n`);
|
|
1163
|
+
}
|
|
1164
|
+
const result = await orchestrationSession.prompt(compressInternalHarnessPrompt(message, args.compressionConfig, "agent"), 900_000);
|
|
1165
|
+
if (!result.success) {
|
|
1166
|
+
throw new exceptions_1.BabysitterRuntimeError("OrchestrationAgentFailed", result.output, { category: exceptions_1.ErrorCategory.External });
|
|
1167
|
+
}
|
|
1168
|
+
writeVerbose(`[phase2 agent] ${summarizeAgentText(result.output)}`);
|
|
1169
|
+
if (options?.fallbackReason && state.pendingActions.size > 0) {
|
|
1170
|
+
await runDeterministicPendingEffects(options.fallbackReason);
|
|
1171
|
+
}
|
|
1172
|
+
};
|
|
938
1173
|
orchestrationSession = (0, piWrapper_1.createPiSession)({
|
|
939
1174
|
workspace: args.workspace,
|
|
940
1175
|
model: args.model,
|
|
941
1176
|
toolsMode: "readonly",
|
|
942
1177
|
customTools,
|
|
943
|
-
appendSystemPrompt: [(0, sessionCreatePrompts_1.buildOrchestrationSystemPrompt)(args.selectedHarnessName)],
|
|
944
|
-
isolated: true,
|
|
1178
|
+
appendSystemPrompt: [(0, sessionCreatePrompts_1.buildOrchestrationSystemPrompt)(args.selectedHarnessName, args.promptContext)],
|
|
945
1179
|
ephemeral: true,
|
|
946
|
-
bashSandbox: "secure",
|
|
947
|
-
enableCompaction: true,
|
|
948
1180
|
});
|
|
949
1181
|
emitProgress({ phase: "2", status: "started", harness: args.selectedHarnessName }, args.json, args.verbose);
|
|
1182
|
+
let unsubscribe = null;
|
|
950
1183
|
try {
|
|
951
1184
|
await orchestrationSession.initialize();
|
|
952
|
-
|
|
953
|
-
if (!args.json) {
|
|
1185
|
+
if (!args.json && args.verbose) {
|
|
954
1186
|
unsubscribe = orchestrationSession.subscribe((event) => {
|
|
955
1187
|
if (event.type === "text_delta") {
|
|
956
1188
|
const text = event.text;
|
|
@@ -959,27 +1191,79 @@ async function runOrchestrationPhase(args) {
|
|
|
959
1191
|
}
|
|
960
1192
|
});
|
|
961
1193
|
}
|
|
962
|
-
|
|
963
|
-
if (
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
if (!
|
|
968
|
-
|
|
1194
|
+
await promptOrchestrationAgent((0, sessionCreatePrompts_1.buildOrchestrationBootstrapPrompt)(path.resolve(args.processPath), args.prompt, args.maxIterations), { label: "phase2 bootstrap" });
|
|
1195
|
+
if (!state.runId || !state.runDir) {
|
|
1196
|
+
writeVerbose("[phase2 fallback] agent did not create a run; creating it in the host");
|
|
1197
|
+
await invokeTool(runCreateTool, "babysitter_run_create", args.prompt ? { prompt: args.prompt } : {});
|
|
1198
|
+
}
|
|
1199
|
+
if (!state.sessionBound) {
|
|
1200
|
+
writeVerbose("[phase2 fallback] agent did not bind the session; binding in the host");
|
|
1201
|
+
await invokeTool(bindSessionTool, "babysitter_bind_session");
|
|
969
1202
|
}
|
|
970
1203
|
if (!state.runId || !state.runDir) {
|
|
971
|
-
throw new exceptions_1.BabysitterRuntimeError("RunNotCreated", "The orchestration
|
|
1204
|
+
throw new exceptions_1.BabysitterRuntimeError("RunNotCreated", "The orchestration session could not establish a run after bootstrap.", { category: exceptions_1.ErrorCategory.Runtime });
|
|
972
1205
|
}
|
|
973
|
-
|
|
974
|
-
|
|
1206
|
+
while (state.iteration < args.maxIterations) {
|
|
1207
|
+
const terminal = ensureTerminalResult();
|
|
1208
|
+
if (terminal !== null) {
|
|
1209
|
+
break;
|
|
1210
|
+
}
|
|
1211
|
+
const iterationBeforeTurn = state.iteration;
|
|
1212
|
+
await promptOrchestrationAgent((0, sessionCreatePrompts_1.buildOrchestrationTurnPrompt)({
|
|
1213
|
+
processPath: path.resolve(args.processPath),
|
|
1214
|
+
userPrompt: args.prompt,
|
|
1215
|
+
maxIterations: args.maxIterations,
|
|
1216
|
+
currentIteration: state.iteration,
|
|
1217
|
+
runId: state.runId,
|
|
1218
|
+
runDir: state.runDir,
|
|
1219
|
+
lastStatus: state.lastIterationResult?.status,
|
|
1220
|
+
pendingEffects: describePendingActions(),
|
|
1221
|
+
}), {
|
|
1222
|
+
label: `phase2 iteration ${state.iteration + 1}`,
|
|
1223
|
+
fallbackReason: "Agent left pending effects unresolved; the host resolved and posted them to keep the orchestration loop moving.",
|
|
1224
|
+
});
|
|
1225
|
+
if (ensureTerminalResult() !== null) {
|
|
1226
|
+
break;
|
|
1227
|
+
}
|
|
1228
|
+
if (state.iteration === iterationBeforeTurn && state.pendingActions.size === 0) {
|
|
1229
|
+
writeVerbose("[phase2 fallback] agent did not advance the run; executing one iteration in the host");
|
|
1230
|
+
await invokeTool(runIterateTool, "babysitter_run_iterate");
|
|
1231
|
+
}
|
|
1232
|
+
if (state.lastIterationResult?.status === "waiting" && state.pendingActions.size > 0) {
|
|
1233
|
+
await runDeterministicPendingEffects("Agent left pending effects unresolved after the turn; the host completed them deterministically.");
|
|
1234
|
+
}
|
|
1235
|
+
const postTurnTerminal = ensureTerminalResult();
|
|
1236
|
+
if (postTurnTerminal !== null) {
|
|
1237
|
+
break;
|
|
1238
|
+
}
|
|
975
1239
|
}
|
|
976
|
-
if (state.lastIterationResult?.status
|
|
977
|
-
|
|
1240
|
+
if (state.lastIterationResult?.status !== "completed" && state.lastIterationResult?.status !== "failed") {
|
|
1241
|
+
state.lastIterationResult = {
|
|
1242
|
+
status: "failed",
|
|
1243
|
+
error: { message: `Max iterations (${args.maxIterations}) reached without completion` },
|
|
1244
|
+
};
|
|
1245
|
+
emitProgress({
|
|
1246
|
+
phase: "2",
|
|
1247
|
+
status: "failed",
|
|
1248
|
+
runId: state.runId,
|
|
1249
|
+
runDir: state.runDir,
|
|
1250
|
+
iteration: state.iteration,
|
|
1251
|
+
runStatus: "failed",
|
|
1252
|
+
error: `Max iterations (${args.maxIterations}) reached without completion`,
|
|
1253
|
+
}, args.json, args.verbose);
|
|
978
1254
|
}
|
|
979
|
-
if (state.lastIterationResult?.status === "failed") {
|
|
980
|
-
|
|
1255
|
+
if (state.lastIterationResult?.status === "completed" || state.lastIterationResult?.status === "failed") {
|
|
1256
|
+
await invokeTool(finishTool, "babysitter_finish_orchestration", {
|
|
1257
|
+
summary: state.lastIterationResult.status === "completed"
|
|
1258
|
+
? `Run ${state.runId} completed after ${state.iteration} iterations.`
|
|
1259
|
+
: `Run ${state.runId} failed after ${state.iteration} iterations.`,
|
|
1260
|
+
});
|
|
981
1261
|
}
|
|
982
|
-
|
|
1262
|
+
const exitCode = ensureTerminalResult();
|
|
1263
|
+
if (exitCode !== null) {
|
|
1264
|
+
return exitCode;
|
|
1265
|
+
}
|
|
1266
|
+
throw new exceptions_1.BabysitterRuntimeError("OrchestrationIncomplete", "The orchestration phase ended without a terminal run state.", { category: exceptions_1.ErrorCategory.Runtime });
|
|
983
1267
|
}
|
|
984
1268
|
catch (error) {
|
|
985
1269
|
emitProgress({
|
|
@@ -993,6 +1277,10 @@ async function runOrchestrationPhase(args) {
|
|
|
993
1277
|
return 1;
|
|
994
1278
|
}
|
|
995
1279
|
finally {
|
|
1280
|
+
if (unsubscribe)
|
|
1281
|
+
unsubscribe();
|
|
1282
|
+
if (!args.json && args.verbose)
|
|
1283
|
+
process.stderr.write("\n");
|
|
996
1284
|
orchestrationSession?.dispose();
|
|
997
1285
|
}
|
|
998
1286
|
}
|
|
@@ -1013,8 +1301,16 @@ async function handleSessionCreate(parsed) {
|
|
|
1013
1301
|
}
|
|
1014
1302
|
const discovered = await (0, discovery_1.discoverHarnesses)();
|
|
1015
1303
|
const selected = selectHarness(discovered, preferredHarness);
|
|
1016
|
-
const selectedHarnessName =
|
|
1304
|
+
const selectedHarnessName = preferredHarness === "pi" || preferredHarness === "oh-my-pi"
|
|
1305
|
+
? preferredHarness
|
|
1306
|
+
: (selected?.name ?? "pi");
|
|
1017
1307
|
const compressionConfig = loadSessionCompressionConfig(workspace);
|
|
1308
|
+
const promptContext = buildPromptContext({
|
|
1309
|
+
workspace,
|
|
1310
|
+
selectedHarnessName,
|
|
1311
|
+
discovered,
|
|
1312
|
+
compressionConfig,
|
|
1313
|
+
});
|
|
1018
1314
|
let processPath = providedProcessPath;
|
|
1019
1315
|
if (processPath) {
|
|
1020
1316
|
emitProgress({ phase: "1", status: "skipped", processPath }, json, verbose);
|
|
@@ -1031,6 +1327,7 @@ async function handleSessionCreate(parsed) {
|
|
|
1031
1327
|
json,
|
|
1032
1328
|
verbose,
|
|
1033
1329
|
compressionConfig,
|
|
1330
|
+
promptContext,
|
|
1034
1331
|
});
|
|
1035
1332
|
}
|
|
1036
1333
|
return await runOrchestrationPhase({
|
|
@@ -1047,6 +1344,7 @@ async function handleSessionCreate(parsed) {
|
|
|
1047
1344
|
selectedHarnessName,
|
|
1048
1345
|
discovered,
|
|
1049
1346
|
compressionConfig,
|
|
1347
|
+
promptContext,
|
|
1050
1348
|
});
|
|
1051
1349
|
}
|
|
1052
1350
|
finally {
|
|
@@ -1,5 +1,39 @@
|
|
|
1
|
-
|
|
1
|
+
import type { HarnessDiscoveryResult } from "../../harness/types";
|
|
2
|
+
export interface SessionCreatePromptContext {
|
|
3
|
+
platform: string;
|
|
4
|
+
arch: string;
|
|
5
|
+
nodeVersion: string;
|
|
6
|
+
cwd: string;
|
|
7
|
+
workspace: string;
|
|
8
|
+
selectedHarnessName?: string;
|
|
9
|
+
discoveredHarnesses: HarnessDiscoveryResult[];
|
|
10
|
+
compressionEnabled: boolean;
|
|
11
|
+
secureSandboxImage: string;
|
|
12
|
+
piDefaultBashSandbox: "local" | "auto" | "secure";
|
|
13
|
+
piIsolationDefault: boolean;
|
|
14
|
+
envFlags: Array<{
|
|
15
|
+
name: string;
|
|
16
|
+
value: string;
|
|
17
|
+
}>;
|
|
18
|
+
}
|
|
19
|
+
export declare function buildProcessDefinitionSystemPrompt(outputPath: string, context: SessionCreatePromptContext): string;
|
|
2
20
|
export declare function buildProcessDefinitionUserPrompt(userPrompt: string, outputPath: string): string;
|
|
3
|
-
export declare function buildOrchestrationSystemPrompt(selectedHarnessName: string): string;
|
|
4
|
-
export declare function
|
|
21
|
+
export declare function buildOrchestrationSystemPrompt(selectedHarnessName: string, context: SessionCreatePromptContext): string;
|
|
22
|
+
export declare function buildOrchestrationBootstrapPrompt(processPath: string, userPrompt: string | undefined, maxIterations: number): string;
|
|
23
|
+
export declare function buildOrchestrationTurnPrompt(args: {
|
|
24
|
+
processPath: string;
|
|
25
|
+
userPrompt?: string;
|
|
26
|
+
maxIterations: number;
|
|
27
|
+
currentIteration: number;
|
|
28
|
+
runId?: string;
|
|
29
|
+
runDir?: string;
|
|
30
|
+
lastStatus?: string;
|
|
31
|
+
pendingEffects?: Array<{
|
|
32
|
+
effectId: string;
|
|
33
|
+
kind: string;
|
|
34
|
+
title?: string;
|
|
35
|
+
harness?: string;
|
|
36
|
+
}>;
|
|
37
|
+
fallbackReason?: string;
|
|
38
|
+
}): string;
|
|
5
39
|
//# sourceMappingURL=sessionCreatePrompts.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sessionCreatePrompts.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/sessionCreatePrompts.ts"],"names":[],"mappings":"AAAA,wBAAgB,kCAAkC,
|
|
1
|
+
{"version":3,"file":"sessionCreatePrompts.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/sessionCreatePrompts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAElE,MAAM,WAAW,0BAA0B;IACzC,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,mBAAmB,EAAE,sBAAsB,EAAE,CAAC;IAC9C,kBAAkB,EAAE,OAAO,CAAC;IAC5B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,oBAAoB,EAAE,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAC;IAClD,kBAAkB,EAAE,OAAO,CAAC;IAC5B,QAAQ,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAClD;AA+ED,wBAAgB,kCAAkC,CAChD,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,0BAA0B,GAClC,MAAM,CAkBR;AAED,wBAAgB,gCAAgC,CAC9C,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,GACjB,MAAM,CAOR;AAED,wBAAgB,8BAA8B,CAC5C,mBAAmB,EAAE,MAAM,EAC3B,OAAO,EAAE,0BAA0B,GAClC,MAAM,CAuBR;AAED,wBAAgB,iCAAiC,CAC/C,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,aAAa,EAAE,MAAM,GACpB,MAAM,CAWR;AAED,wBAAgB,4BAA4B,CAAC,IAAI,EAAE;IACjD,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,gBAAgB,EAAE,MAAM,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,KAAK,CAAC;QACrB,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC,CAAC;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,GAAG,MAAM,CA2CT"}
|