lonny-agent 0.1.1 → 0.1.8
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/.kilo/plans/1780064105789-mighty-pixel.md +171 -0
- package/.lonny/fix-new-command-session-cleanup.md +65 -0
- package/.lonny/tui-autocomplete-above.md +62 -0
- package/dist/agent/__tests__/compaction.test.js +6 -4
- package/dist/agent/__tests__/compaction.test.js.map +1 -1
- package/dist/agent/compaction.d.ts.map +1 -1
- package/dist/agent/compaction.js +3 -2
- package/dist/agent/compaction.js.map +1 -1
- package/dist/agent/llm.d.ts +1 -1
- package/dist/agent/llm.d.ts.map +1 -1
- package/dist/agent/prompt-builder.d.ts.map +1 -1
- package/dist/agent/prompt-builder.js +26 -8
- package/dist/agent/prompt-builder.js.map +1 -1
- package/dist/agent/providers/anthropic.d.ts +1 -1
- package/dist/agent/providers/anthropic.d.ts.map +1 -1
- package/dist/agent/providers/anthropic.js +2 -2
- package/dist/agent/providers/anthropic.js.map +1 -1
- package/dist/agent/providers/google.d.ts +1 -1
- package/dist/agent/providers/google.d.ts.map +1 -1
- package/dist/agent/providers/google.js +2 -1
- package/dist/agent/providers/google.js.map +1 -1
- package/dist/agent/providers/ollama.d.ts +1 -1
- package/dist/agent/providers/ollama.d.ts.map +1 -1
- package/dist/agent/providers/ollama.js +2 -1
- package/dist/agent/providers/ollama.js.map +1 -1
- package/dist/agent/providers/openai.d.ts +1 -1
- package/dist/agent/providers/openai.d.ts.map +1 -1
- package/dist/agent/providers/openai.js +2 -2
- package/dist/agent/providers/openai.js.map +1 -1
- package/dist/agent/session.d.ts +5 -1
- package/dist/agent/session.d.ts.map +1 -1
- package/dist/agent/session.js +22 -3
- package/dist/agent/session.js.map +1 -1
- package/dist/pi-tui/autocomplete.d.ts +54 -0
- package/dist/pi-tui/autocomplete.d.ts.map +1 -0
- package/dist/pi-tui/autocomplete.js +636 -0
- package/dist/pi-tui/autocomplete.js.map +1 -0
- package/dist/pi-tui/components/box.d.ts +22 -0
- package/dist/pi-tui/components/box.d.ts.map +1 -0
- package/dist/pi-tui/components/box.js +104 -0
- package/dist/pi-tui/components/box.js.map +1 -0
- package/dist/pi-tui/components/cancellable-loader.d.ts +22 -0
- package/dist/pi-tui/components/cancellable-loader.d.ts.map +1 -0
- package/dist/pi-tui/components/cancellable-loader.js +35 -0
- package/dist/pi-tui/components/cancellable-loader.js.map +1 -0
- package/dist/pi-tui/components/editor.d.ts +249 -0
- package/dist/pi-tui/components/editor.d.ts.map +1 -0
- package/dist/pi-tui/components/editor.js +1883 -0
- package/dist/pi-tui/components/editor.js.map +1 -0
- package/dist/pi-tui/components/image.d.ts +28 -0
- package/dist/pi-tui/components/image.d.ts.map +1 -0
- package/dist/pi-tui/components/image.js +90 -0
- package/dist/pi-tui/components/image.js.map +1 -0
- package/dist/pi-tui/components/input.d.ts +37 -0
- package/dist/pi-tui/components/input.d.ts.map +1 -0
- package/dist/pi-tui/components/input.js +382 -0
- package/dist/pi-tui/components/input.js.map +1 -0
- package/dist/pi-tui/components/loader.d.ts +31 -0
- package/dist/pi-tui/components/loader.d.ts.map +1 -0
- package/dist/pi-tui/components/loader.js +70 -0
- package/dist/pi-tui/components/loader.js.map +1 -0
- package/dist/pi-tui/components/markdown.d.ts +96 -0
- package/dist/pi-tui/components/markdown.d.ts.map +1 -0
- package/dist/pi-tui/components/markdown.js +647 -0
- package/dist/pi-tui/components/markdown.js.map +1 -0
- package/dist/pi-tui/components/select-list.d.ts +50 -0
- package/dist/pi-tui/components/select-list.d.ts.map +1 -0
- package/dist/pi-tui/components/select-list.js +167 -0
- package/dist/pi-tui/components/select-list.js.map +1 -0
- package/dist/pi-tui/components/settings-list.d.ts +50 -0
- package/dist/pi-tui/components/settings-list.d.ts.map +1 -0
- package/dist/pi-tui/components/settings-list.js +189 -0
- package/dist/pi-tui/components/settings-list.js.map +1 -0
- package/dist/pi-tui/components/spacer.d.ts +12 -0
- package/dist/pi-tui/components/spacer.d.ts.map +1 -0
- package/dist/pi-tui/components/spacer.js +23 -0
- package/dist/pi-tui/components/spacer.js.map +1 -0
- package/dist/pi-tui/components/text.d.ts +19 -0
- package/dist/pi-tui/components/text.d.ts.map +1 -0
- package/dist/pi-tui/components/text.js +91 -0
- package/dist/pi-tui/components/text.js.map +1 -0
- package/dist/pi-tui/components/truncated-text.d.ts +13 -0
- package/dist/pi-tui/components/truncated-text.d.ts.map +1 -0
- package/dist/pi-tui/components/truncated-text.js +51 -0
- package/dist/pi-tui/components/truncated-text.js.map +1 -0
- package/dist/pi-tui/editor-component.d.ts +39 -0
- package/dist/pi-tui/editor-component.d.ts.map +1 -0
- package/dist/pi-tui/editor-component.js +2 -0
- package/dist/pi-tui/editor-component.js.map +1 -0
- package/dist/pi-tui/fuzzy.d.ts +16 -0
- package/dist/pi-tui/fuzzy.d.ts.map +1 -0
- package/dist/pi-tui/fuzzy.js +110 -0
- package/dist/pi-tui/fuzzy.js.map +1 -0
- package/dist/pi-tui/index.d.ts +23 -0
- package/dist/pi-tui/index.d.ts.map +1 -0
- package/dist/pi-tui/index.js +32 -0
- package/dist/pi-tui/index.js.map +1 -0
- package/dist/pi-tui/keybindings.d.ts +193 -0
- package/dist/pi-tui/keybindings.d.ts.map +1 -0
- package/dist/pi-tui/keybindings.js +174 -0
- package/dist/pi-tui/keybindings.js.map +1 -0
- package/dist/pi-tui/keys.d.ts +184 -0
- package/dist/pi-tui/keys.d.ts.map +1 -0
- package/dist/pi-tui/keys.js +1182 -0
- package/dist/pi-tui/keys.js.map +1 -0
- package/dist/pi-tui/kill-ring.d.ts +28 -0
- package/dist/pi-tui/kill-ring.d.ts.map +1 -0
- package/dist/pi-tui/kill-ring.js +44 -0
- package/dist/pi-tui/kill-ring.js.map +1 -0
- package/dist/pi-tui/native/darwin/prebuilds/darwin-arm64/darwin-modifiers.node +0 -0
- package/dist/pi-tui/native/darwin/prebuilds/darwin-x64/darwin-modifiers.node +0 -0
- package/dist/pi-tui/native/win32/prebuilds/win32-arm64/win32-console-mode.node +0 -0
- package/dist/pi-tui/native/win32/prebuilds/win32-x64/win32-console-mode.node +0 -0
- package/dist/pi-tui/native-modifiers.d.ts +3 -0
- package/dist/pi-tui/native-modifiers.d.ts.map +1 -0
- package/dist/pi-tui/native-modifiers.js +53 -0
- package/dist/pi-tui/native-modifiers.js.map +1 -0
- package/dist/pi-tui/stdin-buffer.d.ts +50 -0
- package/dist/pi-tui/stdin-buffer.d.ts.map +1 -0
- package/dist/pi-tui/stdin-buffer.js +361 -0
- package/dist/pi-tui/stdin-buffer.js.map +1 -0
- package/dist/pi-tui/terminal-image.d.ts +90 -0
- package/dist/pi-tui/terminal-image.d.ts.map +1 -0
- package/dist/pi-tui/terminal-image.js +343 -0
- package/dist/pi-tui/terminal-image.js.map +1 -0
- package/dist/pi-tui/terminal.d.ts +113 -0
- package/dist/pi-tui/terminal.d.ts.map +1 -0
- package/dist/pi-tui/terminal.js +478 -0
- package/dist/pi-tui/terminal.js.map +1 -0
- package/dist/pi-tui/tui.d.ts +227 -0
- package/dist/pi-tui/tui.d.ts.map +1 -0
- package/dist/pi-tui/tui.js +1091 -0
- package/dist/pi-tui/tui.js.map +1 -0
- package/dist/pi-tui/undo-stack.d.ts +17 -0
- package/dist/pi-tui/undo-stack.d.ts.map +1 -0
- package/dist/pi-tui/undo-stack.js +25 -0
- package/dist/pi-tui/undo-stack.js.map +1 -0
- package/dist/pi-tui/utils.d.ts +84 -0
- package/dist/pi-tui/utils.d.ts.map +1 -0
- package/dist/pi-tui/utils.js +1024 -0
- package/dist/pi-tui/utils.js.map +1 -0
- package/dist/pi-tui/word-navigation.d.ts +25 -0
- package/dist/pi-tui/word-navigation.d.ts.map +1 -0
- package/dist/pi-tui/word-navigation.js +98 -0
- package/dist/pi-tui/word-navigation.js.map +1 -0
- package/dist/tools/__tests__/edit.test.js +85 -0
- package/dist/tools/__tests__/edit.test.js.map +1 -1
- package/dist/tools/edit.d.ts.map +1 -1
- package/dist/tools/edit.js +23 -1
- package/dist/tools/edit.js.map +1 -1
- package/dist/tools/registry.d.ts +4 -0
- package/dist/tools/registry.d.ts.map +1 -1
- package/dist/tools/registry.js +15 -7
- package/dist/tools/registry.js.map +1 -1
- package/dist/tui/components.d.ts +1 -1
- package/dist/tui/components.d.ts.map +1 -1
- package/dist/tui/components.js +1 -1
- package/dist/tui/components.js.map +1 -1
- package/dist/tui/editor-patch.d.ts +13 -0
- package/dist/tui/editor-patch.d.ts.map +1 -0
- package/dist/tui/editor-patch.js +41 -0
- package/dist/tui/editor-patch.js.map +1 -0
- package/dist/tui/index.d.ts.map +1 -1
- package/dist/tui/index.js +15 -3
- package/dist/tui/index.js.map +1 -1
- package/dist/web/index.d.ts.map +1 -1
- package/dist/web/index.js +11 -2
- package/dist/web/index.js.map +1 -1
- package/dist/web/public/app.js +65 -4
- package/dist/web/public/style.css +49 -0
- package/dist/web/session-bridge.d.ts +0 -4
- package/dist/web/session-bridge.d.ts.map +1 -1
- package/dist/web/session-bridge.js +16 -2
- package/dist/web/session-bridge.js.map +1 -1
- package/package.json +5 -3
- package/src/agent/__tests__/compaction.test.ts +6 -4
- package/src/agent/compaction.ts +3 -2
- package/src/agent/llm.ts +5 -1
- package/src/agent/prompt-builder.ts +27 -8
- package/src/agent/providers/anthropic.ts +15 -8
- package/src/agent/providers/google.ts +6 -1
- package/src/agent/providers/ollama.ts +6 -1
- package/src/agent/providers/openai.ts +21 -12
- package/src/agent/session.ts +26 -3
- package/src/pi-tui/autocomplete.ts +808 -0
- package/src/pi-tui/components/box.ts +137 -0
- package/src/pi-tui/components/cancellable-loader.ts +40 -0
- package/src/pi-tui/components/editor.ts +2321 -0
- package/src/pi-tui/components/image.ts +130 -0
- package/src/pi-tui/components/input.ts +456 -0
- package/src/pi-tui/components/loader.ts +93 -0
- package/src/pi-tui/components/markdown.ts +839 -0
- package/src/pi-tui/components/select-list.ts +263 -0
- package/src/pi-tui/components/settings-list.ts +264 -0
- package/src/pi-tui/components/spacer.ts +28 -0
- package/src/pi-tui/components/text.ts +113 -0
- package/src/pi-tui/components/truncated-text.ts +65 -0
- package/src/pi-tui/editor-component.ts +74 -0
- package/src/pi-tui/fuzzy.ts +137 -0
- package/src/pi-tui/index.ts +115 -0
- package/src/pi-tui/keybindings.ts +245 -0
- package/src/pi-tui/keys.ts +1440 -0
- package/src/pi-tui/kill-ring.ts +46 -0
- package/src/pi-tui/native/darwin/prebuilds/darwin-arm64/darwin-modifiers.node +0 -0
- package/src/pi-tui/native/darwin/prebuilds/darwin-x64/darwin-modifiers.node +0 -0
- package/src/pi-tui/native/win32/prebuilds/win32-arm64/win32-console-mode.node +0 -0
- package/src/pi-tui/native/win32/prebuilds/win32-x64/win32-console-mode.node +0 -0
- package/src/pi-tui/native-modifiers.ts +65 -0
- package/src/pi-tui/stdin-buffer.ts +434 -0
- package/src/pi-tui/terminal-image.ts +469 -0
- package/src/pi-tui/terminal.ts +594 -0
- package/src/pi-tui/tui.ts +1376 -0
- package/src/pi-tui/undo-stack.ts +28 -0
- package/src/pi-tui/utils.ts +1176 -0
- package/src/pi-tui/word-navigation.ts +127 -0
- package/src/tools/__tests__/edit.test.ts +91 -0
- package/src/tools/edit.ts +27 -1
- package/src/tools/registry.ts +18 -8
- package/src/tui/components.ts +2 -2
- package/src/tui/index.ts +24 -10
- package/src/web/index.ts +11 -2
- package/src/web/public/app.js +65 -4
- package/src/web/public/style.css +49 -0
- package/src/web/session-bridge.ts +13 -2
- package/tsconfig.json +2 -2
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
import { EventChannels, getGlobalEventBus } from '../agent/event-bus.js';
|
|
2
|
+
/**
|
|
3
|
+
* Bridge between Session/EventBus and WebSocket.
|
|
4
|
+
* Listens to EventBus events and forwards them as JSON messages.
|
|
5
|
+
*/
|
|
6
|
+
/** Strip ANSI escape codes from a string (terminal colors are meaningless in the browser) */
|
|
7
|
+
function stripAnsi(text) {
|
|
8
|
+
return text.replace(/\x1b\[[0-9;]*m/g, '');
|
|
9
|
+
}
|
|
2
10
|
const WS_PROTOCOL_VERSION = 1;
|
|
3
11
|
export function startSessionBridge(session, config, send) {
|
|
4
12
|
const bus = getGlobalEventBus();
|
|
@@ -24,11 +32,17 @@ export function startSessionBridge(session, config, send) {
|
|
|
24
32
|
});
|
|
25
33
|
const unsubToolResult = bus.on(EventChannels.TOOL_RESULT, data => {
|
|
26
34
|
const d = data;
|
|
27
|
-
send({
|
|
35
|
+
send({
|
|
36
|
+
type: 'tool_result',
|
|
37
|
+
name: d.name,
|
|
38
|
+
id: d.id,
|
|
39
|
+
success: true,
|
|
40
|
+
output: stripAnsi(d.output),
|
|
41
|
+
});
|
|
28
42
|
});
|
|
29
43
|
const unsubToolError = bus.on(EventChannels.TOOL_ERROR, data => {
|
|
30
44
|
const d = data;
|
|
31
|
-
send({ type: 'tool_result', name: d.name, id: d.id, success: false, error: d.error });
|
|
45
|
+
send({ type: 'tool_result', name: d.name, id: d.id, success: false, error: stripAnsi(d.error) });
|
|
32
46
|
});
|
|
33
47
|
const unsubTurnEnd = bus.on(EventChannels.TURN_END, data => {
|
|
34
48
|
const d = data;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-bridge.js","sourceRoot":"","sources":["../../src/web/session-bridge.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAA;
|
|
1
|
+
{"version":3,"file":"session-bridge.js","sourceRoot":"","sources":["../../src/web/session-bridge.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lonny-agent",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": "github:as3long/lonny-agent",
|
|
6
6
|
"description": "AI coding agent that does more with fewer API calls, optimized for Coding Plan (5h 1200-call bundle)",
|
|
@@ -9,8 +9,9 @@
|
|
|
9
9
|
"lonny": "./dist/index.js"
|
|
10
10
|
},
|
|
11
11
|
"scripts": {
|
|
12
|
-
"build": "tsc && npm run copy:web",
|
|
12
|
+
"build": "tsc && npm run copy:web && npm run copy:native",
|
|
13
13
|
"copy:web": "node -e \"const fs=require('fs'),p=require('path');const src=p.join('src','web','public');const dst=p.join('dist','web','public');if(fs.existsSync(src)){if(!fs.existsSync(dst))fs.mkdirSync(dst,{recursive:true});for(const f of fs.readdirSync(src)){fs.copyFileSync(p.join(src,f),p.join(dst,f))}}\"",
|
|
14
|
+
"copy:native": "node -e \"const fs=require('fs'),p=require('path');function cpDir(s,d){fs.mkdirSync(d,{recursive:true});for(const e of fs.readdirSync(s)){const sp=p.join(s,e),dp=p.join(d,e);fs.statSync(sp).isDirectory()?cpDir(sp,dp):fs.copyFileSync(sp,dp)}}const src=p.join('src','pi-tui','native');const dst=p.join('dist','pi-tui','native');if(fs.existsSync(src))cpDir(src,dst)\"",
|
|
14
15
|
"dev": "tsx src/index.ts",
|
|
15
16
|
"start": "node dist/index.js",
|
|
16
17
|
"test": "vitest run",
|
|
@@ -32,8 +33,9 @@
|
|
|
32
33
|
},
|
|
33
34
|
"dependencies": {
|
|
34
35
|
"@anthropic-ai/sdk": "^0.30.0",
|
|
35
|
-
"@earendil-works/pi-tui": "^0.75.5",
|
|
36
36
|
"adm-zip": "^0.5.17",
|
|
37
|
+
"get-east-asian-width": "1.6.0",
|
|
38
|
+
"marked": "15.0.12",
|
|
37
39
|
"commander": "^12.0.0",
|
|
38
40
|
"openai": "^4.0.0",
|
|
39
41
|
"ws": "^8.21.0",
|
|
@@ -97,9 +97,10 @@ describe('compact', () => {
|
|
|
97
97
|
// Should have: system + summary + 5 recent
|
|
98
98
|
expect(result.newCount).toBeLessThan(result.originalCount)
|
|
99
99
|
expect(result.messages[0].role).toBe('system')
|
|
100
|
-
//
|
|
101
|
-
|
|
102
|
-
expect(
|
|
100
|
+
// Last message should be the summary (appended at end for prompt cache stability)
|
|
101
|
+
const summaryMsg = result.messages[result.messages.length - 1]
|
|
102
|
+
expect(summaryMsg.role).toBe('system')
|
|
103
|
+
expect(summaryMsg.content).toContain('Conversation History Summary')
|
|
103
104
|
})
|
|
104
105
|
|
|
105
106
|
test('preserves tool-call cycles when cutting off', () => {
|
|
@@ -140,7 +141,8 @@ describe('compact', () => {
|
|
|
140
141
|
|
|
141
142
|
const result = compact(messages, 100, 5)
|
|
142
143
|
if (result.compressed) {
|
|
143
|
-
|
|
144
|
+
// Summary is always the last message (appended at end for prompt cache stability)
|
|
145
|
+
const summary = result.messages[result.messages.length - 1].content || ''
|
|
144
146
|
expect(summary).toContain('Total exchanges')
|
|
145
147
|
}
|
|
146
148
|
})
|
package/src/agent/compaction.ts
CHANGED
|
@@ -113,11 +113,12 @@ export function compact(
|
|
|
113
113
|
// Build a summary of the older conversation
|
|
114
114
|
const summary = buildSummary(toSummarize)
|
|
115
115
|
|
|
116
|
-
// Reconstruct: system +
|
|
116
|
+
// Reconstruct: system + recent messages + summary (appended at end so
|
|
117
|
+
// the sys+recent prefix stays stable for LLM prompt caching)
|
|
117
118
|
const compacted: LLMMessage[] = [
|
|
118
119
|
systemMsg,
|
|
119
|
-
{ role: 'system', content: `[Conversation History Summary]\n${summary}` },
|
|
120
120
|
...recentMessages,
|
|
121
|
+
{ role: 'system', content: `[Conversation History Summary]\n${summary}` },
|
|
121
122
|
]
|
|
122
123
|
|
|
123
124
|
return {
|
package/src/agent/llm.ts
CHANGED
|
@@ -10,7 +10,11 @@ export interface LLMMessage {
|
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
export interface LLMProvider {
|
|
13
|
-
chat(
|
|
13
|
+
chat(
|
|
14
|
+
messages: LLMMessage[],
|
|
15
|
+
tools: ToolDefinition[],
|
|
16
|
+
signal?: AbortSignal,
|
|
17
|
+
): AsyncGenerator<LLMChunk>
|
|
14
18
|
}
|
|
15
19
|
|
|
16
20
|
export interface TokenUsage {
|
|
@@ -26,7 +26,19 @@ export function buildSystemPrompt(config: Config): string {
|
|
|
26
26
|
- \`search\`: Search the web using Tavily (query: string, search_depth?: string, include_answer?: boolean, max_results?: number, topic?: string, days?: number)
|
|
27
27
|
`
|
|
28
28
|
}
|
|
29
|
-
|
|
29
|
+
if (mode === 'plan') {
|
|
30
|
+
return `Available tools (read-only investigation + write_plan):
|
|
31
|
+
- \`read\`: Read file contents (paths: string[])
|
|
32
|
+
- \`glob\`: Find files by glob pattern (pattern: string)
|
|
33
|
+
- \`grep\`: Search file content by regex (pattern: string, include?: string, path?: string)
|
|
34
|
+
- \`ls\`: List directory (path?: string)
|
|
35
|
+
- \`bash\`: Execute read-only shell commands for investigation (NEVER modify files)
|
|
36
|
+
- \`find\`: Find files by name pattern (pattern: string, path?: string, maxResults?: number)
|
|
37
|
+
- \`git\`: Run read-only git commands (command: string)
|
|
38
|
+
- \`search\`: Search the web using Tavily (query: string, search_depth?: string, include_answer?: boolean, max_results?: number, topic?: string, days?: number)
|
|
39
|
+
- \`write_plan\`: Save plan/todo markdown into .lonny/ folder
|
|
40
|
+
`
|
|
41
|
+
}
|
|
30
42
|
return `Available tools:
|
|
31
43
|
- \`read\`: Read file contents (paths: string[])
|
|
32
44
|
- \`glob\`: Find files by glob pattern (pattern: string)
|
|
@@ -34,7 +46,7 @@ export function buildSystemPrompt(config: Config): string {
|
|
|
34
46
|
- \`ls\`: List directory (path?: string)
|
|
35
47
|
- \`bash\`: Execute a shell command
|
|
36
48
|
- \`edit\`: Replace text in files — call with {"edits": [{"file_path", "old_string", "new_string"}]} (array required)
|
|
37
|
-
|
|
49
|
+
- \`install_skill\`: Install an npm package as a skill — fetches package info from npm, runs npm install, and creates a .lonny/skills/ file with usage instructions for the AI
|
|
38
50
|
- \`find\`: Find files by name pattern (pattern: string, path?: string, maxResults?: number)
|
|
39
51
|
- \`git\`: Run read-only git commands (command: string)
|
|
40
52
|
- \`search\`: Search the web using Tavily (query: string, search_depth?: string, include_answer?: boolean, max_results?: number, topic?: string, days?: number)
|
|
@@ -59,10 +71,12 @@ ${getToolListForMode(config.mode)}`
|
|
|
59
71
|
|
|
60
72
|
RULES (plan-specific):
|
|
61
73
|
1. Read first: Use read/grep/glob tools to gather all context you need before planning.
|
|
62
|
-
2. You
|
|
63
|
-
3. Use \`bash\` for
|
|
64
|
-
4.
|
|
65
|
-
5. You MUST
|
|
74
|
+
2. You NEVER edit source files. You ONLY use read-only tools (read/glob/grep/ls/find/git/search) and bash (read-only commands only). You do NOT have access to edit, install_skill, or exec.
|
|
75
|
+
3. Use \`bash\` for investigation only — NEVER to modify files, install packages, or run write operations.
|
|
76
|
+
4. Your ONLY output is a plan file saved via \`write_plan\`. You CANNOT modify the codebase directly.
|
|
77
|
+
5. You MUST persist the final plan AND todo list to a file in \`.lonny/\` using \`write_plan\`. The \`write_plan\` content MUST include both ## Plan and ## Todo List sections.
|
|
78
|
+
6. You MUST also include the todo list in your text response to the user (not just in the file).
|
|
79
|
+
7. If the user asks you to modify files, run write commands, or install packages — refuse and explain they need to switch to code mode (\`/mode code\`).
|
|
66
80
|
|
|
67
81
|
OUTPUT FORMAT (you MUST include both in write_plan AND in your response text):
|
|
68
82
|
|
|
@@ -113,8 +127,13 @@ RULES (code-specific):
|
|
|
113
127
|
${isWindows ? ' - Use PowerShell. Do NOT use Unix commands like `cat`, `ls`, `grep`, `which`, `chmod`, `mv`, `cp`, `rm`, `touch`, `mkdir`, `uname`, etc.' : ''}
|
|
114
128
|
${isWindows ? ' - Use `type` instead of `cat`, `dir` instead of `ls`, `where` instead of `which`' : ''}`
|
|
115
129
|
|
|
130
|
+
// Plan mode uses its own standalone tool list inside modeInstructions — skip sharedRules
|
|
131
|
+
const rulesSection =
|
|
132
|
+
config.mode === 'plan'
|
|
133
|
+
? ''
|
|
134
|
+
: `
|
|
135
|
+
${sharedRules}`
|
|
116
136
|
return `${modeInstructions}
|
|
117
137
|
|
|
118
|
-
${envSection}
|
|
119
|
-
${sharedRules}${skillsSection}`
|
|
138
|
+
${envSection}${rulesSection}${skillsSection}`
|
|
120
139
|
}
|
|
@@ -12,7 +12,11 @@ export class AnthropicProvider implements LLMProvider {
|
|
|
12
12
|
this.model = model || 'claude-sonnet-4-20250514'
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
async *chat(
|
|
15
|
+
async *chat(
|
|
16
|
+
messages: LLMMessage[],
|
|
17
|
+
tools: ToolDefinition[],
|
|
18
|
+
signal?: AbortSignal,
|
|
19
|
+
): AsyncGenerator<LLMChunk> {
|
|
16
20
|
const anthropicTools: Anthropic.Tool[] = tools.map(t => {
|
|
17
21
|
const properties: Record<string, unknown> = {}
|
|
18
22
|
for (const [key, param] of Object.entries(t.parameters)) {
|
|
@@ -71,13 +75,16 @@ export class AnthropicProvider implements LLMProvider {
|
|
|
71
75
|
return { role: 'user' as const, content: '' }
|
|
72
76
|
})
|
|
73
77
|
|
|
74
|
-
const stream = this.client.messages.stream(
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
78
|
+
const stream = this.client.messages.stream(
|
|
79
|
+
{
|
|
80
|
+
model: this.model,
|
|
81
|
+
system: systemMsg?.content || '',
|
|
82
|
+
messages: anthropicMessages,
|
|
83
|
+
tools: anthropicTools.length > 0 ? anthropicTools : undefined,
|
|
84
|
+
max_tokens: 8192,
|
|
85
|
+
},
|
|
86
|
+
signal ? { signal } : undefined,
|
|
87
|
+
)
|
|
81
88
|
|
|
82
89
|
let currentToolUse: {
|
|
83
90
|
id: string
|
|
@@ -48,7 +48,11 @@ export class GoogleProvider implements LLMProvider {
|
|
|
48
48
|
this.baseUrl = baseURL || 'https://generativelanguage.googleapis.com/v1beta'
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
async *chat(
|
|
51
|
+
async *chat(
|
|
52
|
+
messages: LLMMessage[],
|
|
53
|
+
tools: ToolDefinition[],
|
|
54
|
+
signal?: AbortSignal,
|
|
55
|
+
): AsyncGenerator<LLMChunk> {
|
|
52
56
|
const systemInstruction = messages.find(m => m.role === 'system')?.content || ''
|
|
53
57
|
const nonSystemMessages = messages.filter(m => m.role !== 'system')
|
|
54
58
|
|
|
@@ -135,6 +139,7 @@ export class GoogleProvider implements LLMProvider {
|
|
|
135
139
|
'Content-Type': 'application/json',
|
|
136
140
|
'x-goog-api-key': this.apiKey,
|
|
137
141
|
},
|
|
142
|
+
signal,
|
|
138
143
|
body: JSON.stringify(body),
|
|
139
144
|
})
|
|
140
145
|
|
|
@@ -40,7 +40,11 @@ export class OllamaProvider implements LLMProvider {
|
|
|
40
40
|
this.model = model || 'llama3.2'
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
async *chat(
|
|
43
|
+
async *chat(
|
|
44
|
+
messages: LLMMessage[],
|
|
45
|
+
tools: ToolDefinition[],
|
|
46
|
+
signal?: AbortSignal,
|
|
47
|
+
): AsyncGenerator<LLMChunk> {
|
|
44
48
|
// Build Ollama-format messages
|
|
45
49
|
const ollamaMessages: OllamaMessage[] = messages.map(m => {
|
|
46
50
|
if (m.role === 'system') {
|
|
@@ -108,6 +112,7 @@ export class OllamaProvider implements LLMProvider {
|
|
|
108
112
|
const response = await fetch(`${this.baseUrl}/api/chat`, {
|
|
109
113
|
method: 'POST',
|
|
110
114
|
headers: { 'Content-Type': 'application/json' },
|
|
115
|
+
signal,
|
|
111
116
|
body: JSON.stringify(body),
|
|
112
117
|
})
|
|
113
118
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import OpenAI from 'openai'
|
|
2
|
+
import type { RequestOptions } from 'openai/core.js'
|
|
2
3
|
import type {
|
|
3
4
|
ChatCompletionChunk,
|
|
4
5
|
ChatCompletionMessageParam,
|
|
@@ -47,7 +48,11 @@ export class OpenAIProvider implements LLMProvider {
|
|
|
47
48
|
this.strictTools = strictTools ?? (baseURL ? /beta/i.test(baseURL) : false)
|
|
48
49
|
}
|
|
49
50
|
|
|
50
|
-
async *chat(
|
|
51
|
+
async *chat(
|
|
52
|
+
messages: LLMMessage[],
|
|
53
|
+
tools: ToolDefinition[],
|
|
54
|
+
signal?: AbortSignal,
|
|
55
|
+
): AsyncGenerator<LLMChunk> {
|
|
51
56
|
const openAIFormattedTools: ChatCompletionTool[] = tools.map(t => {
|
|
52
57
|
const properties: Record<string, unknown> = {}
|
|
53
58
|
for (const [key, param] of Object.entries(t.parameters)) {
|
|
@@ -117,18 +122,22 @@ export class OpenAIProvider implements LLMProvider {
|
|
|
117
122
|
const stream: Stream<ChatCompletionChunk> = await (
|
|
118
123
|
this.client.chat.completions.create as (
|
|
119
124
|
params: ExtendedCreateParams,
|
|
125
|
+
options?: RequestOptions,
|
|
120
126
|
) => Promise<Stream<ChatCompletionChunk>>
|
|
121
|
-
)(
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
127
|
+
)(
|
|
128
|
+
{
|
|
129
|
+
model: this.model,
|
|
130
|
+
messages: openAIMessages,
|
|
131
|
+
tools: openAIFormattedTools.length > 0 ? openAIFormattedTools : undefined,
|
|
132
|
+
stream: true,
|
|
133
|
+
stream_options: { include_usage: true },
|
|
134
|
+
...(this.thinking
|
|
135
|
+
? { thinking: { type: 'enabled' }, reasoning_effort: this.reasoningEffort || 'high' }
|
|
136
|
+
: {}),
|
|
137
|
+
...(this.enableCache ? { enable_cache: true } : {}),
|
|
138
|
+
},
|
|
139
|
+
signal ? { signal } : undefined,
|
|
140
|
+
)
|
|
132
141
|
|
|
133
142
|
let currentToolCall: {
|
|
134
143
|
id: string
|
package/src/agent/session.ts
CHANGED
|
@@ -155,7 +155,7 @@ function printToolResult(tc: ToolCall, result: ToolResult, output?: SessionOutpu
|
|
|
155
155
|
writeOut(` ${GY}│${RS} ${GR}✔${RS} edit\n`, output)
|
|
156
156
|
if (result.output) {
|
|
157
157
|
for (const l of result.output.split('\n')) {
|
|
158
|
-
if (l.trim()) writeOut(` ${GY}│${RS}
|
|
158
|
+
if (l.trim()) writeOut(` ${GY}│${RS} ${l.trim()}\n`, output)
|
|
159
159
|
}
|
|
160
160
|
}
|
|
161
161
|
} else if (tc.name === 'write_plan') {
|
|
@@ -238,7 +238,20 @@ export class Session {
|
|
|
238
238
|
applier: FileReadTracker
|
|
239
239
|
config: Config
|
|
240
240
|
output?: SessionOutput
|
|
241
|
-
|
|
241
|
+
private _onPlanWritten?: (display: string) => void
|
|
242
|
+
/** Set the plan-written callback and propagate to ToolRegistry */
|
|
243
|
+
set onPlanWritten(cb: ((display: string) => void) | undefined) {
|
|
244
|
+
this._onPlanWritten = cb
|
|
245
|
+
// Update context so setMode() picks it up too
|
|
246
|
+
this.registry.updateContext({ onPlanWritten: cb })
|
|
247
|
+
// Re-register write_plan tool with the new callback
|
|
248
|
+
if (this.registry.has('write_plan')) {
|
|
249
|
+
this.registry.reRegisterWritePlan(this.config.cwd, cb)
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
get onPlanWritten(): ((display: string) => void) | undefined {
|
|
253
|
+
return this._onPlanWritten
|
|
254
|
+
}
|
|
242
255
|
totalInputTokens: number = 0
|
|
243
256
|
totalOutputTokens: number = 0
|
|
244
257
|
turnInputTokens: number = 0
|
|
@@ -246,6 +259,7 @@ export class Session {
|
|
|
246
259
|
turnApiCalls: number = 0
|
|
247
260
|
totalApiCalls: number = 0
|
|
248
261
|
private stopped: boolean = false
|
|
262
|
+
private abortController: AbortController | null = null
|
|
249
263
|
|
|
250
264
|
constructor(config: Config, output?: SessionOutput) {
|
|
251
265
|
this.config = config
|
|
@@ -355,6 +369,8 @@ export class Session {
|
|
|
355
369
|
/** Stop the current conversation gracefully */
|
|
356
370
|
stop(): void {
|
|
357
371
|
this.stopped = true
|
|
372
|
+
// Abort any in-flight LLM stream to stop token consumption immediately
|
|
373
|
+
this.abortController?.abort()
|
|
358
374
|
}
|
|
359
375
|
|
|
360
376
|
/** Check if the session was stopped */
|
|
@@ -383,6 +399,9 @@ export class Session {
|
|
|
383
399
|
|
|
384
400
|
// Reset stopped flag for new conversation
|
|
385
401
|
this.resetStopped()
|
|
402
|
+
// Create a new AbortController for this chat invocation
|
|
403
|
+
// (a new controller is needed each time because abort() is one-shot)
|
|
404
|
+
this.abortController = new AbortController()
|
|
386
405
|
|
|
387
406
|
// Declare toolCalls outside the loop so we can reference it in stop check
|
|
388
407
|
let toolCalls: ToolCall[] = []
|
|
@@ -406,7 +425,11 @@ export class Session {
|
|
|
406
425
|
bus.emit(EventChannels.TURN_START, { prompt: userPrompt, iteration: iterations })
|
|
407
426
|
bus.emit(EventChannels.LLM_STREAM_START, { iteration: iterations })
|
|
408
427
|
|
|
409
|
-
const stream = this.provider.chat(
|
|
428
|
+
const stream = this.provider.chat(
|
|
429
|
+
this.messages,
|
|
430
|
+
this.registry.getDefinitions(),
|
|
431
|
+
this.abortController.signal,
|
|
432
|
+
)
|
|
410
433
|
|
|
411
434
|
for await (const chunk of stream) {
|
|
412
435
|
if (chunk.reasoning_content) {
|