praxis-agent 0.14.0 → 0.16.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 +5 -2
- package/dist/application/session-service.d.ts +18 -0
- package/dist/application/session-service.js +180 -41
- package/dist/application/subagent-service.d.ts +7 -1
- package/dist/application/subagent-service.js +238 -53
- package/dist/cli/interactive.d.ts +7 -1
- package/dist/cli/interactive.js +77 -3
- package/dist/cli/protocol.d.ts +13 -0
- package/dist/cli/protocol.js +34 -0
- package/dist/cli/tui/claude-command-inventory.d.ts +1 -2
- package/dist/cli/tui/claude-command-inventory.js +1 -6
- package/dist/cli/tui/claude-style.d.ts +4 -1
- package/dist/cli/tui/claude-style.js +8 -3
- package/dist/cli/tui/slash-commands.d.ts +1 -0
- package/dist/cli/tui/slash-commands.js +11 -0
- package/dist/cli/tui/theme.d.ts +2 -0
- package/dist/cli/tui/theme.js +69 -0
- package/dist/cli.d.ts +6 -0
- package/dist/cli.js +95 -27
- package/dist/compatibility/claude/agent-color.d.ts +25 -0
- package/dist/compatibility/claude/agent-color.js +79 -0
- package/dist/compatibility/claude/fork.js +5 -1
- package/dist/compatibility/claude/schema.js +13 -1
- package/dist/extensions/claude-extensions.d.ts +19 -1
- package/dist/extensions/claude-extensions.js +126 -1
- package/dist/hooks/claude-hooks.d.ts +3 -1
- package/dist/hooks/claude-hooks.js +14 -0
- package/dist/mcp/claude-mcp-tools.d.ts +18 -0
- package/dist/mcp/claude-mcp-tools.js +46 -0
- package/dist/persistence/claude-transcript-store.js +1 -0
- package/dist/tools/claude-interactive-tools.d.ts +1 -0
- package/dist/tools/claude-interactive-tools.js +3 -0
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -95,7 +95,8 @@ troubleshooting. Run `praxis --help` for the authoritative command surface.
|
|
|
95
95
|
tabs, `/sandbox` mode/dependency/override/config controls, local cached
|
|
96
96
|
`/release-notes`, Claude-compatible `/statusline` command execution and setup
|
|
97
97
|
agent, source-aligned `/init` project-instruction onboarding with its enhanced
|
|
98
|
-
skills/hooks flow,
|
|
98
|
+
skills/hooks flow, provider-free per-session `/color` prompt-bar styling,
|
|
99
|
+
`/mcp`, `/memory` shared instruction and auto-memory
|
|
99
100
|
access, and live extension-reload controls,
|
|
100
101
|
cursor/history composer, per-session model/effort/permission controls,
|
|
101
102
|
context/status/skill/task dashboards, prompt stash and continuation shortcuts,
|
|
@@ -137,7 +138,9 @@ troubleshooting. Run `praxis --help` for the authoritative command surface.
|
|
|
137
138
|
workspace-directory add/remove controls, path confinement, credential
|
|
138
139
|
redaction, and sanitized child processes.
|
|
139
140
|
- **Durable local work** — resumable sessions, full-history forks, file
|
|
140
|
-
checkpoints, tasks, foreground/background subagents,
|
|
141
|
+
checkpoints, tasks, foreground/background subagents, top-level agents, and
|
|
142
|
+
Claude-compatible main-thread agent definitions with native prompt, model,
|
|
143
|
+
tool, memory, first-turn, and resume behavior.
|
|
141
144
|
- **Claude-compatible ecosystem** — shared instructions with recursive `@`
|
|
142
145
|
imports, memory, skills, commands, agents, hooks, settings, MCP servers,
|
|
143
146
|
plugins, and transcript data.
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type AgentColorName, type AgentColorSelection } from '../compatibility/claude/agent-color.js';
|
|
1
2
|
import type { ClaudeConditionalRuleResolver } from '../compatibility/claude/context.js';
|
|
2
3
|
import { type ClaudeFileResource, type ClaudeFileResourceConfig } from '../compatibility/claude/file-resources.js';
|
|
3
4
|
import { type ClaudeDisplayTranscriptItem } from '../compatibility/claude/projection.js';
|
|
@@ -24,6 +25,7 @@ export interface ClaudeSessionServiceOptions {
|
|
|
24
25
|
tools?: ToolRegistry;
|
|
25
26
|
permissions?: PermissionResolver;
|
|
26
27
|
permissionResolverForMode?: (mode: AgentPermissionMode) => PermissionResolver;
|
|
28
|
+
permissionMode?: ClaudePermissionMode;
|
|
27
29
|
persistPermissionUpdates?: (updates: readonly PermissionUpdate[]) => void | Promise<void>;
|
|
28
30
|
approveTool?: (call: ModelToolCall, originalCall?: ModelToolCall, decision?: PermissionDecision) => PermissionApproval | Promise<PermissionApproval>;
|
|
29
31
|
approveRecovery?: (call: ModelToolCall) => boolean | Promise<boolean>;
|
|
@@ -43,6 +45,11 @@ export interface ClaudeSessionServiceOptions {
|
|
|
43
45
|
enableDynamicWakeups?: boolean;
|
|
44
46
|
enableWorkflows?: boolean;
|
|
45
47
|
providerForModel?: (model: string) => ModelProvider;
|
|
48
|
+
providerForMainModel?: (model: string) => ModelProvider;
|
|
49
|
+
explicitModel?: boolean;
|
|
50
|
+
explicitSystemPrompt?: boolean;
|
|
51
|
+
agentInitialPromptHandledExternally?: boolean;
|
|
52
|
+
agentSystemPromptOverridesExplicit?: boolean;
|
|
46
53
|
effort?: string;
|
|
47
54
|
maxModelTurns?: number;
|
|
48
55
|
betas?: readonly string[];
|
|
@@ -149,6 +156,7 @@ export declare class ClaudeSessionService {
|
|
|
149
156
|
private readonly hostedSubagentsByRegistry;
|
|
150
157
|
private readonly backgroundNotificationWrites;
|
|
151
158
|
private readonly downloadedFileResourceSessions;
|
|
159
|
+
private activeProvider;
|
|
152
160
|
private mcpClosePromise;
|
|
153
161
|
private runtimeCwd;
|
|
154
162
|
constructor(options: ClaudeSessionServiceOptions);
|
|
@@ -175,6 +183,7 @@ export declare class ClaudeSessionService {
|
|
|
175
183
|
sessionNameSuggestion(sessionId: string, signal?: AbortSignal): Promise<string | null>;
|
|
176
184
|
sessions(): Promise<SessionSummary[]>;
|
|
177
185
|
inspect(sessionId: string): Promise<SessionInspection>;
|
|
186
|
+
readEffectiveAgentColor(sessionId: string): Promise<AgentColorName | undefined>;
|
|
178
187
|
export(sessionId: string): Promise<Buffer>;
|
|
179
188
|
transcript(sessionId: string, resumeSessionAt?: string): Promise<ClaudeDisplayTranscriptItem[]>;
|
|
180
189
|
rename(sessionId: string, name: string): Promise<void>;
|
|
@@ -183,6 +192,9 @@ export declare class ClaudeSessionService {
|
|
|
183
192
|
approveRecentlyDenied(sessionId: string, display: string): Promise<void>;
|
|
184
193
|
retryRecentlyDenied(sessionId: string, display: string, signal?: AbortSignal): Promise<SessionRunResult>;
|
|
185
194
|
recordBtwUsage(sessionId: string | undefined, permissionMode?: ClaudePermissionMode): Promise<string>;
|
|
195
|
+
recordColorUsage(sessionId: string | undefined, selection: AgentColorSelection, display: string, permissionMode?: ClaudePermissionMode, options?: {
|
|
196
|
+
createSession?: boolean;
|
|
197
|
+
}): Promise<string>;
|
|
186
198
|
recordBackgroundUsage(sessionId: string | undefined, permissionMode?: ClaudePermissionMode): Promise<string>;
|
|
187
199
|
recordBackgroundLaunch(sessionId: string): Promise<SessionForkCheckpoint>;
|
|
188
200
|
compact(sessionId: string, signal?: AbortSignal, selection?: ManualCompactSelection): Promise<ManualCompactResult>;
|
|
@@ -207,6 +219,7 @@ export declare class ClaudeSessionService {
|
|
|
207
219
|
private restoreWorktree;
|
|
208
220
|
private paths;
|
|
209
221
|
private appendCdCommand;
|
|
222
|
+
private appendAgentColorUsage;
|
|
210
223
|
private appendSystemLocalCommand;
|
|
211
224
|
private ensureLocalSession;
|
|
212
225
|
private appendInputHistory;
|
|
@@ -221,6 +234,11 @@ export declare class ClaudeSessionService {
|
|
|
221
234
|
private assertWritable;
|
|
222
235
|
private sessionStatus;
|
|
223
236
|
private provider;
|
|
237
|
+
model(): string | undefined;
|
|
238
|
+
private providerForAgent;
|
|
239
|
+
private resolveAgent;
|
|
240
|
+
private mainAgentSystemPrompt;
|
|
241
|
+
private assembledSystemMessages;
|
|
224
242
|
private contextBudget;
|
|
225
243
|
private append;
|
|
226
244
|
private logicalTailUuid;
|
|
@@ -2,6 +2,7 @@ import { randomUUID } from 'node:crypto';
|
|
|
2
2
|
import { appendFile, copyFile, link, lstat, mkdir, readdir, realpath, stat, unlink, } from 'node:fs/promises';
|
|
3
3
|
import { homedir } from 'node:os';
|
|
4
4
|
import { basename, extname, isAbsolute, join, relative } from 'node:path';
|
|
5
|
+
import { AGENT_COLOR_DEFAULT, agentColorMessage, getClaudeEffectiveAgentColor, } from '../compatibility/claude/agent-color.js';
|
|
5
6
|
import { createClaudeCompactEntries, formatClaudeCompactSummary, getCumulativeDroppedTokens, } from '../compatibility/claude/compaction.js';
|
|
6
7
|
import { isClaudeSessionId, resolveClaudePaths, resolveClaudeScheduledTaskFile, } from '../compatibility/claude/paths.js';
|
|
7
8
|
import { downloadClaudeFileResources, } from '../compatibility/claude/file-resources.js';
|
|
@@ -22,7 +23,7 @@ import { ClaudeHookToolCoordinator } from '../hooks/claude-hook-tools.js';
|
|
|
22
23
|
import { ClaudeTranscriptStore, } from '../persistence/claude-transcript-store.js';
|
|
23
24
|
import { InMemoryTranscriptStore } from '../persistence/in-memory-transcript-store.js';
|
|
24
25
|
import { ModelCompactor } from './model-compactor.js';
|
|
25
|
-
import { ClaudeSubagentExecutor, StructuredOutputRegistry, } from './subagent-service.js';
|
|
26
|
+
import { agentMemoryPrompt, ClaudeSubagentExecutor, StructuredOutputRegistry, } from './subagent-service.js';
|
|
26
27
|
import { ScheduledPromptManager } from './scheduled-prompt-manager.js';
|
|
27
28
|
import { ClaudeScheduledToolRegistry } from '../tools/claude-scheduled-tools.js';
|
|
28
29
|
import { ClaudeTaskToolRegistry } from '../tools/claude-task-tools.js';
|
|
@@ -30,8 +31,29 @@ import { ClaudeWorkflowToolRegistry } from '../tools/claude-workflow-tools.js';
|
|
|
30
31
|
import { WorkflowManager, } from './workflow-manager.js';
|
|
31
32
|
import { SessionWorktreeManager } from './session-worktree.js';
|
|
32
33
|
import { ClaudeWorktreeToolRegistry } from '../tools/claude-worktree-tools.js';
|
|
34
|
+
import { FilteredToolRegistry } from '../tools/filtered-tool-registry.js';
|
|
33
35
|
import { generateToolUseSummary } from './tool-use-summary.js';
|
|
34
36
|
import { ClaudeUserMessageToolRegistry, CLAUDE_USER_MESSAGE_PROMPT, } from '../tools/claude-user-message.js';
|
|
37
|
+
function agentPermissionMode(mode) {
|
|
38
|
+
return mode === undefined || mode === 'manual' ? 'default' : mode;
|
|
39
|
+
}
|
|
40
|
+
function agentToolName(rule) {
|
|
41
|
+
const opening = rule.indexOf('(');
|
|
42
|
+
return (opening < 0 ? rule : rule.slice(0, opening)).trim();
|
|
43
|
+
}
|
|
44
|
+
function mainAgentToolNames(tools, agent) {
|
|
45
|
+
const requested = agent.tools ? new Set(agent.tools.map(agentToolName)) : null;
|
|
46
|
+
if (requested && agent.memory) {
|
|
47
|
+
requested.add('Read');
|
|
48
|
+
requested.add('Edit');
|
|
49
|
+
requested.add('Write');
|
|
50
|
+
}
|
|
51
|
+
const disallowed = new Set(agent.disallowedTools?.map(agentToolName) ?? []);
|
|
52
|
+
return tools
|
|
53
|
+
.definitions()
|
|
54
|
+
.map(({ name }) => name)
|
|
55
|
+
.filter((name) => (!requested || requested.has(name)) && !disallowed.has(name));
|
|
56
|
+
}
|
|
35
57
|
const emptyToolRegistry = {
|
|
36
58
|
definitions: () => [],
|
|
37
59
|
prepare: async (call) => call,
|
|
@@ -97,6 +119,7 @@ export class ClaudeSessionService {
|
|
|
97
119
|
hostedSubagentsByRegistry = new WeakMap();
|
|
98
120
|
backgroundNotificationWrites = new Map();
|
|
99
121
|
downloadedFileResourceSessions = new Set();
|
|
122
|
+
activeProvider;
|
|
100
123
|
mcpClosePromise;
|
|
101
124
|
runtimeCwd;
|
|
102
125
|
constructor(options) {
|
|
@@ -127,6 +150,12 @@ export class ClaudeSessionService {
|
|
|
127
150
|
: {}),
|
|
128
151
|
})
|
|
129
152
|
: null;
|
|
153
|
+
const configuredAgent = options.agent
|
|
154
|
+
? (options.extensions?.agent(options.agent) ?? null)
|
|
155
|
+
: null;
|
|
156
|
+
if (configuredAgent && options.provider) {
|
|
157
|
+
this.activeProvider = this.providerForAgent(configuredAgent);
|
|
158
|
+
}
|
|
130
159
|
}
|
|
131
160
|
nextScheduledPrompt(signal) {
|
|
132
161
|
return this.scheduledPrompts?.next(signal) ?? Promise.resolve(null);
|
|
@@ -240,12 +269,15 @@ export class ClaudeSessionService {
|
|
|
240
269
|
permissionResolverForMode: this.options.permissionResolverForMode,
|
|
241
270
|
}
|
|
242
271
|
: {}),
|
|
272
|
+
parentPermissionMode: () => agentPermissionMode(this.options.interactiveTools?.mode(sessionId) ??
|
|
273
|
+
this.options.permissionMode),
|
|
243
274
|
...(this.options.subagentToolNames
|
|
244
275
|
? { toolNames: this.options.subagentToolNames }
|
|
245
276
|
: {}),
|
|
246
277
|
...(this.options.extensions
|
|
247
278
|
? { extensions: this.options.extensions }
|
|
248
279
|
: {}),
|
|
280
|
+
...(this.options.mcp ? { mcp: this.options.mcp } : {}),
|
|
249
281
|
...(this.options.hooks ? { hooks: this.options.hooks } : {}),
|
|
250
282
|
...(this.options.contextAssembler
|
|
251
283
|
? { contextAssembler: this.options.contextAssembler }
|
|
@@ -501,7 +533,6 @@ export class ClaudeSessionService {
|
|
|
501
533
|
return { agentId, name };
|
|
502
534
|
}
|
|
503
535
|
async promptSuggestion(sessionId, signal) {
|
|
504
|
-
const provider = this.provider();
|
|
505
536
|
const loaded = this.options.sessionPersistence === false
|
|
506
537
|
? await this.turnStore(sessionId).withLease((lease) => lease.load())
|
|
507
538
|
: {
|
|
@@ -513,20 +544,19 @@ export class ClaudeSessionService {
|
|
|
513
544
|
const entries = loaded.value;
|
|
514
545
|
this.restoreWorktree(entries.entries);
|
|
515
546
|
const agentName = this.options.agent ?? getClaudeAgentSetting(entries.entries);
|
|
516
|
-
const agent =
|
|
547
|
+
const agent = this.resolveAgent(agentName);
|
|
548
|
+
const provider = this.providerForAgent(agent);
|
|
549
|
+
this.activeProvider = provider;
|
|
517
550
|
const assembledContext = await this.options.contextAssembler?.assemble({
|
|
518
551
|
cwd: this.activeCwd(),
|
|
519
552
|
});
|
|
553
|
+
const agentSystem = await this.mainAgentSystemPrompt(agent);
|
|
554
|
+
const assembledSystemMessages = this.assembledSystemMessages(agent, assembledContext?.systemMessages ?? []);
|
|
520
555
|
const contextMessages = [
|
|
521
|
-
...(
|
|
522
|
-
|
|
523
|
-
? [
|
|
524
|
-
{
|
|
525
|
-
role: 'system',
|
|
526
|
-
content: `# Agent definition: ${agent.name}\n\n${agent.body}`,
|
|
527
|
-
},
|
|
528
|
-
]
|
|
556
|
+
...(agentSystem
|
|
557
|
+
? [{ role: 'system', content: agentSystem }]
|
|
529
558
|
: []),
|
|
559
|
+
...assembledSystemMessages,
|
|
530
560
|
];
|
|
531
561
|
const messages = [
|
|
532
562
|
...contextMessages,
|
|
@@ -535,11 +565,16 @@ export class ClaudeSessionService {
|
|
|
535
565
|
{ role: 'user', content: PROMPT_SUGGESTION_INSTRUCTION },
|
|
536
566
|
], assembledContext?.firstUserMessageContext),
|
|
537
567
|
];
|
|
568
|
+
const suggestionTools = agent && this.options.tools
|
|
569
|
+
? new FilteredToolRegistry(this.options.tools, {
|
|
570
|
+
tools: mainAgentToolNames(this.options.tools, agent),
|
|
571
|
+
})
|
|
572
|
+
: this.options.tools;
|
|
538
573
|
let suggestion = '';
|
|
539
574
|
for await (const event of provider.complete({
|
|
540
575
|
messages,
|
|
541
576
|
...(provider.capabilities.tools
|
|
542
|
-
? { tools:
|
|
577
|
+
? { tools: suggestionTools?.definitions() ?? [] }
|
|
543
578
|
: {}),
|
|
544
579
|
...(this.options.effort ? { effort: this.options.effort } : {}),
|
|
545
580
|
...(signal ? { signal } : {}),
|
|
@@ -662,6 +697,11 @@ export class ClaudeSessionService {
|
|
|
662
697
|
: {}),
|
|
663
698
|
};
|
|
664
699
|
}
|
|
700
|
+
async readEffectiveAgentColor(sessionId) {
|
|
701
|
+
this.assertSessionPersistence();
|
|
702
|
+
const recovery = await this.store(sessionId).loadReadOnly();
|
|
703
|
+
return getClaudeEffectiveAgentColor(recovery.entries, sessionId);
|
|
704
|
+
}
|
|
665
705
|
async export(sessionId) {
|
|
666
706
|
this.assertSessionPersistence();
|
|
667
707
|
try {
|
|
@@ -900,6 +940,21 @@ export class ClaudeSessionService {
|
|
|
900
940
|
await new Promise((resolve) => setTimeout(resolve, 25));
|
|
901
941
|
}
|
|
902
942
|
}
|
|
943
|
+
async recordColorUsage(sessionId, selection, display, permissionMode = 'default', options = {}) {
|
|
944
|
+
const output = agentColorMessage(selection);
|
|
945
|
+
const agentColor = selection.kind === 'color'
|
|
946
|
+
? selection.color
|
|
947
|
+
: selection.kind === 'reset'
|
|
948
|
+
? AGENT_COLOR_DEFAULT
|
|
949
|
+
: undefined;
|
|
950
|
+
const createLocalSession = sessionId === undefined || options.createSession === true;
|
|
951
|
+
const activeSessionId = await this.ensureLocalSession(sessionId, permissionMode, createLocalSession ? agentColor : undefined, options.createSession === true);
|
|
952
|
+
if (this.options.sessionPersistence !== false) {
|
|
953
|
+
await this.appendInputHistory(display, activeSessionId);
|
|
954
|
+
}
|
|
955
|
+
await this.appendAgentColorUsage(activeSessionId, display, output, createLocalSession ? undefined : agentColor);
|
|
956
|
+
return activeSessionId;
|
|
957
|
+
}
|
|
903
958
|
async recordBackgroundUsage(sessionId, permissionMode = 'default') {
|
|
904
959
|
this.assertWritable();
|
|
905
960
|
const activeSessionId = await this.ensureLocalSession(sessionId, permissionMode);
|
|
@@ -1332,7 +1387,17 @@ export class ClaudeSessionService {
|
|
|
1332
1387
|
tail: appendResult.tail,
|
|
1333
1388
|
};
|
|
1334
1389
|
}
|
|
1335
|
-
const
|
|
1390
|
+
const agentName = this.options.agent ?? getClaudeAgentSetting(snapshot.entries);
|
|
1391
|
+
const agent = this.resolveAgent(agentName);
|
|
1392
|
+
const provider = this.providerForAgent(agent);
|
|
1393
|
+
this.activeProvider = provider;
|
|
1394
|
+
const effectivePrompt = !requireExisting &&
|
|
1395
|
+
!skipUserPrompt &&
|
|
1396
|
+
!this.options.agentInitialPromptHandledExternally &&
|
|
1397
|
+
shellCommand === undefined &&
|
|
1398
|
+
agent?.initialPrompt
|
|
1399
|
+
? `${agent.initialPrompt}\n\n${prompt}`
|
|
1400
|
+
: prompt;
|
|
1336
1401
|
const initialPricing = this.options.pricing?.resolve(provider.model ?? 'praxis/provider');
|
|
1337
1402
|
if (this.options.maxBudgetUsd !== undefined && !initialPricing) {
|
|
1338
1403
|
throw new Error(`Cannot enforce --max-budget-usd: no pricing is configured for model ${provider.model ?? 'praxis/provider'}`);
|
|
@@ -1450,12 +1515,15 @@ export class ClaudeSessionService {
|
|
|
1450
1515
|
permissionResolverForMode: this.options.permissionResolverForMode,
|
|
1451
1516
|
}
|
|
1452
1517
|
: {}),
|
|
1518
|
+
parentPermissionMode: () => agentPermissionMode(this.options.interactiveTools?.mode(sessionId) ??
|
|
1519
|
+
this.options.permissionMode),
|
|
1453
1520
|
...(this.options.subagentToolNames
|
|
1454
1521
|
? { toolNames: this.options.subagentToolNames }
|
|
1455
1522
|
: {}),
|
|
1456
1523
|
...(this.options.extensions
|
|
1457
1524
|
? { extensions: this.options.extensions }
|
|
1458
1525
|
: {}),
|
|
1526
|
+
...(this.options.mcp ? { mcp: this.options.mcp } : {}),
|
|
1459
1527
|
...(this.options.hooks ? { hooks: this.options.hooks } : {}),
|
|
1460
1528
|
...(this.options.contextAssembler
|
|
1461
1529
|
? { contextAssembler: this.options.contextAssembler }
|
|
@@ -1498,7 +1566,7 @@ export class ClaudeSessionService {
|
|
|
1498
1566
|
promptIdForCall: (callId) => currentPromptId ??
|
|
1499
1567
|
this.promptIdForToolCall(snapshot.entries, callId),
|
|
1500
1568
|
defaultModel: provider.model ?? 'praxis/provider',
|
|
1501
|
-
tokenBudget: workflowTokenTarget(
|
|
1569
|
+
tokenBudget: workflowTokenTarget(effectivePrompt),
|
|
1502
1570
|
enabled: true,
|
|
1503
1571
|
})
|
|
1504
1572
|
: agentTools;
|
|
@@ -1575,9 +1643,14 @@ export class ClaudeSessionService {
|
|
|
1575
1643
|
const structuredCapture = this.options.structuredOutputSchema
|
|
1576
1644
|
? { calls: 0, value: undefined }
|
|
1577
1645
|
: undefined;
|
|
1578
|
-
const
|
|
1579
|
-
? new
|
|
1646
|
+
const agentScopedTools = agent && fileHistoryTools
|
|
1647
|
+
? new FilteredToolRegistry(fileHistoryTools, {
|
|
1648
|
+
tools: mainAgentToolNames(fileHistoryTools, agent),
|
|
1649
|
+
})
|
|
1580
1650
|
: fileHistoryTools;
|
|
1651
|
+
const structuredTools = this.options.structuredOutputSchema && structuredCapture
|
|
1652
|
+
? new StructuredOutputRegistry(agentScopedTools ?? this.options.tools ?? emptyToolRegistry, this.options.structuredOutputSchema, structuredCapture)
|
|
1653
|
+
: agentScopedTools;
|
|
1581
1654
|
const hookTools = this.options.hooks && structuredTools && turnPermissions
|
|
1582
1655
|
? new ClaudeHookToolCoordinator({
|
|
1583
1656
|
tools: structuredTools,
|
|
@@ -1768,14 +1841,8 @@ export class ClaudeSessionService {
|
|
|
1768
1841
|
inputTokens: usage.inputTokens + (result.usage?.inputTokens ?? 0),
|
|
1769
1842
|
outputTokens: usage.outputTokens + (result.usage?.outputTokens ?? 0),
|
|
1770
1843
|
}), { inputTokens: 0, outputTokens: 0 });
|
|
1771
|
-
const agentName = this.options.agent ?? getClaudeAgentSetting(snapshot.entries);
|
|
1772
|
-
const agent = agentName
|
|
1773
|
-
? this.options.extensions?.agent(agentName)
|
|
1774
|
-
: null;
|
|
1775
|
-
if (agentName && !agent) {
|
|
1776
|
-
throw new Error(`Unknown Claude agent ${agentName}`);
|
|
1777
|
-
}
|
|
1778
1844
|
if (this.options.agent &&
|
|
1845
|
+
agent &&
|
|
1779
1846
|
getClaudeAgentSetting(snapshot.entries) !== this.options.agent) {
|
|
1780
1847
|
const agentSetting = createClaudeAgentSettingEntry(sessionId, this.options.agent);
|
|
1781
1848
|
const settingTail = await this.append(lease, snapshot.tail, agentSetting);
|
|
@@ -1787,9 +1854,14 @@ export class ClaudeSessionService {
|
|
|
1787
1854
|
const assembledContext = await this.options.contextAssembler?.assemble({
|
|
1788
1855
|
cwd: this.activeCwd(),
|
|
1789
1856
|
});
|
|
1857
|
+
const agentSystem = await this.mainAgentSystemPrompt(agent);
|
|
1858
|
+
const assembledSystemMessages = this.assembledSystemMessages(agent, assembledContext?.systemMessages ?? []);
|
|
1790
1859
|
const planModeMessage = this.options.interactiveTools?.contextMessage(sessionId);
|
|
1791
1860
|
const contextMessages = [
|
|
1792
|
-
...(
|
|
1861
|
+
...(agentSystem
|
|
1862
|
+
? [{ role: 'system', content: agentSystem }]
|
|
1863
|
+
: []),
|
|
1864
|
+
...assembledSystemMessages,
|
|
1793
1865
|
...(planModeMessage
|
|
1794
1866
|
? [{ role: 'system', content: planModeMessage }]
|
|
1795
1867
|
: []),
|
|
@@ -1801,14 +1873,6 @@ export class ClaudeSessionService {
|
|
|
1801
1873
|
},
|
|
1802
1874
|
]
|
|
1803
1875
|
: []),
|
|
1804
|
-
...(agent
|
|
1805
|
-
? [
|
|
1806
|
-
{
|
|
1807
|
-
role: 'system',
|
|
1808
|
-
content: `# Agent definition: ${agent.name}\n\n${agent.body}`,
|
|
1809
|
-
},
|
|
1810
|
-
]
|
|
1811
|
-
: []),
|
|
1812
1876
|
...(this.options.structuredOutputSchema
|
|
1813
1877
|
? [
|
|
1814
1878
|
{
|
|
@@ -1822,8 +1886,8 @@ export class ClaudeSessionService {
|
|
|
1822
1886
|
? { userMessages: [] }
|
|
1823
1887
|
: shellCommand === undefined
|
|
1824
1888
|
? this.options.extensions
|
|
1825
|
-
? await this.options.extensions.expandPromptAsync(
|
|
1826
|
-
: { userMessages: [
|
|
1889
|
+
? await this.options.extensions.expandPromptAsync(effectivePrompt, signal, toolResultDirectory)
|
|
1890
|
+
: { userMessages: [effectivePrompt] }
|
|
1827
1891
|
: {
|
|
1828
1892
|
userMessages: [`<bash-input>${shellCommand}</bash-input>`],
|
|
1829
1893
|
};
|
|
@@ -1864,7 +1928,8 @@ export class ClaudeSessionService {
|
|
|
1864
1928
|
: {}),
|
|
1865
1929
|
}));
|
|
1866
1930
|
const agentMentionMessages = shellCommand === undefined && !skipUserPrompt
|
|
1867
|
-
? (this.options.extensions?.agentMentionMessages(
|
|
1931
|
+
? (this.options.extensions?.agentMentionMessages(effectivePrompt) ??
|
|
1932
|
+
[])
|
|
1868
1933
|
: [];
|
|
1869
1934
|
const injectAgentMentionContext = (messages) => {
|
|
1870
1935
|
if (agentMentionMessages.length === 0)
|
|
@@ -1875,7 +1940,7 @@ export class ClaudeSessionService {
|
|
|
1875
1940
|
const message = messages[index];
|
|
1876
1941
|
if (message?.role === 'user' &&
|
|
1877
1942
|
typeof message.content === 'string' &&
|
|
1878
|
-
message.content.endsWith(
|
|
1943
|
+
message.content.endsWith(effectivePrompt)) {
|
|
1879
1944
|
insertionIndex = index;
|
|
1880
1945
|
foundPrompt = true;
|
|
1881
1946
|
break;
|
|
@@ -2073,7 +2138,7 @@ export class ClaudeSessionService {
|
|
|
2073
2138
|
...hookSession,
|
|
2074
2139
|
hook_event_name: 'UserPromptSubmit',
|
|
2075
2140
|
prompt_id: currentPromptId ?? randomUUID(),
|
|
2076
|
-
prompt,
|
|
2141
|
+
prompt: effectivePrompt,
|
|
2077
2142
|
}, undefined, signal);
|
|
2078
2143
|
await recordHookOutcome(outcome);
|
|
2079
2144
|
if (outcome.blockedReason) {
|
|
@@ -2252,7 +2317,7 @@ export class ClaudeSessionService {
|
|
|
2252
2317
|
if (!skipUserPrompt) {
|
|
2253
2318
|
await this.append(lease, snapshot.tail, createClaudeLastPromptEntry({
|
|
2254
2319
|
sessionId,
|
|
2255
|
-
lastPrompt:
|
|
2320
|
+
lastPrompt: effectivePrompt,
|
|
2256
2321
|
leafUuid: finalLeafUuid,
|
|
2257
2322
|
}));
|
|
2258
2323
|
}
|
|
@@ -2522,6 +2587,35 @@ export class ClaudeSessionService {
|
|
|
2522
2587
|
throw new Error(`Claude local command conflict: ${result.reason}`);
|
|
2523
2588
|
}
|
|
2524
2589
|
}
|
|
2590
|
+
async appendAgentColorUsage(sessionId, display, output, agentColor) {
|
|
2591
|
+
const args = display.replace(/^\/color\s*/u, '').trim();
|
|
2592
|
+
while (true) {
|
|
2593
|
+
const result = await this.turnStore(sessionId).withLease(async (lease) => {
|
|
2594
|
+
const snapshot = await lease.load();
|
|
2595
|
+
if (snapshot.entries.length === 0) {
|
|
2596
|
+
throw new Error(`Claude session not found: ${sessionId}`);
|
|
2597
|
+
}
|
|
2598
|
+
const appended = await lease.appendMany(snapshot.tail, [
|
|
2599
|
+
...(agentColor === undefined
|
|
2600
|
+
? []
|
|
2601
|
+
: [
|
|
2602
|
+
{
|
|
2603
|
+
type: 'agent-color',
|
|
2604
|
+
agentColor,
|
|
2605
|
+
sessionId,
|
|
2606
|
+
},
|
|
2607
|
+
]),
|
|
2608
|
+
...this.localCommandEntries(sessionId, this.activeCwd(), this.logicalTailUuid(snapshot.tail), 'color', args, output),
|
|
2609
|
+
]);
|
|
2610
|
+
if (appended.status === 'conflict') {
|
|
2611
|
+
throw new Error(`Claude color local command append conflict: ${appended.reason}`);
|
|
2612
|
+
}
|
|
2613
|
+
});
|
|
2614
|
+
if (result.status === 'completed')
|
|
2615
|
+
return;
|
|
2616
|
+
await new Promise((resolve) => setTimeout(resolve, 25));
|
|
2617
|
+
}
|
|
2618
|
+
}
|
|
2525
2619
|
async appendSystemLocalCommand(sessionId, command, args, output) {
|
|
2526
2620
|
while (true) {
|
|
2527
2621
|
const result = await this.turnStore(sessionId).withLease(async (lease) => {
|
|
@@ -2539,13 +2633,22 @@ export class ClaudeSessionService {
|
|
|
2539
2633
|
await new Promise((resolve) => setTimeout(resolve, 25));
|
|
2540
2634
|
}
|
|
2541
2635
|
}
|
|
2542
|
-
async ensureLocalSession(sessionId, permissionMode) {
|
|
2543
|
-
if (sessionId)
|
|
2636
|
+
async ensureLocalSession(sessionId, permissionMode, agentColor, createExplicit = false) {
|
|
2637
|
+
if (sessionId !== undefined && !createExplicit)
|
|
2544
2638
|
return sessionId;
|
|
2545
2639
|
this.assertWritable();
|
|
2546
|
-
const createdSessionId = randomUUID();
|
|
2640
|
+
const createdSessionId = sessionId ?? randomUUID();
|
|
2547
2641
|
const store = this.turnStore(createdSessionId);
|
|
2548
2642
|
const created = await store.create([
|
|
2643
|
+
...(agentColor === undefined
|
|
2644
|
+
? []
|
|
2645
|
+
: [
|
|
2646
|
+
{
|
|
2647
|
+
type: 'agent-color',
|
|
2648
|
+
agentColor,
|
|
2649
|
+
sessionId: createdSessionId,
|
|
2650
|
+
},
|
|
2651
|
+
]),
|
|
2549
2652
|
{ type: 'mode', mode: 'normal', sessionId: createdSessionId },
|
|
2550
2653
|
{
|
|
2551
2654
|
type: 'permission-mode',
|
|
@@ -2865,6 +2968,42 @@ export class ClaudeSessionService {
|
|
|
2865
2968
|
}
|
|
2866
2969
|
return this.options.provider;
|
|
2867
2970
|
}
|
|
2971
|
+
model() {
|
|
2972
|
+
return this.activeProvider?.model ?? this.options.provider?.model;
|
|
2973
|
+
}
|
|
2974
|
+
providerForAgent(agent) {
|
|
2975
|
+
const inherited = this.provider();
|
|
2976
|
+
const selectProvider = this.options.providerForMainModel ?? this.options.providerForModel;
|
|
2977
|
+
if (this.options.explicitModel ||
|
|
2978
|
+
!agent?.model ||
|
|
2979
|
+
agent.model === 'inherit' ||
|
|
2980
|
+
!selectProvider) {
|
|
2981
|
+
return inherited;
|
|
2982
|
+
}
|
|
2983
|
+
return selectProvider(agent.model);
|
|
2984
|
+
}
|
|
2985
|
+
resolveAgent(name) {
|
|
2986
|
+
if (!name)
|
|
2987
|
+
return null;
|
|
2988
|
+
return this.options.extensions?.agent(name) ?? null;
|
|
2989
|
+
}
|
|
2990
|
+
async mainAgentSystemPrompt(agent) {
|
|
2991
|
+
if (!agent ||
|
|
2992
|
+
(this.options.explicitSystemPrompt &&
|
|
2993
|
+
!this.options.agentSystemPromptOverridesExplicit)) {
|
|
2994
|
+
return null;
|
|
2995
|
+
}
|
|
2996
|
+
const memory = await agentMemoryPrompt(this.options.configRoot, this.activeCwd(), agent);
|
|
2997
|
+
const system = memory ? `${agent.body}\n\n${memory}` : agent.body;
|
|
2998
|
+
return system.trim() ? system : null;
|
|
2999
|
+
}
|
|
3000
|
+
assembledSystemMessages(agent, messages) {
|
|
3001
|
+
return agent &&
|
|
3002
|
+
this.options.explicitSystemPrompt &&
|
|
3003
|
+
this.options.agentSystemPromptOverridesExplicit
|
|
3004
|
+
? messages.slice(1)
|
|
3005
|
+
: messages;
|
|
3006
|
+
}
|
|
2868
3007
|
contextBudget(provider) {
|
|
2869
3008
|
if (this.options.contextBudget)
|
|
2870
3009
|
return this.options.contextBudget;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { type ClaudeSidechainPermissionMode } from '../compatibility/claude/sidechain.js';
|
|
2
2
|
import { type ContextAssembler } from '../core/context.js';
|
|
3
3
|
import { type ModelProvider, type ModelToolCall, type ModelToolDefinition, type ModelUsage, type PermissionResolver, type PermissionApproval, type PermissionDecision, type PermissionUpdate, type RuntimeEventSink, type ToolExecutionContext, type ToolExecutionResult, type ToolRegistry } from '../core/runtime.js';
|
|
4
|
-
import { type ClaudeExtensionCatalog } from '../extensions/claude-extensions.js';
|
|
4
|
+
import { type ClaudeAgentRuntimeDefinition, type ClaudeExtensionCatalog } from '../extensions/claude-extensions.js';
|
|
5
5
|
import type { ClaudeHookRunner } from '../hooks/claude-hooks.js';
|
|
6
|
+
import type { ClaudeMcpRuntime } from '../mcp/claude-mcp-tools.js';
|
|
6
7
|
import { type BackgroundAgentSnapshot } from './background-agent-manager.js';
|
|
7
8
|
export interface WorkflowAgentRunOptions {
|
|
8
9
|
sessionId: string;
|
|
@@ -43,6 +44,7 @@ export declare class StructuredOutputRegistry implements ToolRegistry {
|
|
|
43
44
|
prepare(call: ModelToolCall, context: ToolExecutionContext): Promise<ModelToolCall>;
|
|
44
45
|
execute(call: ModelToolCall, context: ToolExecutionContext): Promise<ToolExecutionResult>;
|
|
45
46
|
}
|
|
47
|
+
export declare function agentMemoryPrompt(configRoot: string, cwd: string, definition: ClaudeAgentRuntimeDefinition | null): Promise<string | null>;
|
|
46
48
|
export interface ClaudeSubagentExecutorOptions {
|
|
47
49
|
configRoot: string;
|
|
48
50
|
cwd: string;
|
|
@@ -52,7 +54,9 @@ export interface ClaudeSubagentExecutorOptions {
|
|
|
52
54
|
baseTools: ToolRegistry;
|
|
53
55
|
permissions: PermissionResolver;
|
|
54
56
|
permissionResolverForMode?: (mode: AgentPermissionMode) => PermissionResolver;
|
|
57
|
+
parentPermissionMode?: () => AgentPermissionMode;
|
|
55
58
|
extensions?: ClaudeExtensionCatalog;
|
|
59
|
+
mcp?: ClaudeMcpRuntime;
|
|
56
60
|
hooks?: ClaudeHookRunner;
|
|
57
61
|
contextAssembler?: ContextAssembler;
|
|
58
62
|
contextReserveTokens?: number;
|
|
@@ -80,6 +84,8 @@ export declare class ClaudeSubagentExecutor {
|
|
|
80
84
|
backgroundSnapshots(): readonly BackgroundAgentSnapshot[];
|
|
81
85
|
stopBackgroundTask(taskId: string): string;
|
|
82
86
|
private cwd;
|
|
87
|
+
private agentDefinition;
|
|
88
|
+
private resolveAgentInput;
|
|
83
89
|
registry(sessionId: string, depth: number, promptIdForCall: (callId: string) => string | null): ToolRegistry;
|
|
84
90
|
definitions(): ModelToolDefinition;
|
|
85
91
|
managementDefinitions(): readonly ModelToolDefinition[];
|