@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.
- package/dist/agent/actions/disconnect-chatgpt-subscription.d.ts +10 -1
- package/dist/agent/actions/disconnect-chatgpt-subscription.js +23 -5
- package/dist/agent/actions/get-chatgpt-subscription-status.d.ts +1 -6
- package/dist/agent/actions/get-chatgpt-subscription-status.js +1 -1
- package/dist/agent/actions/list-chatgpt-subscription-accounts.d.ts +5 -0
- package/dist/agent/actions/list-chatgpt-subscription-accounts.js +14 -0
- package/dist/agent/actions/select-chatgpt-subscription-account.d.ts +7 -0
- package/dist/agent/actions/select-chatgpt-subscription-account.js +22 -0
- package/dist/agent/chatgpt-subscription-contract.d.ts +14 -4
- package/dist/agent/chatgpt-subscription-contract.js +20 -8
- package/dist/agent/engine/builtin.js +5 -5
- package/dist/agent/engine/chatgpt-subscription-engine.d.ts +6 -0
- package/dist/agent/engine/chatgpt-subscription-engine.js +149 -49
- package/dist/agent/engine/registry.js +2 -6
- package/dist/automation/index.d.ts +1 -1
- package/dist/client/chat-model-groups.d.ts +3 -0
- package/dist/client/chat-model-groups.js +12 -1
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/routes.d.ts +2 -2
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +2 -2
- package/dist/framework-tools.js +2 -0
- package/dist/labs/core-labs.js +1 -2
- package/dist/localization/default-messages.d.ts +26 -0
- package/dist/localization/default-messages.js +26 -0
- package/dist/oauth-tokens/lifecycle.d.ts +1 -0
- package/dist/oauth-tokens/lifecycle.js +5 -1
- package/dist/observability/routes.d.ts +7 -7
- package/dist/org/handlers.d.ts +1 -1
- package/dist/org/index.d.ts +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +16 -16
- package/dist/provider-api/actions/provider-api.d.ts +11 -11
- package/dist/scripts/agent-engines/list-agent-engines.js +48 -10
- package/dist/scripts/agent-engines/manage-agent-engine.js +16 -0
- package/dist/scripts/agent-engines/set-agent-engine.d.ts +3 -0
- package/dist/scripts/agent-engines/set-agent-engine.js +51 -9
- package/dist/secrets/routes.d.ts +10 -10
- package/dist/server/action-discovery.js +8 -0
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/agent-engine-default-model-route.d.ts +2 -2
- package/dist/server/agent-engine-ollama-models-route.d.ts +1 -1
- package/dist/server/chatgpt-subscription-oauth.d.ts +85 -5
- package/dist/server/chatgpt-subscription-oauth.js +1098 -212
- package/dist/server/core-routes-plugin.d.ts +1 -1
- package/dist/server/core-routes-plugin.js +2 -4
- package/dist/vite/action-types-plugin.js +8 -0
- package/docs/content/toolkit-settings.mdx +30 -22
- package/package.json +6 -4
|
@@ -1,4 +1,13 @@
|
|
|
1
|
-
declare const _default: import("../../action.js").ActionDefinition<
|
|
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: "
|
|
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
|
-
|
|
12
|
-
|
|
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
|
|
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,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,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
|
|
4
|
-
export declare const
|
|
5
|
-
export declare const
|
|
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
|
|
4
|
-
export const
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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 {
|
|
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
|
|
82
|
-
description: "
|
|
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:
|
|
85
|
-
supportedModels:
|
|
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 {
|
|
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
|
|
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("
|
|
35
|
+
headers.delete("originator");
|
|
36
|
+
headers.delete("chatgpt-account-id");
|
|
18
37
|
return headers;
|
|
19
38
|
}
|
|
20
|
-
function
|
|
21
|
-
|
|
22
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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("
|
|
52
|
-
|
|
53
|
-
if (
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
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
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
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
|
|
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
|
|
90
|
-
model:
|
|
91
|
-
supportedModels:
|
|
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
|
|
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("
|
|
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:
|
|
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
|
}>>;
|
package/dist/collab/routes.d.ts
CHANGED
|
@@ -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;
|
|
@@ -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;
|
package/dist/framework-tools.js
CHANGED
|
@@ -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",
|