glitool 1.0.0 → 1.0.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 +5 -2
- package/dist/agent.js +5 -3
- package/dist/agents/coder.js +1 -1
- package/dist/agents/planner.js +4 -2
- package/dist/agents/reviewer.js +1 -1
- package/dist/llm/router.js +67 -15
- package/dist/llm/telemetry.js +18 -0
- package/dist/tools/writeFileTool.js +0 -1
- package/package.json +52 -47
package/README.md
CHANGED
|
@@ -40,6 +40,9 @@ glitool config --show
|
|
|
40
40
|
| /exit | Save and exit |
|
|
41
41
|
|
|
42
42
|
## Requirements
|
|
43
|
+
- Node.js 22 or higher
|
|
44
|
+
- npm install -g glitool
|
|
43
45
|
|
|
44
|
-
|
|
45
|
-
-
|
|
46
|
+
|
|
47
|
+
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
|
|
48
|
+
sudo apt-get install -y nodejs
|
package/dist/agent.js
CHANGED
|
@@ -9,7 +9,8 @@ import { loadProjectMemory } from "./projectMemory.js";
|
|
|
9
9
|
import { config as loadEnv } from 'dotenv';
|
|
10
10
|
import { fileURLToPath } from 'url';
|
|
11
11
|
import { dirname, join } from 'path';
|
|
12
|
-
import {
|
|
12
|
+
import { route } from './llm/router.js';
|
|
13
|
+
import { logRouting } from './llm/telemetry.js';
|
|
13
14
|
import { runAgentGraph } from "./agents/graph.js";
|
|
14
15
|
import os from 'os';
|
|
15
16
|
const __filename = fileURLToPath(import.meta.url);
|
|
@@ -61,9 +62,10 @@ const complexAgent = createReactAgent({
|
|
|
61
62
|
stateModifier: new SystemMessage(buildSystemPrompt())
|
|
62
63
|
});
|
|
63
64
|
export async function chat(userInput, onToolCall, onStatus, onToken) {
|
|
64
|
-
const
|
|
65
|
+
const decision = route(userInput);
|
|
66
|
+
logRouting(userInput, decision);
|
|
65
67
|
sessionMessages.push(new HumanMessage(userInput));
|
|
66
|
-
if (
|
|
68
|
+
if (decision.domain === 'coding' || decision.tier === 'complex') {
|
|
67
69
|
const result = await runAgentGraph(userInput, buildSystemPrompt(), onToolCall, onStatus ?? (() => { }));
|
|
68
70
|
if (result !== null && result !== undefined) {
|
|
69
71
|
sessionMessages.push(new AIMessage(result));
|
package/dist/agents/coder.js
CHANGED
|
@@ -6,7 +6,7 @@ import { listFilesTool, readFileTool, searchCodeTool, editFileTool, writeFileToo
|
|
|
6
6
|
import { scoreRisk, getRiskMessage } from "../trust/riskScorer.js";
|
|
7
7
|
import { requestConfirm } from "../confirmHandler.js";
|
|
8
8
|
const coderLlm = new ChatOpenAI({
|
|
9
|
-
model: 'gpt-
|
|
9
|
+
model: 'gpt-5.4-mini',
|
|
10
10
|
apiKey: process.env.OPENAI_API_KEY
|
|
11
11
|
});
|
|
12
12
|
const coderAgent = createReactAgent({
|
package/dist/agents/planner.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ChatOpenAI } from "@langchain/openai";
|
|
2
2
|
import { SystemMessage, HumanMessage } from "@langchain/core/messages";
|
|
3
3
|
const plannerLlm = new ChatOpenAI({
|
|
4
|
-
model: 'gpt-
|
|
4
|
+
model: 'gpt-5.4',
|
|
5
5
|
apiKey: process.env.OPENAI_API_KEY
|
|
6
6
|
});
|
|
7
7
|
export async function runPlanner(userMessage, context) {
|
|
@@ -11,7 +11,9 @@ Rules:
|
|
|
11
11
|
- Be specific about which files to read, edit, or create
|
|
12
12
|
- Do NOT write any code — only plan the steps
|
|
13
13
|
- Keep it to 3-6 steps maximum
|
|
14
|
-
- If the task is a
|
|
14
|
+
- If the task is ONLY a question or explanation with NO file creation or code execution needed, output exactly: SIMPLE
|
|
15
|
+
- Any task that requires creating, editing, or writing files must NEVER be SIMPLE
|
|
16
|
+
`),
|
|
15
17
|
new HumanMessage(`Context:\n${context}\n\nUser request: ${userMessage}`)
|
|
16
18
|
]);
|
|
17
19
|
return response.content;
|
package/dist/agents/reviewer.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ChatOpenAI } from "@langchain/openai";
|
|
2
2
|
import { SystemMessage, HumanMessage } from "@langchain/core/messages";
|
|
3
3
|
const reviewerLlm = new ChatOpenAI({
|
|
4
|
-
model: 'gpt-
|
|
4
|
+
model: 'gpt-5.4-mini',
|
|
5
5
|
apiKey: process.env.OPENAI_API_KEY
|
|
6
6
|
});
|
|
7
7
|
export async function runReviewer(plan, coderOutput, userMessage) {
|
package/dist/llm/router.js
CHANGED
|
@@ -1,25 +1,77 @@
|
|
|
1
|
-
const
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
const MODEL_BY_TIER = {
|
|
2
|
+
quick: 'gpt-4o-mini',
|
|
3
|
+
standard: 'gpt-4o-mini',
|
|
4
|
+
complex: 'gpt-4o-mini'
|
|
5
|
+
};
|
|
6
|
+
const CHAT_PATTERNS = [
|
|
7
|
+
/^(hi|hello|hey|thanks|thank you|ok|sure|yes|no|great|awesome)\b/i,
|
|
5
8
|
/^\/\w+/,
|
|
6
9
|
];
|
|
7
|
-
const
|
|
10
|
+
const EXPLANATION_PATTERNS = [
|
|
11
|
+
/^(explain|describe|what is|what are|tell me about|how does|why does|what does)\s/i,
|
|
12
|
+
/^(what|who|when|where|how|why)\s.{0,60}\?$/i,
|
|
13
|
+
];
|
|
14
|
+
const CODING_PATTERNS = [
|
|
8
15
|
/refactor|rewrite|redesign/i,
|
|
9
16
|
/implement|build|create|add|generate/i,
|
|
10
17
|
/fix|debug|solve|resolve/i,
|
|
11
18
|
/optimize|improve|upgrade/i,
|
|
12
19
|
/migrate|convert|transform/i,
|
|
20
|
+
/function|class|component|api|endpoint|hook|module/i,
|
|
21
|
+
];
|
|
22
|
+
const PLANNING_PATTERNS = [
|
|
23
|
+
/architecture|design|system|scalab/i,
|
|
24
|
+
/plan|roadmap|strategy|approach/i,
|
|
25
|
+
/how should (i|we)|what.s the best way/i,
|
|
13
26
|
];
|
|
27
|
+
function detectDomain(prompt) {
|
|
28
|
+
if (CHAT_PATTERNS.some(p => p.test(prompt)))
|
|
29
|
+
return 'chat';
|
|
30
|
+
if (EXPLANATION_PATTERNS.some(p => p.test(prompt)))
|
|
31
|
+
return 'explanation';
|
|
32
|
+
if (CODING_PATTERNS.some(p => p.test(prompt)))
|
|
33
|
+
return 'coding';
|
|
34
|
+
if (PLANNING_PATTERNS.some(p => p.test(prompt)))
|
|
35
|
+
return 'planning';
|
|
36
|
+
return 'chat';
|
|
37
|
+
}
|
|
38
|
+
function scoreComplexity(prompt) {
|
|
39
|
+
let score = 0;
|
|
40
|
+
if (prompt.length > 300)
|
|
41
|
+
score += 1;
|
|
42
|
+
if (prompt.length > 800)
|
|
43
|
+
score += 1;
|
|
44
|
+
if (/```/.test(prompt))
|
|
45
|
+
score += 1;
|
|
46
|
+
if ((prompt.match(/\n/g)?.length ?? 0) > 5)
|
|
47
|
+
score += 1;
|
|
48
|
+
if (PLANNING_PATTERNS.some(p => p.test(prompt)))
|
|
49
|
+
score += 2;
|
|
50
|
+
return score;
|
|
51
|
+
}
|
|
52
|
+
function selectTier(domain, score) {
|
|
53
|
+
if (domain === 'chat')
|
|
54
|
+
return 'quick';
|
|
55
|
+
if (domain === 'explanation' && score <= 1)
|
|
56
|
+
return 'quick';
|
|
57
|
+
if (score >= 3 || domain === 'planning')
|
|
58
|
+
return 'complex';
|
|
59
|
+
return 'standard';
|
|
60
|
+
}
|
|
61
|
+
export function route(prompt) {
|
|
62
|
+
const trimmed = prompt.trim();
|
|
63
|
+
const domain = detectDomain(trimmed);
|
|
64
|
+
const complexityScore = scoreComplexity(trimmed);
|
|
65
|
+
const tier = selectTier(domain, complexityScore);
|
|
66
|
+
return {
|
|
67
|
+
tier,
|
|
68
|
+
domain,
|
|
69
|
+
complexityScore,
|
|
70
|
+
recommendedModel: MODEL_BY_TIER[tier],
|
|
71
|
+
reason: `domain=${domain} score=${complexityScore} tier=${tier}`
|
|
72
|
+
};
|
|
73
|
+
}
|
|
14
74
|
export function detectComplexity(message) {
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
if (pattern.test(trimmed))
|
|
18
|
-
return 'simple';
|
|
19
|
-
}
|
|
20
|
-
for (const pattern of COMPLEX_PATTERNS) {
|
|
21
|
-
if (pattern.test(trimmed))
|
|
22
|
-
return 'complex';
|
|
23
|
-
}
|
|
24
|
-
return trimmed.length > 120 ? 'complex' : 'simple';
|
|
75
|
+
const { domain, tier } = route(message);
|
|
76
|
+
return (domain === 'coding' || tier === 'complex') ? 'complex' : 'simple';
|
|
25
77
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { appendFileSync, mkdirSync } from "fs";
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
import os from 'os';
|
|
4
|
+
export function logRouting(prompt, decision) {
|
|
5
|
+
try {
|
|
6
|
+
const logDir = join(os.homedir(), '.glitool');
|
|
7
|
+
mkdirSync(logDir, { recursive: true });
|
|
8
|
+
const event = {
|
|
9
|
+
timestamp: new Date().toISOString(),
|
|
10
|
+
prompt_length: prompt.length,
|
|
11
|
+
...decision,
|
|
12
|
+
};
|
|
13
|
+
appendFileSync(join(logDir, 'routing.log.jsonl'), JSON.stringify(event) + '\n', 'utf-8');
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
// never crash the tool because of telemetry
|
|
17
|
+
}
|
|
18
|
+
}
|
package/package.json
CHANGED
|
@@ -1,51 +1,56 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "glitool",
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
"
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
"
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
"
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"main": "index.js",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
7
|
+
"build": "tsc",
|
|
8
|
+
"dev": "tsx src/index.ts",
|
|
9
|
+
"prepublishOnly": "npm run build"
|
|
10
|
+
},
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "https://github.com/deep9038/glitool"
|
|
14
|
+
},
|
|
15
|
+
"bin": {
|
|
16
|
+
"glitool": "./dist/index.js"
|
|
17
|
+
},
|
|
18
|
+
"keywords": [
|
|
19
|
+
"ai",
|
|
20
|
+
"cli",
|
|
21
|
+
"coding-assistant",
|
|
22
|
+
"openai",
|
|
23
|
+
"terminal"
|
|
24
|
+
],
|
|
25
|
+
"author": "Deep Sarkar <deep22sarkar@gmail.com>",
|
|
26
|
+
"license": "MIT",
|
|
22
27
|
"description": "AI coding assistant for your terminal",
|
|
23
|
-
"homepage":"https://github.com/deep9038/glitool",
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
28
|
+
"homepage": "https://github.com/deep9038/glitool",
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@inquirer/prompts": "^8.4.1",
|
|
31
|
+
"@langchain/core": "^1.1.40",
|
|
32
|
+
"@langchain/langgraph": "^1.2.9",
|
|
33
|
+
"@langchain/ollama": "^1.2.6",
|
|
34
|
+
"@langchain/openai": "^1.4.4",
|
|
35
|
+
"chalk": "^5.6.2",
|
|
36
|
+
"commander": "^14.0.3",
|
|
37
|
+
"dotenv": "^17.4.2",
|
|
38
|
+
"ink": "^7.0.1",
|
|
39
|
+
"ink-text-input": "^6.0.0",
|
|
40
|
+
"ora": "^9.3.0",
|
|
41
|
+
"react": "^19.2.5"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@types/node": "^25.6.0",
|
|
45
|
+
"@types/react": "^19.2.14",
|
|
46
|
+
"tsx": "^4.21.0",
|
|
47
|
+
"typescript": "^6.0.2"
|
|
48
|
+
},
|
|
49
|
+
"type": "module",
|
|
50
|
+
"engines": {
|
|
51
|
+
"node": ">=22.0.0"
|
|
52
|
+
},
|
|
53
|
+
"files": [
|
|
54
|
+
"dist/"
|
|
55
|
+
]
|
|
51
56
|
}
|