@ikyyofc/gemini-cli 4.0.8 → 4.0.9
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/package.json +1 -1
- package/src/agent.js +51 -41
package/package.json
CHANGED
package/src/agent.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
// src/agent.js — ReAct agent loop
|
|
1
|
+
// src/agent.js — ReAct agent loop with auto skill injection
|
|
2
2
|
import chalk from "chalk";
|
|
3
3
|
import { callGemini } from "./gemini.js";
|
|
4
4
|
import { GEMINI_TOOLS, FUNCTION_DECLARATIONS, executeTool } from "./tools.js";
|
|
5
5
|
import { Spinner } from "./utils/spinner.js";
|
|
6
|
-
import { loadSkills
|
|
6
|
+
import { loadSkills } from "./skills.js";
|
|
7
7
|
import {
|
|
8
8
|
printAssistant, printError, printWarning,
|
|
9
9
|
printToolCall, printToolResult,
|
|
@@ -13,55 +13,61 @@ import {
|
|
|
13
13
|
const TIMEOUT_MS = 10 * 60 * 1000;
|
|
14
14
|
|
|
15
15
|
// ─────────────────────────────────────────────────────────────────
|
|
16
|
-
//
|
|
16
|
+
// Auto-inject relevant skill content into conversation
|
|
17
|
+
// This happens BEFORE the first LLM call — model has no choice
|
|
18
|
+
// but to see and follow the skill instructions.
|
|
19
|
+
// ─────────────────────────────────────────────────────────────────
|
|
20
|
+
function injectSkills(userMessage, messages) {
|
|
21
|
+
const skills = loadSkills();
|
|
22
|
+
if (!skills.length) return messages;
|
|
23
|
+
|
|
24
|
+
const query = userMessage.toLowerCase();
|
|
25
|
+
const words = query.split(/\s+/).filter(w => w.length > 3);
|
|
26
|
+
|
|
27
|
+
// Score each skill by keyword match
|
|
28
|
+
const scored = skills.map(skill => {
|
|
29
|
+
const hay = (skill.name + " " + skill.slug + " " + skill.content.slice(0, 400)).toLowerCase();
|
|
30
|
+
const hits = words.filter(w => hay.includes(w)).length;
|
|
31
|
+
return { skill, hits };
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
// Use matched skills, or ALL skills if none matched (task is ambiguous)
|
|
35
|
+
const matched = scored.filter(s => s.hits > 0).map(s => s.skill);
|
|
36
|
+
const toInject = matched.length > 0 ? matched : skills;
|
|
37
|
+
|
|
38
|
+
const block = toInject.map(s =>
|
|
39
|
+
`=== SKILL: ${s.name} ===\n${s.content.trim()}`
|
|
40
|
+
).join("\n\n---\n\n");
|
|
41
|
+
|
|
42
|
+
// Replace the last user message with skill context prepended
|
|
43
|
+
const last = messages[messages.length - 1];
|
|
44
|
+
const newLast = {
|
|
45
|
+
role: "user",
|
|
46
|
+
content: `[SKILLS TO APPLY FOR THIS TASK]\n\n${block}\n\n[END SKILLS]\n\nTask: ${last.content ?? userMessage}`
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
return [...messages.slice(0, -1), newLast];
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// ─────────────────────────────────────────────────────────────────
|
|
53
|
+
// System prompt — clean, no skill listing
|
|
17
54
|
// ─────────────────────────────────────────────────────────────────
|
|
18
55
|
function buildSystemPrompt(extra = "") {
|
|
19
56
|
const toolList = FUNCTION_DECLARATIONS.map(t => `- ${t.name}: ${t.description}`).join("\n");
|
|
20
|
-
const skills = loadSkills();
|
|
21
|
-
|
|
22
57
|
const now = new Date();
|
|
23
58
|
const tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
24
59
|
const datetime = now.toLocaleString("id-ID", { timeZone: tz, dateStyle: "full", timeStyle: "long" });
|
|
25
60
|
|
|
26
|
-
// Build skill section
|
|
27
|
-
let skillSection = "";
|
|
28
|
-
if (skills.length) {
|
|
29
|
-
const index = skills.map(s => {
|
|
30
|
-
const desc = s.content.split("\n").find(l => l.trim() && !l.startsWith("#")) ?? "";
|
|
31
|
-
return ` - ${s.slug}: ${desc.slice(0, 80)}`;
|
|
32
|
-
}).join("\n");
|
|
33
|
-
|
|
34
|
-
skillSection = `
|
|
35
|
-
## SKILLS — MANDATORY
|
|
36
|
-
You have skills installed. Skills contain expert instructions for specific tasks.
|
|
37
|
-
|
|
38
|
-
**RULE: You MUST read the relevant skill file BEFORE starting any task.**
|
|
39
|
-
Do NOT proceed with a task until you have read the applicable skill(s).
|
|
40
|
-
|
|
41
|
-
Steps:
|
|
42
|
-
1. Look at the installed skills below
|
|
43
|
-
2. Identify which skill(s) apply to the current task
|
|
44
|
-
3. Use read_file to load the skill: read_file("${SKILLS_DIR}/<slug>/SKILL.md")
|
|
45
|
-
4. Follow the skill's instructions exactly
|
|
46
|
-
5. Only then proceed with the task
|
|
47
|
-
|
|
48
|
-
Installed skills:
|
|
49
|
-
${index}
|
|
50
|
-
|
|
51
|
-
Skills directory: ${SKILLS_DIR}`;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
61
|
return `You are an autonomous AI coding agent running in the user's terminal.
|
|
55
62
|
|
|
56
63
|
## CURRENT TIME
|
|
57
64
|
${datetime} (${tz})
|
|
58
|
-
${skillSection}
|
|
59
65
|
|
|
60
66
|
## CORE RULE — NEVER ASK, ALWAYS ACT
|
|
61
67
|
Use tools to complete every task. Never instruct the user to do anything themselves.
|
|
62
68
|
|
|
63
69
|
## WORKFLOW
|
|
64
|
-
|
|
70
|
+
1. EXPLORE — understand the project structure
|
|
65
71
|
2. ACT — complete the task fully using tools
|
|
66
72
|
3. VERIFY — test after changes
|
|
67
73
|
4. REPORT — brief summary
|
|
@@ -71,7 +77,7 @@ ${toolList}
|
|
|
71
77
|
|
|
72
78
|
## RULES
|
|
73
79
|
- Always read files before editing them
|
|
74
|
-
- Use patch_file for targeted edits
|
|
80
|
+
- Use patch_file for targeted edits
|
|
75
81
|
- Verify code works after changes
|
|
76
82
|
- If a command fails, diagnose and retry
|
|
77
83
|
- Platform: ${process.platform} | CWD: ${process.cwd()}
|
|
@@ -101,10 +107,14 @@ export async function runAgentLoop(userMessage, history, {
|
|
|
101
107
|
} = {}) {
|
|
102
108
|
|
|
103
109
|
const fullSystem = buildSystemPrompt(systemInstruction ?? "");
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
110
|
+
|
|
111
|
+
// Build messages and auto-inject relevant skills
|
|
112
|
+
let messages = [...history, { role: "user", content: userMessage }];
|
|
113
|
+
messages = injectSkills(userMessage, messages);
|
|
114
|
+
|
|
115
|
+
const spinner = new Spinner();
|
|
116
|
+
const deadline = Date.now() + TIMEOUT_MS;
|
|
117
|
+
let iteration = 0;
|
|
108
118
|
|
|
109
119
|
while (true) {
|
|
110
120
|
if (Date.now() > deadline) {
|
|
@@ -156,7 +166,7 @@ export async function runAgentLoop(userMessage, history, {
|
|
|
156
166
|
}
|
|
157
167
|
|
|
158
168
|
// ── Tool calls ─────────────────────────────────────────────
|
|
159
|
-
// Push ALL parts
|
|
169
|
+
// Push ALL parts including thinking into history — maintains context continuity
|
|
160
170
|
messages.push({ role: "model", parts });
|
|
161
171
|
|
|
162
172
|
printStepHeader(iteration);
|