specrails-core 5.4.0 → 5.5.1

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 (86) hide show
  1. package/README.md +2 -0
  2. package/dist/agent-runtime/capabilities.d.ts +3 -2
  3. package/dist/agent-runtime/capabilities.js +10 -2
  4. package/dist/agent-runtime/capabilities.js.map +1 -1
  5. package/dist/agent-runtime/cli-executor.js +10 -5
  6. package/dist/agent-runtime/cli-executor.js.map +1 -1
  7. package/dist/agent-runtime/cli-process.d.ts +1 -0
  8. package/dist/agent-runtime/cli-process.js +13 -2
  9. package/dist/agent-runtime/cli-process.js.map +1 -1
  10. package/dist/agent-runtime/cli.js +2 -1
  11. package/dist/agent-runtime/cli.js.map +1 -1
  12. package/dist/agent-runtime/compact/architect.d.ts +349 -0
  13. package/dist/agent-runtime/compact/architect.js +371 -0
  14. package/dist/agent-runtime/compact/architect.js.map +1 -0
  15. package/dist/agent-runtime/compact/chat-client.d.ts +83 -0
  16. package/dist/agent-runtime/compact/chat-client.js +307 -0
  17. package/dist/agent-runtime/compact/chat-client.js.map +1 -0
  18. package/dist/agent-runtime/compact/developer.d.ts +160 -0
  19. package/dist/agent-runtime/compact/developer.js +823 -0
  20. package/dist/agent-runtime/compact/developer.js.map +1 -0
  21. package/dist/agent-runtime/compact/environment.d.ts +62 -0
  22. package/dist/agent-runtime/compact/environment.js +213 -0
  23. package/dist/agent-runtime/compact/environment.js.map +1 -0
  24. package/dist/agent-runtime/compact/exit-code-honesty.d.ts +8 -0
  25. package/dist/agent-runtime/compact/exit-code-honesty.js +78 -0
  26. package/dist/agent-runtime/compact/exit-code-honesty.js.map +1 -0
  27. package/dist/agent-runtime/compact/guarded-loop.d.ts +73 -0
  28. package/dist/agent-runtime/compact/guarded-loop.js +320 -0
  29. package/dist/agent-runtime/compact/guarded-loop.js.map +1 -0
  30. package/dist/agent-runtime/compact/prompt-inputs.d.ts +42 -0
  31. package/dist/agent-runtime/compact/prompt-inputs.js +59 -0
  32. package/dist/agent-runtime/compact/prompt-inputs.js.map +1 -0
  33. package/dist/agent-runtime/compact/reviewer.d.ts +24 -0
  34. package/dist/agent-runtime/compact/reviewer.js +178 -0
  35. package/dist/agent-runtime/compact/reviewer.js.map +1 -0
  36. package/dist/agent-runtime/compact/step.d.ts +70 -0
  37. package/dist/agent-runtime/compact/step.js +136 -0
  38. package/dist/agent-runtime/compact/step.js.map +1 -0
  39. package/dist/agent-runtime/compact/test-reachability.d.ts +30 -0
  40. package/dist/agent-runtime/compact/test-reachability.js +147 -0
  41. package/dist/agent-runtime/compact/test-reachability.js.map +1 -0
  42. package/dist/agent-runtime/config.js +40 -10
  43. package/dist/agent-runtime/config.js.map +1 -1
  44. package/dist/agent-runtime/core-host.d.ts +4 -4
  45. package/dist/agent-runtime/core-host.js +8 -3
  46. package/dist/agent-runtime/core-host.js.map +1 -1
  47. package/dist/agent-runtime/executor-types.d.ts +37 -3
  48. package/dist/agent-runtime/executor-types.js +7 -2
  49. package/dist/agent-runtime/executor-types.js.map +1 -1
  50. package/dist/agent-runtime/graph/nodes.d.ts +4 -2
  51. package/dist/agent-runtime/graph/nodes.js +160 -53
  52. package/dist/agent-runtime/graph/nodes.js.map +1 -1
  53. package/dist/agent-runtime/graph/roles.d.ts +7 -2
  54. package/dist/agent-runtime/graph/roles.js +19 -11
  55. package/dist/agent-runtime/graph/roles.js.map +1 -1
  56. package/dist/agent-runtime/graph/state.d.ts +2 -1
  57. package/dist/agent-runtime/graph/state.js +2 -1
  58. package/dist/agent-runtime/graph/state.js.map +1 -1
  59. package/dist/agent-runtime/guardrails.d.ts +15 -0
  60. package/dist/agent-runtime/guardrails.js +76 -0
  61. package/dist/agent-runtime/guardrails.js.map +1 -0
  62. package/dist/agent-runtime/openai-executor.d.ts +25 -1
  63. package/dist/agent-runtime/openai-executor.js +67 -122
  64. package/dist/agent-runtime/openai-executor.js.map +1 -1
  65. package/dist/agent-runtime/openspec-tool-server.js +3 -3
  66. package/dist/agent-runtime/openspec-tool-server.js.map +1 -1
  67. package/dist/agent-runtime/openspec.d.ts +76 -1
  68. package/dist/agent-runtime/openspec.js +70 -4
  69. package/dist/agent-runtime/openspec.js.map +1 -1
  70. package/dist/agent-runtime/prompts.d.ts +21 -2
  71. package/dist/agent-runtime/prompts.js +56 -6
  72. package/dist/agent-runtime/prompts.js.map +1 -1
  73. package/dist/agent-runtime/repository-context.js +39 -12
  74. package/dist/agent-runtime/repository-context.js.map +1 -1
  75. package/dist/agent-runtime/role-routing.js +1 -0
  76. package/dist/agent-runtime/role-routing.js.map +1 -1
  77. package/dist/agent-runtime/workflow-types.d.ts +2 -0
  78. package/dist/agent-runtime/workflow.js +1 -1
  79. package/dist/agent-runtime/workflow.js.map +1 -1
  80. package/dist/installer/runtime/pipeline-state.d.ts +1 -0
  81. package/dist/installer/runtime/pipeline-state.js +35 -4
  82. package/dist/installer/runtime/pipeline-state.js.map +1 -1
  83. package/docs/agent-runtime.md +8 -0
  84. package/docs/ci-cd.md +6 -3
  85. package/package.json +2 -2
  86. package/schemas/agent-runtime.schema.json +10 -2
