lonny-agent 0.2.4 → 0.2.6

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.
Files changed (102) hide show
  1. package/README.md +326 -326
  2. package/dist/agent/llm.d.ts +4 -0
  3. package/dist/agent/llm.d.ts.map +1 -1
  4. package/dist/agent/prompt-builder.d.ts.map +1 -1
  5. package/dist/agent/prompt-builder.js +13 -9
  6. package/dist/agent/prompt-builder.js.map +1 -1
  7. package/dist/agent/providers/google.d.ts.map +1 -1
  8. package/dist/agent/providers/google.js.map +1 -1
  9. package/dist/agent/providers/openai.d.ts.map +1 -1
  10. package/dist/agent/providers/openai.js +43 -3
  11. package/dist/agent/providers/openai.js.map +1 -1
  12. package/dist/agent/session.d.ts +4 -0
  13. package/dist/agent/session.d.ts.map +1 -1
  14. package/dist/agent/session.js +45 -7
  15. package/dist/agent/session.js.map +1 -1
  16. package/dist/config/index.d.ts.map +1 -1
  17. package/dist/config/index.js +7 -1
  18. package/dist/config/index.js.map +1 -1
  19. package/dist/tools/__tests__/bash.test.js +1 -1
  20. package/dist/tools/__tests__/bash.test.js.map +1 -1
  21. package/dist/tools/__tests__/edit.test.js +875 -371
  22. package/dist/tools/__tests__/edit.test.js.map +1 -1
  23. package/dist/tools/__tests__/grep.test.js +32 -0
  24. package/dist/tools/__tests__/grep.test.js.map +1 -1
  25. package/dist/tools/__tests__/sed.test.d.ts +2 -0
  26. package/dist/tools/__tests__/sed.test.d.ts.map +1 -0
  27. package/dist/tools/__tests__/sed.test.js +228 -0
  28. package/dist/tools/__tests__/sed.test.js.map +1 -0
  29. package/dist/tools/bash.d.ts.map +1 -1
  30. package/dist/tools/bash.js +83 -10
  31. package/dist/tools/bash.js.map +1 -1
  32. package/dist/tools/edit.d.ts +50 -9
  33. package/dist/tools/edit.d.ts.map +1 -1
  34. package/dist/tools/edit.js +328 -158
  35. package/dist/tools/edit.js.map +1 -1
  36. package/dist/tools/grep.d.ts.map +1 -1
  37. package/dist/tools/grep.js +54 -30
  38. package/dist/tools/grep.js.map +1 -1
  39. package/dist/tools/registry.d.ts +0 -6
  40. package/dist/tools/registry.d.ts.map +1 -1
  41. package/dist/tools/registry.js +2 -29
  42. package/dist/tools/registry.js.map +1 -1
  43. package/dist/tools/sed.d.ts +4 -0
  44. package/dist/tools/sed.d.ts.map +1 -0
  45. package/dist/tools/sed.js +121 -0
  46. package/dist/tools/sed.js.map +1 -0
  47. package/dist/web/index.d.ts.map +1 -1
  48. package/dist/web/index.js +26 -3
  49. package/dist/web/index.js.map +1 -1
  50. package/dist/web/public/app.js +5 -855
  51. package/dist/web/public/confirm.js +70 -0
  52. package/dist/web/public/index.html +121 -120
  53. package/dist/web/public/input.js +107 -0
  54. package/dist/web/public/messages.js +395 -0
  55. package/dist/web/public/sidebar.js +82 -0
  56. package/dist/web/public/state.js +72 -0
  57. package/dist/web/public/style.css +996 -949
  58. package/dist/web/public/utils.js +37 -0
  59. package/dist/web/public/websocket.js +267 -0
  60. package/dist/web/public/ws.js +19 -0
  61. package/dist/web/session-bridge.d.ts.map +1 -1
  62. package/dist/web/session-bridge.js +3 -7
  63. package/dist/web/session-bridge.js.map +1 -1
  64. package/package.json +55 -54
  65. package/scripts/copy-native.mjs +24 -0
  66. package/scripts/copy-web.mjs +15 -0
  67. package/src/agent/index.ts +25 -25
  68. package/src/agent/llm.ts +4 -0
  69. package/src/agent/prompt-builder.ts +13 -9
  70. package/src/agent/providers/anthropic.ts +179 -179
  71. package/src/agent/providers/google.ts +210 -211
  72. package/src/agent/providers/ollama.ts +186 -186
  73. package/src/agent/providers/openai.ts +61 -5
  74. package/src/agent/session.ts +59 -3
  75. package/src/config/index.ts +342 -335
  76. package/src/tools/__tests__/bash.test.ts +1 -1
  77. package/src/tools/__tests__/edit.test.ts +981 -385
  78. package/src/tools/__tests__/grep.test.ts +35 -0
  79. package/src/tools/bash.ts +97 -11
  80. package/src/tools/edit.ts +362 -169
  81. package/src/tools/git.ts +76 -76
  82. package/src/tools/grep.ts +57 -30
  83. package/src/tools/registry.ts +2 -31
  84. package/src/tui/index.ts +786 -786
  85. package/src/web/index.ts +25 -3
  86. package/src/web/public/app.js +5 -855
  87. package/src/web/public/confirm.js +70 -0
  88. package/src/web/public/index.html +121 -120
  89. package/src/web/public/input.js +107 -0
  90. package/src/web/public/messages.js +395 -0
  91. package/src/web/public/sidebar.js +82 -0
  92. package/src/web/public/state.js +72 -0
  93. package/src/web/public/style.css +996 -949
  94. package/src/web/public/utils.js +37 -0
  95. package/src/web/public/websocket.js +267 -0
  96. package/src/web/public/ws.js +19 -0
  97. package/src/web/session-bridge.ts +193 -194
  98. package/.claude/settings.local.json +0 -14
  99. package/.kilo/plans/1780064105789-mighty-pixel.md +0 -171
  100. package/.kilo/plans/1780293725888-quick-wizard.md +0 -62
  101. package/.lonny/plan-web-cwd-status.md +0 -38
  102. package/src/tools/exec.ts +0 -348
