ak-gemini 2.1.1 → 2.1.5
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/chat.js +29 -0
- package/code-agent.js +44 -3
- package/index.cjs +60 -2
- package/package.json +1 -1
- package/types.d.ts +31 -2
package/chat.js
CHANGED
|
@@ -9,6 +9,7 @@ import log from './logger.js';
|
|
|
9
9
|
/**
|
|
10
10
|
* @typedef {import('./types').ChatOptions} ChatOptions
|
|
11
11
|
* @typedef {import('./types').ChatResponse} ChatResponse
|
|
12
|
+
* @typedef {import('./types').ChatStreamEvent} ChatStreamEvent
|
|
12
13
|
*/
|
|
13
14
|
|
|
14
15
|
/**
|
|
@@ -82,6 +83,34 @@ class Chat extends BaseGemini {
|
|
|
82
83
|
usage: this.getLastUsage()
|
|
83
84
|
};
|
|
84
85
|
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Send a message and stream the response as events.
|
|
89
|
+
*
|
|
90
|
+
* @param {string} message - The user's message
|
|
91
|
+
* @param {Object} [opts={}] - Per-message options
|
|
92
|
+
* @yields {ChatStreamEvent}
|
|
93
|
+
*/
|
|
94
|
+
async *stream(message, opts = {}) {
|
|
95
|
+
if (!this.chatSession) await this.init();
|
|
96
|
+
|
|
97
|
+
let fullText = '';
|
|
98
|
+
const streamResponse = await this._withRetry(() => this.chatSession.sendMessageStream({ message }));
|
|
99
|
+
|
|
100
|
+
for await (const chunk of streamResponse) {
|
|
101
|
+
if (chunk.candidates?.[0]?.content?.parts?.[0]?.text) {
|
|
102
|
+
const text = chunk.candidates[0].content.parts[0].text;
|
|
103
|
+
fullText += text;
|
|
104
|
+
yield { type: 'text', text };
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
yield {
|
|
109
|
+
type: 'done',
|
|
110
|
+
fullText,
|
|
111
|
+
usage: this.getLastUsage()
|
|
112
|
+
};
|
|
113
|
+
}
|
|
85
114
|
}
|
|
86
115
|
|
|
87
116
|
export default Chat;
|
package/code-agent.js
CHANGED
|
@@ -8,7 +8,7 @@ import BaseGemini from './base.js';
|
|
|
8
8
|
import log from './logger.js';
|
|
9
9
|
import { execFile } from 'node:child_process';
|
|
10
10
|
import { writeFile, unlink, readdir, readFile, mkdir } from 'node:fs/promises';
|
|
11
|
-
import { join, sep, basename } from 'node:path';
|
|
11
|
+
import { join, sep, basename, isAbsolute } from 'node:path';
|
|
12
12
|
import { randomUUID } from 'node:crypto';
|
|
13
13
|
|
|
14
14
|
/**
|
|
@@ -49,6 +49,17 @@ class CodeAgent extends BaseGemini {
|
|
|
49
49
|
this.skills = options.skills || [];
|
|
50
50
|
this.envOverview = options.envOverview || '';
|
|
51
51
|
|
|
52
|
+
// ── Custom tools ──
|
|
53
|
+
this.customTools = (options.tools || []).map(t => ({
|
|
54
|
+
name: t.name,
|
|
55
|
+
description: t.description,
|
|
56
|
+
parametersJsonSchema: t.parametersJsonSchema || t.parameters || t.input_schema || t.inputSchema
|
|
57
|
+
}));
|
|
58
|
+
this.toolExecutor = options.toolExecutor || null;
|
|
59
|
+
if (this.customTools.length > 0 && !this.toolExecutor) {
|
|
60
|
+
throw new Error('CodeAgent: tools provided without a toolExecutor.');
|
|
61
|
+
}
|
|
62
|
+
|
|
52
63
|
// ── Internal state ──
|
|
53
64
|
this._codebaseContext = null;
|
|
54
65
|
this._contextGathered = false;
|
|
@@ -156,6 +167,11 @@ class CodeAgent extends BaseGemini {
|
|
|
156
167
|
});
|
|
157
168
|
}
|
|
158
169
|
|
|
170
|
+
// Append custom tools
|
|
171
|
+
for (const t of this.customTools) {
|
|
172
|
+
declarations.push({ name: t.name, description: t.description, parametersJsonSchema: t.parametersJsonSchema });
|
|
173
|
+
}
|
|
174
|
+
|
|
159
175
|
return { functionDeclarations: declarations };
|
|
160
176
|
}
|
|
161
177
|
|
|
@@ -252,7 +268,7 @@ class CodeAgent extends BaseGemini {
|
|
|
252
268
|
continue;
|
|
253
269
|
}
|
|
254
270
|
try {
|
|
255
|
-
const fullPath = join(this.workingDirectory, resolved);
|
|
271
|
+
const fullPath = isAbsolute(resolved) ? resolved : join(this.workingDirectory, resolved);
|
|
256
272
|
const content = await readFile(fullPath, 'utf-8');
|
|
257
273
|
importantFileContents.push({ path: resolved, content });
|
|
258
274
|
} catch (e) {
|
|
@@ -269,6 +285,8 @@ class CodeAgent extends BaseGemini {
|
|
|
269
285
|
* @private
|
|
270
286
|
*/
|
|
271
287
|
_resolveImportantFile(filename, fileTreeLines) {
|
|
288
|
+
if (isAbsolute(filename)) return filename;
|
|
289
|
+
|
|
272
290
|
const exact = fileTreeLines.find(line => line === filename);
|
|
273
291
|
if (exact) return exact;
|
|
274
292
|
|
|
@@ -651,12 +669,30 @@ These rules apply when using execute_code, write_and_run_code, or fix_code (with
|
|
|
651
669
|
data: { tool: 'use_skill', skillName: skill.name, content: skill.content, found: true }
|
|
652
670
|
};
|
|
653
671
|
}
|
|
654
|
-
default:
|
|
672
|
+
default: {
|
|
673
|
+
if (this.toolExecutor) {
|
|
674
|
+
try {
|
|
675
|
+
const result = await this.toolExecutor(name, input);
|
|
676
|
+
const resultStr = typeof result === 'string' ? result : JSON.stringify(result);
|
|
677
|
+
return {
|
|
678
|
+
output: resultStr,
|
|
679
|
+
type: 'tool',
|
|
680
|
+
data: { tool: name, args: input, result }
|
|
681
|
+
};
|
|
682
|
+
} catch (err) {
|
|
683
|
+
return {
|
|
684
|
+
output: `Tool "${name}" failed: ${err.message}`,
|
|
685
|
+
type: 'tool',
|
|
686
|
+
data: { tool: name, args: input, error: err.message }
|
|
687
|
+
};
|
|
688
|
+
}
|
|
689
|
+
}
|
|
655
690
|
return {
|
|
656
691
|
output: `Unknown tool: ${name}`,
|
|
657
692
|
type: 'unknown',
|
|
658
693
|
data: { tool: name }
|
|
659
694
|
};
|
|
695
|
+
}
|
|
660
696
|
}
|
|
661
697
|
}
|
|
662
698
|
|
|
@@ -859,6 +895,11 @@ These rules apply when using execute_code, write_and_run_code, or fix_code (with
|
|
|
859
895
|
yield { type: 'skill', skillName: data.skillName, content: data.content, found: data.found };
|
|
860
896
|
}
|
|
861
897
|
|
|
898
|
+
// Emit custom tool event
|
|
899
|
+
if (type === 'tool') {
|
|
900
|
+
yield { type: 'tool', toolName, args: data.args, result: data.result, error: data.error };
|
|
901
|
+
}
|
|
902
|
+
|
|
862
903
|
// Track consecutive failures
|
|
863
904
|
const isExecutingTool = EXECUTING_TOOLS.has(toolName) || (toolName === 'fix_code' && toolInput.execute);
|
|
864
905
|
if (isExecutingTool) {
|
package/index.cjs
CHANGED
|
@@ -1216,6 +1216,30 @@ var Chat = class extends base_default {
|
|
|
1216
1216
|
usage: this.getLastUsage()
|
|
1217
1217
|
};
|
|
1218
1218
|
}
|
|
1219
|
+
/**
|
|
1220
|
+
* Send a message and stream the response as events.
|
|
1221
|
+
*
|
|
1222
|
+
* @param {string} message - The user's message
|
|
1223
|
+
* @param {Object} [opts={}] - Per-message options
|
|
1224
|
+
* @yields {ChatStreamEvent}
|
|
1225
|
+
*/
|
|
1226
|
+
async *stream(message, opts = {}) {
|
|
1227
|
+
if (!this.chatSession) await this.init();
|
|
1228
|
+
let fullText = "";
|
|
1229
|
+
const streamResponse = await this._withRetry(() => this.chatSession.sendMessageStream({ message }));
|
|
1230
|
+
for await (const chunk of streamResponse) {
|
|
1231
|
+
if (chunk.candidates?.[0]?.content?.parts?.[0]?.text) {
|
|
1232
|
+
const text = chunk.candidates[0].content.parts[0].text;
|
|
1233
|
+
fullText += text;
|
|
1234
|
+
yield { type: "text", text };
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
yield {
|
|
1238
|
+
type: "done",
|
|
1239
|
+
fullText,
|
|
1240
|
+
usage: this.getLastUsage()
|
|
1241
|
+
};
|
|
1242
|
+
}
|
|
1219
1243
|
};
|
|
1220
1244
|
var chat_default = Chat;
|
|
1221
1245
|
|
|
@@ -1625,6 +1649,15 @@ var CodeAgent = class extends base_default {
|
|
|
1625
1649
|
this.maxRetries = options.maxRetries ?? 3;
|
|
1626
1650
|
this.skills = options.skills || [];
|
|
1627
1651
|
this.envOverview = options.envOverview || "";
|
|
1652
|
+
this.customTools = (options.tools || []).map((t) => ({
|
|
1653
|
+
name: t.name,
|
|
1654
|
+
description: t.description,
|
|
1655
|
+
parametersJsonSchema: t.parametersJsonSchema || t.parameters || t.input_schema || t.inputSchema
|
|
1656
|
+
}));
|
|
1657
|
+
this.toolExecutor = options.toolExecutor || null;
|
|
1658
|
+
if (this.customTools.length > 0 && !this.toolExecutor) {
|
|
1659
|
+
throw new Error("CodeAgent: tools provided without a toolExecutor.");
|
|
1660
|
+
}
|
|
1628
1661
|
this._codebaseContext = null;
|
|
1629
1662
|
this._contextGathered = false;
|
|
1630
1663
|
this._stopped = false;
|
|
@@ -1722,6 +1755,9 @@ var CodeAgent = class extends base_default {
|
|
|
1722
1755
|
}
|
|
1723
1756
|
});
|
|
1724
1757
|
}
|
|
1758
|
+
for (const t of this.customTools) {
|
|
1759
|
+
declarations.push({ name: t.name, description: t.description, parametersJsonSchema: t.parametersJsonSchema });
|
|
1760
|
+
}
|
|
1725
1761
|
return { functionDeclarations: declarations };
|
|
1726
1762
|
}
|
|
1727
1763
|
// ── Init ─────────────────────────────────────────────────────────────────
|
|
@@ -1799,7 +1835,7 @@ var CodeAgent = class extends base_default {
|
|
|
1799
1835
|
continue;
|
|
1800
1836
|
}
|
|
1801
1837
|
try {
|
|
1802
|
-
const fullPath = (0, import_node_path.join)(this.workingDirectory, resolved);
|
|
1838
|
+
const fullPath = (0, import_node_path.isAbsolute)(resolved) ? resolved : (0, import_node_path.join)(this.workingDirectory, resolved);
|
|
1803
1839
|
const content = await (0, import_promises2.readFile)(fullPath, "utf-8");
|
|
1804
1840
|
importantFileContents.push({ path: resolved, content });
|
|
1805
1841
|
} catch (e) {
|
|
@@ -1814,6 +1850,7 @@ var CodeAgent = class extends base_default {
|
|
|
1814
1850
|
* @private
|
|
1815
1851
|
*/
|
|
1816
1852
|
_resolveImportantFile(filename, fileTreeLines) {
|
|
1853
|
+
if ((0, import_node_path.isAbsolute)(filename)) return filename;
|
|
1817
1854
|
const exact = fileTreeLines.find((line) => line === filename);
|
|
1818
1855
|
if (exact) return exact;
|
|
1819
1856
|
const partial = fileTreeLines.find(
|
|
@@ -2210,12 +2247,30 @@ ${this.envOverview}`;
|
|
|
2210
2247
|
data: { tool: "use_skill", skillName: skill.name, content: skill.content, found: true }
|
|
2211
2248
|
};
|
|
2212
2249
|
}
|
|
2213
|
-
default:
|
|
2250
|
+
default: {
|
|
2251
|
+
if (this.toolExecutor) {
|
|
2252
|
+
try {
|
|
2253
|
+
const result = await this.toolExecutor(name, input);
|
|
2254
|
+
const resultStr = typeof result === "string" ? result : JSON.stringify(result);
|
|
2255
|
+
return {
|
|
2256
|
+
output: resultStr,
|
|
2257
|
+
type: "tool",
|
|
2258
|
+
data: { tool: name, args: input, result }
|
|
2259
|
+
};
|
|
2260
|
+
} catch (err) {
|
|
2261
|
+
return {
|
|
2262
|
+
output: `Tool "${name}" failed: ${err.message}`,
|
|
2263
|
+
type: "tool",
|
|
2264
|
+
data: { tool: name, args: input, error: err.message }
|
|
2265
|
+
};
|
|
2266
|
+
}
|
|
2267
|
+
}
|
|
2214
2268
|
return {
|
|
2215
2269
|
output: `Unknown tool: ${name}`,
|
|
2216
2270
|
type: "unknown",
|
|
2217
2271
|
data: { tool: name }
|
|
2218
2272
|
};
|
|
2273
|
+
}
|
|
2219
2274
|
}
|
|
2220
2275
|
}
|
|
2221
2276
|
// ── Non-Streaming Chat ───────────────────────────────────────────────────
|
|
@@ -2372,6 +2427,9 @@ ${this.envOverview}`;
|
|
|
2372
2427
|
if (toolName === "use_skill") {
|
|
2373
2428
|
yield { type: "skill", skillName: data.skillName, content: data.content, found: data.found };
|
|
2374
2429
|
}
|
|
2430
|
+
if (type === "tool") {
|
|
2431
|
+
yield { type: "tool", toolName, args: data.args, result: data.result, error: data.error };
|
|
2432
|
+
}
|
|
2375
2433
|
const isExecutingTool = EXECUTING_TOOLS.has(toolName) || toolName === "fix_code" && toolInput.execute;
|
|
2376
2434
|
if (isExecutingTool) {
|
|
2377
2435
|
if (data.exitCode !== 0 && !data.denied) {
|
package/package.json
CHANGED
package/types.d.ts
CHANGED
|
@@ -324,6 +324,17 @@ export interface CodeAgentOptions extends BaseGeminiOptions {
|
|
|
324
324
|
skills?: string[];
|
|
325
325
|
/** Plain text environment overview appended to the system prompt — describe the project, stack, conventions, etc. */
|
|
326
326
|
envOverview?: string;
|
|
327
|
+
/** Custom tool declarations to add alongside built-in CodeAgent tools. Accepts Gemini, Claude, or OpenAI tool formats (auto-mapped). */
|
|
328
|
+
tools?: Array<{
|
|
329
|
+
name: string;
|
|
330
|
+
description: string;
|
|
331
|
+
parametersJsonSchema?: any;
|
|
332
|
+
parameters?: any;
|
|
333
|
+
input_schema?: any;
|
|
334
|
+
inputSchema?: any;
|
|
335
|
+
}>;
|
|
336
|
+
/** Function to execute custom tool calls: (toolName, args) => result */
|
|
337
|
+
toolExecutor?: (toolName: string, args: Record<string, any>) => Promise<any>;
|
|
327
338
|
}
|
|
328
339
|
|
|
329
340
|
export interface CodeExecution {
|
|
@@ -340,7 +351,7 @@ export interface CodeExecution {
|
|
|
340
351
|
}
|
|
341
352
|
|
|
342
353
|
export interface ToolCallResult {
|
|
343
|
-
tool: 'write_code' | 'execute_code' | 'write_and_run_code' | 'fix_code' | 'run_bash' | 'use_skill';
|
|
354
|
+
tool: 'write_code' | 'execute_code' | 'write_and_run_code' | 'fix_code' | 'run_bash' | 'use_skill' | string;
|
|
344
355
|
code?: string;
|
|
345
356
|
purpose?: string;
|
|
346
357
|
language?: string;
|
|
@@ -370,7 +381,7 @@ export interface CodeAgentResponse {
|
|
|
370
381
|
}
|
|
371
382
|
|
|
372
383
|
export interface CodeAgentStreamEvent {
|
|
373
|
-
type: 'text' | 'code' | 'output' | 'write' | 'fix' | 'bash' | 'skill' | 'done';
|
|
384
|
+
type: 'text' | 'code' | 'output' | 'write' | 'fix' | 'bash' | 'skill' | 'tool' | 'done';
|
|
374
385
|
text?: string;
|
|
375
386
|
code?: string;
|
|
376
387
|
stdout?: string;
|
|
@@ -390,6 +401,14 @@ export interface CodeAgentStreamEvent {
|
|
|
390
401
|
skillName?: string;
|
|
391
402
|
content?: string;
|
|
392
403
|
found?: boolean;
|
|
404
|
+
/** custom tool: tool name */
|
|
405
|
+
toolName?: string;
|
|
406
|
+
/** custom tool: arguments passed */
|
|
407
|
+
args?: Record<string, any>;
|
|
408
|
+
/** custom tool: result returned */
|
|
409
|
+
result?: any;
|
|
410
|
+
/** custom tool: error message (if failed) */
|
|
411
|
+
error?: string;
|
|
393
412
|
}
|
|
394
413
|
|
|
395
414
|
// ── Per-Message Options ──────────────────────────────────────────────────────
|
|
@@ -421,6 +440,13 @@ export interface ChatResponse {
|
|
|
421
440
|
usage: UsageData | null;
|
|
422
441
|
}
|
|
423
442
|
|
|
443
|
+
export interface ChatStreamEvent {
|
|
444
|
+
type: 'text' | 'done';
|
|
445
|
+
text?: string;
|
|
446
|
+
fullText?: string;
|
|
447
|
+
usage?: UsageData | null;
|
|
448
|
+
}
|
|
449
|
+
|
|
424
450
|
export interface MessageResponse {
|
|
425
451
|
/** The model's text response */
|
|
426
452
|
text: string;
|
|
@@ -548,6 +574,7 @@ export declare class Chat extends BaseGemini {
|
|
|
548
574
|
constructor(options?: ChatOptions);
|
|
549
575
|
|
|
550
576
|
send(message: string, opts?: { labels?: Record<string, string> }): Promise<ChatResponse>;
|
|
577
|
+
stream(message: string, opts?: { labels?: Record<string, string> }): AsyncGenerator<ChatStreamEvent, void, unknown>;
|
|
551
578
|
}
|
|
552
579
|
|
|
553
580
|
export declare class Message extends BaseGemini {
|
|
@@ -617,6 +644,8 @@ export declare class CodeAgent extends BaseGemini {
|
|
|
617
644
|
maxRetries: number;
|
|
618
645
|
skills: string[];
|
|
619
646
|
envOverview: string;
|
|
647
|
+
customTools: Array<{ name: string; description: string; parametersJsonSchema: any }>;
|
|
648
|
+
toolExecutor: ((toolName: string, args: Record<string, any>) => Promise<any>) | null;
|
|
620
649
|
|
|
621
650
|
init(force?: boolean): Promise<void>;
|
|
622
651
|
chat(message: string, opts?: { labels?: Record<string, string> }): Promise<CodeAgentResponse>;
|