@yagni-app/code-staging 0.3.0-staging.1082.1 → 0.3.0-staging.1085.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.
- package/dist/extension/branding.d.ts +11 -1
- package/dist/extension/branding.js +45 -7
- package/dist/extension/index.d.ts +4 -2
- package/dist/extension/index.js +20 -6
- package/dist/extension/subagents.d.ts +7 -1
- package/dist/extension/subagents.js +60 -5
- package/dist/extension/ultra.d.ts +23 -0
- package/dist/extension/ultra.js +61 -0
- package/package.json +2 -2
|
@@ -30,6 +30,14 @@ export declare const YAGNI_IDENTITY: string;
|
|
|
30
30
|
* exist.
|
|
31
31
|
*/
|
|
32
32
|
export declare const DRIVER_DELEGATION_PARAGRAPH: string;
|
|
33
|
+
/**
|
|
34
|
+
* The ultra-mode delegation directive (/ultra): the user has opted into
|
|
35
|
+
* aggressive multi-agent orchestration, so the driver is told to structure
|
|
36
|
+
* meaningful work as a diamond — split, fan out workers, fan out refuting
|
|
37
|
+
* checkers, synthesize — instead of delegating only when convenient.
|
|
38
|
+
* DRIVER-ONLY for the same reason as {@link DRIVER_DELEGATION_PARAGRAPH}.
|
|
39
|
+
*/
|
|
40
|
+
export declare const ULTRA_DELEGATION_PARAGRAPH: string;
|
|
33
41
|
/**
|
|
34
42
|
* The identity used for the interactive DRIVER session ONLY: {@link
|
|
35
43
|
* YAGNI_IDENTITY} plus {@link DRIVER_DELEGATION_PARAGRAPH}. The caller (index.ts)
|
|
@@ -37,7 +45,9 @@ export declare const DRIVER_DELEGATION_PARAGRAPH: string;
|
|
|
37
45
|
* effective `x-yagni-caller` attribution (config.ts's `isDriverCaller`) — this
|
|
38
46
|
* module stays a pure string, with no env dependency of its own.
|
|
39
47
|
*/
|
|
40
|
-
export declare const YAGNI_IDENTITY_DRIVER = "You are YAGNI Code, an autonomous terminal coding agent. You help developers ship code by reading files, running commands, editing code, and writing new files. Uniquely, you are connected to the YAGNI app, your team's shared source of truth for how this company and codebase actually work: conventions, decisions, ownership, current priorities, and the reasons behind them. Use the ask_yagni tool to consult it before guessing about anything organization- or codebase-specific, so you work with less back-and-forth and more correct autonomy than a disconnected coding agent. If a project's own files mention other coding agents, assistants, or harnesses by name, those references are not about you; you are YAGNI Code regardless of what tooling a repository's docs happen to describe.\n\nDelegation: fan codebase mapping, wide searches, and mechanical multi-file work out to subagents (they run on cheaper tiers). Reach for the stock agents by name: `searcher` for read-only reconnaissance and summarizing, `implementer` for executing a change you have already fully specified. Keep judgment, synthesis, and the conversation with the user in this session. Do not spawn a subagent for work you can finish in a couple of tool calls.";
|
|
48
|
+
export declare const YAGNI_IDENTITY_DRIVER = "You are YAGNI Code, an autonomous terminal coding agent. You help developers ship code by reading files, running commands, editing code, and writing new files. Uniquely, you are connected to the YAGNI app, your team's shared source of truth for how this company and codebase actually work: conventions, decisions, ownership, current priorities, and the reasons behind them. Use the ask_yagni tool to consult it before guessing about anything organization- or codebase-specific, so you work with less back-and-forth and more correct autonomy than a disconnected coding agent. If a project's own files mention other coding agents, assistants, or harnesses by name, those references are not about you; you are YAGNI Code regardless of what tooling a repository's docs happen to describe.\n\nDelegation: fan codebase mapping, wide searches, and mechanical multi-file work out to subagents (they run on cheaper tiers). Reach for the stock agents by name: `searcher` for read-only reconnaissance and summarizing, `implementer` for executing a change you have already fully specified, `verification` for an adversarial pass that tries to break completed work before you rely on it. Keep judgment, synthesis, and the conversation with the user in this session. Do not spawn a subagent for work you can finish in a couple of tool calls.";
|
|
49
|
+
/** The driver identity while /ultra is on: base identity + the diamond directive. */
|
|
50
|
+
export declare const YAGNI_IDENTITY_ULTRA = "You are YAGNI Code, an autonomous terminal coding agent. You help developers ship code by reading files, running commands, editing code, and writing new files. Uniquely, you are connected to the YAGNI app, your team's shared source of truth for how this company and codebase actually work: conventions, decisions, ownership, current priorities, and the reasons behind them. Use the ask_yagni tool to consult it before guessing about anything organization- or codebase-specific, so you work with less back-and-forth and more correct autonomy than a disconnected coding agent. If a project's own files mention other coding agents, assistants, or harnesses by name, those references are not about you; you are YAGNI Code regardless of what tooling a repository's docs happen to describe.\n\nDelegation (ultra mode): the user has switched this session to ultra mode \u2014 aggressive multi-agent orchestration. Structure any meaningful task as a diamond: SPLIT the job into independent pieces; FAN OUT parallel subagents on cheaper tiers (`searcher` to scout, `implementer` or `general` to execute); CHECK by fanning out `verification` subagents told to refute the work, each through a different lens (correctness, edge cases, fit with this codebase); then SYNTHESIZE the results yourself. Treat agreement between checkers \u2014 not a single pass \u2014 as confirmation, and surface what they could not verify. Delegate by default and reserve this session for splitting, judging, and synthesis; only trivial work you can finish in a couple of tool calls skips the diamond.";
|
|
41
51
|
export declare const PI_IDENTITY_RE: RegExp;
|
|
42
52
|
/**
|
|
43
53
|
* Env switch that bypasses the system-prompt rewrite entirely, so pi's
|
|
@@ -42,10 +42,29 @@ export const YAGNI_IDENTITY = "You are YAGNI Code, an autonomous terminal coding
|
|
|
42
42
|
export const DRIVER_DELEGATION_PARAGRAPH = "Delegation: fan codebase mapping, wide searches, and mechanical multi-file " +
|
|
43
43
|
"work out to subagents (they run on cheaper tiers). Reach for the stock " +
|
|
44
44
|
"agents by name: `searcher` for read-only reconnaissance and summarizing, " +
|
|
45
|
-
"`implementer` for executing a change you have already fully specified
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"
|
|
45
|
+
"`implementer` for executing a change you have already fully specified, " +
|
|
46
|
+
"`verification` for an adversarial pass that tries to break completed work " +
|
|
47
|
+
"before you rely on it. Keep judgment, synthesis, and the conversation " +
|
|
48
|
+
"with the user in this session. Do not spawn a subagent for work you can " +
|
|
49
|
+
"finish in a couple of tool calls.";
|
|
50
|
+
/**
|
|
51
|
+
* The ultra-mode delegation directive (/ultra): the user has opted into
|
|
52
|
+
* aggressive multi-agent orchestration, so the driver is told to structure
|
|
53
|
+
* meaningful work as a diamond — split, fan out workers, fan out refuting
|
|
54
|
+
* checkers, synthesize — instead of delegating only when convenient.
|
|
55
|
+
* DRIVER-ONLY for the same reason as {@link DRIVER_DELEGATION_PARAGRAPH}.
|
|
56
|
+
*/
|
|
57
|
+
export const ULTRA_DELEGATION_PARAGRAPH = "Delegation (ultra mode): the user has switched this session to ultra mode " +
|
|
58
|
+
"— aggressive multi-agent orchestration. Structure any meaningful task as " +
|
|
59
|
+
"a diamond: SPLIT the job into independent pieces; FAN OUT parallel " +
|
|
60
|
+
"subagents on cheaper tiers (`searcher` to scout, `implementer` or " +
|
|
61
|
+
"`general` to execute); CHECK by fanning out `verification` subagents told " +
|
|
62
|
+
"to refute the work, each through a different lens (correctness, edge cases, " +
|
|
63
|
+
"fit with this codebase); then SYNTHESIZE the results yourself. Treat " +
|
|
64
|
+
"agreement between checkers — not a single pass — as confirmation, and " +
|
|
65
|
+
"surface what they could not verify. Delegate by default and reserve this " +
|
|
66
|
+
"session for splitting, judging, and synthesis; only trivial work you can " +
|
|
67
|
+
"finish in a couple of tool calls skips the diamond.";
|
|
49
68
|
/**
|
|
50
69
|
* The identity used for the interactive DRIVER session ONLY: {@link
|
|
51
70
|
* YAGNI_IDENTITY} plus {@link DRIVER_DELEGATION_PARAGRAPH}. The caller (index.ts)
|
|
@@ -54,6 +73,14 @@ export const DRIVER_DELEGATION_PARAGRAPH = "Delegation: fan codebase mapping, wi
|
|
|
54
73
|
* module stays a pure string, with no env dependency of its own.
|
|
55
74
|
*/
|
|
56
75
|
export const YAGNI_IDENTITY_DRIVER = `${YAGNI_IDENTITY}\n\n${DRIVER_DELEGATION_PARAGRAPH}`;
|
|
76
|
+
/** The driver identity while /ultra is on: base identity + the diamond directive. */
|
|
77
|
+
export const YAGNI_IDENTITY_ULTRA = `${YAGNI_IDENTITY}\n\n${ULTRA_DELEGATION_PARAGRAPH}`;
|
|
78
|
+
/**
|
|
79
|
+
* Every identity variant this module can install, longest-composite-first, so
|
|
80
|
+
* the re-brand swap below never leaves a shorter variant's orphaned delegation
|
|
81
|
+
* paragraph behind (driver/ultra both start with the base identity).
|
|
82
|
+
*/
|
|
83
|
+
const KNOWN_IDENTITIES = [YAGNI_IDENTITY_ULTRA, YAGNI_IDENTITY_DRIVER, YAGNI_IDENTITY];
|
|
57
84
|
// pi 0.84.1's exact identity sentence (dist/core/system-prompt.js). Exported as
|
|
58
85
|
// the identity anchor the CLI's pi-contract tripwire test reads back from pi's
|
|
59
86
|
// built system prompt, so a pi bump that reworded the opener (silently defeating
|
|
@@ -112,15 +139,26 @@ export function brandSystemPrompt(original, opts = {}) {
|
|
|
112
139
|
let s = original;
|
|
113
140
|
// 1. Drop pi's self-referential documentation block.
|
|
114
141
|
s = s.replace(PI_DOCS_BLOCK_RE, "");
|
|
115
|
-
// 2. Own the identity.
|
|
142
|
+
// 2. Own the identity. A previously-branded prompt may open with a DIFFERENT
|
|
143
|
+
// variant than the one now requested (/ultra toggles the driver between the
|
|
144
|
+
// delegation and diamond paragraphs mid-session) — swap it in place rather
|
|
145
|
+
// than prepending a second identity block.
|
|
116
146
|
if (PI_IDENTITY_RE.test(s)) {
|
|
117
147
|
s = s.replace(PI_IDENTITY_RE, identity);
|
|
118
148
|
}
|
|
119
149
|
else if (PI_IDENTITY_LOOSE_RE.test(s)) {
|
|
120
150
|
s = s.replace(PI_IDENTITY_LOOSE_RE, identity);
|
|
121
151
|
}
|
|
122
|
-
else
|
|
123
|
-
|
|
152
|
+
else {
|
|
153
|
+
const trimmed = s.trimStart();
|
|
154
|
+
const lead = s.slice(0, s.length - trimmed.length);
|
|
155
|
+
const existing = KNOWN_IDENTITIES.find((k) => trimmed.startsWith(k));
|
|
156
|
+
if (existing && existing !== identity) {
|
|
157
|
+
s = `${lead}${identity}${trimmed.slice(existing.length)}`;
|
|
158
|
+
}
|
|
159
|
+
else if (!existing && !trimmed.startsWith(identity)) {
|
|
160
|
+
s = `${identity}\n\n${s}`;
|
|
161
|
+
}
|
|
124
162
|
}
|
|
125
163
|
// 3. Safety net for residual brand tokens (never inside user content).
|
|
126
164
|
s = scrubOutsideProjectContext(s);
|
|
@@ -122,7 +122,9 @@ export type { RecordDecisionParams } from "./recordDecisionTool.js";
|
|
|
122
122
|
export { runInitPass, runTeamSetup, registerTeamSetupCommand, isFreshWorkspace, readRepoIntake, draftEngineering, summarizeDraft, FRESH_BRIEF_MIN_CHARS, } from "./initPass.js";
|
|
123
123
|
export type { RunInitPassDeps, InitPassOutcome, RunTeamSetupDeps, TeamSetupOutcome, RepoIntake, RepoIntakeFs, EngineeringDraft, DraftTeam, } from "./initPass.js";
|
|
124
124
|
export { isInitDone, markInitDone, initDoneMarkerFile, _setInitDoneHomeForTest } from "./initDone.js";
|
|
125
|
-
export { brandSystemPrompt, YAGNI_IDENTITY, YAGNI_IDENTITY_DRIVER, BRAND_NAME } from "./branding.js";
|
|
125
|
+
export { brandSystemPrompt, YAGNI_IDENTITY, YAGNI_IDENTITY_DRIVER, YAGNI_IDENTITY_ULTRA, BRAND_NAME } from "./branding.js";
|
|
126
|
+
export { createUltraHolder, registerUltraCommand } from "./ultra.js";
|
|
127
|
+
export type { UltraHolder } from "./ultra.js";
|
|
126
128
|
export { attributionHeaders, isDriverCaller, fetchCatalog, getToken, getWorkspaceId, resolveBaseUrl, sanitizeCallerSegment, } from "./config.js";
|
|
127
129
|
export type { CatalogResult, FetchCatalogOptions, ModelEntry } from "./config.js";
|
|
128
130
|
export { buildYagniProvider } from "./provider.js";
|
|
@@ -139,7 +141,7 @@ export type { VerifyCommand, VerifyOutcome } from "./pipeline/verify.js";
|
|
|
139
141
|
export { blindStages, reportOnlyStages, makeGroundedVsBlindEval, formatComparisonReport } from "./pipeline/eval.js";
|
|
140
142
|
export type { ComparisonReport, LaneFit, LaneOutcome } from "./pipeline/eval.js";
|
|
141
143
|
export { registerGoCompareCommand } from "./pipeline/goCompareCommand.js";
|
|
142
|
-
export { registerSubagents, makeSubagentTool, discoverSubagents, parseAgentMarkdown, buildSubagentStage, formatAgentList, mapModelTier, SUBAGENT_TOOL_NAME, GENERAL_AGENT_NAME, MAX_PARALLEL_SUBAGENTS, DEFAULT_SUBAGENT_TOOLS, } from "./subagents.js";
|
|
144
|
+
export { registerSubagents, makeSubagentTool, discoverSubagents, parseAgentMarkdown, buildSubagentStage, formatAgentList, mapModelTier, SUBAGENT_TOOL_NAME, GENERAL_AGENT_NAME, MAX_PARALLEL_SUBAGENTS, MAX_PARALLEL_SUBAGENTS_ULTRA, DEFAULT_SUBAGENT_TOOLS, } from "./subagents.js";
|
|
143
145
|
export type { SubagentDef, SubagentSource } from "./subagents.js";
|
|
144
146
|
export { registerTodos, makeTodoTool, normalizeTodos, reconstructTodos, renderTodoWidget, formatTodoList, todoSummary, TODO_TOOL_NAME, MAX_TODOS, } from "./todos.js";
|
|
145
147
|
export type { TodoItem, TodoStatus, TodoTheme } from "./todos.js";
|
package/dist/extension/index.js
CHANGED
|
@@ -14,7 +14,7 @@ import { registerCmuxBridge } from "./cmux/index.js";
|
|
|
14
14
|
import { makeRecordEngineeringContextTool } from "./recordContextTool.js";
|
|
15
15
|
import { makeRecordDecisionTool } from "./recordDecisionTool.js";
|
|
16
16
|
import { makeSuggestNextWorkTool } from "./nextWorkTool.js";
|
|
17
|
-
import { BRAND_NAME, brandSystemPrompt, brandingDisabled, buildMastheadString, YAGNI_IDENTITY_DRIVER } from "./branding.js";
|
|
17
|
+
import { BRAND_NAME, brandSystemPrompt, brandingDisabled, buildMastheadString, YAGNI_IDENTITY_DRIVER, YAGNI_IDENTITY_ULTRA } from "./branding.js";
|
|
18
18
|
import { claudeRulesSection } from "./claudeRules.js";
|
|
19
19
|
import { registerCostCommand } from "./costHud.js";
|
|
20
20
|
import { isDebug } from "./diagnostics.js";
|
|
@@ -29,6 +29,7 @@ import { registerGoCommand } from "./pipeline/goCommand.js";
|
|
|
29
29
|
import { registerGoCompareCommand } from "./pipeline/goCompareCommand.js";
|
|
30
30
|
import { DEFAULT_PERMISSION_POLICY, createModeHolder, registerPermissionGate } from "./permission.js";
|
|
31
31
|
import { registerSubagents } from "./subagents.js";
|
|
32
|
+
import { createUltraHolder, registerUltraCommand } from "./ultra.js";
|
|
32
33
|
import { registerTodos } from "./todos.js";
|
|
33
34
|
import { registerDecisionCommands } from "./decisions.js";
|
|
34
35
|
import { makeDecisionCapture } from "./decisionCapture.js";
|
|
@@ -185,7 +186,12 @@ export async function registerYagni(pi, deps = {}) {
|
|
|
185
186
|
// The general subagent tool: delegate self-contained tasks (optionally in
|
|
186
187
|
// parallel) to fresh-context agents defined in .claude/agents / .pi/agents,
|
|
187
188
|
// riding the /go pipeline's child runner. /agents lists what's available.
|
|
188
|
-
|
|
189
|
+
// Ultra mode (/ultra) is an explicit orchestration dial: it swaps the
|
|
190
|
+
// driver's delegation identity for the diamond directive (see the
|
|
191
|
+
// before_agent_start handler below) and widens the tool's fan-out ceiling.
|
|
192
|
+
const ultraHolder = createUltraHolder();
|
|
193
|
+
registerSubagents(pi, { isUltra: () => ultraHolder.get() });
|
|
194
|
+
registerUltraCommand(pi, ultraHolder);
|
|
189
195
|
// Shared fetch timeout for the small, interactive display-path reads below
|
|
190
196
|
// (/cost's spend + headroom, and Task 8's per-run spend for /go's summary):
|
|
191
197
|
// 5s, not the 10s other boot/grounding fetches use, because the user is
|
|
@@ -517,13 +523,19 @@ export async function registerYagni(pi, deps = {}) {
|
|
|
517
523
|
// assembled prompt passes through byte-exact (no rewrite, no brief
|
|
518
524
|
// injection, no rules section, no delegation identity).
|
|
519
525
|
const noBranding = brandingDisabled(env);
|
|
520
|
-
|
|
526
|
+
// Resolved per turn (not once at activation): /ultra can flip the driver
|
|
527
|
+
// between the delegation and diamond identities mid-session.
|
|
528
|
+
const isDriver = isDriverCaller(env);
|
|
521
529
|
pi.on("before_agent_start", (event) => noBranding
|
|
522
530
|
? undefined
|
|
523
531
|
: {
|
|
524
532
|
systemPrompt: brandSystemPrompt(event.systemPrompt, {
|
|
525
533
|
contextBrief,
|
|
526
|
-
identity
|
|
534
|
+
identity: isDriver
|
|
535
|
+
? ultraHolder.get()
|
|
536
|
+
? YAGNI_IDENTITY_ULTRA
|
|
537
|
+
: YAGNI_IDENTITY_DRIVER
|
|
538
|
+
: undefined,
|
|
527
539
|
rulesSection,
|
|
528
540
|
}),
|
|
529
541
|
});
|
|
@@ -781,7 +793,9 @@ export { recordDecision } from "./recordDecisionTool.js";
|
|
|
781
793
|
export { runInitPass, runTeamSetup, registerTeamSetupCommand, isFreshWorkspace, readRepoIntake, draftEngineering, summarizeDraft, FRESH_BRIEF_MIN_CHARS, } from "./initPass.js";
|
|
782
794
|
// Onramp Door B (F2a): the one-time init-pass idempotency marker.
|
|
783
795
|
export { isInitDone, markInitDone, initDoneMarkerFile, _setInitDoneHomeForTest } from "./initDone.js";
|
|
784
|
-
export { brandSystemPrompt, YAGNI_IDENTITY, YAGNI_IDENTITY_DRIVER, BRAND_NAME } from "./branding.js";
|
|
796
|
+
export { brandSystemPrompt, YAGNI_IDENTITY, YAGNI_IDENTITY_DRIVER, YAGNI_IDENTITY_ULTRA, BRAND_NAME } from "./branding.js";
|
|
797
|
+
// Ultra mode (/ultra): the aggressive fan-out/verify/synthesize dial.
|
|
798
|
+
export { createUltraHolder, registerUltraCommand } from "./ultra.js";
|
|
785
799
|
export { attributionHeaders, isDriverCaller, fetchCatalog, getToken, getWorkspaceId, resolveBaseUrl, sanitizeCallerSegment, } from "./config.js";
|
|
786
800
|
export { buildYagniProvider } from "./provider.js";
|
|
787
801
|
export { registerGoCommand } from "./pipeline/goCommand.js";
|
|
@@ -796,7 +810,7 @@ export { buildVerifyEnv, detectVerifyCommand, makeRunVerify, parseVerifyFailures
|
|
|
796
810
|
export { blindStages, reportOnlyStages, makeGroundedVsBlindEval, formatComparisonReport } from "./pipeline/eval.js";
|
|
797
811
|
export { registerGoCompareCommand } from "./pipeline/goCompareCommand.js";
|
|
798
812
|
// The general subagent tool: Claude Code-format agent discovery + fan-out.
|
|
799
|
-
export { registerSubagents, makeSubagentTool, discoverSubagents, parseAgentMarkdown, buildSubagentStage, formatAgentList, mapModelTier, SUBAGENT_TOOL_NAME, GENERAL_AGENT_NAME, MAX_PARALLEL_SUBAGENTS, DEFAULT_SUBAGENT_TOOLS, } from "./subagents.js";
|
|
813
|
+
export { registerSubagents, makeSubagentTool, discoverSubagents, parseAgentMarkdown, buildSubagentStage, formatAgentList, mapModelTier, SUBAGENT_TOOL_NAME, GENERAL_AGENT_NAME, MAX_PARALLEL_SUBAGENTS, MAX_PARALLEL_SUBAGENTS_ULTRA, DEFAULT_SUBAGENT_TOOLS, } from "./subagents.js";
|
|
800
814
|
// The session todo checklist: todo_write tool, widget renderer, /todos.
|
|
801
815
|
export { registerTodos, makeTodoTool, normalizeTodos, reconstructTodos, renderTodoWidget, formatTodoList, todoSummary, TODO_TOOL_NAME, MAX_TODOS, } from "./todos.js";
|
|
802
816
|
// P3 + W4: the permission gate seam (decideGate is pure; policy injectable) plus
|
|
@@ -20,11 +20,13 @@
|
|
|
20
20
|
import { type ExtensionAPI, type ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
21
21
|
import { Type } from "typebox";
|
|
22
22
|
import { runStage } from "./pipeline/runner.js";
|
|
23
|
-
import type
|
|
23
|
+
import { type ModelTier, type PipelineStage } from "./pipeline/types.js";
|
|
24
24
|
import { renderSubagentCall, renderSubagentResult } from "./subagentRender.js";
|
|
25
25
|
export declare const SUBAGENT_TOOL_NAME = "subagent";
|
|
26
26
|
export declare const GENERAL_AGENT_NAME = "general";
|
|
27
27
|
export declare const MAX_PARALLEL_SUBAGENTS = 4;
|
|
28
|
+
/** Wider fan-out ceiling while the session is in ultra mode (/ultra). */
|
|
29
|
+
export declare const MAX_PARALLEL_SUBAGENTS_ULTRA = 8;
|
|
28
30
|
/**
|
|
29
31
|
* The default tool surface a subagent gets when its definition declares none:
|
|
30
32
|
* the full working set plus grounded answers, mirroring what a Claude Code
|
|
@@ -92,6 +94,8 @@ export interface MakeSubagentToolDeps {
|
|
|
92
94
|
runStageImpl?: typeof runStage;
|
|
93
95
|
discover?: (deps: DiscoverDeps) => SubagentDef[];
|
|
94
96
|
homeDir?: string;
|
|
97
|
+
/** Live ultra-mode probe (/ultra): widens the per-call fan-out ceiling. */
|
|
98
|
+
isUltra?: () => boolean;
|
|
95
99
|
}
|
|
96
100
|
export declare function makeSubagentTool(deps?: MakeSubagentToolDeps): {
|
|
97
101
|
name: string;
|
|
@@ -135,6 +139,8 @@ export declare function makeSubagentTool(deps?: MakeSubagentToolDeps): {
|
|
|
135
139
|
export interface RegisterSubagentsDeps {
|
|
136
140
|
discover?: (deps: DiscoverDeps) => SubagentDef[];
|
|
137
141
|
homeDir?: string;
|
|
142
|
+
/** Live ultra-mode probe (/ultra): widens the per-call fan-out ceiling. */
|
|
143
|
+
isUltra?: () => boolean;
|
|
138
144
|
}
|
|
139
145
|
/** Wire the subagent tool and the /agents listing command. */
|
|
140
146
|
export declare function registerSubagents(pi: ExtensionAPI, deps?: RegisterSubagentsDeps): void;
|
|
@@ -23,7 +23,9 @@ import { delimiter, join } from "node:path";
|
|
|
23
23
|
import { parseFrontmatter } from "@earendil-works/pi-coding-agent";
|
|
24
24
|
import { Type } from "typebox";
|
|
25
25
|
import { sanitizeCallerSegment } from "./config.js";
|
|
26
|
+
import { withResilience } from "./pipeline/resilience.js";
|
|
26
27
|
import { runStage } from "./pipeline/runner.js";
|
|
28
|
+
import { DEFAULT_RESILIENCE_POLICY } from "./pipeline/types.js";
|
|
27
29
|
import { applyChildEvent, finalizeTask, formatWorkingMessage, newTaskProgress, progressSummaryText, renderSubagentCall, renderSubagentResult, } from "./subagentRender.js";
|
|
28
30
|
/**
|
|
29
31
|
* YAG-471 attribution: the `x-yagni-caller` prefix for a subagent invocation.
|
|
@@ -34,6 +36,8 @@ const SUBAGENT_CALLER_PREFIX = "subagent:";
|
|
|
34
36
|
export const SUBAGENT_TOOL_NAME = "subagent";
|
|
35
37
|
export const GENERAL_AGENT_NAME = "general";
|
|
36
38
|
export const MAX_PARALLEL_SUBAGENTS = 4;
|
|
39
|
+
/** Wider fan-out ceiling while the session is in ultra mode (/ultra). */
|
|
40
|
+
export const MAX_PARALLEL_SUBAGENTS_ULTRA = 8;
|
|
37
41
|
/**
|
|
38
42
|
* The default tool surface a subagent gets when its definition declares none:
|
|
39
43
|
* the full working set plus grounded answers, mirroring what a Claude Code
|
|
@@ -123,6 +127,50 @@ const IMPLEMENTER_AGENT = {
|
|
|
123
127
|
body: IMPLEMENTER_BODY,
|
|
124
128
|
source: "builtin",
|
|
125
129
|
};
|
|
130
|
+
const VERIFICATION_BODY = `You are an adversarial verifier. Another agent
|
|
131
|
+
produced work — a change, a plan, or a claim — and your job is to try to
|
|
132
|
+
BREAK it, not to summarize it. Default to skepticism: hunt for the concrete
|
|
133
|
+
failure scenario (the inputs, state, or sequence that makes it wrong). Bash
|
|
134
|
+
is read-only here (\`git diff\`, \`git log\`, \`git show\`); do NOT modify files
|
|
135
|
+
or run builds.
|
|
136
|
+
|
|
137
|
+
If your task names a lens (correctness, edge cases, codebase fit, security,
|
|
138
|
+
…), judge ONLY through that lens and leave the rest to your sibling
|
|
139
|
+
verifiers.
|
|
140
|
+
|
|
141
|
+
You are grounded in how THIS company works: call ask_yagni before inferring
|
|
142
|
+
a convention, an ownership rule, or anything organization-specific.
|
|
143
|
+
|
|
144
|
+
Your final message is your verdict back to the driving agent, which has NOT
|
|
145
|
+
seen what you read. Format:
|
|
146
|
+
## Verdict
|
|
147
|
+
BROKEN or HOLDS, with one sentence why.
|
|
148
|
+
## Findings
|
|
149
|
+
Each real problem: file:line, the concrete failure scenario, severity. No
|
|
150
|
+
style nits.
|
|
151
|
+
## Not verified
|
|
152
|
+
What you could not check, and why.
|
|
153
|
+
|
|
154
|
+
A HOLDS after real digging is valuable; a rubber stamp is not. If you found
|
|
155
|
+
nothing, say exactly what you tried to break and how.`;
|
|
156
|
+
/** The diamond's reduce layer: refute-first review of completed work on the
|
|
157
|
+
* advanced tier (judgment is the whole job, so the premium is worth paying —
|
|
158
|
+
* the server clamps subagent children at advanced anyway). It has no
|
|
159
|
+
* edit/write tools; bash is included for `git diff`-style inspection and is
|
|
160
|
+
* restricted to read-only USE by the persona, the same prompt-level stance as
|
|
161
|
+
* /go's reviewer — not a technical guarantee. */
|
|
162
|
+
const VERIFICATION_AGENT = {
|
|
163
|
+
name: "verification",
|
|
164
|
+
description: "Adversarial verification of completed work: tries to refute a change, " +
|
|
165
|
+
"plan, or claim and reports concrete failure scenarios. Does not edit " +
|
|
166
|
+
"files. Fan out 2-3 with different lenses (correctness, edge cases, " +
|
|
167
|
+
"codebase fit) for anything significant and treat agreement as " +
|
|
168
|
+
"confirmation.",
|
|
169
|
+
model: "advanced",
|
|
170
|
+
tools: ["read", "grep", "find", "ls", "bash", "ask_yagni"],
|
|
171
|
+
body: VERIFICATION_BODY,
|
|
172
|
+
source: "builtin",
|
|
173
|
+
};
|
|
126
174
|
// Concrete tiers a subagent can actually run on. `balanced` is deliberately NOT
|
|
127
175
|
// a member here even though it is a member of `ModelTier`: a subagent needs
|
|
128
176
|
// ONE model for its whole run, and balanced is a session-level routing policy,
|
|
@@ -210,7 +258,7 @@ function loadAgentsFromDir(dir, source) {
|
|
|
210
258
|
export function discoverSubagents(deps) {
|
|
211
259
|
const home = deps.homeDir ?? homedir();
|
|
212
260
|
const layers = [
|
|
213
|
-
[GENERAL_AGENT, SEARCHER_AGENT, IMPLEMENTER_AGENT],
|
|
261
|
+
[GENERAL_AGENT, SEARCHER_AGENT, IMPLEMENTER_AGENT, VERIFICATION_AGENT],
|
|
214
262
|
...pluginAgentDirs(deps.env ?? process.env).map((dir) => loadAgentsFromDir(dir, "plugin")),
|
|
215
263
|
loadAgentsFromDir(join(home, ".claude", "agents"), "user-claude"),
|
|
216
264
|
loadAgentsFromDir(join(deps.cwd, ".pi", "agents"), "project-pi"),
|
|
@@ -261,11 +309,17 @@ const parameters = Type.Object({
|
|
|
261
309
|
task: Type.String(),
|
|
262
310
|
agent: Type.Optional(Type.String()),
|
|
263
311
|
}), {
|
|
264
|
-
description: `Run several independent tasks in parallel (max ${MAX_PARALLEL_SUBAGENTS}). Use INSTEAD of task.`,
|
|
312
|
+
description: `Run several independent tasks in parallel (max ${MAX_PARALLEL_SUBAGENTS}; ${MAX_PARALLEL_SUBAGENTS_ULTRA} in ultra mode). Use INSTEAD of task.`,
|
|
265
313
|
})),
|
|
266
314
|
});
|
|
267
315
|
export function makeSubagentTool(deps = {}) {
|
|
268
|
-
|
|
316
|
+
// The default runner rides the /go pipeline's resilience wrapper, so a chat
|
|
317
|
+
// subagent gets the same idle + wall-clock ceilings and transient-only retry
|
|
318
|
+
// as a /go stage child (previously a hung subagent hung the tool call until
|
|
319
|
+
// the user pressed Esc). The synthetic stage id is "implement", so the
|
|
320
|
+
// wrapper's write-gate already refuses to re-run a child that may have
|
|
321
|
+
// landed a partial edit.
|
|
322
|
+
const run = deps.runStageImpl ?? withResilience(runStage, DEFAULT_RESILIENCE_POLICY);
|
|
269
323
|
const discover = deps.discover ?? discoverSubagents;
|
|
270
324
|
return {
|
|
271
325
|
name: SUBAGENT_TOOL_NAME,
|
|
@@ -293,8 +347,9 @@ export function makeSubagentTool(deps = {}) {
|
|
|
293
347
|
if (requested.length === 0) {
|
|
294
348
|
return fail("Error: pass `task` (or a `tasks` array) describing what to do.");
|
|
295
349
|
}
|
|
296
|
-
|
|
297
|
-
|
|
350
|
+
const maxParallel = deps.isUltra?.() ? MAX_PARALLEL_SUBAGENTS_ULTRA : MAX_PARALLEL_SUBAGENTS;
|
|
351
|
+
if (requested.length > maxParallel) {
|
|
352
|
+
return fail(`Error: at most ${maxParallel} parallel tasks per call.`);
|
|
298
353
|
}
|
|
299
354
|
const cwd = ctx?.cwd ?? process.cwd();
|
|
300
355
|
const agents = discover({ cwd, homeDir: deps.homeDir });
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ultra mode (/ultra) — an explicit, session-scoped dial for aggressive
|
|
3
|
+
* multi-agent orchestration ("the diamond": fan out → reduce → synthesize).
|
|
4
|
+
*
|
|
5
|
+
* Off by default so the trial-default behavior is unchanged; toggling on swaps
|
|
6
|
+
* the driver's delegation paragraph for the diamond directive (branding.ts's
|
|
7
|
+
* YAGNI_IDENTITY_ULTRA, read live per turn in index.ts) and widens the
|
|
8
|
+
* subagent tool's per-call fan-out ceiling (subagents.ts). Ultra is a prompt +
|
|
9
|
+
* ceiling change only: it never touches the permission mode, the model tier,
|
|
10
|
+
* or the /go pipeline.
|
|
11
|
+
*/
|
|
12
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
13
|
+
export interface UltraHolder {
|
|
14
|
+
get(): boolean;
|
|
15
|
+
set(on: boolean): void;
|
|
16
|
+
}
|
|
17
|
+
export declare function createUltraHolder(initial?: boolean): UltraHolder;
|
|
18
|
+
/**
|
|
19
|
+
* Wire the /ultra command onto a shared holder. No argument toggles; `on` /
|
|
20
|
+
* `off` set explicitly; `status` reports without changing anything.
|
|
21
|
+
*/
|
|
22
|
+
export declare function registerUltraCommand(pi: ExtensionAPI, holder: UltraHolder): void;
|
|
23
|
+
//# sourceMappingURL=ultra.d.ts.map
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ultra mode (/ultra) — an explicit, session-scoped dial for aggressive
|
|
3
|
+
* multi-agent orchestration ("the diamond": fan out → reduce → synthesize).
|
|
4
|
+
*
|
|
5
|
+
* Off by default so the trial-default behavior is unchanged; toggling on swaps
|
|
6
|
+
* the driver's delegation paragraph for the diamond directive (branding.ts's
|
|
7
|
+
* YAGNI_IDENTITY_ULTRA, read live per turn in index.ts) and widens the
|
|
8
|
+
* subagent tool's per-call fan-out ceiling (subagents.ts). Ultra is a prompt +
|
|
9
|
+
* ceiling change only: it never touches the permission mode, the model tier,
|
|
10
|
+
* or the /go pipeline.
|
|
11
|
+
*/
|
|
12
|
+
export function createUltraHolder(initial = false) {
|
|
13
|
+
let on = initial;
|
|
14
|
+
return {
|
|
15
|
+
get: () => on,
|
|
16
|
+
set: (v) => {
|
|
17
|
+
on = v;
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
/** Status chip shown while ultra is on (same footer surface as the /mode chip). */
|
|
22
|
+
const ULTRA_STATUS = "◆ ultra";
|
|
23
|
+
const ULTRA_ON_COPY = "Ultra mode ON: meaningful work fans out to parallel subagents, adversarial " +
|
|
24
|
+
"verification agents try to break the result, then the agent synthesizes. " +
|
|
25
|
+
"Expect more subagent spend per task.";
|
|
26
|
+
const ULTRA_OFF_COPY = "Ultra mode OFF: back to delegate-when-useful.";
|
|
27
|
+
/**
|
|
28
|
+
* Wire the /ultra command onto a shared holder. No argument toggles; `on` /
|
|
29
|
+
* `off` set explicitly; `status` reports without changing anything.
|
|
30
|
+
*/
|
|
31
|
+
export function registerUltraCommand(pi, holder) {
|
|
32
|
+
pi.registerCommand("ultra", {
|
|
33
|
+
description: "Toggle ultra mode: aggressive fan-out/verify/synthesize orchestration. /ultra on | off | status.",
|
|
34
|
+
handler: async (args, ctx) => {
|
|
35
|
+
const notify = (m, t) => {
|
|
36
|
+
if (ctx.hasUI)
|
|
37
|
+
ctx.ui.notify(m, t);
|
|
38
|
+
};
|
|
39
|
+
const arg = args.trim().toLowerCase();
|
|
40
|
+
if (arg && arg !== "on" && arg !== "off" && arg !== "status") {
|
|
41
|
+
notify(`Unknown argument "${arg}". Use /ultra, /ultra on, /ultra off, or /ultra status.`, "warning");
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
if (arg === "status") {
|
|
45
|
+
notify(holder.get() ? ULTRA_ON_COPY : ULTRA_OFF_COPY, "info");
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const next = arg === "on" ? true : arg === "off" ? false : !holder.get();
|
|
49
|
+
holder.set(next);
|
|
50
|
+
try {
|
|
51
|
+
if (ctx.hasUI)
|
|
52
|
+
ctx.ui.setStatus?.("yagni-ultra", next ? ULTRA_STATUS : undefined);
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
// The chip is chrome; never let it break /ultra.
|
|
56
|
+
}
|
|
57
|
+
notify(next ? ULTRA_ON_COPY : ULTRA_OFF_COPY, "info");
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=ultra.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yagni-app/code-staging",
|
|
3
|
-
"version": "0.3.0-staging.
|
|
3
|
+
"version": "0.3.0-staging.1085.1",
|
|
4
4
|
"description": "YAGNI Code: a terminal coding agent that already knows your company. One YAGNI login routes the model and grounds the agent in your team's context.",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
6
6
|
"author": "YAGNI, Inc. <jack@yagni.app> (https://yagni.app)",
|
|
@@ -38,5 +38,5 @@
|
|
|
38
38
|
"@earendil-works/pi-tui": "0.84.1",
|
|
39
39
|
"typebox": "^1.3.11"
|
|
40
40
|
},
|
|
41
|
-
"yagniSourceSha": "
|
|
41
|
+
"yagniSourceSha": "2af1762b42b06fc1e55b7f85fbbed71ce3bd3272"
|
|
42
42
|
}
|