@agent-native/core 0.198.8 → 0.199.0-nightly-20261001034223

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.
Files changed (48) hide show
  1. package/dist/agent/actions/disconnect-chatgpt-subscription.d.ts +10 -1
  2. package/dist/agent/actions/disconnect-chatgpt-subscription.js +23 -5
  3. package/dist/agent/actions/get-chatgpt-subscription-status.d.ts +1 -6
  4. package/dist/agent/actions/get-chatgpt-subscription-status.js +1 -1
  5. package/dist/agent/actions/list-chatgpt-subscription-accounts.d.ts +5 -0
  6. package/dist/agent/actions/list-chatgpt-subscription-accounts.js +14 -0
  7. package/dist/agent/actions/select-chatgpt-subscription-account.d.ts +7 -0
  8. package/dist/agent/actions/select-chatgpt-subscription-account.js +22 -0
  9. package/dist/agent/chatgpt-subscription-contract.d.ts +14 -4
  10. package/dist/agent/chatgpt-subscription-contract.js +20 -8
  11. package/dist/agent/engine/builtin.js +5 -5
  12. package/dist/agent/engine/chatgpt-subscription-engine.d.ts +6 -0
  13. package/dist/agent/engine/chatgpt-subscription-engine.js +149 -49
  14. package/dist/agent/engine/registry.js +2 -6
  15. package/dist/automation/index.d.ts +1 -1
  16. package/dist/client/chat-model-groups.d.ts +3 -0
  17. package/dist/client/chat-model-groups.js +12 -1
  18. package/dist/collab/awareness.d.ts +2 -2
  19. package/dist/collab/routes.d.ts +2 -2
  20. package/dist/collab/struct-routes.d.ts +1 -1
  21. package/dist/file-upload/actions/upload-image.d.ts +2 -2
  22. package/dist/framework-tools.js +2 -0
  23. package/dist/labs/core-labs.js +1 -2
  24. package/dist/localization/default-messages.d.ts +26 -0
  25. package/dist/localization/default-messages.js +26 -0
  26. package/dist/oauth-tokens/lifecycle.d.ts +1 -0
  27. package/dist/oauth-tokens/lifecycle.js +5 -1
  28. package/dist/observability/routes.d.ts +7 -7
  29. package/dist/org/handlers.d.ts +1 -1
  30. package/dist/org/index.d.ts +1 -1
  31. package/dist/provider-api/actions/custom-provider-registration.d.ts +16 -16
  32. package/dist/provider-api/actions/provider-api.d.ts +11 -11
  33. package/dist/scripts/agent-engines/list-agent-engines.js +48 -10
  34. package/dist/scripts/agent-engines/manage-agent-engine.js +16 -0
  35. package/dist/scripts/agent-engines/set-agent-engine.d.ts +3 -0
  36. package/dist/scripts/agent-engines/set-agent-engine.js +51 -9
  37. package/dist/secrets/routes.d.ts +10 -10
  38. package/dist/server/action-discovery.js +8 -0
  39. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  40. package/dist/server/agent-engine-default-model-route.d.ts +2 -2
  41. package/dist/server/agent-engine-ollama-models-route.d.ts +1 -1
  42. package/dist/server/chatgpt-subscription-oauth.d.ts +85 -5
  43. package/dist/server/chatgpt-subscription-oauth.js +1098 -212
  44. package/dist/server/core-routes-plugin.d.ts +1 -1
  45. package/dist/server/core-routes-plugin.js +2 -4
  46. package/dist/vite/action-types-plugin.js +8 -0
  47. package/docs/content/toolkit-settings.mdx +30 -22
  48. package/package.json +6 -4
