@zelari/core 2.33.0 → 2.34.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 (36) hide show
  1. package/README.md +1 -1
  2. package/dist/agents/council/chairmanDelivery.d.ts +92 -0
  3. package/dist/agents/council/chairmanDelivery.d.ts.map +1 -0
  4. package/dist/agents/council/chairmanDelivery.js +226 -0
  5. package/dist/agents/council/chairmanDelivery.js.map +1 -0
  6. package/dist/agents/council/chairmanFixLoop.d.ts +47 -0
  7. package/dist/agents/council/chairmanFixLoop.d.ts.map +1 -0
  8. package/dist/agents/council/chairmanFixLoop.js +127 -0
  9. package/dist/agents/council/chairmanFixLoop.js.map +1 -0
  10. package/dist/agents/council/memberMessages.d.ts +32 -0
  11. package/dist/agents/council/memberMessages.d.ts.map +1 -0
  12. package/dist/agents/council/memberMessages.js +95 -0
  13. package/dist/agents/council/memberMessages.js.map +1 -0
  14. package/dist/agents/council/outputCleaning.d.ts +37 -0
  15. package/dist/agents/council/outputCleaning.d.ts.map +1 -0
  16. package/dist/agents/council/outputCleaning.js +150 -0
  17. package/dist/agents/council/outputCleaning.js.map +1 -0
  18. package/dist/agents/council/retryTurn.d.ts +128 -0
  19. package/dist/agents/council/retryTurn.d.ts.map +1 -0
  20. package/dist/agents/council/retryTurn.js +200 -0
  21. package/dist/agents/council/retryTurn.js.map +1 -0
  22. package/dist/agents/council/toolEmission.d.ts +61 -0
  23. package/dist/agents/council/toolEmission.d.ts.map +1 -0
  24. package/dist/agents/council/toolEmission.js +110 -0
  25. package/dist/agents/council/toolEmission.js.map +1 -0
  26. package/dist/agents/council/types.d.ts +184 -0
  27. package/dist/agents/council/types.d.ts.map +1 -0
  28. package/dist/agents/council/types.js +15 -0
  29. package/dist/agents/council/types.js.map +1 -0
  30. package/dist/agents/councilApi.d.ts +11 -526
  31. package/dist/agents/councilApi.d.ts.map +1 -1
  32. package/dist/agents/councilApi.js +19 -893
  33. package/dist/agents/councilApi.js.map +1 -1
  34. package/dist/version.d.ts +1 -1
  35. package/dist/version.js +1 -1
  36. package/package.json +1 -1
