praxis-agent 0.54.0 → 0.55.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 +10 -5
- package/dist/application/native-sidechain-transcript.d.ts +2 -0
- package/dist/application/native-sidechain-transcript.js +3 -0
- package/dist/application/session-service.js +6 -0
- package/dist/application/subagent-service.d.ts +2 -0
- package/dist/application/subagent-service.js +28 -12
- package/dist/application/team-agent-runtime.d.ts +1 -0
- package/dist/application/team-agent-runtime.js +3 -0
- package/dist/cli-runtime.js +6 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -253,11 +253,16 @@ troubleshooting. Run `praxis --help` for the authoritative command surface.
|
|
|
253
253
|
recovery for malformed streamed tool arguments without tool execution or
|
|
254
254
|
lost resumability, one default-on bounded Anthropic non-streaming replay for
|
|
255
255
|
eligible stream/idle failures without exposing failed-attempt output, and
|
|
256
|
-
token-only/no-API-dollar accounting for subscription runs.
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
256
|
+
token-only/no-API-dollar accounting for subscription runs. Each main user
|
|
257
|
+
Turn and independent auxiliary Agent, Workflow, Team, recovery, or memory
|
|
258
|
+
Turn receives its own provider client. Session-memory requests reuse a
|
|
259
|
+
completion-scoped client but restart routing from primary for each request;
|
|
260
|
+
auto-mode critic and eval-judge requests remain independently constructed
|
|
261
|
+
one-shot clients. Failed attempts stay buffered, and the first successful
|
|
262
|
+
route, whether primary or fallback, stays sticky only through that logical
|
|
263
|
+
Turn's tool continuations; incompatible routes fail closed, and the next
|
|
264
|
+
independent Turn starts from primary. Recovery may persist only an optional
|
|
265
|
+
selected model, never provider route or wire state.
|
|
261
266
|
- **Transactional self-update** — `praxis update` verifies the package before
|
|
262
267
|
installing it, rejects concurrent updates, and can roll back after an
|
|
263
268
|
interruption or crash.
|
|
@@ -7,6 +7,8 @@ export interface NativeSidechainMetadata {
|
|
|
7
7
|
readonly spawnDepth: number;
|
|
8
8
|
readonly cwd: string;
|
|
9
9
|
readonly promptId: string;
|
|
10
|
+
/** Provider-neutral selected model identifier for recovery. */
|
|
11
|
+
readonly model?: string;
|
|
10
12
|
readonly name?: string;
|
|
11
13
|
readonly permissionMode?: NativeSidechainPermissionMode;
|
|
12
14
|
readonly isolation?: 'worktree';
|
|
@@ -19,6 +19,7 @@ const requiredKeys = [
|
|
|
19
19
|
'promptId',
|
|
20
20
|
];
|
|
21
21
|
const optionalKeys = [
|
|
22
|
+
'model',
|
|
22
23
|
'name',
|
|
23
24
|
'permissionMode',
|
|
24
25
|
'isolation',
|
|
@@ -74,6 +75,8 @@ function validateMetadata(value) {
|
|
|
74
75
|
throw new Error('native sidechain metadata cwd is invalid');
|
|
75
76
|
if (!nonBlank(record.promptId))
|
|
76
77
|
throw new Error('native sidechain metadata promptId is invalid');
|
|
78
|
+
if (record.model !== undefined && !nonBlank(record.model))
|
|
79
|
+
throw new Error('native sidechain metadata model is invalid');
|
|
77
80
|
if (record.name !== undefined && !nonBlank(record.name))
|
|
78
81
|
throw new Error('native sidechain metadata name is invalid');
|
|
79
82
|
if (record.permissionMode !== undefined &&
|
|
@@ -1117,6 +1117,9 @@ export class ClaudeSessionService {
|
|
|
1117
1117
|
...(this.options.providerForModel
|
|
1118
1118
|
? { providerForModel: this.options.providerForModel }
|
|
1119
1119
|
: {}),
|
|
1120
|
+
...(this.options.providerForTurn
|
|
1121
|
+
? { providerForTurn: this.options.providerForTurn }
|
|
1122
|
+
: {}),
|
|
1120
1123
|
baseTools: wrappedBase,
|
|
1121
1124
|
...(this.options.deferMcpTools === undefined
|
|
1122
1125
|
? {}
|
|
@@ -2858,6 +2861,9 @@ export class ClaudeSessionService {
|
|
|
2858
2861
|
...(this.options.providerForModel
|
|
2859
2862
|
? { providerForModel: this.options.providerForModel }
|
|
2860
2863
|
: {}),
|
|
2864
|
+
...(this.options.providerForTurn
|
|
2865
|
+
? { providerForTurn: this.options.providerForTurn }
|
|
2866
|
+
: {}),
|
|
2861
2867
|
baseTools,
|
|
2862
2868
|
...(this.options.deferMcpTools === undefined
|
|
2863
2869
|
? {}
|
|
@@ -76,6 +76,7 @@ export interface ClaudeSubagentExecutorOptions {
|
|
|
76
76
|
maxCalls?: number;
|
|
77
77
|
maxOutputBytes?: number;
|
|
78
78
|
providerForModel?: (model: string) => ModelProvider;
|
|
79
|
+
providerForTurn?: (model?: string) => ModelProvider;
|
|
79
80
|
toolNames?: readonly string[];
|
|
80
81
|
backgroundTaskNotifications?: (waitForRunning: boolean) => Promise<string[]>;
|
|
81
82
|
notificationDelivered?: (notification: {
|
|
@@ -117,6 +118,7 @@ export declare class ClaudeSubagentExecutor {
|
|
|
117
118
|
sendBackgroundMessage(agentId: string, message: string, summary: string | undefined, toolUseId: string): string;
|
|
118
119
|
stopAllBackgroundTasks(): readonly string[];
|
|
119
120
|
private cwd;
|
|
121
|
+
private providerForTurn;
|
|
120
122
|
private agentDefinition;
|
|
121
123
|
private resolveAgentInput;
|
|
122
124
|
registry(sessionId: string, depth: number, promptIdForCall: (callId: string) => string | null, parentAgentId?: string): ToolRegistry;
|
|
@@ -586,6 +586,15 @@ export class ClaudeSubagentExecutor {
|
|
|
586
586
|
cwd() {
|
|
587
587
|
return this.options.cwdProvider?.() ?? this.options.cwd;
|
|
588
588
|
}
|
|
589
|
+
providerForTurn(model) {
|
|
590
|
+
if (this.options.providerForTurn) {
|
|
591
|
+
return this.options.providerForTurn(model);
|
|
592
|
+
}
|
|
593
|
+
if (model !== undefined) {
|
|
594
|
+
return this.options.providerForModel?.(model) ?? this.options.provider;
|
|
595
|
+
}
|
|
596
|
+
return this.options.provider;
|
|
597
|
+
}
|
|
589
598
|
agentDefinition(input) {
|
|
590
599
|
return this.options.extensions?.agent(input.subagentType) ?? null;
|
|
591
600
|
}
|
|
@@ -753,7 +762,9 @@ export class ClaudeSubagentExecutor {
|
|
|
753
762
|
!this.options.extensions?.agent(input.subagentType)) {
|
|
754
763
|
throw new Error(`Unknown Claude agent ${input.subagentType}`);
|
|
755
764
|
}
|
|
756
|
-
if (input.model &&
|
|
765
|
+
if (input.model &&
|
|
766
|
+
!this.options.providerForModel &&
|
|
767
|
+
!this.options.providerForTurn) {
|
|
757
768
|
throw new Error('Agent model overrides are unavailable for this provider');
|
|
758
769
|
}
|
|
759
770
|
if (input.permissionMode &&
|
|
@@ -850,6 +861,7 @@ export class ClaudeSubagentExecutor {
|
|
|
850
861
|
...(input.permissionMode
|
|
851
862
|
? { permissionMode: input.permissionMode }
|
|
852
863
|
: {}),
|
|
864
|
+
...(input.model ? { model: input.model } : {}),
|
|
853
865
|
...(input.isolation ? { isolation: input.isolation } : {}),
|
|
854
866
|
...(parentAgentId ? { parentAgentId } : {}),
|
|
855
867
|
...(initialIsolation ? { worktreePath: initialIsolation.cwd } : {}),
|
|
@@ -863,9 +875,7 @@ export class ClaudeSubagentExecutor {
|
|
|
863
875
|
catch (error) {
|
|
864
876
|
return settleInitialSetupFailure(error, initialIsolation);
|
|
865
877
|
}
|
|
866
|
-
const provider = input.model
|
|
867
|
-
? (this.options.providerForModel?.(input.model) ?? this.options.provider)
|
|
868
|
-
: this.options.provider;
|
|
878
|
+
const provider = this.providerForTurn(input.model);
|
|
869
879
|
const backgroundRun = this.createBackgroundAgentRun({
|
|
870
880
|
input,
|
|
871
881
|
parentCwd,
|
|
@@ -874,11 +884,14 @@ export class ClaudeSubagentExecutor {
|
|
|
874
884
|
...(initialIsolation ? { initialIsolation } : {}),
|
|
875
885
|
createIsolation: () => this.createAgentWorktree(paths.praxisRoot, sessionId, agentId, parentCwd),
|
|
876
886
|
execute: async (cwd, message, signal, continuation) => {
|
|
887
|
+
const turnProvider = continuation
|
|
888
|
+
? this.providerForTurn(input.model)
|
|
889
|
+
: provider;
|
|
877
890
|
const run = (lease) => this.runSidechain({
|
|
878
891
|
...lease,
|
|
879
892
|
sessionId,
|
|
880
893
|
input,
|
|
881
|
-
provider,
|
|
894
|
+
provider: turnProvider,
|
|
882
895
|
agentId,
|
|
883
896
|
spawnDepth,
|
|
884
897
|
promptId,
|
|
@@ -1346,13 +1359,12 @@ export class ClaudeSubagentExecutor {
|
|
|
1346
1359
|
!this.options.extensions?.agent(options.agentType)) {
|
|
1347
1360
|
throw new Error(`Unknown Claude agent ${options.agentType}`);
|
|
1348
1361
|
}
|
|
1349
|
-
if (options.model &&
|
|
1362
|
+
if (options.model &&
|
|
1363
|
+
!this.options.providerForModel &&
|
|
1364
|
+
!this.options.providerForTurn) {
|
|
1350
1365
|
throw new Error('Workflow agent model overrides are unavailable for this provider');
|
|
1351
1366
|
}
|
|
1352
|
-
const provider = options.model
|
|
1353
|
-
? (this.options.providerForModel?.(options.model) ??
|
|
1354
|
-
this.options.provider)
|
|
1355
|
-
: this.options.provider;
|
|
1367
|
+
const provider = this.providerForTurn(options.model);
|
|
1356
1368
|
const input = {
|
|
1357
1369
|
description: options.label ?? 'Workflow agent',
|
|
1358
1370
|
prompt: options.prompt,
|
|
@@ -1395,6 +1407,7 @@ export class ClaudeSubagentExecutor {
|
|
|
1395
1407
|
spawnDepth: 1,
|
|
1396
1408
|
cwd: agentCwd,
|
|
1397
1409
|
promptId: options.promptId,
|
|
1410
|
+
...(input.model ? { model: input.model } : {}),
|
|
1398
1411
|
...(options.isolation ? { isolation: options.isolation } : {}),
|
|
1399
1412
|
...(isolation ? { worktreePath: isolation.cwd } : {}),
|
|
1400
1413
|
});
|
|
@@ -1716,11 +1729,11 @@ export class ClaudeSubagentExecutor {
|
|
|
1716
1729
|
prompt,
|
|
1717
1730
|
subagentType: agentType,
|
|
1718
1731
|
...(name ? { name } : {}),
|
|
1732
|
+
...(metadata?.model ? { model: metadata.model } : {}),
|
|
1719
1733
|
...(permissionMode ? { permissionMode } : {}),
|
|
1720
1734
|
...(isolation ? { isolation } : {}),
|
|
1721
1735
|
runInBackground: true,
|
|
1722
1736
|
};
|
|
1723
|
-
const provider = this.options.provider;
|
|
1724
1737
|
const recoveredPromptId = metadata?.promptId ?? randomUUID();
|
|
1725
1738
|
const backgroundRun = this.createBackgroundAgentRun({
|
|
1726
1739
|
input,
|
|
@@ -1731,6 +1744,9 @@ export class ClaudeSubagentExecutor {
|
|
|
1731
1744
|
...(restoredIsolation ? { initialIsolation: restoredIsolation } : {}),
|
|
1732
1745
|
createIsolation: () => this.createAgentWorktree(paths.praxisRoot, sessionId, agentId, parentCwd),
|
|
1733
1746
|
execute: async (cwd, message, signal, continuation) => {
|
|
1747
|
+
// Recovery never restores provider-native route state. Each recovered
|
|
1748
|
+
// execution, including every later follow-up, gets a fresh turn.
|
|
1749
|
+
const provider = this.providerForTurn(input.model);
|
|
1734
1750
|
const run = (lease) => this.runSidechain({
|
|
1735
1751
|
...lease,
|
|
1736
1752
|
sessionId,
|
|
@@ -1757,7 +1773,7 @@ export class ClaudeSubagentExecutor {
|
|
|
1757
1773
|
prompt,
|
|
1758
1774
|
toolUseId,
|
|
1759
1775
|
outputFile: sidechainPaths.transcriptFile,
|
|
1760
|
-
resolvedModel: provider.model ?? 'praxis/provider',
|
|
1776
|
+
resolvedModel: metadata?.model ?? this.options.provider.model ?? 'praxis/provider',
|
|
1761
1777
|
lifecycle: backgroundRun.lifecycle,
|
|
1762
1778
|
run: backgroundRun.run,
|
|
1763
1779
|
markBackground: backgroundRun.markBackground,
|
|
@@ -14,6 +14,7 @@ export interface ClaudeTeamAgentRuntimeOptions {
|
|
|
14
14
|
readonly hooks?: ClaudeHookRunner;
|
|
15
15
|
readonly contextAssembler?: ContextAssembler;
|
|
16
16
|
readonly providerForModel?: (model: string) => ModelProvider;
|
|
17
|
+
readonly providerForTurn?: (model?: string) => ModelProvider;
|
|
17
18
|
readonly permissionResolverForMode?: (mode: AgentPermissionMode) => PermissionResolver;
|
|
18
19
|
readonly eventSink?: RuntimeEventSink;
|
|
19
20
|
readonly approveTool?: (call: ModelToolCall, originalCall?: ModelToolCall, decision?: PermissionDecision) => PermissionApproval | Promise<PermissionApproval>;
|
|
@@ -79,6 +79,9 @@ export class ClaudeTeamAgentRuntime {
|
|
|
79
79
|
...(this.options.providerForModel
|
|
80
80
|
? { providerForModel: this.options.providerForModel }
|
|
81
81
|
: {}),
|
|
82
|
+
...(this.options.providerForTurn
|
|
83
|
+
? { providerForTurn: this.options.providerForTurn }
|
|
84
|
+
: {}),
|
|
82
85
|
...(this.options.permissionResolverForMode
|
|
83
86
|
? {
|
|
84
87
|
permissionResolverForMode: this.options.permissionResolverForMode,
|
package/dist/cli-runtime.js
CHANGED
|
@@ -1477,9 +1477,11 @@ const createDefaultService = async ({ eventSink, requireProvider, hooksOnly = fa
|
|
|
1477
1477
|
});
|
|
1478
1478
|
if (memoryDirectory)
|
|
1479
1479
|
await mkdir(memoryDirectory, { recursive: true });
|
|
1480
|
-
const projectMemoryProviderFactory =
|
|
1481
|
-
? () =>
|
|
1482
|
-
:
|
|
1480
|
+
const projectMemoryProviderFactory = providerForTurn
|
|
1481
|
+
? () => providerForTurn()
|
|
1482
|
+
: providerForMainModel && model
|
|
1483
|
+
? () => providerForMainModel(model)
|
|
1484
|
+
: undefined;
|
|
1483
1485
|
const projectMemoryRecall = projectMemoryPolicy.recall &&
|
|
1484
1486
|
memoryDirectory &&
|
|
1485
1487
|
projectMemoryProviderFactory
|
|
@@ -1911,6 +1913,7 @@ const createDefaultService = async ({ eventSink, requireProvider, hooksOnly = fa
|
|
|
1911
1913
|
...(hooks ? { hooks } : {}),
|
|
1912
1914
|
...(contextAssembler ? { contextAssembler } : {}),
|
|
1913
1915
|
...(providerForModel ? { providerForModel } : {}),
|
|
1916
|
+
...(providerForTurn ? { providerForTurn } : {}),
|
|
1914
1917
|
permissionResolverForMode,
|
|
1915
1918
|
eventSink: runtimeEventSink,
|
|
1916
1919
|
}),
|