@@ -1,179 +1,179 @@
1
- import Anthropic from '@anthropic-ai/sdk'
2
- import type { MessageParam } from '@anthropic-ai/sdk/resources/messages.js'
3
- import type { ToolDefinition } from '../../tools/types.js'
4
- import type { LLMChunk, LLMMessage, LLMProvider } from '../llm.js'
5
-
6
- export class AnthropicProvider implements LLMProvider {
7
- private client: Anthropic
8
- private model: string
9
-
10
- constructor(apiKey: string, baseURL?: string, model?: string) {
11
- this.client = new Anthropic({ apiKey, baseURL })
12
- this.model = model || 'claude-sonnet-4-20250514'
13
- }
14
-
15
- async *chat(
16
- messages: LLMMessage[],
17
- tools: ToolDefinition[],
18
- signal?: AbortSignal,
19
- ): AsyncGenerator<LLMChunk> {
20
- const anthropicTools: Anthropic.Tool[] = tools.map(t => {
21
- const properties: Record<string, unknown> = {}
22
- for (const [key, param] of Object.entries(t.parameters)) {
23
- const { required: _, ...rest } = param
24
- properties[key] = rest
25
- }
26
- return {
27
- name: t.name,
28
- description: t.description,
29
- input_schema: {
30
- type: 'object' as const,
31
- properties,
32
- required: Object.entries(t.parameters)
33
- .filter(([, v]) => v.required)
34
- .map(([k]) => k),
35
- },
36
- }
37
- })
38
-
39
- const systemMsg = messages.find(m => m.role === 'system')
40
- const nonSystemMessages = messages.filter(m => m.role !== 'system')
41
-
42
- const anthropicMessages: MessageParam[] = nonSystemMessages.map(m => {
43
- if (m.role === 'user') {
44
- return { role: 'user' as const, content: m.content || '' }
45
- }
46
- if (m.role === 'assistant') {
47
- if (m.tool_calls && m.tool_calls.length > 0) {
48
- return {
49
- role: 'assistant' as const,
50
- content: [
51
- ...(m.content ? [{ type: 'text' as const, text: m.content }] : []),
52
- ...m.tool_calls.map(tc => ({
53
- type: 'tool_use' as const,
54
- id: tc.id,
55
- name: tc.name,
56
- input: tc.input,
57
- })),
58
- ],
59
- }
60
- }
61
- return { role: 'assistant' as const, content: m.content || '' }
62
- }
63
- if (m.role === 'tool') {
64
- return {
65
- role: 'user' as const,
66
- content: [
67
- {
68
- type: 'tool_result' as const,
69
- tool_use_id: m.tool_call_id || '',
70
- content: m.content || '',
71
- },
72
- ],
73
- }
74
- }
75
- return { role: 'user' as const, content: '' }
76
- })
77
-
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
- )
88
-
89
- let currentToolUse: {
90
- id: string
91
- name: string
92
- input: string
93
- } | null = null
94
-
95
- let inputTokens = 0
96
- let outputTokens = 0
97
-
98
- for await (const event of stream) {
99
- if (event.type === 'message_start') {
100
- if (event.message.usage) {
101
- inputTokens = event.message.usage.input_tokens ?? 0
102
- }
103
- } else if (event.type === 'content_block_delta') {
104
- if (event.delta.type === 'text_delta') {
105
- yield { type: 'text', text: event.delta.text }
106
- } else if (event.delta.type === 'input_json_delta' && currentToolUse) {
107
- currentToolUse.input += event.delta.partial_json
108
- }
109
- } else if (event.type === 'content_block_start') {
110
- if (event.content_block.type === 'tool_use') {
111
- currentToolUse = {
112
- id: event.content_block.id,
113
- name: event.content_block.name,
114
- input: '',
115
- }
116
- }
117
- } else if (event.type === 'content_block_stop') {
118
- if (currentToolUse) {
119
- let input: Record<string, unknown>
120
- const rawInput = currentToolUse.input || ''
121
- try {
122
- input = JSON.parse(rawInput || '{}')
123
- } catch {
124
- console.error(
125
- '[anthropic] Failed to parse tool_use input (content_block_stop):',
126
- rawInput,
127
- )
128
- input = {}
129
- }
130
- yield {
131
- type: 'tool_use',
132
- tool_call: {
133
- id: currentToolUse.id,
134
- name: currentToolUse.name,
135
- input,
136
- },
137
- }
138
- currentToolUse = null
139
- }
140
- } else if (event.type === 'message_stop') {
141
- yield {
142
- type: 'complete',
143
- finish_reason: 'end_turn',
144
- usage: { input_tokens: inputTokens, output_tokens: outputTokens },
145
- }
146
- } else if (event.type === 'message_delta') {
147
- if (event.usage) {
148
- outputTokens = event.usage.output_tokens ?? 0
149
- }
150
- if (event.delta.stop_reason === 'end_turn' || event.delta.stop_reason === 'stop_sequence') {
151
- if (currentToolUse) {
152
- let input: Record<string, unknown>
153
- const rawInput = currentToolUse.input || ''
154
- try {
155
- input = JSON.parse(rawInput || '{}')
156
- } catch {
157
- console.error('[anthropic] Failed to parse tool_use input (message_delta):', rawInput)
158
- input = {}
159
- }
160
- yield {
161
- type: 'tool_use',
162
- tool_call: {
163
- id: currentToolUse.id,
164
- name: currentToolUse.name,
165
- input,
166
- },
167
- }
168
- currentToolUse = null
169
- }
170
- yield {
171
- type: 'complete',
172
- finish_reason: event.delta.stop_reason,
173
- usage: { input_tokens: inputTokens, output_tokens: outputTokens },
174
- }
175
- }
176
- }
177
- }
178
- }
179
- }
1
+ import Anthropic from '@anthropic-ai/sdk'
2
+ import type { MessageParam } from '@anthropic-ai/sdk/resources/messages.js'
3
+ import type { ToolDefinition } from '../../tools/types.js'
4
+ import type { LLMChunk, LLMMessage, LLMProvider } from '../llm.js'
5
+
6
+ export class AnthropicProvider implements LLMProvider {
7
+ private client: Anthropic
8
+ private model: string
9
+
10
+ constructor(apiKey: string, baseURL?: string, model?: string) {
11
+ this.client = new Anthropic({ apiKey, baseURL })
12
+ this.model = model || 'claude-sonnet-4-20250514'
13
+ }
14
+
15
+ async *chat(
16
+ messages: LLMMessage[],
17
+ tools: ToolDefinition[],
18
+ signal?: AbortSignal,
19
+ ): AsyncGenerator<LLMChunk> {
20
+ const anthropicTools: Anthropic.Tool[] = tools.map(t => {
21
+ const properties: Record<string, unknown> = {}
22
+ for (const [key, param] of Object.entries(t.parameters)) {
23
+ const { required: _, ...rest } = param
24
+ properties[key] = rest
25
+ }
26
+ return {
27
+ name: t.name,
28
+ description: t.description,
29
+ input_schema: {
30
+ type: 'object' as const,
31
+ properties,
32
+ required: Object.entries(t.parameters)
33
+ .filter(([, v]) => v.required)
34
+ .map(([k]) => k),
35
+ },
36
+ }
37
+ })
38
+
39
+ const systemMsg = messages.find(m => m.role === 'system')
40
+ const nonSystemMessages = messages.filter(m => m.role !== 'system')
41
+
42
+ const anthropicMessages: MessageParam[] = nonSystemMessages.map(m => {
43
+ if (m.role === 'user') {
44
+ return { role: 'user' as const, content: m.content || '' }
45
+ }
46
+ if (m.role === 'assistant') {
47
+ if (m.tool_calls && m.tool_calls.length > 0) {
48
+ return {
49
+ role: 'assistant' as const,
50
+ content: [
51
+ ...(m.content ? [{ type: 'text' as const, text: m.content }] : []),
52
+ ...m.tool_calls.map(tc => ({
53
+ type: 'tool_use' as const,
54
+ id: tc.id,
55
+ name: tc.name,
56
+ input: tc.input,
57
+ })),
58
+ ],
59
+ }
60
+ }
61
+ return { role: 'assistant' as const, content: m.content || '' }
62
+ }
63
+ if (m.role === 'tool') {
64
+ return {
65
+ role: 'user' as const,
66
+ content: [
67
+ {
68
+ type: 'tool_result' as const,
69
+ tool_use_id: m.tool_call_id || '',
70
+ content: m.content || '',
71
+ },
72
+ ],
73
+ }
74
+ }
75
+ return { role: 'user' as const, content: '' }
76
+ })
77
+
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
+ )
88
+
89
+ let currentToolUse: {
90
+ id: string
91
+ name: string
92
+ input: string
93
+ } | null = null
94
+
95
+ let inputTokens = 0
96
+ let outputTokens = 0
97
+
98
+ for await (const event of stream) {
99
+ if (event.type === 'message_start') {
100
+ if (event.message.usage) {
101
+ inputTokens = event.message.usage.input_tokens ?? 0
102
+ }
103
+ } else if (event.type === 'content_block_delta') {
104
+ if (event.delta.type === 'text_delta') {
105
+ yield { type: 'text', text: event.delta.text }
106
+ } else if (event.delta.type === 'input_json_delta' && currentToolUse) {
107
+ currentToolUse.input += event.delta.partial_json
108
+ }
109
+ } else if (event.type === 'content_block_start') {
110
+ if (event.content_block.type === 'tool_use') {
111
+ currentToolUse = {
112
+ id: event.content_block.id,
113
+ name: event.content_block.name,
114
+ input: '',
115
+ }
116
+ }
117
+ } else if (event.type === 'content_block_stop') {
118
+ if (currentToolUse) {
119
+ let input: Record<string, unknown>
120
+ const rawInput = currentToolUse.input || ''
121
+ try {
122
+ input = JSON.parse(rawInput || '{}')
123
+ } catch {
124
+ console.error(
125
+ '[anthropic] Failed to parse tool_use input (content_block_stop):',
126
+ rawInput,
127
+ )
128
+ input = {}
129
+ }
130
+ yield {
131
+ type: 'tool_use',
132
+ tool_call: {
133
+ id: currentToolUse.id,
134
+ name: currentToolUse.name,
135
+ input,
136
+ },
137
+ }
138
+ currentToolUse = null
139
+ }
140
+ } else if (event.type === 'message_stop') {
141
+ yield {
142
+ type: 'complete',
143
+ finish_reason: 'end_turn',
144
+ usage: { input_tokens: inputTokens, output_tokens: outputTokens },
145
+ }
146
+ } else if (event.type === 'message_delta') {
147
+ if (event.usage) {
148
+ outputTokens = event.usage.output_tokens ?? 0
149
+ }
150
+ if (event.delta.stop_reason === 'end_turn' || event.delta.stop_reason === 'stop_sequence') {
151
+ if (currentToolUse) {
152
+ let input: Record<string, unknown>
153
+ const rawInput = currentToolUse.input || ''
154
+ try {
155
+ input = JSON.parse(rawInput || '{}')
156
+ } catch {
157
+ console.error('[anthropic] Failed to parse tool_use input (message_delta):', rawInput)
158
+ input = {}
159
+ }
160
+ yield {
161
+ type: 'tool_use',
162
+ tool_call: {
163
+ id: currentToolUse.id,
164
+ name: currentToolUse.name,
165
+ input,
166
+ },
167
+ }
168
+ currentToolUse = null
169
+ }
170
+ yield {
171
+ type: 'complete',
172
+ finish_reason: event.delta.stop_reason,
173
+ usage: { input_tokens: inputTokens, output_tokens: outputTokens },
174
+ }
175
+ }
176
+ }
177
+ }
178
+ }
179
+ }