@ai-sdk/harness-opencode 1.0.92 → 1.0.94
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/dist/bridge/index.mjs +2 -1
- package/dist/bridge/index.mjs.map +1 -1
- package/dist/index.d.ts +4 -32
- package/dist/index.js +29 -76
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/bridge/index.ts +1 -0
- package/src/index.ts +1 -4
- package/src/opencode-auth.ts +36 -129
- package/src/opencode-harness.ts +2 -2
package/src/opencode-auth.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import type {
|
|
2
|
+
HarnessV1Authentication,
|
|
2
3
|
HarnessV1RequestTransformation,
|
|
3
4
|
HarnessV1RequestTransformationSources,
|
|
4
5
|
} from '@ai-sdk/harness';
|
|
5
6
|
import {
|
|
6
7
|
createCredentialRequestTransformation,
|
|
7
8
|
getAiGatewayAuthFromEnv,
|
|
9
|
+
isHarnessAuthenticationEnvironment,
|
|
8
10
|
} from '@ai-sdk/harness/utils';
|
|
9
11
|
|
|
10
12
|
export const OPENCODE_CREDENTIAL_ENVIRONMENT_VARIABLES = [
|
|
@@ -108,40 +110,9 @@ export type OpenCodeResolvedAuthenticationMode =
|
|
|
108
110
|
| 'openai'
|
|
109
111
|
| 'ai-gateway';
|
|
110
112
|
|
|
111
|
-
export type OpenCodeAuthenticationMode =
|
|
112
|
-
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* @deprecated Passing an object to auth options is deprecated. Use an `OpenCodeAuthenticationMode` string value ("auto" | "anthropic" | "openai" | "ai-gateway") instead, and pass credentials via environment variables.
|
|
117
|
-
*/
|
|
118
|
-
export type LegacyOpenCodeAuthOptions = {
|
|
119
|
-
readonly gateway?: {
|
|
120
|
-
readonly apiKey?: string;
|
|
121
|
-
readonly baseUrl?: string;
|
|
122
|
-
};
|
|
123
|
-
readonly anthropic?: {
|
|
124
|
-
readonly apiKey?: string;
|
|
125
|
-
readonly authToken?: string;
|
|
126
|
-
readonly baseUrl?: string;
|
|
127
|
-
};
|
|
128
|
-
readonly openai?: {
|
|
129
|
-
readonly apiKey?: string;
|
|
130
|
-
readonly baseUrl?: string;
|
|
131
|
-
readonly organization?: string;
|
|
132
|
-
readonly project?: string;
|
|
133
|
-
};
|
|
134
|
-
readonly openaiCompatible?: {
|
|
135
|
-
readonly apiKey?: string;
|
|
136
|
-
readonly baseUrl?: string;
|
|
137
|
-
readonly name?: string;
|
|
138
|
-
readonly queryParams?: Record<string, string>;
|
|
139
|
-
};
|
|
140
|
-
};
|
|
141
|
-
|
|
142
|
-
export type OpenCodeAuthOptions =
|
|
143
|
-
| OpenCodeAuthenticationMode
|
|
144
|
-
| LegacyOpenCodeAuthOptions;
|
|
113
|
+
export type OpenCodeAuthenticationMode = HarnessV1Authentication<
|
|
114
|
+
'anthropic' | 'openai'
|
|
115
|
+
>;
|
|
145
116
|
|
|
146
117
|
export function resolveOpenCodeProvider({
|
|
147
118
|
model,
|
|
@@ -188,37 +159,30 @@ export function resolveOpenCodeEnv({
|
|
|
188
159
|
provider,
|
|
189
160
|
processEnv = process.env,
|
|
190
161
|
}: {
|
|
191
|
-
auth:
|
|
162
|
+
auth: OpenCodeAuthenticationMode | undefined;
|
|
192
163
|
model?: string;
|
|
193
164
|
provider?: string;
|
|
194
165
|
processEnv?: Record<string, string | undefined>;
|
|
195
166
|
}): Record<string, string> {
|
|
196
|
-
const
|
|
167
|
+
const suppliedEnvironment = isHarnessAuthenticationEnvironment(auth);
|
|
168
|
+
const authenticationEnvironment = suppliedEnvironment ? auth : processEnv;
|
|
197
169
|
const selectedProvider = resolveOpenCodeProvider({ model, provider });
|
|
198
|
-
if (
|
|
199
|
-
return
|
|
170
|
+
if (selectedProvider === 'openai' && auth === 'openai') {
|
|
171
|
+
return pickOpenAI({ processEnv: authenticationEnvironment });
|
|
200
172
|
}
|
|
201
|
-
if (selectedProvider === '
|
|
202
|
-
|
|
203
|
-
return pickOpenAI({ explicit: normalizedAuth.openai, processEnv });
|
|
204
|
-
}
|
|
205
|
-
} else if (normalizedAuth?.anthropic) {
|
|
206
|
-
return pickAnthropic({ explicit: normalizedAuth.anthropic, processEnv });
|
|
173
|
+
if (selectedProvider === 'anthropic' && auth === 'anthropic') {
|
|
174
|
+
return pickAnthropic({ processEnv: authenticationEnvironment });
|
|
207
175
|
}
|
|
208
176
|
|
|
209
|
-
const gatewayAuthFromEnv = getAiGatewayAuthFromEnv({
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
});
|
|
215
|
-
}
|
|
216
|
-
if (gatewayAuthFromEnv.apiKey) {
|
|
217
|
-
return pickGateway({ explicit: {}, gatewayAuthFromEnv });
|
|
177
|
+
const gatewayAuthFromEnv = getAiGatewayAuthFromEnv({
|
|
178
|
+
env: authenticationEnvironment,
|
|
179
|
+
});
|
|
180
|
+
if (auth === 'ai-gateway' || gatewayAuthFromEnv.apiKey) {
|
|
181
|
+
return pickGateway({ gatewayAuthFromEnv });
|
|
218
182
|
}
|
|
219
183
|
return selectedProvider === 'openai'
|
|
220
|
-
? pickOpenAI({ processEnv })
|
|
221
|
-
: pickAnthropic({ processEnv });
|
|
184
|
+
? pickOpenAI({ processEnv: authenticationEnvironment })
|
|
185
|
+
: pickAnthropic({ processEnv: authenticationEnvironment });
|
|
222
186
|
}
|
|
223
187
|
|
|
224
188
|
export function resolveOpenCodeAuthenticationMode({
|
|
@@ -227,29 +191,24 @@ export function resolveOpenCodeAuthenticationMode({
|
|
|
227
191
|
provider,
|
|
228
192
|
processEnv = process.env,
|
|
229
193
|
}: {
|
|
230
|
-
auth:
|
|
194
|
+
auth: OpenCodeAuthenticationMode | undefined;
|
|
231
195
|
model?: string;
|
|
232
196
|
provider?: string;
|
|
233
197
|
processEnv?: Record<string, string | undefined>;
|
|
234
198
|
}): OpenCodeResolvedAuthenticationMode {
|
|
235
|
-
if (
|
|
236
|
-
return
|
|
199
|
+
if (isHarnessAuthenticationEnvironment(auth)) {
|
|
200
|
+
return getAiGatewayAuthFromEnv({ env: auth }).apiKey
|
|
201
|
+
? 'ai-gateway'
|
|
202
|
+
: resolveOpenCodeProvider({ model, provider });
|
|
237
203
|
}
|
|
238
|
-
|
|
239
204
|
const selectedProvider = resolveOpenCodeProvider({ model, provider });
|
|
240
|
-
if (
|
|
241
|
-
selectedProvider === 'openai' &&
|
|
242
|
-
(auth === 'openai' || (typeof auth !== 'string' && auth?.openai))
|
|
243
|
-
) {
|
|
205
|
+
if (selectedProvider === 'openai' && auth === 'openai') {
|
|
244
206
|
return 'openai';
|
|
245
207
|
}
|
|
246
|
-
if (
|
|
247
|
-
selectedProvider === 'anthropic' &&
|
|
248
|
-
(auth === 'anthropic' || (typeof auth !== 'string' && auth?.anthropic))
|
|
249
|
-
) {
|
|
208
|
+
if (selectedProvider === 'anthropic' && auth === 'anthropic') {
|
|
250
209
|
return 'anthropic';
|
|
251
210
|
}
|
|
252
|
-
if (auth === 'ai-gateway'
|
|
211
|
+
if (auth === 'ai-gateway') {
|
|
253
212
|
return 'ai-gateway';
|
|
254
213
|
}
|
|
255
214
|
if (getAiGatewayAuthFromEnv({ env: processEnv }).apiKey) {
|
|
@@ -258,99 +217,47 @@ export function resolveOpenCodeAuthenticationMode({
|
|
|
258
217
|
return selectedProvider;
|
|
259
218
|
}
|
|
260
219
|
|
|
261
|
-
function normalizeOpenCodeAuthToLegacyAuth(
|
|
262
|
-
auth: OpenCodeAuthOptions | undefined,
|
|
263
|
-
): LegacyOpenCodeAuthOptions | undefined {
|
|
264
|
-
if (auth == null || auth === 'auto') {
|
|
265
|
-
return undefined;
|
|
266
|
-
}
|
|
267
|
-
if (typeof auth === 'string') {
|
|
268
|
-
switch (auth) {
|
|
269
|
-
case 'anthropic':
|
|
270
|
-
return { anthropic: {} };
|
|
271
|
-
case 'openai':
|
|
272
|
-
return { openai: {} };
|
|
273
|
-
case 'ai-gateway':
|
|
274
|
-
return { gateway: {} };
|
|
275
|
-
default:
|
|
276
|
-
return undefined;
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
console.warn(
|
|
281
|
-
'[opencode] Passing an object to auth options is deprecated. Use a string mode ("auto" | "anthropic" | "openai" | "ai-gateway") instead, and pass credentials via environment variables.',
|
|
282
|
-
);
|
|
283
|
-
return auth;
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
function pickOpenAICompatible(
|
|
287
|
-
explicit: NonNullable<LegacyOpenCodeAuthOptions['openaiCompatible']>,
|
|
288
|
-
processEnv: Record<string, string | undefined>,
|
|
289
|
-
): Record<string, string> {
|
|
290
|
-
const env: Record<string, string> = {};
|
|
291
|
-
const apiKey = explicit.apiKey ?? processEnv.OPENAI_API_KEY;
|
|
292
|
-
if (apiKey) env.OPENAI_API_KEY = apiKey;
|
|
293
|
-
const baseUrl = explicit.baseUrl ?? processEnv.OPENAI_BASE_URL;
|
|
294
|
-
if (baseUrl) env.OPENAI_BASE_URL = baseUrl;
|
|
295
|
-
const name = explicit.name ?? processEnv.OPENAI_NAME;
|
|
296
|
-
if (name) env.OPENAI_NAME = name;
|
|
297
|
-
if (explicit.queryParams && Object.keys(explicit.queryParams).length > 0) {
|
|
298
|
-
env.OPENAI_QUERY_PARAMS_JSON = JSON.stringify(explicit.queryParams);
|
|
299
|
-
} else if (processEnv.OPENAI_QUERY_PARAMS_JSON) {
|
|
300
|
-
env.OPENAI_QUERY_PARAMS_JSON = processEnv.OPENAI_QUERY_PARAMS_JSON;
|
|
301
|
-
}
|
|
302
|
-
return env;
|
|
303
|
-
}
|
|
304
|
-
|
|
305
220
|
function pickOpenAI({
|
|
306
|
-
explicit,
|
|
307
221
|
processEnv,
|
|
308
222
|
}: {
|
|
309
|
-
explicit?: NonNullable<LegacyOpenCodeAuthOptions['openai']>;
|
|
310
223
|
processEnv: Record<string, string | undefined>;
|
|
311
224
|
}): Record<string, string> {
|
|
312
225
|
const env: Record<string, string> = {};
|
|
313
|
-
const apiKey =
|
|
226
|
+
const apiKey = processEnv.OPENAI_API_KEY;
|
|
314
227
|
if (apiKey) env.OPENAI_API_KEY = apiKey;
|
|
315
|
-
const baseUrl =
|
|
228
|
+
const baseUrl = processEnv.OPENAI_BASE_URL;
|
|
316
229
|
if (baseUrl) env.OPENAI_BASE_URL = baseUrl;
|
|
317
|
-
const organization =
|
|
230
|
+
const organization = processEnv.OPENAI_ORGANIZATION;
|
|
318
231
|
if (organization) env.OPENAI_ORGANIZATION = organization;
|
|
319
|
-
const project =
|
|
232
|
+
const project = processEnv.OPENAI_PROJECT;
|
|
320
233
|
if (project) env.OPENAI_PROJECT = project;
|
|
321
234
|
return env;
|
|
322
235
|
}
|
|
323
236
|
|
|
324
237
|
function pickAnthropic({
|
|
325
|
-
explicit,
|
|
326
238
|
processEnv,
|
|
327
239
|
}: {
|
|
328
|
-
explicit?: NonNullable<LegacyOpenCodeAuthOptions['anthropic']>;
|
|
329
240
|
processEnv: Record<string, string | undefined>;
|
|
330
241
|
}): Record<string, string> {
|
|
331
242
|
const env: Record<string, string> = {};
|
|
332
|
-
const apiKey =
|
|
243
|
+
const apiKey = processEnv.ANTHROPIC_API_KEY;
|
|
333
244
|
if (apiKey) env.ANTHROPIC_API_KEY = apiKey;
|
|
334
|
-
const authToken =
|
|
245
|
+
const authToken = processEnv.ANTHROPIC_AUTH_TOKEN;
|
|
335
246
|
if (authToken) env.ANTHROPIC_AUTH_TOKEN = authToken;
|
|
336
|
-
const baseUrl =
|
|
247
|
+
const baseUrl = processEnv.ANTHROPIC_BASE_URL;
|
|
337
248
|
if (baseUrl) env.ANTHROPIC_BASE_URL = baseUrl;
|
|
338
249
|
return env;
|
|
339
250
|
}
|
|
340
251
|
|
|
341
252
|
function pickGateway({
|
|
342
|
-
explicit,
|
|
343
253
|
gatewayAuthFromEnv,
|
|
344
254
|
}: {
|
|
345
|
-
explicit: NonNullable<LegacyOpenCodeAuthOptions['gateway']>;
|
|
346
255
|
gatewayAuthFromEnv: ReturnType<typeof getAiGatewayAuthFromEnv>;
|
|
347
256
|
}): Record<string, string> {
|
|
348
257
|
const env: Record<string, string> = {};
|
|
349
|
-
const apiKey =
|
|
258
|
+
const apiKey = gatewayAuthFromEnv.apiKey;
|
|
350
259
|
if (apiKey) env.AI_GATEWAY_API_KEY = apiKey;
|
|
351
|
-
const baseUrl = toOpenCodeGatewayBaseUrl(
|
|
352
|
-
explicit.baseUrl ?? gatewayAuthFromEnv.baseUrl,
|
|
353
|
-
);
|
|
260
|
+
const baseUrl = toOpenCodeGatewayBaseUrl(gatewayAuthFromEnv.baseUrl);
|
|
354
261
|
env.AI_GATEWAY_BASE_URL = baseUrl;
|
|
355
262
|
return env;
|
|
356
263
|
}
|
package/src/opencode-harness.ts
CHANGED
|
@@ -57,7 +57,7 @@ import {
|
|
|
57
57
|
resolveOpenCodeAuthenticationMode,
|
|
58
58
|
resolveOpenCodeEnv,
|
|
59
59
|
splitOpenCodeModel,
|
|
60
|
-
type
|
|
60
|
+
type OpenCodeAuthenticationMode,
|
|
61
61
|
} from './opencode-auth';
|
|
62
62
|
import {
|
|
63
63
|
outboundMessageSchema,
|
|
@@ -79,7 +79,7 @@ type WriteSkillsResult = {
|
|
|
79
79
|
const OPENCODE_CLIENT_APP = `ai-sdk/harness-opencode/${VERSION}`;
|
|
80
80
|
|
|
81
81
|
export type OpenCodeHarnessSettings = {
|
|
82
|
-
readonly auth?:
|
|
82
|
+
readonly auth?: OpenCodeAuthenticationMode;
|
|
83
83
|
/**
|
|
84
84
|
* Customizes each credential value before it is forwarded into a sandbox
|
|
85
85
|
* process. This does not restrict which credentials the harness adapter can
|