@push.rocks/smartai 2.2.0 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,48 @@
1
- import type { JSONObject, JSONValue, LanguageModelV3 } from '@ai-sdk/provider';
1
+ import type { JSONObject, JSONValue, LanguageModelV3, LanguageModelV3Prompt } from '@ai-sdk/provider';
2
+ import type { ISmartAiCacheOptions } from './smartai.cache.js';
2
3
  export type TProvider = 'anthropic' | 'openai' | 'google' | 'groq' | 'mistral' | 'xai' | 'perplexity' | 'ollama';
3
4
  export type TOpenAiReasoningEffort = 'none' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh';
4
5
  export type TOpenAiTextVerbosity = 'low' | 'medium' | 'high';
6
+ export interface IOpenAiChatGptTokenInfo {
7
+ email?: string;
8
+ chatgptPlanType?: string;
9
+ chatgptUserId?: string;
10
+ chatgptAccountId?: string;
11
+ chatgptAccountIsFedramp: boolean;
12
+ expiresAt?: string;
13
+ rawJwt: string;
14
+ }
15
+ export interface IOpenAiChatGptAuthCredentials {
16
+ accessToken: string;
17
+ refreshToken?: string;
18
+ idToken?: string;
19
+ accountId?: string;
20
+ tokenInfo?: IOpenAiChatGptTokenInfo;
21
+ baseUrl?: string;
22
+ originator?: string;
23
+ }
24
+ export interface IOpenAiChatGptTokenData extends IOpenAiChatGptAuthCredentials {
25
+ refreshToken: string;
26
+ tokenInfo: IOpenAiChatGptTokenInfo;
27
+ }
28
+ export interface IOpenAiChatGptDeviceCode {
29
+ verificationUrl: string;
30
+ userCode: string;
31
+ deviceAuthId: string;
32
+ intervalSeconds: number;
33
+ }
34
+ export interface IOpenAiChatGptAuthOptions {
35
+ issuer?: string;
36
+ clientId?: string;
37
+ fetch?: typeof fetch;
38
+ }
39
+ export interface IOpenAiChatGptDeviceCodePollOptions extends IOpenAiChatGptAuthOptions {
40
+ timeoutMs?: number;
41
+ sleep?: (ms: number) => Promise<void>;
42
+ }
43
+ export interface IOpenAiChatGptCompleteDeviceCodeOptions extends IOpenAiChatGptDeviceCodePollOptions {
44
+ forcedChatGptWorkspaceId?: string;
45
+ }
5
46
  export interface IOpenAiProviderOptions extends JSONObject {
6
47
  conversation?: string | null;
7
48
  include?: string[] | null;
@@ -40,6 +81,11 @@ export interface ISmartAiOptions {
40
81
  provider: TProvider;
41
82
  model: string;
42
83
  apiKey?: string;
84
+ /**
85
+ * OpenAI ChatGPT/Codex subscription credentials from the device-code auth flow.
86
+ * Only used when provider === 'openai'.
87
+ */
88
+ openAiChatGptAuth?: IOpenAiChatGptAuthCredentials;
43
89
  /**
44
90
  * Provider-specific AI SDK generation options.
45
91
  * Pass this to generateText()/streamText() alongside the model.
@@ -56,7 +102,7 @@ export interface ISmartAiOptions {
56
102
  * Enable Anthropic prompt caching on system + recent messages.
57
103
  * Only used when provider === 'anthropic'. Default: true.
58
104
  */
59
- promptCaching?: boolean;
105
+ promptCaching?: boolean | ISmartAiCacheOptions;
60
106
  }
61
107
  /**
62
108
  * Ollama model runtime options passed in the request body `options` field.
@@ -79,4 +125,4 @@ export interface IOllamaModelOptions {
79
125
  */
80
126
  think?: boolean;
81
127
  }
82
- export type { LanguageModelV3 };
128
+ export type { LanguageModelV3, LanguageModelV3Prompt };
@@ -1,7 +1,8 @@
1
1
  import type { LanguageModelV3Middleware } from '@ai-sdk/provider';
2
+ import type { ISmartAiCacheOptions } from './smartai.cache.js';
2
3
  /**
3
4
  * Creates middleware that adds Anthropic prompt caching directives.
4
5
  * Marks the last system message and last user message with ephemeral cache control,
5
6
  * reducing input token cost and latency on repeated calls.
6
7
  */
