Two changes: screenshot input gated on the model really reporting vision, and a fix for URLs that arrived as code. Links - A fence whose body is all URLs, a lone `https://...` inline span, and a line that is only a URL are rewritten into [url](url) markdown links. Vicinae attaches only the table and strikethrough GFM extensions, so autolink is off and a bare URL is dead text; clickability comes from MarkdownModel turning CMARK_NODE_LINK into an <a href>. A fenced URL was a dark panel with a Copy button and no way to open it. - promoteStandaloneCodeSpans was itself promoting a lone URL span into a fence, so it made this worse. Link restoration now runs first. - The default prompt says never to fence a URL. - Anything that is not one of those three shapes is copied through, so a curl invocation containing an address is never rewritten. Screenshots - capture.ts shells out to an auto-detected tool: grimblast, grim + slurp, spectacle, maim, scrot, flameshot, or screencapture on macOS. There is no screenshot call in @vicinae/api and Clipboard moves no binary, so the extension owns the capture and reads the file it wrote rather than guessing at the clipboard. Cancel is detected by whether an image landed on disk, because the tools disagree on exit codes. - In chat: "Snip a Region" in the action panel (cmd+shift+S) attaches to the current conversation. Standalone: "Snip to Lam" starts a new one. - vision.ts caches the /api/show capability answer per host and model. A failed check is "unknown", never "no", so a dropped connection is not reported as a fact about the user's model. Actions still fail closed. - Only the path is stored, base64 is read at send time, and the image goes on its own turn only. Capture is never a model-callable tool. Verified: 244 tests, tsc, eslint, and vici build (both entrypoints).
153 lines
5.4 KiB
JSON
153 lines
5.4 KiB
JSON
{
|
|
"$schema": "https://raw.githubusercontent.com/vicinaehq/vicinae/refs/heads/main/extra/schemas/extension.json",
|
|
"name": "lam-agent",
|
|
"title": "Lam Agent",
|
|
"description": "Agentic AI chat powered by Ollama. Ask anything from a global hotkey, with streaming answers, persistent sessions, and web search.",
|
|
"icon": "extension-icon.png",
|
|
"author": "adrianbonpin",
|
|
"categories": ["Productivity", "Developer Tools"],
|
|
"license": "MIT",
|
|
"commands": [
|
|
{
|
|
"name": "chat",
|
|
"title": "Chat with Lam",
|
|
"subtitle": "Lam Agent",
|
|
"description": "Ask Lam anything. Answers stream in as they are generated, your session history is kept, and Lam can search the web when it needs current information.",
|
|
"mode": "view"
|
|
},
|
|
{
|
|
"name": "snip",
|
|
"title": "Snip to Lam",
|
|
"subtitle": "Lam Agent",
|
|
"description": "Capture a region of the screen and start a new chat about it. Offered only when the model in preferences supports image input, so check with \"Set Up Lam Agent\" if the shortcut seems to do nothing.",
|
|
"mode": "view"
|
|
},
|
|
{
|
|
"name": "sessions",
|
|
"title": "Chat Sessions",
|
|
"description": "Browse, reopen, and clean up your past conversations with Lam.",
|
|
"mode": "view"
|
|
},
|
|
{
|
|
"name": "setup",
|
|
"title": "Set Up Lam Agent",
|
|
"description": "Check your Ollama connection, pick the model Lam should use, and tune how Lam answers.",
|
|
"mode": "view"
|
|
}
|
|
],
|
|
"preferences": [
|
|
{
|
|
"name": "apiKey",
|
|
"title": "Ollama API Key",
|
|
"description": "Your Ollama API key, created at ollama.com/settings/keys. Required to reach cloud models and the web search tools.",
|
|
"type": "password",
|
|
"required": true
|
|
},
|
|
{
|
|
"name": "model",
|
|
"title": "Model",
|
|
"description": "The model Lam should use, for example deepseek-v4.1-flash:cloud or gpt-oss:120b. Run \"Set Up Lam Agent\" to pick from the models your key can access.",
|
|
"type": "textfield",
|
|
"required": true
|
|
},
|
|
{
|
|
"name": "ollamaHost",
|
|
"title": "Ollama Host",
|
|
"description": "Base URL of the Ollama API. Leave this alone for Ollama Cloud, or point it at http://localhost:11434 to use a local Ollama server.",
|
|
"type": "textfield",
|
|
"required": false,
|
|
"default": "https://ollama.com"
|
|
},
|
|
{
|
|
"name": "systemPrompt",
|
|
"title": "System Prompt",
|
|
"description": "Extra instructions prepended to every conversation. Leave empty to use Lam's default prompt.",
|
|
"type": "textfield",
|
|
"required": false
|
|
},
|
|
{
|
|
"name": "webSearchEnabled",
|
|
"title": "Web Tools",
|
|
"label": "Let Lam search the web",
|
|
"description": "Let Lam search the web and fetch pages when a question needs up-to-date information.",
|
|
"type": "checkbox",
|
|
"required": false,
|
|
"default": true
|
|
},
|
|
{
|
|
"name": "thinking",
|
|
"title": "Reasoning Effort",
|
|
"description": "Ask supported models to reason before answering. Higher effort is slower but more accurate. Ignored by models that do not support it.",
|
|
"type": "dropdown",
|
|
"required": false,
|
|
"default": "off",
|
|
"data": [
|
|
{ "title": "Off", "value": "off" },
|
|
{ "title": "Low", "value": "low" },
|
|
{ "title": "Medium", "value": "medium" },
|
|
{ "title": "High", "value": "high" }
|
|
]
|
|
},
|
|
{
|
|
"name": "showToolCalls",
|
|
"title": "Show Tool Calls",
|
|
"label": "Show which tools Lam used",
|
|
"description": "List the tools Lam called under each answer, for example web_search or get_datetime.",
|
|
"type": "checkbox",
|
|
"required": false,
|
|
"default": true
|
|
},
|
|
{
|
|
"name": "showReasoning",
|
|
"title": "Show Reasoning",
|
|
"label": "Show the model's reasoning",
|
|
"description": "Include the model's thinking trace under each answer. Useful for seeing why a model answered the way it did, but it makes replies much longer.",
|
|
"type": "checkbox",
|
|
"required": false,
|
|
"default": true
|
|
},
|
|
{
|
|
"name": "resumeTimeout",
|
|
"title": "Start New Chat After",
|
|
"description": "When the command opens, resume the last conversation only if it was used recently. Past this much idle time it starts a fresh chat instead. The old conversation is never deleted — it stays in the sidebar.",
|
|
"type": "dropdown",
|
|
"required": false,
|
|
"default": "1h",
|
|
"data": [
|
|
{ "title": "Never — always reopen the last chat", "value": "never" },
|
|
{ "title": "After 15 minutes", "value": "15m" },
|
|
{ "title": "After 1 hour", "value": "1h" },
|
|
{ "title": "After 6 hours", "value": "6h" },
|
|
{ "title": "After 1 day", "value": "1d" }
|
|
]
|
|
}
|
|
],
|
|
"dependencies": {
|
|
"@vicinae/api": "^0.29.0",
|
|
"zod": "^4.4.3"
|
|
},
|
|
"devDependencies": {
|
|
"@eslint/js": "^9.36.0",
|
|
"@types/node": "22.13.10",
|
|
"@types/react": "19.1.17",
|
|
"eslint": "^9.22.0",
|
|
"eslint-config-prettier": "^10.1.8",
|
|
"globals": "^16.4.0",
|
|
"prettier": "^3.5.3",
|
|
"react": "19.1.1",
|
|
"typescript": "^5.8.2",
|
|
"typescript-eslint": "^8.45.0",
|
|
"vitest": "^4.1.5"
|
|
},
|
|
"scripts": {
|
|
"dev": "vici develop",
|
|
"build": "vici build",
|
|
"lint": "vici lint",
|
|
"lint:code": "eslint .",
|
|
"format": "prettier --write \"src/**/*.{ts,tsx}\"",
|
|
"typecheck": "tsc --noEmit",
|
|
"test": "vitest run",
|
|
"test:watch": "vitest"
|
|
}
|
|
}
|