@mobrienv/autoloop-harness 0.7.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.
Files changed (70) hide show
  1. package/dist/artifacts.d.ts +50 -0
  2. package/dist/artifacts.js +333 -0
  3. package/dist/artifacts.js.map +1 -0
  4. package/dist/config-helpers.d.ts +36 -0
  5. package/dist/config-helpers.js +427 -0
  6. package/dist/config-helpers.js.map +1 -0
  7. package/dist/coordination.d.ts +1 -0
  8. package/dist/coordination.js +126 -0
  9. package/dist/coordination.js.map +1 -0
  10. package/dist/display.d.ts +21 -0
  11. package/dist/display.js +177 -0
  12. package/dist/display.js.map +1 -0
  13. package/dist/emit.d.ts +21 -0
  14. package/dist/emit.js +243 -0
  15. package/dist/emit.js.map +1 -0
  16. package/dist/events.d.ts +56 -0
  17. package/dist/events.js +9 -0
  18. package/dist/events.js.map +1 -0
  19. package/dist/index.d.ts +6 -0
  20. package/dist/index.js +272 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/iteration.d.ts +16 -0
  23. package/dist/iteration.js +153 -0
  24. package/dist/iteration.js.map +1 -0
  25. package/dist/metareview.d.ts +6 -0
  26. package/dist/metareview.js +104 -0
  27. package/dist/metareview.js.map +1 -0
  28. package/dist/metrics.d.ts +12 -0
  29. package/dist/metrics.js +177 -0
  30. package/dist/metrics.js.map +1 -0
  31. package/dist/parallel.d.ts +37 -0
  32. package/dist/parallel.js +242 -0
  33. package/dist/parallel.js.map +1 -0
  34. package/dist/pi-adapter.d.ts +1 -0
  35. package/dist/pi-adapter.js +220 -0
  36. package/dist/pi-adapter.js.map +1 -0
  37. package/dist/prompt.d.ts +46 -0
  38. package/dist/prompt.js +446 -0
  39. package/dist/prompt.js.map +1 -0
  40. package/dist/registry-bridge.d.ts +7 -0
  41. package/dist/registry-bridge.js +63 -0
  42. package/dist/registry-bridge.js.map +1 -0
  43. package/dist/scratchpad.d.ts +2 -0
  44. package/dist/scratchpad.js +65 -0
  45. package/dist/scratchpad.js.map +1 -0
  46. package/dist/stop.d.ts +5 -0
  47. package/dist/stop.js +81 -0
  48. package/dist/stop.js.map +1 -0
  49. package/dist/tools.d.ts +3 -0
  50. package/dist/tools.js +65 -0
  51. package/dist/tools.js.map +1 -0
  52. package/dist/types.d.ts +137 -0
  53. package/dist/types.js +2 -0
  54. package/dist/types.js.map +1 -0
  55. package/dist/wave/finalize-wave.d.ts +9 -0
  56. package/dist/wave/finalize-wave.js +86 -0
  57. package/dist/wave/finalize-wave.js.map +1 -0
  58. package/dist/wave/launch-branches.d.ts +6 -0
  59. package/dist/wave/launch-branches.js +313 -0
  60. package/dist/wave/launch-branches.js.map +1 -0
  61. package/dist/wave/parse-objectives.d.ts +3 -0
  62. package/dist/wave/parse-objectives.js +32 -0
  63. package/dist/wave/parse-objectives.js.map +1 -0
  64. package/dist/wave/types.d.ts +43 -0
  65. package/dist/wave/types.js +2 -0
  66. package/dist/wave/types.js.map +1 -0
  67. package/dist/wave.d.ts +6 -0
  68. package/dist/wave.js +158 -0
  69. package/dist/wave.js.map +1 -0
  70. package/package.json +100 -0
