Add executable detection and export Codex from the SDK (#4532)
Executable detection uses the same rules as the codex wrapper.
This commit is contained in:
12
pnpm-lock.yaml
generated
12
pnpm-lock.yaml
generated
@@ -43,6 +43,9 @@ importers:
|
|||||||
ts-jest:
|
ts-jest:
|
||||||
specifier: ^29.3.4
|
specifier: ^29.3.4
|
||||||
version: 29.4.4(@babel/core@7.28.4)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.4))(esbuild@0.25.10)(jest-util@29.7.0)(jest@29.7.0(@types/node@20.19.18)(ts-node@10.9.2(@types/node@20.19.18)(typescript@5.9.2)))(typescript@5.9.2)
|
version: 29.4.4(@babel/core@7.28.4)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.4))(esbuild@0.25.10)(jest-util@29.7.0)(jest@29.7.0(@types/node@20.19.18)(ts-node@10.9.2(@types/node@20.19.18)(typescript@5.9.2)))(typescript@5.9.2)
|
||||||
|
ts-jest-mock-import-meta:
|
||||||
|
specifier: ^1.3.1
|
||||||
|
version: 1.3.1(ts-jest@29.4.4(@babel/core@7.28.4)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.4))(esbuild@0.25.10)(jest-util@29.7.0)(jest@29.7.0(@types/node@20.19.18)(ts-node@10.9.2(@types/node@20.19.18)(typescript@5.9.2)))(typescript@5.9.2))
|
||||||
ts-node:
|
ts-node:
|
||||||
specifier: ^10.9.2
|
specifier: ^10.9.2
|
||||||
version: 10.9.2(@types/node@20.19.18)(typescript@5.9.2)
|
version: 10.9.2(@types/node@20.19.18)(typescript@5.9.2)
|
||||||
@@ -1979,6 +1982,11 @@ packages:
|
|||||||
ts-interface-checker@0.1.13:
|
ts-interface-checker@0.1.13:
|
||||||
resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==}
|
resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==}
|
||||||
|
|
||||||
|
ts-jest-mock-import-meta@1.3.1:
|
||||||
|
resolution: {integrity: sha512-KGrp9Nh/SdyrQs5hZvtkp0CFPOgAh3DL57NZgFRbtlvMyEo7XuXLbeyylmxFZGGu30pL338h9KxwSxrNDndygw==}
|
||||||
|
peerDependencies:
|
||||||
|
ts-jest: '>=20.0.0'
|
||||||
|
|
||||||
ts-jest@29.4.4:
|
ts-jest@29.4.4:
|
||||||
resolution: {integrity: sha512-ccVcRABct5ZELCT5U0+DZwkXMCcOCLi2doHRrKy1nK/s7J7bch6TzJMsrY09WxgUUIP/ITfmcDS8D2yl63rnXw==}
|
resolution: {integrity: sha512-ccVcRABct5ZELCT5U0+DZwkXMCcOCLi2doHRrKy1nK/s7J7bch6TzJMsrY09WxgUUIP/ITfmcDS8D2yl63rnXw==}
|
||||||
engines: {node: ^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0}
|
engines: {node: ^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0}
|
||||||
@@ -4291,6 +4299,10 @@ snapshots:
|
|||||||
|
|
||||||
ts-interface-checker@0.1.13: {}
|
ts-interface-checker@0.1.13: {}
|
||||||
|
|
||||||
|
ts-jest-mock-import-meta@1.3.1(ts-jest@29.4.4(@babel/core@7.28.4)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.4))(esbuild@0.25.10)(jest-util@29.7.0)(jest@29.7.0(@types/node@20.19.18)(ts-node@10.9.2(@types/node@20.19.18)(typescript@5.9.2)))(typescript@5.9.2)):
|
||||||
|
dependencies:
|
||||||
|
ts-jest: 29.4.4(@babel/core@7.28.4)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.4))(esbuild@0.25.10)(jest-util@29.7.0)(jest@29.7.0(@types/node@20.19.18)(ts-node@10.9.2(@types/node@20.19.18)(typescript@5.9.2)))(typescript@5.9.2)
|
||||||
|
|
||||||
ts-jest@29.4.4(@babel/core@7.28.4)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.4))(esbuild@0.25.10)(jest-util@29.7.0)(jest@29.7.0(@types/node@20.19.18)(ts-node@10.9.2(@types/node@20.19.18)(typescript@5.9.2)))(typescript@5.9.2):
|
ts-jest@29.4.4(@babel/core@7.28.4)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.4))(esbuild@0.25.10)(jest-util@29.7.0)(jest@29.7.0(@types/node@20.19.18)(ts-node@10.9.2(@types/node@20.19.18)(typescript@5.9.2)))(typescript@5.9.2):
|
||||||
dependencies:
|
dependencies:
|
||||||
bs-logger: 0.2.6
|
bs-logger: 0.2.6
|
||||||
|
|||||||
@@ -3,14 +3,29 @@ module.exports = {
|
|||||||
preset: "ts-jest/presets/default-esm",
|
preset: "ts-jest/presets/default-esm",
|
||||||
testEnvironment: "node",
|
testEnvironment: "node",
|
||||||
extensionsToTreatAsEsm: [".ts"],
|
extensionsToTreatAsEsm: [".ts"],
|
||||||
globals: {
|
|
||||||
"ts-jest": {
|
|
||||||
useESM: true,
|
|
||||||
tsconfig: "tsconfig.json",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
moduleNameMapper: {
|
moduleNameMapper: {
|
||||||
"^(\\.{1,2}/.*)\\.js$": "$1",
|
"^(\\.{1,2}/.*)\\.js$": "$1",
|
||||||
},
|
},
|
||||||
testMatch: ["**/tests/**/*.test.ts"],
|
testMatch: ["**/tests/**/*.test.ts"],
|
||||||
|
transform: {
|
||||||
|
"^.+\\.tsx?$": [
|
||||||
|
"ts-jest",
|
||||||
|
{
|
||||||
|
useESM: true,
|
||||||
|
tsconfig: "tsconfig.json",
|
||||||
|
diagnostics: {
|
||||||
|
ignoreCodes: [1343],
|
||||||
|
},
|
||||||
|
astTransformers: {
|
||||||
|
before: [
|
||||||
|
{
|
||||||
|
path: "ts-jest-mock-import-meta",
|
||||||
|
// Workaround for meta.url not working in jest
|
||||||
|
options: { metaObjectReplacement: { url: "file://" + __dirname + "/dist/index.js" } },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -42,15 +42,16 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/jest": "^29.5.14",
|
"@types/jest": "^29.5.14",
|
||||||
"@types/node": "^20.19.18",
|
"@types/node": "^20.19.18",
|
||||||
"typescript-eslint": "^8.45.0",
|
|
||||||
"eslint": "^9.36.0",
|
"eslint": "^9.36.0",
|
||||||
"eslint-config-prettier": "^9.1.2",
|
"eslint-config-prettier": "^9.1.2",
|
||||||
|
"eslint-plugin-jest": "^29.0.1",
|
||||||
"jest": "^29.7.0",
|
"jest": "^29.7.0",
|
||||||
"prettier": "^3.6.2",
|
"prettier": "^3.6.2",
|
||||||
"ts-jest": "^29.3.4",
|
"ts-jest": "^29.3.4",
|
||||||
"ts-node": "^10.9.2",
|
"ts-node": "^10.9.2",
|
||||||
"tsup": "^8.5.0",
|
"tsup": "^8.5.0",
|
||||||
"typescript": "^5.9.2",
|
"typescript": "^5.9.2",
|
||||||
"eslint-plugin-jest": "^29.0.1"
|
"typescript-eslint": "^8.45.0",
|
||||||
|
"ts-jest-mock-import-meta": "^1.3.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,11 +7,7 @@ export class Codex {
|
|||||||
private options: CodexOptions;
|
private options: CodexOptions;
|
||||||
|
|
||||||
constructor(options: CodexOptions) {
|
constructor(options: CodexOptions) {
|
||||||
if (!options.executablePath) {
|
this.exec = new CodexExec(options.codexPathOverride);
|
||||||
throw new Error("executablePath is required");
|
|
||||||
}
|
|
||||||
|
|
||||||
this.exec = new CodexExec(options.executablePath);
|
|
||||||
this.options = options;
|
this.options = options;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
export type CodexOptions = {
|
export type CodexOptions = {
|
||||||
// TODO: remove
|
codexPathOverride?: string;
|
||||||
executablePath: string;
|
|
||||||
// TODO: remove
|
|
||||||
baseUrl?: string;
|
baseUrl?: string;
|
||||||
apiKey?: string;
|
apiKey?: string;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
import { spawn } from "child_process";
|
import { spawn } from "child_process";
|
||||||
|
|
||||||
import readline from "node:readline";
|
import readline from "node:readline";
|
||||||
|
|
||||||
import { SandboxMode } from "./turnOptions";
|
import { SandboxMode } from "./turnOptions";
|
||||||
|
import path from "node:path";
|
||||||
|
import { fileURLToPath } from "node:url";
|
||||||
|
|
||||||
export type CodexExecArgs = {
|
export type CodexExecArgs = {
|
||||||
input: string;
|
input: string;
|
||||||
@@ -15,8 +18,8 @@ export type CodexExecArgs = {
|
|||||||
|
|
||||||
export class CodexExec {
|
export class CodexExec {
|
||||||
private executablePath: string;
|
private executablePath: string;
|
||||||
constructor(executablePath: string) {
|
constructor(executablePath: string | null = null) {
|
||||||
this.executablePath = executablePath;
|
this.executablePath = executablePath || findCodexPath();
|
||||||
}
|
}
|
||||||
|
|
||||||
async *run(args: CodexExecArgs): AsyncGenerator<string> {
|
async *run(args: CodexExecArgs): AsyncGenerator<string> {
|
||||||
@@ -92,3 +95,64 @@ export class CodexExec {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const scriptFileName = fileURLToPath(import.meta.url);
|
||||||
|
const scriptDirName = path.dirname(scriptFileName);
|
||||||
|
|
||||||
|
function findCodexPath() {
|
||||||
|
const { platform, arch } = process;
|
||||||
|
|
||||||
|
let targetTriple = null;
|
||||||
|
switch (platform) {
|
||||||
|
case "linux":
|
||||||
|
case "android":
|
||||||
|
switch (arch) {
|
||||||
|
case "x64":
|
||||||
|
targetTriple = "x86_64-unknown-linux-musl";
|
||||||
|
break;
|
||||||
|
case "arm64":
|
||||||
|
targetTriple = "aarch64-unknown-linux-musl";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "darwin":
|
||||||
|
switch (arch) {
|
||||||
|
case "x64":
|
||||||
|
targetTriple = "x86_64-apple-darwin";
|
||||||
|
break;
|
||||||
|
case "arm64":
|
||||||
|
targetTriple = "aarch64-apple-darwin";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "win32":
|
||||||
|
switch (arch) {
|
||||||
|
case "x64":
|
||||||
|
targetTriple = "x86_64-pc-windows-msvc";
|
||||||
|
break;
|
||||||
|
case "arm64":
|
||||||
|
targetTriple = "aarch64-pc-windows-msvc";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!targetTriple) {
|
||||||
|
throw new Error(`Unsupported platform: ${platform} (${arch})`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const vendorRoot = path.join(scriptDirName, "..", "vendor");
|
||||||
|
const archRoot = path.join(vendorRoot, targetTriple);
|
||||||
|
const codexBinaryName = process.platform === "win32" ? "codex.exe" : "codex";
|
||||||
|
const binaryPath = path.join(archRoot, "codex", codexBinaryName);
|
||||||
|
|
||||||
|
return binaryPath;
|
||||||
|
}
|
||||||
|
|||||||
@@ -22,9 +22,9 @@ export type {
|
|||||||
ErrorItem,
|
ErrorItem,
|
||||||
} from "./items";
|
} from "./items";
|
||||||
|
|
||||||
export type { Thread, RunResult, RunStreamedResult, Input } from "./thread";
|
export { Thread, RunResult, RunStreamedResult, Input } from "./thread";
|
||||||
|
|
||||||
export type { Codex } from "./codex";
|
export { Codex } from "./codex";
|
||||||
|
|
||||||
export type { CodexOptions } from "./codexOptions";
|
export type { CodexOptions } from "./codexOptions";
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ describe("Codex", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const client = new Codex({ executablePath: codexExecPath, baseUrl: url, apiKey: "test" });
|
const client = new Codex({ codexPathOverride: codexExecPath, baseUrl: url, apiKey: "test" });
|
||||||
|
|
||||||
const thread = client.startThread();
|
const thread = client.startThread();
|
||||||
const result = await thread.run("Hello, world!");
|
const result = await thread.run("Hello, world!");
|
||||||
@@ -60,7 +60,7 @@ describe("Codex", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const client = new Codex({ executablePath: codexExecPath, baseUrl: url, apiKey: "test" });
|
const client = new Codex({ codexPathOverride: codexExecPath, baseUrl: url, apiKey: "test" });
|
||||||
|
|
||||||
const thread = client.startThread();
|
const thread = client.startThread();
|
||||||
await thread.run("first input");
|
await thread.run("first input");
|
||||||
@@ -103,7 +103,7 @@ describe("Codex", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const client = new Codex({ executablePath: codexExecPath, baseUrl: url, apiKey: "test" });
|
const client = new Codex({ codexPathOverride: codexExecPath, baseUrl: url, apiKey: "test" });
|
||||||
|
|
||||||
const thread = client.startThread();
|
const thread = client.startThread();
|
||||||
await thread.run("first input");
|
await thread.run("first input");
|
||||||
@@ -149,7 +149,7 @@ describe("Codex", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const client = new Codex({ executablePath: codexExecPath, baseUrl: url, apiKey: "test" });
|
const client = new Codex({ codexPathOverride: codexExecPath, baseUrl: url, apiKey: "test" });
|
||||||
|
|
||||||
const originalThread = client.startThread();
|
const originalThread = client.startThread();
|
||||||
await originalThread.run("first input");
|
await originalThread.run("first input");
|
||||||
@@ -193,7 +193,7 @@ describe("Codex", () => {
|
|||||||
const { args: spawnArgs, restore } = codexExecSpy();
|
const { args: spawnArgs, restore } = codexExecSpy();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const client = new Codex({ executablePath: codexExecPath, baseUrl: url, apiKey: "test" });
|
const client = new Codex({ codexPathOverride: codexExecPath, baseUrl: url, apiKey: "test" });
|
||||||
|
|
||||||
const thread = client.startThread();
|
const thread = client.startThread();
|
||||||
await thread.run("apply options", {
|
await thread.run("apply options", {
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ describe("Codex", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const client = new Codex({ executablePath: codexExecPath, baseUrl: url, apiKey: "test" });
|
const client = new Codex({ codexPathOverride: codexExecPath, baseUrl: url, apiKey: "test" });
|
||||||
|
|
||||||
const thread = client.startThread();
|
const thread = client.startThread();
|
||||||
const result = await thread.runStreamed("Hello, world!");
|
const result = await thread.runStreamed("Hello, world!");
|
||||||
@@ -82,7 +82,7 @@ describe("Codex", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const client = new Codex({ executablePath: codexExecPath, baseUrl: url, apiKey: "test" });
|
const client = new Codex({ codexPathOverride: codexExecPath, baseUrl: url, apiKey: "test" });
|
||||||
|
|
||||||
const thread = client.startThread();
|
const thread = client.startThread();
|
||||||
const first = await thread.runStreamed("first input");
|
const first = await thread.runStreamed("first input");
|
||||||
@@ -128,7 +128,7 @@ describe("Codex", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const client = new Codex({ executablePath: codexExecPath, baseUrl: url, apiKey: "test" });
|
const client = new Codex({ codexPathOverride: codexExecPath, baseUrl: url, apiKey: "test" });
|
||||||
|
|
||||||
const originalThread = client.startThread();
|
const originalThread = client.startThread();
|
||||||
const first = await originalThread.runStreamed("first input");
|
const first = await originalThread.runStreamed("first input");
|
||||||
|
|||||||
@@ -16,7 +16,8 @@
|
|||||||
"declaration": true,
|
"declaration": true,
|
||||||
"declarationMap": true,
|
"declarationMap": true,
|
||||||
"noImplicitAny": true,
|
"noImplicitAny": true,
|
||||||
"outDir": "dist"
|
"outDir": "dist",
|
||||||
|
"stripInternal": true
|
||||||
},
|
},
|
||||||
"include": ["src", "tests", "tsup.config.ts"],
|
"include": ["src", "tests", "tsup.config.ts"],
|
||||||
"exclude": ["dist", "node_modules"]
|
"exclude": ["dist", "node_modules"]
|
||||||
|
|||||||
Reference in New Issue
Block a user