Files
lam-agent-vicinae/package.json
T
adrianbonpin 5f359778b1 fix: take the launcher window out of the shot when snipping
The snip was selecting a region around the launcher panel sitting in the
middle of the screen. `activateEntrypoint` calls `showWindow()` when it
activates a command from a closed launcher, so a view command's window is
already up before any extension code runs. Capturing from inside the chat
view could never have worked.

- `snip` is now a `no-view` command. It calls `closeMainWindow()` first,
  waits out the 50ms hide that `ui-service.hpp` schedules, then captures
  with nothing on screen, then brings the window back by launching `chat`
  with the file. `settleWindow()` exists because a capture started the
  instant the close resolves could still find the window there.
- The chat's action no longer captures inline. It launches `snip` and
  passes the session id, so there is one capture path, one capability
  check, and one place that deals with the window.
- The hand-off relays through `snip` rather than going straight back to
  `chat` on purpose: `ActivateEntrypointOptions::toggleIfAlreadyActive`
  defaults to true, so launching the *already active* view command closes
  the window instead of reopening it. A launch cannot override that flag,
  but relaying through a different no-view command makes the toggle branch
  unreachable.
- The action is hidden while streaming, since the hand-off unloads the
  view and would abandon an answer mid-sentence.
- Vision is settled before the selector appears, so a model that cannot
  read images never costs a selection gesture. `no` and `unknown` get
  different HUD wording.
- `lib/snip.ts` holds the hand-off contract; `lib/hooks/useSnip.ts` is
  gone, as nothing captures from a view any more.

Verified: 252 tests, tsc, eslint, prettier, and vici build. The deployed
manifest now reports `snip mode=no-view`.
2026-10-04 15:26:55 +08:00

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. The launcher window closes first so it cannot end up in the shot. Offered only when the model in preferences supports image input.",
"mode": "no-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"
}
}