@agi-cli/sdk 0.1.169 → 0.1.170

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.
@@ -0,0 +1,40 @@
1
+ import { createOpenAICompatible } from '@ai-sdk/openai-compatible';
2
+ import type { OAuth } from '../../types/src/index.ts';
3
+
4
+ const COPILOT_BASE_URL = 'https://api.githubcopilot.com';
5
+
6
+ export type CopilotOAuthConfig = {
7
+ oauth: OAuth;
8
+ };
9
+
10
+ export function createCopilotFetch(config: CopilotOAuthConfig): typeof fetch {
11
+ return async (
12
+ input: string | URL | Request,
13
+ init?: RequestInit,
14
+ ): Promise<Response> => {
15
+ const headers = new Headers(init?.headers);
16
+ headers.delete('Authorization');
17
+ headers.delete('authorization');
18
+ headers.set('Authorization', `Bearer ${config.oauth.refresh}`);
19
+ headers.set('Openai-Intent', 'conversation-edits');
20
+ headers.set('User-Agent', 'agi-cli');
21
+
22
+ return fetch(input, {
23
+ ...init,
24
+ headers,
25
+ });
26
+ };
27
+ }
28
+
29
+ export function createCopilotModel(model: string, config: CopilotOAuthConfig) {
30
+ const customFetch = createCopilotFetch(config);
31
+
32
+ const provider = createOpenAICompatible({
33
+ name: 'github-copilot',
34
+ baseURL: COPILOT_BASE_URL,
35
+ apiKey: 'copilot-oauth',
36
+ fetch: customFetch,
37
+ });
38
+
39
+ return provider.chatModel(model);
40
+ }
@@ -6,6 +6,7 @@ const ENV_VARS: Record<ProviderId, string> = {
6
6
  google: 'GOOGLE_GENERATIVE_AI_API_KEY',
7
7
  openrouter: 'OPENROUTER_API_KEY',
8
8
  opencode: 'OPENCODE_API_KEY',
9
+ copilot: 'GITHUB_TOKEN',
9
10
  setu: 'SETU_PRIVATE_KEY',
10
11
  zai: 'ZAI_API_KEY',
11
12
  'zai-coding': 'ZAI_API_KEY',
@@ -71,3 +71,5 @@ export { createOpencodeModel } from './opencode-client.ts';
71
71
  export type { OpencodeProviderConfig } from './opencode-client.ts';
72
72
  export { createMoonshotModel } from './moonshot-client.ts';
73
73
  export type { MoonshotProviderConfig } from './moonshot-client.ts';
74
+ export { createCopilotFetch, createCopilotModel } from './copilot-client.ts';
75
+ export type { CopilotOAuthConfig } from './copilot-client.ts';
@@ -3,25 +3,18 @@ import type { OAuth } from '../../types/src/index.ts';
3
3
  import { refreshOpenAIToken } from '../../auth/src/openai-oauth.ts';
4
4
  import { setAuth, getAuth } from '../../auth/src/index.ts';
5
5
 
6
- const CHATGPT_BACKEND_URL = 'https://chatgpt.com/backend-api';
7
- const OPENAI_API_URL = 'https://api.openai.com/v1';
8
-
9
- const DEFAULT_INSTRUCTIONS = `You are a helpful coding assistant. Be concise and direct.`;
6
+ const CODEX_API_ENDPOINT = 'https://chatgpt.com/backend-api/codex/responses';
10
7
 
11
8
  export type OpenAIOAuthConfig = {
12
9
  oauth: OAuth;
13
10
  projectRoot?: string;
14
- instructions?: string;
15
- reasoningEffort?: 'none' | 'low' | 'medium' | 'high' | 'xhigh';
16
- reasoningSummary?: 'auto' | 'detailed';
17
11
  };
18
12
 
19
13
  async function ensureValidToken(
20
14
  oauth: OAuth,
21
15
  projectRoot?: string,
22
16
  ): Promise<{ access: string; accountId?: string }> {
23
- const bufferMs = 5 * 60 * 1000;
24
- if (oauth.expires > Date.now() + bufferMs) {
17
+ if (oauth.access && oauth.expires > Date.now()) {
25
18
  return { access: oauth.access, accountId: oauth.accountId };
26
19
  }
27
20
 
@@ -42,78 +35,19 @@ async function ensureValidToken(
42
35
  }
43
36
  }
44
37
 
45
- function stripIdsFromInput(input: unknown): unknown {
46
- if (Array.isArray(input)) {
47
- const filtered = input.filter((item) => {
48
- if (item && typeof item === 'object' && 'type' in item) {
49
- if (item.type === 'item_reference') return false;
50
- }
51
- return true;
52
- });
53
-
54
- const validCallIds = new Set<string>();
55
- for (const item of filtered) {
56
- if (
57
- item &&
58
- typeof item === 'object' &&
59
- 'type' in item &&
60
- item.type === 'function_call' &&
61
- 'call_id' in item &&
62
- typeof item.call_id === 'string'
63
- ) {
64
- validCallIds.add(item.call_id);
65
- }
66
- }
67
-
68
- return filtered
69
- .filter((item) => {
70
- if (
71
- item &&
72
- typeof item === 'object' &&
73
- 'type' in item &&
74
- item.type === 'function_call_output' &&
75
- 'call_id' in item &&
76
- typeof item.call_id === 'string'
77
- ) {
78
- return validCallIds.has(item.call_id);
79
- }
80
- return true;
81
- })
82
- .map((item) => {
83
- if (item && typeof item === 'object') {
84
- const result: Record<string, unknown> = {};
85
- for (const [key, value] of Object.entries(item)) {
86
- if (key === 'id') continue;
87
- result[key] = stripIdsFromInput(value);
88
- }
89
- return result;
90
- }
91
- return item;
92
- });
93
- }
94
- if (input && typeof input === 'object') {
95
- const result: Record<string, unknown> = {};
96
- for (const [key, value] of Object.entries(input)) {
97
- if (key === 'id') continue;
98
- result[key] = stripIdsFromInput(value);
99
- }
100
- return result;
101
- }
102
- return input;
103
- }
104
-
105
38
  function rewriteUrl(url: string): string {
106
- if (url.includes('/responses')) {
107
- return url
108
- .replace(OPENAI_API_URL, CHATGPT_BACKEND_URL)
109
- .replace('/responses', '/codex/responses');
39
+ const parsed = new URL(url);
40
+ if (
41
+ parsed.pathname.includes('/v1/responses') ||
42
+ parsed.pathname.includes('/chat/completions')
43
+ ) {
44
+ return CODEX_API_ENDPOINT;
110
45
  }
111
- return url.replace(OPENAI_API_URL, CHATGPT_BACKEND_URL);
46
+ return url;
112
47
  }
113
48
 
114
49
  export function createOpenAIOAuthFetch(config: OpenAIOAuthConfig) {
115
50
  let currentOAuth = config.oauth;
116
- const instructions = config.instructions || DEFAULT_INSTRUCTIONS;
117
51
 
118
52
  const customFetch = async (
119
53
  input: Parameters<typeof fetch>[0],
@@ -132,57 +66,17 @@ export function createOpenAIOAuthFetch(config: OpenAIOAuthConfig) {
132
66
  : input.url;
133
67
  const targetUrl = rewriteUrl(originalUrl);
134
68
 
135
- let body = init?.body;
136
- if (body && typeof body === 'string') {
137
- try {
138
- const parsed = JSON.parse(body);
139
-
140
- parsed.store = false;
141
- // ChatGPT backend codex endpoint requires streaming
142
- parsed.stream = true;
143
- parsed.instructions = instructions;
144
-
145
- if (parsed.input) {
146
- parsed.input = stripIdsFromInput(parsed.input);
147
- }
148
-
149
- if (!parsed.include) {
150
- parsed.include = ['reasoning.encrypted_content'];
151
- } else if (
152
- Array.isArray(parsed.include) &&
153
- !parsed.include.includes('reasoning.encrypted_content')
154
- ) {
155
- parsed.include.push('reasoning.encrypted_content');
156
- }
157
-
158
- const existingReasoning = parsed.reasoning || {};
159
- parsed.reasoning = {
160
- effort:
161
- existingReasoning.effort || config.reasoningEffort || 'medium',
162
- summary:
163
- existingReasoning.summary || config.reasoningSummary || 'auto',
164
- };
165
-
166
- delete parsed.max_output_tokens;
167
- delete parsed.max_completion_tokens;
168
-
169
- body = JSON.stringify(parsed);
170
- } catch {}
171
- }
172
-
173
69
  const headers = new Headers(init?.headers);
174
- headers.delete('x-api-key');
175
- headers.set('Authorization', `Bearer ${accessToken}`);
176
- headers.set('OpenAI-Beta', 'responses=experimental');
177
- headers.set('originator', 'codex_cli_rs');
178
- headers.set('accept', 'text/event-stream');
70
+ headers.delete('Authorization');
71
+ headers.delete('authorization');
72
+ headers.set('authorization', `Bearer ${accessToken}`);
73
+ headers.set('originator', 'agi');
179
74
  if (accountId) {
180
- headers.set('chatgpt-account-id', accountId);
75
+ headers.set('ChatGPT-Account-Id', accountId);
181
76
  }
182
77
 
183
78
  const response = await fetch(targetUrl, {
184
79
  ...init,
185
- body,
186
80
  headers,
187
81
  });
188
82
 
@@ -207,9 +101,8 @@ export function createOpenAIOAuthModel(
207
101
 
208
102
  const provider = createOpenAI({
209
103
  apiKey: 'chatgpt-oauth',
210
- baseURL: CHATGPT_BACKEND_URL,
211
104
  fetch: customFetch,
212
105
  });
213
106
 
214
- return provider(model);
107
+ return provider.responses(model);
215
108
  }
@@ -88,6 +88,7 @@ const pricingTable: Record<ProviderName, PricingEntry[]> = {
88
88
  moonshot: [
89
89
  // Pricing from catalog entries; leave empty here
90
90
  ],
91
+ copilot: [],
91
92
  };
92
93
 
93
94
  function findPricing(
@@ -38,7 +38,7 @@ function simplifyPaymentError(errMsg: string): string {
38
38
  return short.length < errMsg.length ? `${short}...` : errMsg;
39
39
  }
40
40
 
41
- const DEFAULT_BASE_URL = 'https://setu.agi.nitish.sh';
41
+ const DEFAULT_BASE_URL = 'https://api.setu.nitish.sh';
42
42
  const DEFAULT_RPC_URL = 'https://api.mainnet-beta.solana.com';
43
43
  const DEFAULT_MAX_ATTEMPTS = 3;
44
44
  const DEFAULT_MAX_PAYMENT_ATTEMPTS = 20;
@@ -48,6 +48,7 @@ const PREFERRED_FAST_MODELS: Partial<Record<ProviderId, string[]>> = {
48
48
  'codex-mini-latest',
49
49
  ],
50
50
  zai: ['glm-4.5-flash', 'glm-4.5-air'],
51
+ copilot: ['gpt-4o-mini', 'gpt-4.1-nano', 'gpt-4.1-mini'],
51
52
  };
52
53
 
53
54
  export function getFastModel(provider: ProviderId): string | undefined {
@@ -150,6 +151,7 @@ export function getUnderlyingProviderKey(
150
151
  if (provider === 'openai') return 'openai';
151
152
  if (provider === 'google') return 'google';
152
153
  if (provider === 'moonshot') return 'moonshot';
154
+ if (provider === 'copilot') return 'openai';
153
155
 
154
156
  const npm = getModelNpmBinding(provider, model);
155
157
  if (npm === '@ai-sdk/anthropic') return 'anthropic';
@@ -169,6 +171,7 @@ export function getModelFamily(
169
171
  if (provider === 'openai') return 'openai';
170
172
  if (provider === 'google') return 'google';
171
173
  if (provider === 'moonshot') return 'moonshot';
174
+ if (provider === 'copilot') return 'openai';
172
175
 
173
176
  // 2) For aggregate providers, infer from model ID patterns
174
177
  if (provider === 'openrouter' || provider === 'opencode') {
@@ -1,6 +1,7 @@
1
1
  // Provider types
2
2
  export type {
3
3
  ProviderId,
4
+ ProviderFamily,
4
5
  ModelInfo,
5
6
  ModelProviderBinding,
6
7
  ProviderCatalogEntry,
@@ -7,6 +7,7 @@ export type ProviderId =
7
7
  | 'google'
8
8
  | 'openrouter'
9
9
  | 'opencode'
10
+ | 'copilot'
10
11
  | 'setu'
11
12
  | 'zai'
12
13
  | 'zai-coding'