get_location printed "City: Manila", derived from the last segment of the IANA zone name. That is the timezone database's representative place, not the user's: Asia/Manila is one zone covering the entire Philippines, Asia/Kolkata covers all of India, Europe/Oslo all of Norway. It was wrong for anyone outside the zone's namesake, and confidently so, because a model asked about the weather uses it without hesitating. The README claimed the value was region-level, so the output also contradicted its own docs. - The zone's label is still reported, as `Timezone area`, and named for what it is. Both the field and the tool note say outright that it is not the user's city, and the tool description repeats it. - The locale region subtag is now used, which is a declaration rather than an inference: a locale of en-PH is the Philippines because the user set it. - A Location preference was added. It is the only exact place this extension has, it is reported verbatim and first, and when it is set the note tells the model to prefer it over anything inferred. - The continent grouping from the zone name was dropped: "Asia" next to a region of "Philippines" reads as two answers to the same question. - ToolContext takes the place as an injected value, keeping tools.ts free of Vicinae imports as the module wiring test requires. Verified: 316 tests, tsc, eslint, prettier, and vici build.
160 lines
5.8 KiB
JSON
160 lines
5.8 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": "location",
|
|
"title": "Location",
|
|
"description": "The place Lam should treat as yours, for example Cebu City, Philippines. Optional. Without it Lam falls back to your device timezone and locale, which are accurate to a region and not to a city, so anything that depends on exactly where you are (weather, opening hours) is worth filling in.",
|
|
"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"
|
|
}
|
|
}
|