7
- export declare function createAnthropicCachingMiddleware(): LanguageModelV3Middleware;
8
+ export declare function createAnthropicCachingMiddleware(options?: ISmartAiCacheOptions): LanguageModelV3Middleware;
@@ -1,36 +1,10 @@
1
+ import { createSmartAiCachingMiddleware } from './smartai.cache.js';
1
2
  /**
2
3
  * Creates middleware that adds Anthropic prompt caching directives.
3
4
  * Marks the last system message and last user message with ephemeral cache control,
4
5
  * reducing input token cost and latency on repeated calls.
5
6
  */
6
- export function createAnthropicCachingMiddleware() {
7
- return {
8
- specificationVersion: 'v3',
9
- transformParams: async ({ params }) => {
10
- const messages = [...params.prompt];
11
- // Find the last system message and last user message
12
- let lastSystemIdx = -1;
13
- let lastUserIdx = -1;
14
- for (let i = 0; i < messages.length; i++) {
15
- if (messages[i].role === 'system')
16
- lastSystemIdx = i;
17
- if (messages[i].role === 'user')
18
- lastUserIdx = i;
19
- }
20
- const targets = [lastSystemIdx, lastUserIdx].filter(i => i >= 0);
21
- for (const idx of targets) {
22
- const msg = { ...messages[idx] };
23
- msg.providerOptions = {
24
- ...(msg.providerOptions || {}),
25
- anthropic: {
26
- ...(msg.providerOptions?.anthropic || {}),
27
- cacheControl: { type: 'ephemeral' },
28
- },
29
- };
30
- messages[idx] = msg;
31
- }
32
- return { ...params, prompt: messages };
33
- },
34
- };
7
+ export function createAnthropicCachingMiddleware(options = {}) {
8
+ return createSmartAiCachingMiddleware({ ...options, provider: 'anthropic' });
35
9
  }
36
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRhaS5taWRkbGV3YXJlLmFudGhyb3BpYy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL3NtYXJ0YWkubWlkZGxld2FyZS5hbnRocm9waWMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBRUE7Ozs7R0FJRztBQUNILE1BQU0sVUFBVSxnQ0FBZ0M7SUFDOUMsT0FBTztRQUNMLG9CQUFvQixFQUFFLElBQUk7UUFDMUIsZUFBZSxFQUFFLEtBQUssRUFBRSxFQUFFLE1BQU0sRUFBRSxFQUFFLEVBQUU7WUFDcEMsTUFBTSxRQUFRLEdBQUcsQ0FBQyxHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQW1DLENBQUM7WUFFdEUscURBQXFEO1lBQ3JELElBQUksYUFBYSxHQUFHLENBQUMsQ0FBQyxDQUFDO1lBQ3ZCLElBQUksV0FBVyxHQUFHLENBQUMsQ0FBQyxDQUFDO1lBQ3JCLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxRQUFRLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUM7Z0JBQ3pDLElBQUksUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksS0FBSyxRQUFRO29CQUFFLGFBQWEsR0FBRyxDQUFDLENBQUM7Z0JBQ3JELElBQUksUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksS0FBSyxNQUFNO29CQUFFLFdBQVcsR0FBRyxDQUFDLENBQUM7WUFDbkQsQ0FBQztZQUVELE1BQU0sT0FBTyxHQUFHLENBQUMsYUFBYSxFQUFFLFdBQVcsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztZQUNqRSxLQUFLLE1BQU0sR0FBRyxJQUFJLE9BQU8sRUFBRSxDQUFDO2dCQUMxQixNQUFNLEdBQUcsR0FBRyxFQUFFLEdBQUcsUUFBUSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUM7Z0JBQ2pDLEdBQUcsQ0FBQyxlQUFlLEdBQUc7b0JBQ3BCLEdBQUcsQ0FBQyxHQUFHLENBQUMsZUFBMEMsSUFBSSxFQUFFLENBQUM7b0JBQ3pELFNBQVMsRUFBRTt3QkFDVCxHQUFHLENBQUUsR0FBRyxDQUFDLGVBQTJDLEVBQUUsU0FBb0MsSUFBSSxFQUFFLENBQUM7d0JBQ2pHLFlBQVksRUFBRSxFQUFFLElBQUksRUFBRSxXQUFXLEVBQUU7cUJBQ3BDO2lCQUNGLENBQUM7Z0JBQ0YsUUFBUSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEdBQUcsQ0FBQztZQUN0QixDQUFDO1lBRUQsT0FBTyxFQUFFLEdBQUcsTUFBTSxFQUFFLE1BQU0sRUFBRSxRQUE0QyxFQUFFLENBQUM7UUFDN0UsQ0FBQztLQUNGLENBQUM7QUFDSixDQUFDIn0=
10
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRhaS5taWRkbGV3YXJlLmFudGhyb3BpYy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL3NtYXJ0YWkubWlkZGxld2FyZS5hbnRocm9waWMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxFQUFFLDhCQUE4QixFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFHcEU7Ozs7R0FJRztBQUNILE1BQU0sVUFBVSxnQ0FBZ0MsQ0FBQyxVQUFnQyxFQUFFO0lBQ2pGLE9BQU8sOEJBQThCLENBQUMsRUFBRSxHQUFHLE9BQU8sRUFBRSxRQUFRLEVBQUUsV0FBVyxFQUFFLENBQUMsQ0FBQztBQUMvRSxDQUFDIn0=
@@ -0,0 +1,43 @@
1
+ import type { IOpenAiChatGptAuthOptions, IOpenAiChatGptTokenData } from '../dist_ts/smartai.interfaces.js';
2
+ export type TOpenAiChatGptAuthSource = 'smartai' | 'opencode' | 'codex';
3
+ export type TOpenAiChatGptAuthFileFormat = TOpenAiChatGptAuthSource | 'auto';
4
+ export interface IOpenAiChatGptAuthSourceConfig {
5
+ source: TOpenAiChatGptAuthSource;
6
+ filePath?: string;
7
+ format?: TOpenAiChatGptAuthFileFormat;
8
+ writeBack?: boolean;
9
+ }
10
+ export interface IOpenAiChatGptAuthSourceInspection {
11
+ source: TOpenAiChatGptAuthSource;
12
+ filePath: string;
13
+ exists: boolean;
14
+ usable: boolean;
15
+ expired?: boolean;
16
+ accountId?: string;
17
+ email?: string;
18
+ plan?: string;
19
+ expiresAt?: string;
20
+ error?: string;
21
+ }
22
+ export interface IInspectOpenAiChatGptAuthSourcesOptions {
23
+ sources?: Array<TOpenAiChatGptAuthSource | IOpenAiChatGptAuthSourceConfig>;
24
+ homeDir?: string;
25
+ now?: Date;
26
+ }
27
+ export interface IResolveOpenAiChatGptAuthOptions extends IInspectOpenAiChatGptAuthSourcesOptions {
28
+ refresh?: 'ifNeeded' | false;
29
+ writeBack?: Partial<Record<TOpenAiChatGptAuthSource, boolean>>;
30
+ authOptions?: IOpenAiChatGptAuthOptions;
31
+ }
32
+ export interface IResolvedOpenAiChatGptAuth {
33
+ source: TOpenAiChatGptAuthSource;
34
+ filePath: string;
35
+ tokenData: IOpenAiChatGptTokenData;
36
+ refreshed: boolean;
37
+ }
38
+ export declare const getDefaultOpenAiChatGptAuthPath: (source: TOpenAiChatGptAuthSource, homeDir?: string) => string;
39
+ export declare const normalizeOpenAiChatGptAuth: (input: unknown, format?: TOpenAiChatGptAuthFileFormat) => IOpenAiChatGptTokenData | undefined;
40
+ export declare const readOpenAiChatGptAuthFile: (filePath: string, format?: TOpenAiChatGptAuthFileFormat) => Promise<IOpenAiChatGptTokenData | undefined>;
41
+ export declare const inspectOpenAiChatGptAuthSources: (options?: IInspectOpenAiChatGptAuthSourcesOptions) => Promise<IOpenAiChatGptAuthSourceInspection[]>;
42
+ export declare const resolveOpenAiChatGptAuth: (options?: IResolveOpenAiChatGptAuthOptions) => Promise<IResolvedOpenAiChatGptAuth | undefined>;
43
+ export declare const writeOpenAiChatGptAuthFile: (filePath: string, tokenData: IOpenAiChatGptTokenData, format?: TOpenAiChatGptAuthFileFormat) => Promise<void>;
@@ -0,0 +1,249 @@
1
+ import * as fs from 'node:fs/promises';
2
+ import * as os from 'node:os';
3
+ import * as path from 'node:path';
4
+ import { parseOpenAiChatGptTokenInfo, refreshOpenAiChatGptTokenData, } from '../dist_ts/smartai.auth.openai.js';
5
+ const defaultSources = ['smartai', 'opencode', 'codex'];
6
+ const refreshWindowMs = 5 * 60 * 1000;
7
+ export const getDefaultOpenAiChatGptAuthPath = (source, homeDir = os.homedir()) => {
8
+ switch (source) {
9
+ case 'smartai':
10
+ return path.join(homeDir, '.git.zone', 'ide', 'openai-chatgpt-auth.json');
11
+ case 'opencode':
12
+ return path.join(homeDir, '.local', 'share', 'opencode', 'auth.json');
13
+ case 'codex':
14
+ return path.join(homeDir, '.codex', 'auth.json');
15
+ default:
16
+ throw new Error(`Unsupported OpenAI ChatGPT auth source: ${source}`);
17
+ }
18
+ };
19
+ export const normalizeOpenAiChatGptAuth = (input, format = 'auto') => {
20
+ if (format === 'auto') {
21
+ return normalizeOpenAiChatGptAuth(input, 'smartai')
22
+ ?? normalizeOpenAiChatGptAuth(input, 'opencode')
23
+ ?? normalizeOpenAiChatGptAuth(input, 'codex');
24
+ }
25
+ if (!isRecord(input))
26
+ return undefined;
27
+ if (format === 'opencode') {
28
+ return normalizeOpenCodeAuth(input);
29
+ }
30
+ return normalizeTokenObject(isRecord(input.tokens) ? input.tokens : input);
31
+ };
32
+ export const readOpenAiChatGptAuthFile = async (filePath, format = 'auto') => {
33
+ const parsed = JSON.parse(await fs.readFile(filePath, 'utf8'));
34
+ return normalizeOpenAiChatGptAuth(parsed, format);
35
+ };
36
+ export const inspectOpenAiChatGptAuthSources = async (options = {}) => {
37
+ const now = options.now ?? new Date();
38
+ const sourceConfigs = normalizeSourceConfigs(options.sources, options.homeDir);
39
+ return Promise.all(sourceConfigs.map(async (sourceConfig) => {
40
+ try {
41
+ const tokenData = await readOpenAiChatGptAuthFile(sourceConfig.filePath, sourceConfig.format ?? sourceConfig.source);
42
+ if (!tokenData) {
43
+ return {
44
+ source: sourceConfig.source,
45
+ filePath: sourceConfig.filePath,
46
+ exists: true,
47
+ usable: false,
48
+ error: 'No OpenAI ChatGPT auth token found in file.',
49
+ };
50
+ }
51
+ return toInspection(sourceConfig.source, sourceConfig.filePath, tokenData, now);
52
+ }
53
+ catch (error) {
54
+ const nodeError = error;
55
+ return {
56
+ source: sourceConfig.source,
57
+ filePath: sourceConfig.filePath,
58
+ exists: nodeError.code !== 'ENOENT',
59
+ usable: false,
60
+ error: nodeError.code === 'ENOENT' ? undefined : nodeError.message,
61
+ };
62
+ }
63
+ }));
64
+ };
65
+ export const resolveOpenAiChatGptAuth = async (options = {}) => {
66
+ const now = options.now ?? new Date();
67
+ const sourceConfigs = normalizeSourceConfigs(options.sources, options.homeDir);
68
+ const refresh = options.refresh ?? 'ifNeeded';
69
+ for (const sourceConfig of sourceConfigs) {
70
+ let tokenData;
71
+ try {
72
+ tokenData = await readOpenAiChatGptAuthFile(sourceConfig.filePath, sourceConfig.format ?? sourceConfig.source);
73
+ }
74
+ catch (error) {
75
+ const nodeError = error;
76
+ if (nodeError.code === 'ENOENT')
77
+ continue;
78
+ continue;
79
+ }
80
+ if (!tokenData)
81
+ continue;
82
+ const shouldRefresh = refresh === 'ifNeeded' && shouldRefreshToken(tokenData, now);
83
+ const writeBack = sourceConfig.writeBack ?? options.writeBack?.[sourceConfig.source] ?? sourceConfig.source === 'smartai';
84
+ if (!shouldRefresh) {
85
+ return { source: sourceConfig.source, filePath: sourceConfig.filePath, tokenData, refreshed: false };
86
+ }
87
+ if (!writeBack) {
88
+ if (!isExpired(tokenData, now)) {
89
+ return { source: sourceConfig.source, filePath: sourceConfig.filePath, tokenData, refreshed: false };
90
+ }
91
+ continue;
92
+ }
93
+ try {
94
+ const refreshed = await refreshOpenAiChatGptTokenData(tokenData, options.authOptions ?? {});
95
+ await writeOpenAiChatGptAuthFile(sourceConfig.filePath, refreshed, sourceConfig.format ?? sourceConfig.source);
96
+ return { source: sourceConfig.source, filePath: sourceConfig.filePath, tokenData: refreshed, refreshed: true };
97
+ }
98
+ catch {
99
+ continue;
100
+ }
101
+ }
102
+ return undefined;
103
+ };
104
+ export const writeOpenAiChatGptAuthFile = async (filePath, tokenData, format = 'smartai') => {
105
+ const current = await readJsonFileIfExists(filePath);
106
+ const payload = format === 'opencode'
107
+ ? toOpenCodeAuthFile(current, tokenData)
108
+ : format === 'codex'
109
+ ? toCodexAuthFile(current, tokenData)
110
+ : toSmartAiAuthFile(tokenData);
111
+ await writeJsonAtomic(filePath, payload);
112
+ };
113
+ const normalizeSourceConfigs = (sources, homeDir = os.homedir()) => {
114
+ return (sources ?? defaultSources).map((sourceInput) => {
115
+ const sourceConfig = typeof sourceInput === 'string' ? { source: sourceInput } : sourceInput;
116
+ return {
117
+ source: sourceConfig.source,
118
+ filePath: sourceConfig.filePath ?? getDefaultOpenAiChatGptAuthPath(sourceConfig.source, homeDir),
119
+ format: sourceConfig.format ?? sourceConfig.source,
120
+ writeBack: sourceConfig.writeBack,
121
+ };
122
+ });
123
+ };
124
+ const toInspection = (source, filePath, tokenData, now) => {
125
+ const expired = isExpired(tokenData, now);
126
+ return {
127
+ source,
128
+ filePath,
129
+ exists: true,
130
+ usable: !expired,
131
+ expired,
132
+ accountId: tokenData.accountId ?? tokenData.tokenInfo.chatgptAccountId,
133
+ email: tokenData.tokenInfo.email,
134
+ plan: tokenData.tokenInfo.chatgptPlanType,
135
+ expiresAt: tokenData.tokenInfo.expiresAt,
136
+ };
137
+ };
138
+ const normalizeTokenObject = (input) => {
139
+ const accessToken = stringValue(input.accessToken) ?? stringValue(input.access_token);
140
+ const refreshToken = stringValue(input.refreshToken) ?? stringValue(input.refresh_token);
141
+ const idToken = stringValue(input.idToken) ?? stringValue(input.id_token) ?? stringValue(input.tokenInfo?.rawJwt);
142
+ const accountId = stringValue(input.accountId) ?? stringValue(input.account_id);
143
+ return createTokenDataFromValues({ accessToken, refreshToken, idToken, accountId });
144
+ };
145
+ const normalizeOpenCodeAuth = (input) => {
146
+ if (!isRecord(input.openai))
147
+ return undefined;
148
+ const accessToken = stringValue(input.openai.access);
149
+ const refreshToken = stringValue(input.openai.refresh);
150
+ const accountId = stringValue(input.openai.accountId);
151
+ const expiresAt = typeof input.openai.expires === 'number' ? new Date(input.openai.expires).toISOString() : undefined;
152
+ return createTokenDataFromValues({ accessToken, refreshToken, accountId, fallbackExpiresAt: expiresAt });
153
+ };
154
+ const createTokenDataFromValues = (input) => {
155
+ if (!input.accessToken || !input.refreshToken)
156
+ return undefined;
157
+ const parseToken = input.idToken ?? input.accessToken;
158
+ const tokenInfo = parseTokenInfo(parseToken, input.accountId, input.fallbackExpiresAt);
159
+ return {
160
+ accessToken: input.accessToken,
161
+ refreshToken: input.refreshToken,
162
+ idToken: input.idToken,
163
+ accountId: input.accountId ?? tokenInfo.chatgptAccountId,
164
+ tokenInfo,
165
+ };
166
+ };
167
+ const parseTokenInfo = (token, accountId, fallbackExpiresAt) => {
168
+ try {
169
+ const tokenInfo = parseOpenAiChatGptTokenInfo(token);
170
+ return {
171
+ ...tokenInfo,
172
+ chatgptAccountId: tokenInfo.chatgptAccountId ?? accountId,
173
+ expiresAt: tokenInfo.expiresAt ?? fallbackExpiresAt,
174
+ };
175
+ }
176
+ catch {
177
+ return {
178
+ chatgptAccountId: accountId,
179
+ chatgptAccountIsFedramp: false,
180
+ expiresAt: fallbackExpiresAt,
181
+ rawJwt: token,
182
+ };
183
+ }
184
+ };
185
+ const toSmartAiAuthFile = (tokenData) => ({
186
+ accessToken: tokenData.accessToken,
187
+ refreshToken: tokenData.refreshToken,
188
+ idToken: tokenData.idToken,
189
+ accountId: tokenData.accountId,
190
+ tokenInfo: tokenData.tokenInfo,
191
+ });
192
+ const toCodexAuthFile = (current, tokenData) => ({
193
+ ...current,
194
+ OPENAI_API_KEY: current.OPENAI_API_KEY ?? null,
195
+ tokens: {
196
+ ...(isRecord(current.tokens) ? current.tokens : {}),
197
+ id_token: tokenData.idToken,
198
+ access_token: tokenData.accessToken,
199
+ refresh_token: tokenData.refreshToken,
200
+ account_id: tokenData.accountId ?? tokenData.tokenInfo.chatgptAccountId,
201
+ },
202
+ last_refresh: new Date().toISOString(),
203
+ });
204
+ const toOpenCodeAuthFile = (current, tokenData) => ({
205
+ ...current,
206
+ openai: {
207
+ ...(isRecord(current.openai) ? current.openai : {}),
208
+ type: 'oauth',
209
+ refresh: tokenData.refreshToken,
210
+ access: tokenData.accessToken,
211
+ expires: tokenData.tokenInfo.expiresAt ? Date.parse(tokenData.tokenInfo.expiresAt) : undefined,
212
+ accountId: tokenData.accountId ?? tokenData.tokenInfo.chatgptAccountId,
213
+ },
214
+ });
215
+ const shouldRefreshToken = (tokenData, now) => {
216
+ if (!tokenData.tokenInfo.expiresAt)
217
+ return false;
218
+ return Date.parse(tokenData.tokenInfo.expiresAt) - now.getTime() < refreshWindowMs;
219
+ };
220
+ const isExpired = (tokenData, now) => {
221
+ if (!tokenData.tokenInfo.expiresAt)
222
+ return false;
223
+ return Date.parse(tokenData.tokenInfo.expiresAt) <= now.getTime();
224
+ };
225
+ const readJsonFileIfExists = async (filePath) => {
226
+ try {
227
+ const parsed = JSON.parse(await fs.readFile(filePath, 'utf8'));
228
+ return isRecord(parsed) ? parsed : {};
229
+ }
230
+ catch (error) {
231
+ const nodeError = error;
232
+ if (nodeError.code === 'ENOENT')
233
+ return {};
234
+ throw error;
235
+ }
236
+ };
237
+ const writeJsonAtomic = async (filePath, payload) => {
238
+ const tempPath = `${filePath}.${process.pid}.${Date.now()}.tmp`;
239
+ await fs.mkdir(path.dirname(filePath), { recursive: true, mode: 0o700 });
240
+ await fs.writeFile(tempPath, `${JSON.stringify(payload, undefined, 2)}\n`, { mode: 0o600 });
241
+ await fs.rename(tempPath, filePath);
242
+ };
243
+ const isRecord = (value) => {
244
+ return !!value && typeof value === 'object' && !Array.isArray(value);
245
+ };
246
+ const stringValue = (value) => {
247
+ return typeof value === 'string' && value.length > 0 ? value : undefined;
248
+ };
249
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90c19vcGVuYWlfY2hhdGdwdF9hdXRoL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFDdkMsT0FBTyxLQUFLLEVBQUUsTUFBTSxTQUFTLENBQUM7QUFDOUIsT0FBTyxLQUFLLElBQUksTUFBTSxXQUFXLENBQUM7QUFDbEMsT0FBTyxFQUNMLDJCQUEyQixFQUMzQiw2QkFBNkIsR0FDOUIsTUFBTSw4QkFBOEIsQ0FBQztBQXdEdEMsTUFBTSxjQUFjLEdBQStCLENBQUMsU0FBUyxFQUFFLFVBQVUsRUFBRSxPQUFPLENBQUMsQ0FBQztBQUNwRixNQUFNLGVBQWUsR0FBRyxDQUFDLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FBQztBQUV0QyxNQUFNLENBQUMsTUFBTSwrQkFBK0IsR0FBRyxDQUM3QyxNQUFnQyxFQUNoQyxPQUFPLEdBQUcsRUFBRSxDQUFDLE9BQU8sRUFBRSxFQUNkLEVBQUU7SUFDVixRQUFRLE1BQU0sRUFBRSxDQUFDO1FBQ2YsS0FBSyxTQUFTO1lBQ1osT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxXQUFXLEVBQUUsS0FBSyxFQUFFLDBCQUEwQixDQUFDLENBQUM7UUFDNUUsS0FBSyxVQUFVO1lBQ2IsT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxRQUFRLEVBQUUsT0FBTyxFQUFFLFVBQVUsRUFBRSxXQUFXLENBQUMsQ0FBQztRQUN4RSxLQUFLLE9BQU87WUFDVixPQUFPLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLFFBQVEsRUFBRSxXQUFXLENBQUMsQ0FBQztRQUNuRDtZQUNFLE1BQU0sSUFBSSxLQUFLLENBQUMsMkNBQTJDLE1BQXNCLEVBQUUsQ0FBQyxDQUFDO0lBQ3pGLENBQUM7QUFDSCxDQUFDLENBQUM7QUFFRixNQUFNLENBQUMsTUFBTSww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QUFRLEVBQUUsR0FBRyxJQUFJLENBQUMsU0FBUyxDQUFDLE9BQU8sRUFBRSxTQUFTLEVBQUUsQ0FBQyxDQUFDLElBQUksRUFBRSxFQUFFLElBQUksRUFBRSxLQUFLLEVBQUUsQ0FBQyxDQUFDO0lBQzVGLE1BQU0sRUFBRSxDQUFDLE1BQU0sQ0FBQyxRQUFRLEVBQUUsUUFBUSxDQUFDLENBQUM7QUFDdEMsQ0FBQyxDQUFDO0FBRUYsTUFBTSxRQUFRLEdBQUcsQ0FBQyxLQUFjLEVBQW9DLEVBQUU7SUFDcEUsT0FBTyxDQUFDLENBQUMsS0FBSyxJQUFJLE9BQU8sS0FBSyxLQUFLLFFBQVEsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUM7QUFDdkUsQ0FBQyxDQUFDO0FBRUYsTUFBTSxXQUFXLEdBQUcsQ0FBQyxLQUFjLEVBQXNCLEVBQUU7SUFDekQsT0FBTyxPQUFPLEtBQUssS0FBSyxRQUFRLElBQUksS0FBSyxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDO0FBQzNFLENBQUMsQ0FBQyJ9
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@push.rocks/smartai",
3
- "version": "2.2.0",
3
+ "version": "4.0.0",
4
4
  "private": false,
5
5
  "description": "Provider registry and capability utilities for ai-sdk (Vercel AI SDK). Core export returns LanguageModel; subpath exports provide vision, audio, image, document and research capabilities.",
6
6
  "main": "dist_ts/index.js",
@@ -30,41 +30,39 @@
30
30
  "./research": {
31
31
  "import": "./dist_ts_research/index.js",
32
32
  "types": "./dist_ts_research/index.d.ts"
33
+ },
34
+ "./openai-chatgpt-auth": {
35
+ "import": "./dist_ts_openai_chatgpt_auth/index.js",
36
+ "types": "./dist_ts_openai_chatgpt_auth/index.d.ts"
33
37
  }
34
38
  },
