@ridit/lens
Advanced tools
+1
-1
| { | ||
| "name": "@ridit/lens", | ||
| "version": "0.4.5", | ||
| "version": "0.4.6", | ||
| "description": "Understand your codebase.", | ||
@@ -5,0 +5,0 @@ "author": "Ridit Jangra <riditjangra09@gmail.com> (https://ridit.space)", |
+27
-1
@@ -44,2 +44,3 @@ # Lens | ||
| lens chat --dev --prompt <text> headless mode: JSON output, no UI | ||
| lens chat --runtime-tools <path> load extra tools from a JSON file at runtime | ||
@@ -94,6 +95,31 @@ lens provider configure AI providers (interactive) | ||
| Custom tools can be built and registered using [`@ridit/lens-sdk`](https://www.npmjs.com/package/@ridit/lens-sdk). | ||
| ### Runtime Tools | ||
| Pass a JSON file to `--runtime-tools` to inject custom tools into any chat session without modifying Lens itself. Each tool declares a name, description, optional parameters, and an HTTP endpoint that Lens will POST to when the AI calls it. | ||
| ```json | ||
| [ | ||
| { | ||
| "name": "get_weather", | ||
| "description": "Returns current weather for a city", | ||
| "parameters": { | ||
| "city": { "type": "string", "description": "City name" } | ||
| }, | ||
| "endpoint": "http://localhost:4242/get_weather" | ||
| } | ||
| ] | ||
| ``` | ||
| ```bash | ||
| lens chat --runtime-tools ./my-tools.json --prompt "What's the weather in London?" | ||
| ``` | ||
| Lens POSTs the tool arguments as JSON to the endpoint and returns the response body to the model. Runtime tools are always auto-approved in headless mode. | ||
| ### SDK | ||
| Custom tools can also be built and registered using [`@ridit/lens-sdk`](https://www.npmjs.com/package/@ridit/lens-sdk). | ||
| ## License | ||
| MIT |
@@ -12,2 +12,3 @@ import React from "react"; | ||
| sessionId, | ||
| runtimeTools, | ||
| }: { | ||
@@ -20,2 +21,3 @@ path: string; | ||
| sessionId?: string; | ||
| runtimeTools?: string; | ||
| }) { | ||
@@ -31,2 +33,3 @@ return ( | ||
| sessionId={sessionId} | ||
| runtimeTools={runtimeTools} | ||
| /> | ||
@@ -33,0 +36,0 @@ </Box> |
@@ -131,2 +131,3 @@ import React, { useState, useRef } from "react"; | ||
| sessionId, | ||
| runtimeTools, | ||
| }: { | ||
@@ -139,2 +140,3 @@ repoPath: string; | ||
| sessionId?: string; | ||
| runtimeTools?: string; | ||
| }) { | ||
@@ -297,2 +299,3 @@ const [stage, setStage] = useState<"idle" | "thinking">("idle"); | ||
| system: getSystemPrompt(repoPath), | ||
| runtimeTools, | ||
| onChunk: () => {}, | ||
@@ -356,2 +359,3 @@ onToolCall: (tool, args) => { | ||
| system: getSystemPrompt(repoPath), | ||
| runtimeTools, | ||
| onBeforeToolCall: (tool, args) => { | ||
@@ -358,0 +362,0 @@ if (forceApproveRef.current || SAFE_TOOLS.has(tool)) |
+16
-2
@@ -79,2 +79,3 @@ import React from "react"; | ||
| forceAll?: boolean; | ||
| runtimeTools?: string; | ||
| }) { | ||
@@ -105,9 +106,19 @@ const repoPath = opts.path; | ||
| // runtime tools are explicitly user-provided — always approve them | ||
| const runtimeToolNames = new Set<string>(); | ||
| if (opts.runtimeTools) { | ||
| try { | ||
| const raw = JSON.parse(require("fs").readFileSync(opts.runtimeTools, "utf-8")); | ||
| if (Array.isArray(raw)) raw.forEach((t: { name: string }) => runtimeToolNames.add(t.name)); | ||
| } catch { /* ignore parse errors */ } | ||
| } | ||
| await chat({ | ||
| messages: getMessages(session), | ||
| system: getSystemPrompt(repoPath), | ||
| runtimeTools: opts.runtimeTools, | ||
| // 2 steps: 1 tool attempt (or denial) + 1 text response | ||
| maxSteps: opts.forceAll ? 50 : 2, | ||
| onBeforeToolCall: (tool, args) => { | ||
| if (opts.forceAll || HEADLESS_SAFE_TOOLS.has(tool)) return Promise.resolve(true); | ||
| if (opts.forceAll || HEADLESS_SAFE_TOOLS.has(tool) || runtimeToolNames.has(tool)) return Promise.resolve(true); | ||
| // record denial — model will respond naturally explaining what it needs | ||
@@ -164,2 +175,3 @@ const a = args as Record<string, unknown>; | ||
| .option("--prompt <text>", "Run a prompt non-interactively") | ||
| .option("--runtime-tools <path>", "path to runtime tools JSON file") | ||
| .action( | ||
@@ -174,2 +186,3 @@ (opts: { | ||
| prompt?: string; | ||
| runtimeTools?: string; | ||
| }) => { | ||
@@ -179,3 +192,3 @@ const sessionId = opts.session ?? opts.id; | ||
| if (opts.prompt && (opts.dev || opts.single)) { | ||
| runHeadless({ path: opts.path, prompt: opts.prompt, sessionId, single: opts.single, forceAll: opts.forceAll }); | ||
| runHeadless({ path: opts.path, prompt: opts.prompt, sessionId, single: opts.single, forceAll: opts.forceAll, runtimeTools: opts.runtimeTools }); | ||
| return; | ||
@@ -191,2 +204,3 @@ } | ||
| initialMessage={opts.prompt} | ||
| runtimeTools={opts.runtimeTools} | ||
| />, | ||
@@ -193,0 +207,0 @@ ); |
Sorry, the diff of this file is too big to display
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
3013650
0.12%84696
0.09%124
26.53%6
20%