@ai-sdk/harness-opencode 0.0.0-d3900c59-20260626174016
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 +53 -0
- package/LICENSE +13 -0
- package/README.md +6 -0
- package/dist/bridge/host-tool-mcp.mjs +103 -0
- package/dist/bridge/host-tool-mcp.mjs.map +1 -0
- package/dist/bridge/index.mjs +1984 -0
- package/dist/bridge/index.mjs.map +1 -0
- package/dist/bridge/package.json +13 -0
- package/dist/bridge/pnpm-lock.yaml +933 -0
- package/dist/index.d.ts +175 -0
- package/dist/index.js +1051 -0
- package/dist/index.js.map +1 -0
- package/package.json +77 -0
- package/src/bridge/host-tool-mcp.ts +136 -0
- package/src/bridge/index.ts +1846 -0
- package/src/bridge/opencode-events.ts +88 -0
- package/src/bridge/opencode-path.ts +17 -0
- package/src/bridge/opencode-usage.ts +156 -0
- package/src/bridge/package.json +13 -0
- package/src/bridge/pnpm-lock.yaml +933 -0
- package/src/index.ts +11 -0
- package/src/opencode-auth.ts +175 -0
- package/src/opencode-bridge-protocol.ts +29 -0
- package/src/opencode-harness.ts +1103 -0
package/src/index.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { createOpenCode } from './opencode-harness';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Default `openCode` harness instance with no overrides. Equivalent to
|
|
5
|
+
* `createOpenCode()`.
|
|
6
|
+
*/
|
|
7
|
+
export const openCode = createOpenCode();
|
|
8
|
+
|
|
9
|
+
export { createOpenCode } from './opencode-harness';
|
|
10
|
+
export type { OpenCodeHarnessSettings } from './opencode-harness';
|
|
11
|
+
export type { OpenCodeAuthOptions } from './opencode-auth';
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { getAiGatewayAuthFromEnv } from '@ai-sdk/harness/utils';
|
|
2
|
+
|
|
3
|
+
export type OpenCodeAuthOptions = {
|
|
4
|
+
readonly gateway?: {
|
|
5
|
+
readonly apiKey?: string;
|
|
6
|
+
readonly baseUrl?: string;
|
|
7
|
+
};
|
|
8
|
+
readonly anthropic?: {
|
|
9
|
+
readonly apiKey?: string;
|
|
10
|
+
readonly authToken?: string;
|
|
11
|
+
readonly baseUrl?: string;
|
|
12
|
+
};
|
|
13
|
+
readonly openai?: {
|
|
14
|
+
readonly apiKey?: string;
|
|
15
|
+
readonly baseUrl?: string;
|
|
16
|
+
readonly organization?: string;
|
|
17
|
+
readonly project?: string;
|
|
18
|
+
};
|
|
19
|
+
readonly openaiCompatible?: {
|
|
20
|
+
readonly apiKey?: string;
|
|
21
|
+
readonly baseUrl?: string;
|
|
22
|
+
readonly name?: string;
|
|
23
|
+
readonly queryParams?: Record<string, string>;
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export function resolveOpenCodeProvider({
|
|
28
|
+
model,
|
|
29
|
+
provider,
|
|
30
|
+
}: {
|
|
31
|
+
model?: string;
|
|
32
|
+
provider?: string;
|
|
33
|
+
}): 'anthropic' | 'openai' {
|
|
34
|
+
if (provider === 'anthropic' || provider === 'openai') {
|
|
35
|
+
return provider;
|
|
36
|
+
}
|
|
37
|
+
if (model?.includes('/')) {
|
|
38
|
+
const [modelProvider] = model.split('/');
|
|
39
|
+
if (modelProvider === 'anthropic' || modelProvider === 'openai') {
|
|
40
|
+
return modelProvider;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return 'anthropic';
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function splitOpenCodeModel(
|
|
47
|
+
model: string | undefined,
|
|
48
|
+
provider: string | undefined,
|
|
49
|
+
): { providerID?: string; modelID?: string; model?: string } {
|
|
50
|
+
if (!model) return {};
|
|
51
|
+
if (model.includes('/')) {
|
|
52
|
+
const [providerID, ...rest] = model.split('/');
|
|
53
|
+
return {
|
|
54
|
+
providerID,
|
|
55
|
+
modelID: rest.join('/'),
|
|
56
|
+
model,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
providerID: provider,
|
|
61
|
+
modelID: model,
|
|
62
|
+
model: provider ? `${provider}/${model}` : model,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function resolveOpenCodeEnv({
|
|
67
|
+
auth,
|
|
68
|
+
model,
|
|
69
|
+
provider,
|
|
70
|
+
processEnv = process.env,
|
|
71
|
+
}: {
|
|
72
|
+
auth: OpenCodeAuthOptions | undefined;
|
|
73
|
+
model?: string;
|
|
74
|
+
provider?: string;
|
|
75
|
+
processEnv?: Record<string, string | undefined>;
|
|
76
|
+
}): Record<string, string> {
|
|
77
|
+
const selectedProvider = resolveOpenCodeProvider({ model, provider });
|
|
78
|
+
if (auth?.openaiCompatible) {
|
|
79
|
+
return pickOpenAICompatible(auth.openaiCompatible, processEnv);
|
|
80
|
+
}
|
|
81
|
+
if (selectedProvider === 'openai') {
|
|
82
|
+
if (auth?.openai) {
|
|
83
|
+
return pickOpenAI({ explicit: auth.openai, processEnv });
|
|
84
|
+
}
|
|
85
|
+
} else if (auth?.anthropic) {
|
|
86
|
+
return pickAnthropic({ explicit: auth.anthropic, processEnv });
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const gatewayAuthFromEnv = getAiGatewayAuthFromEnv({ env: processEnv });
|
|
90
|
+
if (auth?.gateway) {
|
|
91
|
+
return pickGateway({ explicit: auth.gateway, gatewayAuthFromEnv });
|
|
92
|
+
}
|
|
93
|
+
if (gatewayAuthFromEnv.apiKey) {
|
|
94
|
+
return pickGateway({ explicit: {}, gatewayAuthFromEnv });
|
|
95
|
+
}
|
|
96
|
+
return selectedProvider === 'openai'
|
|
97
|
+
? pickOpenAI({ processEnv })
|
|
98
|
+
: pickAnthropic({ processEnv });
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function pickOpenAICompatible(
|
|
102
|
+
explicit: NonNullable<OpenCodeAuthOptions['openaiCompatible']>,
|
|
103
|
+
processEnv: Record<string, string | undefined>,
|
|
104
|
+
): Record<string, string> {
|
|
105
|
+
const env: Record<string, string> = {};
|
|
106
|
+
const apiKey = explicit.apiKey ?? processEnv.OPENAI_API_KEY;
|
|
107
|
+
if (apiKey) env.OPENAI_API_KEY = apiKey;
|
|
108
|
+
const baseUrl = explicit.baseUrl ?? processEnv.OPENAI_BASE_URL;
|
|
109
|
+
if (baseUrl) env.OPENAI_BASE_URL = baseUrl;
|
|
110
|
+
const name = explicit.name ?? processEnv.OPENAI_NAME;
|
|
111
|
+
if (name) env.OPENAI_NAME = name;
|
|
112
|
+
if (explicit.queryParams && Object.keys(explicit.queryParams).length > 0) {
|
|
113
|
+
env.OPENAI_QUERY_PARAMS_JSON = JSON.stringify(explicit.queryParams);
|
|
114
|
+
} else if (processEnv.OPENAI_QUERY_PARAMS_JSON) {
|
|
115
|
+
env.OPENAI_QUERY_PARAMS_JSON = processEnv.OPENAI_QUERY_PARAMS_JSON;
|
|
116
|
+
}
|
|
117
|
+
return env;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function pickOpenAI({
|
|
121
|
+
explicit,
|
|
122
|
+
processEnv,
|
|
123
|
+
}: {
|
|
124
|
+
explicit?: NonNullable<OpenCodeAuthOptions['openai']>;
|
|
125
|
+
processEnv: Record<string, string | undefined>;
|
|
126
|
+
}): Record<string, string> {
|
|
127
|
+
const env: Record<string, string> = {};
|
|
128
|
+
const apiKey = explicit?.apiKey ?? processEnv.OPENAI_API_KEY;
|
|
129
|
+
if (apiKey) env.OPENAI_API_KEY = apiKey;
|
|
130
|
+
const baseUrl = explicit?.baseUrl ?? processEnv.OPENAI_BASE_URL;
|
|
131
|
+
if (baseUrl) env.OPENAI_BASE_URL = baseUrl;
|
|
132
|
+
const organization = explicit?.organization ?? processEnv.OPENAI_ORGANIZATION;
|
|
133
|
+
if (organization) env.OPENAI_ORGANIZATION = organization;
|
|
134
|
+
const project = explicit?.project ?? processEnv.OPENAI_PROJECT;
|
|
135
|
+
if (project) env.OPENAI_PROJECT = project;
|
|
136
|
+
return env;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function pickAnthropic({
|
|
140
|
+
explicit,
|
|
141
|
+
processEnv,
|
|
142
|
+
}: {
|
|
143
|
+
explicit?: NonNullable<OpenCodeAuthOptions['anthropic']>;
|
|
144
|
+
processEnv: Record<string, string | undefined>;
|
|
145
|
+
}): Record<string, string> {
|
|
146
|
+
const env: Record<string, string> = {};
|
|
147
|
+
const apiKey = explicit?.apiKey ?? processEnv.ANTHROPIC_API_KEY;
|
|
148
|
+
if (apiKey) env.ANTHROPIC_API_KEY = apiKey;
|
|
149
|
+
const authToken = explicit?.authToken ?? processEnv.ANTHROPIC_AUTH_TOKEN;
|
|
150
|
+
if (authToken) env.ANTHROPIC_AUTH_TOKEN = authToken;
|
|
151
|
+
const baseUrl = explicit?.baseUrl ?? processEnv.ANTHROPIC_BASE_URL;
|
|
152
|
+
if (baseUrl) env.ANTHROPIC_BASE_URL = baseUrl;
|
|
153
|
+
return env;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function pickGateway({
|
|
157
|
+
explicit,
|
|
158
|
+
gatewayAuthFromEnv,
|
|
159
|
+
}: {
|
|
160
|
+
explicit: NonNullable<OpenCodeAuthOptions['gateway']>;
|
|
161
|
+
gatewayAuthFromEnv: ReturnType<typeof getAiGatewayAuthFromEnv>;
|
|
162
|
+
}): Record<string, string> {
|
|
163
|
+
const env: Record<string, string> = {};
|
|
164
|
+
const apiKey = explicit.apiKey ?? gatewayAuthFromEnv.apiKey;
|
|
165
|
+
if (apiKey) env.AI_GATEWAY_API_KEY = apiKey;
|
|
166
|
+
env.AI_GATEWAY_BASE_URL = toOpenCodeGatewayBaseUrl(
|
|
167
|
+
explicit.baseUrl ?? gatewayAuthFromEnv.baseUrl,
|
|
168
|
+
);
|
|
169
|
+
return env;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export function toOpenCodeGatewayBaseUrl(baseUrl: string): string {
|
|
173
|
+
const trimmed = baseUrl.replace(/\/+$/, '');
|
|
174
|
+
return trimmed.endsWith('/v1') ? trimmed : `${trimmed}/v1`;
|
|
175
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import {
|
|
2
|
+
harnessV1BridgeInboundCommandSchemas,
|
|
3
|
+
harnessV1BridgeOutboundMessageSchema,
|
|
4
|
+
harnessV1BridgeReadySchema,
|
|
5
|
+
harnessV1BridgeStartBaseSchema,
|
|
6
|
+
} from '@ai-sdk/harness';
|
|
7
|
+
import { z } from 'zod/v4';
|
|
8
|
+
|
|
9
|
+
export const outboundMessageSchema = harnessV1BridgeOutboundMessageSchema;
|
|
10
|
+
export type OutboundMessage = z.infer<typeof outboundMessageSchema>;
|
|
11
|
+
|
|
12
|
+
export const startMessageSchema = harnessV1BridgeStartBaseSchema.extend({
|
|
13
|
+
operation: z.enum(['prompt', 'compact']).optional(),
|
|
14
|
+
provider: z.string().optional(),
|
|
15
|
+
variant: z.string().optional(),
|
|
16
|
+
instructions: z.string().optional(),
|
|
17
|
+
resumeSessionId: z.string().optional(),
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
export type StartMessage = z.infer<typeof startMessageSchema>;
|
|
21
|
+
|
|
22
|
+
export const inboundMessageSchema = z.discriminatedUnion('type', [
|
|
23
|
+
startMessageSchema,
|
|
24
|
+
...harnessV1BridgeInboundCommandSchemas,
|
|
25
|
+
]);
|
|
26
|
+
export type InboundMessage = z.infer<typeof inboundMessageSchema>;
|
|
27
|
+
|
|
28
|
+
export const bridgeReadySchema = harnessV1BridgeReadySchema;
|
|
29
|
+
export type BridgeReady = z.infer<typeof bridgeReadySchema>;
|