@contractspec/lib.ai-agent 1.45.6 → 1.46.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.
Files changed (77) hide show
  1. package/dist/_virtual/rolldown_runtime.js +8 -0
  2. package/dist/agent/index.d.ts +2 -2
  3. package/dist/agent/index.js +2 -2
  4. package/dist/agent/unified-agent.d.ts +131 -0
  5. package/dist/agent/unified-agent.d.ts.map +1 -0
  6. package/dist/agent/unified-agent.js +267 -0
  7. package/dist/agent/unified-agent.js.map +1 -0
  8. package/dist/exporters/claude-agent-exporter.d.ts +64 -0
  9. package/dist/exporters/claude-agent-exporter.d.ts.map +1 -0
  10. package/dist/exporters/claude-agent-exporter.js +210 -0
  11. package/dist/exporters/claude-agent-exporter.js.map +1 -0
  12. package/dist/exporters/index.d.ts +4 -0
  13. package/dist/exporters/index.js +4 -0
  14. package/dist/exporters/opencode-exporter.d.ts +64 -0
  15. package/dist/exporters/opencode-exporter.d.ts.map +1 -0
  16. package/dist/exporters/opencode-exporter.js +200 -0
  17. package/dist/exporters/opencode-exporter.js.map +1 -0
  18. package/dist/exporters/types.d.ts +239 -0
  19. package/dist/exporters/types.d.ts.map +1 -0
  20. package/dist/exporters/types.js +0 -0
  21. package/dist/index.d.ts +16 -3
  22. package/dist/index.js +11 -2
  23. package/dist/interop/index.d.ts +4 -0
  24. package/dist/interop/index.js +4 -0
  25. package/dist/interop/spec-consumer.d.ts +81 -0
  26. package/dist/interop/spec-consumer.d.ts.map +1 -0
  27. package/dist/interop/spec-consumer.js +287 -0
  28. package/dist/interop/spec-consumer.js.map +1 -0
  29. package/dist/interop/tool-consumer.d.ts +68 -0
  30. package/dist/interop/tool-consumer.d.ts.map +1 -0
  31. package/dist/interop/tool-consumer.js +220 -0
  32. package/dist/interop/tool-consumer.js.map +1 -0
  33. package/dist/interop/types.d.ts +262 -0
  34. package/dist/interop/types.d.ts.map +1 -0
  35. package/dist/interop/types.js +0 -0
  36. package/dist/providers/claude-agent-sdk/adapter.d.ts +58 -0
  37. package/dist/providers/claude-agent-sdk/adapter.d.ts.map +1 -0
  38. package/dist/providers/claude-agent-sdk/adapter.js +306 -0
  39. package/dist/providers/claude-agent-sdk/adapter.js.map +1 -0
  40. package/dist/providers/claude-agent-sdk/index.d.ts +4 -0
  41. package/dist/providers/claude-agent-sdk/index.js +5 -0
  42. package/dist/providers/claude-agent-sdk/session-bridge.d.ts +101 -0
  43. package/dist/providers/claude-agent-sdk/session-bridge.d.ts.map +1 -0
  44. package/dist/providers/claude-agent-sdk/session-bridge.js +158 -0
  45. package/dist/providers/claude-agent-sdk/session-bridge.js.map +1 -0
  46. package/dist/providers/claude-agent-sdk/tool-bridge.d.ts +110 -0
  47. package/dist/providers/claude-agent-sdk/tool-bridge.d.ts.map +1 -0
  48. package/dist/providers/claude-agent-sdk/tool-bridge.js +122 -0
  49. package/dist/providers/claude-agent-sdk/tool-bridge.js.map +1 -0
  50. package/dist/providers/index.d.ts +7 -0
  51. package/dist/providers/index.js +8 -0
  52. package/dist/providers/opencode-sdk/adapter.d.ts +54 -0
  53. package/dist/providers/opencode-sdk/adapter.d.ts.map +1 -0
  54. package/dist/providers/opencode-sdk/adapter.js +276 -0
  55. package/dist/providers/opencode-sdk/adapter.js.map +1 -0
  56. package/dist/providers/opencode-sdk/agent-bridge.d.ts +94 -0
  57. package/dist/providers/opencode-sdk/agent-bridge.d.ts.map +1 -0
  58. package/dist/providers/opencode-sdk/agent-bridge.js +165 -0
  59. package/dist/providers/opencode-sdk/agent-bridge.js.map +1 -0
  60. package/dist/providers/opencode-sdk/index.d.ts +4 -0
  61. package/dist/providers/opencode-sdk/index.js +5 -0
  62. package/dist/providers/opencode-sdk/tool-bridge.d.ts +81 -0
  63. package/dist/providers/opencode-sdk/tool-bridge.d.ts.map +1 -0
  64. package/dist/providers/opencode-sdk/tool-bridge.js +127 -0
  65. package/dist/providers/opencode-sdk/tool-bridge.js.map +1 -0
  66. package/dist/providers/registry.d.ts +22 -0
  67. package/dist/providers/registry.d.ts.map +1 -0
  68. package/dist/providers/registry.js +52 -0
  69. package/dist/providers/registry.js.map +1 -0
  70. package/dist/providers/types.d.ts +243 -0
  71. package/dist/providers/types.d.ts.map +1 -0
  72. package/dist/providers/types.js +44 -0
  73. package/dist/providers/types.js.map +1 -0
  74. package/dist/tools/index.d.ts +1 -1
  75. package/dist/types.d.ts +1 -1
  76. package/dist/types.d.ts.map +1 -1
  77. package/package.json +37 -5