@@ -0,0 +1,95 @@
1
+ import { resolveRoleSystemPrompt } from '../roles.js';
2
+ import { buildSystemPromptSplit, computeAgentTools } from '../systemPromptBuilder.js';
3
+ import { getAllTools } from '../tools.js';
4
+ import { councilModeBanner } from '../../council/modeBanners.js';
5
+ /**
6
+ * Tools that mutate project files. In implementation-mode council runs only the
7
+ * chairman (Lucifero) implements; specialists + Minosse analyze and hand off.
8
+ * We strip these from every non-implementer so multiple agents never edit the
9
+ * same files (multi-writer chaos) and "who implemented" stays unambiguous.
10
+ * Note: specialists inherit write tools via skill `requiredTools`, so this must
11
+ * filter the RESULT of computeAgentTools, not just the declared role tools.
12
+ */
13
+ export const MUTATING_PROJECT_TOOLS = ['write_file', 'edit_file'];
14
+ /**
15
+ * Remove file-mutating tools for non-implementer members in implementation mode.
16
+ * Design-phase and the implementer (chairman) keep the full set unchanged.
17
+ */
18
+ export function restrictImplementationWrites(toolNames, opts) {
19
+ if (opts.runMode !== 'implementation' || opts.isImplementer)
20
+ return toolNames;
21
+ return toolNames.filter((t) => !MUTATING_PROJECT_TOOLS.includes(t));
22
+ }
23
+ /** @internal */
24
+ export function buildAgentMessages(agent, userMessage, ragContext, workspaceContext, priorOutputs, aiConfig, executableTools, runMode = 'implementation', languageModule) {
25
+ // v0.7.5: the AVAILABLE TOOLS prompt block must match the schemas the
26
+ // harness actually advertises. The v0.7.3 fix filtered the schemas
27
+ // (filterExecutable) but NOT this prompt text, so members still read
28
+ // "searchRAG: search the knowledge base…" in their system prompt and
29
+ // called it — every call a guaranteed "Tool not found" (live test
30
+ // 2026-07-03, /council in Z:\EasyPeasy\test).
31
+ const allToolNames = computeAgentTools(agent, aiConfig);
32
+ const toolNames = executableTools
33
+ ? allToolNames.filter((n) => executableTools.has(n))
34
+ : allToolNames;
35
+ // Merge language policy into custom modules so every primary council turn
36
+ // gets it (retries previously received the arg but never used it).
37
+ const mergedAiConfig = languageModule
38
+ ? {
39
+ enabledSkills: aiConfig?.enabledSkills ?? [],
40
+ enabledTools: aiConfig?.enabledTools ?? [],
41
+ agentSkillConfigs: aiConfig?.agentSkillConfigs ?? [],
42
+ customSkills: aiConfig?.customSkills,
43
+ customPromptModules: [
44
+ ...(aiConfig?.customPromptModules ?? []),
45
+ languageModule,
46
+ ],
47
+ }
48
+ : aiConfig;
49
+ // Mode-split: design mandatories only when runMode is design-phase.
50
+ const modeAwareAgent = {
51
+ ...agent,
52
+ systemPrompt: resolveRoleSystemPrompt(agent, runMode),
53
+ };
54
+ // Cache-efficient split (Cache Wars): stable = identity/tools/role;
55
+ // volatile = workspace/RAG; banners stay trailing system msgs (volatile).
56
+ const split = buildSystemPromptSplit(modeAwareAgent, {
57
+ tools: getAllTools(),
58
+ toolNames,
59
+ aiConfig: mergedAiConfig,
60
+ workspaceContext,
61
+ ragContext,
62
+ mode: 'council',
63
+ includeWorkspaceInPrompt: true,
64
+ });
65
+ const messages = [
66
+ { role: 'system', content: split.stable },
67
+ ];
68
+ if (split.volatile.trim()) {
69
+ messages.push({ role: 'system', content: split.volatile });
70
+ }
71
+ messages.push({ role: 'system', content: councilModeBanner(runMode, { isImplementer: agent.id === 'lucifer' }) }, { role: 'system', content: 'IMPORTANT: Before making any tool calls or expensive operations, check if the information already exists in the shared context from previous agents. Avoid redundant work.' });
72
+ if (priorOutputs.length > 0) {
73
+ // Cap each prior member blob so one verbose specialist cannot saturate
74
+ // downstream members (chairman especially). Full text is not product law.
75
+ const MAX_PRIOR_CHARS = 2800;
76
+ const summary = priorOutputs
77
+ .map((o) => {
78
+ const body = o.content.length > MAX_PRIOR_CHARS
79
+ ? `${o.content.slice(0, MAX_PRIOR_CHARS)}\n… [truncated ${o.content.length}→${MAX_PRIOR_CHARS} chars; treat as hypothesis]`
80
+ : o.content;
81
+ return `[${o.name} - ${o.role}]: ${body}`;
82
+ })
83
+ .join('\n\n');
84
+ messages.push({
85
+ role: 'user',
86
+ content: `Previous council members have said (hypotheses — prefer product files on disk if they conflict):\n${summary}\n\n` +
87
+ `Original user request: ${userMessage}`,
88
+ });
89
+ }
90
+ else {
91
+ messages.push({ role: 'user', content: userMessage });
92
+ }
93
+ return messages;
94
+ }
95
+ //# sourceMappingURL=memberMessages.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memberMessages.js","sourceRoot":"","sources":["../../../src/agents/council/memberMessages.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ export interface ClarificationRequest {
2
+ question: string;
3
+ choices?: string[];
4
+ context?: string;
5
+ }
6
+ export declare function parseClarificationRequest(text: string): ClarificationRequest | null;
7
+ /** True when text contains a structured question with ≥2 choices (pause UI). */
8
+ export declare function hasInteractiveClarification(text: string): boolean;
9
+ export declare function parseThinking(text: string): string;
10
+ export interface CleanAgentContentOptions {
11
+ /**
12
+ * When true (default), strip `---QUESTION---` blocks from display text.
13
+ * Set false when cleaning text for rolling PROVIDER history — the model
14
+ * still needs to see its own clarifying question on the next turn.
15
+ */
16
+ stripQuestion?: boolean;
17
+ /**
18
+ * When true (default), strip `<think>` / `<thinking>` blocks (UI display).
19
+ * Set **false** for multi-turn **provider** history: MiniMax-M3 (and M2.x)
20
+ * require the full assistant `content` including think tags so interleaved
21
+ * tool-use reasoning continues. Stripping them for the API degrades tool
22
+ * loops ("announces intent then stops"). Display paths keep the default.
23
+ */
24
+ stripThink?: boolean;
25
+ }
26
+ /**
27
+ * Strip model "private" channels from text shown to the user / re-fed as
28
+ * history. Covers:
29
+ * - complete + unclosed `<think>` / `<thinking>` (GLM/MiniMax style) — optional
30
+ * - MiniMax XML tool-call wrappers
31
+ * - clarifying-question JSON blocks (display only; keep in provider history)
32
+ *
33
+ * Without unclosed-tag stripping, streamed thinking that never got a closing
34
+ * tag leaked into the TUI as visible assistant prose (v1.8.1).
35
+ */
36
+ export declare function cleanAgentContent(text: string, opts?: CleanAgentContentOptions): string;
37
+ //# sourceMappingURL=outputCleaning.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"outputCleaning.d.ts","sourceRoot":"","sources":["../../../src/agents/council/outputCleaning.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAwCD,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,GAAG,oBAAoB,GAAG,IAAI,CA6BnF;AAED,gFAAgF;AAChF,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAGjE;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAMlD;AAED,MAAM,WAAW,wBAAwB;IACvC;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE,wBAA6B,GAClC,MAAM,CAmDR"}
@@ -0,0 +1,150 @@
1
+ /**
2
+ * outputCleaning — clarifying-question parsing and model output cleaning,
3
+ * extracted verbatim from agents/councilApi.ts.
4
+ */
5
+ import { scrubProprietaryLeak } from '../secrecyPolicy.js';
6
+ const QUESTION_MARKER = '---QUESTION---';
7
+ const QUESTION_END_MARKER = '---END---';
8
+ /**
9
+ * Extract the first top-level JSON object from `s` using brace depth so trailing
10
+ * MiniMax/tool garbage after `}` does not break JSON.parse (common failure mode:
11
+ * `---QUESTION--- {…}]<]minimax…` without ---END---).
12
+ */
13
+ function extractBalancedJsonObject(s) {
14
+ const start = s.indexOf('{');
15
+ if (start < 0)
16
+ return null;
17
+ let depth = 0;
18
+ let inString = false;
19
+ let escape = false;
20
+ for (let i = start; i < s.length; i++) {
21
+ const ch = s[i];
22
+ if (inString) {
23
+ if (escape) {
24
+ escape = false;
25
+ continue;
26
+ }
27
+ if (ch === '\\') {
28
+ escape = true;
29
+ continue;
30
+ }
31
+ if (ch === '"')
32
+ inString = false;
33
+ continue;
34
+ }
35
+ if (ch === '"') {
36
+ inString = true;
37
+ continue;
38
+ }
39
+ if (ch === '{')
40
+ depth++;
41
+ else if (ch === '}') {
42
+ depth--;
43
+ if (depth === 0)
44
+ return s.slice(start, i + 1);
45
+ }
46
+ }
47
+ return null;
48
+ }
49
+ export function parseClarificationRequest(text) {
50
+ const start = text.indexOf(QUESTION_MARKER);
51
+ if (start < 0)
52
+ return null;
53
+ const rest = text.slice(start + QUESTION_MARKER.length);
54
+ const end = rest.indexOf(QUESTION_END_MARKER);
55
+ const block = end >= 0 ? rest.slice(0, end) : rest;
56
+ const cleaned = block.replace(/```json\n?/g, '').replace(/```\n?/g, '').trim();
57
+ const jsonText = extractBalancedJsonObject(cleaned) ??
58
+ (() => {
59
+ const objStart = cleaned.indexOf('{');
60
+ const objEnd = cleaned.lastIndexOf('}');
61
+ return objStart >= 0 && objEnd > objStart
62
+ ? cleaned.slice(objStart, objEnd + 1)
63
+ : cleaned;
64
+ })();
65
+ try {
66
+ const parsed = JSON.parse(jsonText);
67
+ if (typeof parsed.question !== 'string' || !parsed.question.trim())
68
+ return null;
69
+ return {
70
+ question: parsed.question.trim(),
71
+ choices: Array.isArray(parsed.choices)
72
+ ? parsed.choices.filter((c) => typeof c === 'string' && c.trim().length > 0).map((c) => c.trim())
73
+ : undefined,
74
+ context: typeof parsed.context === 'string' ? parsed.context.trim() : undefined,
75
+ };
76
+ }
77
+ catch {
78
+ return null;
79
+ }
80
+ }
81
+ /** True when text contains a structured question with ≥2 choices (pause UI). */
82
+ export function hasInteractiveClarification(text) {
83
+ const c = parseClarificationRequest(text);
84
+ return !!(c && c.choices && c.choices.length >= 2);
85
+ }
86
+ export function parseThinking(text) {
87
+ // Prefer complete blocks; fall back to unclosed trailing block (common mid-stream).
88
+ const complete = text.match(/<think(?:ing)?>([\s\S]*?)<\/think(?:ing)?>/i);
89
+ if (complete)
90
+ return complete[1].trim();
91
+ const open = text.match(/<think(?:ing)?>([\s\S]*)$/i);
92
+ return open ? open[1].trim() : '';
93
+ }
94
+ /**
95
+ * Strip model "private" channels from text shown to the user / re-fed as
96
+ * history. Covers:
97
+ * - complete + unclosed `<think>` / `<thinking>` (GLM/MiniMax style) — optional
98
+ * - MiniMax XML tool-call wrappers
99
+ * - clarifying-question JSON blocks (display only; keep in provider history)
100
+ *
101
+ * Without unclosed-tag stripping, streamed thinking that never got a closing
102
+ * tag leaked into the TUI as visible assistant prose (v1.8.1).
103
+ */
104
+ export function cleanAgentContent(text, opts = {}) {
105
+ const stripQuestion = opts.stripQuestion !== false;
106
+ const stripThink = opts.stripThink !== false;
107
+ let out = text;
108
+ if (stripThink) {
109
+ out = out
110
+ .replace(/<think(?:ing)?>[\s\S]*?<\/think(?:ing)?>/gi, '')
111
+ .replace(/<think(?:ing)?>[\s\S]*$/gi, '')
112
+ .replace(/<\/think(?:ing)?>/gi, '');
113
+ }
114
+ // Tool-call markup that models sometimes dump into prose (MiniMax / GLM / generic).
115
+ // Prefer closed-block removal first; only then strip *trailing* unclosed
116
+ // open tags. Never use a mid-string open-tag → EOF wipe for tool tags when
117
+ // there may still be real prose after a broken unclosed tag sequence —
118
+ // headless streamScrub re-cleans the full buffer each push, so closed pairs
119
+ // are enough mid-stream; trailing open is for end-of-turn.
120
+ out = out
121
+ .replace(/<minimax:tool_call>[\s\S]*?<\/minimax:tool_call>/gi, '')
122
+ .replace(/<\/?minimax:tool_call>/gi, '')
123
+ .replace(/<tool_call>[\s\S]*?<\/tool_call>/gi, '')
124
+ .replace(/<\/?tool_call>/gi, '')
125
+ .replace(/<function_call>[\s\S]*?<\/function_call>/gi, '')
126
+ .replace(/<\/?function_call>/gi, '')
127
+ .replace(/<invoke\b[^>]*>[\s\S]*?<\/invoke>/gi, '')
128
+ .replace(/<\/invoke>/gi, '')
129
+ .replace(/<parameter\b[^>]*>[\s\S]*?<\/parameter>/gi, '')
130
+ .replace(/<\/parameter>/gi, '')
131
+ .replace(/\]\s*<\]\s*minimax\s*\[>\s*\[?<invoke\b[^>]*>[\s\S]*?<\/invoke>/gi, '')
132
+ // Trailing unclosed tool channels only (end of buffer)
133
+ .replace(/<minimax:tool_call>[\s\S]*$/gi, '')
134
+ .replace(/<tool_call>[\s\S]*$/gi, '')
135
+ .replace(/<function_call>[\s\S]*$/gi, '')
136
+ .replace(/<invoke\b[^>]*>[\s\S]*$/gi, '')
137
+ .replace(/\]\s*<\]\s*minimax\s*\[>[\s\S]*$/gi, '')
138
+ .replace(/^\s*\]\s*<\]\s*minimax\s*\[>.*$/gim, '')
139
+ .replace(/^\s*<\/?(?:tool_call|function_call|invoke|parameter|minimax:tool_call)\b[^>]*>\s*$/gim, '');
140
+ if (stripQuestion) {
141
+ // Closed block, or unclosed (model often omits ---END--- then dumps tools).
142
+ out = out
143
+ .replace(/---QUESTION---[\s\S]*?---END---/g, '')
144
+ .replace(/---QUESTION---[\s\S]*$/g, '');
145
+ }
146
+ out = out.replace(/\n{3,}/g, '\n\n').trim();
147
+ // Defense-in-depth: strip proprietary prompt dumps that escaped model policy.
148
+ return scrubProprietaryLeak(out);
149
+ }
150
+ //# sourceMappingURL=outputCleaning.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"outputCleaning.js","sourceRoot":"","sources":["../../../src/agents/council/outputCleaning.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,128 @@
1
+ /**
2
+ * retryTurn — forced tool-emission retry turns (v0.7.7 Pass 3), extracted
3
+ * verbatim from agents/councilApi.ts.
4
+ */
5
+ import type { BrainEvent } from '../../shared/events.js';
6
+ import type { ProviderStreamFn } from '../../core/AgentHarness.js';
7
+ import type { AgentRole } from '../../types/index.js';
8
+ import type { SystemPromptConfig, SystemPromptModule } from '../../types/systemTypes.js';
9
+ import type { CouncilRunMode } from '../../council/runMode.js';
10
+ import type { ToolEmissionCheckResult, ToolEmissionRequirement } from './toolEmission.js';
11
+ import type { PureCouncilConfig } from './types.js';
12
+ /**
13
+ * Maximum number of forced retry turns per council member. Cap of 1
14
+ * keeps the worst-case council latency bounded (a single extra turn per
15
+ * member × 4 design-phase members ≈ 30-60 s on top of the base run).
16
+ * Going above 1 tends to produce hallucinated tool arguments because
17
+ * the model has already spent its "tool budget" on exploration.
18
+ */
19
+ export declare const MAX_RETRY_PER_MEMBER = 1;
20
+ /**
21
+ * Pure helper: should the council loop spin up one more forced turn for
22
+ * this member to recover the missing tool emissions?
23
+ *
24
+ * Returns true when:
25
+ * - at least one tool is still missing after the post-condition check, AND
26
+ * - the retry budget for this member has not been exhausted.
27
+ *
28
+ * Returns false otherwise. Tested as a pure function so the council
29
+ * loop can branch on the answer without coupling to AgentHarness.
30
+ */
31
+ export declare function shouldRetryMember(missingToolNames: string[], attemptsSoFar: number): boolean;
32
+ /**
33
+ * Build the one-line prompt that the retry turn sends to the model.
34
+ * The shape matters: the model is primed by its role prompt to produce
35
+ * prose, so the retry prompt must be unambiguous, imperative, and
36
+ * scoped to ONLY the missing tools.
37
+ *
38
+ * Format: "You did not emit: <names>. Call <names> NOW with concrete
39
+ * arguments. No prose."
40
+ *
41
+ * Multiple tools are listed comma-separated in the same call so the
42
+ * model can satisfy them in a single tool_calls turn (which is the
43
+ * cheapest path through AgentHarness).
44
+ */
45
+ export declare function buildRetryPrompt(missingToolNames: string[]): string;
46
+ export declare function runRetryTurnForMember(args: {
47
+ agent: AgentRole;
48
+ missingToolNames: string[];
49
+ /**
50
+ * Per-tool minimum emission count. The retry budget is the SUM of these
51
+ * values (not just the number of distinct missing tools), because
52
+ * requirements like `createTask min: 12` need 12 separate calls even
53
+ * though only 1 distinct tool is missing. If omitted, the budget
54
+ * defaults to `missingToolNames.length` (suitable for tools like
55
+ * createDocument that need only one call).
56
+ */
57
+ minPerTool?: Record<string, number>;
58
+ executableTools: ReadonlySet<string> | null;
59
+ userMessage: string;
60
+ ragContext: string;
61
+ workspaceContext: string;
62
+ priorOutputs: {
63
+ name: string;
64
+ role: string;
65
+ content: string;
66
+ }[];
67
+ aiConfig?: SystemPromptConfig;
68
+ sessionId: string;
69
+ effectiveModel: string;
70
+ effectiveProvider: string;
71
+ eventBus?: BrainEvent['sessionId'] extends string ? unknown : never;
72
+ toolRegistry?: unknown;
73
+ providerStream: ProviderStreamFn;
74
+ runMode?: CouncilRunMode;
75
+ /** Override the default buildRetryPrompt message. */
76
+ retryPrompt?: string;
77
+ /**
78
+ * v1.7.0 (agy audit M2): pre-built language module. Optional — when
79
+ * omitted, no language-policy system message is added (preserves the
80
+ * pre-1.7 retry behavior for tests and callers that don't track it).
81
+ * `runCouncilPure` threads the module it built once per run.
82
+ */
83
+ languageModule?: SystemPromptModule;
84
+ }): AsyncGenerator<BrainEvent, string[], void>;
85
+ /**
86
+ * Shared retry orchestrator used by specialist, oracle, and chairman
87
+ * loops. Given the post-condition check result, decides whether to
88
+ * spin up a forced retry turn, and if so yields the events from that
89
+ * turn back to the caller (so the UI sees them) while mutating the
90
+ * shared `emittedToolNames` array (so the next post-condition check
91
+ * sees the union of original + retry emissions).
92
+ *
93
+ * The retry turn is skipped when:
94
+ * - the check passed (no missing tools), OR
95
+ * - the retry budget for this member is exhausted (shouldRetryMember).
96
+ *
97
+ * On retry failure (network error, model error, etc.) the function logs
98
+ * the error and continues — it never throws. The next post-condition
99
+ * check will simply re-warn.
100
+ */
101
+ export declare function applyRetryIfMissing(args: {
102
+ agent: AgentRole;
103
+ check: ToolEmissionCheckResult;
104
+ /**
105
+ * Original per-member requirements. Used to compute the retry budget
106
+ * (sum of `min` for each missing tool) so the model can satisfy all
107
+ * minimums in one tool_calls turn. If omitted, defaults to 1 per
108
+ * distinct missing tool.
109
+ */
110
+ requirements?: ToolEmissionRequirement[];
111
+ emittedToolNames: string[];
112
+ executableNames: ReadonlySet<string> | null;
113
+ sessionId: string;
114
+ userMessage: string;
115
+ agentOutputs: {
116
+ name: string;
117
+ role: string;
118
+ content: string;
119
+ }[];
120
+ config: PureCouncilConfig;
121
+ effectiveProvider: string;
122
+ effectiveModel: string;
123
+ /** Callback to bump the per-member tool-call counter on each retry emission. */
124
+ onToolCall: () => void;
125
+ /** v1.7.0 (Pass-2 agy finding): see applyCompletionRetry. */
126
+ languageModule?: SystemPromptModule;
127
+ }): AsyncGenerator<BrainEvent, void, void>;
128
+ //# sourceMappingURL=retryTurn.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retryTurn.d.ts","sourceRoot":"","sources":["../../../src/agents/council/retryTurn.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,200 @@
1
+ import { AgentHarness } from '../../core/AgentHarness.js';
2
+ import { getProviderTools } from '../toolSchemas.js';
3
+ import { buildAgentMessages } from './memberMessages.js';
4
+ import { enforceDesignPhaseToolEmissions } from './toolEmission.js';
5
+ /**
6
+ * Maximum number of forced retry turns per council member. Cap of 1
7
+ * keeps the worst-case council latency bounded (a single extra turn per
8
+ * member × 4 design-phase members ≈ 30-60 s on top of the base run).
9
+ * Going above 1 tends to produce hallucinated tool arguments because
10
+ * the model has already spent its "tool budget" on exploration.
11
+ */
12
+ export const MAX_RETRY_PER_MEMBER = 1;
13
+ /**
14
+ * Pure helper: should the council loop spin up one more forced turn for
15
+ * this member to recover the missing tool emissions?
16
+ *
17
+ * Returns true when:
18
+ * - at least one tool is still missing after the post-condition check, AND
19
+ * - the retry budget for this member has not been exhausted.
20
+ *
21
+ * Returns false otherwise. Tested as a pure function so the council
22
+ * loop can branch on the answer without coupling to AgentHarness.
23
+ */
24
+ export function shouldRetryMember(missingToolNames, attemptsSoFar) {
25
+ if (missingToolNames.length === 0)
26
+ return false;
27
+ if (attemptsSoFar >= MAX_RETRY_PER_MEMBER)
28
+ return false;
29
+ return true;
30
+ }
31
+ /**
32
+ * Build the one-line prompt that the retry turn sends to the model.
33
+ * The shape matters: the model is primed by its role prompt to produce
34
+ * prose, so the retry prompt must be unambiguous, imperative, and
35
+ * scoped to ONLY the missing tools.
36
+ *
37
+ * Format: "You did not emit: <names>. Call <names> NOW with concrete
38
+ * arguments. No prose."
39
+ *
40
+ * Multiple tools are listed comma-separated in the same call so the
41
+ * model can satisfy them in a single tool_calls turn (which is the
42
+ * cheapest path through AgentHarness).
43
+ */
44
+ export function buildRetryPrompt(missingToolNames) {
45
+ const names = missingToolNames.join(', ');
46
+ return `You did not emit the required workspace tools: ${names}. Call ${names} NOW with concrete arguments. No prose. No search.`;
47
+ }
48
+ // ── Forced retry turn (v0.7.7 Pass 3) ──────────────────────────────────────
49
+ //
50
+ // When the post-condition check fails for a member, the council loop can
51
+ // spin up ONE more AgentHarness turn whose ONLY purpose is to force the
52
+ // missing tool emissions. This is a structural fix for the failure mode
53
+ // where the model terminates after exploration (`searchDocuments` × 2)
54
+ // without persisting the required artifacts.
55
+ //
56
+ // The retry turn is intentionally minimal:
57
+ // - System prompt: same as the original (via buildAgentMessages) so
58
+ // the model still has its role contract.
59
+ // - User message: the retry prompt (one line, imperative).
60
+ // - Tools: ONLY the missing tools (filtered through filterExecutable
61
+ // so we never advertise a tool the runtime cannot execute).
62
+ // - maxToolCallsPerTurn: exactly the number of missing tools — the
63
+ // model cannot explore again, it can only call what's missing.
64
+ //
65
+ // Returns the additional tool names emitted during the retry. The caller
66
+ // is responsible for re-running checkMemberToolEmissions with the
67
+ // union of original + retry emissions.
68
+ export async function* runRetryTurnForMember(args) {
69
+ // Filter the missing tools against what's actually executable in this
70
+ // runtime. If a tool is missing from executableTools, the retry can't
71
+ // emit it — log and skip.
72
+ const executableMissing = args.executableTools
73
+ ? args.missingToolNames.filter((n) => args.executableTools.has(n))
74
+ : args.missingToolNames;
75
+ if (executableMissing.length === 0) {
76
+ return [];
77
+ }
78
+ // Build the minimal tool set — only the missing tools.
79
+ const retryToolNames = executableMissing;
80
+ const retryToolSpecs = getProviderTools(retryToolNames).map((t) => ({
81
+ name: t.function.name,
82
+ description: t.function.description,
83
+ parameters: t.function.parameters,
84
+ }));
85
+ // Build the messages: same system + role context as the original turn,
86
+ // then the retry prompt as a user message appended at the end.
87
+ const baseMessages = buildAgentMessages(args.agent, args.userMessage, args.ragContext, args.workspaceContext, args.priorOutputs, args.aiConfig, args.executableTools, args.runMode ?? 'implementation', args.languageModule);
88
+ const retryMessages = [
89
+ ...baseMessages,
90
+ {
91
+ role: 'user',
92
+ content: args.retryPrompt ?? buildRetryPrompt(executableMissing),
93
+ },
94
+ ];
95
+ // Budget the retry turn so the model can satisfy ALL minimums in a
96
+ // single tool_calls turn. For createDocument min:1 this is 1; for
97
+ // createTask min:12 this is 12. Falls back to `missingToolNames.length`
98
+ // when no per-tool min map is provided.
99
+ const maxToolCalls = args.minPerTool !== undefined
100
+ ? Object.entries(args.minPerTool)
101
+ .filter(([name]) => executableMissing.includes(name))
102
+ .reduce((sum, [, min]) => sum + min, 0)
103
+ : retryToolNames.length;
104
+ const retryHarness = new AgentHarness({
105
+ model: args.effectiveModel,
106
+ provider: args.effectiveProvider,
107
+ sessionId: args.sessionId,
108
+ messages: retryMessages,
109
+ tools: retryToolSpecs,
110
+ eventBus: args.eventBus,
111
+ toolRegistry: args.toolRegistry,
112
+ // Budget the retry so the model can satisfy every requirement in
113
+ // ONE tool_calls turn. For createTask min:12 this needs 12 calls.
114
+ maxToolCallsPerTurn: maxToolCalls,
115
+ memberId: args.agent.id,
116
+ memberName: args.agent.name,
117
+ providerStream: (params) => args.providerStream(params),
118
+ });
119
+ const retryEmitted = [];
120
+ for await (const event of retryHarness.run()) {
121
+ if (event.type === 'tool_execution_start') {
122
+ retryEmitted.push(event.toolName);
123
+ }
124
+ yield event;
125
+ }
126
+ return retryEmitted;
127
+ }
128
+ /**
129
+ * Shared retry orchestrator used by specialist, oracle, and chairman
130
+ * loops. Given the post-condition check result, decides whether to
131
+ * spin up a forced retry turn, and if so yields the events from that
132
+ * turn back to the caller (so the UI sees them) while mutating the
133
+ * shared `emittedToolNames` array (so the next post-condition check
134
+ * sees the union of original + retry emissions).
135
+ *
136
+ * The retry turn is skipped when:
137
+ * - the check passed (no missing tools), OR
138
+ * - the retry budget for this member is exhausted (shouldRetryMember).
139
+ *
140
+ * On retry failure (network error, model error, etc.) the function logs
141
+ * the error and continues — it never throws. The next post-condition
142
+ * check will simply re-warn.
143
+ */
144
+ export async function* applyRetryIfMissing(args) {
145
+ if (args.check.ok)
146
+ return;
147
+ const missingToolNames = args.check.missing.map((m) => m.split(' ')[0]);
148
+ if (!shouldRetryMember(missingToolNames, 0))
149
+ return;
150
+ // eslint-disable-next-line no-console
151
+ console.warn(`[council] ${args.agent.id} retrying missing tools: ${missingToolNames.join(', ')}`);
152
+ // Build the minPerTool map from the original requirements so the
153
+ // retry turn budgets enough tool calls to satisfy every minimum.
154
+ // Without this, a createTask min:12 requirement would be capped at
155
+ // 1 call (the number of distinct missing tools).
156
+ const minPerTool = {};
157
+ if (args.requirements) {
158
+ for (const req of args.requirements) {
159
+ if (missingToolNames.includes(req.name)) {
160
+ minPerTool[req.name] = req.min;
161
+ }
162
+ }
163
+ }
164
+ try {
165
+ const retryGenerator = runRetryTurnForMember({
166
+ agent: args.agent,
167
+ missingToolNames,
168
+ minPerTool,
169
+ executableTools: args.executableNames,
170
+ userMessage: args.userMessage,
171
+ ragContext: args.config.ragContext,
172
+ workspaceContext: args.config.workspaceContext,
173
+ priorOutputs: args.agentOutputs,
174
+ aiConfig: args.config.aiConfig,
175
+ sessionId: args.sessionId,
176
+ effectiveModel: args.effectiveModel,
177
+ effectiveProvider: args.effectiveProvider,
178
+ eventBus: args.config.eventBus,
179
+ toolRegistry: args.config.tools,
180
+ providerStream: args.config.providerStream,
181
+ runMode: args.config.runMode,
182
+ languageModule: args.languageModule,
183
+ });
184
+ for await (const event of retryGenerator) {
185
+ if (event.type === 'tool_execution_start') {
186
+ args.onToolCall();
187
+ args.emittedToolNames.push(event.toolName);
188
+ }
189
+ yield event;
190
+ }
191
+ }
192
+ catch (retryErr) {
193
+ // eslint-disable-next-line no-console
194
+ console.error(`[council] ${args.agent.id} retry failed:`, retryErr);
195
+ }
196
+ // Re-run the check so the final warning reflects the union of
197
+ // original + retry emissions.
198
+ enforceDesignPhaseToolEmissions(args.agent.id, args.emittedToolNames);
199
+ }
200
+ //# sourceMappingURL=retryTurn.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retryTurn.js","sourceRoot":"","sources":["../../../src/agents/council/retryTurn.ts"],"names":[],"mappings":"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"}