tesseract-agent 0.11.15 → 0.11.17
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/dist-bundle/cli.js +116 -121
- package/dist-bundle/mesh-core/package.json +1 -1
- package/package.json +1 -1
package/dist-bundle/cli.js
CHANGED
|
@@ -20222,6 +20222,21 @@ Rules:
|
|
|
20222
20222
|
- Plain words a non-expert understands. No jargon, no file paths, no command names unless the suggestion itself names them.
|
|
20223
20223
|
- Address the developer directly ("This would\u2026"). Never answer the suggestion, never do the work, never ask a question.
|
|
20224
20224
|
- Two sentences maximum. Stop.`
|
|
20225
|
+
},
|
|
20226
|
+
{
|
|
20227
|
+
id: "side-llm.summarize-turn",
|
|
20228
|
+
group: "side-llm",
|
|
20229
|
+
label: "Conversation tab summariser",
|
|
20230
|
+
help: "One short line describing what the conversation has DONE so far, shown in the tab's hover tooltip under the title. Rebuilt after each turn. The \u226412-word / one-sentence limit is the whole contract \u2014 it sits in a small tooltip, so anything longer is clipped; and it must read as a status of work done, never as a reply to the developer.",
|
|
20231
|
+
vars: [],
|
|
20232
|
+
content: `A developer is working with an AI coding agent. Summarise, in ONE short sentence, what this conversation has accomplished SO FAR \u2014 the kind of line that belongs under a browser-tab title.
|
|
20233
|
+
Rules:
|
|
20234
|
+
- Output ONLY the sentence. No markdown, no quotes, no preamble, no trailing period.
|
|
20235
|
+
- 12 words MAXIMUM. Shorter is better.
|
|
20236
|
+
- Describe the WORK DONE, not what is planned or being asked. Past/perfect or a noun phrase ("Added tab tooltips and per-turn summaries", "Debugging the failing image upload").
|
|
20237
|
+
- Weight the MOST RECENT messages most heavily: if the topic shifted, describe where it is now, not where it started.
|
|
20238
|
+
- Plain, concrete words. Name the real feature/file/thing when it is clear. No filler like "The agent\u2026" or "This conversation\u2026".
|
|
20239
|
+
- Never answer the developer, never do the work, never ask a question.`
|
|
20225
20240
|
},
|
|
20226
20241
|
{
|
|
20227
20242
|
id: "side-llm.project-inspect",
|
|
@@ -23061,7 +23076,7 @@ var init_capabilities = __esm({
|
|
|
23061
23076
|
label: "Create a presentation",
|
|
23062
23077
|
help: "What the model is told the `present.create_deck` App-Control capability does (present domain, write).",
|
|
23063
23078
|
vars: [],
|
|
23064
|
-
content: `Make a new, empty Tesseract Stage presentation in the user
|
|
23079
|
+
content: `Make a new, empty Tesseract Stage presentation and return its deck handle. It lands in the project the user has open \u2014 beside the files it is about \u2014 or in their library (~/Documents/Tesseract/Presentations) when no project is open. This is how you make a presentation \u2014 NOT a PowerPoint file, NOT markdown, NOT an HTML canvas. Pass the title in the user's own words and language. Optionally set a theme: CSS custom properties every slide inherits, e.g. { "--bg": "#FFFFFF", "--ink": "#16130F", "--accent": "#D97757" }. Then write slides with write_slide.`
|
|
23065
23080
|
},
|
|
23066
23081
|
{
|
|
23067
23082
|
id: "capability.present.write_slide",
|
|
@@ -24422,6 +24437,13 @@ function schemaFieldRejected(status2, body) {
|
|
|
24422
24437
|
function anthropicBaseUrl(env) {
|
|
24423
24438
|
return env?.ANTHROPIC_BASE_URL?.trim() || process.env.ANTHROPIC_BASE_URL?.trim() || "https://api.anthropic.com";
|
|
24424
24439
|
}
|
|
24440
|
+
function isAnthropicEndpoint(env) {
|
|
24441
|
+
try {
|
|
24442
|
+
return /(^|\.)api\.anthropic\.com$/i.test(new URL(anthropicBaseUrl(env)).hostname);
|
|
24443
|
+
} catch {
|
|
24444
|
+
return false;
|
|
24445
|
+
}
|
|
24446
|
+
}
|
|
24425
24447
|
var OAUTH_BETA_HEADER;
|
|
24426
24448
|
var init_model_json = __esm({
|
|
24427
24449
|
"../../packages/shared/dist/model-json.js"() {
|
|
@@ -24974,15 +24996,12 @@ function isAnthropicModelId(model) {
|
|
|
24974
24996
|
const id = (model ?? "").trim().toLowerCase();
|
|
24975
24997
|
if (!id)
|
|
24976
24998
|
return false;
|
|
24977
|
-
if (TIER_ALIAS.test(id))
|
|
24978
|
-
return false;
|
|
24979
24999
|
return /(^|[/.\-])(claude|opus|sonnet|haiku|fable)([/.\-]|$)/.test(id) || /^(opus|sonnet|haiku|fable)\b/.test(id);
|
|
24980
25000
|
}
|
|
24981
|
-
var
|
|
25001
|
+
var ONE_MILLION_FAMILIES, SUFFIX;
|
|
24982
25002
|
var init_model_long_context = __esm({
|
|
24983
25003
|
"../../packages/shared/dist/model-long-context.js"() {
|
|
24984
25004
|
"use strict";
|
|
24985
|
-
TIER_ALIAS = /^tsr-/i;
|
|
24986
25005
|
ONE_MILLION_FAMILIES = [
|
|
24987
25006
|
/(^|[/.])claude-sonnet-(4-6|4-7|4-8|5)\b/i,
|
|
24988
25007
|
/(^|[/.])claude-opus-(4-6|4-7|4-8|5)\b/i,
|
|
@@ -26626,10 +26645,10 @@ function providerBase(key2, which2) {
|
|
|
26626
26645
|
return fromServer;
|
|
26627
26646
|
return which2 === "anthropic" ? gatewayAnthropicBaseUrl(key2.baseUrl) : which2 === "openai" ? gatewayOpenAiBaseUrl(key2.baseUrl) : gatewayGeminiBaseUrl(key2.baseUrl);
|
|
26628
26647
|
}
|
|
26629
|
-
function
|
|
26648
|
+
function slotProviders(key2) {
|
|
26630
26649
|
const out = /* @__PURE__ */ new Map();
|
|
26631
26650
|
for (const slot of Object.keys(TIER_PROVIDER)) {
|
|
26632
|
-
const id = key2.models[slot];
|
|
26651
|
+
const id = key2.models[slot]?.trim();
|
|
26633
26652
|
if (id)
|
|
26634
26653
|
out.set(id, TIER_PROVIDER[slot]);
|
|
26635
26654
|
}
|
|
@@ -26638,25 +26657,26 @@ function aliasProviders(key2) {
|
|
|
26638
26657
|
function tiers(engineId, key2, models) {
|
|
26639
26658
|
const provider = gatewayProviderForEngine(engineId);
|
|
26640
26659
|
const preference = provider ? TIER_PREFERENCE[provider] : void 0;
|
|
26641
|
-
const
|
|
26660
|
+
const byModel = slotProviders(key2);
|
|
26642
26661
|
const asked = (v) => {
|
|
26643
26662
|
const t = v?.trim();
|
|
26644
26663
|
if (!t)
|
|
26645
26664
|
return void 0;
|
|
26646
26665
|
if (t.includes("/"))
|
|
26647
26666
|
return t;
|
|
26648
|
-
return
|
|
26667
|
+
return byModel.get(t) === provider ? t : void 0;
|
|
26649
26668
|
};
|
|
26650
26669
|
const pick3 = (slots) => {
|
|
26651
26670
|
for (const slot of slots) {
|
|
26652
|
-
const id = key2.models[slot];
|
|
26671
|
+
const id = key2.models[slot]?.trim();
|
|
26653
26672
|
if (id)
|
|
26654
26673
|
return id;
|
|
26655
26674
|
}
|
|
26656
26675
|
return void 0;
|
|
26657
26676
|
};
|
|
26658
|
-
const
|
|
26659
|
-
const
|
|
26677
|
+
const serverDefault = asked(key2.defaults?.model);
|
|
26678
|
+
const main2 = asked(models.main) || serverDefault || preference && pick3(preference.main);
|
|
26679
|
+
const fast = asked(models.fast) || serverDefault || preference && pick3(preference.fast) || main2;
|
|
26660
26680
|
return { main: main2 || void 0, fast: fast || void 0 };
|
|
26661
26681
|
}
|
|
26662
26682
|
function planGatewayRun(engineId, key2, models, homeBase) {
|
|
@@ -26698,7 +26718,7 @@ var init_gateway_plan = __esm({
|
|
|
26698
26718
|
};
|
|
26699
26719
|
TIER_PREFERENCE = {
|
|
26700
26720
|
// No fast rung of its own on the OpenAI side: Codex is one model plus a reasoning dial,
|
|
26701
|
-
// and
|
|
26721
|
+
// and the nano model remains the cheap fallback for anything that asks for one.
|
|
26702
26722
|
openai: { main: ["codex", "gpt", "high"], fast: ["low", "high"] },
|
|
26703
26723
|
anthropic: { main: ["claude"], fast: ["claudeFast", "claude"] },
|
|
26704
26724
|
"google-ai": { main: ["vision"], fast: ["vision"] }
|
|
@@ -32981,8 +33001,9 @@ ${JSON.stringify(r, null, 2)}`
|
|
|
32981
33001
|
domain: "present",
|
|
32982
33002
|
title: "Create a presentation",
|
|
32983
33003
|
input: external_exports.object({
|
|
32984
|
-
title: external_exports.string().describe("What the presentation is called.
|
|
33004
|
+
title: external_exports.string().describe("What the presentation is called. Used for its folder name; keep the user's own wording and language."),
|
|
32985
33005
|
description: external_exports.string().optional().describe("One line about what it is for."),
|
|
33006
|
+
root: external_exports.string().optional().describe("Folder to create it in. Leave unset \u2014 it then lands in the project the user has open, which is almost always what they want. Only set this if they asked for somewhere specific."),
|
|
32986
33007
|
theme: external_exports.record(external_exports.string(), external_exports.string()).optional().describe('CSS custom properties applied to every slide, e.g. { "--bg": "#FFFFFF", "--ink": "#16130F", "--accent": "#D97757" }.')
|
|
32987
33008
|
}),
|
|
32988
33009
|
mutation: "write",
|
|
@@ -32995,7 +33016,7 @@ ${JSON.stringify(r, null, 2)}`
|
|
|
32995
33016
|
domain: "present",
|
|
32996
33017
|
title: "Write a slide",
|
|
32997
33018
|
input: external_exports.object({
|
|
32998
|
-
deck: external_exports.string().describe("The deck
|
|
33019
|
+
deck: external_exports.string().describe("The deck handle, exactly as `list_decks` or `create_deck` returned it. Either a folder name or an absolute path, both ending in .tessdeck \u2014 pass it back unchanged rather than rebuilding it."),
|
|
32999
33020
|
path: external_exports.string().describe('Path inside the presentation, e.g. "slides/03-pricing.tsx". Filename order IS slide order, so number the prefixes. Helper files may live anywhere in the package.'),
|
|
33000
33021
|
source: external_exports.string().describe("The whole file. A slide exports `meta` ({ id, title, summary?, notes?, transition?, builds? }) and a default React component.")
|
|
33001
33022
|
}),
|
|
@@ -33009,7 +33030,7 @@ ${JSON.stringify(r, null, 2)}`
|
|
|
33009
33030
|
domain: "present",
|
|
33010
33031
|
title: "Read a slide",
|
|
33011
33032
|
input: external_exports.object({
|
|
33012
|
-
deck: external_exports.string().describe("The deck
|
|
33033
|
+
deck: external_exports.string().describe("The deck handle, exactly as it was returned to you."),
|
|
33013
33034
|
path: external_exports.string().describe('Path inside the presentation, e.g. "slides/03-pricing.tsx".')
|
|
33014
33035
|
}),
|
|
33015
33036
|
mutation: "read",
|
|
@@ -33021,7 +33042,7 @@ ${JSON.stringify(r, null, 2)}`
|
|
|
33021
33042
|
domain: "present",
|
|
33022
33043
|
title: "Delete a slide",
|
|
33023
33044
|
input: external_exports.object({
|
|
33024
|
-
deck: external_exports.string().describe("The deck
|
|
33045
|
+
deck: external_exports.string().describe("The deck handle, exactly as it was returned to you."),
|
|
33025
33046
|
path: external_exports.string().describe("Path inside the presentation.")
|
|
33026
33047
|
}),
|
|
33027
33048
|
mutation: "write",
|
|
@@ -33033,7 +33054,7 @@ ${JSON.stringify(r, null, 2)}`
|
|
|
33033
33054
|
id: "present.validate_deck",
|
|
33034
33055
|
domain: "present",
|
|
33035
33056
|
title: "Check a presentation",
|
|
33036
|
-
input: external_exports.object({ deck: external_exports.string().describe("The deck
|
|
33057
|
+
input: external_exports.object({ deck: external_exports.string().describe("The deck handle, exactly as it was returned to you.") }),
|
|
33037
33058
|
mutation: "read",
|
|
33038
33059
|
availability: "desktop",
|
|
33039
33060
|
binding: { kind: "ipc", channel: "decklib", verb: "validate" },
|
|
@@ -33044,7 +33065,7 @@ ${JSON.stringify(r, null, 2)}`
|
|
|
33044
33065
|
domain: "present",
|
|
33045
33066
|
title: "Set a presentation\u2019s theme",
|
|
33046
33067
|
input: external_exports.object({
|
|
33047
|
-
deck: external_exports.string().describe("The deck
|
|
33068
|
+
deck: external_exports.string().describe("The deck handle, exactly as it was returned to you."),
|
|
33048
33069
|
theme: external_exports.record(external_exports.string(), external_exports.string()).describe(`CSS custom properties, e.g. { "--bg": "#0C0A14", "--ink": "#FFFFFF" }. Replaces the deck's current theme.`)
|
|
33049
33070
|
}),
|
|
33050
33071
|
mutation: "write",
|
|
@@ -33057,7 +33078,7 @@ ${JSON.stringify(r, null, 2)}`
|
|
|
33057
33078
|
domain: "present",
|
|
33058
33079
|
title: "Add an image to a presentation",
|
|
33059
33080
|
input: external_exports.object({
|
|
33060
|
-
deck: external_exports.string().describe("The deck
|
|
33081
|
+
deck: external_exports.string().describe("The deck handle, exactly as it was returned to you."),
|
|
33061
33082
|
source_path: external_exports.string().describe("Absolute path of the file to copy in \u2014 a generated image, a photo, an audio clip."),
|
|
33062
33083
|
name: external_exports.string().optional().describe("Filename to use inside the presentation.")
|
|
33063
33084
|
}),
|
|
@@ -33070,7 +33091,7 @@ ${JSON.stringify(r, null, 2)}`
|
|
|
33070
33091
|
id: "present.open_deck",
|
|
33071
33092
|
domain: "present",
|
|
33072
33093
|
title: "Open a presentation",
|
|
33073
|
-
input: external_exports.object({ deck: external_exports.string().describe("The deck
|
|
33094
|
+
input: external_exports.object({ deck: external_exports.string().describe("The deck handle, exactly as it was returned to you.") }),
|
|
33074
33095
|
mutation: "write",
|
|
33075
33096
|
availability: "desktop",
|
|
33076
33097
|
binding: { kind: "ipc", channel: "decklib", verb: "open" },
|
|
@@ -33080,7 +33101,7 @@ ${JSON.stringify(r, null, 2)}`
|
|
|
33080
33101
|
id: "present.delete_deck",
|
|
33081
33102
|
domain: "present",
|
|
33082
33103
|
title: "Delete a presentation",
|
|
33083
|
-
input: external_exports.object({ deck: external_exports.string().describe("The deck
|
|
33104
|
+
input: external_exports.object({ deck: external_exports.string().describe("The deck handle, exactly as it was returned to you.") }),
|
|
33084
33105
|
mutation: "write",
|
|
33085
33106
|
availability: "desktop",
|
|
33086
33107
|
binding: { kind: "ipc", channel: "decklib", verb: "delete" },
|
|
@@ -33285,7 +33306,7 @@ var CAPABILITIES_DOC;
|
|
|
33285
33306
|
var init_capabilities_doc_generated = __esm({
|
|
33286
33307
|
"../../packages/agent-core/dist/capabilities-doc.generated.js"() {
|
|
33287
33308
|
"use strict";
|
|
33288
|
-
CAPABILITIES_DOC = '# Tesseract \u2014 what the product can do\n\nOne-page map of **every user-reachable capability**, derived from the 80 area briefs in\n[`functional-testing/`](functional-testing/). It is the source for the `tesseract_capabilities`\ntool, so the agent can answer "what can you do?" about *Tesseract*, not just about its own toolbelt.\n\n> Read this before telling a user something is or isn\'t possible. \xA718 lists what is deliberately\n> **not** built \u2014 promising any of it is the most common way to be wrong about this product.\n\n---\n\n## 1. What Tesseract is\n\nA desktop-first AI workspace: an always-on agent that can drive your machine, your browser and your\nfiles; plus a fleet layer that makes every machine you own reachable from any of them; plus a set of\ncreative, communication and security products built on the same transport. It ships as **eight\nseparate clients** and is not a single app.\n\n## 2. Clients (each a distinct product)\n\n| Client | What it is |\n|---|---|\n| **Desktop** (Electron, mac/Win/Linux) | The full product. Tab workspace \u2014 **no router**: a recursive split-pane tree of tab groups, **24 tab kinds**, **10 dockable panels** (dock left/right/bottom, float, detach), multi-window, native menu, command + search palettes (**31 stable command ids**), \u23181\u20130 tab assign/recall, per-machine keybinding overrides, memory governor + layout restore. |\n| **Web** (`dist-web`) | Same React renderer over a relay transport. **No local agent, no local engine** \u2014 it always runs on a remote host. Terminals are all remote and pinned to the opening host. Documented stubs: undo-delete, engines, runner configs, window resize; voice keys sit in `localStorage`. Always auth-gated. |\n| **Mobile** (Flutter, iOS/Android/macOS) | A **roaming client** \u2014 it never hosts an agent. Chat with streaming, team chat, present-follower, full password vault (incl. TOTP + native autofill), realtime voice, rdesk viewer, clipboard sync, push. Uniquely: **phone-as-host** (serve your photo library and files to your desktop) and a create-video screen. |\n| **CLI** `tesseract-agent` (npm) | Headless daemon, ~18 commands: `login/logout/whoami`, `run`, service `install/start/stop/restart/status/logs`, `link add`, `runner \u2026`, `net \u2026`, self-update. `--instance <id>` namespaces state dir, service name and device id. Docker-friendly (`login --token` then `run` as PID 1). |\n| **Browser extension** (Chrome MV3) | Claude sidebar (sessions, slash commands, todos, sources, DOM tree, run modes), element picker, vault/autofill popup with biometrics, QR pairing, fullpage + plan views. Talks to the daemon through a native-messaging companion host. |\n| **Remote Desktop** (`apps/rdesk`) | Slim standalone binary, ~\xBC the size \u2014 ships **no AI/browser payload**. Server/client/chooser roles, coexists with the full daemon (demotes itself to client rather than quitting). |\n| **Mesh** (`apps/mesh`) | Slim standalone binary for the private network only \u2014 "moves packets, not pixels". Create a mesh, enrol, list peers. No role chooser by design. |\n| **Thin installer** (Flutter, ~20\u201340 MB) | The default download. Resolves the release feed at run time, picks the arch-correct asset, streams + sha512-verifies, installs, launches. Version-agnostic. |\n\nPlus the **admin/operations console** (`admin.tesseract.dev`: gateway credentials, users and keys,\nerror inspector, remediation trigger, audit log) and the **landing site** with its waitlist.\n\n## 3. The agent\n\n- **Turn lifecycle**: stream, interrupt, rapid-follow-up auto-cancel (first seconds only), stall\n watchdog, orphan-turn recovery, token compaction, usage-limit handling, cost ledger per session.\n- **Run modes**: **5 permission modes \xD7 6 effort levels**, thinking budget, per-turn engine/model pick.\n Default permission mode is `bypassPermissions`.\n- **Interactive cards** (~9): permission request, plan review, elicitation, confirm, verification,\n user dialog, skill UI, archive password, unattended report. "Deny & stop" also aborts the turn.\n- **Block renderers** (~9): mission, subagent, report, sources, provenance, event, notice, surface,\n image grid \u2014 plus tool-run cards joined at render time with 6/8-line clamping.\n- **Composer** (~25 actions): attach, slash commands, @-mention, reverse search, screen-region\n capture, element picker, voice, undo-last-turn, queued-message reorder.\n- **Sessions**: list, search (one host-side search across every engine\'s stored conversations),\n resume, summarize, **fork**, merge, delete-message, keep-alive, focus; session mirror + transfer;\n share a conversation by unguessable capability token.\n- **Subsystems**: reinforced verification, plan splitter, narrator (live status strip, capped at 24\n model calls/turn), hook bus (9 events), option ratings, unattended mode.\n- **Also**: a playable **chess** surface (5 tools) and chat slash toys (`/shrug`, `/tableflip`, \u2026).\n\n## 4. Engines, runners, gateway\n\n- **4 engines \xD7 3 auth modes** (`oauth` / `apiKey` / `localCli`), a 24-capability engine matrix,\n engine + model swap mid-session (model/permission-mode reconcile live; effort/cwd/MCP/system-prompt\n force a respawn).\n- **Runner config pool** with rotation, cooldown and failover; auto-retry is bounded and only fires\n when the turn did no work.\n- **Provider gateway** \u2014 a credential-injecting reverse proxy, **19 routes** across AGENT (anthropic,\n openai, google-ai, groq, xai, deepseek, moonshot, openrouter, custom-openai, customer-litellm,\n azure-openai), EMBEDDING, SEARCH (serpapi), VIDEO (heygen, gemini), VOICE, MEDIA (klipy, unsplash,\n pexels). Virtual keys `tsk_live_*`, budgets, LiteLLM price map, spend ledger, credential pools with\n health-based failover that never crosses a category. Model aliases: `tsr-low`, `tsr-high`,\n `tsr-vision`, `tsr-claude`, `tsr-claude-fast`, `tsr-image` ($0.10/image flat).\n- **Framework cross-product gate**: the user\'s self-updating `claude` CLI \xD7 the pinned Agent SDK,\n verified nightly across pinned CLI versions.\n\n## 5. Files, editors, viewers\n\n- **Finder-like browser**: list/grid/columns, breadcrumbs, bookmarks + OS favourites, **host\n switcher** (every op can be remote), new/rename (F2)/move/duplicate/cut-copy-paste/delete + undo,\n Get Info, send-to-machine, find-in-files, native drag in **and out** (macOS `NSFilePromiseProvider`\n \u2014 drag a not-yet-downloaded remote file to Finder).\n- **~20 typed viewers/editors**: Monaco source editor, PDF (view + edit), Word/docx, spreadsheets,\n presentations, markdown, data grid, hex, audio, video, font, HTML canvas, diff, info.\n- **Archives as folders**: ~20 formats (zip, 7z, tar, gz/bz2/xz/zst, rar, iso, wim, cab, cpio, lzh\u2026)\n browsed, extracted and **edited in place** from the same tree. `rar`/`iso`/`cab` are read-only.\n Encrypted archives prompt for a password and can remember it.\n- **Image editor**: layered canvas, 10 tools (marquee, lasso, move, crop, paint, eraser, fill,\n eyedropper, text, zoom), 25 rail controls, **200+ AI effect styles**, layers, adjust/resize, markup,\n and 3 AI ops (`prompt`/`inpaint`/`outpaint`), transparent-background output, animate\u2192video.\n- **Video editor**: EDL timeline (cut/trim/reorder/transitions/speed/crop/reframe/flip/reverse/colour\n effects/audio tracks), burned-in captions, **18 MCP tools** \u2014 probe, render, frame extract, silence\n detect, transcribe with diarization, extract/isolate audio, music generation, voice list/clone/TTS,\n avatars, caption export, effects, upscale (ffmpeg + local Real-ESRGAN free; fal-Topaz paid).\n- **Undo & time travel**: agent-driven **file rewind** (undo what a turn wrote), file-tree \u2318Z with a\n per-window trash, workspace snapshots and git checkpoints, canvas/design version history with\n diff-and-restore, and message deletion with uniform semantics across engines.\n- **Native inspectors**: **Flutter** widget inspector (tree, on-device tap-to-pick, properties,\n deterministic Dart source edits, hot reload) and **React Native** (source binding + AST edits).\n\n## 6. Create, Design Studio, Stage, Publish\n\n- **Create** \u2014 5 generative document formats (incl. infographic and poster), ~90 actions: outline\n ops, 10 insert kinds, card generation, AI layouts, export.\n- **Design Studio** \u2014 a 10-stage wizard (pick \u2192 launch/browse \u2192 preview \u2192 target \u2192 inspect \u2192 brief \u2192\n build \u2192 QA \u2192 deploy) over **254 templates across 19 industry verticals**, Figma import, in-studio\n theme/token editing.\n- **Stage** \u2014 presentation engine: decks, slides, transitions, **slide audio** (narration/music/sfx\n with music ducking under narration), a live assistant, presenter mode, zoom/blank. 8 present tools\n let the agent drive the deck; followers converge from absolute-state snapshots.\n- **Export**: PowerPoint (.pptx), deck and card export, PNG.\n- **Publish** \u2014 private/org/public visibility, server-rendered public pages on a 192-bit token, live\n data sources (SSRF-guarded), embeds; **community gallery** with explore/following/team/mine, like,\n follow and clone.\n- **Deploy** \u2014 one-click hosting to `*.tesseract.dev` in per-user hardened containers (cap-drop ALL,\n no-new-privileges, read-only, egress-locked), metered on compute/storage/egress. One of the few\n genuinely entitlement-gated features. A separate **per-user cloud agent** container is provisioned\n on demand so you have a machine in the fleet even with every laptop closed.\n\n## 7. Generative media\n\n| What | Notes |\n|---|---|\n| **Images** | 2 providers (OpenAI gpt-image-2, Google). Generate (4-up by default), edit, inpaint/outpaint, transparent background (inpaint + chroma-key). **$0.10/image**. Ungated, BYO key. |\n| **Stock images** | AI-ranked Unsplash/Pexels search as its own tab. Free tier, rate-limited. |\n| **Video** | Google Veo 3.1 \u2014 4/6/8s clips, 720p/1080p, 16:9 or 9:16, keyframe conditioning (first/last frame), native audio. Free on the bundled tier; otherwise cost-confirmed. Multi-scene storyboards chain clip-to-clip for longer videos. |\n| **Avatar video** | HeyGen talking presenter from a script. |\n| **Music / speech** | ElevenLabs music generation, TTS, and instant **voice cloning**. |\n| **Fonts & brand** | Prompt \u2192 AI glyph sheets \u2192 **vision QC** \u2192 vectorize \u2192 kerning/spacing \u2192 a real installable font. Plus logo/wordmark candidates, SVG lockups and a brand kit. Assembly/vectorize/build are local and free. |\n| **Trending effects** | One-tap video effects (hug/kiss, squish, bring-photo-to-life, age, anime restyle, 3D figurine, outfit change, consent-gated face-swap\u2026). |\n\n## 8. Voice\n\n- **3 realtime providers**: OpenAI Realtime, Gemini Live, ElevenLabs ConvAI \u2014 plus a non-realtime\n **STT\u2192LLM\u2192TTS pipeline cascade**. Audio goes **client\u2194provider direct**; the daemon only mints the\n ephemeral credential and runs the control loop.\n- Group calls, live captions, and the **\u2325Space voice widget**.\n- **Voice as a control modality**: the realtime model is the *operator*, Claude Code is the *worker*.\n It decomposes a spoken request into one small dispatched step at a time, all to the same agent\n session, and is explicitly forbidden from claiming an outcome the agent did not report \u2014 when\n unsure it dispatches a check. Its own screen view is a deliberately low-res ~1 fps grab.\n\n## 9. Computer control\n\n- **Two distinct MCP servers**: `tesseract-computer` (**26 tools** \u2014 raw control: move/click/drag/\n scroll/key/type, see_screen, read_text, read_ui (accessibility), clipboard, windows, apps, open\n url/path, notify, annotate, draw) and `tesseract-screen` (**15 tools** \u2014 a guided\n look \u2192 figure_out_next \u2192 perform_step \u2192 **verify** loop that can fail and retry).\n- Plus `tesseract-os-control`: processes, network, structured fs, AX tree + AX actions, preferred app\n and usage profile, screen overlays (arrow/bubble/highlight/text/popup/choice), and\n `request_user_input` / `confirm_action`.\n- **Click grounding** is AX-tree + a local Moondream vision sidecar (free); screenshots are\n Retina-aware and downscaled to point coordinates so clicks line up.\n- **Off by default** \u2014 `computerControlEnabled` must be turned on.\n- **\u2325Space co-pilot HUD** + **13 daemon-owned windows** (spotlight, pastebar, publisher, annotate,\n draw, overlay, input, choice, consent, control-bar, ai-cursor, rdesk call/client), the tray, screen-\n region capture with multi-display number flash, and `tesseract://` deep links. The HUD is\n deliberately **invisible to the AI\'s own screenshots**.\n\n## 10. Integrated browser\n\n- In-app browser tabs with a shared persist partition, per-tab zoom, OAuth popups, URL-safety and\n proxy routing.\n- **Agent control over CDP**: navigate, snapshot, screenshot (viewport + full page), click (synthetic\n and real trusted input), type, key, eval, cookies, raw CDP for any domain, buffered event draining.\n Drives the **user\'s real logged-in browser** via the companion extension, or the built-in engine.\n- **Inspectors**: DOM tree, properties, native inspector; markup pen; click-to-source (JSX elements\n resolve to their source line).\n- **6 Toolkit mission playbooks**: accessibility, GDPR/cookies, health, performance, SEO, UX review \u2014\n each configures, runs, and emits a structured report.\n- **`appbrowser` collaboration**: presence, cursors, comments and edits on a visible tab.\n\n## 11. Web search\n\n`serp_*` over **121 engines / 1,726 parameters**, ~19 tools grouped by family: web, news, images\n(incl. reverse-image and Google Lens), video (incl. YouTube transcripts), maps/local, shopping,\nmarketplaces (Amazon/eBay/Walmart/Home Depot/Zillow), travel (flights/hotels), places & reviews,\nacademic (Scholar/patents), jobs, finance & trends, app stores, ads transparency, social.\nBrokered free tier: **100 searches/month signed in, 10/month anonymous** \u2014 the only hard per-user\nquota in the product.\n\n## 12. Multi-machine\n\n- **Host registry & fleet**: every machine you sign into registers itself; pick one and run the turn\n there. Dual-role nodes are both client and host at once.\n- **Remote fs + terminals** over the relay (9 relayed channels: agent, signal, browser, frame, fs,\n term, editor, rdesk, present). A remote driver may only launch an enumerated interpreter.\n- **File Provider (macOS)**: remote machines appear as native **Finder locations** \u2014 browse, read,\n write, rename, move, Trash + Put Back, thumbnails, progress. Identity survives rename/move.\n- **Drops** \u2014 AirDrop-like sharing to your own devices or another account. E2E-sealed, blind fan-out\n (first device to accept wins; the sender never learns which), receive policies + receive codes,\n blocks and abuse reports that are deliberately **indistinguishable** from "nobody was there".\n- **Universal clipboard**: text/HTML/images fan out to your other machines; >512 KB syncs a thumbnail\n + reference and pulls the bytes on demand. A privacy gate blocks password-manager and secure-input\n content. Plus **paste history** (\u2318\u21E7V pastebar), clipboard over the rdesk channel, and mobile\n text-only sync.\n- **Peer-link**: agent\u2194agent direct transport with a 3-tier ladder (LAN TLS \u2192 observed public IP \u2192\n UDP hole-punch), cert-pinned, relayed only as a fallback.\n- **Mesh VPN**: own PKI with SAS verification, join tickets, recovery mnemonic, a policy bundle with a\n fail-closed freshness clock, an authenticated Noise data plane, disco/path selection, a 25-pair NAT\n punch matrix, and a privileged `netd` helper that **derives** every route itself (the IPC has no\n "add route" field, by design) with journal-based teardown after a crash or reboot.\n- **Remote desktop**: screen share and control. 3 grant paths (same-account registry, cross-account\n code, unattended password), 3 engines (native, VNC, RDP), display picker, quality, Ctrl+Alt+Del,\n in-session voice on the same peer connection, side chat, and a phone viewer.\n- **Present & collaboration**: a presenter drives followers across devices; join codes; live cursors,\n comments and captions.\n- **Co-view mirroring**: a second device with the same conversation open sees **26 allowlisted\n events**. Permission prompts are deliberately *not* mirrored \u2014 a card you can\'t answer is a dead\n button.\n- **Settings & session sync**: keys, tokens, active engine and model are account-wide; `localCli`\n paths are machine-local and must never cross. Plus continuous folder mirroring (active link).\n\n## 13. Team chat & conferencing\n\nSlack-class: spaces, categories, channels, DMs, threads, mentions, reactions, custom emoji, stickers,\nattachments, forum channels, pins, presence, search (Postgres **or** Elasticsearch), link unfurl,\nGIF/meme, bots + a bot API, incoming webhooks, automations, governance, retention and audit.\n**Huddles** over a self-hosted LiveKit SFU with captions and a summary posted back to the channel;\ntoken minting and webhooks work without the SFU, and captions still work when LiveKit is unconfigured.\n\n## 14. Vault (password manager)\n\nZero-knowledge, Argon2id + AES-GCM, server holds only opaque ciphertext. **5 item types** (logins,\npasskeys, payments, secure notes, personal info), ~28 daemon ops, **4 unlock paths** (master password,\ndevice, biometric, **QR from your phone**), sharing sealed to recipient device keys, transfer,\nimport/export (Chrome, Safari, zip), a generator, TOTP, the **macOS AutoFill provider**, and browser\nautofill through the extension.\n\n## 15. Extensions platform\n\nFamilies: **skills, code plugins, bundle plugins, MCP connectors** (3 transports: stdio/http/sse),\nplus **theme packs**. Marketplace discovery with a security verdict that gates install; enable/disable;\nper-extension encrypted secrets; updates; uninstall. Extensions contribute **tabs, panels, settings\npages, status items, menu items and reskins**. First-party skills are free; marketplace ones are\ngated \u2014 `plugins` is the one entitlement actually enforced.\n\n## 16. App Control \u2014 the AI operating Tesseract itself\n\n**144 capabilities across 19 domains** (`settings, navigation, engines, runners, runtimes,\nextensions, hosts, account, daemon, providers, image, voice, permissions, project, privacy, system,\nfonts, present, tour`), exposed as 2 meta-tools + one executor per domain, each input validated\nagainst its own schema. **There is no confirmation gate \u2014 actions happen immediately, by product\ndecision.**\n\n## 17. Platform\n\n- **Accounts**: invite-only (there is **no public sign-up**; Google sign-in on an unknown email is\n rejected), password + Google, password reset, device registration/claim/keys, a CLI device-code\n flow, and an offline-tolerance contract \u2014 only an explicit 401/403 signs you out.\n- **Plans**: `free`, `standard` (shown as **"Pro"**), `pro` (shown as **"Team"**) \u2014 17 feature flags,\n quotas on compute/storage/egress/video, seats, invites, orgs. Your effective plan is the best across\n every org you belong to.\n- **Missions, cron & unattended**: schedule agent turns that run with nobody present, with catch-up\n after downtime, background tasks and structured reports.\n- **Settings**: **23 sections, ~300 controls** \u2014 appearance, editor, general, runners, agent, voice,\n image editing, search, extensions, background tasks, account, team, sync, privacy, file drops,\n remote desktop, permissions, hooks (9 events), env, about, shortcuts (31 rebindable commands).\n- **Theming**: DTCG design tokens, theme packs with **8 independently switchable facets** (colors,\n shape, fonts, background, decorations, sounds, intro, extraCss) and a 3-entry-point **Safe Mode** to\n recover from a bad pack.\n- **Accessibility & motion**: light/dark \xD7 comfortable/compact density throughout, reduced-motion\n and sound-mute as separate switches, and labelled roles on every interactive element. Animation\n is a product requirement, not a preference \u2014 every show/hide, open/close and surface switch is\n animated (140\u2013220ms), and native unstyled controls are not used.\n- **OS permissions**: 7 tracked (microphone, camera, screen recording, full-disk access, accessibility,\n notifications, local network) with per-platform availability; three require a relaunch after grant.\n- **Observability**: crash/error reporting from 6 producers with separate crash and telemetry consent\n (**opt-out \u2014 on unless explicitly disabled**), fingerprinting and grouping, an error inspector, an\n alerting bridge, in-app issue submission, and a GDPR export-and-erase path.\n- **The always-on background service**: the desktop app *is* the daemon (merged process); the slim\n rdesk and mesh builds and the headless CLI keep the classic separate-service model, installed via\n launchd / systemd / Windows services. It self-heals silently, degrades from GUI to headless rather\n than dying, and only one daemon owns a machine at a time. This is why clipboard sync, remote\n access, scheduled turns and the \u2325Space HUD keep working with no app window open.\n- **Connectivity**: the relay is stateless and queues nothing \u2014 a dropped socket re-bootstraps rather\n than replaying. In-flight turns survive a disconnect and stay interruptible.\n- **Updates**: check \u2192 download \u2192 stage \u2192 apply \u2192 relaunch, with an external reaper, log rotation on\n version change and a What\'s New screen. System events (sleep/wake, lock, AC/battery, clock jump,\n displays, interfaces) drive recovery.\n\n## 18. Deliberately NOT built \u2014 do not promise these\n\n- **Create multiplayer co-editing / comments-in-Create** \u2014 deferred; the stores exist but are unwired.\n- **Marketplace** as a product \u2014 brainstorm only.\n- **Team chat**: voice messages, async video clips, keyword alerts, scheduled send, `/remind`, saved\n messages, guest/single-channel access, outgoing webhooks, AI catch-up/digest, public communities,\n nested threads, Block Kit, workflow builder, read receipts, E2E encryption for team chat.\n- **Create/Gamma parity gaps**: todo blocks, GIF/QR/illustrations, media library, form embeds, Google\n Slides export, theme gallery picker, share analytics, public generate API, custom domains, SEO\n toggle, password-protected publish, sites manager.\n- **Hosting**: the managed DB/auth/storage layer, secrets manager, git sync + 1-click Publish.\n- **Mobile**: file browsing, in-app browser, hosting an agent, rendering canvas/surface blocks.\n- **Web app**: undo-delete, local engines, runner configs, the errors panel, open/save-to-code for\n remote hosts.\n- **Mesh**: there is no VPN tunnel a user can turn on yet \u2014 PKI, protocol and data plane are built,\n route execution is not a shipped user feature. No Windows/macOS netd hosting.\n- **Other**: Homebrew formula, Chrome Web Store listing (the extension installs unpacked), Deepgram\n voice, Office (ZetaOffice) editing, AWS Bedrock and Google Vertex gateway routes, VNC clipboard,\n Wayland-specific clipboard handling, RN live widget tree (blocked upstream), the voice tutorial.\n\n## 19. Honest caveats\n\n- **Entitlements are almost entirely unenforced.** Only `plugins` is gated in production, and the\n desktop client is never gated at all. Both the API and the relay **fail open** on billing errors.\n- **Realtime voice has never run live against a provider** \u2014 treat first-run voice as unproven.\n- **HeyGen avatar video has no key configured** as shipped.\n- **The self-hosted web stack has no per-user data isolation** \u2014 auth there is a login wall over one\n shared workspace root.\n- `standard` = "Pro" and `pro` = "Team" \u2014 the plan id and the display name are inverted.\n';
|
|
33309
|
+
CAPABILITIES_DOC = '# Tesseract \u2014 what the product can do\n\nOne-page map of **every user-reachable capability**, derived from the 80 area briefs in\n[`functional-testing/`](functional-testing/). It is the source for the `tesseract_capabilities`\ntool, so the agent can answer "what can you do?" about *Tesseract*, not just about its own toolbelt.\n\n> Read this before telling a user something is or isn\'t possible. \xA718 lists what is deliberately\n> **not** built \u2014 promising any of it is the most common way to be wrong about this product.\n\n---\n\n## 1. What Tesseract is\n\nA desktop-first AI workspace: an always-on agent that can drive your machine, your browser and your\nfiles; plus a fleet layer that makes every machine you own reachable from any of them; plus a set of\ncreative, communication and security products built on the same transport. It ships as **eight\nseparate clients** and is not a single app.\n\n## 2. Clients (each a distinct product)\n\n| Client | What it is |\n|---|---|\n| **Desktop** (Electron, mac/Win/Linux) | The full product. Tab workspace \u2014 **no router**: a recursive split-pane tree of tab groups, **24 tab kinds**, **10 dockable panels** (dock left/right/bottom, float, detach), multi-window, native menu, command + search palettes (**31 stable command ids**), \u23181\u20130 tab assign/recall, per-machine keybinding overrides, memory governor + layout restore. |\n| **Web** (`dist-web`) | Same React renderer over a relay transport. **No local agent, no local engine** \u2014 it always runs on a remote host. Terminals are all remote and pinned to the opening host. Documented stubs: undo-delete, engines, runner configs, window resize; voice keys sit in `localStorage`. Always auth-gated. |\n| **Mobile** (Flutter, iOS/Android/macOS) | A **roaming client** \u2014 it never hosts an agent. Chat with streaming, team chat, present-follower, full password vault (incl. TOTP + native autofill), realtime voice, rdesk viewer, clipboard sync, push. Uniquely: **phone-as-host** (serve your photo library and files to your desktop) and a create-video screen. |\n| **CLI** `tesseract-agent` (npm) | Headless daemon, ~18 commands: `login/logout/whoami`, `run`, service `install/start/stop/restart/status/logs`, `link add`, `runner \u2026`, `net \u2026`, self-update. `--instance <id>` namespaces state dir, service name and device id. Docker-friendly (`login --token` then `run` as PID 1). |\n| **Browser extension** (Chrome MV3) | Claude sidebar (sessions, slash commands, todos, sources, DOM tree, run modes), element picker, vault/autofill popup with biometrics, QR pairing, fullpage + plan views. Talks to the daemon through a native-messaging companion host. |\n| **Remote Desktop** (`apps/rdesk`) | Slim standalone binary, ~\xBC the size \u2014 ships **no AI/browser payload**. Server/client/chooser roles, coexists with the full daemon (demotes itself to client rather than quitting). |\n| **Mesh** (`apps/mesh`) | Slim standalone binary for the private network only \u2014 "moves packets, not pixels". Create a mesh, enrol, list peers. No role chooser by design. |\n| **Thin installer** (Flutter, ~20\u201340 MB) | The default download. Resolves the release feed at run time, picks the arch-correct asset, streams + sha512-verifies, installs, launches. Version-agnostic. |\n\nPlus the **admin/operations console** (`admin.tesseract.dev`: gateway credentials, users and keys,\nerror inspector, remediation trigger, audit log) and the **landing site** with its waitlist.\n\n## 3. The agent\n\n- **Turn lifecycle**: stream, interrupt, rapid-follow-up auto-cancel (first seconds only), stall\n watchdog, orphan-turn recovery, token compaction, usage-limit handling, cost ledger per session.\n- **Run modes**: **5 permission modes \xD7 6 effort levels**, thinking budget, per-turn engine/model pick.\n Default permission mode is `bypassPermissions`.\n- **Interactive cards** (~9): permission request, plan review, elicitation, confirm, verification,\n user dialog, skill UI, archive password, unattended report. "Deny & stop" also aborts the turn.\n- **Block renderers** (~9): mission, subagent, report, sources, provenance, event, notice, surface,\n image grid \u2014 plus tool-run cards joined at render time with 6/8-line clamping.\n- **Composer** (~25 actions): attach, slash commands, @-mention, reverse search, screen-region\n capture, element picker, voice, undo-last-turn, queued-message reorder.\n- **Sessions**: list, search (one host-side search across every engine\'s stored conversations),\n resume, summarize, **fork**, merge, delete-message, keep-alive, focus; session mirror + transfer;\n share a conversation by unguessable capability token.\n- **Subsystems**: reinforced verification, plan splitter, narrator (live status strip, capped at 24\n model calls/turn), hook bus (9 events), option ratings, unattended mode.\n- **Also**: a playable **chess** surface (5 tools) and chat slash toys (`/shrug`, `/tableflip`, \u2026).\n\n## 4. Engines, runners, gateway\n\n- **4 engines \xD7 3 auth modes** (`oauth` / `apiKey` / `localCli`), a 24-capability engine matrix,\n engine + model swap mid-session (model/permission-mode reconcile live; effort/cwd/MCP/system-prompt\n force a respawn).\n- **Runner config pool** with rotation, cooldown and failover; auto-retry is bounded and only fires\n when the turn did no work.\n- **Provider gateway** \u2014 a credential-injecting reverse proxy, **19 routes** across AGENT (anthropic,\n openai, google-ai, groq, xai, deepseek, moonshot, openrouter, custom-openai, customer-litellm,\n azure-openai), EMBEDDING, SEARCH (serpapi), VIDEO (heygen, gemini), VOICE, MEDIA (klipy, unsplash,\n pexels). Virtual keys `tsk_live_*`, budgets, LiteLLM price map, spend ledger, credential pools with\n health-based failover that never crosses a category. Models are named the way their makers\n name them \u2014 `claude-sonnet-4-6`, `claude-haiku-4-5-20251001`, `gpt-6-astra`, `gpt-5.5`,\n `gpt-5.4-mini`, `gpt-5.4-nano`, `gemini-2.5-flash`, `gpt-image-2` ($0.10/image flat) \u2014 and a\n signed-in key may also name a model we do not host as `vendor/model`.\n- **Framework cross-product gate**: the user\'s self-updating `claude` CLI \xD7 the pinned Agent SDK,\n verified nightly across pinned CLI versions.\n\n## 5. Files, editors, viewers\n\n- **Finder-like browser**: list/grid/columns, breadcrumbs, bookmarks + OS favourites, **host\n switcher** (every op can be remote), new/rename (F2)/move/duplicate/cut-copy-paste/delete + undo,\n Get Info, send-to-machine, find-in-files, native drag in **and out** (macOS `NSFilePromiseProvider`\n \u2014 drag a not-yet-downloaded remote file to Finder).\n- **~20 typed viewers/editors**: Monaco source editor, PDF (view + edit), Word/docx, spreadsheets,\n presentations, markdown, data grid, hex, audio, video, font, HTML canvas, diff, info.\n- **Archives as folders**: ~20 formats (zip, 7z, tar, gz/bz2/xz/zst, rar, iso, wim, cab, cpio, lzh\u2026)\n browsed, extracted and **edited in place** from the same tree. `rar`/`iso`/`cab` are read-only.\n Encrypted archives prompt for a password and can remember it.\n- **Image editor**: layered canvas, 10 tools (marquee, lasso, move, crop, paint, eraser, fill,\n eyedropper, text, zoom), 25 rail controls, **200+ AI effect styles**, layers, adjust/resize, markup,\n and 3 AI ops (`prompt`/`inpaint`/`outpaint`), transparent-background output, animate\u2192video.\n- **Video editor**: EDL timeline (cut/trim/reorder/transitions/speed/crop/reframe/flip/reverse/colour\n effects/audio tracks), burned-in captions, **18 MCP tools** \u2014 probe, render, frame extract, silence\n detect, transcribe with diarization, extract/isolate audio, music generation, voice list/clone/TTS,\n avatars, caption export, effects, upscale (ffmpeg + local Real-ESRGAN free; fal-Topaz paid).\n- **Undo & time travel**: agent-driven **file rewind** (undo what a turn wrote), file-tree \u2318Z with a\n per-window trash, workspace snapshots and git checkpoints, canvas/design version history with\n diff-and-restore, and message deletion with uniform semantics across engines.\n- **Native inspectors**: **Flutter** widget inspector (tree, on-device tap-to-pick, properties,\n deterministic Dart source edits, hot reload) and **React Native** (source binding + AST edits).\n\n## 6. Create, Design Studio, Stage, Publish\n\n- **Create** \u2014 5 generative document formats (incl. infographic and poster), ~90 actions: outline\n ops, 10 insert kinds, card generation, AI layouts, export.\n- **Design Studio** \u2014 a 10-stage wizard (pick \u2192 launch/browse \u2192 preview \u2192 target \u2192 inspect \u2192 brief \u2192\n build \u2192 QA \u2192 deploy) over **254 templates across 19 industry verticals**, Figma import, in-studio\n theme/token editing.\n- **Stage** \u2014 presentation engine: decks, slides, transitions, **slide audio** (narration/music/sfx\n with music ducking under narration), a live assistant, presenter mode, zoom/blank. 8 present tools\n let the agent drive the deck; followers converge from absolute-state snapshots.\n- **Export**: PowerPoint (.pptx), deck and card export, PNG.\n- **Publish** \u2014 private/org/public visibility, server-rendered public pages on a 192-bit token, live\n data sources (SSRF-guarded), embeds; **community gallery** with explore/following/team/mine, like,\n follow and clone.\n- **Deploy** \u2014 one-click hosting to `*.tesseract.dev` in per-user hardened containers (cap-drop ALL,\n no-new-privileges, read-only, egress-locked), metered on compute/storage/egress. One of the few\n genuinely entitlement-gated features. A separate **per-user cloud agent** container is provisioned\n on demand so you have a machine in the fleet even with every laptop closed.\n\n## 7. Generative media\n\n| What | Notes |\n|---|---|\n| **Images** | 2 providers (OpenAI gpt-image-2, Google). Generate (4-up by default), edit, inpaint/outpaint, transparent background (inpaint + chroma-key). **$0.10/image**. Ungated, BYO key. |\n| **Stock images** | AI-ranked Unsplash/Pexels search as its own tab. Free tier, rate-limited. |\n| **Video** | Google Veo 3.1 \u2014 4/6/8s clips, 720p/1080p, 16:9 or 9:16, keyframe conditioning (first/last frame), native audio. Free on the bundled tier; otherwise cost-confirmed. Multi-scene storyboards chain clip-to-clip for longer videos. |\n| **Avatar video** | HeyGen talking presenter from a script. |\n| **Music / speech** | ElevenLabs music generation, TTS, and instant **voice cloning**. |\n| **Fonts & brand** | Prompt \u2192 AI glyph sheets \u2192 **vision QC** \u2192 vectorize \u2192 kerning/spacing \u2192 a real installable font. Plus logo/wordmark candidates, SVG lockups and a brand kit. Assembly/vectorize/build are local and free. |\n| **Trending effects** | One-tap video effects (hug/kiss, squish, bring-photo-to-life, age, anime restyle, 3D figurine, outfit change, consent-gated face-swap\u2026). |\n\n## 8. Voice\n\n- **3 realtime providers**: OpenAI Realtime, Gemini Live, ElevenLabs ConvAI \u2014 plus a non-realtime\n **STT\u2192LLM\u2192TTS pipeline cascade**. Audio goes **client\u2194provider direct**; the daemon only mints the\n ephemeral credential and runs the control loop.\n- Group calls, live captions, and the **\u2325Space voice widget**.\n- **Voice as a control modality**: the realtime model is the *operator*, Claude Code is the *worker*.\n It decomposes a spoken request into one small dispatched step at a time, all to the same agent\n session, and is explicitly forbidden from claiming an outcome the agent did not report \u2014 when\n unsure it dispatches a check. Its own screen view is a deliberately low-res ~1 fps grab.\n\n## 9. Computer control\n\n- **Two distinct MCP servers**: `tesseract-computer` (**26 tools** \u2014 raw control: move/click/drag/\n scroll/key/type, see_screen, read_text, read_ui (accessibility), clipboard, windows, apps, open\n url/path, notify, annotate, draw) and `tesseract-screen` (**15 tools** \u2014 a guided\n look \u2192 figure_out_next \u2192 perform_step \u2192 **verify** loop that can fail and retry).\n- Plus `tesseract-os-control`: processes, network, structured fs, AX tree + AX actions, preferred app\n and usage profile, screen overlays (arrow/bubble/highlight/text/popup/choice), and\n `request_user_input` / `confirm_action`.\n- **Click grounding** is AX-tree + a local Moondream vision sidecar (free); screenshots are\n Retina-aware and downscaled to point coordinates so clicks line up.\n- **Off by default** \u2014 `computerControlEnabled` must be turned on.\n- **\u2325Space co-pilot HUD** + **13 daemon-owned windows** (spotlight, pastebar, publisher, annotate,\n draw, overlay, input, choice, consent, control-bar, ai-cursor, rdesk call/client), the tray, screen-\n region capture with multi-display number flash, and `tesseract://` deep links. The HUD is\n deliberately **invisible to the AI\'s own screenshots**.\n\n## 10. Integrated browser\n\n- In-app browser tabs with a shared persist partition, per-tab zoom, OAuth popups, URL-safety and\n proxy routing.\n- **Agent control over CDP**: navigate, snapshot, screenshot (viewport + full page), click (synthetic\n and real trusted input), type, key, eval, cookies, raw CDP for any domain, buffered event draining.\n Drives the **user\'s real logged-in browser** via the companion extension, or the built-in engine.\n- **Inspectors**: DOM tree, properties, native inspector; markup pen; click-to-source (JSX elements\n resolve to their source line).\n- **6 Toolkit mission playbooks**: accessibility, GDPR/cookies, health, performance, SEO, UX review \u2014\n each configures, runs, and emits a structured report.\n- **`appbrowser` collaboration**: presence, cursors, comments and edits on a visible tab.\n\n## 11. Web search\n\n`serp_*` over **121 engines / 1,726 parameters**, ~19 tools grouped by family: web, news, images\n(incl. reverse-image and Google Lens), video (incl. YouTube transcripts), maps/local, shopping,\nmarketplaces (Amazon/eBay/Walmart/Home Depot/Zillow), travel (flights/hotels), places & reviews,\nacademic (Scholar/patents), jobs, finance & trends, app stores, ads transparency, social.\nBrokered free tier: **100 searches/month signed in, 10/month anonymous** \u2014 the only hard per-user\nquota in the product.\n\n## 12. Multi-machine\n\n- **Host registry & fleet**: every machine you sign into registers itself; pick one and run the turn\n there. Dual-role nodes are both client and host at once.\n- **Remote fs + terminals** over the relay (9 relayed channels: agent, signal, browser, frame, fs,\n term, editor, rdesk, present). A remote driver may only launch an enumerated interpreter.\n- **File Provider (macOS)**: remote machines appear as native **Finder locations** \u2014 browse, read,\n write, rename, move, Trash + Put Back, thumbnails, progress. Identity survives rename/move.\n- **Drops** \u2014 AirDrop-like sharing to your own devices or another account. E2E-sealed, blind fan-out\n (first device to accept wins; the sender never learns which), receive policies + receive codes,\n blocks and abuse reports that are deliberately **indistinguishable** from "nobody was there".\n- **Universal clipboard**: text/HTML/images fan out to your other machines; >512 KB syncs a thumbnail\n + reference and pulls the bytes on demand. A privacy gate blocks password-manager and secure-input\n content. Plus **paste history** (\u2318\u21E7V pastebar), clipboard over the rdesk channel, and mobile\n text-only sync.\n- **Peer-link**: agent\u2194agent direct transport with a 3-tier ladder (LAN TLS \u2192 observed public IP \u2192\n UDP hole-punch), cert-pinned, relayed only as a fallback.\n- **Mesh VPN**: own PKI with SAS verification, join tickets, recovery mnemonic, a policy bundle with a\n fail-closed freshness clock, an authenticated Noise data plane, disco/path selection, a 25-pair NAT\n punch matrix, and a privileged `netd` helper that **derives** every route itself (the IPC has no\n "add route" field, by design) with journal-based teardown after a crash or reboot.\n- **Remote desktop**: screen share and control. 3 grant paths (same-account registry, cross-account\n code, unattended password), 3 engines (native, VNC, RDP), display picker, quality, Ctrl+Alt+Del,\n in-session voice on the same peer connection, side chat, and a phone viewer.\n- **Present & collaboration**: a presenter drives followers across devices; join codes; live cursors,\n comments and captions.\n- **Co-view mirroring**: a second device with the same conversation open sees **26 allowlisted\n events**. Permission prompts are deliberately *not* mirrored \u2014 a card you can\'t answer is a dead\n button.\n- **Settings & session sync**: keys, tokens, active engine and model are account-wide; `localCli`\n paths are machine-local and must never cross. Plus continuous folder mirroring (active link).\n\n## 13. Team chat & conferencing\n\nSlack-class: spaces, categories, channels, DMs, threads, mentions, reactions, custom emoji, stickers,\nattachments, forum channels, pins, presence, search (Postgres **or** Elasticsearch), link unfurl,\nGIF/meme, bots + a bot API, incoming webhooks, automations, governance, retention and audit.\n**Huddles** over a self-hosted LiveKit SFU with captions and a summary posted back to the channel;\ntoken minting and webhooks work without the SFU, and captions still work when LiveKit is unconfigured.\n\n## 14. Vault (password manager)\n\nZero-knowledge, Argon2id + AES-GCM, server holds only opaque ciphertext. **5 item types** (logins,\npasskeys, payments, secure notes, personal info), ~28 daemon ops, **4 unlock paths** (master password,\ndevice, biometric, **QR from your phone**), sharing sealed to recipient device keys, transfer,\nimport/export (Chrome, Safari, zip), a generator, TOTP, the **macOS AutoFill provider**, and browser\nautofill through the extension.\n\n## 15. Extensions platform\n\nFamilies: **skills, code plugins, bundle plugins, MCP connectors** (3 transports: stdio/http/sse),\nplus **theme packs**. Marketplace discovery with a security verdict that gates install; enable/disable;\nper-extension encrypted secrets; updates; uninstall. Extensions contribute **tabs, panels, settings\npages, status items, menu items and reskins**. First-party skills are free; marketplace ones are\ngated \u2014 `plugins` is the one entitlement actually enforced.\n\n## 16. App Control \u2014 the AI operating Tesseract itself\n\n**144 capabilities across 19 domains** (`settings, navigation, engines, runners, runtimes,\nextensions, hosts, account, daemon, providers, image, voice, permissions, project, privacy, system,\nfonts, present, tour`), exposed as 2 meta-tools + one executor per domain, each input validated\nagainst its own schema. **There is no confirmation gate \u2014 actions happen immediately, by product\ndecision.**\n\n## 17. Platform\n\n- **Accounts**: invite-only (there is **no public sign-up**; Google sign-in on an unknown email is\n rejected), password + Google, password reset, device registration/claim/keys, a CLI device-code\n flow, and an offline-tolerance contract \u2014 only an explicit 401/403 signs you out.\n- **Plans**: `free`, `standard` (shown as **"Pro"**), `pro` (shown as **"Team"**) \u2014 17 feature flags,\n quotas on compute/storage/egress/video, seats, invites, orgs. Your effective plan is the best across\n every org you belong to.\n- **Missions, cron & unattended**: schedule agent turns that run with nobody present, with catch-up\n after downtime, background tasks and structured reports.\n- **Settings**: **23 sections, ~300 controls** \u2014 appearance, editor, general, runners, agent, voice,\n image editing, search, extensions, background tasks, account, team, sync, privacy, file drops,\n remote desktop, permissions, hooks (9 events), env, about, shortcuts (31 rebindable commands).\n- **Theming**: DTCG design tokens, theme packs with **8 independently switchable facets** (colors,\n shape, fonts, background, decorations, sounds, intro, extraCss) and a 3-entry-point **Safe Mode** to\n recover from a bad pack.\n- **Accessibility & motion**: light/dark \xD7 comfortable/compact density throughout, reduced-motion\n and sound-mute as separate switches, and labelled roles on every interactive element. Animation\n is a product requirement, not a preference \u2014 every show/hide, open/close and surface switch is\n animated (140\u2013220ms), and native unstyled controls are not used.\n- **OS permissions**: 7 tracked (microphone, camera, screen recording, full-disk access, accessibility,\n notifications, local network) with per-platform availability; three require a relaunch after grant.\n- **Observability**: crash/error reporting from 6 producers with separate crash and telemetry consent\n (**opt-out \u2014 on unless explicitly disabled**), fingerprinting and grouping, an error inspector, an\n alerting bridge, in-app issue submission, and a GDPR export-and-erase path.\n- **The always-on background service**: the desktop app *is* the daemon (merged process); the slim\n rdesk and mesh builds and the headless CLI keep the classic separate-service model, installed via\n launchd / systemd / Windows services. It self-heals silently, degrades from GUI to headless rather\n than dying, and only one daemon owns a machine at a time. This is why clipboard sync, remote\n access, scheduled turns and the \u2325Space HUD keep working with no app window open.\n- **Connectivity**: the relay is stateless and queues nothing \u2014 a dropped socket re-bootstraps rather\n than replaying. In-flight turns survive a disconnect and stay interruptible.\n- **Updates**: check \u2192 download \u2192 stage \u2192 apply \u2192 relaunch, with an external reaper, log rotation on\n version change and a What\'s New screen. System events (sleep/wake, lock, AC/battery, clock jump,\n displays, interfaces) drive recovery.\n\n## 18. Deliberately NOT built \u2014 do not promise these\n\n- **Create multiplayer co-editing / comments-in-Create** \u2014 deferred; the stores exist but are unwired.\n- **Marketplace** as a product \u2014 brainstorm only.\n- **Team chat**: voice messages, async video clips, keyword alerts, scheduled send, `/remind`, saved\n messages, guest/single-channel access, outgoing webhooks, AI catch-up/digest, public communities,\n nested threads, Block Kit, workflow builder, read receipts, E2E encryption for team chat.\n- **Create/Gamma parity gaps**: todo blocks, GIF/QR/illustrations, media library, form embeds, Google\n Slides export, theme gallery picker, share analytics, public generate API, custom domains, SEO\n toggle, password-protected publish, sites manager.\n- **Hosting**: the managed DB/auth/storage layer, secrets manager, git sync + 1-click Publish.\n- **Mobile**: file browsing, in-app browser, hosting an agent, rendering canvas/surface blocks.\n- **Web app**: undo-delete, local engines, runner configs, the errors panel, open/save-to-code for\n remote hosts.\n- **Mesh**: there is no VPN tunnel a user can turn on yet \u2014 PKI, protocol and data plane are built,\n route execution is not a shipped user feature. No Windows/macOS netd hosting.\n- **Other**: Homebrew formula, Chrome Web Store listing (the extension installs unpacked), Deepgram\n voice, Office (ZetaOffice) editing, AWS Bedrock and Google Vertex gateway routes, VNC clipboard,\n Wayland-specific clipboard handling, RN live widget tree (blocked upstream), the voice tutorial.\n\n## 19. Honest caveats\n\n- **Entitlements are almost entirely unenforced.** Only `plugins` is gated in production, and the\n desktop client is never gated at all. Both the API and the relay **fail open** on billing errors.\n- **Realtime voice has never run live against a provider** \u2014 treat first-run voice as unproven.\n- **HeyGen avatar video has no key configured** as shipped.\n- **The self-hosted web stack has no per-user data isolation** \u2014 auth there is a login wall over one\n shared workspace root.\n- `standard` = "Pro" and `pro` = "Team" \u2014 the plan id and the display name are inverted.\n';
|
|
33289
33310
|
}
|
|
33290
33311
|
});
|
|
33291
33312
|
|
|
@@ -38847,13 +38868,6 @@ async function anthropicCall(args) {
|
|
|
38847
38868
|
}
|
|
38848
38869
|
return { text: null, rateLimited: false };
|
|
38849
38870
|
}
|
|
38850
|
-
function isDirectAnthropic(env) {
|
|
38851
|
-
try {
|
|
38852
|
-
return /(^|\.)api\.anthropic\.com$/i.test(new URL(anthropicBaseUrl(env)).hostname);
|
|
38853
|
-
} catch {
|
|
38854
|
-
return false;
|
|
38855
|
-
}
|
|
38856
|
-
}
|
|
38857
38871
|
async function buildClaudeNarrationLlm(env) {
|
|
38858
38872
|
if (!await hasAnthropicCred(env))
|
|
38859
38873
|
return null;
|
|
@@ -38943,7 +38957,7 @@ async function buildClaudeVisionLlm(env) {
|
|
|
38943
38957
|
]
|
|
38944
38958
|
});
|
|
38945
38959
|
}
|
|
38946
|
-
var execFileP, USAGE_URL, FETCH_TIMEOUT_MS, cache, TTL_MS, RATE_LIMIT_BACKOFF_MS, inFlight, rateLimitedUntil, schemaUnsupported, schemaKey, SMART_TIMEOUT_MS, VISION_TIMEOUT_MS;
|
|
38960
|
+
var execFileP, USAGE_URL, FETCH_TIMEOUT_MS, cache, TTL_MS, RATE_LIMIT_BACKOFF_MS, inFlight, rateLimitedUntil, isDirectAnthropic, schemaUnsupported, schemaKey, SMART_TIMEOUT_MS, VISION_TIMEOUT_MS;
|
|
38947
38961
|
var init_session_usage = __esm({
|
|
38948
38962
|
"../../packages/agent-core/dist/session-usage.js"() {
|
|
38949
38963
|
"use strict";
|
|
@@ -38958,6 +38972,7 @@ var init_session_usage = __esm({
|
|
|
38958
38972
|
RATE_LIMIT_BACKOFF_MS = 5 * 6e4;
|
|
38959
38973
|
inFlight = null;
|
|
38960
38974
|
rateLimitedUntil = 0;
|
|
38975
|
+
isDirectAnthropic = isAnthropicEndpoint;
|
|
38961
38976
|
schemaUnsupported = /* @__PURE__ */ new Set();
|
|
38962
38977
|
schemaKey = (base, model) => `${base}|${model}`;
|
|
38963
38978
|
SMART_TIMEOUT_MS = RV_GRADE_TIMEOUT_MS;
|
|
@@ -39087,7 +39102,7 @@ var init_stream_stall = __esm({
|
|
|
39087
39102
|
// ../../packages/agent-core/dist/model-switch.js
|
|
39088
39103
|
function modelFamily(model) {
|
|
39089
39104
|
const id = (model ?? "").trim().toLowerCase();
|
|
39090
|
-
if (!id
|
|
39105
|
+
if (!id)
|
|
39091
39106
|
return void 0;
|
|
39092
39107
|
return FAMILIES2.find((family) => id.includes(family));
|
|
39093
39108
|
}
|
|
@@ -39492,12 +39507,14 @@ function sessionStoreFor(mode) {
|
|
|
39492
39507
|
function unattendedReportDirective(send5) {
|
|
39493
39508
|
return unattendedModeFor({ optedIn: send5.unattended, origin: send5.origin }) !== "off" ? prompt("agent.system.unattended-report") : "";
|
|
39494
39509
|
}
|
|
39495
|
-
function sdkModelId(model) {
|
|
39510
|
+
function sdkModelId(model, env) {
|
|
39496
39511
|
const id = model?.trim();
|
|
39497
39512
|
if (!id)
|
|
39498
39513
|
return void 0;
|
|
39499
39514
|
if (process.env.TESSERACT_DISABLE_1M_CONTEXT === "1")
|
|
39500
39515
|
return id;
|
|
39516
|
+
if (!isAnthropicEndpoint(env))
|
|
39517
|
+
return id;
|
|
39501
39518
|
if (/[/]/.test(id) || /^[a-z]{2,}\./i.test(id))
|
|
39502
39519
|
return id;
|
|
39503
39520
|
return withOneMillionContext(id) ?? id;
|
|
@@ -41317,7 +41334,7 @@ var init_agent_manager = __esm({
|
|
|
41317
41334
|
return false;
|
|
41318
41335
|
}
|
|
41319
41336
|
try {
|
|
41320
|
-
await live.query.setModel(sdkModelId(next));
|
|
41337
|
+
await live.query.setModel(sdkModelId(next, live.endpointEnv));
|
|
41321
41338
|
} catch (err2) {
|
|
41322
41339
|
log(`[model] ${turnSid}: could not switch to ${next}:`, err2 instanceof Error ? err2.message : String(err2));
|
|
41323
41340
|
return false;
|
|
@@ -42852,7 +42869,7 @@ ${lines}`;
|
|
|
42852
42869
|
if (opts.permissionMode)
|
|
42853
42870
|
await live.query.setPermissionMode(sdkPermissionMode(opts.permissionMode));
|
|
42854
42871
|
if (opts.model !== void 0) {
|
|
42855
|
-
await live.query.setModel(sdkModelId(opts.model));
|
|
42872
|
+
await live.query.setModel(sdkModelId(opts.model, live.endpointEnv));
|
|
42856
42873
|
live.model = opts.model || void 0;
|
|
42857
42874
|
this.rememberSessionModel(live.sessionId, live.model);
|
|
42858
42875
|
}
|
|
@@ -43081,7 +43098,7 @@ ${lines}`;
|
|
|
43081
43098
|
live.windowId = params.windowId;
|
|
43082
43099
|
live.pendingTitle = params.message.trim().slice(0, 80);
|
|
43083
43100
|
if (params.model)
|
|
43084
|
-
void live.query.setModel(sdkModelId(params.model)).catch(() => {
|
|
43101
|
+
void live.query.setModel(sdkModelId(params.model, live.endpointEnv)).catch(() => {
|
|
43085
43102
|
});
|
|
43086
43103
|
if (params.permissionMode)
|
|
43087
43104
|
void live.query.setPermissionMode(sdkPermissionMode(params.permissionMode)).catch(() => {
|
|
@@ -43398,6 +43415,7 @@ ${prompt("agent.system.long-running")}`;
|
|
|
43398
43415
|
}
|
|
43399
43416
|
async createLiveSession(params) {
|
|
43400
43417
|
const spawnModel = this.modelForSpawn(params);
|
|
43418
|
+
const spawnEndpoint = { ...params.env ?? {}, ...params.engineEnv ?? {} };
|
|
43401
43419
|
this.rememberSessionModel(params.sessionId, spawnModel);
|
|
43402
43420
|
this.rememberSessionModel(params.clientRequestId, spawnModel);
|
|
43403
43421
|
const openProject = params.projectDir ?? this.projectDir ?? params.sources?.[0];
|
|
@@ -43559,7 +43577,7 @@ ${prompt("agent.system.long-running")}`;
|
|
|
43559
43577
|
// `modelForSpawn`, not `params.model`: a resume that nobody sent a model with (a
|
|
43560
43578
|
// wake-up after a background task, a daemon-side continuation) would otherwise open a
|
|
43561
43579
|
// 1M conversation against 200k. See sessionModels.
|
|
43562
|
-
...spawnModel ? { model: sdkModelId(spawnModel) } : {},
|
|
43580
|
+
...spawnModel ? { model: sdkModelId(spawnModel, spawnEndpoint) } : {},
|
|
43563
43581
|
// Clamp to what THIS CLI accepts — an unsupported level is a hard exit-1, not
|
|
43564
43582
|
// a warning. See clampEffort.
|
|
43565
43583
|
...ultracodeEffort ? { effort: ultracodeEffort } : {},
|
|
@@ -43568,7 +43586,7 @@ ${prompt("agent.system.long-running")}`;
|
|
|
43568
43586
|
// of surfacing an error the user has to act on.
|
|
43569
43587
|
// Same for the fallback: it REPLACES the main model on an overload, so a bare id here
|
|
43570
43588
|
// would quietly move a long conversation onto a 200k window mid-run.
|
|
43571
|
-
...params.fallbackModel ? { fallbackModel: sdkModelId(params.fallbackModel) } : {},
|
|
43589
|
+
...params.fallbackModel ? { fallbackModel: sdkModelId(params.fallbackModel, spawnEndpoint) } : {},
|
|
43572
43590
|
...params.enableFileCheckpointing ? { enableFileCheckpointing: true } : {},
|
|
43573
43591
|
// ON BY DEFAULT. This is what turns a silent helper into one that says what it is
|
|
43574
43592
|
// doing — a short present-tense line on each progress frame, written by forking the
|
|
@@ -44299,7 +44317,7 @@ ${prompt("agent.system.long-running")}`;
|
|
|
44299
44317
|
// rather than the number in the run-mode menu.
|
|
44300
44318
|
...this.daemonCompactEnv(params.env),
|
|
44301
44319
|
// A GATEWAY MODEL ALIAS MUST NOT BE WINDOW-ENFORCED BY THE CLI. Routed through
|
|
44302
|
-
// our gateway
|
|
44320
|
+
// our gateway it may be a retired tier alias the CLI does not know. Harmless
|
|
44303
44321
|
// for an ordinary query; fatal for its INTERNAL compaction query, which never
|
|
44304
44322
|
// returns — no frame, 120s stall, killed as "connection went quiet", replayed
|
|
44305
44323
|
// by the client, and stalled again every two minutes for ever. MEASURED on a
|
|
@@ -47514,9 +47532,9 @@ function materializeClaudeAuthHome(contents) {
|
|
|
47514
47532
|
});
|
|
47515
47533
|
return home;
|
|
47516
47534
|
}
|
|
47517
|
-
function withClaudeModels(env, main2, fast) {
|
|
47535
|
+
function withClaudeModels(env, main2, fast, longWindow = true) {
|
|
47518
47536
|
if (main2) {
|
|
47519
|
-
env.ANTHROPIC_MODEL = withOneMillionContext(main2) ?? main2;
|
|
47537
|
+
env.ANTHROPIC_MODEL = (longWindow ? withOneMillionContext(main2) : main2) ?? main2;
|
|
47520
47538
|
}
|
|
47521
47539
|
if (fast)
|
|
47522
47540
|
env.ANTHROPIC_SMALL_FAST_MODEL = fast;
|
|
@@ -47563,7 +47581,7 @@ function resolveRunnerEnv(spec) {
|
|
|
47563
47581
|
if (!baseUrl.trim()) {
|
|
47564
47582
|
return { CCB_RUNNER_CONFIG_ERROR: `Set an address for ${provider.label} in Settings \u2192 Models & accounts.` };
|
|
47565
47583
|
}
|
|
47566
|
-
return withClaudeModels({ ANTHROPIC_BASE_URL: baseUrl, ANTHROPIC_AUTH_TOKEN: key2, ANTHROPIC_API_KEY: "" }, main2, fast);
|
|
47584
|
+
return withClaudeModels({ ANTHROPIC_BASE_URL: baseUrl, ANTHROPIC_AUTH_TOKEN: key2, ANTHROPIC_API_KEY: "" }, main2, fast, false);
|
|
47567
47585
|
}
|
|
47568
47586
|
const endpoint2 = routerEndpointSync({
|
|
47569
47587
|
providerId,
|
|
@@ -47637,7 +47655,10 @@ function readGatewayKey() {
|
|
|
47637
47655
|
baseUrl: raw.baseUrl,
|
|
47638
47656
|
apiKey: raw.apiKey,
|
|
47639
47657
|
models: raw.models,
|
|
47640
|
-
...raw.endpoints ? { endpoints: raw.endpoints } : {}
|
|
47658
|
+
...raw.endpoints ? { endpoints: raw.endpoints } : {},
|
|
47659
|
+
// Per-audience defaults (engine + model) travel through too — `tiers()` in shared
|
|
47660
|
+
// honours `defaults.model` on this headless spawn path exactly as the desktop does.
|
|
47661
|
+
...raw.defaults ? { defaults: raw.defaults } : {}
|
|
47641
47662
|
};
|
|
47642
47663
|
}
|
|
47643
47664
|
} catch {
|
|
@@ -48159,29 +48180,6 @@ function readDaemonAgentSettings() {
|
|
|
48159
48180
|
return snap;
|
|
48160
48181
|
}
|
|
48161
48182
|
}
|
|
48162
|
-
function gatewayCanCall(model, snapshot4) {
|
|
48163
|
-
const tiers2 = snapshot4.gatewayTiers;
|
|
48164
|
-
if (!tiers2?.length)
|
|
48165
|
-
return true;
|
|
48166
|
-
return tiers2.includes(model) || snapshot4.gatewayDirectNaming === true;
|
|
48167
|
-
}
|
|
48168
|
-
function gatewayTierRejection(model) {
|
|
48169
|
-
if (!model)
|
|
48170
|
-
return null;
|
|
48171
|
-
const snap = readDaemonAgentSettings();
|
|
48172
|
-
if (gatewayCanCall(model, snap))
|
|
48173
|
-
return null;
|
|
48174
|
-
return { model, tiers: [...snap.gatewayTiers ?? []] };
|
|
48175
|
-
}
|
|
48176
|
-
function gatewayTierClamp(model) {
|
|
48177
|
-
if (!model)
|
|
48178
|
-
return model;
|
|
48179
|
-
const snap = readDaemonAgentSettings();
|
|
48180
|
-
if (gatewayCanCall(model, snap))
|
|
48181
|
-
return model;
|
|
48182
|
-
console.warn(`[gateway] Model "${model}" isn't served by this device's gateway key (${(snap.gatewayTiers ?? []).join(", ")}) \u2014 dropping it so the gateway picks one it can reach.`);
|
|
48183
|
-
return void 0;
|
|
48184
|
-
}
|
|
48185
48183
|
function chatSendToParams(msg, defaults) {
|
|
48186
48184
|
return mergeDaemonAgentSettings({
|
|
48187
48185
|
message: msg.message,
|
|
@@ -48222,7 +48220,6 @@ function chatSendToParams(msg, defaults) {
|
|
|
48222
48220
|
function mergeDaemonAgentSettings(params) {
|
|
48223
48221
|
const s = readDaemonAgentSettings();
|
|
48224
48222
|
const hostModel = poolActiveModel() ?? s.model;
|
|
48225
|
-
const clampToGatewayTier = gatewayTierClamp;
|
|
48226
48223
|
return {
|
|
48227
48224
|
...params,
|
|
48228
48225
|
mcpServers: params.mcpServers ?? s.mcpServers,
|
|
@@ -48232,16 +48229,15 @@ function mergeDaemonAgentSettings(params) {
|
|
|
48232
48229
|
settingSources: params.settingSources ?? s.settingSources,
|
|
48233
48230
|
maxTurns: params.maxTurns ?? s.maxTurns,
|
|
48234
48231
|
maxBudgetUsd: params.maxBudgetUsd ?? s.maxBudgetUsd,
|
|
48235
|
-
model:
|
|
48232
|
+
model: params.model ?? hostModel,
|
|
48236
48233
|
hostInjectedModel: params.hostInjectedModel ?? (params.model === void 0 && hostModel !== void 0),
|
|
48237
48234
|
permissionMode: params.permissionMode ?? s.permissionMode,
|
|
48238
48235
|
effort: params.effort ?? s.effort,
|
|
48239
48236
|
ultracode: params.ultracode ?? s.ultracode,
|
|
48240
48237
|
// Model-level fallback: the engine switches models BEFORE the turn fails. Our runner
|
|
48241
48238
|
// rotation works one level up (credential/config) and only AFTER a failure, so the two
|
|
48242
|
-
// compose rather than compete.
|
|
48243
|
-
|
|
48244
|
-
fallbackModel: clampToGatewayTier(params.fallbackModel ?? s.fallbackModel),
|
|
48239
|
+
// compose rather than compete. Sent as named, like `model`.
|
|
48240
|
+
fallbackModel: params.fallbackModel ?? s.fallbackModel,
|
|
48245
48241
|
// Token budget the MODEL is told about, so it paces tool use and wraps up instead of
|
|
48246
48242
|
// being cut off mid-thought (distinct from maxBudgetUsd, which is dollars and hard).
|
|
48247
48243
|
taskBudget: params.taskBudget ?? s.taskBudget,
|
|
@@ -84110,7 +84106,6 @@ function toRewindOutcome(res, noHistory) {
|
|
|
84110
84106
|
|
|
84111
84107
|
// ../../packages/host-core/dist/control-link.js
|
|
84112
84108
|
import { join as join67, basename as basename12 } from "node:path";
|
|
84113
|
-
import { randomUUID as randomUUID28 } from "node:crypto";
|
|
84114
84109
|
import { mkdirSync as mkdirSync31 } from "node:fs";
|
|
84115
84110
|
|
|
84116
84111
|
// ../../node_modules/ws/wrapper.mjs
|
|
@@ -98523,7 +98518,7 @@ var GeminiVeoProvider = class {
|
|
|
98523
98518
|
};
|
|
98524
98519
|
|
|
98525
98520
|
// ../../packages/video-core/dist/tesseract.js
|
|
98526
|
-
var DEFAULT_MODEL4 = "
|
|
98521
|
+
var DEFAULT_MODEL4 = "veo-3.1-fast-generate-preview";
|
|
98527
98522
|
var REQUEST_TIMEOUT_MS2 = 9e4;
|
|
98528
98523
|
var DOWNLOAD_TIMEOUT_MS2 = 18e4;
|
|
98529
98524
|
var withTimeout4 = (signal2, ms) => signal2 ?? AbortSignal.timeout(ms);
|
|
@@ -99734,8 +99729,8 @@ var VIDEO_PROVIDERS = [
|
|
|
99734
99729
|
{
|
|
99735
99730
|
id: "tesseract",
|
|
99736
99731
|
label: "Tesseract \xB7 free (no key)",
|
|
99737
|
-
defaultModel: "
|
|
99738
|
-
models: ["
|
|
99732
|
+
defaultModel: "veo-3.1-fast-generate-preview",
|
|
99733
|
+
models: ["veo-3.1-fast-generate-preview"],
|
|
99739
99734
|
keysUrl: "",
|
|
99740
99735
|
free: true
|
|
99741
99736
|
},
|
|
@@ -100001,7 +99996,7 @@ var IN_TURN_WAIT_MS = 8 * 6e4;
|
|
|
100001
99996
|
var HEARTBEAT_MS2 = 15e3;
|
|
100002
99997
|
var FAST_MODEL = VIDEO_PROVIDERS.find((p) => p.id === "google").defaultModel;
|
|
100003
99998
|
var STANDARD_MODEL = "veo-3.1-generate-preview";
|
|
100004
|
-
var FREE_MODEL = "
|
|
99999
|
+
var FREE_MODEL = "veo-3.1-fast-generate-preview";
|
|
100005
100000
|
var clampDuration2 = (n) => [4, 6, 8].reduce((best, d) => Math.abs(d - n) < Math.abs(best - n) ? d : best);
|
|
100006
100001
|
function creds2() {
|
|
100007
100002
|
return readDaemonAgentSettings().videoGen;
|
|
@@ -104943,7 +104938,25 @@ var PeerLinkManager = class {
|
|
|
104943
104938
|
const socket2 = await q.makeQuicSocket(this.udpPort);
|
|
104944
104939
|
this.quicSocket = socket2;
|
|
104945
104940
|
await q.startQuicServerOnSocket({ socket: socket2, identity, onStream: (bs5) => this.acceptInbound(bs5, "punch") });
|
|
104941
|
+
const disableQuicTier = (why) => {
|
|
104942
|
+
if (this.quicUnavailable)
|
|
104943
|
+
return;
|
|
104944
|
+
this.quicUnavailable = true;
|
|
104945
|
+
if (this.quicKeepalive) {
|
|
104946
|
+
clearInterval(this.quicKeepalive);
|
|
104947
|
+
this.quicKeepalive = null;
|
|
104948
|
+
}
|
|
104949
|
+
this.quicSocket = null;
|
|
104950
|
+
try {
|
|
104951
|
+
void socket2.stop({ force: true });
|
|
104952
|
+
} catch {
|
|
104953
|
+
}
|
|
104954
|
+
console.warn(`[peer-link] QUIC tier disabled at runtime \u2014 ${why}. Using TCP tiers; a sandbox-safe @matrixai/quic rebuild re-enables it.`);
|
|
104955
|
+
};
|
|
104956
|
+
const isSandboxFailure = (m) => /create external arraybuffer failed/i.test(m);
|
|
104946
104957
|
const refresh = async () => {
|
|
104958
|
+
if (this.quicUnavailable)
|
|
104959
|
+
return;
|
|
104947
104960
|
const found = [];
|
|
104948
104961
|
for (const { host, port } of resolveStunServers()) {
|
|
104949
104962
|
try {
|
|
@@ -104953,7 +104966,12 @@ var PeerLinkManager = class {
|
|
|
104953
104966
|
if (!found.some((c) => c.ip === cand.ip && c.port === cand.port))
|
|
104954
104967
|
found.push(cand);
|
|
104955
104968
|
} catch (e) {
|
|
104956
|
-
|
|
104969
|
+
const detail = e.message;
|
|
104970
|
+
if (isSandboxFailure(detail)) {
|
|
104971
|
+
disableQuicTier(`the native binding rejects this runtime's ArrayBuffers (${detail})`);
|
|
104972
|
+
return;
|
|
104973
|
+
}
|
|
104974
|
+
console.warn(`[peer-link] srflx FAILED via ${host}:${port}: ${detail}`);
|
|
104957
104975
|
}
|
|
104958
104976
|
}
|
|
104959
104977
|
if (found.length && JSON.stringify(found) !== JSON.stringify(this.quicSrflxList)) {
|
|
@@ -104961,6 +104979,14 @@ var PeerLinkManager = class {
|
|
|
104961
104979
|
console.log(`[peer-link] srflx candidates: ${found.map((c) => `${c.ip}:${c.port}`).join(", ")}`);
|
|
104962
104980
|
}
|
|
104963
104981
|
};
|
|
104982
|
+
const onUnhandled = (reason) => {
|
|
104983
|
+
const m = reason instanceof Error ? reason.message : String(reason);
|
|
104984
|
+
if (!isSandboxFailure(m))
|
|
104985
|
+
return;
|
|
104986
|
+
process.off("unhandledRejection", onUnhandled);
|
|
104987
|
+
disableQuicTier(`the native binding rejects this runtime's ArrayBuffers (${m})`);
|
|
104988
|
+
};
|
|
104989
|
+
process.on("unhandledRejection", onUnhandled);
|
|
104964
104990
|
await refresh();
|
|
104965
104991
|
this.quicKeepalive = setInterval(() => {
|
|
104966
104992
|
void refresh();
|
|
@@ -110527,23 +110553,7 @@ async function handleInboundAgent(msg, driverClientId) {
|
|
|
110527
110553
|
void b.backgroundTask?.(msg.sessionId, msg.toolUseId, origin);
|
|
110528
110554
|
break;
|
|
110529
110555
|
case "agent:set_mode":
|
|
110530
|
-
{
|
|
110531
|
-
const rejected = gatewayTierRejection(msg.model);
|
|
110532
|
-
if (rejected) {
|
|
110533
|
-
send3("agent", {
|
|
110534
|
-
type: "agent:notice",
|
|
110535
|
-
sessionId: msg.sessionId,
|
|
110536
|
-
noticeId: randomUUID28(),
|
|
110537
|
-
category: "model",
|
|
110538
|
-
level: "warning",
|
|
110539
|
-
title: "That model is not available on this device",
|
|
110540
|
-
body: `The gateway key on this machine serves ${rejected.tiers.join(", ")}, so "${rejected.model}" was not applied \u2014 the conversation is still on its previous model.`,
|
|
110541
|
-
toast: true,
|
|
110542
|
-
inline: true
|
|
110543
|
-
}, route3);
|
|
110544
|
-
}
|
|
110545
|
-
}
|
|
110546
|
-
void b.setRunMode?.(msg.sessionId, { permissionMode: msg.permissionMode, model: gatewayTierClamp(msg.model), maxThinkingTokens: msg.maxThinkingTokens, unattended: msg.unattended, reinforcedVerification: msg.reinforcedVerification, effort: msg.effort, ultracode: msg.ultracode });
|
|
110556
|
+
void b.setRunMode?.(msg.sessionId, { permissionMode: msg.permissionMode, model: msg.model, maxThinkingTokens: msg.maxThinkingTokens, unattended: msg.unattended, reinforcedVerification: msg.reinforcedVerification, effort: msg.effort, ultracode: msg.ultracode });
|
|
110547
110557
|
break;
|
|
110548
110558
|
case "chat:permission":
|
|
110549
110559
|
b.respondToPermission?.(msg.requestId, { behavior: msg.behavior, updatedInput: msg.updatedInput, persist: msg.persist, message: msg.message, interrupt: msg.interrupt }, origin);
|
|
@@ -111354,7 +111364,7 @@ init_base_paths();
|
|
|
111354
111364
|
init_credentials();
|
|
111355
111365
|
init_dist5();
|
|
111356
111366
|
import { mkdirSync as mkdirSync32, readFileSync as readFileSync42, writeFileSync as writeFileSync28 } from "node:fs";
|
|
111357
|
-
import { randomUUID as
|
|
111367
|
+
import { randomUUID as randomUUID28 } from "node:crypto";
|
|
111358
111368
|
import { dirname as dirname28 } from "node:path";
|
|
111359
111369
|
var REFRESH_MS = 24 * 60 * 60 * 1e3;
|
|
111360
111370
|
var TIMEOUT_MS2 = 1e4;
|
|
@@ -111370,7 +111380,7 @@ function deviceId2() {
|
|
|
111370
111380
|
return raw.deviceId;
|
|
111371
111381
|
} catch {
|
|
111372
111382
|
}
|
|
111373
|
-
const fresh =
|
|
111383
|
+
const fresh = randomUUID28().slice(0, 8);
|
|
111374
111384
|
try {
|
|
111375
111385
|
mkdirSync32(dirname28(DEVICE_ID()), { recursive: true });
|
|
111376
111386
|
writeFileSync28(DEVICE_ID(), JSON.stringify({ deviceId: fresh }), { mode: 384 });
|
|
@@ -113451,7 +113461,6 @@ function stopSystemEvents() {
|
|
|
113451
113461
|
}
|
|
113452
113462
|
|
|
113453
113463
|
// ../../packages/host-core/dist/local-server.js
|
|
113454
|
-
import { randomUUID as randomUUID31 } from "node:crypto";
|
|
113455
113464
|
init_daemon_settings();
|
|
113456
113465
|
|
|
113457
113466
|
// ../../packages/host-core/dist/vault/manager.js
|
|
@@ -114047,7 +114056,7 @@ var XJSON_AAD = utf8("tesseract-vault-encrypted-json-v1");
|
|
|
114047
114056
|
init_credentials();
|
|
114048
114057
|
|
|
114049
114058
|
// ../../packages/host-core/dist/vault/store.js
|
|
114050
|
-
import { randomUUID as
|
|
114059
|
+
import { randomUUID as randomUUID29 } from "node:crypto";
|
|
114051
114060
|
var b64 = (u) => Buffer.from(u).toString("base64");
|
|
114052
114061
|
var u82 = (s) => new Uint8Array(Buffer.from(s, "base64"));
|
|
114053
114062
|
var isServerRecoverableMeta = (m) => !m.wrappedVaultKey;
|
|
@@ -114349,7 +114358,7 @@ var VaultStore = class {
|
|
|
114349
114358
|
const existing = input.id ? items.get(input.id) : void 0;
|
|
114350
114359
|
const { id: _drop, name, folderId, favorite, reprompt, notes, tags, ...content } = input;
|
|
114351
114360
|
const item = {
|
|
114352
|
-
id: input.id ??
|
|
114361
|
+
id: input.id ?? randomUUID29(),
|
|
114353
114362
|
name,
|
|
114354
114363
|
folderId,
|
|
114355
114364
|
favorite,
|
|
@@ -114378,7 +114387,7 @@ var VaultStore = class {
|
|
|
114378
114387
|
const now2 = this.now();
|
|
114379
114388
|
for (const d of drafts) {
|
|
114380
114389
|
const { name, notes, favorite, tags, ...content } = d;
|
|
114381
|
-
const item = { id:
|
|
114390
|
+
const item = { id: randomUUID29(), name, notes, favorite, tags, createdAt: now2, updatedAt: now2, ...content };
|
|
114382
114391
|
items.set(item.id, item);
|
|
114383
114392
|
this.enc.set(item.id, await encryptItem(key2, item));
|
|
114384
114393
|
this.dirty.add(item.id);
|
|
@@ -115421,21 +115430,7 @@ async function startLocalServer(opts) {
|
|
|
115421
115430
|
void b.backgroundTask?.(msg.sessionId, msg.toolUseId, loopbackOrigin);
|
|
115422
115431
|
break;
|
|
115423
115432
|
case "agent:set_mode": {
|
|
115424
|
-
|
|
115425
|
-
if (rejected) {
|
|
115426
|
-
send5("agent", {
|
|
115427
|
-
type: "agent:notice",
|
|
115428
|
-
sessionId: msg.sessionId,
|
|
115429
|
-
noticeId: randomUUID31(),
|
|
115430
|
-
category: "model",
|
|
115431
|
-
level: "warning",
|
|
115432
|
-
title: "That model is not available on this device",
|
|
115433
|
-
body: `Your gateway key serves ${rejected.tiers.join(", ")}, so "${rejected.model}" was not applied \u2014 the conversation is still on its previous model.`,
|
|
115434
|
-
toast: true,
|
|
115435
|
-
inline: true
|
|
115436
|
-
});
|
|
115437
|
-
}
|
|
115438
|
-
void b.setRunMode?.(msg.sessionId, { permissionMode: msg.permissionMode, model: gatewayTierClamp(msg.model), maxThinkingTokens: msg.maxThinkingTokens, unattended: msg.unattended, reinforcedVerification: msg.reinforcedVerification, effort: msg.effort, ultracode: msg.ultracode });
|
|
115433
|
+
void b.setRunMode?.(msg.sessionId, { permissionMode: msg.permissionMode, model: msg.model, maxThinkingTokens: msg.maxThinkingTokens, unattended: msg.unattended, reinforcedVerification: msg.reinforcedVerification, effort: msg.effort, ultracode: msg.ultracode });
|
|
115439
115434
|
break;
|
|
115440
115435
|
}
|
|
115441
115436
|
case "chat:permission":
|
|
@@ -119484,7 +119479,7 @@ async function fetchBlobDrop(opts) {
|
|
|
119484
119479
|
}
|
|
119485
119480
|
|
|
119486
119481
|
// ../../packages/host-core/dist/chat-agent.js
|
|
119487
|
-
import { randomUUID as
|
|
119482
|
+
import { randomUUID as randomUUID30 } from "node:crypto";
|
|
119488
119483
|
init_prompts();
|
|
119489
119484
|
var TURN_TIMEOUT_MS = 4 * 6e4;
|
|
119490
119485
|
var PARTIAL_INTERVAL_MS = 700;
|
|
@@ -119513,7 +119508,7 @@ function createChatAgentRunner(deps) {
|
|
|
119513
119508
|
}
|
|
119514
119509
|
async function runTurn(prompt2, onPartial) {
|
|
119515
119510
|
const backend2 = await getSharedBackend();
|
|
119516
|
-
const clientRequestId = `chat-agent-${
|
|
119511
|
+
const clientRequestId = `chat-agent-${randomUUID30()}`;
|
|
119517
119512
|
return new Promise((resolve16, reject) => {
|
|
119518
119513
|
let text13 = "";
|
|
119519
119514
|
let settled = false;
|
|
@@ -121539,7 +121534,7 @@ init_credentials();
|
|
|
121539
121534
|
init_base_paths();
|
|
121540
121535
|
import { existsSync as existsSync47, mkdirSync as mkdirSync46, readFileSync as readFileSync57, writeFileSync as writeFileSync43 } from "node:fs";
|
|
121541
121536
|
import { dirname as dirname39, join as join88 } from "node:path";
|
|
121542
|
-
import { randomUUID as
|
|
121537
|
+
import { randomUUID as randomUUID31 } from "node:crypto";
|
|
121543
121538
|
function deviceIdFile() {
|
|
121544
121539
|
return join88(tesseractHome(), "device-id.json");
|
|
121545
121540
|
}
|
|
@@ -121555,7 +121550,7 @@ function persistentDeviceId() {
|
|
|
121555
121550
|
const cur = readPersistedDeviceId();
|
|
121556
121551
|
if (cur)
|
|
121557
121552
|
return cur;
|
|
121558
|
-
const id =
|
|
121553
|
+
const id = randomUUID31().slice(0, 8);
|
|
121559
121554
|
try {
|
|
121560
121555
|
const f = deviceIdFile();
|
|
121561
121556
|
const dir2 = dirname39(f);
|
|
@@ -121570,7 +121565,7 @@ function persistentDeviceId() {
|
|
|
121570
121565
|
// ../../packages/host-core/dist/error-report.js
|
|
121571
121566
|
init_dist2();
|
|
121572
121567
|
init_credentials();
|
|
121573
|
-
import { randomUUID as
|
|
121568
|
+
import { randomUUID as randomUUID32 } from "node:crypto";
|
|
121574
121569
|
import { release as osRelease, arch as osArch } from "node:os";
|
|
121575
121570
|
var MAX_QUEUE = 100;
|
|
121576
121571
|
var FLUSH_INTERVAL_MS = 3e4;
|
|
@@ -121622,7 +121617,7 @@ function captureDaemonError(error51, opts = {}) {
|
|
|
121622
121617
|
return;
|
|
121623
121618
|
const creds3 = readCredentials();
|
|
121624
121619
|
const report = {
|
|
121625
|
-
reportId:
|
|
121620
|
+
reportId: randomUUID32(),
|
|
121626
121621
|
occurredAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
121627
121622
|
schemaVersion: 1,
|
|
121628
121623
|
surface,
|