35
39
  "author": "Task Venture Capital GmbH",
36
40
  "license": "MIT",
37
- "scripts": {
38
- "test": "(tstest test/ --verbose --logfile)",
39
- "typecheck": "tsbuild check",
40
- "build": "(tsbuild tsfolders)",
41
- "buildDocs": "(tsdoc)"
42
- },
43
41
  "devDependencies": {
44
- "@git.zone/tsbuild": "^4.4.0",
45
- "@git.zone/tsrun": "^2.0.3",
46
- "@git.zone/tstest": "^3.6.3",
42
+ "@git.zone/tsbuild": "^4.4.1",
43
+ "@git.zone/tsrun": "^2.0.4",
44
+ "@git.zone/tstest": "^3.6.6",
47
45
  "@push.rocks/qenv": "^6.1.4",
48
46
  "@types/json-schema": "^7.0.15",
49
47
  "@types/lodash.clonedeep": "^4.5.9",
50
- "@types/node": "^25.6.0",
48
+ "@types/node": "^25.7.0",
51
49
  "@types/pngjs": "^6.0.5",
52
50
  "typescript": "^6.0.3",
53
51
  "undici-types": "^8.2.0"
54
52
  },
55
53
  "dependencies": {
56
- "@ai-sdk/anthropic": "^3.0.75",
57
- "@ai-sdk/google": "^3.0.67",
58
- "@ai-sdk/groq": "^3.0.38",
59
- "@ai-sdk/mistral": "^3.0.35",
60
- "@ai-sdk/openai": "^3.0.62",
61
- "@ai-sdk/perplexity": "^3.0.32",
54
+ "@ai-sdk/anthropic": "^3.0.77",
55
+ "@ai-sdk/google": "^3.0.73",
56
+ "@ai-sdk/groq": "^3.0.39",
57
+ "@ai-sdk/mistral": "^3.0.36",
58
+ "@ai-sdk/openai": "^3.0.63",
59
+ "@ai-sdk/perplexity": "^3.0.33",
62
60
  "@ai-sdk/provider": "^3.0.10",
63
- "@ai-sdk/xai": "^3.0.88",
64
- "@anthropic-ai/sdk": "0.95.0",
61
+ "@ai-sdk/xai": "^3.0.89",
62
+ "@anthropic-ai/sdk": "0.95.2",
65
63
  "@push.rocks/smartpdf": "^4.2.2",
66
- "ai": "^6.0.175",
67
- "openai": "^6.36.0"
64
+ "ai": "^6.0.180",
65
+ "openai": "^6.37.0"
68
66
  },
