aiden-runtime 4.6.1 → 4.8.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.
- package/README.md +499 -265
- package/dist/cli/v4/aidenCLI.js +44 -5
- package/dist/cli/v4/callbacks.js +52 -31
- package/dist/cli/v4/chatSession.js +46 -1
- package/dist/cli/v4/commands/help.js +22 -11
- package/dist/cli/v4/commands/runs.js +42 -24
- package/dist/cli/v4/commands/skills.js +15 -17
- package/dist/cli/v4/commands/usage.js +17 -5
- package/dist/cli/v4/daemonAgentBuilder.js +13 -4
- package/dist/cli/v4/design/tokens.js +265 -0
- package/dist/cli/v4/display/framedPanel.js +116 -0
- package/dist/cli/v4/display/toolTrail.js +2 -2
- package/dist/cli/v4/display.js +446 -164
- package/dist/cli/v4/onboarding/disclaimer.js +42 -10
- package/dist/cli/v4/onboarding/loading.js +24 -1
- package/dist/cli/v4/onboarding/successScreen.js +17 -8
- package/dist/cli/v4/replyRenderer.js +74 -58
- package/dist/cli/v4/setupWizard.js +19 -2
- package/dist/cli/v4/skinEngine.js +13 -0
- package/dist/cli/v4/table.js +65 -8
- package/dist/core/v4/aidenAgent.js +42 -14
- package/dist/core/v4/auxiliaryClient.js +46 -13
- package/dist/core/v4/daemon/dispatcher/realAgentRunner.js +13 -8
- package/dist/core/v4/promptBuilder.js +45 -0
- package/dist/core/v4/sandboxFs.js +1 -1
- package/dist/core/v4/subagent/childBuilder.js +13 -4
- package/dist/core/v4/subagent/spawnSubAgent.js +7 -1
- package/dist/core/v4/ui/banner.js +16 -16
- package/dist/core/version.js +1 -1
- package/dist/moat/approvalEngine.js +14 -0
- package/dist/moat/honestyEnforcement.js +143 -241
- package/dist/tools/v4/index.js +54 -0
- package/dist/tools/v4/subagent/spawnSubAgentTool.js +23 -0
- package/package.json +10 -4
|
@@ -45,19 +45,35 @@ class AuxiliaryClient {
|
|
|
45
45
|
return this.opts.adapter;
|
|
46
46
|
if (!this.opts.resolver)
|
|
47
47
|
return null;
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
48
|
+
// v4.8.0 Slice 11 — resolution chain: default first, then each
|
|
49
|
+
// fallback in order. The first attempt that resolves wins. This
|
|
50
|
+
// is the routing-fix entry point for the chatgpt-plus + gpt-5
|
|
51
|
+
// bug: aidenCLI hands us Groq as the default and the parent
|
|
52
|
+
// provider/model as the fallback, so auxiliary calls land on
|
|
53
|
+
// Groq when configured and the parent only sees traffic when
|
|
54
|
+
// Groq is absent.
|
|
55
|
+
const attempts = [
|
|
56
|
+
{ providerId: this.opts.defaultProvider, modelId: this.opts.defaultModel },
|
|
57
|
+
...(this.opts.fallbacks ?? []),
|
|
58
|
+
];
|
|
59
|
+
const failures = [];
|
|
60
|
+
for (const att of attempts) {
|
|
61
|
+
this.resolveCallCount += 1;
|
|
62
|
+
try {
|
|
63
|
+
const adapter = await this.opts.resolver.resolve({
|
|
64
|
+
providerId: att.providerId,
|
|
65
|
+
modelId: att.modelId,
|
|
66
|
+
});
|
|
67
|
+
this.warn(`auxiliary resolved via ${att.providerId}/${att.modelId}`);
|
|
68
|
+
return adapter;
|
|
69
|
+
}
|
|
70
|
+
catch (err) {
|
|
71
|
+
failures.push(`${att.providerId}/${att.modelId}: ${err.message}`);
|
|
72
|
+
}
|
|
60
73
|
}
|
|
74
|
+
this.warn(`auxiliary client unavailable (tried ${attempts.length}): ${failures.join('; ')}`);
|
|
75
|
+
this.adapterUnavailable = true;
|
|
76
|
+
return null;
|
|
61
77
|
}
|
|
62
78
|
/** Resolve count for tests (verifies single-resolution behaviour). */
|
|
63
79
|
_resolveCallCount() {
|
|
@@ -122,7 +138,24 @@ class AuxiliaryClient {
|
|
|
122
138
|
this.usage.set(purpose, cur);
|
|
123
139
|
}
|
|
124
140
|
warn(msg) {
|
|
125
|
-
|
|
141
|
+
// v4.8.0 Slice 5 — gate console output behind AIDEN_VERBOSE.
|
|
142
|
+
// Auxiliary failures are recoverable (the main loop continues;
|
|
143
|
+
// result content is just empty), so the warning is pure noise
|
|
144
|
+
// for end users. Power users set AIDEN_VERBOSE=1 to surface them.
|
|
145
|
+
// Inline env-read preserves the core → cli no-import invariant;
|
|
146
|
+
// canonical isVerbose() lives at cli/v4/design/tokens.ts.
|
|
147
|
+
//
|
|
148
|
+
// v4.8.0 Slice 11 — if opts.warn is explicitly injected, always
|
|
149
|
+
// forward (tests + advanced callers register their own sink and
|
|
150
|
+
// expect every message). The AIDEN_VERBOSE gate now applies only
|
|
151
|
+
// to the default console.warn fallback that end-users see.
|
|
152
|
+
if (this.opts.warn) {
|
|
153
|
+
this.opts.warn(msg);
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
if (process.env.AIDEN_VERBOSE !== '1')
|
|
157
|
+
return;
|
|
158
|
+
console.warn(`[auxiliary] ${msg}`);
|
|
126
159
|
}
|
|
127
160
|
async withTimeout(p, ms) {
|
|
128
161
|
return new Promise((resolve, reject) => {
|
|
@@ -177,14 +177,19 @@ function createRealAgentRunner(opts) {
|
|
|
177
177
|
let invocationError = null;
|
|
178
178
|
try {
|
|
179
179
|
result = await agent.runConversation(history, {
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
180
|
+
// The agent honours its own abort signal via per-tool aborts;
|
|
181
|
+
// tools that respect AbortSignal (shell_exec, fetch_*) will
|
|
182
|
+
// bail when perTurnWatcher trips.
|
|
183
|
+
//
|
|
184
|
+
// Note: runConversation doesn't currently take an abort
|
|
185
|
+
// signal in its options — the budget watcher is best-effort
|
|
186
|
+
// observability via tally(). Future enhancement: thread the
|
|
187
|
+
// signal into the loop body via options.
|
|
188
|
+
//
|
|
189
|
+
// v4.8.0 Phase 2.2 — uiOnly events on the daemon side are
|
|
190
|
+
// dropped here. Phase 2.4 will serialize them into the
|
|
191
|
+
// dispatcher's run_events stream.
|
|
192
|
+
onUiEvent: () => { },
|
|
188
193
|
});
|
|
189
194
|
// Stamp the actual token usage onto the watcher for the
|
|
190
195
|
// post-turn snapshot below.
|
|
@@ -131,6 +131,42 @@ const EXECUTION_DISCIPLINE_PROSE = [
|
|
|
131
131
|
'result. When the user requests an action, take it. When the user requests',
|
|
132
132
|
'discussion, discuss.',
|
|
133
133
|
].join('\n');
|
|
134
|
+
/**
|
|
135
|
+
* v4.8.0 Phase 2.6 — UI events nudge. Without this, the model only
|
|
136
|
+
* emits ui_* tools when explicitly told to (e.g. "call ui_task_update
|
|
137
|
+
* with ..."). With it, events fire during normal multi-step work —
|
|
138
|
+
* research, file creation, test runs, command execution. Always-on:
|
|
139
|
+
* every model that sees the ui_* tools benefits.
|
|
140
|
+
*/
|
|
141
|
+
const UI_EVENTS_GUIDANCE = [
|
|
142
|
+
'## UI events',
|
|
143
|
+
'',
|
|
144
|
+
'When doing multi-step work, emit structured progress signals INSTEAD OF',
|
|
145
|
+
'writing them as text. The user sees these as inline rows separate from',
|
|
146
|
+
'your prose reply.',
|
|
147
|
+
'',
|
|
148
|
+
'WRONG (do NOT do this):',
|
|
149
|
+
' "✓ Done — found 3 results"',
|
|
150
|
+
' "⟳ Searching the web..."',
|
|
151
|
+
' "Created hello.py"',
|
|
152
|
+
'',
|
|
153
|
+
'RIGHT:',
|
|
154
|
+
' ui_task_update {task_id, label, status: "running"}',
|
|
155
|
+
' ui_task_done {task_id, status: "success", summary}',
|
|
156
|
+
' ui_artifact_created {path, kind: "file", preview}',
|
|
157
|
+
'',
|
|
158
|
+
'When to fire each:',
|
|
159
|
+
'- ui_task_update + ui_task_done for any multi-step task (pair them by task_id)',
|
|
160
|
+
'- ui_command_result after shell_exec when the output is interesting',
|
|
161
|
+
'- ui_test_result after running tests',
|
|
162
|
+
'- ui_toast for transient notices (e.g. "switched to dark mode")',
|
|
163
|
+
'- ui_artifact_created when you create or modify a file/skill',
|
|
164
|
+
'- ui_approval_request fires automatically for risky tools — NEVER emit it manually',
|
|
165
|
+
'',
|
|
166
|
+
'Markdown text in your reply is for explanation, not status. Status goes',
|
|
167
|
+
'through events. Skip events entirely on single-shot queries that aren\'t',
|
|
168
|
+
'multi-step work.',
|
|
169
|
+
].join('\n');
|
|
134
170
|
/**
|
|
135
171
|
* Llama-3.3-specific tool-call format guard. Adapter-side recovery picks
|
|
136
172
|
* up failures, but we'd rather avoid the 400 round-trip.
|
|
@@ -358,6 +394,15 @@ class PromptBuilder {
|
|
|
358
394
|
optional: true,
|
|
359
395
|
});
|
|
360
396
|
}
|
|
397
|
+
// ── 6.6. UI events nudge (v4.8.0 Phase 2.6) ───────────────────────
|
|
398
|
+
// Unconditional like execution discipline — every model that sees
|
|
399
|
+
// the ui_* tools benefits. Teaches structured-event emission for
|
|
400
|
+
// multi-step work instead of relying on text status formatting.
|
|
401
|
+
slots.push({
|
|
402
|
+
name: 'uiEvents',
|
|
403
|
+
content: UI_EVENTS_GUIDANCE,
|
|
404
|
+
optional: true,
|
|
405
|
+
});
|
|
361
406
|
// ── 7. Iteration budget ───────────────────────────────────────────
|
|
362
407
|
if (opts.initialBudget) {
|
|
363
408
|
const { used, max } = opts.initialBudget;
|
|
@@ -94,7 +94,7 @@ function expandPathInline(input, cwd) {
|
|
|
94
94
|
}
|
|
95
95
|
/**
|
|
96
96
|
* Boundary-aware containment check. `path.relative` avoids the
|
|
97
|
-
*
|
|
97
|
+
* `<root>/user-evil` vs `<root>/user` false positive that a naive
|
|
98
98
|
* `startsWith` would produce.
|
|
99
99
|
*/
|
|
100
100
|
function isWithin(child, parent) {
|
|
@@ -33,6 +33,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
33
33
|
exports.ProviderNotFoundError = exports.SUBAGENT_BLOCKED_TOOL_NAMES = void 0;
|
|
34
34
|
exports.buildChildAgent = buildChildAgent;
|
|
35
35
|
const approvalEngine_1 = require("../../../moat/approvalEngine");
|
|
36
|
+
const honestyEnforcement_1 = require("../../../moat/honestyEnforcement");
|
|
36
37
|
const aidenAgent_1 = require("../aidenAgent");
|
|
37
38
|
const providerFallback_1 = require("../providerFallback");
|
|
38
39
|
// ── Hard-coded blocklist (Q5 from design doc §2) ────────────────────────────
|
|
@@ -177,10 +178,16 @@ function buildChildAgent(deps, input) {
|
|
|
177
178
|
// Pure no-op when runStore is absent (unit tests of buildChildAgent).
|
|
178
179
|
const onToolCall = buildOnToolCall(deps);
|
|
179
180
|
// ── 7. Build the child agent ─────────────────────────────────────────────
|
|
180
|
-
// Focused worker config: omit plannerGuard,
|
|
181
|
-
//
|
|
182
|
-
//
|
|
183
|
-
//
|
|
181
|
+
// Focused worker config: omit plannerGuard, skillTeacher, skillMiner,
|
|
182
|
+
// contextCompressor, promptCaching, promptBuilder. Match the daemon
|
|
183
|
+
// agent's "act on the task, don't self-improve" shape.
|
|
184
|
+
//
|
|
185
|
+
// v4.7.0: HonestyEnforcement is now structural (reads tool trace only,
|
|
186
|
+
// no natural-language scanning) and cheap enough to run in subagents.
|
|
187
|
+
// Mode is 'detect' here — events are captured into the child's run
|
|
188
|
+
// record but never produce user-visible output (subagents have no
|
|
189
|
+
// chat surface; the parent assembles their summary).
|
|
190
|
+
const childHonestyEnforcement = new honestyEnforcement_1.HonestyEnforcement('detect');
|
|
184
191
|
const agent = new aidenAgent_1.AidenAgent({
|
|
185
192
|
provider: childProvider,
|
|
186
193
|
tools: childTools,
|
|
@@ -192,6 +199,8 @@ function buildChildAgent(deps, input) {
|
|
|
192
199
|
resolveVerifiedFlag: deps.resolveVerifiedFlag,
|
|
193
200
|
resolveToolset: deps.resolveToolset,
|
|
194
201
|
resolveMutates: deps.resolveMutates,
|
|
202
|
+
resolveUiOnly: deps.resolveUiOnly,
|
|
203
|
+
honestyEnforcement: childHonestyEnforcement,
|
|
195
204
|
onToolCall,
|
|
196
205
|
// iterationBudgetInjection inherits the default (true) — child
|
|
197
206
|
// sees its own remaining-budget hint near the end of the run.
|
|
@@ -190,7 +190,13 @@ async function spawnSubAgent(spec, deps, ctx) {
|
|
|
190
190
|
let tokensIn = 0;
|
|
191
191
|
let tokensOut = 0;
|
|
192
192
|
try {
|
|
193
|
-
const result = await agentBundle.agent.runConversation(agentBundle.history, {
|
|
193
|
+
const result = await agentBundle.agent.runConversation(agentBundle.history, {
|
|
194
|
+
signal: childCtrl.signal,
|
|
195
|
+
// v4.8.0 Phase 2.2 — uiOnly events from a subagent are
|
|
196
|
+
// dropped. Subagents have no chat surface; the parent
|
|
197
|
+
// assembles their summary. Stub stays a no-op forever.
|
|
198
|
+
onUiEvent: () => { },
|
|
199
|
+
});
|
|
194
200
|
apiCalls = result.turnCount; // one provider call per turn
|
|
195
201
|
tokensIn = result.totalUsage.inputTokens;
|
|
196
202
|
tokensOut = result.totalUsage.outputTokens;
|
|
@@ -90,29 +90,29 @@ function renderBanner(opts) {
|
|
|
90
90
|
out.push('');
|
|
91
91
|
return out.join('\n') + '\n';
|
|
92
92
|
}
|
|
93
|
-
//
|
|
93
|
+
// v4.8.0 Slice 10b — wide layout flows the AIDEN art without the
|
|
94
|
+
// heavy `╔══╗` frame (legacy chrome). The art carries its own
|
|
95
|
+
// visual weight as the boot-card identity anchor; framing it
|
|
96
|
+
// inside a closed box collides with the asymmetric orange-bar
|
|
97
|
+
// language used by every other v4.8.0 surface.
|
|
98
|
+
//
|
|
99
|
+
// v4.8.0 Slice 10c — emit raw 24-bit truecolor for the AIDEN art
|
|
100
|
+
// instead of routing through `c.primary` (which depth-detects via
|
|
101
|
+
// theme.ts and degrades to 256-color or 16-color when COLORTERM is
|
|
102
|
+
// unset — common on Windows ConPTY). Result on those terminals was
|
|
103
|
+
// a washed-out / grey AIDEN that didn't match the boot card's
|
|
104
|
+
// skinEngine-painted brand orange. Forcing truecolor here brings
|
|
105
|
+
// disclaimer + setupWizard banner in line with the boot card.
|
|
106
|
+
const ORANGE_ON = '\x1b[38;2;255;107;53m';
|
|
107
|
+
const COLOR_OFF = '\x1b[39m';
|
|
94
108
|
const inner = w - 2;
|
|
95
109
|
const artPad = Math.max(0, Math.floor((inner - ART_WIDTH) / 2));
|
|
96
|
-
const framed = opts.framed !== false;
|
|
97
|
-
const horiz = '═'.repeat(inner);
|
|
98
|
-
const top = framed ? theme_1.c.rule(`╔${horiz}╗`) : '';
|
|
99
|
-
const bottom = framed ? theme_1.c.rule(`╚${horiz}╝`) : '';
|
|
100
|
-
const blank = framed
|
|
101
|
-
? `${theme_1.c.rule('║')}${' '.repeat(inner)}${theme_1.c.rule('║')}`
|
|
102
|
-
: ' '.repeat(w);
|
|
103
110
|
const lines = [];
|
|
104
111
|
lines.push('');
|
|
105
|
-
if (framed)
|
|
106
|
-
lines.push(top);
|
|
107
|
-
lines.push(blank);
|
|
108
112
|
for (const row of AIDEN_ART) {
|
|
109
113
|
const padded = rpad(' '.repeat(artPad) + row, inner);
|
|
110
|
-
|
|
111
|
-
lines.push(framed ? `${theme_1.c.rule('║')}${coloured}${theme_1.c.rule('║')}` : ` ${coloured}`);
|
|
114
|
+
lines.push(` ${ORANGE_ON}${padded}${COLOR_OFF}`);
|
|
112
115
|
}
|
|
113
|
-
lines.push(blank);
|
|
114
|
-
if (framed)
|
|
115
|
-
lines.push(bottom);
|
|
116
116
|
lines.push('');
|
|
117
117
|
lines.push(' ' + (0, theme_1.dim)(theme_1.c.muted(versionLine)));
|
|
118
118
|
lines.push('');
|
package/dist/core/version.js
CHANGED
|
@@ -237,6 +237,20 @@ class ApprovalEngine {
|
|
|
237
237
|
this.callbacks.onDecision?.(req, 'deny');
|
|
238
238
|
return false;
|
|
239
239
|
}
|
|
240
|
+
// v4.8.0 Phase 2.5 — emit a structured ui_approval_request event
|
|
241
|
+
// BEFORE the y/n prompt fires. Additive: the display layer paints
|
|
242
|
+
// the gutter-integrated row, then the existing promptUser flow
|
|
243
|
+
// runs unchanged. Moat-tier (safe/caution/dangerous) maps to the
|
|
244
|
+
// ui schema's 4-tier scale; 'critical' is reserved for future
|
|
245
|
+
// wiring and unreachable from this path.
|
|
246
|
+
const uiTier = req.riskTier === 'safe' ? 'low' :
|
|
247
|
+
req.riskTier === 'dangerous' ? 'high' : 'medium';
|
|
248
|
+
const argsPreview = JSON.stringify(req.args).slice(0, 80);
|
|
249
|
+
this.callbacks.onUiEvent?.('ui_approval_request', {
|
|
250
|
+
prompt: `${req.toolName} ${argsPreview}`,
|
|
251
|
+
risk_tier: uiTier,
|
|
252
|
+
reason: req.reason,
|
|
253
|
+
});
|
|
240
254
|
const decision = await this.callbacks.promptUser(req);
|
|
241
255
|
this.callbacks.onDecision?.(req, decision);
|
|
242
256
|
if (decision === 'deny')
|