pi-openai-codex-compat 0.0.5 → 0.0.7-alpha.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/CHANGELOG.md +18 -0
- package/README.md +9 -2
- package/extensions/openai-codex-compat/codex-protocol.ts +7 -3
- package/extensions/openai-codex-compat/codex-stream.ts +1 -1
- package/extensions/openai-codex-compat/codex-transport.ts +1 -1
- package/extensions/openai-codex-compat/footer.ts +9 -0
- package/extensions/openai-codex-compat/remote-compaction.ts +4 -6
- package/extensions/openai-codex-compat/tool-runtime.ts +2 -2
- package/extensions/openai-codex-compat/vendor/pi-ai/README.md +1 -1
- package/extensions/openai-codex-compat/vendor/pi-ai/openai-responses-serialization.ts +1 -1
- package/package.json +9 -7
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
### Security
|
|
6
|
+
|
|
7
|
+
- Require npm releases to match a locally built SHA-256 recorded in an SSH-signed release commit before trusted publishing can stage the package.
|
|
8
|
+
|
|
9
|
+
## 0.0.6 - 2026-08-10
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- Add `npm run pack:dry` to inspect the npm package contents before release.
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
- Require Pi 0.84.x, use Pi 0.84.1 as the development integration baseline, and preserve Pi 0.84 header removals across Codex tools and native compaction.
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
|
|
21
|
+
- Support Pi 0.84's subscription-aware default footer without crashing during startup.
|
|
22
|
+
|
|
5
23
|
## 0.0.5 - 2026-08-07
|
|
6
24
|
|
|
7
25
|
### Fixed
|
package/README.md
CHANGED
|
@@ -20,7 +20,7 @@ Pi provides the Codex OAuth flow and model catalog. At session start, this packa
|
|
|
20
20
|
## Requirements
|
|
21
21
|
|
|
22
22
|
- Node.js 22.19 or newer
|
|
23
|
-
- Pi `>=0.
|
|
23
|
+
- Pi `>=0.84.0 <0.85.0`
|
|
24
24
|
- An OpenAI Codex login in Pi
|
|
25
25
|
|
|
26
26
|
Authenticate through Pi if needed:
|
|
@@ -379,6 +379,7 @@ mise install
|
|
|
379
379
|
npm install
|
|
380
380
|
npm run check
|
|
381
381
|
npm test
|
|
382
|
+
npm run pack:dry
|
|
382
383
|
```
|
|
383
384
|
|
|
384
385
|
Run the credentialed Pi/Codex integration tests separately. They load the real
|
|
@@ -403,7 +404,13 @@ search, and compaction continuation.
|
|
|
403
404
|
|
|
404
405
|
## Release staging
|
|
405
406
|
|
|
406
|
-
|
|
407
|
+
1. Run `npm run release -- X.Y.Z` from a clean, synchronized `main`.
|
|
408
|
+
2. The command builds the exact package locally, records its SHA-256 in an SSH-signed release commit, proves a clean rebuild is reproducible, and creates a lightweight tag.
|
|
409
|
+
3. Inspect the result, then push atomically with `git push --atomic origin main vX.Y.Z`.
|
|
410
|
+
4. A read-only GitHub Actions job validates and packs the package. A separate GitHub-owned job verifies the signature and signed digest before attesting and staging that exact archive through npm trusted publishing.
|
|
411
|
+
5. Approve the staged package on npmjs.com, or with `npm stage approve <stage-id>`.
|
|
412
|
+
|
|
413
|
+
Stable releases use `latest`; prereleases derive their npm dist-tag from the first prerelease identifier.
|
|
407
414
|
|
|
408
415
|
## Acknowledgements
|
|
409
416
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { calculateCost, type Model, type Usage } from "@earendil-works/pi-ai";
|
|
1
|
+
import { calculateCost, type Model, type ProviderHeaders, type Usage } from "@earendil-works/pi-ai";
|
|
2
2
|
|
|
3
3
|
export const REMOTE_COMPACTION_BETA = "remote_compaction_v2";
|
|
4
4
|
export const RETAINED_CONTEXT_BUDGET = 64_000;
|
|
@@ -327,10 +327,14 @@ function accountIdFromToken(token: string): string {
|
|
|
327
327
|
|
|
328
328
|
export function remoteCompactionHeaders(options: {
|
|
329
329
|
token: string;
|
|
330
|
-
providerHeaders?:
|
|
330
|
+
providerHeaders?: ProviderHeaders | undefined;
|
|
331
331
|
sessionId: string;
|
|
332
332
|
}): Headers {
|
|
333
|
-
const headers = new Headers(
|
|
333
|
+
const headers = new Headers();
|
|
334
|
+
for (const [name, value] of Object.entries(options.providerHeaders ?? {})) {
|
|
335
|
+
if (value === null) headers.delete(name);
|
|
336
|
+
else headers.set(name, value);
|
|
337
|
+
}
|
|
334
338
|
headers.set("authorization", `Bearer ${options.token}`);
|
|
335
339
|
headers.set("chatgpt-account-id", accountIdFromToken(options.token));
|
|
336
340
|
headers.set("originator", "pi");
|
|
@@ -14,7 +14,7 @@ import { isObject, type JsonRecord } from "./codex-protocol.ts";
|
|
|
14
14
|
import { CODEX_NAMESPACED_TOOL_NAMES, namespacedToolCallName } from "./namespaced-tools.ts";
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
|
-
* Focused adaptation of @earendil-works/pi-ai@0.
|
|
17
|
+
* Focused adaptation of @earendil-works/pi-ai@0.84.1
|
|
18
18
|
* src/api/openai-responses-shared.ts stream processing.
|
|
19
19
|
*/
|
|
20
20
|
|
|
@@ -21,7 +21,7 @@ import { normalizeReplayItem, stableResponsesJson } from "./responses-replay.ts"
|
|
|
21
21
|
import { applyResponsesLiteHeaders, responsesLiteSsePayload } from "./responses-lite.ts";
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
|
-
* Focused adaptation of @earendil-works/pi-ai@0.
|
|
24
|
+
* Focused adaptation of @earendil-works/pi-ai@0.84.1
|
|
25
25
|
* src/api/openai-codex-responses.ts transport behavior.
|
|
26
26
|
*/
|
|
27
27
|
|
|
@@ -59,6 +59,15 @@ function footerSession(ctx: ExtensionContext, resolveConfig: ConfigResolver): Fo
|
|
|
59
59
|
model && model.provider === provider && ctx.modelRegistry.isUsingOAuth(model),
|
|
60
60
|
);
|
|
61
61
|
},
|
|
62
|
+
isUsingSubscription(provider: string) {
|
|
63
|
+
const model = ctx.model;
|
|
64
|
+
return Boolean(
|
|
65
|
+
model &&
|
|
66
|
+
model.provider === provider &&
|
|
67
|
+
ctx.modelRegistry.isUsingOAuth(model) &&
|
|
68
|
+
ctx.modelRegistry.getProvider(provider)?.auth.oauth?.isSubscription === true,
|
|
69
|
+
);
|
|
70
|
+
},
|
|
62
71
|
},
|
|
63
72
|
} as unknown as FooterSession;
|
|
64
73
|
}
|
|
@@ -6,7 +6,7 @@ import type {
|
|
|
6
6
|
SessionEntry,
|
|
7
7
|
ToolInfo,
|
|
8
8
|
} from "@earendil-works/pi-coding-agent";
|
|
9
|
-
import type { Model, OpenAICodexResponsesOptions } from "@earendil-works/pi-ai";
|
|
9
|
+
import type { Model, OpenAICodexResponsesOptions, ProviderHeaders } from "@earendil-works/pi-ai";
|
|
10
10
|
import { addRemoteCompactionFeature, type JsonRecord } from "./codex-protocol.ts";
|
|
11
11
|
import {
|
|
12
12
|
activeResponsesTools,
|
|
@@ -40,12 +40,10 @@ function appendFeatureHeader(headers: Record<string, string | null>): void {
|
|
|
40
40
|
else headers["x-codex-beta-features"] = addRemoteCompactionFeature(undefined);
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
function featureHeaders(headers:
|
|
44
|
-
const result:
|
|
43
|
+
function featureHeaders(headers: ProviderHeaders | undefined): ProviderHeaders {
|
|
44
|
+
const result: ProviderHeaders = { ...headers };
|
|
45
45
|
appendFeatureHeader(result);
|
|
46
|
-
return
|
|
47
|
-
Object.entries(result).filter((entry): entry is [string, string] => entry[1] !== null),
|
|
48
|
-
);
|
|
46
|
+
return result;
|
|
49
47
|
}
|
|
50
48
|
|
|
51
49
|
function markerSummary(): string {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ExtensionAPI, ExtensionContext, SessionEntry } from "@earendil-works/pi-coding-agent";
|
|
2
|
-
import type { Model } from "@earendil-works/pi-ai";
|
|
2
|
+
import type { Model, ProviderHeaders } from "@earendil-works/pi-ai";
|
|
3
3
|
import { providerHistory } from "./compaction-checkpoint.ts";
|
|
4
4
|
import type { ImageDetail } from "./config.ts";
|
|
5
5
|
import type { ResponsesItem } from "./codex-protocol.ts";
|
|
@@ -7,7 +7,7 @@ import type { ResponsesItem } from "./codex-protocol.ts";
|
|
|
7
7
|
export async function codexToolAuthentication(
|
|
8
8
|
ctx: ExtensionContext,
|
|
9
9
|
model: Model<any>,
|
|
10
|
-
): Promise<{ apiKey: string; headers?:
|
|
10
|
+
): Promise<{ apiKey: string; headers?: ProviderHeaders }> {
|
|
11
11
|
const authentication = await ctx.modelRegistry.getApiKeyAndHeaders(model);
|
|
12
12
|
if (!authentication.ok) throw new Error(authentication.error);
|
|
13
13
|
if (!authentication.apiKey) throw new Error("OpenAI Codex authentication is unavailable.");
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
This directory intentionally contains only the Pi AI methods needed to serialize checkpoint and native replay history for OpenAI's Responses API. It does not contain Pi AI's complete source dependency graph.
|
|
4
4
|
|
|
5
|
-
[`openai-responses-serialization.ts`](openai-responses-serialization.ts) adapts the relevant methods from `@earendil-works/pi-ai@0.
|
|
5
|
+
[`openai-responses-serialization.ts`](openai-responses-serialization.ts) adapts the relevant methods from `@earendil-works/pi-ai@0.84.1`. Its header lists the upstream source files. Keep the behavioral equivalence test in [`test/pi-ai-serialization.test.ts`](../../../../test/pi-ai-serialization.test.ts) passing when updating the Pi dependencies.
|
|
6
6
|
|
|
7
7
|
The optional `namespacedToolNames`, `textContentItemToolResultNames`, and `toolResultImageDetail` paths are extension-owned additions. Without those options, serialization must continue to match Pi AI. `namespacedToolNames` groups only the fixed Codex allowlist into native Responses namespaces and replays namespace/member call identities. `textContentItemToolResultNames` preserves Codex tools such as `web.run` whose successful text output is transported as an `input_text` content-item array instead of Pi's usual plain string. `toolResultImageDetail` overrides the otherwise canonical `auto` detail used for image tool-result content.
|
|
8
8
|
|
|
@@ -13,7 +13,7 @@ import type {
|
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* Focused copies of the methods used to serialize Pi messages for OpenAI's
|
|
16
|
-
* Responses API. Adapted from @earendil-works/pi-ai@0.
|
|
16
|
+
* Responses API. Adapted from @earendil-works/pi-ai@0.84.1:
|
|
17
17
|
*
|
|
18
18
|
* - src/api/openai-responses-shared.ts
|
|
19
19
|
* - src/api/transform-messages.ts
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-openai-codex-compat",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.7-alpha.0",
|
|
4
4
|
"description": "OpenAI Codex compatibility for Pi with native compaction, fast mode, and Codex-optimized capabilities",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi-package"
|
|
@@ -32,14 +32,16 @@
|
|
|
32
32
|
"check": "hk check --all --check",
|
|
33
33
|
"test": "node --test --test-concurrency=1 test/*.test.ts",
|
|
34
34
|
"test:live:codex": "PI_CODEX_LIVE_TEST=1 node --test --test-concurrency=1 test/codex-host.live.test.ts",
|
|
35
|
+
"pack:dry": "npm pack --dry-run --allow-directory=all",
|
|
36
|
+
"release": "node scripts/release.ts",
|
|
35
37
|
"fmt": "oxfmt",
|
|
36
38
|
"lint": "oxlint",
|
|
37
39
|
"lint:fix": "oxlint --fix"
|
|
38
40
|
},
|
|
39
41
|
"devDependencies": {
|
|
40
|
-
"@earendil-works/pi-ai": "0.
|
|
41
|
-
"@earendil-works/pi-coding-agent": "0.
|
|
42
|
-
"@earendil-works/pi-tui": "0.
|
|
42
|
+
"@earendil-works/pi-ai": "0.84.1",
|
|
43
|
+
"@earendil-works/pi-coding-agent": "0.84.1",
|
|
44
|
+
"@earendil-works/pi-tui": "0.84.1",
|
|
43
45
|
"@types/node": "22.20.1",
|
|
44
46
|
"oxfmt": "0.60.0",
|
|
45
47
|
"oxlint": "1.75.0",
|
|
@@ -48,9 +50,9 @@
|
|
|
48
50
|
"typescript": "7.0.2"
|
|
49
51
|
},
|
|
50
52
|
"peerDependencies": {
|
|
51
|
-
"@earendil-works/pi-ai": ">=0.
|
|
52
|
-
"@earendil-works/pi-coding-agent": ">=0.
|
|
53
|
-
"@earendil-works/pi-tui": ">=0.
|
|
53
|
+
"@earendil-works/pi-ai": ">=0.84.0 <0.85.0",
|
|
54
|
+
"@earendil-works/pi-coding-agent": ">=0.84.0 <0.85.0",
|
|
55
|
+
"@earendil-works/pi-tui": ">=0.84.0 <0.85.0",
|
|
54
56
|
"typebox": "*"
|
|
55
57
|
},
|
|
56
58
|
"engines": {
|