@@ -1,4 +1,13 @@
1
- declare const _default: import("../../action.js").ActionDefinition<Record<string, never>, {
1
+ declare const _default: import("../../action.js").ActionDefinition<{
2
+ accountId?: string;
3
+ removeLegacyCredential?: boolean;
4
+ }, {
5
+ removed: boolean;
6
+ remoteRevocationConfirmed: false;
7
+ } | {
8
+ disconnectedAccountId: string | null;
9
+ activeAccountId: string | null;
2
10
  connected: boolean;
11
+ remoteRevocationConfirmed: boolean;
3
12
  }>;
4
13
  export default _default;
@@ -1,14 +1,32 @@
1
1
  import { z } from "zod";
2
2
  import { defineAction, fail } from "../../action.js";
3
- import { disconnectChatGPTSubscription } from "../../server/chatgpt-subscription-oauth.js";
3
+ import { disconnectChatGPTSubscription, removeLegacyChatGPTSubscriptionCredential, } from "../../server/chatgpt-subscription-oauth.js";
4
4
  export default defineAction({
5
- description: "Disconnect the current user's ChatGPT subscription from the experimental Codex engine.",
6
- schema: z.object({}),
5
+ description: "Sign out of one of the current user's saved ChatGPT registrations, or remove an unusable credential from the older experimental ChatGPT flow. Remote revocation is attempted for current registrations; it cannot be confirmed for the older credential.",
6
+ schema: z.object({
7
+ accountId: z
8
+ .string()
9
+ .optional()
10
+ .describe("Saved ChatGPT registration ID. Omit to disconnect the active registration."),
11
+ removeLegacyCredential: z
12
+ .boolean()
13
+ .optional()
14
+ .describe("Remove the user's unusable credential from the older experimental ChatGPT flow."),
15
+ }),
7
16
  run: async (_args, ctx) => {
8
17
  const email = ctx?.userEmail;
9
18
  if (!email)
10
19
  fail("Not authenticated.", { statusCode: 401 });
11
- await disconnectChatGPTSubscription(email);
12
- return { connected: false };
20
+ try {
21
+ if (_args.removeLegacyCredential) {
22
+ return await removeLegacyChatGPTSubscriptionCredential(email);
23
+ }
24
+ return await disconnectChatGPTSubscription(email, _args.accountId);
25
+ }
26
+ catch (error) {
27
+ fail(error instanceof Error
28
+ ? error.message
29
+ : "Unable to disconnect ChatGPT.", { statusCode: 400 });
30
+ }
13
31
  },
14
32
  });
@@ -1,7 +1,2 @@
1
- declare const _default: import("../../action.js").ActionDefinition<Record<string, never>, {
2
- labEnabled: boolean;
3
- connected: boolean;
4
- reconnectRequired: boolean;
5
- accountId: string | null;
6
- }>;
1
+ declare const _default: import("../../action.js").ActionDefinition<Record<string, never>, import("../../server/chatgpt-subscription-oauth.js").ChatGPTSubscriptionStatus>;
7
2
  export default _default;
@@ -2,7 +2,7 @@ import { z } from "zod";
2
2
  import { defineAction, fail } from "../../action.js";
3
3
  import { getChatGPTSubscriptionStatus } from "../../server/chatgpt-subscription-oauth.js";
4
4
  export default defineAction({
5
- description: "Return the current user's experimental ChatGPT subscription connection status.",
5
+ description: "Return the current user's ChatGPT subscription support, selected registration, and saved account registrations.",
6
6
  schema: z.object({}),
7
7
  http: { method: "GET" },
8
8
  run: async (_args, ctx) => {
@@ -0,0 +1,5 @@
1
+ declare const _default: import("../../action.js").ActionDefinition<Record<string, never>, {
2
+ accounts: import("../../server/chatgpt-subscription-oauth.js").ChatGPTSubscriptionAccountSummary[];
3
+ activeAccountId: string | null;
4
+ }>;
5
+ export default _default;
@@ -0,0 +1,14 @@
1
+ import { z } from "zod";
2
+ import { defineAction, fail } from "../../action.js";
3
+ import { listChatGPTSubscriptionAccounts } from "../../server/chatgpt-subscription-oauth.js";
4
+ export default defineAction({
5
+ description: "List the current user's saved ChatGPT registrations without exposing credentials.",
6
+ schema: z.object({}),
7
+ http: { method: "GET" },
8
+ run: async (_args, ctx) => {
9
+ const email = ctx?.userEmail;
10
+ if (!email)
11
+ fail("Not authenticated.", { statusCode: 401 });
12
+ return listChatGPTSubscriptionAccounts(email);
13
+ },
14
+ });
@@ -0,0 +1,7 @@
1
+ declare const _default: import("../../action.js").ActionDefinition<{
2
+ accountId: string;
3
+ }, {
4
+ activeAccountId: string;
5
+ connected: boolean;
6
+ }>;
7
+ export default _default;
@@ -0,0 +1,22 @@
1
+ import { z } from "zod";
2
+ import { defineAction, fail } from "../../action.js";
3
+ import { selectChatGPTSubscriptionAccount } from "../../server/chatgpt-subscription-oauth.js";
4
+ export default defineAction({
5
+ description: "Set one of the current user's saved ChatGPT registrations as active.",
6
+ schema: z.object({
7
+ accountId: z.string().min(1).max(80),
8
+ }),
9
+ run: async (args, ctx) => {
10
+ const email = ctx?.userEmail;
11
+ if (!email)
12
+ fail("Not authenticated.", { statusCode: 401 });
13
+ try {
14
+ return await selectChatGPTSubscriptionAccount(email, args.accountId);
15
+ }
16
+ catch (error) {
17
+ fail(error instanceof Error
18
+ ? error.message
19
+ : "Unable to select ChatGPT account.", { statusCode: 400 });
20
+ }
21
+ },
22
+ });
@@ -1,5 +1,15 @@
1
- export declare const CHATGPT_SUBSCRIPTION_LAB_KEY = "agent.chatgpt-subscription";
2
1
  export declare const CHATGPT_SUBSCRIPTION_ENGINE_NAME = "chatgpt-subscription";
3
- export declare const CHATGPT_SUBSCRIPTION_ENDPOINT = "https://chatgpt.com/backend-api/codex/responses";
4
- export declare const CHATGPT_SUBSCRIPTION_MODELS: readonly ["gpt-5.5", "gpt-5.4", "gpt-5.4-mini", "gpt-5.3-codex-spark"];
5
- export declare const CHATGPT_SUBSCRIPTION_DEFAULT_MODEL: "gpt-5.5";
2
+ export declare const CHATGPT_SUBSCRIPTION_RESOURCE = "https://api.openai.com/v1";
3
+ export declare const CHATGPT_SUBSCRIPTION_ENDPOINT = "https://api.openai.com/v1/responses";
4
+ export declare const CHATGPT_SUBSCRIPTION_AUTHORIZATION_ENDPOINT = "https://auth.openai.com/api/accounts/authorize";
5
+ export declare const CHATGPT_SUBSCRIPTION_TOKEN_ENDPOINT = "https://auth.openai.com/api/accounts/oauth/token";
6
+ export declare const CHATGPT_SUBSCRIPTION_ISSUER = "https://auth.openai.com";
7
+ export declare const CHATGPT_SUBSCRIPTION_JWKS_URI = "https://auth.openai.com/.well-known/jwks.json";
8
+ export declare const CHATGPT_SUBSCRIPTION_OIDC_CONFIGURATION_URI = "https://auth.openai.com/.well-known/openid-configuration";
9
+ export declare const CHATGPT_SUBSCRIPTION_DYNAMIC_CLIENT_ID = "dynamic_agent_client";
10
+ export declare const CHATGPT_SUBSCRIPTION_CALLBACK_PATH = "/auth/callback";
11
+ export declare const CHATGPT_SUBSCRIPTION_HOST_ID_SETTING_KEY = "agent.chatgpt-subscription.host-id";
12
+ export declare const CHATGPT_SUBSCRIPTION_ACTIVE_ACCOUNT_SETTING_KEY = "agent.chatgpt-subscription.active-account";
13
+ export declare const CHATGPT_SUBSCRIPTION_REGISTRATIONS_SETTING_KEY = "agent.chatgpt-subscription.registrations";
14
+ export declare const CHATGPT_SUBSCRIPTION_PROVIDER = "openai-codex";
15
+ export declare const CHATGPT_SUBSCRIPTION_SCOPES: readonly ["openid", "profile", "email", "offline_access", "resource.invoke", "chatgpt.tokens.use.direct"];
@@ -1,10 +1,22 @@
1
- export const CHATGPT_SUBSCRIPTION_LAB_KEY = "agent.chatgpt-subscription";
2
1
  export const CHATGPT_SUBSCRIPTION_ENGINE_NAME = "chatgpt-subscription";
3
- export const CHATGPT_SUBSCRIPTION_ENDPOINT = "https://chatgpt.com/backend-api/codex/responses";
4
- export const CHATGPT_SUBSCRIPTION_MODELS = [
5
- "gpt-5.5",
6
- "gpt-5.4",
7
- "gpt-5.4-mini",
8
- "gpt-5.3-codex-spark",
2
+ export const CHATGPT_SUBSCRIPTION_RESOURCE = "https://api.openai.com/v1";
3
+ export const CHATGPT_SUBSCRIPTION_ENDPOINT = `${CHATGPT_SUBSCRIPTION_RESOURCE}/responses`;
4
+ export const CHATGPT_SUBSCRIPTION_AUTHORIZATION_ENDPOINT = "https://auth.openai.com/api/accounts/authorize";
5
+ export const CHATGPT_SUBSCRIPTION_TOKEN_ENDPOINT = "https://auth.openai.com/api/accounts/oauth/token";
6
+ export const CHATGPT_SUBSCRIPTION_ISSUER = "https://auth.openai.com";
7
+ export const CHATGPT_SUBSCRIPTION_JWKS_URI = "https://auth.openai.com/.well-known/jwks.json";
8
+ export const CHATGPT_SUBSCRIPTION_OIDC_CONFIGURATION_URI = "https://auth.openai.com/.well-known/openid-configuration";
9
+ export const CHATGPT_SUBSCRIPTION_DYNAMIC_CLIENT_ID = "dynamic_agent_client";
10
+ export const CHATGPT_SUBSCRIPTION_CALLBACK_PATH = "/auth/callback";
11
+ export const CHATGPT_SUBSCRIPTION_HOST_ID_SETTING_KEY = "agent.chatgpt-subscription.host-id";
12
+ export const CHATGPT_SUBSCRIPTION_ACTIVE_ACCOUNT_SETTING_KEY = "agent.chatgpt-subscription.active-account";
13
+ export const CHATGPT_SUBSCRIPTION_REGISTRATIONS_SETTING_KEY = "agent.chatgpt-subscription.registrations";
14
+ export const CHATGPT_SUBSCRIPTION_PROVIDER = "openai-codex";
15
+ export const CHATGPT_SUBSCRIPTION_SCOPES = [
16
+ "openid",
17
+ "profile",
18
+ "email",
19
+ "offline_access",
20
+ "resource.invoke",
21
+ "chatgpt.tokens.use.direct",
9
22
  ];
10
- export const CHATGPT_SUBSCRIPTION_DEFAULT_MODEL = CHATGPT_SUBSCRIPTION_MODELS[0];
@@ -1,5 +1,5 @@
1
1
  import { AppConfigurationError, getAppConfig } from "../../app-config/index.js";
2
- import { CHATGPT_SUBSCRIPTION_DEFAULT_MODEL, CHATGPT_SUBSCRIPTION_ENGINE_NAME, CHATGPT_SUBSCRIPTION_MODELS, } from "../chatgpt-subscription-contract.js";
2
+ import { CHATGPT_SUBSCRIPTION_ENGINE_NAME } from "../chatgpt-subscription-contract.js";
3
3
  import { createAISDKEngine, PROVIDER_CAPABILITIES, PROVIDER_DEFAULT_MODELS, PROVIDER_SUPPORTED_MODELS, PROVIDER_ENV_VARS, PROVIDER_PACKAGES, } from "./ai-sdk-engine.js";
4
4
  import { createAnthropicEngine, ANTHROPIC_CAPABILITIES, ANTHROPIC_DEFAULT_MODEL, ANTHROPIC_SUPPORTED_MODELS, } from "./anthropic-engine.js";
5
5
  import { createBuilderEngine, BUILDER_CAPABILITIES, BUILDER_DEFAULT_MODEL, BUILDER_SUPPORTED_MODELS, } from "./builder-engine.js";
@@ -78,11 +78,11 @@ function builtinEngineEntries() {
78
78
  })),
79
79
  {
80
80
  name: CHATGPT_SUBSCRIPTION_ENGINE_NAME,
81
- label: "ChatGPT subscription",
82
- description: "Experimental Codex access through a user's ChatGPT subscription. Enable the matching lab first.",
81
+ label: "ChatGPT plan access",
82
+ description: "Use eligible OpenAI models through a user's ChatGPT plan.",
83
83
  capabilities: PROVIDER_CAPABILITIES.openai,
84
- defaultModel: CHATGPT_SUBSCRIPTION_DEFAULT_MODEL,
85
- supportedModels: CHATGPT_SUBSCRIPTION_MODELS,
84
+ defaultModel: "",
85
+ supportedModels: [],
86
86
  acceptsCustomModels: false,
87
87
  requiredEnvVars: [],
88
88
  create: (config) => createChatGPTSubscriptionEngine(config),
@@ -1,3 +1,9 @@
1
1
  import type { AgentEngine } from "./types.js";
2
+ export declare function normalizeChatGPTSubscriptionResponsesBody(body: unknown): string;
3
+ export interface ChatGPTSubscriptionModelCatalog {
4
+ models: string[];
5
+ modelDisplayNames: Record<string, string>;
6
+ }
7
+ export declare function listChatGPTSubscriptionModels(email: string): Promise<ChatGPTSubscriptionModelCatalog>;
2
8
  export declare function createChatGPTSubscriptionFetch(email: string): typeof fetch;
3
9
  export declare function createChatGPTSubscriptionEngine(config?: Record<string, unknown>): AgentEngine;
@@ -1,37 +1,68 @@
1
1
  import { getChatGPTSubscriptionAccess, markChatGPTSubscriptionReconnectRequired, } from "../../server/chatgpt-subscription-oauth.js";
2
2
  import { getRequestUserEmail } from "../../server/request-context.js";
3
- import { CHATGPT_SUBSCRIPTION_DEFAULT_MODEL, CHATGPT_SUBSCRIPTION_ENDPOINT, CHATGPT_SUBSCRIPTION_ENGINE_NAME, CHATGPT_SUBSCRIPTION_MODELS, } from "../chatgpt-subscription-contract.js";
3
+ import { CHATGPT_SUBSCRIPTION_ENDPOINT, CHATGPT_SUBSCRIPTION_ENGINE_NAME, } from "../chatgpt-subscription-contract.js";
4
4
  import { createAISDKEngine, PROVIDER_CAPABILITIES } from "./ai-sdk-engine.js";
5
5
  const OPENAI_RESPONSES_BASE_URL = "https://api.openai.com/v1";
6
+ const UNSUPPORTED_RESPONSES_FIELDS = [
7
+ "background",
8
+ "conversation",
9
+ "max_output_tokens",
10
+ "max_tool_calls",
11
+ "metadata",
12
+ "moderation",
13
+ "multi_agent",
14
+ "previous_response_id",
15
+ "prompt",
16
+ "prompt_cache_retention",
17
+ "safety_identifier",
18
+ "temperature",
19
+ "top_logprobs",
20
+ "top_p",
21
+ "truncation",
22
+ "user",
23
+ ];
6
24
  function requestUrl(input) {
7
25
  return input instanceof URL
8
26
  ? input
9
27
  : new URL(typeof input === "string" ? input : input.url);
10
28
  }
11
- function copyHeaders(input, init) {
29
+ function requestHeaders(input, init) {
12
30
  const headers = new Headers(input instanceof Request ? input.headers : undefined);
13
31
  if (init?.headers) {
14
32
  new Headers(init.headers).forEach((value, key) => headers.set(key, value));
15
33
  }
16
34
  headers.delete("authorization");
17
- headers.delete("Authorization");
35
+ headers.delete("originator");
36
+ headers.delete("chatgpt-account-id");
18
37
  return headers;
19
38
  }
20
- function stripUnsupportedRequestFields(body) {
21
- if (typeof body !== "string")
22
- return body;
39
+ function isRecord(value) {
40
+ return !!value && typeof value === "object" && !Array.isArray(value);
41
+ }
42
+ export function normalizeChatGPTSubscriptionResponsesBody(body) {
43
+ if (typeof body !== "string") {
44
+ throw new Error("Sign in with ChatGPT requires a JSON Responses request.");
45
+ }
46
+ let value;
23
47
  try {
24
- const parsed = JSON.parse(body);
25
- if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
26
- return body;
27
- }
28
- const request = { ...parsed };
29
- delete request.max_output_tokens;
30
- return JSON.stringify(request);
48
+ value = JSON.parse(body);
31
49
  }
32
50
  catch {
33
- return body;
51
+ throw new Error("Sign in with ChatGPT received invalid Responses JSON.");
52
+ }
53
+ if (!isRecord(value) || !Array.isArray(value.input)) {
54
+ throw new Error("Sign in with ChatGPT requires Responses input as an array.");
34
55
  }
56
+ const request = { ...value };
57
+ for (const field of UNSUPPORTED_RESPONSES_FIELDS)
58
+ delete request[field];
59
+ const input = request.input;
60
+ request.input = input.map((item) => isRecord(item) && item.role === "system"
61
+ ? { ...item, role: "developer" }
62
+ : item);
63
+ request.store = false;
64
+ request.stream = true;
65
+ return JSON.stringify(request);
35
66
  }
36
67
  function currentUserEmail(config) {
37
68
  const configured = typeof config.userEmail === "string" ? config.userEmail.trim() : "";
@@ -39,56 +70,125 @@ function currentUserEmail(config) {
39
70
  return configured;
40
71
  return getRequestUserEmail()?.trim() ?? "";
41
72
  }
73
+ async function markUnauthorized(email, response) {
74
+ if (response.status === 401) {
75
+ await markChatGPTSubscriptionReconnectRequired(email);
76
+ }
77
+ }
78
+ async function readChatGPTSubscriptionModelCatalog(accessToken, email) {
79
+ const response = await fetch(`${OPENAI_RESPONSES_BASE_URL}/models`, {
80
+ method: "GET",
81
+ headers: { authorization: `Bearer ${accessToken}` },
82
+ cache: "no-store",
83
+ redirect: "error",
84
+ });
85
+ await markUnauthorized(email, response);
86
+ if (!response.ok) {
87
+ throw new Error(`OpenAI ChatGPT model listing failed with HTTP ${response.status}.`);
88
+ }
89
+ let payload;
90
+ try {
91
+ payload = await response.json();
92
+ }
93
+ catch {
94
+ throw new Error("OpenAI returned invalid ChatGPT model-list JSON.");
95
+ }
96
+ if (!isRecord(payload) || !Array.isArray(payload.models)) {
97
+ throw new Error("OpenAI returned an invalid ChatGPT model catalog.");
98
+ }
99
+ const models = [];
100
+ const modelDisplayNameEntries = [];
101
+ const seen = new Set();
102
+ for (const item of payload.models) {
103
+ if (!isRecord(item)) {
104
+ throw new Error("OpenAI returned an invalid ChatGPT model-list row.");
105
+ }
106
+ if (item.visibility !== "list")
107
+ continue;
108
+ const { slug, display_name: displayName } = item;
109
+ if (typeof slug !== "string" ||
110
+ !slug.trim() ||
111
+ slug.length > 200 ||
112
+ /[\s\p{Cc}]/u.test(slug) ||
113
+ typeof displayName !== "string" ||
114
+ !displayName.trim() ||
115
+ displayName.length > 200 ||
116
+ /[\p{Cc}]/u.test(displayName)) {
117
+ throw new Error("OpenAI returned an invalid visible ChatGPT model.");
118
+ }
119
+ if (seen.has(slug)) {
120
+ throw new Error("OpenAI returned a duplicate visible ChatGPT model.");
121
+ }
122
+ seen.add(slug);
123
+ models.push(slug);
124
+ modelDisplayNameEntries.push([slug, displayName]);
125
+ }
126
+ if (models.length === 0) {
127
+ throw new Error("The selected ChatGPT account has no visible models.");
128
+ }
129
+ return {
130
+ models,
131
+ modelDisplayNames: Object.fromEntries(modelDisplayNameEntries),
132
+ };
133
+ }
134
+ export async function listChatGPTSubscriptionModels(email) {
135
+ const access = await getChatGPTSubscriptionAccess(email);
136
+ return readChatGPTSubscriptionModelCatalog(access.accessToken, email);
137
+ }
42
138
  export function createChatGPTSubscriptionFetch(email) {
43
139
  return async (input, init) => {
140
+ const target = requestUrl(input);
141
+ const endpoint = new URL(CHATGPT_SUBSCRIPTION_ENDPOINT);
142
+ if (target.origin !== endpoint.origin ||
143
+ target.pathname !== endpoint.pathname ||
144
+ target.search ||
145
+ target.hash) {
146
+ throw new Error("Sign in with ChatGPT requests must use the public OpenAI Responses API.");
147
+ }
148
+ const source = input instanceof Request ? input : undefined;
149
+ const method = init?.method ?? source?.method ?? "GET";
150
+ if (method.toUpperCase() !== "POST") {
151
+ throw new Error("The OpenAI Responses API requires POST requests.");
152
+ }
153
+ const body = source && init?.body === undefined
154
+ ? await source.clone().text()
155
+ : init?.body;
44
156
  const access = await getChatGPTSubscriptionAccess(email);
45
- const parsed = requestUrl(input);
46
- const rewrite = parsed.pathname.includes("/v1/responses") ||
47
- parsed.pathname.includes("/chat/completions");
48
- const url = rewrite ? new URL(CHATGPT_SUBSCRIPTION_ENDPOINT) : parsed;
49
- const headers = copyHeaders(input, init);
157
+ const headers = requestHeaders(input, init);
50
158
  headers.set("authorization", `Bearer ${access.accessToken}`);
51
- headers.set("originator", "agent-native");
52
- headers.set("user-agent", "agent-native-framework");
53
- if (access.accountId)
54
- headers.set("ChatGPT-Account-Id", access.accountId);
55
- const source = input instanceof Request ? input : undefined;
56
- const requestInit = {
57
- ...(source
58
- ? {
59
- method: source.method,
60
- body: source.method === "GET" || source.method === "HEAD"
61
- ? undefined
62
- : source.body,
63
- signal: source.signal,
64
- }
65
- : {}),
159
+ headers.set("content-type", "application/json");
160
+ const requestBody = JSON.parse(normalizeChatGPTSubscriptionResponsesBody(body));
161
+ if (typeof requestBody.model !== "string" || !requestBody.model.trim()) {
162
+ const catalog = await readChatGPTSubscriptionModelCatalog(access.accessToken, email);
163
+ const model = catalog.models[0];
164
+ if (!model) {
165
+ throw new Error("The selected ChatGPT account has no visible models.");
166
+ }
167
+ requestBody.model = model;
168
+ }
169
+ const response = await fetch(endpoint, {
66
170
  ...(init ?? {}),
171
+ method: "POST",
67
172
  headers,
68
- };
69
- if (rewrite) {
70
- requestInit.body =
71
- source && init?.body === undefined
72
- ? stripUnsupportedRequestFields(await source.clone().text())
73
- : stripUnsupportedRequestFields(requestInit.body);
74
- }
75
- const response = await fetch(url, requestInit);
76
- if (response.status === 401) {
77
- await markChatGPTSubscriptionReconnectRequired(email).catch(() => { });
78
- }
173
+ body: JSON.stringify(requestBody),
174
+ cache: "no-store",
175
+ redirect: "error",
176
+ ...(source?.signal ? { signal: source.signal } : {}),
177
+ });
178
+ await markUnauthorized(email, response);
79
179
  return response;
80
180
  };
81
181
  }
82
182
  export function createChatGPTSubscriptionEngine(config = {}) {
83
183
  const email = currentUserEmail(config);
84
184
  if (!email) {
85
- throw new Error("A signed-in user is required for a ChatGPT subscription.");
185
+ throw new Error("A signed-in user is required for ChatGPT plan access.");
86
186
  }
87
187
  return createAISDKEngine("openai", {
88
188
  name: CHATGPT_SUBSCRIPTION_ENGINE_NAME,
89
- label: "ChatGPT subscription",
90
- model: CHATGPT_SUBSCRIPTION_DEFAULT_MODEL,
91
- supportedModels: CHATGPT_SUBSCRIPTION_MODELS,
189
+ label: "ChatGPT plan access",
190
+ model: typeof config.model === "string" ? config.model : "",
191
+ supportedModels: [],
92
192
  acceptsCustomModels: false,
93
193
  capabilities: PROVIDER_CAPABILITIES.openai,
94
194
  apiKey: "chatgpt-subscription",
@@ -2,14 +2,13 @@ import { createRequire } from "node:module";
2
2
  import { getAppConfig } from "../../app-config/index.js";
3
3
  import { assertCredentialCanReachEndpoint, } from "../../credentials/index.js";
4
4
  import { isBlockedExtensionUrlWithDns } from "../../extensions/url-safety.js";
5
- import { getUserLabs } from "../../labs/store.js";
6
5
  import { BUILDER_OAUTH_SCOPE, hasBuilderOAuthSession, resolveBuilderOAuthRequestAccess, } from "../../server/builder-oauth.js";
7
6
  import { hasChatGPTSubscriptionCredential } from "../../server/chatgpt-subscription-oauth.js";
8
7
  import { assertCredentialStoreReadable, canUseDeployCredentialFallbackForRequest, getBuilderCredentialAuthFailure, getProviderCredentialAuthFailure, isTrustedSelfHostedRuntime, prefetchSecrets, readDeployCredentialEnv, resolveBuilderCredentialsDetailed, resolveBuilderGatewayCredentialsDetailed, resolveSecretDetailed, } from "../../server/credential-provider.js";
9
8
  import { getRequestOrgId, getRequestContext, getRequestUserEmail, } from "../../server/request-context.js";
10
9
  import { resolveSecretWithAliasesDetailed, secretKeyNames, } from "../../server/secret-key-aliases.js";
11
10
  import { getAgentAppModelDefaultForCurrentRequest } from "../app-model-defaults.js";
12
- import { CHATGPT_SUBSCRIPTION_ENGINE_NAME, CHATGPT_SUBSCRIPTION_LAB_KEY, } from "../chatgpt-subscription-contract.js";
11
+ import { CHATGPT_SUBSCRIPTION_ENGINE_NAME } from "../chatgpt-subscription-contract.js";
13
12
  import { readDefaultAgentEngineSetting } from "../default-agent-engine.js";
14
13
  import { createProviderEndpointFetch } from "./ai-sdk-engine.js";
15
14
  import { OLLAMA_DEFAULT_BASE_URL, OLLAMA_BASE_URL_ENV_VAR, OPENAI_BASE_URL_ENV_VAR, isCustomOpenAiBaseUrl, } from "./openai-compatible-endpoint.js";
@@ -597,9 +596,6 @@ async function chatGPTSubscriptionUsableForRequest(identity) {
597
596
  const email = identityUserEmail(identity);
598
597
  if (!email)
599
598
  return false;
600
- const labs = await getUserLabs(email);
601
- if (labs[CHATGPT_SUBSCRIPTION_LAB_KEY] !== true)
602
- return false;
603
599
  return hasChatGPTSubscriptionCredential(email);
604
600
  }
605
601
  /**
@@ -643,7 +639,7 @@ async function engineCreateConfigForEntry(entry, apiKey, extra, credentialResolu
643
639
  const email = identityUserEmail(credentialIdentity);
644
640
  if (!email ||
645
641
  !(await chatGPTSubscriptionUsableForRequest(credentialIdentity))) {
646
- throw new Error("Enable the ChatGPT subscription lab and connect a ChatGPT subscription before using this engine.");
642
+ throw new Error("Connect a ChatGPT account with direct model access before using this engine.");
647
643
  }
648
644
  safeExtra.userEmail = email;
649
645
  }
@@ -139,8 +139,8 @@ export declare function createAutomationCallbackHandler(runtime: AutomationRunti
139
139
  duplicate?: undefined;
140
140
  eventId?: undefined;
141
141
  } | {
142
+ error?: undefined;
142
143
  accepted: boolean;
143
144
  duplicate: boolean;
144
145
  eventId: string;
145
- error?: undefined;
146
146
  }>;
@@ -2,12 +2,15 @@ export interface EngineModelGroup {
2
2
  engine: string;
3
3
  label: string;
4
4
  models: string[];
5
+ modelDisplayNames?: Readonly<Record<string, string>>;
5
6
  configured: boolean;
7
+ isSubscription?: boolean;
6
8
  }
7
9
  export interface ChatModelEngineEntry {
8
10
  name: string;
9
11
  label: string;
10
12
  supportedModels?: readonly string[];
13
+ modelDisplayNames?: Readonly<Record<string, string>>;
11
14
  acceptsCustomModels?: boolean;
12
15
  preserveCustomModels?: boolean;
13
16
  requiredEnvVars?: readonly string[];
@@ -1,3 +1,4 @@
1
+ import { CHATGPT_SUBSCRIPTION_ENGINE_NAME } from "../agent/chatgpt-subscription-contract.js";
1
2
  export function modelCatalogConfirmsMissing(groups, loading) {
2
3
  return (loading === false &&
3
4
  groups !== undefined &&
@@ -116,6 +117,8 @@ function shouldShowDirectEngine(engine, configured, currentEngineName) {
116
117
  return false;
117
118
  if (engine.name === "ai-sdk:anthropic")
118
119
  return false;
120
+ if (engine.name === CHATGPT_SUBSCRIPTION_ENGINE_NAME)
121
+ return configured;
119
122
  // Keyless engines (Ollama) always report ready, so only models someone
120
123
  // checked for them say they are set up.
121
124
  if (engine.requiredEnvVars?.length === 0) {
@@ -159,10 +162,18 @@ export function buildChatModelGroups({ engines, configuredKeys, builderConnected
159
162
  const group = {
160
163
  engine: engine.name,
161
164
  label: engine.label,
162
- models: sortModelsByCost(modelsFor(engine, true)),
165
+ models: engine.name === CHATGPT_SUBSCRIPTION_ENGINE_NAME
166
+ ? modelsFor(engine, false)
167
+ : sortModelsByCost(modelsFor(engine, true)),
168
+ ...(engine.modelDisplayNames
169
+ ? { modelDisplayNames: engine.modelDisplayNames }
170
+ : {}),
163
171
  configured: engine.configured ??
164
172
  (requiredEnvVars.length === 0 ||
165
173
  requiredEnvVars.some((key) => configured.has(key))),
174
+ ...(engine.name === CHATGPT_SUBSCRIPTION_ENGINE_NAME
175
+ ? { isSubscription: true }
176
+ : {}),
166
177
  };
167
178
  return { engine, group };
168
179
  })
@@ -38,19 +38,19 @@ export declare const postAwareness: import("h3").EventHandlerWithFetch<import("h
38
38
  error: string;
39
39
  states?: undefined;
40
40
  } | {
41
- error?: undefined;
42
41
  states: {
43
42
  clientId: number;
44
43
  state: string;
45
44
  }[];
45
+ error?: undefined;
46
46
  }>>;
47
47
  export declare const getActiveUsers: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
48
48
  error: string;
49
49
  users?: undefined;
50
50
  } | {
51
- error?: undefined;
52
51
  users: {
53
52
  clientId: number;
54
53
  lastSeen: number;
55
54
  }[];
55
+ error?: undefined;
56
56
  }>>;
@@ -8,16 +8,16 @@ export declare const getCollabState: import("h3").EventHandlerWithFetch<import("
8
8
  state: string;
9
9
  }>>;
10
10
  export declare const postCollabUpdate: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
11
- error: string;
12
11
  ok?: undefined;
12
+ error: string;
13
13
  } | {
14
14
  error?: undefined;
15
15
  ok: boolean;
16
16
  }>>;
17
17
  export declare const postCollabText: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
18
18
  ok?: undefined;
19
- error: string;
20
19
  text?: undefined;
20
+ error: string;
21
21
  } | {
22
22
  error?: undefined;
23
23
  ok: boolean;
@@ -1,6 +1,6 @@
1
1
  export declare const postCollabJson: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
2
- ok?: undefined;
3
2
  error: string;
3
+ ok?: undefined;
4
4
  } | {
5
5
  error?: undefined;
6
6
  ok: boolean;
@@ -33,9 +33,9 @@ declare const _default: import("../../action.js").ActionDefinition<{
33
33
  idempotencyKey: string;
34
34
  deleted: boolean;
35
35
  } | {
36
+ id?: undefined;
36
37
  error: string;
37
38
  url?: undefined;
38
- id?: undefined;
39
39
  provider?: undefined;
40
40
  configured?: undefined;
41
41
  } | {
@@ -45,8 +45,8 @@ declare const _default: import("../../action.js").ActionDefinition<{
45
45
  configured?: undefined;
46
46
  error?: undefined;
47
47
  } | {
48
- url?: undefined;
49
48
  id?: undefined;
49
+ url?: undefined;
50
50
  provider?: undefined;
51
51
  error: string;
52
52
  configured: boolean;
@@ -112,6 +112,8 @@ export const CORE_ACTION_GROUPS = {
112
112
  "set-lab": "labs",
113
113
  "get-chatgpt-subscription-status": "chat",
114
114
  "disconnect-chatgpt-subscription": "chat",
115
+ "list-chatgpt-subscription-accounts": "chat",
116
+ "select-chatgpt-subscription-account": "chat",
115
117
  "preview-secret-removal": "chat",
116
118
  "list-api-keys": "chat",
117
119
  "delete-api-key": "chat",