@ridit/lens 0.3.4 → 0.3.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.
- package/LENS.md +27 -20
- package/README.md +16 -14
- package/dist/index.mjs +946 -784
- package/package.json +2 -2
- package/src/commands/{watch.tsx → run.tsx} +3 -3
- package/src/components/chat/ChatRunner.tsx +131 -877
- package/src/components/chat/hooks/useChat.ts +540 -0
- package/src/components/chat/hooks/useChatInput.ts +79 -0
- package/src/components/chat/hooks/useCommandHandlers.ts +327 -0
- package/src/components/watch/{WatchRunner.tsx → RunRunner.tsx} +1 -2
- package/src/index.tsx +12 -17
- package/src/prompts/system.ts +141 -20
- package/src/tools/chart.ts +0 -8
- package/src/tools/git.ts +26 -0
- package/src/utils/intentClassifier.ts +58 -0
- package/src/utils/tools/builtins.ts +15 -0
- package/src/utils/tools/registry.ts +65 -9
package/src/tools/git.ts
CHANGED
|
@@ -27,6 +27,7 @@ function parseArgs(body: string): GitArgs | null {
|
|
|
27
27
|
export const gitStatusTool: Tool<GitArgs> = {
|
|
28
28
|
name: "git-status",
|
|
29
29
|
description: "show working tree status",
|
|
30
|
+
tag: "git",
|
|
30
31
|
safe: true,
|
|
31
32
|
permissionLabel: "git status",
|
|
32
33
|
systemPromptEntry: (i) =>
|
|
@@ -45,6 +46,7 @@ export const gitStatusTool: Tool<GitArgs> = {
|
|
|
45
46
|
export const gitLogTool: Tool<GitArgs> = {
|
|
46
47
|
name: "git-log",
|
|
47
48
|
description: "show commit log",
|
|
49
|
+
tag: "git",
|
|
48
50
|
safe: true,
|
|
49
51
|
permissionLabel: "git log",
|
|
50
52
|
systemPromptEntry: (i) =>
|
|
@@ -60,6 +62,7 @@ export const gitLogTool: Tool<GitArgs> = {
|
|
|
60
62
|
export const gitDiffTool: Tool<GitArgs> = {
|
|
61
63
|
name: "git-diff",
|
|
62
64
|
description: "show changes between commits, working tree, or staged files",
|
|
65
|
+
tag: "git",
|
|
63
66
|
safe: true,
|
|
64
67
|
permissionLabel: "git diff",
|
|
65
68
|
systemPromptEntry: (i) =>
|
|
@@ -75,6 +78,7 @@ export const gitDiffTool: Tool<GitArgs> = {
|
|
|
75
78
|
export const gitShowTool: Tool<GitArgs> = {
|
|
76
79
|
name: "git-show",
|
|
77
80
|
description: "show a commit's details and stat",
|
|
81
|
+
tag: "git",
|
|
78
82
|
safe: true,
|
|
79
83
|
permissionLabel: "git show",
|
|
80
84
|
systemPromptEntry: (i) =>
|
|
@@ -90,6 +94,7 @@ export const gitShowTool: Tool<GitArgs> = {
|
|
|
90
94
|
export const gitBranchTool: Tool<GitArgs> = {
|
|
91
95
|
name: "git-branch",
|
|
92
96
|
description: "list branches",
|
|
97
|
+
tag: "git",
|
|
93
98
|
safe: true,
|
|
94
99
|
permissionLabel: "git branch",
|
|
95
100
|
systemPromptEntry: (i) =>
|
|
@@ -105,6 +110,7 @@ export const gitBranchTool: Tool<GitArgs> = {
|
|
|
105
110
|
export const gitRemoteTool: Tool<GitArgs> = {
|
|
106
111
|
name: "git-remote",
|
|
107
112
|
description: "list or inspect remotes",
|
|
113
|
+
tag: "git",
|
|
108
114
|
safe: true,
|
|
109
115
|
permissionLabel: "git remote",
|
|
110
116
|
systemPromptEntry: (i) =>
|
|
@@ -120,6 +126,7 @@ export const gitRemoteTool: Tool<GitArgs> = {
|
|
|
120
126
|
export const gitTagTool: Tool<GitArgs> = {
|
|
121
127
|
name: "git-tag",
|
|
122
128
|
description: "list tags",
|
|
129
|
+
tag: "git",
|
|
123
130
|
safe: true,
|
|
124
131
|
permissionLabel: "git tag",
|
|
125
132
|
systemPromptEntry: (i) =>
|
|
@@ -135,6 +142,7 @@ export const gitTagTool: Tool<GitArgs> = {
|
|
|
135
142
|
export const gitBlameTool: Tool<GitArgs> = {
|
|
136
143
|
name: "git-blame",
|
|
137
144
|
description: "show who last modified each line of a file",
|
|
145
|
+
tag: "git",
|
|
138
146
|
safe: true,
|
|
139
147
|
permissionLabel: "git blame",
|
|
140
148
|
systemPromptEntry: (i) =>
|
|
@@ -168,6 +176,7 @@ export const gitBlameTool: Tool<GitArgs> = {
|
|
|
168
176
|
export const gitStashListTool: Tool<GitArgs> = {
|
|
169
177
|
name: "git-stash-list",
|
|
170
178
|
description: "list stashed changes",
|
|
179
|
+
tag: "git",
|
|
171
180
|
safe: true,
|
|
172
181
|
permissionLabel: "git stash list",
|
|
173
182
|
systemPromptEntry: (i) =>
|
|
@@ -183,6 +192,7 @@ export const gitStashListTool: Tool<GitArgs> = {
|
|
|
183
192
|
export const gitAddTool: Tool<GitArgs> = {
|
|
184
193
|
name: "git-add",
|
|
185
194
|
description: "stage files for commit",
|
|
195
|
+
tag: "git",
|
|
186
196
|
safe: false,
|
|
187
197
|
permissionLabel: "git add",
|
|
188
198
|
systemPromptEntry: (i) =>
|
|
@@ -202,6 +212,7 @@ export const gitAddTool: Tool<GitArgs> = {
|
|
|
202
212
|
export const gitCommitTool: Tool<GitArgs> = {
|
|
203
213
|
name: "git-commit",
|
|
204
214
|
description: "commit staged changes with a message",
|
|
215
|
+
tag: "git",
|
|
205
216
|
safe: false,
|
|
206
217
|
permissionLabel: "git commit",
|
|
207
218
|
systemPromptEntry: (i) =>
|
|
@@ -222,6 +233,7 @@ export const gitCommitTool: Tool<GitArgs> = {
|
|
|
222
233
|
export const gitCommitAmendTool: Tool<GitArgs> = {
|
|
223
234
|
name: "git-commit-amend",
|
|
224
235
|
description: "amend the last commit message",
|
|
236
|
+
tag: "git",
|
|
225
237
|
safe: false,
|
|
226
238
|
permissionLabel: "git commit --amend",
|
|
227
239
|
systemPromptEntry: (i) =>
|
|
@@ -246,6 +258,7 @@ export const gitRevertTool: Tool<GitArgs> = {
|
|
|
246
258
|
name: "git-revert",
|
|
247
259
|
description:
|
|
248
260
|
"revert a commit by hash (creates a new revert commit, history preserved)",
|
|
261
|
+
tag: "git",
|
|
249
262
|
safe: false,
|
|
250
263
|
permissionLabel: "git revert",
|
|
251
264
|
systemPromptEntry: (i) =>
|
|
@@ -266,6 +279,7 @@ export const gitRevertTool: Tool<GitArgs> = {
|
|
|
266
279
|
export const gitResetTool: Tool<GitArgs> = {
|
|
267
280
|
name: "git-reset",
|
|
268
281
|
description: "reset HEAD or unstage files",
|
|
282
|
+
tag: "git",
|
|
269
283
|
safe: false,
|
|
270
284
|
permissionLabel: "git reset",
|
|
271
285
|
systemPromptEntry: (i) =>
|
|
@@ -285,6 +299,7 @@ export const gitResetTool: Tool<GitArgs> = {
|
|
|
285
299
|
export const gitCheckoutTool: Tool<GitArgs> = {
|
|
286
300
|
name: "git-checkout",
|
|
287
301
|
description: "switch branches or restore files",
|
|
302
|
+
tag: "git",
|
|
288
303
|
safe: false,
|
|
289
304
|
permissionLabel: "git checkout",
|
|
290
305
|
systemPromptEntry: (i) =>
|
|
@@ -305,6 +320,7 @@ export const gitCheckoutTool: Tool<GitArgs> = {
|
|
|
305
320
|
export const gitSwitchTool: Tool<GitArgs> = {
|
|
306
321
|
name: "git-switch",
|
|
307
322
|
description: "switch or create branches",
|
|
323
|
+
tag: "git",
|
|
308
324
|
safe: false,
|
|
309
325
|
permissionLabel: "git switch",
|
|
310
326
|
systemPromptEntry: (i) =>
|
|
@@ -325,6 +341,7 @@ export const gitSwitchTool: Tool<GitArgs> = {
|
|
|
325
341
|
export const gitMergeTool: Tool<GitArgs> = {
|
|
326
342
|
name: "git-merge",
|
|
327
343
|
description: "merge a branch into the current branch",
|
|
344
|
+
tag: "git",
|
|
328
345
|
safe: false,
|
|
329
346
|
permissionLabel: "git merge",
|
|
330
347
|
systemPromptEntry: (i) =>
|
|
@@ -345,6 +362,7 @@ export const gitMergeTool: Tool<GitArgs> = {
|
|
|
345
362
|
export const gitPullTool: Tool<GitArgs> = {
|
|
346
363
|
name: "git-pull",
|
|
347
364
|
description: "pull from remote",
|
|
365
|
+
tag: "git",
|
|
348
366
|
safe: false,
|
|
349
367
|
permissionLabel: "git pull",
|
|
350
368
|
systemPromptEntry: (i) =>
|
|
@@ -363,6 +381,7 @@ export const gitPullTool: Tool<GitArgs> = {
|
|
|
363
381
|
export const gitPushTool: Tool<GitArgs> = {
|
|
364
382
|
name: "git-push",
|
|
365
383
|
description: "push commits to remote",
|
|
384
|
+
tag: "git",
|
|
366
385
|
safe: false,
|
|
367
386
|
permissionLabel: "git push",
|
|
368
387
|
systemPromptEntry: (i) =>
|
|
@@ -381,6 +400,7 @@ export const gitPushTool: Tool<GitArgs> = {
|
|
|
381
400
|
export const gitStashTool: Tool<GitArgs> = {
|
|
382
401
|
name: "git-stash",
|
|
383
402
|
description: "stash or apply stashed changes",
|
|
403
|
+
tag: "git",
|
|
384
404
|
safe: false,
|
|
385
405
|
permissionLabel: "git stash",
|
|
386
406
|
systemPromptEntry: (i) =>
|
|
@@ -401,6 +421,7 @@ export const gitStashTool: Tool<GitArgs> = {
|
|
|
401
421
|
export const gitBranchCreateTool: Tool<GitArgs> = {
|
|
402
422
|
name: "git-branch-create",
|
|
403
423
|
description: "create a new branch without switching to it",
|
|
424
|
+
tag: "git",
|
|
404
425
|
safe: false,
|
|
405
426
|
permissionLabel: "git branch (create)",
|
|
406
427
|
systemPromptEntry: (i) =>
|
|
@@ -421,6 +442,7 @@ export const gitBranchCreateTool: Tool<GitArgs> = {
|
|
|
421
442
|
export const gitBranchDeleteTool: Tool<GitArgs> = {
|
|
422
443
|
name: "git-branch-delete",
|
|
423
444
|
description: "delete a branch",
|
|
445
|
+
tag: "git",
|
|
424
446
|
safe: false,
|
|
425
447
|
permissionLabel: "git branch -d",
|
|
426
448
|
systemPromptEntry: (i) =>
|
|
@@ -444,6 +466,7 @@ export const gitBranchDeleteTool: Tool<GitArgs> = {
|
|
|
444
466
|
export const gitCherryPickTool: Tool<GitArgs> = {
|
|
445
467
|
name: "git-cherry-pick",
|
|
446
468
|
description: "apply a specific commit from another branch",
|
|
469
|
+
tag: "git",
|
|
447
470
|
safe: false,
|
|
448
471
|
permissionLabel: "git cherry-pick",
|
|
449
472
|
systemPromptEntry: (i) =>
|
|
@@ -466,6 +489,7 @@ export const gitCherryPickTool: Tool<GitArgs> = {
|
|
|
466
489
|
export const gitTagCreateTool: Tool<GitArgs> = {
|
|
467
490
|
name: "git-tag-create",
|
|
468
491
|
description: "create a lightweight or annotated tag",
|
|
492
|
+
tag: "git",
|
|
469
493
|
safe: false,
|
|
470
494
|
permissionLabel: "git tag (create)",
|
|
471
495
|
systemPromptEntry: (i) =>
|
|
@@ -486,6 +510,7 @@ export const gitRestoreTool: Tool<GitArgs> = {
|
|
|
486
510
|
name: "git-restore",
|
|
487
511
|
description:
|
|
488
512
|
"discard working directory changes for a file (cannot be undone)",
|
|
513
|
+
tag: "git",
|
|
489
514
|
safe: false,
|
|
490
515
|
permissionLabel: "git restore",
|
|
491
516
|
systemPromptEntry: (i) =>
|
|
@@ -505,6 +530,7 @@ export const gitRestoreTool: Tool<GitArgs> = {
|
|
|
505
530
|
export const gitCleanTool: Tool<GitArgs> = {
|
|
506
531
|
name: "git-clean",
|
|
507
532
|
description: "remove untracked files (cannot be undone)",
|
|
533
|
+
tag: "git",
|
|
508
534
|
safe: false,
|
|
509
535
|
permissionLabel: "git clean",
|
|
510
536
|
systemPromptEntry: (i) =>
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Classifies user message intent to scope which tools the LLM is allowed to use.
|
|
3
|
+
*
|
|
4
|
+
* readonly → only read/search/fetch tools exposed (no write, delete, shell)
|
|
5
|
+
* mutating → all tools exposed
|
|
6
|
+
* any → all tools exposed (ambiguous / can't tell)
|
|
7
|
+
*/
|
|
8
|
+
export type Intent = "readonly" | "mutating" | "any";
|
|
9
|
+
|
|
10
|
+
const READONLY_PATTERNS: RegExp[] = [
|
|
11
|
+
// listing / exploring
|
|
12
|
+
/\b(list|ls|dir|show|display|print|dump)\b/i,
|
|
13
|
+
/\bwhat(('?s| is| are| does)\b| files| folder)/i,
|
|
14
|
+
/\b(folder|directory|file) (structure|tree|layout|contents?)\b/i,
|
|
15
|
+
/\bexplore\b/i,
|
|
16
|
+
|
|
17
|
+
// reading / explaining
|
|
18
|
+
/\b(read|open|view|look at|check out|inspect|peek)\b/i,
|
|
19
|
+
/\b(explain|describe|summarize|summarise|tell me about|walk me through)\b/i,
|
|
20
|
+
/\bhow does\b/i,
|
|
21
|
+
/\bwhat('?s| is) (in|inside|this|that|the)\b/i,
|
|
22
|
+
|
|
23
|
+
// searching
|
|
24
|
+
/\b(find|search|grep|locate|where is|where are)\b/i,
|
|
25
|
+
/\b(look for|scan|trace)\b/i,
|
|
26
|
+
|
|
27
|
+
// understanding
|
|
28
|
+
/\bunderstand\b/i,
|
|
29
|
+
/\bshow me (how|what|where|why)\b/i,
|
|
30
|
+
];
|
|
31
|
+
|
|
32
|
+
const MUTATING_PATTERNS: RegExp[] = [
|
|
33
|
+
// writing
|
|
34
|
+
/\b(write|create|make|generate|add|build|scaffold|init|initialize|setup|set up)\b/i,
|
|
35
|
+
/\b(new file|new folder|new component|new page|new route)\b/i,
|
|
36
|
+
|
|
37
|
+
// editing
|
|
38
|
+
/\b(edit|modify|update|change|refactor|rename|move|migrate)\b/i,
|
|
39
|
+
/\b(fix|patch|resolve|correct|debug|repair)\b/i,
|
|
40
|
+
/\b(implement|add .+ to|insert|inject|append|prepend)\b/i,
|
|
41
|
+
|
|
42
|
+
// deleting
|
|
43
|
+
/\b(delete|remove|drop|clean ?up|purge|wipe)\b/i,
|
|
44
|
+
|
|
45
|
+
// running
|
|
46
|
+
/\b(run|execute|install|deploy|build|test|start|launch|compile|lint|format)\b/i,
|
|
47
|
+
];
|
|
48
|
+
|
|
49
|
+
export function classifyIntent(userMessage: string): Intent {
|
|
50
|
+
const text = userMessage.trim();
|
|
51
|
+
|
|
52
|
+
const mutatingScore = MUTATING_PATTERNS.filter((p) => p.test(text)).length;
|
|
53
|
+
const readonlyScore = READONLY_PATTERNS.filter((p) => p.test(text)).length;
|
|
54
|
+
|
|
55
|
+
if (mutatingScore === 0 && readonlyScore > 0) return "readonly";
|
|
56
|
+
if (mutatingScore > 0) return "mutating";
|
|
57
|
+
return "any";
|
|
58
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Tool, ToolContext } from "@ridit/lens-sdk";
|
|
2
|
+
import { TOOL_TAGS } from "@ridit/lens-sdk";
|
|
2
3
|
import {
|
|
3
4
|
fetchUrl,
|
|
4
5
|
searchWeb,
|
|
@@ -23,6 +24,7 @@ export const fetchTool: Tool<string> = {
|
|
|
23
24
|
name: "fetch",
|
|
24
25
|
description: "load a URL",
|
|
25
26
|
safe: true,
|
|
27
|
+
tag: TOOL_TAGS.net,
|
|
26
28
|
permissionLabel: "fetch",
|
|
27
29
|
systemPromptEntry: (i) =>
|
|
28
30
|
`### ${i}. fetch — load a URL\n<fetch>https://example.com</fetch>`,
|
|
@@ -45,6 +47,7 @@ export const shellTool: Tool<string> = {
|
|
|
45
47
|
name: "shell",
|
|
46
48
|
description: "run a terminal command",
|
|
47
49
|
safe: false,
|
|
50
|
+
tag: TOOL_TAGS.shell,
|
|
48
51
|
permissionLabel: "run",
|
|
49
52
|
systemPromptEntry: (i) =>
|
|
50
53
|
`### ${i}. shell — run a terminal command\n<shell>node -v</shell>`,
|
|
@@ -60,6 +63,7 @@ export const readFileTool: Tool<string> = {
|
|
|
60
63
|
name: "read-file",
|
|
61
64
|
description: "read a file from the repo",
|
|
62
65
|
safe: true,
|
|
66
|
+
tag: TOOL_TAGS.read,
|
|
63
67
|
permissionLabel: "read",
|
|
64
68
|
systemPromptEntry: (i) =>
|
|
65
69
|
`### ${i}. read-file — read a file from the repo\n<read-file>src/foo.ts</read-file>`,
|
|
@@ -74,6 +78,7 @@ export const readFileTool: Tool<string> = {
|
|
|
74
78
|
export const readFolderTool: Tool<string> = {
|
|
75
79
|
name: "read-folder",
|
|
76
80
|
description: "list contents of a folder (files + subfolders, one level deep)",
|
|
81
|
+
tag: TOOL_TAGS.read,
|
|
77
82
|
safe: true,
|
|
78
83
|
permissionLabel: "folder",
|
|
79
84
|
systemPromptEntry: (i) =>
|
|
@@ -94,6 +99,7 @@ interface GrepInput {
|
|
|
94
99
|
export const grepTool: Tool<GrepInput> = {
|
|
95
100
|
name: "grep",
|
|
96
101
|
description: "search for a pattern across files in the repo",
|
|
102
|
+
tag: TOOL_TAGS.find,
|
|
97
103
|
safe: true,
|
|
98
104
|
permissionLabel: "grep",
|
|
99
105
|
systemPromptEntry: (i) =>
|
|
@@ -124,6 +130,7 @@ interface WriteFileInput {
|
|
|
124
130
|
export const writeFileTool: Tool<WriteFileInput> = {
|
|
125
131
|
name: "write-file",
|
|
126
132
|
description: "create or overwrite a file",
|
|
133
|
+
tag: TOOL_TAGS.write,
|
|
127
134
|
safe: false,
|
|
128
135
|
permissionLabel: "write",
|
|
129
136
|
systemPromptEntry: (i) =>
|
|
@@ -147,6 +154,7 @@ export const writeFileTool: Tool<WriteFileInput> = {
|
|
|
147
154
|
export const deleteFileTool: Tool<string> = {
|
|
148
155
|
name: "delete-file",
|
|
149
156
|
description: "permanently delete a single file",
|
|
157
|
+
tag: TOOL_TAGS.delete,
|
|
150
158
|
safe: false,
|
|
151
159
|
permissionLabel: "delete",
|
|
152
160
|
systemPromptEntry: (i) =>
|
|
@@ -162,6 +170,7 @@ export const deleteFileTool: Tool<string> = {
|
|
|
162
170
|
export const deleteFolderTool: Tool<string> = {
|
|
163
171
|
name: "delete-folder",
|
|
164
172
|
description: "permanently delete a folder and all its contents",
|
|
173
|
+
tag: TOOL_TAGS.delete,
|
|
165
174
|
safe: false,
|
|
166
175
|
permissionLabel: "delete folder",
|
|
167
176
|
systemPromptEntry: (i) =>
|
|
@@ -177,6 +186,7 @@ export const deleteFolderTool: Tool<string> = {
|
|
|
177
186
|
export const openUrlTool: Tool<string> = {
|
|
178
187
|
name: "open-url",
|
|
179
188
|
description: "open a URL in the user's default browser",
|
|
189
|
+
tag: TOOL_TAGS.net,
|
|
180
190
|
safe: true,
|
|
181
191
|
permissionLabel: "open",
|
|
182
192
|
systemPromptEntry: (i) =>
|
|
@@ -194,6 +204,7 @@ interface GeneratePdfInput {
|
|
|
194
204
|
export const generatePdfTool: Tool<GeneratePdfInput> = {
|
|
195
205
|
name: "generate-pdf",
|
|
196
206
|
description: "generate a PDF file from markdown-style content",
|
|
207
|
+
tag: TOOL_TAGS.write,
|
|
197
208
|
safe: false,
|
|
198
209
|
permissionLabel: "pdf",
|
|
199
210
|
systemPromptEntry: (i) =>
|
|
@@ -222,6 +233,7 @@ export const generatePdfTool: Tool<GeneratePdfInput> = {
|
|
|
222
233
|
|
|
223
234
|
export const searchTool: Tool<string> = {
|
|
224
235
|
name: "search",
|
|
236
|
+
tag: TOOL_TAGS.net,
|
|
225
237
|
description: "search the internet for anything you are unsure about",
|
|
226
238
|
safe: true,
|
|
227
239
|
permissionLabel: "search",
|
|
@@ -245,6 +257,7 @@ export const searchTool: Tool<string> = {
|
|
|
245
257
|
export const cloneTool: Tool<string> = {
|
|
246
258
|
name: "clone",
|
|
247
259
|
description: "clone a GitHub repo so you can explore and discuss it",
|
|
260
|
+
tag: TOOL_TAGS.write,
|
|
248
261
|
safe: false,
|
|
249
262
|
permissionLabel: "clone",
|
|
250
263
|
systemPromptEntry: (i) =>
|
|
@@ -265,6 +278,7 @@ export interface ChangesInput {
|
|
|
265
278
|
export const changesTool: Tool<ChangesInput> = {
|
|
266
279
|
name: "changes",
|
|
267
280
|
description: "propose code edits (shown as a diff for user approval)",
|
|
281
|
+
tag: TOOL_TAGS.write,
|
|
268
282
|
safe: false,
|
|
269
283
|
permissionLabel: "changes",
|
|
270
284
|
systemPromptEntry: (i) =>
|
|
@@ -290,6 +304,7 @@ interface ReadFilesInput {
|
|
|
290
304
|
export const readFilesTool: Tool<ReadFilesInput> = {
|
|
291
305
|
name: "read-files",
|
|
292
306
|
description: "read multiple files from the repo at once",
|
|
307
|
+
tag: TOOL_TAGS.read,
|
|
293
308
|
safe: true,
|
|
294
309
|
permissionLabel: "read",
|
|
295
310
|
systemPromptEntry: (i) =>
|
|
@@ -1,4 +1,23 @@
|
|
|
1
|
-
import type { Tool } from "@ridit/lens-sdk";
|
|
1
|
+
import type { Tool, ToolTag } from "@ridit/lens-sdk";
|
|
2
|
+
import type { Intent } from "../intentClassifier";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Broad capability category for a tool.
|
|
6
|
+
* Used to filter the system prompt based on classified user intent.
|
|
7
|
+
*
|
|
8
|
+
* "read" — safe, purely observational (read-file, read-folder, grep, etc.)
|
|
9
|
+
* "net" — outbound network (fetch, search, clone, open-url)
|
|
10
|
+
* "write" — creates or overwrites file content (write-file, changes, generate-pdf)
|
|
11
|
+
* "delete" — destructive removal (delete-file, delete-folder)
|
|
12
|
+
* "shell" — arbitrary shell execution
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/** Tools allowed for each intent level */
|
|
16
|
+
const INTENT_ALLOWED: Record<Intent, ToolTag[]> = {
|
|
17
|
+
readonly: ["read", "net"],
|
|
18
|
+
mutating: ["read", "net", "write", "delete", "shell"],
|
|
19
|
+
any: ["read", "net", "write", "delete", "shell"],
|
|
20
|
+
};
|
|
2
21
|
|
|
3
22
|
class ToolRegistry {
|
|
4
23
|
private tools = new Map<string, Tool<unknown>>();
|
|
@@ -27,17 +46,54 @@ class ToolRegistry {
|
|
|
27
46
|
}
|
|
28
47
|
|
|
29
48
|
/**
|
|
30
|
-
*
|
|
49
|
+
* Returns tool names that are allowed for the given intent.
|
|
50
|
+
* Falls back to all names when a tool has no tag (legacy / addons).
|
|
51
|
+
*/
|
|
52
|
+
namesForIntent(intent: Intent): string[] {
|
|
53
|
+
const allowed = new Set(INTENT_ALLOWED[intent]);
|
|
54
|
+
return Array.from(this.tools.values())
|
|
55
|
+
.filter((t) => {
|
|
56
|
+
const tag = (t as any).tag as ToolTag | undefined;
|
|
57
|
+
// No tag = addon / unknown → always allow (conservative)
|
|
58
|
+
if (!tag) return true;
|
|
59
|
+
return allowed.has(tag);
|
|
60
|
+
})
|
|
61
|
+
.map((t) => t.name);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Build the TOOLS section of the system prompt from all registered tools,
|
|
66
|
+
* optionally scoped to a specific intent.
|
|
67
|
+
*
|
|
68
|
+
* When intent is "readonly", write/delete/shell tools are omitted entirely
|
|
69
|
+
* so the LLM never sees them and can't hallucinate calls to them.
|
|
31
70
|
*/
|
|
32
|
-
buildSystemPromptSection(): string {
|
|
71
|
+
buildSystemPromptSection(intent: Intent = "any"): string {
|
|
72
|
+
const allowed = new Set(INTENT_ALLOWED[intent]);
|
|
73
|
+
|
|
74
|
+
const visible = Array.from(this.tools.values()).filter((t) => {
|
|
75
|
+
const tag = (t as any).tag as ToolTag | undefined;
|
|
76
|
+
if (!tag) return true; // addon without tag → always show
|
|
77
|
+
return allowed.has(tag);
|
|
78
|
+
});
|
|
79
|
+
|
|
33
80
|
const lines: string[] = ["## TOOLS\n"];
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
81
|
+
|
|
82
|
+
if (intent === "readonly") {
|
|
83
|
+
lines.push(
|
|
84
|
+
`You have ${visible.length} tools available for this read-only request. ` +
|
|
85
|
+
`Do NOT attempt to write, delete, or run shell commands — ` +
|
|
86
|
+
`those tools are not available right now.\n`,
|
|
87
|
+
);
|
|
88
|
+
} else {
|
|
89
|
+
lines.push(
|
|
90
|
+
`You have exactly ${visible.length} tools. To use a tool you MUST wrap it ` +
|
|
91
|
+
`in the exact XML tags shown below — no other format will work.\n`,
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
39
95
|
let i = 1;
|
|
40
|
-
for (const tool of
|
|
96
|
+
for (const tool of visible) {
|
|
41
97
|
lines.push(tool.systemPromptEntry(i++));
|
|
42
98
|
}
|
|
43
99
|
return lines.join("\n");
|