@@ -0,0 +1,320 @@
1
+ import { toolEvent } from '../tool-event.js';
2
+ import { OPENSPEC_TOOL_ACTIONS } from '../openspec.js';
3
+ import { AgentExecutionError } from '../executor-types.js';
4
+ import { record } from './chat-client.js';
5
+ export const DEFAULT_CONTEXT_WINDOW_TOKENS = 32_768;
6
+ /** Consecutive identical calls answered with an error instead of executing. */
7
+ export const REPEAT_WARN_AT = 3;
8
+ /** Total identical calls that abort the step. */
9
+ export const REPEAT_ABORT_AT = 5;
10
+ const COMPACTION_RATIO = 0.7;
11
+ const PROTECTED_TAIL = 4;
12
+ const PLACEHOLDER_QUERIES = new Set(['.', '*', '**', '.*', '..', '?', 'query', '<query>']);
13
+ const NUDGE = 'Your reply was empty. Reply with the final result now, as requested; do not call tools.';
14
+ /** Default output budget of one tool turn. A tool turn should emit a tool call or a short reply, so this is a runaway guard, not a ceiling for real work; a connection whose model thinks privately (that counts against `max_tokens`) raises it with `maxOutputTokens`. */
15
+ export const TOOL_TURN_MAX_OUTPUT = 8192;
16
+ /** Headroom kept between the transcript and the context window when bounding an output budget. */
17
+ const OUTPUT_HEADROOM_TOKENS = 512;
18
+ /**
19
+ * `max_tokens` counts INSIDE the context window (prompt + output ≤ window), so
20
+ * a budget wider than what remains makes llama.cpp refuse the request
21
+ * ("exceeds the available context size") instead of helping. Bound every
22
+ * request to the room actually left; never below a minimal useful reply.
23
+ */
24
+ export function boundedOutputBudget(requested, contextWindowTokens, messages) {
25
+ const remaining = contextWindowTokens - estimateTokens(messages) - OUTPUT_HEADROOM_TOKENS;
26
+ return Math.max(256, Math.min(requested, remaining));
27
+ }
28
+ const EFFORT_STEP_DOWN = { high: 'medium', medium: 'low' };
29
+ /** Tools whose result is a pure function of the workspace: safe to answer a repeated call with a pointer to the earlier identical result. */
30
+ const READ_TOOLS = new Set(['read_file', 'read_lines', 'search_text', 'get_diff', 'list_files']);
31
+ /** Consecutive rewrites of one path (no other tool call between them) before the loop refuses the next one. */
32
+ export const REWRITE_WARN_AT = 3;
33
+ /** Whole-file rewrites only: iterating a file with apply_patch between reads is the normal edit flow. */
34
+ const WRITE_TOOLS = new Set(['write_file']);
35
+ /** The rewrite streak keys on the file NAME: a model alternating `tests/x.test.js` with an invented `repo/tests/x.test.js` (observed, 7 rewrites) is still rewriting one file. */
36
+ function pathOf(args) {
37
+ try {
38
+ const value = JSON.parse(args).path;
39
+ return typeof value === 'string' ? value.replace(/\\/g, '/').split('/').pop() : undefined;
40
+ }
41
+ catch {
42
+ return undefined;
43
+ }
44
+ }
45
+ /** Below this size a re-read is cheaper than the pointer text. */
46
+ const READ_CACHE_MIN_CHARS = 600;
47
+ function summarizeArgs(args) {
48
+ try {
49
+ const parsed = JSON.parse(args);
50
+ return Object.entries(parsed).map(([k, v]) => `${k}=${String(v)}`).join(' ').slice(0, 120);
51
+ }
52
+ catch {
53
+ return args.slice(0, 120);
54
+ }
55
+ }
56
+ /** Estimated tokens for the transcript: chars/4, which is what small local servers count against. */
57
+ export function estimateTokens(messages) {
58
+ return Math.ceil(messages.reduce((total, message) => total + JSON.stringify(message).length, 0) / 4);
59
+ }
60
+ /** One correct example the model can copy when its arguments were rejected. */
61
+ export function toolExample(name) {
62
+ switch (name) {
63
+ case 'search_text': return '{"path":".","query":"functionName"}';
64
+ case 'read_lines': return '{"path":"src/index.ts","startLine":1,"endLine":120}';
65
+ case 'write_file': return '{"path":"src/feature.ts","content":"export const feature = 1\\n"}';
66
+ case 'apply_patch': return '{"path":"src/feature.ts","oldText":"const a = 1","newText":"const a = 2"}';
67
+ case 'openspec_workflow': return '{"action":"instructions","artifact":"proposal"}';
68
+ case 'read_verification_evidence': return '{"id":"<evidence id from the verification result>","section":"stdout"}';
69
+ default: return '{"path":"src/index.ts"}';
70
+ }
71
+ }
72
+ /** Schema-level argument repair: returns the error the model receives instead of executing. */
73
+ export function validateToolArguments(name, raw, available) {
74
+ const example = `Example of a correct ${name} call: ${toolExample(name)}`;
75
+ if (!available.has(name))
76
+ return { error: `Tool '${name}' is unavailable for this step. Available tools: ${[...available].join(', ')}.` };
77
+ let parsed;
78
+ try {
79
+ parsed = raw.trim() === '' ? {} : JSON.parse(raw);
80
+ }
81
+ catch {
82
+ return { error: `Tool arguments must be a JSON object. ${example}` };
83
+ }
84
+ const args = record(parsed);
85
+ if (!args)
86
+ return { error: `Tool arguments must be a JSON object. ${example}` };
87
+ if (name === 'openspec_workflow') {
88
+ if (typeof args.action !== 'string' || !OPENSPEC_TOOL_ACTIONS.includes(args.action))
89
+ return { error: `openspec_workflow.action must be one of ${OPENSPEC_TOOL_ACTIONS.join(', ')}; file paths go in "path", artifact ids in "artifact". ${example}` };
90
+ return { args };
91
+ }
92
+ if (name === 'read_verification_evidence') {
93
+ if (typeof args.id !== 'string' || !args.id.trim())
94
+ return { error: `read_verification_evidence.id must be the evidence id returned by the verification result. ${example}` };
95
+ return { args };
96
+ }
97
+ // Every remaining tool is a workspace file tool keyed by a relative path.
98
+ if (typeof args.path !== 'string' || !args.path.trim())
99
+ return { error: `"path" must be a non-empty relative path string. ${example}` };
100
+ if (name === 'search_text') {
101
+ const query = typeof args.query === 'string' ? args.query.trim() : '';
102
+ if (!query || PLACEHOLDER_QUERIES.has(query) || query.length > 1000 || /^[\s.*?]+$/.test(query))
103
+ return { error: `search_text.query must be a literal, non-empty piece of text you expect to find (an identifier, a string, a heading); "${String(args.query ?? '')}" is a placeholder. Use list_files to browse instead. ${example}` };
104
+ }
105
+ if (name === 'write_file' && typeof args.content !== 'string')
106
+ return { error: `write_file.content must be the complete file text as a string. ${example}` };
107
+ if (name === 'apply_patch' && (typeof args.oldText !== 'string' || !args.oldText || typeof args.newText !== 'string'))
108
+ return { error: `apply_patch needs a non-empty oldText copied exactly from the file and a newText string. ${example}` };
109
+ return { args };
110
+ }
111
+ /** Replaces the oldest tool results with one-line summaries until the transcript fits the budget. */
112
+ export function compactMessages(messages, contextWindowTokens, calls) {
113
+ let compacted = 0;
114
+ for (let index = 2; index < messages.length - PROTECTED_TAIL && estimateTokens(messages) > COMPACTION_RATIO * contextWindowTokens; index++) {
115
+ const message = messages[index];
116
+ // Executed write/patch calls carry whole files in their arguments; the file
117
+ // is on disk, so the path alone is enough for the model's memory.
118
+ if (message.role === 'assistant' && Array.isArray(message.tool_calls) && message.compacted !== true) {
119
+ let changed = false;
120
+ const toolCalls = message.tool_calls.map(call => {
121
+ if ((call.function.name !== 'write_file' && call.function.name !== 'apply_patch') || call.function.arguments.length < 400)
122
+ return call;
123
+ let target = '';
124
+ try {
125
+ target = String(JSON.parse(call.function.arguments).path ?? '');
126
+ }
127
+ catch { /* keep as is */ }
128
+ if (!target)
129
+ return call;
130
+ changed = true;
131
+ return { ...call, function: { ...call.function, arguments: JSON.stringify({ path: target, content: `[compacted: ${call.function.name} of ${call.function.arguments.length} chars already applied to ${target}]` }) } };
132
+ });
133
+ if (changed) {
134
+ messages[index] = { ...message, tool_calls: toolCalls, compacted: true };
135
+ compacted++;
136
+ }
137
+ continue;
138
+ }
139
+ if (message.role !== 'tool' || message.compacted === true || typeof message.content !== 'string')
140
+ continue;
141
+ const call = calls.get(String(message.tool_call_id));
142
+ const args = (call?.args ?? '').replace(/\s+/g, ' ');
143
+ messages[index] = { ...message, compacted: true, content: `[compacted: ${call?.name ?? 'tool'} ${args.length > 80 ? args.slice(0, 79) + '…' : args} → ${message.content.replace(/\s+/g, ' ').slice(0, 120)}]` };
144
+ compacted++;
145
+ }
146
+ return compacted;
147
+ }
148
+ function stripInternal(message) {
149
+ const { compacted: _compacted, ...rest } = message;
150
+ return rest;
151
+ }
152
+ /**
153
+ * The agentic loop shared by the free and compact modes for OpenAI-compatible
154
+ * endpoints: repetition guard, argument repair with one correct example, one nudge
155
+ * for an empty final reply, `content: ''` on assistant tool-call messages and
156
+ * context compaction against the provider's window.
157
+ */
158
+ export async function runToolLoop(options) {
159
+ const outputBudget = options.maxOutputTokens ?? TOOL_TURN_MAX_OUTPUT;
160
+ let toolControls = { maxOutputTokens: outputBudget };
161
+ let toolRetried = false;
162
+ const { client, messages, signal } = options;
163
+ const available = new Set(options.tools.map(tool => String(record(record(tool)?.function)?.name ?? '')));
164
+ const calls = new Map();
165
+ const totals = new Map();
166
+ let previous = '', consecutive = 0, toolCalls = 0, nudged = false, budgetNotice = false, cachedReads = 0, extended = false, wroteSomething = false, rewriteStreak = 0;
167
+ let lastWrittenPath;
168
+ const reads = new Map();
169
+ // The write-only extension adds its calls to the turn budget too, else a
170
+ // maxTurns sized for the original budget ends the step before the extra calls.
171
+ for (let turn = 0; turn < options.maxTurns + (extended ? options.writeExtension.extraCalls : 0); turn++) {
172
+ signal.throwIfAborted();
173
+ let exhausted = options.maxToolCalls !== undefined && toolCalls >= options.maxToolCalls;
174
+ // Read-only budget spent: a step that must change files gets a short
175
+ // write-only extension instead of being asked to "reply now".
176
+ let writeOnly = false;
177
+ if (exhausted && options.writeExtension && !wroteSomething && !extended) {
178
+ extended = true;
179
+ exhausted = false;
180
+ const ext = options.writeExtension;
181
+ options.onEvent?.({ kind: 'text', text: `Tool budget spent on reads alone; granting ${ext.extraCalls} extra calls restricted to ${ext.tools.join('/')}.` });
182
+ messages.push({ role: 'user', content: `You have used the whole tool budget reading and have not written anything yet. You know enough: make the change now. You have ${ext.extraCalls} more tool calls and ONLY ${ext.tools.join(' / ')} are available — no more reading. Then reply with the final result.` });
183
+ }
184
+ if (extended && options.writeExtension) {
185
+ writeOnly = toolCalls < (options.maxToolCalls ?? 0) + options.writeExtension.extraCalls;
186
+ exhausted = !writeOnly;
187
+ }
188
+ if (exhausted && !budgetNotice) {
189
+ budgetNotice = true;
190
+ messages.push({ role: 'user', content: 'The tool budget for this step is spent. Reply with the final result now using what you already learned; do not call tools.' });
191
+ }
192
+ const offered = writeOnly ? options.tools.filter(tool => options.writeExtension.tools.includes(String(record(record(tool)?.function)?.name ?? ''))) : options.tools;
193
+ // A tool turn cut off by the output budget (`finish_reason: length`) is the
194
+ // model's hidden reasoning eating max_tokens. Retry the same turn once with
195
+ // a wider budget and, when the endpoint supports it, one notch less effort.
196
+ const body = { messages: messages.map(stripInternal), ...(exhausted ? {} : { tools: offered, tool_choice: 'auto' }) };
197
+ const bounded = (requested) => boundedOutputBudget(requested, options.contextWindowTokens, body.messages);
198
+ let completion;
199
+ try {
200
+ completion = await client.complete(body, { ...toolControls, maxOutputTokens: bounded(toolControls.maxOutputTokens ?? outputBudget) });
201
+ }
202
+ catch (error) {
203
+ if (!(error instanceof AgentExecutionError) || error.code !== 'incomplete_response' || toolRetried)
204
+ throw error;
205
+ toolRetried = true;
206
+ const current = toolControls.reasoningEffort ?? client.defaultEffort;
207
+ const lower = current ? EFFORT_STEP_DOWN[current] : undefined;
208
+ const wide = bounded(outputBudget * 2);
209
+ // Nothing to change (no effort to lower, no room left in the window): a retry would only repeat the cut-off.
210
+ if (!lower && wide <= bounded(outputBudget))
211
+ throw error;
212
+ options.onEvent?.({ kind: 'text', text: `Tool turn ran out of output budget (${bounded(outputBudget)} tokens)${lower ? `; retrying at "${lower}" effort` : ''}${wide > bounded(outputBudget) ? ` with ${wide} tokens` : ' — the context window leaves no more room'}.` });
213
+ toolControls = { ...toolControls, maxOutputTokens: wide, ...(lower ? { reasoningEffort: lower } : {}) };
214
+ completion = await client.complete(body, toolControls);
215
+ }
216
+ const { message } = completion;
217
+ const raw = message.tool_calls;
218
+ if (raw !== undefined && !Array.isArray(raw))
219
+ throw new AgentExecutionError('Invalid tool calls in provider response', 'invalid_tool_call', client.usage);
220
+ if (Array.isArray(raw) && raw.length > 0) {
221
+ if (raw.length > 32)
222
+ throw new AgentExecutionError('Provider requested too many tools in one turn', 'invalid_tool_call', client.usage);
223
+ const ids = new Set();
224
+ const parsed = raw.map(item => {
225
+ const call = record(item), fn = record(call?.function);
226
+ if (call?.type !== 'function' || typeof call.id !== 'string' || !call.id || ids.has(call.id) || typeof fn?.name !== 'string' || typeof fn.arguments !== 'string')
227
+ throw new AgentExecutionError('Malformed provider tool call', 'invalid_tool_call', client.usage);
228
+ ids.add(call.id);
229
+ return { id: call.id, name: fn.name, arguments: fn.arguments, call };
230
+ });
231
+ messages.push({ role: 'assistant', content: typeof message.content === 'string' ? message.content : '', tool_calls: parsed.map(item => item.call) });
232
+ for (const item of parsed) {
233
+ signal.throwIfAborted();
234
+ toolCalls++;
235
+ options.onToolCall?.();
236
+ calls.set(item.id, { name: item.name, args: item.arguments });
237
+ options.onEvent?.(toolEvent(item.name, item.arguments));
238
+ const key = item.name + '' + item.arguments.replace(/\s+/g, '');
239
+ consecutive = key === previous ? consecutive + 1 : 1;
240
+ previous = key;
241
+ const total = (totals.get(key) ?? 0) + 1;
242
+ totals.set(key, total);
243
+ // Rewrite loop: the same path written turn after turn with DIFFERENT
244
+ // content slips past the identical-arguments guard (observed: one
245
+ // generator script rewritten ten times in a row, 23 s apart, by a
246
+ // developer that cannot run it). Refuse the third consecutive rewrite.
247
+ const writtenPath = WRITE_TOOLS.has(item.name) ? pathOf(item.arguments) : undefined;
248
+ // Reads of that same file between rewrites keep the streak; any other action ends it.
249
+ const sameFileRead = (item.name === 'read_lines' || item.name === 'read_file') && lastWrittenPath !== undefined && pathOf(item.arguments) === lastWrittenPath;
250
+ if (writtenPath) {
251
+ rewriteStreak = writtenPath === lastWrittenPath ? rewriteStreak + 1 : 1;
252
+ lastWrittenPath = writtenPath;
253
+ }
254
+ else if (!sameFileRead) {
255
+ rewriteStreak = 0;
256
+ lastWrittenPath = undefined;
257
+ }
258
+ let result;
259
+ // A repeated READ now costs a pointer, not the bytes, and the pointer tells
260
+ // the model to stop: give reads more rope before calling it a loop
261
+ // (observed: a group closed as `tool_loop` on the fifth read of one test
262
+ // file while the model was legitimately editing between reads).
263
+ if (total >= (READ_TOOLS.has(item.name) ? REPEAT_ABORT_AT + 3 : REPEAT_ABORT_AT))
264
+ throw new AgentExecutionError(`Tool call ${item.name} repeated ${total} times with identical arguments`, 'tool_loop', client.usage);
265
+ if (rewriteStreak >= REWRITE_WARN_AT) {
266
+ result = JSON.stringify({ error: `"${writtenPath}" has been rewritten ${rewriteStreak} times in a row. Stop iterating on this file: you cannot execute scripts or check output here, so polishing it further changes nothing. Move on to the next file the task names, or reply with the final result.` });
267
+ rewriteStreak = 0;
268
+ }
269
+ else if (consecutive >= REPEAT_WARN_AT)
270
+ result = JSON.stringify({ error: `identical call repeated (${item.name} with the same arguments, ${consecutive} times in a row); the result has not changed. Move on: use a different tool or arguments, or reply with the final result.` });
271
+ else {
272
+ const checked = validateToolArguments(item.name, item.arguments, available);
273
+ if ('error' in checked)
274
+ result = JSON.stringify({ error: checked.error });
275
+ else {
276
+ try {
277
+ result = await options.execute(item.name, checked.args);
278
+ }
279
+ catch (error) {
280
+ result = JSON.stringify({ error: error instanceof Error ? error.message : 'Tool execution failed' });
281
+ }
282
+ if (options.writeExtension?.tools.includes(item.name) && !/^\s*\{\s*"error"/.test(result))
283
+ wroteSomething = true;
284
+ // Read cache: a small model re-reads the same unchanged file several
285
+ // times per group (observed: a 14 KB test file read four times = 16k
286
+ // tokens of transcript, minutes of prefill on a GPU spilling to RAM).
287
+ // The earlier result is still in the transcript, so the re-read gets a
288
+ // pointer instead of the bytes. A changed file, or an earlier read that
289
+ // compaction already folded, returns the full content again.
290
+ if (READ_TOOLS.has(item.name)) {
291
+ const earlier = reads.get(key);
292
+ const still = earlier !== undefined ? messages[earlier.index] : undefined;
293
+ if (earlier && still && still.role === 'tool' && still.compacted !== true && still.content === result && result.length >= READ_CACHE_MIN_CHARS) {
294
+ cachedReads++;
295
+ result = JSON.stringify({ unchanged: true, note: `Identical to your earlier ${item.name} ${summarizeArgs(item.arguments)} — that content is still above in this conversation and the file has not changed since. Do not read it again; use read_lines with a startLine/endLine range if you need one part, or continue with the edit.` });
296
+ }
297
+ else
298
+ reads.set(key, { index: messages.length, content: result });
299
+ }
300
+ }
301
+ }
302
+ messages.push({ role: 'tool', tool_call_id: item.id, content: result });
303
+ options.onEvent?.({ kind: 'tool-end', tool: item.name });
304
+ }
305
+ compactMessages(messages, options.contextWindowTokens, calls);
306
+ continue;
307
+ }
308
+ if (typeof message.content === 'string' && message.content.trim()) {
309
+ if (cachedReads)
310
+ options.onEvent?.({ kind: 'text', text: `Read cache: ${cachedReads} repeated read${cachedReads === 1 ? '' : 's'} of unchanged content answered with a pointer instead of the bytes.` });
311
+ return { text: message.content, toolCalls };
312
+ }
313
+ if (nudged)
314
+ throw new AgentExecutionError('Provider returned an empty final result', 'invalid_response', client.usage);
315
+ nudged = true;
316
+ messages.push({ role: 'assistant', content: '' }, { role: 'user', content: NUDGE });
317
+ }
318
+ throw new AgentExecutionError(`Agent exhausted ${options.maxTurns} turns without a final result`, 'max_turns', client.usage);
319
+ }
320
+ //# sourceMappingURL=guarded-loop.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guarded-loop.js","sourceRoot":"","sources":["../../../src/agent-runtime/compact/guarded-loop.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * The compact pipelines receive the same role prompt the graph builds for every
3
+ * executor (`roleInstructions` + frozen obligations + repository map). They have
4
+ * no `PipelineContext`, so the deterministic sections are extracted here instead
5
+ * of changing the prompts or the graph.
6
+ */
7
+ import type { FrozenCriterion } from '../prompts.js';
8
+ export interface ScopeRepository {
9
+ id: string;
10
+ name: string;
11
+ path: string;
12
+ }
13
+ export interface PromptInputs {
14
+ /** `## Frozen scope` section: change name, repositories and the requested work. */
15
+ scope: string;
16
+ repositories: ScopeRepository[];
17
+ /** `## Answers from the requester`, when the run resumed with an answer. */
18
+ answers: string;
19
+ /** Host-configured verification commands paragraph shown to the architect. */
20
+ configuredVerification: string;
21
+ criteria: FrozenCriterion[];
22
+ /** `## Repository reference` map, bounded. */
23
+ repositoryMap: string;
24
+ /** `## Developer summary` shown to the reviewer. */
25
+ developerSummary: string;
26
+ /** Reviewer gate thresholds line, verbatim from the output contract. */
27
+ reviewGate: string;
28
+ /** `## Verification result` / `## Previous review` feedback for correction passes. */
29
+ feedback: string;
30
+ /** The role definition (`## Your task: …` up to the next section) — the host-editable stance text. */
31
+ definition: string;
32
+ /** Re-review after a correction round: the files that changed since the previous verdict (empty ⇒ a full review). */
33
+ reReviewChanges: Array<{
34
+ repositoryId: string;
35
+ path: string;
36
+ status: 'added' | 'changed' | 'deleted';
37
+ }>;
38
+ }
39
+ /** Text of one `## Heading` section up to the next heading (or terminator), without the heading line. */
40
+ export declare function section(prompt: string, heading: string): string;
41
+ export declare function bounded(text: string, limit: number): string;
42
+ export declare function extractPromptInputs(prompt: string): PromptInputs;
@@ -0,0 +1,59 @@
1
+ import { RE_REVIEW_MARKER } from '../prompts.js';
2
+ const STOP = /^(## |Planning policy:|Current frozen acceptance obligations)/;
3
+ /** Text of one `## Heading` section up to the next heading (or terminator), without the heading line. */
4
+ export function section(prompt, heading) {
5
+ const lines = prompt.split('\n');
6
+ const start = lines.findIndex(line => line.trim() === heading);
7
+ if (start < 0)
8
+ return '';
9
+ const body = [];
10
+ for (let index = start + 1; index < lines.length; index++) {
11
+ const line = lines[index];
12
+ if (STOP.test(line))
13
+ break;
14
+ body.push(line);
15
+ }
16
+ return body.join('\n').trim();
17
+ }
18
+ export function bounded(text, limit) {
19
+ return text.length > limit ? text.slice(0, limit - 1).trimEnd() + '…' : text;
20
+ }
21
+ function parseReReviewChanges(prompt) {
22
+ const line = prompt.split('\n').find(row => row.startsWith(RE_REVIEW_MARKER));
23
+ if (!line)
24
+ return [];
25
+ try {
26
+ const parsed = JSON.parse(line.slice(RE_REVIEW_MARKER.length).trim());
27
+ return Array.isArray(parsed) ? parsed.filter((item) => !!item && typeof item === 'object' && typeof item.path === 'string' && typeof item.repositoryId === 'string' && ['added', 'changed', 'deleted'].includes(String(item.status))).slice(0, 200) : [];
28
+ }
29
+ catch {
30
+ return [];
31
+ }
32
+ }
33
+ export function extractPromptInputs(prompt) {
34
+ const scope = section(prompt, '## Frozen scope');
35
+ const repositories = [];
36
+ for (const match of scope.matchAll(/^- `([^`]+)` \(([^)]*)\): `([^`]+)`$/gm))
37
+ repositories.push({ id: match[1], name: match[2], path: match[3] });
38
+ const obligations = /Current frozen acceptance obligations \(all remain required\):\n(\[[^\n]*\])/.exec(prompt);
39
+ let criteria = [];
40
+ try {
41
+ const parsed = obligations ? JSON.parse(obligations[1]) : [];
42
+ criteria = Array.isArray(parsed) ? parsed.filter((item) => !!item && typeof item === 'object' && typeof item.specId === 'string' && Number.isInteger(item.criterionIndex) && typeof item.requirement === 'string') : [];
43
+ }
44
+ catch {
45
+ criteria = [];
46
+ }
47
+ const mapStart = prompt.indexOf('## Repository reference');
48
+ const configured = /^(Verification commands already configured by the host[\s\S]*?|No verification commands are configured by the host for this run\.)\n\n/m.exec(prompt);
49
+ const gate = /^- Scores are numbers from 0 to 100\..*$/m.exec(prompt);
50
+ const feedback = ['## Verification result', '## Previous review'].map(heading => { const text = section(prompt, heading); return text ? heading + '\n' + text : ''; }).filter(Boolean).join('\n\n');
51
+ return {
52
+ scope, repositories, answers: section(prompt, '## Answers from the requester'), configuredVerification: configured?.[1]?.trim() ?? '',
53
+ criteria, repositoryMap: mapStart >= 0 ? prompt.slice(mapStart) : '', developerSummary: section(prompt, '## Developer summary'),
54
+ reviewGate: gate?.[0] ?? '', feedback,
55
+ definition: /^## Your task:[^\n]*\n([\s\S]*?)(?=^## |(?![\s\S]))/m.exec(prompt)?.[1]?.trim() ?? '',
56
+ reReviewChanges: parseReReviewChanges(prompt),
57
+ };
58
+ }
59
+ //# sourceMappingURL=prompt-inputs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt-inputs.js","sourceRoot":"","sources":["../../../src/agent-runtime/compact/prompt-inputs.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import type { AgentResult } from '../executor-types.js';
2
+ import { type CompactEnv } from './step.js';
3
+ /** Tool calls the reviewer may spend inspecting beyond the supplied diff. */
4
+ export declare const DEFAULT_REVIEW_TOOL_BUDGET = 15;
5
+ /** A re-review only opens the changed files. */
6
+ export declare const RE_REVIEW_TOOL_BUDGET = 6;
7
+ /** Working-tree changes of every allowed root against HEAD, plus the content of new files, bounded. `only` restricts the diff and the new-file listing to those repository-relative paths (a re-review reads just what the fixer touched). */
8
+ export declare function collectDiff(roots: string[], only?: readonly string[]): string;
9
+ /** The gate thresholds the host rendered into the reviewer prompt (`score is at least N`, `aspect ≥ N`). */
10
+ export declare function reviewGateThresholds(gate: string): {
11
+ minScore: number;
12
+ aspects: Record<string, number>;
13
+ };
14
+ /** Files named by the previous review's issues (`path: what must change` lines under `## Previous review`). */
15
+ export declare function previousIssueFiles(feedback: string): string[];
16
+ /**
17
+ * The compact reviewer: the host supplies the diff and the frozen criteria, the
18
+ * model inspects read-only within a small budget, and the verdict is forced
19
+ * into REVIEW_OUTPUT_SCHEMA. Missing criteria are recorded as pending, never
20
+ * invented as met.
21
+ */
22
+ export declare function runCompactReviewer(env: CompactEnv, options?: {
23
+ reviewToolBudget?: number;
24
+ }): Promise<AgentResult>;