@mastra/code-sdk 1.0.3-alpha.0 → 1.1.0-alpha.2
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 +49 -0
- package/dist/acp/agent.js +155 -167
- package/dist/acp/agent.js.map +1 -1
- package/dist/acp/event-mapper.js +193 -168
- package/dist/acp/event-mapper.js.map +1 -1
- package/dist/acp/index.js +60 -49
- package/dist/acp/index.js.map +1 -1
- package/dist/acp/server.js +31 -30
- package/dist/acp/server.js.map +1 -1
- package/dist/acp.js +1 -4
- package/dist/agents/credential-resolver.js +40 -29
- package/dist/agents/credential-resolver.js.map +1 -1
- package/dist/agents/custom-provider-source.js +16 -9
- package/dist/agents/custom-provider-source.js.map +1 -1
- package/dist/agents/instructions.js +27 -36
- package/dist/agents/instructions.js.map +1 -1
- package/dist/agents/mastracode-gateway.js +355 -428
- package/dist/agents/mastracode-gateway.js.map +1 -1
- package/dist/agents/memory.js +87 -78
- package/dist/agents/memory.js.map +1 -1
- package/dist/agents/model.js +114 -119
- package/dist/agents/model.js.map +1 -1
- package/dist/agents/modes/build.js +12 -13
- package/dist/agents/modes/build.js.map +1 -1
- package/dist/agents/modes/explore.js +14 -13
- package/dist/agents/modes/explore.js.map +1 -1
- package/dist/agents/modes/plan.js +14 -15
- package/dist/agents/modes/plan.js.map +1 -1
- package/dist/agents/prompts/agent-instructions.js +78 -69
- package/dist/agents/prompts/agent-instructions.js.map +1 -1
- package/dist/agents/prompts/build.js +19 -16
- package/dist/agents/prompts/build.js.map +1 -1
- package/dist/agents/prompts/fast.js +8 -4
- package/dist/agents/prompts/fast.js.map +1 -1
- package/dist/agents/prompts/index.js +48 -47
- package/dist/agents/prompts/index.js.map +1 -1
- package/dist/agents/prompts/model.js +6 -5
- package/dist/agents/prompts/model.js.map +1 -1
- package/dist/agents/prompts/plan.js +20 -16
- package/dist/agents/prompts/plan.js.map +1 -1
- package/dist/agents/prompts/tool-guidance.js +77 -109
- package/dist/agents/prompts/tool-guidance.js.map +1 -1
- package/dist/agents/sandbox-filesystem.js +245 -259
- package/dist/agents/sandbox-filesystem.js.map +1 -1
- package/dist/agents/sandbox-reattach.js +9 -11
- package/dist/agents/sandbox-reattach.js.map +1 -1
- package/dist/agents/thread-caveman-state.js +92 -81
- package/dist/agents/thread-caveman-state.js.map +1 -1
- package/dist/agents/tool-availability.js +62 -80
- package/dist/agents/tool-availability.js.map +1 -1
- package/dist/agents/tools.js +99 -139
- package/dist/agents/tools.js.map +1 -1
- package/dist/agents/workspace.js +232 -225
- package/dist/agents/workspace.js.map +1 -1
- package/dist/analytics.js +139 -128
- package/dist/analytics.js.map +1 -1
- package/dist/auth/authorization-input.js +39 -25
- package/dist/auth/authorization-input.js.map +1 -1
- package/dist/auth/device-code.js +112 -80
- package/dist/auth/device-code.js.map +1 -1
- package/dist/auth/index.js +2 -9
- package/dist/auth/pkce.js +27 -16
- package/dist/auth/pkce.js.map +1 -1
- package/dist/auth/providers/anthropic.js +107 -93
- package/dist/auth/providers/anthropic.js.map +1 -1
- package/dist/auth/providers/github-copilot.js +304 -293
- package/dist/auth/providers/github-copilot.js.map +1 -1
- package/dist/auth/providers/openai-codex.js +442 -460
- package/dist/auth/providers/openai-codex.js.map +1 -1
- package/dist/auth/providers/xai.js +179 -145
- package/dist/auth/providers/xai.js.map +1 -1
- package/dist/auth/storage.js +182 -175
- package/dist/auth/storage.js.map +1 -1
- package/dist/auth/types.js +1 -1
- package/dist/clipboard/index.js +206 -172
- package/dist/clipboard/index.js.map +1 -1
- package/dist/constants.js +11 -16
- package/dist/constants.js.map +1 -1
- package/dist/error-classification.js +19 -11
- package/dist/error-classification.js.map +1 -1
- package/dist/evals/context-builder.js +145 -104
- package/dist/evals/context-builder.js.map +1 -1
- package/dist/evals/index.js +4 -7
- package/dist/evals/scorers/classify-command.js +62 -41
- package/dist/evals/scorers/classify-command.js.map +1 -1
- package/dist/evals/scorers/efficiency.js +239 -181
- package/dist/evals/scorers/efficiency.js.map +1 -1
- package/dist/evals/scorers/extract-tools.js +51 -47
- package/dist/evals/scorers/extract-tools.js.map +1 -1
- package/dist/evals/scorers/index.js +1 -5
- package/dist/evals/scorers/outcome.js +321 -212
- package/dist/evals/scorers/outcome.js.map +1 -1
- package/dist/goal-manager.js +266 -261
- package/dist/goal-manager.js.map +1 -1
- package/dist/goal-signal.js +14 -13
- package/dist/goal-signal.js.map +1 -1
- package/dist/headless/cli.js +153 -154
- package/dist/headless/cli.js.map +1 -1
- package/dist/headless/flags.js +180 -178
- package/dist/headless/flags.js.map +1 -1
- package/dist/headless/format.js +72 -71
- package/dist/headless/format.js.map +1 -1
- package/dist/headless/index.js +5 -31
- package/dist/headless/policy.js +35 -31
- package/dist/headless/policy.js.map +1 -1
- package/dist/headless/run-mc.js +332 -334
- package/dist/headless/run-mc.js.map +1 -1
- package/dist/headless/types.js +16 -7
- package/dist/headless/types.js.map +1 -1
- package/dist/hooks/config.js +56 -61
- package/dist/hooks/config.js.map +1 -1
- package/dist/hooks/executor.js +118 -116
- package/dist/hooks/executor.js.map +1 -1
- package/dist/hooks/index.js +4 -15
- package/dist/hooks/manager.js +221 -280
- package/dist/hooks/manager.js.map +1 -1
- package/dist/hooks/types.js +5 -4
- package/dist/hooks/types.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +632 -712
- package/dist/index.js.map +1 -1
- package/dist/ipc/ipc-reporter.js +19 -22
- package/dist/ipc/ipc-reporter.js.map +1 -1
- package/dist/lsp/client.js +248 -306
- package/dist/lsp/client.js.map +1 -1
- package/dist/lsp/index.js +1 -6
- package/dist/lsp/language.js +39 -43
- package/dist/lsp/language.js.map +1 -1
- package/dist/lsp/manager.js +78 -93
- package/dist/lsp/manager.js.map +1 -1
- package/dist/lsp/server.js +151 -120
- package/dist/lsp/server.js.map +1 -1
- package/dist/lsp/workspace.js +50 -47
- package/dist/lsp/workspace.js.map +1 -1
- package/dist/mcp/config.js +210 -199
- package/dist/mcp/config.js.map +1 -1
- package/dist/mcp/index.js +2 -9
- package/dist/mcp/manager.js +482 -475
- package/dist/mcp/manager.js.map +1 -1
- package/dist/mcp/types.js +1 -1
- package/dist/onboarding/custom-packs.js +14 -17
- package/dist/onboarding/custom-packs.js.map +1 -1
- package/dist/onboarding/custom-providers.js +22 -20
- package/dist/onboarding/custom-providers.js.map +1 -1
- package/dist/onboarding/index.d.ts +1 -1
- package/dist/onboarding/index.d.ts.map +1 -1
- package/dist/onboarding/index.js +3 -21
- package/dist/onboarding/om-settings.d.ts +5 -0
- package/dist/onboarding/om-settings.d.ts.map +1 -1
- package/dist/onboarding/om-settings.js +41 -20
- package/dist/onboarding/om-settings.js.map +1 -1
- package/dist/onboarding/packs.d.ts +4 -6
- package/dist/onboarding/packs.d.ts.map +1 -1
- package/dist/onboarding/packs.js +154 -105
- package/dist/onboarding/packs.js.map +1 -1
- package/dist/onboarding/settings.js +575 -517
- package/dist/onboarding/settings.js.map +1 -1
- package/dist/permissions.js +112 -99
- package/dist/permissions.js.map +1 -1
- package/dist/plugin.js +21 -23
- package/dist/plugin.js.map +1 -1
- package/dist/plugins/dependencies.js +64 -87
- package/dist/plugins/dependencies.js.map +1 -1
- package/dist/plugins/install.js +159 -169
- package/dist/plugins/install.js.map +1 -1
- package/dist/plugins/loader.js +170 -185
- package/dist/plugins/loader.js.map +1 -1
- package/dist/plugins/manager.js +374 -380
- package/dist/plugins/manager.js.map +1 -1
- package/dist/plugins/manifest.js +38 -63
- package/dist/plugins/manifest.js.map +1 -1
- package/dist/plugins/package-link.js +48 -64
- package/dist/plugins/package-link.js.map +1 -1
- package/dist/plugins/paths.js +18 -19
- package/dist/plugins/paths.js.map +1 -1
- package/dist/plugins/registry.js +97 -81
- package/dist/plugins/registry.js.map +1 -1
- package/dist/plugins/scaffold.js +62 -98
- package/dist/plugins/scaffold.js.map +1 -1
- package/dist/plugins/types.js +1 -1
- package/dist/processors/plan-rejection-abort.js +45 -44
- package/dist/processors/plan-rejection-abort.js.map +1 -1
- package/dist/providers/amazon-bedrock-gateway.js +134 -125
- package/dist/providers/amazon-bedrock-gateway.js.map +1 -1
- package/dist/providers/amazon-bedrock.js +68 -47
- package/dist/providers/amazon-bedrock.js.map +1 -1
- package/dist/providers/claude-max.js +153 -133
- package/dist/providers/claude-max.js.map +1 -1
- package/dist/providers/github-copilot.js +232 -230
- package/dist/providers/github-copilot.js.map +1 -1
- package/dist/providers/openai-codex.js +271 -260
- package/dist/providers/openai-codex.js.map +1 -1
- package/dist/providers/xai.js +57 -50
- package/dist/providers/xai.js.map +1 -1
- package/dist/schema.js +91 -89
- package/dist/schema.js.map +1 -1
- package/dist/theme-palette.js +18 -14
- package/dist/theme-palette.js.map +1 -1
- package/dist/tool-names.js +46 -37
- package/dist/tool-names.js.map +1 -1
- package/dist/tools/index.js +2 -8
- package/dist/tools/request-sandbox-access.js +71 -80
- package/dist/tools/request-sandbox-access.js.map +1 -1
- package/dist/tools/utils.js +26 -16
- package/dist/tools/utils.js.map +1 -1
- package/dist/tools/web-search.js +51 -55
- package/dist/tools/web-search.js.map +1 -1
- package/dist/utils/binaries.js +65 -61
- package/dist/utils/binaries.js.map +1 -1
- package/dist/utils/debug-log.js +51 -47
- package/dist/utils/debug-log.js.map +1 -1
- package/dist/utils/errors.js +157 -192
- package/dist/utils/errors.js.map +1 -1
- package/dist/utils/gateway-sync.js +49 -37
- package/dist/utils/gateway-sync.js.map +1 -1
- package/dist/utils/path-security.js +7 -6
- package/dist/utils/path-security.js.map +1 -1
- package/dist/utils/plan-diff.js +58 -39
- package/dist/utils/plan-diff.js.map +1 -1
- package/dist/utils/plans.js +92 -74
- package/dist/utils/plans.js.map +1 -1
- package/dist/utils/project.js +318 -256
- package/dist/utils/project.js.map +1 -1
- package/dist/utils/signals-pubsub.js +117 -99
- package/dist/utils/signals-pubsub.js.map +1 -1
- package/dist/utils/slash-command-loader.js +118 -154
- package/dist/utils/slash-command-loader.js.map +1 -1
- package/dist/utils/slash-command-processor.js +92 -83
- package/dist/utils/slash-command-processor.js.map +1 -1
- package/dist/utils/stdin-pipe.js +87 -63
- package/dist/utils/stdin-pipe.js.map +1 -1
- package/dist/utils/storage-factory.js +104 -84
- package/dist/utils/storage-factory.js.map +1 -1
- package/dist/utils/storage-maintenance.js +249 -211
- package/dist/utils/storage-maintenance.js.map +1 -1
- package/dist/utils/thread-lock.js +96 -92
- package/dist/utils/thread-lock.js.map +1 -1
- package/dist/utils/token-estimator.js +12 -12
- package/dist/utils/token-estimator.js.map +1 -1
- package/dist/utils/update-check.d.ts +1 -1
- package/dist/utils/update-check.js +341 -259
- package/dist/utils/update-check.js.map +1 -1
- package/dist/voice/stt-registry.js +131 -113
- package/dist/voice/stt-registry.js.map +1 -1
- package/package.json +11 -11
- package/dist/acp.js.map +0 -1
- package/dist/auth/index.js.map +0 -1
- package/dist/auth/types.js.map +0 -1
- package/dist/evals/index.js.map +0 -1
- package/dist/evals/scorers/index.js.map +0 -1
- package/dist/headless/index.js.map +0 -1
- package/dist/hooks/index.js.map +0 -1
- package/dist/lsp/index.js.map +0 -1
- package/dist/mcp/index.js.map +0 -1
- package/dist/mcp/types.js.map +0 -1
- package/dist/onboarding/index.js.map +0 -1
- package/dist/plugins/types.js.map +0 -1
- package/dist/tools/index.js.map +0 -1
|
@@ -1,291 +1,302 @@
|
|
|
1
|
+
import { AuthStorage } from "../auth/storage.js";
|
|
1
2
|
import { createOpenAI } from "@ai-sdk/openai";
|
|
2
3
|
import { wrapLanguageModel } from "ai";
|
|
3
|
-
|
|
4
|
+
//#region src/providers/openai-codex.ts
|
|
5
|
+
/**
|
|
6
|
+
* OpenAI Codex OAuth Provider
|
|
7
|
+
*
|
|
8
|
+
* Uses OAuth tokens from AuthStorage to authenticate with ChatGPT Plus/Pro subscription.
|
|
9
|
+
* This allows access to OpenAI models through the ChatGPT OAuth flow.
|
|
10
|
+
*
|
|
11
|
+
* Inspired by opencode's Codex plugin implementation:
|
|
12
|
+
* https://github.com/sst/opencode/blob/main/packages/opencode/src/plugin/codex.ts
|
|
13
|
+
*/
|
|
4
14
|
const CODEX_API_ENDPOINT = "https://chatgpt.com/backend-api/codex/responses";
|
|
5
15
|
const CODEX_ORIGINATOR = "mastracode";
|
|
6
16
|
const CODEX_USER_AGENT = "mastracode";
|
|
7
17
|
let authStorageInstance = null;
|
|
18
|
+
/**
|
|
19
|
+
* Get or create the shared AuthStorage instance
|
|
20
|
+
*/
|
|
8
21
|
function getAuthStorage() {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
}
|
|
12
|
-
return authStorageInstance;
|
|
22
|
+
if (!authStorageInstance) authStorageInstance = new AuthStorage();
|
|
23
|
+
return authStorageInstance;
|
|
13
24
|
}
|
|
25
|
+
/**
|
|
26
|
+
* Set a custom AuthStorage instance (useful for TUI integration)
|
|
27
|
+
*/
|
|
14
28
|
function setAuthStorage(storage) {
|
|
15
|
-
|
|
29
|
+
authStorageInstance = storage ?? null;
|
|
16
30
|
}
|
|
17
31
|
const CODEX_INSTRUCTIONS = `You are an interactive CLI tool that helps users with software engineering tasks. Use the instructions below and the tools available to you to assist the user.
|
|
18
32
|
|
|
19
33
|
IMPORTANT: You should be concise, direct, and helpful. Focus on solving the user's problem efficiently.`;
|
|
20
34
|
const GPT5_MODEL_RE = /^gpt-5(?:\.|-|$)/;
|
|
21
35
|
function getEffectiveThinkingLevel(modelId, level) {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
25
|
-
return level;
|
|
36
|
+
if (GPT5_MODEL_RE.test(modelId) && level === "off") return "low";
|
|
37
|
+
return level;
|
|
26
38
|
}
|
|
27
39
|
const THINKING_LEVEL_TO_REASONING_EFFORT = {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
40
|
+
off: void 0,
|
|
41
|
+
low: "low",
|
|
42
|
+
medium: "medium",
|
|
43
|
+
high: "high",
|
|
44
|
+
xhigh: "xhigh"
|
|
33
45
|
};
|
|
46
|
+
/**
|
|
47
|
+
* Create Codex middleware with the given reasoning effort level.
|
|
48
|
+
*/
|
|
34
49
|
function createCodexMiddleware(reasoningEffort) {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
...reasoningEffort ? { reasoningEffort } : {}
|
|
52
|
-
}
|
|
53
|
-
};
|
|
54
|
-
return params;
|
|
55
|
-
}
|
|
56
|
-
};
|
|
50
|
+
return {
|
|
51
|
+
specificationVersion: "v3",
|
|
52
|
+
transformParams: async ({ params }) => {
|
|
53
|
+
if (params.temperature !== void 0 && params.temperature !== null) delete params.topP;
|
|
54
|
+
params.providerOptions = {
|
|
55
|
+
...params.providerOptions,
|
|
56
|
+
openai: {
|
|
57
|
+
...params.providerOptions?.openai ?? {},
|
|
58
|
+
instructions: CODEX_INSTRUCTIONS,
|
|
59
|
+
store: false,
|
|
60
|
+
...reasoningEffort ? { reasoningEffort } : {}
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
return params;
|
|
64
|
+
}
|
|
65
|
+
};
|
|
57
66
|
}
|
|
67
|
+
/**
|
|
68
|
+
* Get a live OAuth bearer token for the Codex OAuth credential.
|
|
69
|
+
*
|
|
70
|
+
* Refreshes the token if it's expired, and returns the credential's
|
|
71
|
+
* accountId alongside the access token. Throws if the user isn't logged in
|
|
72
|
+
* or if the refresh fails.
|
|
73
|
+
*
|
|
74
|
+
* This is the only piece of Codex auth that is genuinely shared between
|
|
75
|
+
* the main agent's fetch (`buildOpenAICodexOAuthFetch`) and the Stagehand
|
|
76
|
+
* fetch (`buildCodexStagehandFetch`).
|
|
77
|
+
*/
|
|
58
78
|
async function getCodexBearer(authStorage) {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
return { accessToken, accountId: cred.accountId };
|
|
79
|
+
const storage = authStorage ?? getAuthStorage();
|
|
80
|
+
storage.reload();
|
|
81
|
+
const cred = storage.get("openai-codex");
|
|
82
|
+
if (!cred || cred.type !== "oauth") throw new Error("Not logged in to OpenAI Codex. Run /login first.");
|
|
83
|
+
let accessToken = cred.access;
|
|
84
|
+
if (Date.now() >= cred.expires) {
|
|
85
|
+
const refreshedToken = await storage.getApiKey("openai-codex");
|
|
86
|
+
if (!refreshedToken) throw new Error("Failed to refresh OpenAI Codex token. Please /login again.");
|
|
87
|
+
accessToken = refreshedToken;
|
|
88
|
+
storage.reload();
|
|
89
|
+
}
|
|
90
|
+
return {
|
|
91
|
+
accessToken,
|
|
92
|
+
accountId: cred.accountId
|
|
93
|
+
};
|
|
75
94
|
}
|
|
95
|
+
/**
|
|
96
|
+
* Build a fetch function that handles OpenAI Codex OAuth.
|
|
97
|
+
* Preserves non-authorization headers from init.
|
|
98
|
+
* When rewriteUrl is true (default), rewrites /v1/responses and /chat/completions
|
|
99
|
+
* to the Codex API endpoint. Set rewriteUrl: false for gateway usage where the
|
|
100
|
+
* SDK already targets the correct URL.
|
|
101
|
+
*/
|
|
76
102
|
function buildOpenAICodexOAuthFetch(opts = {}) {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
}
|
|
105
|
-
if (!headers.has("User-Agent")) {
|
|
106
|
-
headers.set("User-Agent", CODEX_USER_AGENT);
|
|
107
|
-
}
|
|
108
|
-
if (accountId) {
|
|
109
|
-
headers.set("ChatGPT-Account-ID", accountId);
|
|
110
|
-
}
|
|
111
|
-
const parsed = url instanceof URL ? url : new URL(typeof url === "string" ? url : url.url);
|
|
112
|
-
const shouldRewrite = opts.rewriteUrl !== false && (parsed.pathname.includes("/v1/responses") || parsed.pathname.includes("/chat/completions"));
|
|
113
|
-
const finalUrl = shouldRewrite ? new URL(CODEX_API_ENDPOINT) : parsed;
|
|
114
|
-
try {
|
|
115
|
-
return await fetch(finalUrl, { ...init, headers });
|
|
116
|
-
} catch (error) {
|
|
117
|
-
if (error && typeof error === "object") {
|
|
118
|
-
Object.assign(error, {
|
|
119
|
-
requestUrl: finalUrl.toString()
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
throw error;
|
|
123
|
-
}
|
|
124
|
-
});
|
|
103
|
+
return (async (url, init) => {
|
|
104
|
+
const { accessToken, accountId } = await getCodexBearer(opts.authStorage);
|
|
105
|
+
const headers = new Headers();
|
|
106
|
+
if (init?.headers) {
|
|
107
|
+
if (init.headers instanceof Headers) init.headers.forEach((value, key) => {
|
|
108
|
+
if (key.toLowerCase() !== "authorization") headers.set(key, value);
|
|
109
|
+
});
|
|
110
|
+
else if (Array.isArray(init.headers)) {
|
|
111
|
+
for (const [key, value] of init.headers) if (key.toLowerCase() !== "authorization" && value !== void 0) headers.set(key, String(value));
|
|
112
|
+
} else for (const [key, value] of Object.entries(init.headers)) if (key.toLowerCase() !== "authorization" && value !== void 0) headers.set(key, String(value));
|
|
113
|
+
}
|
|
114
|
+
headers.set("Authorization", `Bearer ${accessToken}`);
|
|
115
|
+
if (!headers.has("originator")) headers.set("originator", CODEX_ORIGINATOR);
|
|
116
|
+
if (!headers.has("User-Agent")) headers.set("User-Agent", CODEX_USER_AGENT);
|
|
117
|
+
if (accountId) headers.set("ChatGPT-Account-ID", accountId);
|
|
118
|
+
const parsed = url instanceof URL ? url : new URL(typeof url === "string" ? url : url.url);
|
|
119
|
+
const finalUrl = opts.rewriteUrl !== false && (parsed.pathname.includes("/v1/responses") || parsed.pathname.includes("/chat/completions")) ? new URL(CODEX_API_ENDPOINT) : parsed;
|
|
120
|
+
try {
|
|
121
|
+
return await fetch(finalUrl, {
|
|
122
|
+
...init,
|
|
123
|
+
headers
|
|
124
|
+
});
|
|
125
|
+
} catch (error) {
|
|
126
|
+
if (error && typeof error === "object") Object.assign(error, { requestUrl: finalUrl.toString() });
|
|
127
|
+
throw error;
|
|
128
|
+
}
|
|
129
|
+
});
|
|
125
130
|
}
|
|
131
|
+
/**
|
|
132
|
+
* Build a fetch function for Stagehand-on-Codex.
|
|
133
|
+
*
|
|
134
|
+
* The Codex backend has two requirements that AI SDK's non-streaming
|
|
135
|
+
* `generateText` path doesn't naturally satisfy:
|
|
136
|
+
*
|
|
137
|
+
* 1. `stream: true` must be set on every request body.
|
|
138
|
+
* 2. The response is delivered as Server-Sent Events; AI SDK's
|
|
139
|
+
* non-streaming code path expects a single JSON body.
|
|
140
|
+
*
|
|
141
|
+
* This fetch forces streaming on the outgoing request, collects the SSE
|
|
142
|
+
* events, and synthesizes the non-streaming JSON shape that
|
|
143
|
+
* `@ai-sdk/openai`'s Responses API parser expects.
|
|
144
|
+
*
|
|
145
|
+
* Headers, OAuth refresh, and URL targeting are handled by the caller via
|
|
146
|
+
* `baseURL` / `headers` on the AI SDK provider; this fetch only injects the
|
|
147
|
+
* live OAuth bearer per call.
|
|
148
|
+
*/
|
|
126
149
|
function buildCodexStagehandFetch(authStorage) {
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
+
return (async (url, init) => {
|
|
151
|
+
const { accessToken } = await getCodexBearer(authStorage);
|
|
152
|
+
const headers = new Headers(init?.headers);
|
|
153
|
+
headers.set("Authorization", `Bearer ${accessToken}`);
|
|
154
|
+
headers.set("Accept", "text/event-stream");
|
|
155
|
+
let body = init?.body;
|
|
156
|
+
if (typeof init?.body === "string") try {
|
|
157
|
+
const parsed = JSON.parse(init.body);
|
|
158
|
+
parsed.stream = true;
|
|
159
|
+
body = JSON.stringify(parsed);
|
|
160
|
+
if (!headers.has("content-type")) headers.set("content-type", "application/json");
|
|
161
|
+
} catch {}
|
|
162
|
+
const upstream = await fetch(url, {
|
|
163
|
+
...init,
|
|
164
|
+
headers,
|
|
165
|
+
body
|
|
166
|
+
});
|
|
167
|
+
if (!upstream.ok) return upstream;
|
|
168
|
+
const aggregated = await aggregateCodexStream(upstream);
|
|
169
|
+
return new Response(aggregated, {
|
|
170
|
+
status: 200,
|
|
171
|
+
headers: { "content-type": "application/json" }
|
|
172
|
+
});
|
|
173
|
+
});
|
|
150
174
|
}
|
|
175
|
+
/**
|
|
176
|
+
* Read an SSE Response and reduce it to a single JSON string matching the
|
|
177
|
+
* non-streaming OpenAI Responses-API shape.
|
|
178
|
+
*
|
|
179
|
+
* Event vocabulary we care about (per OpenAI Responses API streaming):
|
|
180
|
+
* - response.created → carries `response` object (id, model, usage stub)
|
|
181
|
+
* - response.output_item.added/done → output items (message, reasoning, etc.)
|
|
182
|
+
* - response.output_text.delta → text chunks
|
|
183
|
+
* - response.completed → final `response` snapshot incl. usage
|
|
184
|
+
* - response.error / error → bubble up as a thrown body
|
|
185
|
+
*
|
|
186
|
+
* Reasoning events (`response.reasoning_summary.*`) are intentionally ignored
|
|
187
|
+
* for the non-streaming text response.
|
|
188
|
+
*/
|
|
151
189
|
async function aggregateCodexStream(response) {
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
if (done) break;
|
|
230
|
-
processChunk(decoder.decode(value, { stream: true }));
|
|
231
|
-
}
|
|
232
|
-
processChunk(decoder.decode());
|
|
233
|
-
} finally {
|
|
234
|
-
reader.releaseLock();
|
|
235
|
-
}
|
|
236
|
-
const base = finalResponse ?? createdResponse ?? { output: [] };
|
|
237
|
-
const finalItems = Array.from(items.entries()).sort(([a], [b]) => a - b).map(([index, item]) => {
|
|
238
|
-
if (item?.type === "message" && Array.isArray(item.content)) {
|
|
239
|
-
item.content = item.content.map((c, ci) => {
|
|
240
|
-
const key = `${index}:${ci}`;
|
|
241
|
-
if (textBuffers.has(key)) {
|
|
242
|
-
return { ...c, text: textBuffers.get(key) };
|
|
243
|
-
}
|
|
244
|
-
return c;
|
|
245
|
-
});
|
|
246
|
-
}
|
|
247
|
-
return item;
|
|
248
|
-
});
|
|
249
|
-
base.output = finalItems.length > 0 ? finalItems : base.output ?? [];
|
|
250
|
-
return JSON.stringify(base);
|
|
190
|
+
if (!response.body) throw new Error("Codex streaming response had no body");
|
|
191
|
+
const reader = response.body.getReader();
|
|
192
|
+
const decoder = new TextDecoder("utf-8");
|
|
193
|
+
let buffer = "";
|
|
194
|
+
let finalResponse = null;
|
|
195
|
+
let createdResponse = null;
|
|
196
|
+
const items = /* @__PURE__ */ new Map();
|
|
197
|
+
const textBuffers = /* @__PURE__ */ new Map();
|
|
198
|
+
const handleEvent = (event) => {
|
|
199
|
+
if (!event.data || event.data === "[DONE]") return;
|
|
200
|
+
let payload;
|
|
201
|
+
try {
|
|
202
|
+
payload = JSON.parse(event.data);
|
|
203
|
+
} catch {
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
switch (payload.type ?? event.event ?? "") {
|
|
207
|
+
case "response.created":
|
|
208
|
+
createdResponse = payload.response ?? createdResponse;
|
|
209
|
+
break;
|
|
210
|
+
case "response.output_item.added":
|
|
211
|
+
if (typeof payload.output_index === "number" && payload.item) items.set(payload.output_index, payload.item);
|
|
212
|
+
break;
|
|
213
|
+
case "response.output_item.done":
|
|
214
|
+
if (typeof payload.output_index === "number" && payload.item) items.set(payload.output_index, payload.item);
|
|
215
|
+
break;
|
|
216
|
+
case "response.output_text.delta": {
|
|
217
|
+
const key = `${payload.output_index}:${payload.content_index ?? 0}`;
|
|
218
|
+
textBuffers.set(key, (textBuffers.get(key) ?? "") + (payload.delta ?? ""));
|
|
219
|
+
break;
|
|
220
|
+
}
|
|
221
|
+
case "response.completed":
|
|
222
|
+
finalResponse = payload.response ?? finalResponse;
|
|
223
|
+
break;
|
|
224
|
+
case "response.error":
|
|
225
|
+
case "error": throw new Error(`Codex stream error: ${JSON.stringify(payload.error ?? payload)}`);
|
|
226
|
+
default: break;
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
const processChunk = (chunk) => {
|
|
230
|
+
buffer += chunk.replace(/\r\n/g, "\n");
|
|
231
|
+
let sepIdx;
|
|
232
|
+
while ((sepIdx = buffer.indexOf("\n\n")) !== -1) {
|
|
233
|
+
const raw = buffer.slice(0, sepIdx);
|
|
234
|
+
buffer = buffer.slice(sepIdx + 2);
|
|
235
|
+
const event = {};
|
|
236
|
+
const dataLines = [];
|
|
237
|
+
for (const line of raw.split("\n")) if (line.startsWith("event:")) event.event = line.slice(6).trim();
|
|
238
|
+
else if (line.startsWith("data:")) dataLines.push(line.slice(5).trimStart());
|
|
239
|
+
if (dataLines.length > 0) event.data = dataLines.join("\n");
|
|
240
|
+
handleEvent(event);
|
|
241
|
+
}
|
|
242
|
+
};
|
|
243
|
+
try {
|
|
244
|
+
while (true) {
|
|
245
|
+
const { value, done } = await reader.read();
|
|
246
|
+
if (done) break;
|
|
247
|
+
processChunk(decoder.decode(value, { stream: true }));
|
|
248
|
+
}
|
|
249
|
+
processChunk(decoder.decode());
|
|
250
|
+
} finally {
|
|
251
|
+
reader.releaseLock();
|
|
252
|
+
}
|
|
253
|
+
const base = finalResponse ?? createdResponse ?? { output: [] };
|
|
254
|
+
const finalItems = Array.from(items.entries()).sort(([a], [b]) => a - b).map(([index, item]) => {
|
|
255
|
+
if (item?.type === "message" && Array.isArray(item.content)) item.content = item.content.map((c, ci) => {
|
|
256
|
+
const key = `${index}:${ci}`;
|
|
257
|
+
if (textBuffers.has(key)) return {
|
|
258
|
+
...c,
|
|
259
|
+
text: textBuffers.get(key)
|
|
260
|
+
};
|
|
261
|
+
return c;
|
|
262
|
+
});
|
|
263
|
+
return item;
|
|
264
|
+
});
|
|
265
|
+
base.output = finalItems.length > 0 ? finalItems : base.output ?? [];
|
|
266
|
+
return JSON.stringify(base);
|
|
251
267
|
}
|
|
268
|
+
/**
|
|
269
|
+
* Creates an OpenAI model using ChatGPT OAuth authentication
|
|
270
|
+
* Uses OAuth tokens from AuthStorage (auto-refreshes when needed)
|
|
271
|
+
*
|
|
272
|
+
* IMPORTANT: This uses the Codex API endpoint, not the standard OpenAI API.
|
|
273
|
+
* URLs are rewritten from /v1/responses or /chat/completions to the Codex endpoint.
|
|
274
|
+
*/
|
|
252
275
|
function openaiCodexProvider(modelId = "codex-mini-latest", options) {
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
});
|
|
276
|
-
return wrapLanguageModel({
|
|
277
|
-
model: openai.responses(modelId),
|
|
278
|
-
middleware: [middleware]
|
|
279
|
-
});
|
|
276
|
+
const effectiveLevel = getEffectiveThinkingLevel(modelId, options?.thinkingLevel ?? "medium");
|
|
277
|
+
const reasoningEffort = THINKING_LEVEL_TO_REASONING_EFFORT[effectiveLevel];
|
|
278
|
+
const middleware = createCodexMiddleware(reasoningEffort);
|
|
279
|
+
const headers = options?.headers;
|
|
280
|
+
const baseURL = process.env.OPENAI_BASE_URL;
|
|
281
|
+
if (process.env.NODE_ENV === "test" || process.env.VITEST) return wrapLanguageModel({
|
|
282
|
+
model: createOpenAI({
|
|
283
|
+
apiKey: "test-api-key",
|
|
284
|
+
baseURL,
|
|
285
|
+
headers
|
|
286
|
+
}).responses(modelId),
|
|
287
|
+
middleware: [middleware]
|
|
288
|
+
});
|
|
289
|
+
return wrapLanguageModel({
|
|
290
|
+
model: createOpenAI({
|
|
291
|
+
apiKey: "oauth-dummy-key",
|
|
292
|
+
baseURL,
|
|
293
|
+
headers,
|
|
294
|
+
fetch: buildOpenAICodexOAuthFetch({ authStorage: options?.authStorage })
|
|
295
|
+
}).responses(modelId),
|
|
296
|
+
middleware: [middleware]
|
|
297
|
+
});
|
|
280
298
|
}
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
buildOpenAICodexOAuthFetch,
|
|
285
|
-
createCodexMiddleware,
|
|
286
|
-
getAuthStorage,
|
|
287
|
-
getEffectiveThinkingLevel,
|
|
288
|
-
openaiCodexProvider,
|
|
289
|
-
setAuthStorage
|
|
290
|
-
};
|
|
299
|
+
//#endregion
|
|
300
|
+
export { THINKING_LEVEL_TO_REASONING_EFFORT, buildCodexStagehandFetch, buildOpenAICodexOAuthFetch, createCodexMiddleware, getAuthStorage, getEffectiveThinkingLevel, openaiCodexProvider, setAuthStorage };
|
|
301
|
+
|
|
291
302
|
//# sourceMappingURL=openai-codex.js.map
|