@@ -0,0 +1,220 @@
1
+ import { execSync } from "node:child_process";
2
+ import { existsSync, readFileSync, writeFileSync } from "node:fs";
3
+ import { shellWords } from "@mobrienv/autoloop-core";
4
+ const BRIDGE_SCRIPT = `
5
+ import json
6
+ import os
7
+ import pathlib
8
+ import subprocess
9
+ import sys
10
+
11
+
12
+ def extract_text_from_message(message):
13
+ text_parts = []
14
+ for item in message.get("content") or []:
15
+ if item.get("type") == "text":
16
+ text_parts.append(item.get("text", ""))
17
+ return "".join(text_parts)
18
+
19
+
20
+ def extract_text_from_messages(messages):
21
+ if not messages:
22
+ return ""
23
+ return extract_text_from_message(messages[-1] or {})
24
+
25
+
26
+ def extract_tool_error(response):
27
+ for item in response.get("output") or []:
28
+ if item.get("type") == "text":
29
+ text = item.get("text", "")
30
+ if text:
31
+ return text
32
+ return ""
33
+
34
+
35
+ def stream_log_path():
36
+ state_dir = os.environ.get("AUTOLOOP_STATE_DIR", "")
37
+ if not state_dir:
38
+ return None
39
+ prefix = "pi-review" if os.environ.get("AUTOLOOP_REVIEW_MODE", "") == "hyperagent" else "pi-stream"
40
+ iteration = os.environ.get("AUTOLOOP_ITERATION", "")
41
+ name = prefix + (("." + iteration) if iteration else "") + ".jsonl"
42
+ return pathlib.Path(state_dir) / name
43
+
44
+
45
+ cmd = sys.argv[1:-1]
46
+ prompt_path = sys.argv[-1]
47
+ raw_output = ""
48
+ exit_code = 1
49
+
50
+ try:
51
+ with open(prompt_path, "r", encoding="utf-8") as prompt_file:
52
+ completed = subprocess.run(cmd, stdin=prompt_file, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, encoding="utf-8", errors="replace")
53
+ raw_output = completed.stdout or ""
54
+ exit_code = completed.returncode
55
+ except FileNotFoundError as exc:
56
+ raw_output = str(exc)
57
+ exit_code = 127
58
+
59
+ log_path = stream_log_path()
60
+ if log_path is not None:
61
+ log_path.parent.mkdir(parents=True, exist_ok=True)
62
+ log_path.write_text(raw_output)
63
+
64
+ text_parts = []
65
+ fallback_text = ""
66
+ saw_turn_end = False
67
+ saw_agent_end = False
68
+ error = ""
69
+
70
+ for raw_line in raw_output.splitlines():
71
+ line = raw_line.strip()
72
+ if not line:
73
+ continue
74
+
75
+ try:
76
+ event = json.loads(line)
77
+ except Exception:
78
+ continue
79
+
80
+ event_type = event.get("type")
81
+
82
+ if event_type == "message_update":
83
+ assistant_event = event.get("assistantMessageEvent") or {}
84
+ assistant_type = assistant_event.get("type")
85
+ if assistant_type == "text_delta":
86
+ text_parts.append(assistant_event.get("delta", ""))
87
+ elif assistant_type == "error" and assistant_event.get("reason"):
88
+ error = assistant_event.get("reason")
89
+ elif event_type == "tool_execution_end":
90
+ response = event.get("toolExecutionResponseEvent") or {}
91
+ if response.get("isError"):
92
+ detail = extract_tool_error(response)
93
+ if detail:
94
+ error = detail
95
+ elif event_type == "turn_end":
96
+ saw_turn_end = True
97
+ if not fallback_text:
98
+ fallback_text = extract_text_from_message(event.get("message") or {})
99
+ elif event_type == "agent_end":
100
+ saw_agent_end = True
101
+ if not fallback_text:
102
+ fallback_text = extract_text_from_messages(event.get("messages") or [])
103
+
104
+ text = "".join(text_parts)
105
+ if not text:
106
+ text = fallback_text
107
+
108
+ failed = exit_code != 0 or (not saw_turn_end and not saw_agent_end) or bool(error)
109
+ verbose = os.environ.get("AUTOLOOP_LOG_LEVEL", "") == "debug"
110
+ output = ""
111
+
112
+ if failed:
113
+ if verbose:
114
+ if text and error:
115
+ output = text + "\\n\\npi error: " + error
116
+ elif text:
117
+ output = text
118
+ else:
119
+ output = raw_output or error
120
+ else:
121
+ if text:
122
+ output = text
123
+ elif error:
124
+ output = "pi failed (run with -v for details)"
125
+ else:
126
+ output = raw_output or "pi failed"
127
+ else:
128
+ output = text
129
+
130
+ if output:
131
+ sys.stdout.write(output)
132
+
133
+ sys.exit(1 if failed else 0)
134
+ `;
135
+ export function run(args) {
136
+ const prompt = resolvePrompt();
137
+ if (!prompt) {
138
+ finishFailure("missing projected prompt");
139
+ return;
140
+ }
141
+ const promptPath = materializePromptPath(prompt);
142
+ const piCommand = args[0] || "pi";
143
+ const piArgs = args.slice(1);
144
+ const command = buildPiBridgeCommand(piCommand, piArgs, promptPath);
145
+ try {
146
+ const output = execSync(command, {
147
+ encoding: "utf-8",
148
+ stdio: ["pipe", "pipe", "pipe"],
149
+ shell: "/bin/sh",
150
+ maxBuffer: 100 * 1024 * 1024,
151
+ });
152
+ finishSuccess(output || "");
153
+ }
154
+ catch (err) {
155
+ const e = err;
156
+ finishFailure(e.stdout || e.stderr || "");
157
+ }
158
+ }
159
+ function resolvePrompt() {
160
+ const envPrompt = process.env.AUTOLOOP_PROMPT;
161
+ if (envPrompt)
162
+ return envPrompt;
163
+ const pathPrompt = promptFromPath();
164
+ if (pathPrompt)
165
+ return pathPrompt;
166
+ return projectedPrompt();
167
+ }
168
+ function projectedPrompt() {
169
+ const bin = process.env.AUTOLOOP_BIN || "";
170
+ const iteration = process.env.AUTOLOOP_ITERATION || "";
171
+ if (!bin || !iteration)
172
+ return "";
173
+ try {
174
+ const output = execSync(shellWords([bin, "inspect", "prompt", iteration, "--format", "md"]), { encoding: "utf-8", shell: "/bin/sh", timeout: 30000 });
175
+ return output || "";
176
+ }
177
+ catch {
178
+ return "";
179
+ }
180
+ }
181
+ function promptFromPath() {
182
+ const path = process.env.AUTOLOOP_PROMPT_PATH || "";
183
+ if (!path || !existsSync(path))
184
+ return "";
185
+ return readFileSync(path, "utf-8");
186
+ }
187
+ function buildPiBridgeCommand(command, extraArgs, promptPath) {
188
+ return shellWords([
189
+ "python3",
190
+ "-c",
191
+ BRIDGE_SCRIPT,
192
+ command,
193
+ ...defaultPiArgs(),
194
+ ...extraArgs,
195
+ promptPath,
196
+ ]);
197
+ }
198
+ function materializePromptPath(prompt) {
199
+ const path = promptStoragePath();
200
+ writeFileSync(path, prompt, "utf-8");
201
+ return path;
202
+ }
203
+ function promptStoragePath() {
204
+ const configured = process.env.AUTOLOOP_PROMPT_PATH || "";
205
+ return configured || "/tmp/autoloop-pi-adapter-prompt.md";
206
+ }
207
+ function defaultPiArgs() {
208
+ return ["-p", "--mode", "json", "--no-session"];
209
+ }
210
+ function finishSuccess(output) {
211
+ if (output)
212
+ process.stdout.write(output);
213
+ process.exitCode = 0;
214
+ }
215
+ function finishFailure(output) {
216
+ if (output)
217
+ process.stdout.write(output);
218
+ process.exitCode = 1;
219
+ }
220
+ //# sourceMappingURL=pi-adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pi-adapter.js","sourceRoot":"","sources":["../src/pi-adapter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ import type { TwoTierMemoryStats } from "@mobrienv/autoloop-core/memory-render";
2
+ import * as topology from "@mobrienv/autoloop-core/topology";
3
+ import type { LoopContext } from "./index.js";
4
+ export interface IterationContext {
5
+ iteration: number;
6
+ recentEvent: string;
7
+ allowedRoles: string[];
8
+ allowedEvents: string[];
9
+ backpressure: string;
10
+ lastRejected: string;
11
+ scratchpadText: string;
12
+ memoryText: string;
13
+ prompt: string;
14
+ roleAgent: string;
15
+ }
16
+ interface DerivedRunContext {
17
+ scratchpadText: string;
18
+ memoryText: string;
19
+ memoryStats: TwoTierMemoryStats;
20
+ tasksText: string;
21
+ tasksStats: {
22
+ open: number;
23
+ done: number;
24
+ total: number;
25
+ };
26
+ guidanceMessages: string[];
27
+ routing: RoutingContext;
28
+ backpressure: string;
29
+ invalidCount: number;
30
+ lastRejected: string;
31
+ }
32
+ export declare function buildIterationContext(loop: LoopContext, iteration: number): IterationContext;
33
+ interface RoutingContext {
34
+ recentEvent: string;
35
+ allowedRoles: string[];
36
+ allowedEvents: string[];
37
+ }
38
+ export declare function iterationRoutingContext(topo: topology.Topology, runLines: string[]): RoutingContext;
39
+ export declare function routingEventFromLines(lines: string[]): string;
40
+ export declare function latestInvalidNote(runLines: string[]): string;
41
+ export declare function invalidEventCount(runLines: string[]): number;
42
+ export declare function lastRejectedTopic(runLines: string[]): string;
43
+ export declare function renderIterationPromptText(loop: LoopContext, iteration: number, derived: DerivedRunContext): string;
44
+ export declare function renderReviewPromptText(loop: LoopContext, iteration: number, runLines: string[]): string;
45
+ export declare function drainGuidance(runLines: string[]): string[];
46
+ export {};