@limo-labs/deity-adapter-copilot 0.1.0-alpha.1

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/README.md ADDED
@@ -0,0 +1,285 @@
1
+ # @limo-labs/deity-adapter-copilot
2
+
3
+ GitHub Copilot SDK adapter for the Deity framework.
4
+
5
+ ## Overview
6
+
7
+ This adapter enables Deity agents to use GitHub Copilot's language models (GPT-4o, Claude Opus, o1, etc.) through the Copilot SDK. It implements Deity's `LLMAdapter` interface and handles the conversion between Deity's tool format and Copilot SDK's native tool calling.
8
+
9
+ ## Features
10
+
11
+ - **Native Tool Support**: Uses Copilot SDK's built-in tool calling for reliable execution
12
+ - **Disposable Sessions**: Creates fresh sessions for each request, optimized for Deity's stateless design
13
+ - **Multiple Models**: Support for GPT-4o, Claude Opus 4.6, o1, o1-mini, and other Copilot-supported models
14
+ - **Tool Call Tracking**: Automatically tracks tool executions via hooks
15
+ - **Environment Isolation**: Blocks environment tools to ensure only registered tools are used
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ npm install @limo-labs/deity-adapter-copilot
21
+ ```
22
+
23
+ **Peer Dependencies:**
24
+ - `@limo-labs/deity`: ^0.1.3-alpha.2
25
+ - `@github/copilot-sdk`: ^0.1.25
26
+
27
+ ## Basic Usage
28
+
29
+ ```typescript
30
+ import { CopilotSDKAdapter } from '@limo-labs/deity-adapter-copilot';
31
+ import { Agent, createTool } from '@limo-labs/deity';
32
+ import { z } from 'zod';
33
+
34
+ // Create adapter
35
+ const adapter = new CopilotSDKAdapter({
36
+ model: 'claude-opus-4.6', // or 'gpt-4o', 'o1', etc.
37
+ debug: true // Enable logging
38
+ });
39
+
40
+ // Initialize adapter
41
+ await adapter.initialize();
42
+
43
+ // Define a tool
44
+ const searchTool = createTool({
45
+ name: 'search',
46
+ description: 'Search for information',
47
+ inputSchema: z.object({
48
+ query: z.string()
49
+ }),
50
+ execute: async (input, ctx) => {
51
+ // Your search implementation
52
+ return `Results for: ${input.query}`;
53
+ }
54
+ });
55
+
56
+ // Create agent with adapter
57
+ const agent = new Agent({
58
+ name: 'research-agent',
59
+ systemPrompt: 'You are a helpful research assistant.',
60
+ tools: [searchTool],
61
+ llmAdapter: adapter
62
+ });
63
+
64
+ // Execute agent
65
+ const result = await agent.execute({
66
+ input: { topic: 'AI agents' }
67
+ });
68
+
69
+ // Cleanup
70
+ await adapter.cleanup();
71
+ ```
72
+
73
+ ## Configuration Options
74
+
75
+ ```typescript
76
+ interface CopilotSDKAdapterConfig {
77
+ /**
78
+ * Model to use (default: 'gpt-4o')
79
+ * Options: 'gpt-4o', 'claude-opus-4.6', 'o1', 'o1-mini', etc.
80
+ */
81
+ model?: string;
82
+
83
+ /**
84
+ * Custom Copilot CLI URL (optional)
85
+ * If not provided, SDK will auto-manage the CLI
86
+ */
87
+ cliUrl?: string;
88
+
89
+ /**
90
+ * Callback for streaming response chunks (optional)
91
+ */
92
+ onStreamChunk?: (chunk: string) => void;
93
+
94
+ /**
95
+ * Callback for reasoning/thinking chunks (optional)
96
+ */
97
+ onReasoningChunk?: (chunk: string) => void;
98
+
99
+ /**
100
+ * Enable debug logging (default: false)
101
+ */
102
+ debug?: boolean;
103
+ }
104
+ ```
105
+
106
+ ## Architecture
107
+
108
+ ### Disposable Session Pattern
109
+
110
+ This adapter uses a **disposable session pattern** optimized for Deity's stateless design:
111
+
112
+ 1. **Create**: A new session is created for each `generate()` call
113
+ 2. **Use**: Session executes the request and tool calls
114
+ 3. **Destroy**: Session is immediately destroyed in a `finally` block
115
+
116
+ **Why disposable sessions?**
117
+
118
+ - Deity uses an intelligent memory system instead of traditional chat history
119
+ - Retaining full chat history consumes significant context with low information density
120
+ - Each request should be self-contained based on dynamically reconstructed context
121
+ - Sessions are lightweight to create/destroy
122
+
123
+ ```typescript
124
+ async generate(messages, tools, config, ctx) {
125
+ const session = await this.client.createSession({...});
126
+
127
+ try {
128
+ // Execute request
129
+ const result = await session.sendAndWait({ prompt });
130
+ return result;
131
+ } catch (error) {
132
+ await session.destroy();
133
+ throw error;
134
+ } finally {
135
+ // Always destroy session
136
+ await session.destroy();
137
+ }
138
+ }
139
+ ```
140
+
141
+ ### Tool Execution Model
142
+
143
+ The adapter uses Copilot SDK's native tool support:
144
+
145
+ 1. **Registration**: Deity tools are converted to SDK tools using `defineTool()`
146
+ 2. **Execution**: SDK handles the tool calling loop automatically
147
+ 3. **Tracking**: `onPostToolUse` hook tracks tool calls for Deity compatibility
148
+ 4. **Return**: Tool calls are marked as `_alreadyExecuted` to prevent re-execution
149
+
150
+ ```typescript
151
+ // Tool conversion
152
+ const copilotTool = defineTool(tool.name, {
153
+ description: tool.description,
154
+ parameters: tool.inputSchema, // Zod schema (v4 has native toJSONSchema())
155
+ handler: async (args) => {
156
+ // Execute Deity tool
157
+ return await tool.execute(args, ctx);
158
+ }
159
+ });
160
+
161
+ // Hook for tracking
162
+ hooks: {
163
+ onPostToolUse: async (input) => {
164
+ this.toolCallHistory.push({
165
+ id: `call_${Date.now()}_${Math.random()}`,
166
+ name: input.toolName,
167
+ arguments: input.toolArgs,
168
+ _alreadyExecuted: true // Prevent re-execution
169
+ });
170
+ }
171
+ }
172
+ ```
173
+
174
+ ### Environment Tool Isolation
175
+
176
+ The adapter excludes all environment tools to ensure only registered tools are used:
177
+
178
+ ```typescript
179
+ excludedTools: [
180
+ 'bash', 'shell', 'view', 'create', 'edit',
181
+ 'web_fetch', 'sql', 'grep', 'glob', 'task',
182
+ // ... and more
183
+ ]
184
+ ```
185
+
186
+ This prevents the LLM from calling tools you haven't explicitly registered.
187
+
188
+ ## Supported Models
189
+
190
+ - `gpt-4o` (default)
191
+ - `claude-opus-4.6`
192
+ - `o1`
193
+ - `o1-mini`
194
+ - Other models supported by Copilot SDK
195
+
196
+ ## Advanced Usage
197
+
198
+ ### Custom CLI Management
199
+
200
+ ```typescript
201
+ const adapter = new CopilotSDKAdapter({
202
+ cliUrl: 'http://localhost:9090', // Custom CLI server
203
+ model: 'gpt-4o'
204
+ });
205
+ ```
206
+
207
+ ### Streaming Responses
208
+
209
+ ```typescript
210
+ const adapter = new CopilotSDKAdapter({
211
+ model: 'gpt-4o',
212
+ onStreamChunk: (chunk) => {
213
+ process.stdout.write(chunk);
214
+ },
215
+ onReasoningChunk: (chunk) => {
216
+ console.log('[Reasoning]', chunk);
217
+ }
218
+ });
219
+ ```
220
+
221
+ ### Debug Logging
222
+
223
+ ```typescript
224
+ const adapter = new CopilotSDKAdapter({
225
+ debug: true // Enables detailed logging
226
+ });
227
+ ```
228
+
229
+ ## Validation
230
+
231
+ This adapter has been validated with:
232
+
233
+ - ✅ Multi-turn tool calling conversations
234
+ - ✅ Long system messages (~20k characters)
235
+ - ✅ Multiple tool registrations (5+ tools)
236
+ - ✅ Complex Zod schemas with nested objects
237
+ - ✅ Error handling and recovery
238
+
239
+ ## Troubleshooting
240
+
241
+ ### Tools not being called
242
+
243
+ 1. Check that `excludedTools` includes environment tools
244
+ 2. Verify tool schemas are valid Zod v4 schemas
245
+ 3. Enable debug logging to see tool registration
246
+
247
+ ### Session errors
248
+
249
+ 1. Ensure `initialize()` is called before `generate()`
250
+ 2. Check that CLI is accessible (if using custom cliUrl)
251
+ 3. Verify Copilot SDK is properly installed
252
+
253
+ ### Tool execution failures
254
+
255
+ 1. Check that ExecutionContext is available
256
+ 2. Verify tool handler implementation
257
+ 3. Enable debug logging to see execution details
258
+
259
+ ## Development
260
+
261
+ ```bash
262
+ # Install dependencies
263
+ npm install
264
+
265
+ # Build
266
+ npm run build
267
+
268
+ # Type check
269
+ npm run type-check
270
+
271
+ # Lint
272
+ npm run lint
273
+
274
+ # Test
275
+ npm test
276
+ ```
277
+
278
+ ## License
279
+
280
+ MIT
281
+
282
+ ## Related
283
+
284
+ - [Deity Framework](https://github.com/limo-labs/deity)
285
+ - [GitHub Copilot SDK](https://github.com/github/copilot-sdk)
package/dist/index.cjs ADDED
@@ -0,0 +1,255 @@
1
+ 'use strict';
2
+
3
+ var copilotSdk = require('@github/copilot-sdk');
4
+
5
+ // src/adapter.ts
6
+ var CopilotSDKAdapter = class {
7
+ client;
8
+ model;
9
+ sessionCounter = 0;
10
+ isInitialized = false;
11
+ onStreamChunk;
12
+ currentContext;
13
+ debugEnabled;
14
+ // Track tool calls for Deity compatibility
15
+ toolCallHistory = [];
16
+ constructor(config = {}) {
17
+ this.model = config.model || "gpt-4o";
18
+ this.onStreamChunk = config.onStreamChunk;
19
+ this.debugEnabled = config.debug || false;
20
+ this.client = new copilotSdk.CopilotClient({
21
+ cliUrl: config.cliUrl,
22
+ cliArgs: ["--disable-builtin-mcps"]
23
+ });
24
+ this.log("CopilotSDKAdapter created:", {
25
+ model: this.model,
26
+ mode: config.cliUrl ? "external-server" : "auto-managed",
27
+ streaming: !!this.onStreamChunk,
28
+ nativeToolSupport: true
29
+ });
30
+ }
31
+ log(...args) {
32
+ if (this.debugEnabled) {
33
+ console.log("[CopilotSDKAdapter]", ...args);
34
+ }
35
+ }
36
+ async initialize() {
37
+ if (this.isInitialized) {
38
+ this.log("Client already initialized, skipping");
39
+ return;
40
+ }
41
+ this.log("Starting Copilot client...");
42
+ await this.client.start();
43
+ this.isInitialized = true;
44
+ this.log("Copilot client started successfully");
45
+ }
46
+ /**
47
+ * Generate LLM response using Copilot SDK's native tool support
48
+ *
49
+ * Copilot SDK handles:
50
+ * - Tool definition injection
51
+ * - Tool call generation
52
+ * - Tool execution via handlers
53
+ * - Multi-turn tool calling loop
54
+ *
55
+ * Architecture notes:
56
+ * - Creates a disposable session for each call
57
+ * - Session is destroyed after use (in finally block)
58
+ * - Tool calls are tracked via onPostToolUse hook
59
+ * - Returns toolCalls array marked as already executed
60
+ */
61
+ async generate(messages, tools, _config, ctx) {
62
+ if (!this.isInitialized) {
63
+ await this.initialize();
64
+ }
65
+ this.currentContext = ctx;
66
+ this.toolCallHistory = [];
67
+ const startTime = Date.now();
68
+ const sessionId = `deity-session-${Date.now()}-${this.sessionCounter++}`;
69
+ this.log("Creating disposable session:", sessionId);
70
+ const copilotTools = tools ? this.convertTools(tools) : void 0;
71
+ const toolNames = copilotTools?.map((t) => t.name) || [];
72
+ this.log("Session tools:", {
73
+ count: toolNames.length,
74
+ names: toolNames
75
+ });
76
+ const sessionConfig = {
77
+ sessionId,
78
+ model: this.model,
79
+ tools: copilotTools,
80
+ // Exclude ALL environment tools to ensure only registered tools are used
81
+ excludedTools: [
82
+ "bash",
83
+ "write_bash",
84
+ "read_bash",
85
+ "stop_bash",
86
+ "list_bash",
87
+ "shell",
88
+ "view",
89
+ "create",
90
+ "edit",
91
+ "web_fetch",
92
+ "report_intent",
93
+ "read_file",
94
+ "write_file",
95
+ "sql",
96
+ "read_agent",
97
+ "list_agents",
98
+ "grep",
99
+ "glob",
100
+ "task"
101
+ ],
102
+ // Add hooks to track tool calls for Deity compatibility
103
+ hooks: {
104
+ onPostToolUse: (input) => {
105
+ const toolCall = {
106
+ id: `call_${Date.now()}_${Math.random().toString(36).slice(2)}`,
107
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
108
+ name: input.toolName,
109
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
110
+ arguments: input.toolArgs,
111
+ _alreadyExecuted: true,
112
+ // Mark as already executed by SDK
113
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
114
+ _executionResult: JSON.stringify(input.toolResult)
115
+ // Store result for reference
116
+ };
117
+ this.toolCallHistory.push(toolCall);
118
+ this.log("Tool call tracked:", {
119
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
120
+ name: input.toolName,
121
+ totalCalls: this.toolCallHistory.length
122
+ });
123
+ return void 0;
124
+ }
125
+ }
126
+ };
127
+ const session = await this.client.createSession(sessionConfig);
128
+ this.log("Session created:", sessionId);
129
+ try {
130
+ const prompt = this.messagesToPrompt(messages);
131
+ this.log("Sending prompt:", {
132
+ promptLength: prompt.length,
133
+ sessionId: session.sessionId,
134
+ toolsCount: tools?.length || 0
135
+ });
136
+ let responseContent = "";
137
+ try {
138
+ const result = await session.sendAndWait({ prompt }, 12e6);
139
+ if (result) {
140
+ responseContent = result.data.content || "";
141
+ this.log("Response received:", {
142
+ length: responseContent.length
143
+ });
144
+ }
145
+ } catch (error) {
146
+ console.error("[CopilotSDKAdapter] sendAndWait error:", error.message);
147
+ throw error;
148
+ }
149
+ const elapsed = Date.now() - startTime;
150
+ this.log(`API response received in ${elapsed}ms`);
151
+ if (this.toolCallHistory.length > 0) {
152
+ this.log(`Session executed ${this.toolCallHistory.length} tool calls`);
153
+ }
154
+ const response = {
155
+ content: responseContent,
156
+ toolCalls: this.toolCallHistory.length > 0 ? this.toolCallHistory : void 0
157
+ };
158
+ return response;
159
+ } catch (error) {
160
+ await session.destroy();
161
+ throw error;
162
+ } finally {
163
+ await session.destroy();
164
+ this.log("Session destroyed:", sessionId);
165
+ }
166
+ }
167
+ /**
168
+ * Convert Deity Tool to Copilot SDK Tool using defineTool
169
+ *
170
+ * Uses SDK's defineTool() function which properly registers tools.
171
+ * Zod schemas are passed directly - Zod v4 has native toJSONSchema() method.
172
+ */
173
+ convertTools(deityTools) {
174
+ this.log("Converting Deity tools to Copilot SDK format:", {
175
+ count: deityTools.length,
176
+ names: deityTools.map((t) => t.name)
177
+ });
178
+ const converted = deityTools.map((tool) => {
179
+ const parameters = tool.inputSchema;
180
+ return copilotSdk.defineTool(tool.name, {
181
+ description: tool.description || `Tool: ${tool.name}`,
182
+ parameters,
183
+ handler: async (args) => {
184
+ this.log("Executing tool via SDK handler:", {
185
+ name: tool.name
186
+ });
187
+ try {
188
+ if (!this.currentContext) {
189
+ throw new Error("Execution context not available for tool handler");
190
+ }
191
+ const result = await tool.execute(args, this.currentContext);
192
+ this.log("Tool execution successful:", tool.name);
193
+ return typeof result === "string" ? result : JSON.stringify(result);
194
+ } catch (error) {
195
+ const errorMsg = error instanceof Error ? error.message : String(error);
196
+ console.error("[CopilotSDKAdapter] Tool execution failed:", {
197
+ tool: tool.name,
198
+ error: errorMsg
199
+ });
200
+ return JSON.stringify({
201
+ success: false,
202
+ error: errorMsg
203
+ });
204
+ }
205
+ }
206
+ });
207
+ });
208
+ this.log("Tool conversion complete:", {
209
+ convertedCount: converted.length,
210
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access
211
+ toolNames: converted.map((t) => t.name || "unknown")
212
+ });
213
+ return converted;
214
+ }
215
+ /**
216
+ * Convert Deity messages to Copilot prompt format
217
+ *
218
+ * Note: Copilot SDK uses a simple string prompt format.
219
+ * All message types are concatenated into a single prompt.
220
+ */
221
+ messagesToPrompt(messages) {
222
+ let prompt = "";
223
+ for (const msg of messages) {
224
+ switch (msg.role) {
225
+ case "system":
226
+ prompt += msg.content + "\n\n";
227
+ break;
228
+ case "user":
229
+ prompt += `User: ${msg.content}
230
+
231
+ `;
232
+ break;
233
+ case "assistant":
234
+ prompt += `Assistant: ${msg.content}
235
+
236
+ `;
237
+ break;
238
+ }
239
+ }
240
+ return prompt;
241
+ }
242
+ async cleanup() {
243
+ if (!this.isInitialized) {
244
+ return;
245
+ }
246
+ this.log("Stopping Copilot client...");
247
+ await this.client.stop();
248
+ this.isInitialized = false;
249
+ this.log("Copilot client stopped");
250
+ }
251
+ };
252
+
253
+ exports.CopilotSDKAdapter = CopilotSDKAdapter;
254
+ //# sourceMappingURL=index.cjs.map
255
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/adapter.ts"],"names":["CopilotClient","defineTool"],"mappings":";;;;;AA4DO,IAAM,oBAAN,MAA8C;AAAA,EAC3C,MAAA;AAAA,EACA,KAAA;AAAA,EACA,cAAA,GAAiB,CAAA;AAAA,EACjB,aAAA,GAAgB,KAAA;AAAA,EAChB,aAAA;AAAA,EACA,cAAA;AAAA,EACA,YAAA;AAAA;AAAA,EAGA,kBAA8B,EAAC;AAAA,EAEvC,WAAA,CAAY,MAAA,GAAkC,EAAC,EAAG;AAChD,IAAA,IAAA,CAAK,KAAA,GAAQ,OAAO,KAAA,IAAS,QAAA;AAC7B,IAAA,IAAA,CAAK,gBAAgB,MAAA,CAAO,aAAA;AAC5B,IAAA,IAAA,CAAK,YAAA,GAAe,OAAO,KAAA,IAAS,KAAA;AAIpC,IAAA,IAAA,CAAK,MAAA,GAAS,IAAIA,wBAAA,CAAc;AAAA,MAC9B,QAAQ,MAAA,CAAO,MAAA;AAAA,MACf,OAAA,EAAS,CAAC,wBAAwB;AAAA,KACnC,CAAA;AAED,IAAA,IAAA,CAAK,IAAI,4BAAA,EAA8B;AAAA,MACrC,OAAO,IAAA,CAAK,KAAA;AAAA,MACZ,IAAA,EAAM,MAAA,CAAO,MAAA,GAAS,iBAAA,GAAoB,cAAA;AAAA,MAC1C,SAAA,EAAW,CAAC,CAAC,IAAA,CAAK,aAAA;AAAA,MAClB,iBAAA,EAAmB;AAAA,KACpB,CAAA;AAAA,EACH;AAAA,EAEQ,OAAO,IAAA,EAAmB;AAChC,IAAA,IAAI,KAAK,YAAA,EAAc;AAErB,MAAA,OAAA,CAAQ,GAAA,CAAI,qBAAA,EAAuB,GAAG,IAAI,CAAA;AAAA,IAC5C;AAAA,EACF;AAAA,EAEA,MAAM,UAAA,GAA4B;AAChC,IAAA,IAAI,KAAK,aAAA,EAAe;AACtB,MAAA,IAAA,CAAK,IAAI,sCAAsC,CAAA;AAC/C,MAAA;AAAA,IACF;AAEA,IAAA,IAAA,CAAK,IAAI,4BAA4B,CAAA;AACrC,IAAA,MAAM,IAAA,CAAK,OAAO,KAAA,EAAM;AACxB,IAAA,IAAA,CAAK,aAAA,GAAgB,IAAA;AACrB,IAAA,IAAA,CAAK,IAAI,qCAAqC,CAAA;AAAA,EAChD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiBA,MAAM,QAAA,CACJ,QAAA,EACA,KAAA,EACA,SACA,GAAA,EACsB;AACtB,IAAA,IAAI,CAAC,KAAK,aAAA,EAAe;AACvB,MAAA,MAAM,KAAK,UAAA,EAAW;AAAA,IACxB;AAGA,IAAA,IAAA,CAAK,cAAA,GAAiB,GAAA;AAGtB,IAAA,IAAA,CAAK,kBAAkB,EAAC;AAExB,IAAA,MAAM,SAAA,GAAY,KAAK,GAAA,EAAI;AAG3B,IAAA,MAAM,YAAY,CAAA,cAAA,EAAiB,IAAA,CAAK,KAAK,CAAA,CAAA,EAAI,KAAK,cAAA,EAAgB,CAAA,CAAA;AACtE,IAAA,IAAA,CAAK,GAAA,CAAI,gCAAgC,SAAS,CAAA;AAGlD,IAAA,MAAM,YAAA,GAAe,KAAA,GAAQ,IAAA,CAAK,YAAA,CAAa,KAAK,CAAA,GAAI,MAAA;AAExD,IAAA,MAAM,SAAA,GAAY,cAAc,GAAA,CAAI,CAAC,MAAO,CAAA,CAAU,IAAI,KAAK,EAAC;AAEhE,IAAA,IAAA,CAAK,IAAI,gBAAA,EAAkB;AAAA,MACzB,OAAO,SAAA,CAAU,MAAA;AAAA,MACjB,KAAA,EAAO;AAAA,KACR,CAAA;AAGD,IAAA,MAAM,aAAA,GAAqB;AAAA,MACzB,SAAA;AAAA,MACA,OAAO,IAAA,CAAK,KAAA;AAAA,MACZ,KAAA,EAAO,YAAA;AAAA;AAAA,MAEP,aAAA,EAAe;AAAA,QACb,MAAA;AAAA,QACA,YAAA;AAAA,QACA,WAAA;AAAA,QACA,WAAA;AAAA,QACA,WAAA;AAAA,QACA,OAAA;AAAA,QACA,MAAA;AAAA,QACA,QAAA;AAAA,QACA,MAAA;AAAA,QACA,WAAA;AAAA,QACA,eAAA;AAAA,QACA,WAAA;AAAA,QACA,YAAA;AAAA,QACA,KAAA;AAAA,QACA,YAAA;AAAA,QACA,aAAA;AAAA,QACA,MAAA;AAAA,QACA,MAAA;AAAA,QACA;AAAA,OACF;AAAA;AAAA,MAEA,KAAA,EAAO;AAAA,QACL,aAAA,EAAe,CAAC,KAAA,KAAe;AAE7B,UAAA,MAAM,QAAA,GAAgB;AAAA,YACpB,EAAA,EAAI,CAAA,KAAA,EAAQ,IAAA,CAAK,GAAA,EAAK,CAAA,CAAA,EAAI,IAAA,CAAK,MAAA,EAAO,CAAE,QAAA,CAAS,EAAE,CAAA,CAAE,KAAA,CAAM,CAAC,CAAC,CAAA,CAAA;AAAA;AAAA,YAE7D,MAAM,KAAA,CAAM,QAAA;AAAA;AAAA,YAEZ,WAAW,KAAA,CAAM,QAAA;AAAA,YACjB,gBAAA,EAAkB,IAAA;AAAA;AAAA;AAAA,YAElB,gBAAA,EAAkB,IAAA,CAAK,SAAA,CAAU,KAAA,CAAM,UAAU;AAAA;AAAA,WACnD;AAEA,UAAA,IAAA,CAAK,eAAA,CAAgB,KAAK,QAAQ,CAAA;AAElC,UAAA,IAAA,CAAK,IAAI,oBAAA,EAAsB;AAAA;AAAA,YAE7B,MAAM,KAAA,CAAM,QAAA;AAAA,YACZ,UAAA,EAAY,KAAK,eAAA,CAAgB;AAAA,WAClC,CAAA;AAGD,UAAA,OAAO,MAAA;AAAA,QACT;AAAA;AACF,KACF;AAGA,IAAA,MAAM,OAAA,GAAU,MAAM,IAAA,CAAK,MAAA,CAAO,cAAc,aAAa,CAAA;AAC7D,IAAA,IAAA,CAAK,GAAA,CAAI,oBAAoB,SAAS,CAAA;AAEtC,IAAA,IAAI;AAEF,MAAA,MAAM,MAAA,GAAS,IAAA,CAAK,gBAAA,CAAiB,QAAQ,CAAA;AAE7C,MAAA,IAAA,CAAK,IAAI,iBAAA,EAAmB;AAAA,QAC1B,cAAc,MAAA,CAAO,MAAA;AAAA,QACrB,WAAW,OAAA,CAAQ,SAAA;AAAA,QACnB,UAAA,EAAY,OAAO,MAAA,IAAU;AAAA,OAC9B,CAAA;AAED,MAAA,IAAI,eAAA,GAAkB,EAAA;AAGtB,MAAA,IAAI;AACF,QAAA,MAAM,SAAS,MAAM,OAAA,CAAQ,YAAY,EAAE,MAAA,IAAU,IAAQ,CAAA;AAE7D,QAAA,IAAI,MAAA,EAAQ;AACV,UAAA,eAAA,GAAkB,MAAA,CAAO,KAAK,OAAA,IAAW,EAAA;AACzC,UAAA,IAAA,CAAK,IAAI,oBAAA,EAAsB;AAAA,YAC7B,QAAQ,eAAA,CAAgB;AAAA,WACzB,CAAA;AAAA,QACH;AAAA,MACF,SAAS,KAAA,EAAY;AAEnB,QAAA,OAAA,CAAQ,KAAA,CAAM,wCAAA,EAA0C,KAAA,CAAM,OAAO,CAAA;AACrE,QAAA,MAAM,KAAA;AAAA,MACR;AAEA,MAAA,MAAM,OAAA,GAAU,IAAA,CAAK,GAAA,EAAI,GAAI,SAAA;AAC7B,MAAA,IAAA,CAAK,GAAA,CAAI,CAAA,yBAAA,EAA4B,OAAO,CAAA,EAAA,CAAI,CAAA;AAEhD,MAAA,IAAI,IAAA,CAAK,eAAA,CAAgB,MAAA,GAAS,CAAA,EAAG;AACnC,QAAA,IAAA,CAAK,GAAA,CAAI,CAAA,iBAAA,EAAoB,IAAA,CAAK,eAAA,CAAgB,MAAM,CAAA,WAAA,CAAa,CAAA;AAAA,MACvE;AAIA,MAAA,MAAM,QAAA,GAAwB;AAAA,QAC5B,OAAA,EAAS,eAAA;AAAA,QACT,WAAW,IAAA,CAAK,eAAA,CAAgB,MAAA,GAAS,CAAA,GAAI,KAAK,eAAA,GAAkB,KAAA;AAAA,OACtE;AAEA,MAAA,OAAO,QAAA;AAAA,IACT,SAAS,KAAA,EAAO;AAEd,MAAA,MAAM,QAAQ,OAAA,EAAQ;AACtB,MAAA,MAAM,KAAA;AAAA,IACR,CAAA,SAAE;AAEA,MAAA,MAAM,QAAQ,OAAA,EAAQ;AACtB,MAAA,IAAA,CAAK,GAAA,CAAI,sBAAsB,SAAS,CAAA;AAAA,IAC1C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQQ,aAAa,UAAA,EAAmC;AACtD,IAAA,IAAA,CAAK,IAAI,+CAAA,EAAiD;AAAA,MACxD,OAAO,UAAA,CAAW,MAAA;AAAA,MAClB,OAAO,UAAA,CAAW,GAAA,CAAI,CAAC,CAAA,KAAM,EAAE,IAAI;AAAA,KACpC,CAAA;AAED,IAAA,MAAM,SAAA,GAAY,UAAA,CAAW,GAAA,CAAI,CAAC,IAAA,KAAS;AAGzC,MAAA,MAAM,aAAa,IAAA,CAAK,WAAA;AAIxB,MAAA,OAAOC,qBAAA,CAAW,KAAK,IAAA,EAAM;AAAA,QAC3B,WAAA,EAAa,IAAA,CAAK,WAAA,IAAe,CAAA,MAAA,EAAS,KAAK,IAAI,CAAA,CAAA;AAAA,QACnD,UAAA;AAAA,QACA,OAAA,EAAS,OAAO,IAAA,KAAkB;AAChC,UAAA,IAAA,CAAK,IAAI,iCAAA,EAAmC;AAAA,YAC1C,MAAM,IAAA,CAAK;AAAA,WACZ,CAAA;AAED,UAAA,IAAI;AACF,YAAA,IAAI,CAAC,KAAK,cAAA,EAAgB;AACxB,cAAA,MAAM,IAAI,MAAM,kDAAkD,CAAA;AAAA,YACpE;AAGA,YAAA,MAAM,SAAS,MAAM,IAAA,CAAK,OAAA,CAAQ,IAAA,EAAM,KAAK,cAAc,CAAA;AAE3D,YAAA,IAAA,CAAK,GAAA,CAAI,4BAAA,EAA8B,IAAA,CAAK,IAAI,CAAA;AAGhD,YAAA,OAAO,OAAO,MAAA,KAAW,QAAA,GAAW,MAAA,GAAS,IAAA,CAAK,UAAU,MAAM,CAAA;AAAA,UACpE,SAAS,KAAA,EAAO;AACd,YAAA,MAAM,WAAW,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU,OAAO,KAAK,CAAA;AACtE,YAAA,OAAA,CAAQ,MAAM,4CAAA,EAA8C;AAAA,cAC1D,MAAM,IAAA,CAAK,IAAA;AAAA,cACX,KAAA,EAAO;AAAA,aACR,CAAA;AAGD,YAAA,OAAO,KAAK,SAAA,CAAU;AAAA,cACpB,OAAA,EAAS,KAAA;AAAA,cACT,KAAA,EAAO;AAAA,aACR,CAAA;AAAA,UACH;AAAA,QACF;AAAA,OACD,CAAA;AAAA,IACH,CAAC,CAAA;AAED,IAAA,IAAA,CAAK,IAAI,2BAAA,EAA6B;AAAA,MACpC,gBAAgB,SAAA,CAAU,MAAA;AAAA;AAAA,MAE1B,WAAW,SAAA,CAAU,GAAA,CAAI,CAAC,CAAA,KAAW,CAAA,CAAE,QAAQ,SAAS;AAAA,KACzD,CAAA;AAED,IAAA,OAAO,SAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQQ,iBAAiB,QAAA,EAA6B;AACpD,IAAA,IAAI,MAAA,GAAS,EAAA;AAEb,IAAA,KAAA,MAAW,OAAO,QAAA,EAAU;AAC1B,MAAA,QAAQ,IAAI,IAAA;AAAM,QAChB,KAAK,QAAA;AACH,UAAA,MAAA,IAAU,IAAI,OAAA,GAAU,MAAA;AACxB,UAAA;AAAA,QACF,KAAK,MAAA;AACH,UAAA,MAAA,IAAU,CAAA,MAAA,EAAS,IAAI,OAAO;;AAAA,CAAA;AAC9B,UAAA;AAAA,QACF,KAAK,WAAA;AACH,UAAA,MAAA,IAAU,CAAA,WAAA,EAAc,IAAI,OAAO;;AAAA,CAAA;AACnC,UAAA;AAGA;AACJ,IACF;AAEA,IAAA,OAAO,MAAA;AAAA,EACT;AAAA,EAEA,MAAM,OAAA,GAAyB;AAC7B,IAAA,IAAI,CAAC,KAAK,aAAA,EAAe;AACvB,MAAA;AAAA,IACF;AAGA,IAAA,IAAA,CAAK,IAAI,4BAA4B,CAAA;AACrC,IAAA,MAAM,IAAA,CAAK,OAAO,IAAA,EAAK;AACvB,IAAA,IAAA,CAAK,aAAA,GAAgB,KAAA;AACrB,IAAA,IAAA,CAAK,IAAI,wBAAwB,CAAA;AAAA,EACnC;AACF","file":"index.cjs","sourcesContent":["/* eslint-disable @typescript-eslint/no-unsafe-assignment */\n\n/**\n * Copilot SDK Adapter for Deity Framework\n *\n * Uses Copilot SDK's native tool support for reliable tool calling.\n *\n * Architecture:\n * - Deity passes tools to generate()\n * - Adapter converts Deity tools to Copilot SDK tools\n * - Copilot SDK handles tool calling loop automatically\n * - Adapter returns final response with tool call information\n *\n * Session Management:\n * - Uses disposable session pattern (create → use → destroy)\n * - Each generate() call creates a fresh session\n * - Sessions are destroyed in finally block to ensure cleanup\n * - This pattern is optimized for Deity's stateless design\n */\n\nimport { CopilotClient, defineTool, type Tool as CopilotTool } from '@github/copilot-sdk';\nimport type {\n LLMAdapter,\n LLMResponse,\n Message,\n Tool,\n GenerationConfig,\n ExecutionContext,\n ToolCall,\n} from '@limo-labs/deity';\n\nexport interface CopilotSDKAdapterConfig {\n /**\n * Model to use (default: 'gpt-4o')\n * Options: 'gpt-4o', 'claude-opus-4.6', 'o1', 'o1-mini', etc.\n */\n model?: string;\n\n /**\n * Custom Copilot CLI URL (optional)\n * If not provided, SDK will auto-manage the CLI\n */\n cliUrl?: string;\n\n /**\n * Callback for streaming response chunks (optional)\n */\n onStreamChunk?: (chunk: string) => void;\n\n /**\n * Callback for reasoning/thinking chunks (optional)\n */\n onReasoningChunk?: (chunk: string) => void;\n\n /**\n * Enable debug logging (default: false)\n */\n debug?: boolean;\n}\n\nexport class CopilotSDKAdapter implements LLMAdapter {\n private client: CopilotClient;\n private model: string;\n private sessionCounter = 0;\n private isInitialized = false;\n private onStreamChunk?: (chunk: string) => void;\n private currentContext?: ExecutionContext;\n private debugEnabled: boolean;\n\n // Track tool calls for Deity compatibility\n private toolCallHistory: ToolCall[] = [];\n\n constructor(config: CopilotSDKAdapterConfig = {}) {\n this.model = config.model || 'gpt-4o';\n this.onStreamChunk = config.onStreamChunk;\n this.debugEnabled = config.debug || false;\n\n // CRITICAL FIX: Disable built-in GitHub MCP server\n // GitHub MCP server auto-activates in git repos and overrides SDK tools\n this.client = new CopilotClient({\n cliUrl: config.cliUrl,\n cliArgs: ['--disable-builtin-mcps'],\n });\n\n this.log('CopilotSDKAdapter created:', {\n model: this.model,\n mode: config.cliUrl ? 'external-server' : 'auto-managed',\n streaming: !!this.onStreamChunk,\n nativeToolSupport: true,\n });\n }\n\n private log(...args: any[]): void {\n if (this.debugEnabled) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n console.log('[CopilotSDKAdapter]', ...args);\n }\n }\n\n async initialize(): Promise<void> {\n if (this.isInitialized) {\n this.log('Client already initialized, skipping');\n return;\n }\n\n this.log('Starting Copilot client...');\n await this.client.start();\n this.isInitialized = true;\n this.log('Copilot client started successfully');\n }\n\n /**\n * Generate LLM response using Copilot SDK's native tool support\n *\n * Copilot SDK handles:\n * - Tool definition injection\n * - Tool call generation\n * - Tool execution via handlers\n * - Multi-turn tool calling loop\n *\n * Architecture notes:\n * - Creates a disposable session for each call\n * - Session is destroyed after use (in finally block)\n * - Tool calls are tracked via onPostToolUse hook\n * - Returns toolCalls array marked as already executed\n */\n async generate(\n messages: Message[],\n tools?: Tool[],\n _config?: GenerationConfig,\n ctx?: ExecutionContext\n ): Promise<LLMResponse> {\n if (!this.isInitialized) {\n await this.initialize();\n }\n\n // Store context for tool handlers\n this.currentContext = ctx;\n\n // Reset tool call history for this generation\n this.toolCallHistory = [];\n\n const startTime = Date.now();\n\n // Disposable session pattern: create new session for each call\n const sessionId = `deity-session-${Date.now()}-${this.sessionCounter++}`;\n this.log('Creating disposable session:', sessionId);\n\n // Convert Deity tools to Copilot SDK tools\n const copilotTools = tools ? this.convertTools(tools) : undefined;\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access\n const toolNames = copilotTools?.map((t) => (t as any).name) || [];\n\n this.log('Session tools:', {\n count: toolNames.length,\n names: toolNames,\n });\n\n // Create session with hooks to track tool calls\n const sessionConfig: any = {\n sessionId,\n model: this.model,\n tools: copilotTools,\n // Exclude ALL environment tools to ensure only registered tools are used\n excludedTools: [\n 'bash',\n 'write_bash',\n 'read_bash',\n 'stop_bash',\n 'list_bash',\n 'shell',\n 'view',\n 'create',\n 'edit',\n 'web_fetch',\n 'report_intent',\n 'read_file',\n 'write_file',\n 'sql',\n 'read_agent',\n 'list_agents',\n 'grep',\n 'glob',\n 'task',\n ],\n // Add hooks to track tool calls for Deity compatibility\n hooks: {\n onPostToolUse: (input: any) => {\n // Record tool call in history with execution metadata\n const toolCall: any = {\n id: `call_${Date.now()}_${Math.random().toString(36).slice(2)}`,\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access\n name: input.toolName,\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access\n arguments: input.toolArgs,\n _alreadyExecuted: true, // Mark as already executed by SDK\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n _executionResult: JSON.stringify(input.toolResult), // Store result for reference\n };\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n this.toolCallHistory.push(toolCall);\n\n this.log('Tool call tracked:', {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access\n name: input.toolName,\n totalCalls: this.toolCallHistory.length,\n });\n\n // Don't modify anything, just track\n return undefined;\n },\n },\n };\n\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n const session = await this.client.createSession(sessionConfig);\n this.log('Session created:', sessionId);\n\n try {\n // Convert ALL messages to prompt (including system messages)\n const prompt = this.messagesToPrompt(messages);\n\n this.log('Sending prompt:', {\n promptLength: prompt.length,\n sessionId: session.sessionId,\n toolsCount: tools?.length || 0,\n });\n\n let responseContent = '';\n\n // Use sendAndWait() to get the response\n try {\n const result = await session.sendAndWait({ prompt }, 12000000); // 12000s timeout\n\n if (result) {\n responseContent = result.data.content || '';\n this.log('Response received:', {\n length: responseContent.length,\n });\n }\n } catch (error: any) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n console.error('[CopilotSDKAdapter] sendAndWait error:', error.message);\n throw error;\n }\n\n const elapsed = Date.now() - startTime;\n this.log(`API response received in ${elapsed}ms`);\n\n if (this.toolCallHistory.length > 0) {\n this.log(`Session executed ${this.toolCallHistory.length} tool calls`);\n }\n\n // Return result with toolCalls marked as already executed\n // Deity llm-loop will check _alreadyExecuted flag and skip re-execution\n const response: LLMResponse = {\n content: responseContent,\n toolCalls: this.toolCallHistory.length > 0 ? this.toolCallHistory : undefined,\n };\n\n return response;\n } catch (error) {\n // Clean up session on error\n await session.destroy();\n throw error;\n } finally {\n // Always destroy disposable session\n await session.destroy();\n this.log('Session destroyed:', sessionId);\n }\n }\n\n /**\n * Convert Deity Tool to Copilot SDK Tool using defineTool\n *\n * Uses SDK's defineTool() function which properly registers tools.\n * Zod schemas are passed directly - Zod v4 has native toJSONSchema() method.\n */\n private convertTools(deityTools: Tool[]): CopilotTool[] {\n this.log('Converting Deity tools to Copilot SDK format:', {\n count: deityTools.length,\n names: deityTools.map((t) => t.name),\n });\n\n const converted = deityTools.map((tool) => {\n // Pass Zod schema directly - Zod v4 has native toJSONSchema() method\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n const parameters = tool.inputSchema as any;\n\n // Use SDK's defineTool function (critical for proper registration)\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-return\n return defineTool(tool.name, {\n description: tool.description || `Tool: ${tool.name}`,\n parameters,\n handler: async (args: unknown) => {\n this.log('Executing tool via SDK handler:', {\n name: tool.name,\n });\n\n try {\n if (!this.currentContext) {\n throw new Error('Execution context not available for tool handler');\n }\n\n // Execute Deity tool\n const result = await tool.execute(args, this.currentContext);\n\n this.log('Tool execution successful:', tool.name);\n\n // Return result in format expected by Copilot SDK\n return typeof result === 'string' ? result : JSON.stringify(result);\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error);\n console.error('[CopilotSDKAdapter] Tool execution failed:', {\n tool: tool.name,\n error: errorMsg,\n });\n\n // Return error result\n return JSON.stringify({\n success: false,\n error: errorMsg,\n });\n }\n },\n });\n });\n\n this.log('Tool conversion complete:', {\n convertedCount: converted.length,\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access\n toolNames: converted.map((t: any) => t.name || 'unknown'),\n });\n\n return converted;\n }\n\n /**\n * Convert Deity messages to Copilot prompt format\n *\n * Note: Copilot SDK uses a simple string prompt format.\n * All message types are concatenated into a single prompt.\n */\n private messagesToPrompt(messages: Message[]): string {\n let prompt = '';\n\n for (const msg of messages) {\n switch (msg.role) {\n case 'system':\n prompt += msg.content + '\\n\\n';\n break;\n case 'user':\n prompt += `User: ${msg.content}\\n\\n`;\n break;\n case 'assistant':\n prompt += `Assistant: ${msg.content}\\n\\n`;\n break;\n case 'tool':\n // Skip tool messages - SDK handles them internally\n break;\n }\n }\n\n return prompt;\n }\n\n async cleanup(): Promise<void> {\n if (!this.isInitialized) {\n return;\n }\n\n // No sessions to clean up (disposable session pattern)\n this.log('Stopping Copilot client...');\n await this.client.stop();\n this.isInitialized = false;\n this.log('Copilot client stopped');\n }\n}\n"]}
@@ -0,0 +1,72 @@
1
+ import { LLMAdapter, Message, Tool, GenerationConfig, ExecutionContext, LLMResponse } from '@limo-labs/deity';
2
+
3
+ interface CopilotSDKAdapterConfig {
4
+ /**
5
+ * Model to use (default: 'gpt-4o')
6
+ * Options: 'gpt-4o', 'claude-opus-4.6', 'o1', 'o1-mini', etc.
7
+ */
8
+ model?: string;
9
+ /**
10
+ * Custom Copilot CLI URL (optional)
11
+ * If not provided, SDK will auto-manage the CLI
12
+ */
13
+ cliUrl?: string;
14
+ /**
15
+ * Callback for streaming response chunks (optional)
16
+ */
17
+ onStreamChunk?: (chunk: string) => void;
18
+ /**
19
+ * Callback for reasoning/thinking chunks (optional)
20
+ */
21
+ onReasoningChunk?: (chunk: string) => void;
22
+ /**
23
+ * Enable debug logging (default: false)
24
+ */
25
+ debug?: boolean;
26
+ }
27
+ declare class CopilotSDKAdapter implements LLMAdapter {
28
+ private client;
29
+ private model;
30
+ private sessionCounter;
31
+ private isInitialized;
32
+ private onStreamChunk?;
33
+ private currentContext?;
34
+ private debugEnabled;
35
+ private toolCallHistory;
36
+ constructor(config?: CopilotSDKAdapterConfig);
37
+ private log;
38
+ initialize(): Promise<void>;
39
+ /**
40
+ * Generate LLM response using Copilot SDK's native tool support
41
+ *
42
+ * Copilot SDK handles:
43
+ * - Tool definition injection
44
+ * - Tool call generation
45
+ * - Tool execution via handlers
46
+ * - Multi-turn tool calling loop
47
+ *
48
+ * Architecture notes:
49
+ * - Creates a disposable session for each call
50
+ * - Session is destroyed after use (in finally block)
51
+ * - Tool calls are tracked via onPostToolUse hook
52
+ * - Returns toolCalls array marked as already executed
53
+ */
54
+ generate(messages: Message[], tools?: Tool[], _config?: GenerationConfig, ctx?: ExecutionContext): Promise<LLMResponse>;
55
+ /**
56
+ * Convert Deity Tool to Copilot SDK Tool using defineTool
57
+ *
58
+ * Uses SDK's defineTool() function which properly registers tools.
59
+ * Zod schemas are passed directly - Zod v4 has native toJSONSchema() method.
60
+ */
61
+ private convertTools;
62
+ /**
63
+ * Convert Deity messages to Copilot prompt format
64
+ *
65
+ * Note: Copilot SDK uses a simple string prompt format.
66
+ * All message types are concatenated into a single prompt.
67
+ */
68
+ private messagesToPrompt;
69
+ cleanup(): Promise<void>;
70
+ }
71
+
72
+ export { CopilotSDKAdapter, type CopilotSDKAdapterConfig };
@@ -0,0 +1,72 @@
1
+ import { LLMAdapter, Message, Tool, GenerationConfig, ExecutionContext, LLMResponse } from '@limo-labs/deity';
2
+
3
+ interface CopilotSDKAdapterConfig {
4
+ /**
5
+ * Model to use (default: 'gpt-4o')
6
+ * Options: 'gpt-4o', 'claude-opus-4.6', 'o1', 'o1-mini', etc.
7
+ */
8
+ model?: string;
9
+ /**
10
+ * Custom Copilot CLI URL (optional)
11
+ * If not provided, SDK will auto-manage the CLI
12
+ */
13
+ cliUrl?: string;
14
+ /**
15
+ * Callback for streaming response chunks (optional)
16
+ */
17
+ onStreamChunk?: (chunk: string) => void;
18
+ /**
19
+ * Callback for reasoning/thinking chunks (optional)
20
+ */
21
+ onReasoningChunk?: (chunk: string) => void;
22
+ /**
23
+ * Enable debug logging (default: false)
24
+ */
25
+ debug?: boolean;
26
+ }
27
+ declare class CopilotSDKAdapter implements LLMAdapter {
28
+ private client;
29
+ private model;
30
+ private sessionCounter;
31
+ private isInitialized;
32
+ private onStreamChunk?;
33
+ private currentContext?;
34
+ private debugEnabled;
35
+ private toolCallHistory;
36
+ constructor(config?: CopilotSDKAdapterConfig);
37
+ private log;
38
+ initialize(): Promise<void>;
39
+ /**
40
+ * Generate LLM response using Copilot SDK's native tool support
41
+ *
42
+ * Copilot SDK handles:
43
+ * - Tool definition injection
44
+ * - Tool call generation
45
+ * - Tool execution via handlers
46
+ * - Multi-turn tool calling loop
47
+ *
48
+ * Architecture notes:
49
+ * - Creates a disposable session for each call
50
+ * - Session is destroyed after use (in finally block)
51
+ * - Tool calls are tracked via onPostToolUse hook
52
+ * - Returns toolCalls array marked as already executed
53
+ */
54
+ generate(messages: Message[], tools?: Tool[], _config?: GenerationConfig, ctx?: ExecutionContext): Promise<LLMResponse>;
55
+ /**
56
+ * Convert Deity Tool to Copilot SDK Tool using defineTool
57
+ *
58
+ * Uses SDK's defineTool() function which properly registers tools.
59
+ * Zod schemas are passed directly - Zod v4 has native toJSONSchema() method.
60
+ */
61
+ private convertTools;
62
+ /**
63
+ * Convert Deity messages to Copilot prompt format
64
+ *
65
+ * Note: Copilot SDK uses a simple string prompt format.
66
+ * All message types are concatenated into a single prompt.
67
+ */
68
+ private messagesToPrompt;
69
+ cleanup(): Promise<void>;
70
+ }
71
+
72
+ export { CopilotSDKAdapter, type CopilotSDKAdapterConfig };
package/dist/index.js ADDED
@@ -0,0 +1,253 @@
1
+ import { CopilotClient, defineTool } from '@github/copilot-sdk';
2
+
3
+ // src/adapter.ts
4
+ var CopilotSDKAdapter = class {
5
+ client;
6
+ model;
7
+ sessionCounter = 0;
8
+ isInitialized = false;
9
+ onStreamChunk;
10
+ currentContext;
11
+ debugEnabled;
12
+ // Track tool calls for Deity compatibility
13
+ toolCallHistory = [];
14
+ constructor(config = {}) {
15
+ this.model = config.model || "gpt-4o";
16
+ this.onStreamChunk = config.onStreamChunk;
17
+ this.debugEnabled = config.debug || false;
18
+ this.client = new CopilotClient({
19
+ cliUrl: config.cliUrl,
20
+ cliArgs: ["--disable-builtin-mcps"]
21
+ });
22
+ this.log("CopilotSDKAdapter created:", {
23
+ model: this.model,
24
+ mode: config.cliUrl ? "external-server" : "auto-managed",
25
+ streaming: !!this.onStreamChunk,
26
+ nativeToolSupport: true
27
+ });
28
+ }
29
+ log(...args) {
30
+ if (this.debugEnabled) {
31
+ console.log("[CopilotSDKAdapter]", ...args);
32
+ }
33
+ }
34
+ async initialize() {
35
+ if (this.isInitialized) {
36
+ this.log("Client already initialized, skipping");
37
+ return;
38
+ }
39
+ this.log("Starting Copilot client...");
40
+ await this.client.start();
41
+ this.isInitialized = true;
42
+ this.log("Copilot client started successfully");
43
+ }
44
+ /**
45
+ * Generate LLM response using Copilot SDK's native tool support
46
+ *
47
+ * Copilot SDK handles:
48
+ * - Tool definition injection
49
+ * - Tool call generation
50
+ * - Tool execution via handlers
51
+ * - Multi-turn tool calling loop
52
+ *
53
+ * Architecture notes:
54
+ * - Creates a disposable session for each call
55
+ * - Session is destroyed after use (in finally block)
56
+ * - Tool calls are tracked via onPostToolUse hook
57
+ * - Returns toolCalls array marked as already executed
58
+ */
59
+ async generate(messages, tools, _config, ctx) {
60
+ if (!this.isInitialized) {
61
+ await this.initialize();
62
+ }
63
+ this.currentContext = ctx;
64
+ this.toolCallHistory = [];
65
+ const startTime = Date.now();
66
+ const sessionId = `deity-session-${Date.now()}-${this.sessionCounter++}`;
67
+ this.log("Creating disposable session:", sessionId);
68
+ const copilotTools = tools ? this.convertTools(tools) : void 0;
69
+ const toolNames = copilotTools?.map((t) => t.name) || [];
70
+ this.log("Session tools:", {
71
+ count: toolNames.length,
72
+ names: toolNames
73
+ });
74
+ const sessionConfig = {
75
+ sessionId,
76
+ model: this.model,
77
+ tools: copilotTools,
78
+ // Exclude ALL environment tools to ensure only registered tools are used
79
+ excludedTools: [
80
+ "bash",
81
+ "write_bash",
82
+ "read_bash",
83
+ "stop_bash",
84
+ "list_bash",
85
+ "shell",
86
+ "view",
87
+ "create",
88
+ "edit",
89
+ "web_fetch",
90
+ "report_intent",
91
+ "read_file",
92
+ "write_file",
93
+ "sql",
94
+ "read_agent",
95
+ "list_agents",
96
+ "grep",
97
+ "glob",
98
+ "task"
99
+ ],
100
+ // Add hooks to track tool calls for Deity compatibility
101
+ hooks: {
102
+ onPostToolUse: (input) => {
103
+ const toolCall = {
104
+ id: `call_${Date.now()}_${Math.random().toString(36).slice(2)}`,
105
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
106
+ name: input.toolName,
107
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
108
+ arguments: input.toolArgs,
109
+ _alreadyExecuted: true,
110
+ // Mark as already executed by SDK
111
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
112
+ _executionResult: JSON.stringify(input.toolResult)
113
+ // Store result for reference
114
+ };
115
+ this.toolCallHistory.push(toolCall);
116
+ this.log("Tool call tracked:", {
117
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
118
+ name: input.toolName,
119
+ totalCalls: this.toolCallHistory.length
120
+ });
121
+ return void 0;
122
+ }
123
+ }
124
+ };
125
+ const session = await this.client.createSession(sessionConfig);
126
+ this.log("Session created:", sessionId);
127
+ try {
128
+ const prompt = this.messagesToPrompt(messages);
129
+ this.log("Sending prompt:", {
130
+ promptLength: prompt.length,
131
+ sessionId: session.sessionId,
132
+ toolsCount: tools?.length || 0
133
+ });
134
+ let responseContent = "";
135
+ try {
136
+ const result = await session.sendAndWait({ prompt }, 12e6);
137
+ if (result) {
138
+ responseContent = result.data.content || "";
139
+ this.log("Response received:", {
140
+ length: responseContent.length
141
+ });
142
+ }
143
+ } catch (error) {
144
+ console.error("[CopilotSDKAdapter] sendAndWait error:", error.message);
145
+ throw error;
146
+ }
147
+ const elapsed = Date.now() - startTime;
148
+ this.log(`API response received in ${elapsed}ms`);
149
+ if (this.toolCallHistory.length > 0) {
150
+ this.log(`Session executed ${this.toolCallHistory.length} tool calls`);
151
+ }
152
+ const response = {
153
+ content: responseContent,
154
+ toolCalls: this.toolCallHistory.length > 0 ? this.toolCallHistory : void 0
155
+ };
156
+ return response;
157
+ } catch (error) {
158
+ await session.destroy();
159
+ throw error;
160
+ } finally {
161
+ await session.destroy();
162
+ this.log("Session destroyed:", sessionId);
163
+ }
164
+ }
165
+ /**
166
+ * Convert Deity Tool to Copilot SDK Tool using defineTool
167
+ *
168
+ * Uses SDK's defineTool() function which properly registers tools.
169
+ * Zod schemas are passed directly - Zod v4 has native toJSONSchema() method.
170
+ */
171
+ convertTools(deityTools) {
172
+ this.log("Converting Deity tools to Copilot SDK format:", {
173
+ count: deityTools.length,
174
+ names: deityTools.map((t) => t.name)
175
+ });
176
+ const converted = deityTools.map((tool) => {
177
+ const parameters = tool.inputSchema;
178
+ return defineTool(tool.name, {
179
+ description: tool.description || `Tool: ${tool.name}`,
180
+ parameters,
181
+ handler: async (args) => {
182
+ this.log("Executing tool via SDK handler:", {
183
+ name: tool.name
184
+ });
185
+ try {
186
+ if (!this.currentContext) {
187
+ throw new Error("Execution context not available for tool handler");
188
+ }
189
+ const result = await tool.execute(args, this.currentContext);
190
+ this.log("Tool execution successful:", tool.name);
191
+ return typeof result === "string" ? result : JSON.stringify(result);
192
+ } catch (error) {
193
+ const errorMsg = error instanceof Error ? error.message : String(error);
194
+ console.error("[CopilotSDKAdapter] Tool execution failed:", {
195
+ tool: tool.name,
196
+ error: errorMsg
197
+ });
198
+ return JSON.stringify({
199
+ success: false,
200
+ error: errorMsg
201
+ });
202
+ }
203
+ }
204
+ });
205
+ });
206
+ this.log("Tool conversion complete:", {
207
+ convertedCount: converted.length,
208
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access
209
+ toolNames: converted.map((t) => t.name || "unknown")
210
+ });
211
+ return converted;
212
+ }
213
+ /**
214
+ * Convert Deity messages to Copilot prompt format
215
+ *
216
+ * Note: Copilot SDK uses a simple string prompt format.
217
+ * All message types are concatenated into a single prompt.
218
+ */
219
+ messagesToPrompt(messages) {
220
+ let prompt = "";
221
+ for (const msg of messages) {
222
+ switch (msg.role) {
223
+ case "system":
224
+ prompt += msg.content + "\n\n";
225
+ break;
226
+ case "user":
227
+ prompt += `User: ${msg.content}
228
+
229
+ `;
230
+ break;
231
+ case "assistant":
232
+ prompt += `Assistant: ${msg.content}
233
+
234
+ `;
235
+ break;
236
+ }
237
+ }
238
+ return prompt;
239
+ }
240
+ async cleanup() {
241
+ if (!this.isInitialized) {
242
+ return;
243
+ }
244
+ this.log("Stopping Copilot client...");
245
+ await this.client.stop();
246
+ this.isInitialized = false;
247
+ this.log("Copilot client stopped");
248
+ }
249
+ };
250
+
251
+ export { CopilotSDKAdapter };
252
+ //# sourceMappingURL=index.js.map
253
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/adapter.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/* eslint-disable @typescript-eslint/no-unsafe-assignment */\n\n/**\n * Copilot SDK Adapter for Deity Framework\n *\n * Uses Copilot SDK's native tool support for reliable tool calling.\n *\n * Architecture:\n * - Deity passes tools to generate()\n * - Adapter converts Deity tools to Copilot SDK tools\n * - Copilot SDK handles tool calling loop automatically\n * - Adapter returns final response with tool call information\n *\n * Session Management:\n * - Uses disposable session pattern (create → use → destroy)\n * - Each generate() call creates a fresh session\n * - Sessions are destroyed in finally block to ensure cleanup\n * - This pattern is optimized for Deity's stateless design\n */\n\nimport { CopilotClient, defineTool, type Tool as CopilotTool } from '@github/copilot-sdk';\nimport type {\n LLMAdapter,\n LLMResponse,\n Message,\n Tool,\n GenerationConfig,\n ExecutionContext,\n ToolCall,\n} from '@limo-labs/deity';\n\nexport interface CopilotSDKAdapterConfig {\n /**\n * Model to use (default: 'gpt-4o')\n * Options: 'gpt-4o', 'claude-opus-4.6', 'o1', 'o1-mini', etc.\n */\n model?: string;\n\n /**\n * Custom Copilot CLI URL (optional)\n * If not provided, SDK will auto-manage the CLI\n */\n cliUrl?: string;\n\n /**\n * Callback for streaming response chunks (optional)\n */\n onStreamChunk?: (chunk: string) => void;\n\n /**\n * Callback for reasoning/thinking chunks (optional)\n */\n onReasoningChunk?: (chunk: string) => void;\n\n /**\n * Enable debug logging (default: false)\n */\n debug?: boolean;\n}\n\nexport class CopilotSDKAdapter implements LLMAdapter {\n private client: CopilotClient;\n private model: string;\n private sessionCounter = 0;\n private isInitialized = false;\n private onStreamChunk?: (chunk: string) => void;\n private currentContext?: ExecutionContext;\n private debugEnabled: boolean;\n\n // Track tool calls for Deity compatibility\n private toolCallHistory: ToolCall[] = [];\n\n constructor(config: CopilotSDKAdapterConfig = {}) {\n this.model = config.model || 'gpt-4o';\n this.onStreamChunk = config.onStreamChunk;\n this.debugEnabled = config.debug || false;\n\n // CRITICAL FIX: Disable built-in GitHub MCP server\n // GitHub MCP server auto-activates in git repos and overrides SDK tools\n this.client = new CopilotClient({\n cliUrl: config.cliUrl,\n cliArgs: ['--disable-builtin-mcps'],\n });\n\n this.log('CopilotSDKAdapter created:', {\n model: this.model,\n mode: config.cliUrl ? 'external-server' : 'auto-managed',\n streaming: !!this.onStreamChunk,\n nativeToolSupport: true,\n });\n }\n\n private log(...args: any[]): void {\n if (this.debugEnabled) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n console.log('[CopilotSDKAdapter]', ...args);\n }\n }\n\n async initialize(): Promise<void> {\n if (this.isInitialized) {\n this.log('Client already initialized, skipping');\n return;\n }\n\n this.log('Starting Copilot client...');\n await this.client.start();\n this.isInitialized = true;\n this.log('Copilot client started successfully');\n }\n\n /**\n * Generate LLM response using Copilot SDK's native tool support\n *\n * Copilot SDK handles:\n * - Tool definition injection\n * - Tool call generation\n * - Tool execution via handlers\n * - Multi-turn tool calling loop\n *\n * Architecture notes:\n * - Creates a disposable session for each call\n * - Session is destroyed after use (in finally block)\n * - Tool calls are tracked via onPostToolUse hook\n * - Returns toolCalls array marked as already executed\n */\n async generate(\n messages: Message[],\n tools?: Tool[],\n _config?: GenerationConfig,\n ctx?: ExecutionContext\n ): Promise<LLMResponse> {\n if (!this.isInitialized) {\n await this.initialize();\n }\n\n // Store context for tool handlers\n this.currentContext = ctx;\n\n // Reset tool call history for this generation\n this.toolCallHistory = [];\n\n const startTime = Date.now();\n\n // Disposable session pattern: create new session for each call\n const sessionId = `deity-session-${Date.now()}-${this.sessionCounter++}`;\n this.log('Creating disposable session:', sessionId);\n\n // Convert Deity tools to Copilot SDK tools\n const copilotTools = tools ? this.convertTools(tools) : undefined;\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access\n const toolNames = copilotTools?.map((t) => (t as any).name) || [];\n\n this.log('Session tools:', {\n count: toolNames.length,\n names: toolNames,\n });\n\n // Create session with hooks to track tool calls\n const sessionConfig: any = {\n sessionId,\n model: this.model,\n tools: copilotTools,\n // Exclude ALL environment tools to ensure only registered tools are used\n excludedTools: [\n 'bash',\n 'write_bash',\n 'read_bash',\n 'stop_bash',\n 'list_bash',\n 'shell',\n 'view',\n 'create',\n 'edit',\n 'web_fetch',\n 'report_intent',\n 'read_file',\n 'write_file',\n 'sql',\n 'read_agent',\n 'list_agents',\n 'grep',\n 'glob',\n 'task',\n ],\n // Add hooks to track tool calls for Deity compatibility\n hooks: {\n onPostToolUse: (input: any) => {\n // Record tool call in history with execution metadata\n const toolCall: any = {\n id: `call_${Date.now()}_${Math.random().toString(36).slice(2)}`,\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access\n name: input.toolName,\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access\n arguments: input.toolArgs,\n _alreadyExecuted: true, // Mark as already executed by SDK\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n _executionResult: JSON.stringify(input.toolResult), // Store result for reference\n };\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n this.toolCallHistory.push(toolCall);\n\n this.log('Tool call tracked:', {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access\n name: input.toolName,\n totalCalls: this.toolCallHistory.length,\n });\n\n // Don't modify anything, just track\n return undefined;\n },\n },\n };\n\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n const session = await this.client.createSession(sessionConfig);\n this.log('Session created:', sessionId);\n\n try {\n // Convert ALL messages to prompt (including system messages)\n const prompt = this.messagesToPrompt(messages);\n\n this.log('Sending prompt:', {\n promptLength: prompt.length,\n sessionId: session.sessionId,\n toolsCount: tools?.length || 0,\n });\n\n let responseContent = '';\n\n // Use sendAndWait() to get the response\n try {\n const result = await session.sendAndWait({ prompt }, 12000000); // 12000s timeout\n\n if (result) {\n responseContent = result.data.content || '';\n this.log('Response received:', {\n length: responseContent.length,\n });\n }\n } catch (error: any) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n console.error('[CopilotSDKAdapter] sendAndWait error:', error.message);\n throw error;\n }\n\n const elapsed = Date.now() - startTime;\n this.log(`API response received in ${elapsed}ms`);\n\n if (this.toolCallHistory.length > 0) {\n this.log(`Session executed ${this.toolCallHistory.length} tool calls`);\n }\n\n // Return result with toolCalls marked as already executed\n // Deity llm-loop will check _alreadyExecuted flag and skip re-execution\n const response: LLMResponse = {\n content: responseContent,\n toolCalls: this.toolCallHistory.length > 0 ? this.toolCallHistory : undefined,\n };\n\n return response;\n } catch (error) {\n // Clean up session on error\n await session.destroy();\n throw error;\n } finally {\n // Always destroy disposable session\n await session.destroy();\n this.log('Session destroyed:', sessionId);\n }\n }\n\n /**\n * Convert Deity Tool to Copilot SDK Tool using defineTool\n *\n * Uses SDK's defineTool() function which properly registers tools.\n * Zod schemas are passed directly - Zod v4 has native toJSONSchema() method.\n */\n private convertTools(deityTools: Tool[]): CopilotTool[] {\n this.log('Converting Deity tools to Copilot SDK format:', {\n count: deityTools.length,\n names: deityTools.map((t) => t.name),\n });\n\n const converted = deityTools.map((tool) => {\n // Pass Zod schema directly - Zod v4 has native toJSONSchema() method\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n const parameters = tool.inputSchema as any;\n\n // Use SDK's defineTool function (critical for proper registration)\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-return\n return defineTool(tool.name, {\n description: tool.description || `Tool: ${tool.name}`,\n parameters,\n handler: async (args: unknown) => {\n this.log('Executing tool via SDK handler:', {\n name: tool.name,\n });\n\n try {\n if (!this.currentContext) {\n throw new Error('Execution context not available for tool handler');\n }\n\n // Execute Deity tool\n const result = await tool.execute(args, this.currentContext);\n\n this.log('Tool execution successful:', tool.name);\n\n // Return result in format expected by Copilot SDK\n return typeof result === 'string' ? result : JSON.stringify(result);\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error);\n console.error('[CopilotSDKAdapter] Tool execution failed:', {\n tool: tool.name,\n error: errorMsg,\n });\n\n // Return error result\n return JSON.stringify({\n success: false,\n error: errorMsg,\n });\n }\n },\n });\n });\n\n this.log('Tool conversion complete:', {\n convertedCount: converted.length,\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access\n toolNames: converted.map((t: any) => t.name || 'unknown'),\n });\n\n return converted;\n }\n\n /**\n * Convert Deity messages to Copilot prompt format\n *\n * Note: Copilot SDK uses a simple string prompt format.\n * All message types are concatenated into a single prompt.\n */\n private messagesToPrompt(messages: Message[]): string {\n let prompt = '';\n\n for (const msg of messages) {\n switch (msg.role) {\n case 'system':\n prompt += msg.content + '\\n\\n';\n break;\n case 'user':\n prompt += `User: ${msg.content}\\n\\n`;\n break;\n case 'assistant':\n prompt += `Assistant: ${msg.content}\\n\\n`;\n break;\n case 'tool':\n // Skip tool messages - SDK handles them internally\n break;\n }\n }\n\n return prompt;\n }\n\n async cleanup(): Promise<void> {\n if (!this.isInitialized) {\n return;\n }\n\n // No sessions to clean up (disposable session pattern)\n this.log('Stopping Copilot client...');\n await this.client.stop();\n this.isInitialized = false;\n this.log('Copilot client stopped');\n }\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,80 @@
1
+ {
2
+ "name": "@limo-labs/deity-adapter-copilot",
3
+ "version": "0.1.0-alpha.1",
4
+ "description": "GitHub Copilot SDK adapter for Deity framework",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "files": [
10
+ "dist",
11
+ "README.md"
12
+ ],
13
+ "publishConfig": {
14
+ "access": "public"
15
+ },
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "https://github.com/Limo-Deity/Limo-Deity.git",
19
+ "directory": "packages/adapter-copilot"
20
+ },
21
+ "bugs": {
22
+ "url": "https://github.com/Limo-Deity/Limo-Deity/issues"
23
+ },
24
+ "homepage": "https://github.com/Limo-Deity/Limo-Deity/tree/main/packages/adapter-copilot#readme",
25
+ "exports": {
26
+ ".": {
27
+ "require": {
28
+ "types": "./dist/index.d.cts",
29
+ "default": "./dist/index.cjs"
30
+ },
31
+ "import": {
32
+ "types": "./dist/index.d.ts",
33
+ "default": "./dist/index.js"
34
+ }
35
+ }
36
+ },
37
+ "scripts": {
38
+ "build": "tsup",
39
+ "prepublishOnly": "npm run build",
40
+ "test": "vitest run",
41
+ "test:watch": "vitest watch",
42
+ "test:coverage": "vitest run --coverage",
43
+ "type-check": "tsc --noEmit",
44
+ "lint": "eslint src --ext .ts",
45
+ "lint:fix": "eslint src --ext .ts --fix",
46
+ "format": "prettier --write \"src/**/*.ts\"",
47
+ "format:check": "prettier --check \"src/**/*.ts\""
48
+ },
49
+ "keywords": [
50
+ "deity",
51
+ "adapter",
52
+ "copilot",
53
+ "github",
54
+ "llm",
55
+ "ai"
56
+ ],
57
+ "author": "Limo Labs",
58
+ "license": "MIT",
59
+ "peerDependencies": {
60
+ "@limo-labs/deity": "^0.1.3-alpha.2",
61
+ "@github/copilot-sdk": "^0.1.25"
62
+ },
63
+ "devDependencies": {
64
+ "@limo-labs/deity": "^0.1.3-alpha.2",
65
+ "@github/copilot-sdk": "^0.1.25",
66
+ "@types/node": "^20.11.0",
67
+ "@typescript-eslint/eslint-plugin": "^6.19.0",
68
+ "@typescript-eslint/parser": "^6.19.0",
69
+ "@vitest/coverage-v8": "^1.2.0",
70
+ "eslint": "^8.56.0",
71
+ "prettier": "^3.2.4",
72
+ "tsup": "^8.0.1",
73
+ "tsx": "^4.7.0",
74
+ "typescript": "^5.3.3",
75
+ "vitest": "^1.2.0"
76
+ },
77
+ "engines": {
78
+ "node": ">=18.0.0"
79
+ }
80
+ }