praxis-agent 0.53.1 → 0.54.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 +24 -5
- package/dist/application/session-service.d.ts +2 -0
- package/dist/application/session-service.js +16 -1
- package/dist/cli-runtime.js +13 -3
- package/dist/providers/codex-subscription.d.ts +1 -7
- package/dist/providers/codex-subscription.js +32 -694
- package/dist/providers/fallback-provider.d.ts +5 -1
- package/dist/providers/fallback-provider.js +62 -4
- package/dist/providers/openai-responses.d.ts +26 -0
- package/dist/providers/openai-responses.js +162 -0
- package/dist/providers/provider-registry.js +22 -0
- package/dist/providers/provider-settings.d.ts +1 -1
- package/dist/providers/provider-settings.js +13 -2
- package/dist/providers/responses-codec.d.ts +31 -0
- package/dist/providers/responses-codec.js +742 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -13,7 +13,8 @@ Praxis is a local-first, single-user general agent for the command line.
|
|
|
13
13
|
|
|
14
14
|
It provides an interactive or headless agent loop, local tools, permissions,
|
|
15
15
|
sessions, skills, hooks, MCP, plugins, background agents, and provider-neutral
|
|
16
|
-
Anthropic
|
|
16
|
+
Anthropic, OpenAI-compatible Chat Completions, and OpenAI Responses model
|
|
17
|
+
access. Praxis deliberately excludes
|
|
17
18
|
accounts, organizations, billing, managed enterprise policy, remote control,
|
|
18
19
|
IDE surfaces, and telemetry control planes.
|
|
19
20
|
|
|
@@ -27,9 +28,9 @@ sessions, configuration, or compatibility directories.
|
|
|
27
28
|
- macOS or Linux
|
|
28
29
|
- Node.js 24 or newer
|
|
29
30
|
- [`ripgrep`](https://github.com/BurntSushi/ripgrep) (`rg`) for the Grep tool
|
|
30
|
-
- an API key and model ID for an Anthropic
|
|
31
|
-
stable setup), or the explicitly enabled experimental
|
|
32
|
-
subscription integration
|
|
31
|
+
- an API key and model ID for an Anthropic, OpenAI-compatible, or OpenAI
|
|
32
|
+
Responses provider (the stable setup), or the explicitly enabled experimental
|
|
33
|
+
ChatGPT-backed Codex subscription integration
|
|
33
34
|
|
|
34
35
|
Praxis does not use Claude subscription authentication. Claude-shaped message,
|
|
35
36
|
tool, and CLI protocol forms remain supported where they are part of the
|
|
@@ -63,6 +64,20 @@ cd /path/to/project
|
|
|
63
64
|
praxis
|
|
64
65
|
```
|
|
65
66
|
|
|
67
|
+
To use OpenAI's Responses API with an explicit API-key provider:
|
|
68
|
+
|
|
69
|
+
```sh
|
|
70
|
+
export PRAXIS_PROVIDER="openai-responses"
|
|
71
|
+
export OPENAI_API_KEY="your-api-key"
|
|
72
|
+
export PRAXIS_MODEL="your-responses-model-id"
|
|
73
|
+
|
|
74
|
+
cd /path/to/project
|
|
75
|
+
praxis
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
The `openai` provider remains OpenAI-compatible Chat Completions. Provider
|
|
79
|
+
protocols are selected explicitly; model IDs never switch protocols implicitly.
|
|
80
|
+
|
|
66
81
|
Praxis also has an experimental `openai-codex` provider for ChatGPT-backed
|
|
67
82
|
Codex subscriptions. It is separate from OpenAI API-key access, requires
|
|
68
83
|
`experimental.codexSubscription: true`, and stores OAuth credentials in the
|
|
@@ -238,7 +253,11 @@ troubleshooting. Run `praxis --help` for the authoritative command surface.
|
|
|
238
253
|
recovery for malformed streamed tool arguments without tool execution or
|
|
239
254
|
lost resumability, one default-on bounded Anthropic non-streaming replay for
|
|
240
255
|
eligible stream/idle failures without exposing failed-attempt output, and
|
|
241
|
-
token-only/no-API-dollar accounting for subscription runs.
|
|
256
|
+
token-only/no-API-dollar accounting for subscription runs. For each main user
|
|
257
|
+
turn, failed provider attempts stay buffered; the first successful route,
|
|
258
|
+
whether primary or fallback, is sticky and sealed through that turn's tool
|
|
259
|
+
continuations; incompatible fallback routes fail closed, and each new main
|
|
260
|
+
user turn starts from primary.
|
|
242
261
|
- **Transactional self-update** — `praxis update` verifies the package before
|
|
243
262
|
installing it, rejects concurrent updates, and can roll back after an
|
|
244
263
|
interruption or crash.
|
|
@@ -70,6 +70,8 @@ export interface ClaudeSessionServiceOptions {
|
|
|
70
70
|
enableWorkflows?: boolean;
|
|
71
71
|
providerForModel?: (model: string) => ModelProvider;
|
|
72
72
|
providerForMainModel?: (model: string) => ModelProvider;
|
|
73
|
+
/** Creates one fresh main-turn provider per outer user turn; never used for auxiliary model calls. */
|
|
74
|
+
providerForTurn?: (model?: string) => ModelProvider;
|
|
73
75
|
/** Creates a provider adapter dedicated to Session memory requests so
|
|
74
76
|
* adapter-local cache and retry state are not shared with the foreground. */
|
|
75
77
|
sessionMemoryProviderFactory?: () => ModelProvider;
|
|
@@ -745,7 +745,16 @@ export class ClaudeSessionService {
|
|
|
745
745
|
? (options.extensions?.agent(options.agent) ?? null)
|
|
746
746
|
: null;
|
|
747
747
|
if (configuredAgent && options.provider) {
|
|
748
|
-
|
|
748
|
+
const selectedModel = !options.explicitModel &&
|
|
749
|
+
configuredAgent.model &&
|
|
750
|
+
configuredAgent.model !== 'inherit'
|
|
751
|
+
? configuredAgent.model
|
|
752
|
+
: undefined;
|
|
753
|
+
const selectProvider = options.providerForMainModel ?? options.providerForModel;
|
|
754
|
+
this.activeProvider =
|
|
755
|
+
selectedModel !== undefined && selectProvider
|
|
756
|
+
? selectProvider(selectedModel)
|
|
757
|
+
: this.options.provider;
|
|
749
758
|
}
|
|
750
759
|
}
|
|
751
760
|
nextScheduledPrompt(signal) {
|
|
@@ -5043,6 +5052,12 @@ export class ClaudeSessionService {
|
|
|
5043
5052
|
providerForAgent(agent) {
|
|
5044
5053
|
const inherited = this.provider();
|
|
5045
5054
|
const selectProvider = this.options.providerForMainModel ?? this.options.providerForModel;
|
|
5055
|
+
const effectiveModel = !this.options.explicitModel && agent?.model && agent.model !== 'inherit'
|
|
5056
|
+
? agent.model
|
|
5057
|
+
: inherited.model;
|
|
5058
|
+
if (this.options.providerForTurn) {
|
|
5059
|
+
return this.options.providerForTurn(effectiveModel);
|
|
5060
|
+
}
|
|
5046
5061
|
if (this.options.explicitModel ||
|
|
5047
5062
|
!agent?.model ||
|
|
5048
5063
|
agent.model === 'inherit' ||
|
package/dist/cli-runtime.js
CHANGED
|
@@ -1044,6 +1044,7 @@ const createDefaultService = async ({ eventSink, requireProvider, hooksOnly = fa
|
|
|
1044
1044
|
let provider;
|
|
1045
1045
|
let providerForModel;
|
|
1046
1046
|
let providerForMainModel;
|
|
1047
|
+
let providerForTurn;
|
|
1047
1048
|
let providerBillingMode;
|
|
1048
1049
|
const context = parseContextEnvironment(runtimeEnvironment);
|
|
1049
1050
|
const apiKey = runtimeEnvironment.PRAXIS_API_KEY;
|
|
@@ -1164,17 +1165,25 @@ const createDefaultService = async ({ eventSink, requireProvider, hooksOnly = fa
|
|
|
1164
1165
|
providerBillingMode = registry.target.billingMode;
|
|
1165
1166
|
providerForModel = (selectedModel) => registry.create(selectedModel);
|
|
1166
1167
|
const createProvider = providerForModel;
|
|
1167
|
-
|
|
1168
|
+
const createProviderStack = (primaryModel, routeScope) => {
|
|
1168
1169
|
const models = [primaryModel, ...(cli.fallbackModels ?? [])].filter((candidate, index, all) => all.indexOf(candidate) === index);
|
|
1169
1170
|
const providers = models.map((candidate) => createProvider(candidate));
|
|
1170
1171
|
const selected = providers[0];
|
|
1171
1172
|
if (!selected)
|
|
1172
1173
|
throw new Error('A primary model is required');
|
|
1173
1174
|
return providers.length > 1
|
|
1174
|
-
? new FallbackModelProvider({ providers })
|
|
1175
|
+
? new FallbackModelProvider({ providers, routeScope })
|
|
1175
1176
|
: selected;
|
|
1176
1177
|
};
|
|
1177
|
-
|
|
1178
|
+
providerForMainModel = (primaryModel) => createProviderStack(primaryModel, 'completion');
|
|
1179
|
+
const defaultProvider = providerForMainModel(model);
|
|
1180
|
+
provider = defaultProvider;
|
|
1181
|
+
providerForTurn = (turnModel) => {
|
|
1182
|
+
const selectedModel = turnModel ?? model;
|
|
1183
|
+
return selectedModel === undefined
|
|
1184
|
+
? defaultProvider
|
|
1185
|
+
: createProviderStack(selectedModel, 'turn');
|
|
1186
|
+
};
|
|
1178
1187
|
}
|
|
1179
1188
|
catch (error) {
|
|
1180
1189
|
const optionalProviderError = error instanceof ProviderAuthenticationError ||
|
|
@@ -1918,6 +1927,7 @@ const createDefaultService = async ({ eventSink, requireProvider, hooksOnly = fa
|
|
|
1918
1927
|
provider: hostedToolProvider,
|
|
1919
1928
|
...(providerForModel ? { providerForModel } : {}),
|
|
1920
1929
|
...(providerForMainModel ? { providerForMainModel } : {}),
|
|
1930
|
+
...(providerForTurn ? { providerForTurn } : {}),
|
|
1921
1931
|
tools: filteredTools,
|
|
1922
1932
|
toolCapabilityEnvironment: runtimeEnvironment,
|
|
1923
1933
|
...(!experimentalNativeTranscriptWrites ? { mcp: mcpTools } : {}),
|
|
@@ -14,19 +14,13 @@ export interface CodexSubscriptionProviderOptions {
|
|
|
14
14
|
maxErrorBodyBytes?: number;
|
|
15
15
|
thinking?: ModelThinkingConfig;
|
|
16
16
|
}
|
|
17
|
-
export declare function serializeCodexRequest(request: ModelRequest, model: string, configuredThinking?: ModelThinkingConfig): Record<string, unknown>;
|
|
18
|
-
export declare function parseCodexSseFrame(data: string): ModelStreamEvent[];
|
|
19
17
|
export declare class CodexSubscriptionProvider implements ModelProvider {
|
|
20
18
|
private readonly options;
|
|
21
19
|
readonly model: string;
|
|
22
20
|
readonly capabilities: ModelProvider['capabilities'];
|
|
23
21
|
private readonly fetchImplementation;
|
|
24
|
-
private readonly maxStreamBufferBytes;
|
|
25
|
-
private readonly maxToolArgumentsBytes;
|
|
26
|
-
private readonly maxToolCallsPerResponse;
|
|
27
|
-
private readonly maxToolMetadataBytes;
|
|
28
|
-
private readonly maxReasoningBytes;
|
|
29
22
|
private readonly maxErrorBodyBytes;
|
|
23
|
+
private readonly responsesCodec;
|
|
30
24
|
constructor(options: CodexSubscriptionProviderOptions);
|
|
31
25
|
complete(request: ModelRequest): AsyncIterable<ModelStreamEvent>;
|
|
32
26
|
}
|