69
67
  "repository": {
70
68
  "type": "git",
@@ -84,6 +82,7 @@
84
82
  "ts_image/**/*",
85
83
  "ts_document/**/*",
86
84
  "ts_research/**/*",
85
+ "ts_openai_chatgpt_auth/**/*",
87
86
  "dist_*/**/*",
88
87
  "assets/**/*",
89
88
  ".smartconfig.json",
@@ -115,11 +114,10 @@
115
114
  "AI toolkit",
116
115
  "provider switching"
117
116
  ],
118
- "pnpm": {
119
- "onlyBuiltDependencies": [
120
- "esbuild",
121
- "puppeteer"
122
- ]
123
- },
124
- "packageManager": "pnpm@10.28.2"
125
- }
117
+ "scripts": {
118
+ "test": "(tstest test/ --verbose --logfile)",
119
+ "typecheck": "tsbuild check",
120
+ "build": "(tsbuild tsfolders)",
121
+ "buildDocs": "(tsdoc)"
122
+ }
123
+ }
package/readme.hints.md CHANGED
@@ -10,6 +10,8 @@ The package is a **provider registry** built on the Vercel AI SDK (`ai` v6). The
10
10
  - Providers: anthropic, openai, google, groq, mistral, xai, perplexity, ollama
11
11
  - Anthropic prompt caching via `wrapLanguageModel` middleware (enabled by default)
12
12
  - Custom Ollama provider implementing `LanguageModelV3` directly (for think, num_ctx support)
13
+ - OpenAI ChatGPT/Codex device-code auth in `smartai.auth.openai.ts`; `openAiChatGptAuth` routes OpenAI models to the ChatGPT Codex backend
14
+ - Node-only local auth source helpers live in `ts_openai_chatgpt_auth/` and support SmartAI, OpenCode, and Codex auth file formats
13
15
 
14
16
  ### Subpath Exports
15
17
  - `@push.rocks/smartai/vision` — `analyzeImage()` using `generateText` with image content
@@ -43,6 +45,7 @@ The package is a **provider registry** built on the Vercel AI SDK (`ai` v6). The
43
45
  - `qenv.getEnvVarOnDemand()` returns a Promise — must be awaited in tests
44
46
  - OpenAI reasoning options belong in AI SDK `providerOptions`, not model construction options
45
47
  - SmartAI accepts OpenAI model IDs as plain strings, including `gpt-5.5`
48
+ - ChatGPT-authenticated OpenAI model calls use `https://chatgpt.com/backend-api/codex` plus bearer access token and `ChatGPT-Account-ID`, not `https://api.openai.com/v1`
46
49
 
47
50
  ## Testing
48
51