@@ -0,0 +1,276 @@
1
+ import { __require } from "../../_virtual/rolldown_runtime.js";
2
+ import { agentKey } from "../../spec/spec.js";
3
+ import { injectStaticKnowledge } from "../../knowledge/injector.js";
4
+ import { ContextCreationError, ProviderExecutionError, ProviderNotAvailableError } from "../types.js";
5
+ import { createToolHandlerMap, executeToolCall, specToolToExternalToolForOpenCode } from "./tool-bridge.js";
6
+ import { inferAgentType } from "./agent-bridge.js";
7
+
8
+ //#region src/providers/opencode-sdk/adapter.ts
9
+ /**
10
+ * OpenCode SDK Provider implementation.
11
+ */
12
+ var OpenCodeSDKProvider = class {
13
+ name = "opencode-sdk";
14
+ version = "1.0.0";
15
+ config;
16
+ sdkAvailable = null;
17
+ constructor(config = {}) {
18
+ this.config = {
19
+ serverUrl: "http://127.0.0.1:4096",
20
+ port: 4096,
21
+ agentType: "general",
22
+ temperature: .7,
23
+ timeout: 3e4,
24
+ ...config
25
+ };
26
+ if (!config.serverUrl && config.port) this.config.serverUrl = `http://127.0.0.1:${config.port}`;
27
+ }
28
+ /**
29
+ * Check if OpenCode SDK is available.
30
+ */
31
+ isAvailable() {
32
+ if (this.sdkAvailable !== null) return this.sdkAvailable;
33
+ try {
34
+ __require.resolve("@opencode-ai/sdk");
35
+ this.sdkAvailable = true;
36
+ } catch {
37
+ this.sdkAvailable = false;
38
+ }
39
+ return this.sdkAvailable;
40
+ }
41
+ /**
42
+ * Create an execution context from an AgentSpec.
43
+ */
44
+ async createContext(spec) {
45
+ if (!this.isAvailable()) throw new ProviderNotAvailableError(this.name, "SDK not installed");
46
+ try {
47
+ const { client } = await (await this.loadSDK()).createOpencode({
48
+ hostname: this.getHostname(),
49
+ port: this.config.port ?? 4096,
50
+ timeout: this.config.timeout
51
+ });
52
+ const session = await client.session.create({
53
+ agent: this.config.agentType ?? inferAgentType(spec),
54
+ model: this.config.model
55
+ });
56
+ const toolSet = {};
57
+ for (const tool of spec.tools) toolSet[tool.name] = specToolToExternalToolForOpenCode(tool);
58
+ const instructions = await injectStaticKnowledge(spec.instructions, spec.knowledge ?? [], void 0);
59
+ const contextId = `opencode-${agentKey(spec.meta)}-${Date.now()}`;
60
+ const metadata = {
61
+ sessionId: session.id,
62
+ agentType: this.config.agentType ?? inferAgentType(spec),
63
+ serverUrl: this.config.serverUrl ?? `http://127.0.0.1:${this.config.port ?? 4096}`
64
+ };
65
+ return {
66
+ id: contextId,
67
+ spec: {
68
+ ...spec,
69
+ instructions
70
+ },
71
+ tools: toolSet,
72
+ metadata,
73
+ cleanup: async () => {
74
+ try {
75
+ await client.session.delete({ id: session.id });
76
+ } catch {}
77
+ }
78
+ };
79
+ } catch (error) {
80
+ throw new ContextCreationError(this.name, `Failed to create context: ${error instanceof Error ? error.message : String(error)}`, error instanceof Error ? error : void 0);
81
+ }
82
+ }
83
+ /**
84
+ * Execute a prompt using OpenCode SDK.
85
+ */
86
+ async execute(context, params) {
87
+ try {
88
+ const sdk = await this.loadSDK();
89
+ const metadata = context.metadata;
90
+ const { client } = await sdk.createOpencodeClient({ baseUrl: metadata.serverUrl });
91
+ const systemPrompt = params.systemOverride ? `${context.spec.instructions}\n\n${params.systemOverride}` : context.spec.instructions;
92
+ const response = await client.session.prompt({
93
+ id: metadata.sessionId,
94
+ body: {
95
+ content: params.prompt,
96
+ system: systemPrompt
97
+ }
98
+ });
99
+ const toolCalls = this.extractToolCalls(response);
100
+ const toolHandlers = createToolHandlerMap(context.tools);
101
+ const toolResults = await Promise.all(toolCalls.map((tc) => executeToolCall(tc, toolHandlers)));
102
+ return {
103
+ text: this.extractTextContent(response),
104
+ toolCalls: toolCalls.map((tc) => ({
105
+ type: "tool-call",
106
+ toolCallId: tc.id,
107
+ toolName: tc.name,
108
+ args: tc.arguments
109
+ })),
110
+ toolResults: toolResults.map((tr) => ({
111
+ type: "tool-result",
112
+ toolCallId: tr.tool_call_id,
113
+ toolName: toolCalls.find((tc) => tc.id === tr.tool_call_id)?.name ?? "",
114
+ output: tr.output
115
+ })),
116
+ usage: {
117
+ inputTokens: response.usage?.input_tokens ?? 0,
118
+ outputTokens: response.usage?.output_tokens ?? 0
119
+ },
120
+ finishReason: this.mapFinishReason(response.finish_reason),
121
+ metadata: {
122
+ sessionId: metadata.sessionId,
123
+ agentType: metadata.agentType
124
+ }
125
+ };
126
+ } catch (error) {
127
+ throw new ProviderExecutionError(this.name, `Execution failed: ${error instanceof Error ? error.message : String(error)}`, error instanceof Error ? error : void 0);
128
+ }
129
+ }
130
+ /**
131
+ * Stream execution with real-time updates.
132
+ */
133
+ async *stream(context, params) {
134
+ try {
135
+ const sdk = await this.loadSDK();
136
+ const metadata = context.metadata;
137
+ const { client } = await sdk.createOpencodeClient({ baseUrl: metadata.serverUrl });
138
+ const systemPrompt = params.systemOverride ? `${context.spec.instructions}\n\n${params.systemOverride}` : context.spec.instructions;
139
+ const events = client.session.subscribe({ id: metadata.sessionId });
140
+ await client.session.prompt({
141
+ id: metadata.sessionId,
142
+ body: {
143
+ content: params.prompt,
144
+ system: systemPrompt
145
+ }
146
+ });
147
+ let fullText = "";
148
+ const allToolCalls = [];
149
+ const toolHandlers = createToolHandlerMap(context.tools);
150
+ let stepIndex = 0;
151
+ for await (const event of events) {
152
+ if (event.type === "message.delta") {
153
+ const text = event.delta?.content ?? "";
154
+ fullText += text;
155
+ yield {
156
+ type: "text",
157
+ text
158
+ };
159
+ }
160
+ if (event.type === "tool.call") {
161
+ const toolCall = {
162
+ id: event.tool_call_id ?? `tc-${Date.now()}`,
163
+ name: event.tool_name ?? "",
164
+ arguments: event.arguments ?? {}
165
+ };
166
+ allToolCalls.push(toolCall);
167
+ yield {
168
+ type: "tool-call",
169
+ toolCall: {
170
+ type: "tool-call",
171
+ toolCallId: toolCall.id,
172
+ toolName: toolCall.name,
173
+ args: toolCall.arguments
174
+ }
175
+ };
176
+ }
177
+ if (event.type === "step.complete") {
178
+ stepIndex++;
179
+ yield {
180
+ type: "step-complete",
181
+ stepIndex
182
+ };
183
+ }
184
+ if (event.type === "message.complete") break;
185
+ }
186
+ for (const toolCall of allToolCalls) {
187
+ const result = await executeToolCall(toolCall, toolHandlers);
188
+ yield {
189
+ type: "tool-result",
190
+ toolResult: {
191
+ type: "tool-result",
192
+ toolCallId: result.tool_call_id,
193
+ toolName: toolCall.name,
194
+ output: result.output
195
+ }
196
+ };
197
+ }
198
+ yield {
199
+ type: "done",
200
+ result: {
201
+ text: fullText,
202
+ toolCalls: allToolCalls.map((tc) => ({
203
+ type: "tool-call",
204
+ toolCallId: tc.id,
205
+ toolName: tc.name,
206
+ args: tc.arguments
207
+ })),
208
+ toolResults: [],
209
+ usage: {
210
+ inputTokens: 0,
211
+ outputTokens: 0
212
+ },
213
+ finishReason: "stop"
214
+ }
215
+ };
216
+ } catch (error) {
217
+ throw new ProviderExecutionError(this.name, `Stream failed: ${error instanceof Error ? error.message : String(error)}`, error instanceof Error ? error : void 0);
218
+ }
219
+ }
220
+ /**
221
+ * Load the OpenCode SDK dynamically.
222
+ */
223
+ async loadSDK() {
224
+ try {
225
+ return __require("@opencode-ai/sdk");
226
+ } catch {
227
+ throw new ProviderNotAvailableError(this.name, "@opencode-ai/sdk is not installed");
228
+ }
229
+ }
230
+ /**
231
+ * Get hostname from server URL.
232
+ */
233
+ getHostname() {
234
+ if (!this.config.serverUrl) return "127.0.0.1";
235
+ try {
236
+ return new URL(this.config.serverUrl).hostname;
237
+ } catch {
238
+ return "127.0.0.1";
239
+ }
240
+ }
241
+ /**
242
+ * Extract tool calls from response.
243
+ */
244
+ extractToolCalls(response) {
245
+ if (!response.tool_calls) return [];
246
+ return response.tool_calls.map((tc) => ({
247
+ id: tc.id,
248
+ name: tc.name,
249
+ arguments: tc.arguments ?? {}
250
+ }));
251
+ }
252
+ /**
253
+ * Extract text content from response.
254
+ */
255
+ extractTextContent(response) {
256
+ return response.content ?? response.message?.content ?? "";
257
+ }
258
+ /**
259
+ * Map OpenCode finish reason to ContractSpec finish reason.
260
+ */
261
+ mapFinishReason(finishReason) {
262
+ switch (finishReason) {
263
+ case "stop":
264
+ case "end": return "stop";
265
+ case "tool_use":
266
+ case "tool_calls": return "tool-calls";
267
+ case "length":
268
+ case "max_tokens": return "length";
269
+ default: return "stop";
270
+ }
271
+ }
272
+ };
273
+
274
+ //#endregion
275
+ export { OpenCodeSDKProvider };
276
+ //# sourceMappingURL=adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter.js","names":["toolSet: ExternalToolSet","metadata: OpenCodeContextMetadata","allToolCalls: OpenCodeToolCall[]","toolCall: OpenCodeToolCall"],"sources":["../../../src/providers/opencode-sdk/adapter.ts"],"sourcesContent":["/**\n * OpenCode SDK Provider\n *\n * Enables ContractSpec agents to run via OpenCode server:\n * - Session-based execution\n * - Multiple agent types (Build, Plan, General, Explore)\n * - Type-safe client interface\n * - Real-time streaming support\n *\n * This adapter wraps @opencode-ai/sdk to work as a backend\n * for ContractSpec agents.\n */\n\nimport type { AgentSpec } from '../../spec/spec';\nimport { agentKey } from '../../spec/spec';\nimport type {\n ExternalAgentProvider,\n ExternalAgentContext,\n ExternalExecuteParams,\n ExternalExecuteResult,\n ExternalStreamChunk,\n ExternalToolSet,\n OpenCodeSDKConfig,\n OpenCodeContextMetadata,\n OpenCodeAgentType,\n} from '../types';\nimport {\n ContextCreationError,\n ProviderExecutionError,\n ProviderNotAvailableError,\n} from '../types';\nimport {\n specToolToExternalToolForOpenCode,\n createToolHandlerMap,\n executeToolCall,\n type OpenCodeToolCall,\n} from './tool-bridge';\nimport { inferAgentType } from './agent-bridge';\nimport { injectStaticKnowledge } from '../../knowledge/injector';\n\n// ============================================================================\n// Provider Implementation\n// ============================================================================\n\n/**\n * OpenCode SDK Provider implementation.\n */\nexport class OpenCodeSDKProvider implements ExternalAgentProvider {\n readonly name = 'opencode-sdk';\n readonly version = '1.0.0';\n\n private config: OpenCodeSDKConfig;\n private sdkAvailable: boolean | null = null;\n\n constructor(config: OpenCodeSDKConfig = {}) {\n this.config = {\n serverUrl: 'http://127.0.0.1:4096',\n port: 4096,\n agentType: 'general',\n temperature: 0.7,\n timeout: 30000,\n ...config,\n };\n\n // Build server URL from port if not explicitly set\n if (!config.serverUrl && config.port) {\n this.config.serverUrl = `http://127.0.0.1:${config.port}`;\n }\n }\n\n /**\n * Check if OpenCode SDK is available.\n */\n isAvailable(): boolean {\n if (this.sdkAvailable !== null) {\n return this.sdkAvailable;\n }\n\n try {\n // Check if the SDK is installed\n require.resolve('@opencode-ai/sdk');\n this.sdkAvailable = true;\n } catch {\n this.sdkAvailable = false;\n }\n\n return this.sdkAvailable;\n }\n\n /**\n * Create an execution context from an AgentSpec.\n */\n async createContext(spec: AgentSpec): Promise<ExternalAgentContext> {\n if (!this.isAvailable()) {\n throw new ProviderNotAvailableError(this.name, 'SDK not installed');\n }\n\n try {\n const sdk = await this.loadSDK();\n\n // Create or connect to OpenCode client\n const { client } = await sdk.createOpencode({\n hostname: this.getHostname(),\n port: this.config.port ?? 4096,\n timeout: this.config.timeout,\n });\n\n // Create session\n const session = await client.session.create({\n agent: this.config.agentType ?? inferAgentType(spec),\n model: this.config.model,\n });\n\n // Build tools set\n const toolSet: ExternalToolSet = {};\n for (const tool of spec.tools) {\n toolSet[tool.name] = specToolToExternalToolForOpenCode(tool);\n }\n\n // Inject static knowledge into instructions\n const instructions = await injectStaticKnowledge(\n spec.instructions,\n spec.knowledge ?? [],\n undefined\n );\n\n const contextId = `opencode-${agentKey(spec.meta)}-${Date.now()}`;\n\n const metadata: OpenCodeContextMetadata = {\n sessionId: session.id,\n agentType: this.config.agentType ?? inferAgentType(spec),\n serverUrl:\n this.config.serverUrl ??\n `http://127.0.0.1:${this.config.port ?? 4096}`,\n };\n\n return {\n id: contextId,\n spec: {\n ...spec,\n instructions,\n },\n tools: toolSet,\n metadata: metadata as unknown as Record<string, unknown>,\n cleanup: async () => {\n // Cleanup session if needed\n try {\n await client.session.delete({ id: session.id });\n } catch {\n // Ignore cleanup errors\n }\n },\n };\n } catch (error) {\n throw new ContextCreationError(\n this.name,\n `Failed to create context: ${error instanceof Error ? error.message : String(error)}`,\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * Execute a prompt using OpenCode SDK.\n */\n async execute(\n context: ExternalAgentContext,\n params: ExternalExecuteParams\n ): Promise<ExternalExecuteResult> {\n try {\n const sdk = await this.loadSDK();\n const metadata = context.metadata as unknown as OpenCodeContextMetadata;\n\n // Connect to existing session\n const { client } = await sdk.createOpencodeClient({\n baseUrl: metadata.serverUrl,\n });\n\n // Build system prompt\n const systemPrompt = params.systemOverride\n ? `${context.spec.instructions}\\n\\n${params.systemOverride}`\n : context.spec.instructions;\n\n // Execute prompt\n const response = await client.session.prompt({\n id: metadata.sessionId,\n body: {\n content: params.prompt,\n system: systemPrompt,\n },\n });\n\n // Extract tool calls from response\n const toolCalls = this.extractToolCalls(response);\n const toolHandlers = createToolHandlerMap(context.tools);\n\n // Execute tools\n const toolResults = await Promise.all(\n toolCalls.map((tc) => executeToolCall(tc, toolHandlers))\n );\n\n return {\n text: this.extractTextContent(response),\n toolCalls: toolCalls.map((tc) => ({\n type: 'tool-call' as const,\n toolCallId: tc.id,\n toolName: tc.name,\n args: tc.arguments,\n })),\n toolResults: toolResults.map((tr) => ({\n type: 'tool-result' as const,\n toolCallId: tr.tool_call_id,\n toolName:\n toolCalls.find((tc) => tc.id === tr.tool_call_id)?.name ?? '',\n output: tr.output,\n })),\n usage: {\n inputTokens: response.usage?.input_tokens ?? 0,\n outputTokens: response.usage?.output_tokens ?? 0,\n },\n finishReason: this.mapFinishReason(response.finish_reason),\n metadata: {\n sessionId: metadata.sessionId,\n agentType: metadata.agentType,\n },\n };\n } catch (error) {\n throw new ProviderExecutionError(\n this.name,\n `Execution failed: ${error instanceof Error ? error.message : String(error)}`,\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * Stream execution with real-time updates.\n */\n async *stream(\n context: ExternalAgentContext,\n params: ExternalExecuteParams\n ): AsyncIterable<ExternalStreamChunk> {\n try {\n const sdk = await this.loadSDK();\n const metadata = context.metadata as unknown as OpenCodeContextMetadata;\n\n const { client } = await sdk.createOpencodeClient({\n baseUrl: metadata.serverUrl,\n });\n\n const systemPrompt = params.systemOverride\n ? `${context.spec.instructions}\\n\\n${params.systemOverride}`\n : context.spec.instructions;\n\n // Subscribe to session events\n const events = client.session.subscribe({\n id: metadata.sessionId,\n });\n\n // Send prompt\n await client.session.prompt({\n id: metadata.sessionId,\n body: {\n content: params.prompt,\n system: systemPrompt,\n },\n });\n\n let fullText = '';\n const allToolCalls: OpenCodeToolCall[] = [];\n const toolHandlers = createToolHandlerMap(context.tools);\n let stepIndex = 0;\n\n for await (const event of events) {\n if (event.type === 'message.delta') {\n const text = event.delta?.content ?? '';\n fullText += text;\n yield { type: 'text', text };\n }\n\n if (event.type === 'tool.call') {\n const toolCall: OpenCodeToolCall = {\n id: event.tool_call_id ?? `tc-${Date.now()}`,\n name: event.tool_name ?? '',\n arguments: event.arguments ?? {},\n };\n allToolCalls.push(toolCall);\n yield {\n type: 'tool-call',\n toolCall: {\n type: 'tool-call',\n toolCallId: toolCall.id,\n toolName: toolCall.name,\n args: toolCall.arguments,\n },\n };\n }\n\n if (event.type === 'step.complete') {\n stepIndex++;\n yield { type: 'step-complete', stepIndex };\n }\n\n if (event.type === 'message.complete') {\n break;\n }\n }\n\n // Execute pending tools\n for (const toolCall of allToolCalls) {\n const result = await executeToolCall(toolCall, toolHandlers);\n yield {\n type: 'tool-result',\n toolResult: {\n type: 'tool-result',\n toolCallId: result.tool_call_id,\n toolName: toolCall.name,\n output: result.output,\n },\n };\n }\n\n // Final done event\n yield {\n type: 'done',\n result: {\n text: fullText,\n toolCalls: allToolCalls.map((tc) => ({\n type: 'tool-call' as const,\n toolCallId: tc.id,\n toolName: tc.name,\n args: tc.arguments,\n })),\n toolResults: [],\n usage: { inputTokens: 0, outputTokens: 0 },\n finishReason: 'stop',\n },\n };\n } catch (error) {\n throw new ProviderExecutionError(\n this.name,\n `Stream failed: ${error instanceof Error ? error.message : String(error)}`,\n error instanceof Error ? error : undefined\n );\n }\n }\n\n // ============================================================================\n // Private Helpers\n // ============================================================================\n\n /**\n * Load the OpenCode SDK dynamically.\n */\n private async loadSDK(): Promise<OpenCodeSDKInterface> {\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const module = require('@opencode-ai/sdk');\n return module;\n } catch {\n throw new ProviderNotAvailableError(\n this.name,\n '@opencode-ai/sdk is not installed'\n );\n }\n }\n\n /**\n * Get hostname from server URL.\n */\n private getHostname(): string {\n if (!this.config.serverUrl) {\n return '127.0.0.1';\n }\n try {\n const url = new URL(this.config.serverUrl);\n return url.hostname;\n } catch {\n return '127.0.0.1';\n }\n }\n\n /**\n * Extract tool calls from response.\n */\n private extractToolCalls(response: {\n tool_calls?: { id: string; name: string; arguments: unknown }[];\n }): OpenCodeToolCall[] {\n if (!response.tool_calls) {\n return [];\n }\n\n return response.tool_calls.map((tc) => ({\n id: tc.id,\n name: tc.name,\n arguments: (tc.arguments ?? {}) as Record<string, unknown>,\n }));\n }\n\n /**\n * Extract text content from response.\n */\n private extractTextContent(response: {\n content?: string;\n message?: { content?: string };\n }): string {\n return response.content ?? response.message?.content ?? '';\n }\n\n /**\n * Map OpenCode finish reason to ContractSpec finish reason.\n */\n private mapFinishReason(\n finishReason?: string\n ): ExternalExecuteResult['finishReason'] {\n switch (finishReason) {\n case 'stop':\n case 'end':\n return 'stop';\n case 'tool_use':\n case 'tool_calls':\n return 'tool-calls';\n case 'length':\n case 'max_tokens':\n return 'length';\n default:\n return 'stop';\n }\n }\n}\n\n// ============================================================================\n// SDK Interface Type (for dynamic import)\n// ============================================================================\n\n/**\n * Interface for OpenCode SDK (used for dynamic import).\n */\ninterface OpenCodeSDKInterface {\n createOpencode(options: {\n hostname?: string;\n port?: number;\n timeout?: number;\n config?: unknown;\n }): Promise<{\n client: OpenCodeClient;\n }>;\n\n createOpencodeClient(options: { baseUrl: string }): Promise<{\n client: OpenCodeClient;\n }>;\n}\n\n/**\n * OpenCode client interface.\n */\ninterface OpenCodeClient {\n session: {\n create(options: {\n agent?: OpenCodeAgentType;\n model?: string;\n }): Promise<{ id: string }>;\n\n prompt(options: {\n id: string;\n body: {\n content: string;\n system?: string;\n };\n }): Promise<{\n content?: string;\n message?: { content?: string };\n tool_calls?: { id: string; name: string; arguments: unknown }[];\n usage?: { input_tokens?: number; output_tokens?: number };\n finish_reason?: string;\n }>;\n\n delete(options: { id: string }): Promise<void>;\n\n subscribe(options: { id: string }): AsyncIterable<{\n type: string;\n delta?: { content?: string };\n tool_call_id?: string;\n tool_name?: string;\n arguments?: Record<string, unknown>;\n }>;\n };\n\n app: {\n agents(): Promise<{ name: string; type: OpenCodeAgentType }[]>;\n };\n\n global: {\n health(): Promise<{ status: string }>;\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,94 @@
1
+ import { AgentSpec } from "../../spec/spec.js";
2
+ import { OpenCodeAgentType } from "../types.js";
3
+ import { OpenCodeTool } from "./tool-bridge.js";
4
+
5
+ //#region src/providers/opencode-sdk/agent-bridge.d.ts
6
+
7
+ /**
8
+ * OpenCode agent configuration in JSON format.
9
+ */
10
+ interface OpenCodeAgentJSON {
11
+ /** Agent name */
12
+ name: string;
13
+ /** Agent version */
14
+ version?: string;
15
+ /** Agent description */
16
+ description?: string;
17
+ /** System instructions */
18
+ instructions?: string;
19
+ /** Agent type */
20
+ agent_type: OpenCodeAgentType;
21
+ /** Available tools */
22
+ tools?: OpenCodeTool[];
23
+ /** Configuration options */
24
+ config?: OpenCodeAgentConfig;
25
+ }
26
+ /**
27
+ * OpenCode agent configuration options.
28
+ */
29
+ interface OpenCodeAgentConfig {
30
+ /** Maximum agentic iterations */
31
+ max_steps?: number;
32
+ /** Temperature for generation */
33
+ temperature?: number;
34
+ /** Model to use */
35
+ model?: string;
36
+ /** Tool permissions */
37
+ permissions?: Record<string, 'allow' | 'ask' | 'deny'>;
38
+ }
39
+ /**
40
+ * OpenCode agent markdown format (for .opencode/agent/*.md files).
41
+ */
42
+ interface OpenCodeAgentMarkdown {
43
+ /** Frontmatter */
44
+ frontmatter: {
45
+ name: string;
46
+ type: OpenCodeAgentType;
47
+ version?: string;
48
+ model?: string;
49
+ temperature?: number;
50
+ max_steps?: number;
51
+ tools?: string[];
52
+ };
53
+ /** Body content */
54
+ body: string;
55
+ }
56
+ /**
57
+ * Infer the appropriate OpenCode agent type from an AgentSpec.
58
+ *
59
+ * The inference is based on:
60
+ * - Tool capabilities (file editing, bash execution → build)
61
+ * - Instructions content (planning keywords → plan)
62
+ * - Exploration keywords (search, find → explore)
63
+ */
64
+ declare function inferAgentType(spec: AgentSpec): OpenCodeAgentType;
65
+ /**
66
+ * Convert an AgentSpec to OpenCode agent JSON configuration.
67
+ */
68
+ declare function specToOpenCodeConfig(spec: AgentSpec, options?: {
69
+ agentType?: OpenCodeAgentType;
70
+ model?: string;
71
+ temperature?: number;
72
+ maxSteps?: number;
73
+ }): OpenCodeAgentJSON;
74
+ /**
75
+ * Convert an AgentSpec to OpenCode agent markdown format.
76
+ */
77
+ declare function specToOpenCodeMarkdown(spec: AgentSpec, options?: {
78
+ agentType?: OpenCodeAgentType;
79
+ model?: string;
80
+ temperature?: number;
81
+ maxSteps?: number;
82
+ }): OpenCodeAgentMarkdown;
83
+ /**
84
+ * Serialize OpenCode agent markdown to string.
85
+ */
86
+ declare function serializeOpenCodeMarkdown(markdown: OpenCodeAgentMarkdown): string;
87
+ /**
88
+ * Convert OpenCode agent configuration to partial AgentSpec.
89
+ * Note: This is a partial conversion as OpenCode config may not have all spec fields.
90
+ */
91
+ declare function openCodeConfigToSpec(config: OpenCodeAgentJSON): Partial<AgentSpec>;
92
+ //#endregion
93
+ export { OpenCodeAgentConfig, OpenCodeAgentJSON, OpenCodeAgentMarkdown, inferAgentType, openCodeConfigToSpec, serializeOpenCodeMarkdown, specToOpenCodeConfig, specToOpenCodeMarkdown };
94
+ //# sourceMappingURL=agent-bridge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-bridge.d.ts","names":[],"sources":["../../../src/providers/opencode-sdk/agent-bridge.ts"],"sourcesContent":[],"mappings":";;;;;;AAkFA;AA0DA;;AAGgB,UA1HC,iBAAA,CA0HD;EAKb;EAAiB,IAAA,EAAA,MAAA;EA2CJ;EACR,OAAA,CAAA,EAAA,MAAA;EAEQ;EAKb,WAAA,CAAA,EAAA,MAAA;EAAqB;EAyER,YAAA,CAAA,EAAA,MAAA;EAgDA;EACN,UAAA,EAlSI,iBAkSJ;EACC;EAAR,KAAA,CAAA,EAjSO,YAiSP,EAAA;EAAO;WA/RC;;;;;UAMM,mBAAA;;;;;;;;gBAQD;;;;;UAMC,qBAAA;;;;UAIP;;;;;;;;;;;;;;;;;;iBAuBM,cAAA,OAAqB,YAAY;;;;iBA0DjC,oBAAA,OACR;cAEQ;;;;IAKb;;;;iBA2Ca,sBAAA,OACR;cAEQ;;;;IAKb;;;;iBAyEa,yBAAA,WACJ;;;;;iBA+CI,oBAAA,SACN,oBACP,QAAQ"}
@@ -0,0 +1,165 @@
1
+ import { specToolsToOpenCodeTools } from "./tool-bridge.js";
2
+
3
+ //#region src/providers/opencode-sdk/agent-bridge.ts
4
+ /**
5
+ * Infer the appropriate OpenCode agent type from an AgentSpec.
6
+ *
7
+ * The inference is based on:
8
+ * - Tool capabilities (file editing, bash execution → build)
9
+ * - Instructions content (planning keywords → plan)
10
+ * - Exploration keywords (search, find → explore)
11
+ */
12
+ function inferAgentType(spec) {
13
+ const hasCodeTools = spec.tools.some((tool) => [
14
+ "write_file",
15
+ "edit_file",
16
+ "create_file",
17
+ "delete_file",
18
+ "bash",
19
+ "execute",
20
+ "run_command",
21
+ "terminal"
22
+ ].includes(tool.name.toLowerCase()));
23
+ const instructionsLower = spec.instructions.toLowerCase();
24
+ const hasPlanningKeywords = /\b(plan|design|architect|strategy|analyze|review|assess|evaluate)\b/.test(instructionsLower);
25
+ const hasExplorationKeywords = /\b(search|find|explore|discover|locate|grep|pattern)\b/.test(instructionsLower);
26
+ const hasResearchKeywords = /\b(research|investigate|understand|learn|gather|collect)\b/.test(instructionsLower);
27
+ if (hasCodeTools) return "build";
28
+ if (hasPlanningKeywords && !hasCodeTools) return "plan";
29
+ if (hasExplorationKeywords && !hasResearchKeywords) return "explore";
30
+ return "general";
31
+ }
32
+ /**
33
+ * Convert an AgentSpec to OpenCode agent JSON configuration.
34
+ */
35
+ function specToOpenCodeConfig(spec, options) {
36
+ const agentType = options?.agentType ?? inferAgentType(spec);
37
+ return {
38
+ name: spec.meta.key,
39
+ version: spec.meta.version,
40
+ description: spec.description ?? spec.meta.description,
41
+ instructions: spec.instructions,
42
+ agent_type: agentType,
43
+ tools: specToolsToOpenCodeTools(spec.tools),
44
+ config: {
45
+ max_steps: options?.maxSteps ?? spec.maxSteps ?? 10,
46
+ temperature: options?.temperature ?? .7,
47
+ model: options?.model,
48
+ permissions: buildPermissions(spec)
49
+ }
50
+ };
51
+ }
52
+ /**
53
+ * Build tool permissions from spec.
54
+ */
55
+ function buildPermissions(spec) {
56
+ const permissions = {};
57
+ for (const tool of spec.tools) if (tool.requiresApproval) permissions[tool.name] = "ask";
58
+ else if (tool.automationSafe === false) permissions[tool.name] = "ask";
59
+ else permissions[tool.name] = "allow";
60
+ return permissions;
61
+ }
62
+ /**
63
+ * Convert an AgentSpec to OpenCode agent markdown format.
64
+ */
65
+ function specToOpenCodeMarkdown(spec, options) {
66
+ const agentType = options?.agentType ?? inferAgentType(spec);
67
+ return {
68
+ frontmatter: {
69
+ name: spec.meta.key,
70
+ type: agentType,
71
+ version: spec.meta.version,
72
+ model: options?.model,
73
+ temperature: options?.temperature ?? .7,
74
+ max_steps: options?.maxSteps ?? spec.maxSteps ?? 10,
75
+ tools: spec.tools.map((t) => t.name)
76
+ },
77
+ body: buildMarkdownBody(spec)
78
+ };
79
+ }
80
+ /**
81
+ * Build markdown body content from spec.
82
+ */
83
+ function buildMarkdownBody(spec) {
84
+ const lines = [];
85
+ lines.push(`# ${spec.meta.key}`);
86
+ lines.push("");
87
+ if (spec.description ?? spec.meta.description) {
88
+ lines.push(spec.description ?? spec.meta.description ?? "");
89
+ lines.push("");
90
+ }
91
+ lines.push("## Instructions");
92
+ lines.push("");
93
+ lines.push(spec.instructions);
94
+ lines.push("");
95
+ if (spec.tools.length > 0) {
96
+ lines.push("## Tools");
97
+ lines.push("");
98
+ for (const tool of spec.tools) {
99
+ const permission = tool.requiresApproval ? "(requires approval)" : tool.automationSafe === false ? "(ask mode)" : "";
100
+ lines.push(`- **${tool.name}**: ${tool.description ?? "No description"} ${permission}`.trim());
101
+ }
102
+ lines.push("");
103
+ }
104
+ if (spec.knowledge && spec.knowledge.length > 0) {
105
+ lines.push("## Knowledge Sources");
106
+ lines.push("");
107
+ for (const k of spec.knowledge) {
108
+ const required = k.required ? "(required)" : "(optional)";
109
+ lines.push(`- ${k.key} ${required}`);
110
+ }
111
+ lines.push("");
112
+ }
113
+ return lines.join("\n");
114
+ }
115
+ /**
116
+ * Serialize OpenCode agent markdown to string.
117
+ */
118
+ function serializeOpenCodeMarkdown(markdown) {
119
+ const lines = [];
120
+ lines.push("---");
121
+ lines.push(`name: ${markdown.frontmatter.name}`);
122
+ lines.push(`type: ${markdown.frontmatter.type}`);
123
+ if (markdown.frontmatter.version) lines.push(`version: ${markdown.frontmatter.version}`);
124
+ if (markdown.frontmatter.model) lines.push(`model: ${markdown.frontmatter.model}`);
125
+ if (markdown.frontmatter.temperature !== void 0) lines.push(`temperature: ${markdown.frontmatter.temperature}`);
126
+ if (markdown.frontmatter.max_steps !== void 0) lines.push(`max_steps: ${markdown.frontmatter.max_steps}`);
127
+ if (markdown.frontmatter.tools && markdown.frontmatter.tools.length > 0) {
128
+ lines.push(`tools:`);
129
+ for (const tool of markdown.frontmatter.tools) lines.push(` - ${tool}`);
130
+ }
131
+ lines.push("---");
132
+ lines.push("");
133
+ lines.push(markdown.body);
134
+ return lines.join("\n");
135
+ }
136
+ /**
137
+ * Convert OpenCode agent configuration to partial AgentSpec.
138
+ * Note: This is a partial conversion as OpenCode config may not have all spec fields.
139
+ */
140
+ function openCodeConfigToSpec(config) {
141
+ return {
142
+ meta: {
143
+ key: config.name,
144
+ version: config.version ?? "1.0.0",
145
+ description: config.description ?? "",
146
+ stability: "experimental",
147
+ owners: [],
148
+ tags: []
149
+ },
150
+ description: config.description,
151
+ instructions: config.instructions ?? "",
152
+ tools: config.tools?.map((tool) => ({
153
+ name: tool.name,
154
+ description: tool.description,
155
+ schema: tool.parameters,
156
+ requiresApproval: tool.permission === "ask",
157
+ automationSafe: tool.permission === "allow"
158
+ })) ?? [],
159
+ maxSteps: config.config?.max_steps ?? 10
160
+ };
161
+ }
162
+
163
+ //#endregion
164
+ export { inferAgentType, openCodeConfigToSpec, serializeOpenCodeMarkdown, specToOpenCodeConfig, specToOpenCodeMarkdown };
165
+ //# sourceMappingURL=agent-bridge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-bridge.js","names":["permissions: Record<string, 'allow' | 'ask' | 'deny'>","lines: string[]"],"sources":["../../../src/providers/opencode-sdk/agent-bridge.ts"],"sourcesContent":["/**\n * Agent bridge for mapping between ContractSpec AgentSpec and OpenCode agent configuration.\n *\n * OpenCode has four built-in agent types:\n * - build: Primary agent with all tools enabled (default for code generation)\n * - plan: Restricted agent for analysis/planning (file edits and bash in \"ask\" mode)\n * - general: Subagent for complex questions and multi-step tasks\n * - explore: Fast subagent for codebase exploration\n */\n\nimport type { AgentSpec } from '../../spec/spec';\nimport type { OpenCodeAgentType } from '../types';\nimport { specToolsToOpenCodeTools, type OpenCodeTool } from './tool-bridge';\n\n// ============================================================================\n// OpenCode Agent Configuration Types\n// ============================================================================\n\n/**\n * OpenCode agent configuration in JSON format.\n */\nexport interface OpenCodeAgentJSON {\n /** Agent name */\n name: string;\n /** Agent version */\n version?: string;\n /** Agent description */\n description?: string;\n /** System instructions */\n instructions?: string;\n /** Agent type */\n agent_type: OpenCodeAgentType;\n /** Available tools */\n tools?: OpenCodeTool[];\n /** Configuration options */\n config?: OpenCodeAgentConfig;\n}\n\n/**\n * OpenCode agent configuration options.\n */\nexport interface OpenCodeAgentConfig {\n /** Maximum agentic iterations */\n max_steps?: number;\n /** Temperature for generation */\n temperature?: number;\n /** Model to use */\n model?: string;\n /** Tool permissions */\n permissions?: Record<string, 'allow' | 'ask' | 'deny'>;\n}\n\n/**\n * OpenCode agent markdown format (for .opencode/agent/*.md files).\n */\nexport interface OpenCodeAgentMarkdown {\n /** Frontmatter */\n frontmatter: {\n name: string;\n type: OpenCodeAgentType;\n version?: string;\n model?: string;\n temperature?: number;\n max_steps?: number;\n tools?: string[];\n };\n /** Body content */\n body: string;\n}\n\n// ============================================================================\n// Agent Type Inference\n// ============================================================================\n\n/**\n * Infer the appropriate OpenCode agent type from an AgentSpec.\n *\n * The inference is based on:\n * - Tool capabilities (file editing, bash execution → build)\n * - Instructions content (planning keywords → plan)\n * - Exploration keywords (search, find → explore)\n */\nexport function inferAgentType(spec: AgentSpec): OpenCodeAgentType {\n // Check for code-generation/modification tools\n const hasCodeTools = spec.tools.some((tool) =>\n [\n 'write_file',\n 'edit_file',\n 'create_file',\n 'delete_file',\n 'bash',\n 'execute',\n 'run_command',\n 'terminal',\n ].includes(tool.name.toLowerCase())\n );\n\n // Check instructions for planning-related keywords\n const instructionsLower = spec.instructions.toLowerCase();\n const hasPlanningKeywords =\n /\\b(plan|design|architect|strategy|analyze|review|assess|evaluate)\\b/.test(\n instructionsLower\n );\n\n // Check for exploration-related keywords\n const hasExplorationKeywords =\n /\\b(search|find|explore|discover|locate|grep|pattern)\\b/.test(\n instructionsLower\n );\n\n // Check for research/general keywords\n const hasResearchKeywords =\n /\\b(research|investigate|understand|learn|gather|collect)\\b/.test(\n instructionsLower\n );\n\n // Decision logic\n if (hasCodeTools) {\n return 'build';\n }\n\n if (hasPlanningKeywords && !hasCodeTools) {\n return 'plan';\n }\n\n if (hasExplorationKeywords && !hasResearchKeywords) {\n return 'explore';\n }\n\n // Default to general for most use cases\n return 'general';\n}\n\n// ============================================================================\n// Spec to OpenCode Conversion\n// ============================================================================\n\n/**\n * Convert an AgentSpec to OpenCode agent JSON configuration.\n */\nexport function specToOpenCodeConfig(\n spec: AgentSpec,\n options?: {\n agentType?: OpenCodeAgentType;\n model?: string;\n temperature?: number;\n maxSteps?: number;\n }\n): OpenCodeAgentJSON {\n const agentType = options?.agentType ?? inferAgentType(spec);\n\n return {\n name: spec.meta.key,\n version: spec.meta.version,\n description: spec.description ?? spec.meta.description,\n instructions: spec.instructions,\n agent_type: agentType,\n tools: specToolsToOpenCodeTools(spec.tools),\n config: {\n max_steps: options?.maxSteps ?? spec.maxSteps ?? 10,\n temperature: options?.temperature ?? 0.7,\n model: options?.model,\n permissions: buildPermissions(spec),\n },\n };\n}\n\n/**\n * Build tool permissions from spec.\n */\nfunction buildPermissions(\n spec: AgentSpec\n): Record<string, 'allow' | 'ask' | 'deny'> {\n const permissions: Record<string, 'allow' | 'ask' | 'deny'> = {};\n\n for (const tool of spec.tools) {\n if (tool.requiresApproval) {\n permissions[tool.name] = 'ask';\n } else if (tool.automationSafe === false) {\n permissions[tool.name] = 'ask';\n } else {\n permissions[tool.name] = 'allow';\n }\n }\n\n return permissions;\n}\n\n/**\n * Convert an AgentSpec to OpenCode agent markdown format.\n */\nexport function specToOpenCodeMarkdown(\n spec: AgentSpec,\n options?: {\n agentType?: OpenCodeAgentType;\n model?: string;\n temperature?: number;\n maxSteps?: number;\n }\n): OpenCodeAgentMarkdown {\n const agentType = options?.agentType ?? inferAgentType(spec);\n\n return {\n frontmatter: {\n name: spec.meta.key,\n type: agentType,\n version: spec.meta.version,\n model: options?.model,\n temperature: options?.temperature ?? 0.7,\n max_steps: options?.maxSteps ?? spec.maxSteps ?? 10,\n tools: spec.tools.map((t) => t.name),\n },\n body: buildMarkdownBody(spec),\n };\n}\n\n/**\n * Build markdown body content from spec.\n */\nfunction buildMarkdownBody(spec: AgentSpec): string {\n const lines: string[] = [];\n\n // Title\n lines.push(`# ${spec.meta.key}`);\n lines.push('');\n\n // Description\n if (spec.description ?? spec.meta.description) {\n lines.push(spec.description ?? spec.meta.description ?? '');\n lines.push('');\n }\n\n // Instructions\n lines.push('## Instructions');\n lines.push('');\n lines.push(spec.instructions);\n lines.push('');\n\n // Tools\n if (spec.tools.length > 0) {\n lines.push('## Tools');\n lines.push('');\n for (const tool of spec.tools) {\n const permission = tool.requiresApproval\n ? '(requires approval)'\n : tool.automationSafe === false\n ? '(ask mode)'\n : '';\n lines.push(\n `- **${tool.name}**: ${tool.description ?? 'No description'} ${permission}`.trim()\n );\n }\n lines.push('');\n }\n\n // Knowledge sources\n if (spec.knowledge && spec.knowledge.length > 0) {\n lines.push('## Knowledge Sources');\n lines.push('');\n for (const k of spec.knowledge) {\n const required = k.required ? '(required)' : '(optional)';\n lines.push(`- ${k.key} ${required}`);\n }\n lines.push('');\n }\n\n return lines.join('\\n');\n}\n\n/**\n * Serialize OpenCode agent markdown to string.\n */\nexport function serializeOpenCodeMarkdown(\n markdown: OpenCodeAgentMarkdown\n): string {\n const lines: string[] = [];\n\n // Frontmatter\n lines.push('---');\n lines.push(`name: ${markdown.frontmatter.name}`);\n lines.push(`type: ${markdown.frontmatter.type}`);\n\n if (markdown.frontmatter.version) {\n lines.push(`version: ${markdown.frontmatter.version}`);\n }\n\n if (markdown.frontmatter.model) {\n lines.push(`model: ${markdown.frontmatter.model}`);\n }\n\n if (markdown.frontmatter.temperature !== undefined) {\n lines.push(`temperature: ${markdown.frontmatter.temperature}`);\n }\n\n if (markdown.frontmatter.max_steps !== undefined) {\n lines.push(`max_steps: ${markdown.frontmatter.max_steps}`);\n }\n\n if (markdown.frontmatter.tools && markdown.frontmatter.tools.length > 0) {\n lines.push(`tools:`);\n for (const tool of markdown.frontmatter.tools) {\n lines.push(` - ${tool}`);\n }\n }\n\n lines.push('---');\n lines.push('');\n lines.push(markdown.body);\n\n return lines.join('\\n');\n}\n\n// ============================================================================\n// OpenCode to Spec Conversion\n// ============================================================================\n\n/**\n * Convert OpenCode agent configuration to partial AgentSpec.\n * Note: This is a partial conversion as OpenCode config may not have all spec fields.\n */\nexport function openCodeConfigToSpec(\n config: OpenCodeAgentJSON\n): Partial<AgentSpec> {\n return {\n meta: {\n key: config.name,\n version: config.version ?? '1.0.0',\n description: config.description ?? '',\n stability: 'experimental',\n owners: [],\n tags: [],\n },\n description: config.description,\n instructions: config.instructions ?? '',\n tools:\n config.tools?.map((tool) => ({\n name: tool.name,\n description: tool.description,\n schema: tool.parameters,\n requiresApproval: tool.permission === 'ask',\n automationSafe: tool.permission === 'allow',\n // category not supported in AgentToolConfig\n })) ?? [],\n maxSteps: config.config?.max_steps ?? 10,\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { OpenCodeSDKProvider } from "./adapter.js";
2
+ import { OpenCodeParameter, OpenCodeTool, OpenCodeToolCall, OpenCodeToolResult, createToolHandlerMap, executeToolCall, openCodeToolToSpecTool, openCodeToolsToSpecTools, specToolToExternalToolForOpenCode, specToolToOpenCodeTool, specToolsToOpenCodeTools } from "./tool-bridge.js";
3
+ import { OpenCodeAgentConfig, OpenCodeAgentJSON, OpenCodeAgentMarkdown, inferAgentType, openCodeConfigToSpec, serializeOpenCodeMarkdown, specToOpenCodeConfig, specToOpenCodeMarkdown } from "./agent-bridge.js";
4
+ export { OpenCodeAgentConfig, OpenCodeAgentJSON, OpenCodeAgentMarkdown, OpenCodeParameter, OpenCodeSDKProvider, OpenCodeTool, OpenCodeToolCall, OpenCodeToolResult, createToolHandlerMap, executeToolCall, inferAgentType, openCodeConfigToSpec, openCodeToolToSpecTool, openCodeToolsToSpecTools, serializeOpenCodeMarkdown, specToOpenCodeConfig, specToOpenCodeMarkdown, specToolToExternalToolForOpenCode, specToolToOpenCodeTool, specToolsToOpenCodeTools };
@@ -0,0 +1,5 @@
1
+ import { createToolHandlerMap, executeToolCall, openCodeToolToSpecTool, openCodeToolsToSpecTools, specToolToExternalToolForOpenCode, specToolToOpenCodeTool, specToolsToOpenCodeTools } from "./tool-bridge.js";
2
+ import { inferAgentType, openCodeConfigToSpec, serializeOpenCodeMarkdown, specToOpenCodeConfig, specToOpenCodeMarkdown } from "./agent-bridge.js";
3
+ import { OpenCodeSDKProvider } from "./adapter.js";
4
+
5
+ export { OpenCodeSDKProvider, createToolHandlerMap, executeToolCall, inferAgentType, openCodeConfigToSpec, openCodeToolToSpecTool, openCodeToolsToSpecTools, serializeOpenCodeMarkdown, specToOpenCodeConfig, specToOpenCodeMarkdown, specToolToExternalToolForOpenCode, specToolToOpenCodeTool, specToolsToOpenCodeTools };