praxis-agent 0.62.0 → 0.62.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/README.md +11 -2
- package/dist/core/context-budget.js +8 -4
- package/dist/providers/anthropic-compatible.d.ts +6 -0
- package/dist/providers/anthropic-compatible.js +20 -14
- package/dist/providers/anthropic-model-spec.d.ts +9 -0
- package/dist/providers/anthropic-model-spec.js +15 -0
- package/dist/providers/provider-registry.js +1 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -98,6 +98,13 @@ cd /path/to/project
|
|
|
98
98
|
praxis
|
|
99
99
|
```
|
|
100
100
|
|
|
101
|
+
Anthropic models use a 200,000-token context window by default, including
|
|
102
|
+
unknown model IDs. Add the exact terminal `[1m]` suffix (for example,
|
|
103
|
+
`claude-sonnet-4-20250514[1m]`) to request a 1,000,000-token context window;
|
|
104
|
+
Praxis keeps that selected model public, removes the suffix on the wire, and
|
|
105
|
+
adds the `context-1m-2025-08-07` Anthropic beta once. An explicit
|
|
106
|
+
`PRAXIS_CONTEXT_WINDOW_TOKENS` value overrides either inferred window.
|
|
107
|
+
|
|
101
108
|
Common non-interactive operations:
|
|
102
109
|
|
|
103
110
|
```sh
|
|
@@ -177,7 +184,7 @@ troubleshooting. Run `praxis --help` for the authoritative command surface.
|
|
|
177
184
|
patches and readable binary/conflict/transient-path notes, semantic plan/question decision panels with complete
|
|
178
185
|
screen-reader actions, semantic screen projection across selectable surfaces,
|
|
179
186
|
deterministic resize-aware URL/form elicitation rendering, and measured
|
|
180
|
-
context budgets; print mode,
|
|
187
|
+
context budgets with base64-payload-independent image estimates; print mode,
|
|
181
188
|
structured JSON/JSONL, context compaction, tool loops, and bounded execution.
|
|
182
189
|
- **Built-in tools** — read, write, edit, `ApplyPatch` for bounded ordered exact
|
|
183
190
|
multi-file replacements, configured plugin LSP navigation with fresh bounded
|
|
@@ -294,7 +301,9 @@ troubleshooting. Run `praxis --help` for the authoritative command surface.
|
|
|
294
301
|
route, whether primary or fallback, stays sticky only through that logical
|
|
295
302
|
Turn's tool continuations; incompatible routes fail closed, and the next
|
|
296
303
|
independent Turn starts from primary. Recovery may persist only an optional
|
|
297
|
-
selected model, never provider route or wire state.
|
|
304
|
+
selected model, never provider route or wire state. Anthropic uses a
|
|
305
|
+
200,000-token default or exact terminal `[1m]` model syntax for 1,000,000
|
|
306
|
+
tokens; `PRAXIS_CONTEXT_WINDOW_TOKENS` overrides the advertised window.
|
|
298
307
|
- **Transactional self-update** — `praxis update` verifies the package before
|
|
299
308
|
installing it, rejects concurrent updates, and can roll back after an
|
|
300
309
|
interruption or crash.
|
|
@@ -24,6 +24,12 @@ export function estimateTextTokens(value) {
|
|
|
24
24
|
}
|
|
25
25
|
return Math.ceil(ascii / 4) + nonAscii;
|
|
26
26
|
}
|
|
27
|
+
const IMAGE_VISUAL_TOKEN_ESTIMATE = 1_600;
|
|
28
|
+
// This provider-neutral conservative fallback never interprets billed usage;
|
|
29
|
+
// observed provider usage remains authoritative at a ContextBudget watermark.
|
|
30
|
+
function estimateImageTokens(mediaType) {
|
|
31
|
+
return 8 + estimateTextTokens(mediaType) + IMAGE_VISUAL_TOKEN_ESTIMATE;
|
|
32
|
+
}
|
|
27
33
|
function estimateMessageTokens(message) {
|
|
28
34
|
let tokens = 4 + estimateTextTokens(message.role);
|
|
29
35
|
if (message.role === 'tool') {
|
|
@@ -31,16 +37,14 @@ function estimateMessageTokens(message) {
|
|
|
31
37
|
estimateTextTokens(message.toolCallId) +
|
|
32
38
|
estimateTextTokens(message.content);
|
|
33
39
|
for (const image of message.images ?? []) {
|
|
34
|
-
tokens +=
|
|
35
|
-
8 + estimateTextTokens(image.mediaType) + estimateTextTokens(image.data);
|
|
40
|
+
tokens += estimateImageTokens(image.mediaType);
|
|
36
41
|
}
|
|
37
42
|
return tokens + (message.isError ? 1 : 0);
|
|
38
43
|
}
|
|
39
44
|
tokens += estimateTextTokens(message.content);
|
|
40
45
|
if (message.role === 'user') {
|
|
41
46
|
for (const image of message.images ?? []) {
|
|
42
|
-
tokens +=
|
|
43
|
-
8 + estimateTextTokens(image.mediaType) + estimateTextTokens(image.data);
|
|
47
|
+
tokens += estimateImageTokens(image.mediaType);
|
|
44
48
|
}
|
|
45
49
|
for (const document of message.documents ?? []) {
|
|
46
50
|
tokens += 8 + estimateTextTokens(document.mediaType) + 2000;
|
|
@@ -4,6 +4,10 @@ export interface AnthropicCompatibleProviderOptions {
|
|
|
4
4
|
baseUrl: string;
|
|
5
5
|
apiKey: string;
|
|
6
6
|
model: string;
|
|
7
|
+
promptCacheResolver?: (target: {
|
|
8
|
+
baseUrl: string;
|
|
9
|
+
model: string;
|
|
10
|
+
}) => AnthropicPromptCachePolicy;
|
|
7
11
|
maxOutputTokens?: number;
|
|
8
12
|
anthropicVersion?: string;
|
|
9
13
|
webSearch?: boolean;
|
|
@@ -32,6 +36,8 @@ export declare class AnthropicCompatibleProvider implements ModelProvider {
|
|
|
32
36
|
private readonly maxToolMetadataBytes;
|
|
33
37
|
private readonly maxErrorBodyBytes;
|
|
34
38
|
private readonly thinking;
|
|
39
|
+
private readonly wireModel;
|
|
40
|
+
private readonly providerBetas;
|
|
35
41
|
private readonly promptCaching;
|
|
36
42
|
private readonly streaming;
|
|
37
43
|
constructor(options: AnthropicCompatibleProviderOptions);
|
|
@@ -3,6 +3,7 @@ import { transportFailureKind } from './provider-errors.js';
|
|
|
3
3
|
import { reportProviderTransportActivity } from './provider-transport-activity.js';
|
|
4
4
|
import { markNonStreamingFallbackEligible } from './non-streaming-fallback-provider.js';
|
|
5
5
|
import { createAnthropicPromptCachePolicyResolver, } from './anthropic-prompt-cache.js';
|
|
6
|
+
import { resolveAnthropicModelSpec } from './anthropic-model-spec.js';
|
|
6
7
|
function isRecord(value) {
|
|
7
8
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
8
9
|
}
|
|
@@ -643,21 +644,24 @@ export class AnthropicCompatibleProvider {
|
|
|
643
644
|
maxToolMetadataBytes;
|
|
644
645
|
maxErrorBodyBytes;
|
|
645
646
|
thinking;
|
|
647
|
+
wireModel;
|
|
648
|
+
providerBetas;
|
|
646
649
|
promptCaching;
|
|
647
650
|
streaming;
|
|
648
651
|
constructor(options) {
|
|
649
652
|
this.options = options;
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
}
|
|
653
|
+
const modelSpec = resolveAnthropicModelSpec(options.model, options.contextWindowTokens);
|
|
654
|
+
positiveInteger(modelSpec.contextWindowTokens, 'Context window tokens');
|
|
653
655
|
this.endpoint = `${options.baseUrl.replace(/\/+$/, '')}/messages`;
|
|
654
|
-
this.model =
|
|
656
|
+
this.model = modelSpec.model;
|
|
657
|
+
this.wireModel = modelSpec.wireModel;
|
|
658
|
+
this.providerBetas = Object.freeze([...modelSpec.betas]);
|
|
655
659
|
this.streaming = options.streaming ?? true;
|
|
656
660
|
this.fetchImplementation = options.fetchImplementation ?? fetch;
|
|
657
661
|
this.maxOutputTokens = positiveInteger(options.maxOutputTokens ??
|
|
658
|
-
(
|
|
662
|
+
(this.wireModel.includes('claude-opus-4-6')
|
|
659
663
|
? 64_000
|
|
660
|
-
:
|
|
664
|
+
: this.wireModel.startsWith('claude-')
|
|
661
665
|
? 32_000
|
|
662
666
|
: 8192), 'Max output tokens');
|
|
663
667
|
this.capabilities = {
|
|
@@ -671,19 +675,20 @@ export class AnthropicCompatibleProvider {
|
|
|
671
675
|
modes: ['enabled', 'adaptive', 'disabled'],
|
|
672
676
|
maxTokens: true,
|
|
673
677
|
},
|
|
674
|
-
|
|
675
|
-
? {}
|
|
676
|
-
: { contextWindowTokens: options.contextWindowTokens }),
|
|
678
|
+
contextWindowTokens: modelSpec.contextWindowTokens,
|
|
677
679
|
maxOutputTokens: this.maxOutputTokens,
|
|
678
680
|
terminalReasons: true,
|
|
679
681
|
};
|
|
680
682
|
this.thinking = validateThinking(options.thinking);
|
|
681
|
-
const promptCaching = options.promptCaching
|
|
682
|
-
?
|
|
683
|
-
: (options.
|
|
683
|
+
const promptCaching = options.promptCaching !== undefined
|
|
684
|
+
? options.promptCaching
|
|
685
|
+
: (options.promptCacheResolver?.({
|
|
686
|
+
baseUrl: options.baseUrl,
|
|
687
|
+
model: this.wireModel,
|
|
688
|
+
}) ??
|
|
684
689
|
createAnthropicPromptCachePolicyResolver({}, 'native')({
|
|
685
690
|
baseUrl: options.baseUrl,
|
|
686
|
-
model:
|
|
691
|
+
model: this.wireModel,
|
|
687
692
|
}));
|
|
688
693
|
this.promptCaching = promptCaching
|
|
689
694
|
? cacheControl(promptCaching.ttl)
|
|
@@ -714,6 +719,7 @@ export class AnthropicCompatibleProvider {
|
|
|
714
719
|
budget_tokens: thinking.maxTokens ?? maxTokens - 1,
|
|
715
720
|
};
|
|
716
721
|
const betas = [
|
|
722
|
+
...this.providerBetas,
|
|
717
723
|
...(request.betas ?? []),
|
|
718
724
|
...(thinking && thinking.mode !== 'disabled'
|
|
719
725
|
? ['interleaved-thinking-2025-05-14']
|
|
@@ -730,7 +736,7 @@ export class AnthropicCompatibleProvider {
|
|
|
730
736
|
...(betas.length ? { 'anthropic-beta': betas.join(',') } : {}),
|
|
731
737
|
},
|
|
732
738
|
body: JSON.stringify({
|
|
733
|
-
model: this.
|
|
739
|
+
model: this.wireModel,
|
|
734
740
|
max_tokens: maxTokens,
|
|
735
741
|
messages: serialized.messages,
|
|
736
742
|
stream: this.streaming,
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare const ANTHROPIC_LONG_CONTEXT_BETA = "context-1m-2025-08-07";
|
|
2
|
+
export interface ResolvedAnthropicModelSpec {
|
|
3
|
+
readonly model: string;
|
|
4
|
+
readonly wireModel: string;
|
|
5
|
+
readonly contextWindowTokens: number;
|
|
6
|
+
readonly betas: readonly string[];
|
|
7
|
+
}
|
|
8
|
+
export declare function resolveAnthropicModelSpec(model: string, explicitContextWindowTokens?: number): ResolvedAnthropicModelSpec;
|
|
9
|
+
//# sourceMappingURL=anthropic-model-spec.d.ts.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export const ANTHROPIC_LONG_CONTEXT_BETA = 'context-1m-2025-08-07';
|
|
2
|
+
export function resolveAnthropicModelSpec(model, explicitContextWindowTokens) {
|
|
3
|
+
const longContext = model.endsWith('[1m]');
|
|
4
|
+
const wireModel = longContext ? model.slice(0, -'[1m]'.length) : model;
|
|
5
|
+
if (longContext && wireModel.trim().length === 0) {
|
|
6
|
+
throw new Error('Anthropic [1m] model spec must include a base model name');
|
|
7
|
+
}
|
|
8
|
+
return Object.freeze({
|
|
9
|
+
model,
|
|
10
|
+
wireModel,
|
|
11
|
+
contextWindowTokens: explicitContextWindowTokens ?? (longContext ? 1_000_000 : 200_000),
|
|
12
|
+
betas: Object.freeze(longContext ? [ANTHROPIC_LONG_CONTEXT_BETA] : []),
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=anthropic-model-spec.js.map
|
|
@@ -175,10 +175,7 @@ class NativeProviderRegistry {
|
|
|
175
175
|
...(this.options.anthropicPromptCacheResolver === undefined
|
|
176
176
|
? {}
|
|
177
177
|
: {
|
|
178
|
-
|
|
179
|
-
baseUrl: target.baseUrl,
|
|
180
|
-
model: target.modelId,
|
|
181
|
-
}),
|
|
178
|
+
promptCacheResolver: this.options.anthropicPromptCacheResolver,
|
|
182
179
|
}),
|
|
183
180
|
...(this.options.providerEnvironment?.maxOutputTokens === undefined
|
|
184
181
|
? {}
|