@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.
@@ -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,EAGvB,MAAM,qBAAqB,CAAC;AAwB7B,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;AAqGD,wBAAgB,aAAa,CAC3B,UAAU,EAAE,sBAAsB,EAAE,EACpC,SAAS,CAAC,EAAE,MAAM,GACjB,sBAAsB,GAAG,SAAS,CAYpC;AA0rCD,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,iBAAiB,GACxB,OAAO,CAAC,MAAM,CAAC,CAsEjB"}
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
- throw new exceptions_1.BabysitterRuntimeError("ProcessDefinitionReportMissing", "The process-definition agent finished without calling babysitter_report_process_definition.", { category: exceptions_1.ErrorCategory.Runtime });
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 === "pi" || taskHarness === "oh-my-pi") {
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
- toolsMode: "coding",
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
- let unsubscribe = null;
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
- const result = await orchestrationSession.prompt(compressInternalHarnessPrompt((0, sessionCreatePrompts_1.buildOrchestrationUserPrompt)(path.resolve(args.processPath), args.prompt, args.maxIterations), args.compressionConfig, "agent"), 900_000);
963
- if (unsubscribe)
964
- unsubscribe();
965
- if (!args.json)
966
- process.stderr.write("\n");
967
- if (!result.success) {
968
- throw new exceptions_1.BabysitterRuntimeError("OrchestrationAgentFailed", result.output, { category: exceptions_1.ErrorCategory.External });
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 agent exited without creating a run.", { category: exceptions_1.ErrorCategory.Runtime });
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
- if (!state.finished) {
974
- throw new exceptions_1.BabysitterRuntimeError("OrchestrationFinishMissing", "The orchestration agent exited without calling babysitter_finish_orchestration.", { category: exceptions_1.ErrorCategory.Runtime });
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 === "completed") {
977
- return 0;
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
- return 1;
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
- throw new exceptions_1.BabysitterRuntimeError("OrchestrationIncomplete", "The orchestration agent exited before the run reached a terminal state.", { category: exceptions_1.ErrorCategory.Runtime });
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 = selected?.name ?? "pi";
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
- export declare function buildProcessDefinitionSystemPrompt(outputPath: string): string;
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 buildOrchestrationUserPrompt(processPath: string, userPrompt: string | undefined, maxIterations: number): string;
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,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAe7E;AAED,wBAAgB,gCAAgC,CAC9C,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,GACjB,MAAM,CAOR;AAED,wBAAgB,8BAA8B,CAAC,mBAAmB,EAAE,MAAM,GAAG,MAAM,CAmBlF;AAED,wBAAgB,4BAA4B,CAC1C,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,aAAa,EAAE,MAAM,GACpB,MAAM,CAQR"}
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"}