@gtc6244/immediacy-daemon 0.1.1 → 0.1.3
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/README.md +58 -25
- package/dist/src/agent/agent.d.ts +19 -6
- package/dist/src/agent/agent.js +3 -1
- package/dist/src/agent/agent.js.map +1 -1
- package/dist/src/agent/anthropic-probe.d.ts +24 -0
- package/dist/src/agent/anthropic-probe.js +81 -0
- package/dist/src/agent/anthropic-probe.js.map +1 -0
- package/dist/src/agent/claude.d.ts +4 -2
- package/dist/src/agent/claude.js +32 -4
- package/dist/src/agent/claude.js.map +1 -1
- package/dist/src/agent/codex.d.ts +1 -1
- package/dist/src/agent/codex.js +26 -3
- package/dist/src/agent/codex.js.map +1 -1
- package/dist/src/agent/images.d.ts +21 -0
- package/dist/src/agent/images.js +54 -0
- package/dist/src/agent/images.js.map +1 -0
- package/dist/src/agent/mock.d.ts +1 -1
- package/dist/src/agent/mock.js +28 -3
- package/dist/src/agent/mock.js.map +1 -1
- package/dist/src/agent/ollama-probe.d.ts +28 -0
- package/dist/src/agent/ollama-probe.js +76 -0
- package/dist/src/agent/ollama-probe.js.map +1 -0
- package/dist/src/agent/ollama.d.ts +42 -0
- package/dist/src/agent/ollama.js +64 -0
- package/dist/src/agent/ollama.js.map +1 -0
- package/dist/src/agent/openai-probe.d.ts +18 -0
- package/dist/src/agent/openai-probe.js +83 -0
- package/dist/src/agent/openai-probe.js.map +1 -0
- package/dist/src/agent/openrouter-probe.d.ts +21 -0
- package/dist/src/agent/openrouter-probe.js +77 -0
- package/dist/src/agent/openrouter-probe.js.map +1 -0
- package/dist/src/cli/paths.d.ts +2 -0
- package/dist/src/cli/paths.js +14 -7
- package/dist/src/cli/paths.js.map +1 -1
- package/dist/src/cli.js +40 -0
- package/dist/src/cli.js.map +1 -1
- package/dist/src/crypto.js +7 -2
- package/dist/src/crypto.js.map +1 -1
- package/dist/src/hub.d.ts +7 -0
- package/dist/src/hub.js +14 -0
- package/dist/src/hub.js.map +1 -1
- package/dist/src/index.d.ts +3 -0
- package/dist/src/index.js +35 -3
- package/dist/src/index.js.map +1 -1
- package/dist/src/jobs/scheduler.d.ts +1 -0
- package/dist/src/jobs/scheduler.js +1 -0
- package/dist/src/jobs/scheduler.js.map +1 -1
- package/dist/src/media-watch.d.ts +29 -0
- package/dist/src/media-watch.js +108 -0
- package/dist/src/media-watch.js.map +1 -0
- package/dist/src/media.d.ts +54 -0
- package/dist/src/media.js +156 -0
- package/dist/src/media.js.map +1 -0
- package/dist/src/model-efforts.d.ts +49 -0
- package/dist/src/model-efforts.js +107 -0
- package/dist/src/model-efforts.js.map +1 -0
- package/dist/src/models.d.ts +50 -17
- package/dist/src/models.js +119 -21
- package/dist/src/models.js.map +1 -1
- package/dist/src/projects.d.ts +7 -0
- package/dist/src/projects.js +14 -0
- package/dist/src/projects.js.map +1 -1
- package/dist/src/protocol.d.ts +163 -9
- package/dist/src/protocol.js +1 -1
- package/dist/src/server.js +141 -5
- package/dist/src/server.js.map +1 -1
- package/dist/src/types.d.ts +9 -0
- package/dist/src/updater.d.ts +78 -0
- package/dist/src/updater.js +240 -0
- package/dist/src/updater.js.map +1 -0
- package/dist/src/workspace.d.ts +25 -0
- package/dist/src/workspace.js +159 -6
- package/dist/src/workspace.js.map +1 -1
- package/package.json +4 -2
- package/dist/src/migrate-state-dir.d.ts +0 -1
- package/dist/src/migrate-state-dir.js +0 -47
- package/dist/src/migrate-state-dir.js.map +0 -1
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MediaStore — durable, content-addressed store for agent-produced images.
|
|
3
|
+
*
|
|
4
|
+
* When an agent surfaces an image (a screenshot returned by a tool, or a PNG it
|
|
5
|
+
* wrote into the worktree), the daemon persists the bytes here and broadcasts a
|
|
6
|
+
* lightweight `event.assistant_image` carrying only metadata (id + mediaType +
|
|
7
|
+
* size). Clients fetch the bytes on demand (`media.get`, or the web app's
|
|
8
|
+
* immutable `/media/<ws>/<id>` HTTP endpoint), so multi-MB screenshots never
|
|
9
|
+
* bloat event frames, the chatlog, or the E2E-sealed channel.
|
|
10
|
+
*
|
|
11
|
+
* Files live under `~/.immediacy/media/<wsId>/<id>.<ext>` (override via
|
|
12
|
+
* MEDIA_DIR), mirroring the per-workspace partitioning of the chatlog — so
|
|
13
|
+
* removing a workspace's media is a single directory delete, and the orphan
|
|
14
|
+
* sweep can reconcile against the live workspace set.
|
|
15
|
+
*
|
|
16
|
+
* The id is the sha256 of the bytes, so identical images collapse to one file
|
|
17
|
+
* and the id is a stable, immutable cache key clients can persist forever.
|
|
18
|
+
*/
|
|
19
|
+
import { createHash } from "node:crypto";
|
|
20
|
+
import { mkdir, readdir, readFile, rm, stat, writeFile } from "node:fs/promises";
|
|
21
|
+
import { homedir } from "node:os";
|
|
22
|
+
import { join } from "node:path";
|
|
23
|
+
import { logger } from "./log.js";
|
|
24
|
+
const MEDIA_DIR = process.env.MEDIA_DIR ?? join(homedir(), ".immediacy", "media");
|
|
25
|
+
export class MediaStore {
|
|
26
|
+
dir;
|
|
27
|
+
constructor(dir = MEDIA_DIR) {
|
|
28
|
+
this.dir = dir;
|
|
29
|
+
}
|
|
30
|
+
wsDir(ws) {
|
|
31
|
+
return join(this.dir, safeId(ws));
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Persist an image for a workspace and return its metadata. Idempotent: the
|
|
35
|
+
* same bytes hash to the same id, so a re-emitted screenshot is written once.
|
|
36
|
+
* `name` is a display hint (e.g. a relative worktree path for a file-sourced
|
|
37
|
+
* image); a default is synthesized from the id + type otherwise.
|
|
38
|
+
*/
|
|
39
|
+
async put(ws, mediaType, base64, name) {
|
|
40
|
+
const bytes = Buffer.from(base64, "base64");
|
|
41
|
+
const id = createHash("sha256").update(bytes).digest("hex");
|
|
42
|
+
const ext = extFor(mediaType);
|
|
43
|
+
const file = join(this.wsDir(ws), `${id}.${ext}`);
|
|
44
|
+
await mkdir(this.wsDir(ws), { recursive: true });
|
|
45
|
+
// Content-addressed → if it already exists, the bytes are identical.
|
|
46
|
+
if (!(await exists(file)))
|
|
47
|
+
await writeFile(file, bytes);
|
|
48
|
+
return {
|
|
49
|
+
id,
|
|
50
|
+
name: name && name.trim() ? name : `image-${id.slice(0, 8)}.${ext}`,
|
|
51
|
+
mediaType,
|
|
52
|
+
size: bytes.length,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
/** Fetch stored bytes by id (base64), or null if absent. */
|
|
56
|
+
async get(ws, id) {
|
|
57
|
+
if (!isHexId(id))
|
|
58
|
+
return null; // ids are sha256 hex; reject anything else
|
|
59
|
+
let names;
|
|
60
|
+
try {
|
|
61
|
+
names = await readdir(this.wsDir(ws));
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
const match = names.find((n) => n.startsWith(`${id}.`));
|
|
67
|
+
if (!match)
|
|
68
|
+
return null;
|
|
69
|
+
try {
|
|
70
|
+
const bytes = await readFile(join(this.wsDir(ws), match));
|
|
71
|
+
return { mediaType: mimeFor(match), data: bytes.toString("base64") };
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/** Drop all media for a workspace (Tier-1 cleanup on workspace removal). */
|
|
78
|
+
async remove(ws) {
|
|
79
|
+
try {
|
|
80
|
+
await rm(this.wsDir(ws), { recursive: true, force: true });
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
/* best-effort */
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/** Workspace ids that currently have a media directory (for the orphan sweep). */
|
|
87
|
+
async listWorkspaces() {
|
|
88
|
+
try {
|
|
89
|
+
const entries = await readdir(this.dir, { withFileTypes: true });
|
|
90
|
+
return entries.filter((e) => e.isDirectory()).map((e) => e.name);
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
return [];
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Tier-2 orphan sweep: delete media dirs whose workspace id is not in `live`.
|
|
98
|
+
* Returns the number of workspace dirs removed. Best-effort; never throws.
|
|
99
|
+
*/
|
|
100
|
+
async sweepOrphans(live) {
|
|
101
|
+
let removed = 0;
|
|
102
|
+
for (const ws of await this.listWorkspaces()) {
|
|
103
|
+
if (live.has(ws))
|
|
104
|
+
continue;
|
|
105
|
+
try {
|
|
106
|
+
await rm(join(this.dir, ws), { recursive: true, force: true });
|
|
107
|
+
removed++;
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
/* best-effort */
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
if (removed > 0) {
|
|
114
|
+
logger.info("system", "media orphan sweep removed workspace media", {
|
|
115
|
+
data: { removed },
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
return removed;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
const MIME_EXT = {
|
|
122
|
+
"image/png": "png",
|
|
123
|
+
"image/jpeg": "jpg",
|
|
124
|
+
"image/gif": "gif",
|
|
125
|
+
"image/webp": "webp",
|
|
126
|
+
"image/bmp": "bmp",
|
|
127
|
+
"image/svg+xml": "svg",
|
|
128
|
+
};
|
|
129
|
+
const EXT_MIME = Object.fromEntries(Object.entries(MIME_EXT).map(([m, e]) => [e, m]));
|
|
130
|
+
function extFor(mediaType) {
|
|
131
|
+
return MIME_EXT[mediaType] ?? "bin";
|
|
132
|
+
}
|
|
133
|
+
function mimeFor(fileName) {
|
|
134
|
+
const ext = fileName.split(".").pop()?.toLowerCase() ?? "";
|
|
135
|
+
return EXT_MIME[ext] ?? "application/octet-stream";
|
|
136
|
+
}
|
|
137
|
+
async function exists(p) {
|
|
138
|
+
try {
|
|
139
|
+
await stat(p);
|
|
140
|
+
return true;
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
function isHexId(id) {
|
|
147
|
+
return /^[a-f0-9]{64}$/.test(id);
|
|
148
|
+
}
|
|
149
|
+
/** Guard a workspace id used as a directory name against path traversal. */
|
|
150
|
+
function safeId(ws) {
|
|
151
|
+
if (!/^[A-Za-z0-9._-]+$/.test(ws) || ws === "." || ws === "..") {
|
|
152
|
+
throw new Error(`unsafe workspace id: ${JSON.stringify(ws)}`);
|
|
153
|
+
}
|
|
154
|
+
return ws;
|
|
155
|
+
}
|
|
156
|
+
//# sourceMappingURL=media.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"media.js","sourceRoot":"","sources":["../../src/media.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reasoning-effort policy — the single source of truth for which effort levels
|
|
3
|
+
* each provider/family exposes, and the labels shown to clients.
|
|
4
|
+
*
|
|
5
|
+
* Effort ("how hard the model thinks") is a per-model knob:
|
|
6
|
+
* - Claude → low / medium / high / xhigh / max, gated by model family
|
|
7
|
+
* (see effortsForClaude). Handed to the Agent SDK's `effort`
|
|
8
|
+
* option; unsupported levels are silently downgraded by the CLI.
|
|
9
|
+
* - Codex → minimal / low / medium / high, passed to the Codex CLI as
|
|
10
|
+
* `-c model_reasoning_effort=<level>`.
|
|
11
|
+
* - OpenRouter → low / medium / high when the model advertises `reasoning`
|
|
12
|
+
* in its `supported_parameters`.
|
|
13
|
+
* - Ollama → none.
|
|
14
|
+
*
|
|
15
|
+
* Discovery probes (anthropic/openai/openrouter) and the static fallback
|
|
16
|
+
* catalog in models.ts both call these helpers, so a model carries the same
|
|
17
|
+
* effort set however it was surfaced.
|
|
18
|
+
*/
|
|
19
|
+
import type { ModelEffort } from "./protocol.js";
|
|
20
|
+
/** True if `iso` is missing/unparseable or falls within the trailing 12 months. */
|
|
21
|
+
export declare function withinLastYear(iso?: string): boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Effort levels a Claude model supports, by family (per Anthropic's effort docs):
|
|
24
|
+
* - Fable / Mythos, Opus 4.7+/4.8 → low, medium, high, xhigh, max
|
|
25
|
+
* - Opus 4.6, Sonnet 4.6 → low, medium, high, max
|
|
26
|
+
* - Opus 4.5 → low, medium, high
|
|
27
|
+
* - Sonnet 4.5 / Haiku / older → none (effort would error / no-op)
|
|
28
|
+
* Returns undefined when the model has no effort knob.
|
|
29
|
+
*/
|
|
30
|
+
export declare function effortsForClaude(id: string): ModelEffort[] | undefined;
|
|
31
|
+
/**
|
|
32
|
+
* Effort levels a Codex/OpenAI model supports:
|
|
33
|
+
* - GPT-5 family → minimal, low, medium, high
|
|
34
|
+
* - o-series (o1/o3/o4…) → low, medium, high
|
|
35
|
+
* - everything else (incl. the "codex" account-default sentinel) → none
|
|
36
|
+
*/
|
|
37
|
+
export declare function effortsForCodex(id: string): ModelEffort[] | undefined;
|
|
38
|
+
/**
|
|
39
|
+
* Effort levels for an OpenRouter model — low/medium/high when it advertises
|
|
40
|
+
* `reasoning` support, else none. OpenRouter maps these onto its
|
|
41
|
+
* `reasoning: { effort }` request field.
|
|
42
|
+
*/
|
|
43
|
+
export declare function effortsForOpenRouter(supportedParameters?: string[]): ModelEffort[] | undefined;
|
|
44
|
+
/** Prefer "high" for Claude (the coding/agentic sweet spot), else the top level. */
|
|
45
|
+
export declare function DEFAULT_CLAUDE_EFFORT(efforts: ModelEffort[]): string;
|
|
46
|
+
/** Prefer "medium" for Codex, else the top level. */
|
|
47
|
+
export declare function DEFAULT_CODEX_EFFORT(efforts: ModelEffort[]): string;
|
|
48
|
+
/** Prefer "medium" for OpenRouter, else the top level. */
|
|
49
|
+
export declare function DEFAULT_OPENROUTER_EFFORT(efforts: ModelEffort[]): string;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reasoning-effort policy — the single source of truth for which effort levels
|
|
3
|
+
* each provider/family exposes, and the labels shown to clients.
|
|
4
|
+
*
|
|
5
|
+
* Effort ("how hard the model thinks") is a per-model knob:
|
|
6
|
+
* - Claude → low / medium / high / xhigh / max, gated by model family
|
|
7
|
+
* (see effortsForClaude). Handed to the Agent SDK's `effort`
|
|
8
|
+
* option; unsupported levels are silently downgraded by the CLI.
|
|
9
|
+
* - Codex → minimal / low / medium / high, passed to the Codex CLI as
|
|
10
|
+
* `-c model_reasoning_effort=<level>`.
|
|
11
|
+
* - OpenRouter → low / medium / high when the model advertises `reasoning`
|
|
12
|
+
* in its `supported_parameters`.
|
|
13
|
+
* - Ollama → none.
|
|
14
|
+
*
|
|
15
|
+
* Discovery probes (anthropic/openai/openrouter) and the static fallback
|
|
16
|
+
* catalog in models.ts both call these helpers, so a model carries the same
|
|
17
|
+
* effort set however it was surfaced.
|
|
18
|
+
*/
|
|
19
|
+
const YEAR_MS = 365 * 24 * 60 * 60 * 1000;
|
|
20
|
+
/** Human-readable label for each effort id. */
|
|
21
|
+
const EFFORT_LABELS = {
|
|
22
|
+
minimal: "Minimal",
|
|
23
|
+
low: "Low",
|
|
24
|
+
medium: "Medium",
|
|
25
|
+
high: "High",
|
|
26
|
+
xhigh: "Extra high",
|
|
27
|
+
max: "Max",
|
|
28
|
+
};
|
|
29
|
+
/** Build `ModelEffort[]` from ordered ids, labeling each from the table above. */
|
|
30
|
+
function mk(ids) {
|
|
31
|
+
return ids.map((id) => ({ id, label: EFFORT_LABELS[id] ?? id }));
|
|
32
|
+
}
|
|
33
|
+
/** True if `iso` is missing/unparseable or falls within the trailing 12 months. */
|
|
34
|
+
export function withinLastYear(iso) {
|
|
35
|
+
if (!iso)
|
|
36
|
+
return true;
|
|
37
|
+
const t = Date.parse(iso);
|
|
38
|
+
if (Number.isNaN(t))
|
|
39
|
+
return true;
|
|
40
|
+
return t >= Date.now() - YEAR_MS;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Effort levels a Claude model supports, by family (per Anthropic's effort docs):
|
|
44
|
+
* - Fable / Mythos, Opus 4.7+/4.8 → low, medium, high, xhigh, max
|
|
45
|
+
* - Opus 4.6, Sonnet 4.6 → low, medium, high, max
|
|
46
|
+
* - Opus 4.5 → low, medium, high
|
|
47
|
+
* - Sonnet 4.5 / Haiku / older → none (effort would error / no-op)
|
|
48
|
+
* Returns undefined when the model has no effort knob.
|
|
49
|
+
*/
|
|
50
|
+
export function effortsForClaude(id) {
|
|
51
|
+
const s = id.toLowerCase();
|
|
52
|
+
if (/fable|mythos/.test(s))
|
|
53
|
+
return mk(["low", "medium", "high", "xhigh", "max"]);
|
|
54
|
+
if (/opus-4-(7|8)\b/.test(s))
|
|
55
|
+
return mk(["low", "medium", "high", "xhigh", "max"]);
|
|
56
|
+
if (/opus-4-6\b/.test(s))
|
|
57
|
+
return mk(["low", "medium", "high", "max"]);
|
|
58
|
+
if (/sonnet-4-6\b/.test(s))
|
|
59
|
+
return mk(["low", "medium", "high", "max"]);
|
|
60
|
+
if (/opus-4-5\b/.test(s))
|
|
61
|
+
return mk(["low", "medium", "high"]);
|
|
62
|
+
return undefined;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Effort levels a Codex/OpenAI model supports:
|
|
66
|
+
* - GPT-5 family → minimal, low, medium, high
|
|
67
|
+
* - o-series (o1/o3/o4…) → low, medium, high
|
|
68
|
+
* - everything else (incl. the "codex" account-default sentinel) → none
|
|
69
|
+
*/
|
|
70
|
+
export function effortsForCodex(id) {
|
|
71
|
+
const s = id.toLowerCase();
|
|
72
|
+
if (s === "codex")
|
|
73
|
+
return undefined;
|
|
74
|
+
if (/^gpt-5/.test(s))
|
|
75
|
+
return mk(["minimal", "low", "medium", "high"]);
|
|
76
|
+
if (/^o[0-9]/.test(s))
|
|
77
|
+
return mk(["low", "medium", "high"]);
|
|
78
|
+
return undefined;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Effort levels for an OpenRouter model — low/medium/high when it advertises
|
|
82
|
+
* `reasoning` support, else none. OpenRouter maps these onto its
|
|
83
|
+
* `reasoning: { effort }` request field.
|
|
84
|
+
*/
|
|
85
|
+
export function effortsForOpenRouter(supportedParameters) {
|
|
86
|
+
if (supportedParameters?.includes("reasoning")) {
|
|
87
|
+
return mk(["low", "medium", "high"]);
|
|
88
|
+
}
|
|
89
|
+
return undefined;
|
|
90
|
+
}
|
|
91
|
+
/** Prefer "high" for Claude (the coding/agentic sweet spot), else the top level. */
|
|
92
|
+
export function DEFAULT_CLAUDE_EFFORT(efforts) {
|
|
93
|
+
return pick(efforts, "high");
|
|
94
|
+
}
|
|
95
|
+
/** Prefer "medium" for Codex, else the top level. */
|
|
96
|
+
export function DEFAULT_CODEX_EFFORT(efforts) {
|
|
97
|
+
return pick(efforts, "medium");
|
|
98
|
+
}
|
|
99
|
+
/** Prefer "medium" for OpenRouter, else the top level. */
|
|
100
|
+
export function DEFAULT_OPENROUTER_EFFORT(efforts) {
|
|
101
|
+
return pick(efforts, "medium");
|
|
102
|
+
}
|
|
103
|
+
function pick(efforts, preferred) {
|
|
104
|
+
const hit = efforts.find((e) => e.id === preferred);
|
|
105
|
+
return (hit ?? efforts[efforts.length - 1])?.id ?? preferred;
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=model-efforts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-efforts.js","sourceRoot":"","sources":["../../src/model-efforts.ts"],"names":[],"mappings":"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"}
|
package/dist/src/models.d.ts
CHANGED
|
@@ -1,36 +1,69 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Model catalog — the daemon's source of truth for which agent models
|
|
3
|
-
* may pick from.
|
|
2
|
+
* Model catalog — the daemon's source of truth for which agent models (and, for
|
|
3
|
+
* models that support it, which reasoning-effort levels) the app may pick from.
|
|
4
4
|
*
|
|
5
5
|
* A model's `provider` decides which agent backend runs it:
|
|
6
|
-
* - "claude" → ClaudeAgent (Agent SDK, `model`
|
|
7
|
-
* - "codex" → CodexAgent (OpenAI Codex CLI, `-m`
|
|
6
|
+
* - "claude" → ClaudeAgent (Agent SDK, `model` + `effort` options)
|
|
7
|
+
* - "codex" → CodexAgent (OpenAI Codex CLI, `-m` + `-c
|
|
8
|
+
* model_reasoning_effort=<level>`)
|
|
8
9
|
* - "openrouter" → OpenRouterAgent (Agent SDK against OpenRouter's
|
|
9
|
-
* Anthropic-compatible endpoint;
|
|
10
|
-
* `vendor/model` slug
|
|
10
|
+
* Anthropic-compatible endpoint; `id` is an OpenRouter
|
|
11
|
+
* `vendor/model` slug)
|
|
12
|
+
* - "ollama" → OllamaAgent (Agent SDK against a local Ollama's
|
|
13
|
+
* Anthropic-compatible endpoint; `id` is an Ollama model tag.
|
|
14
|
+
* Runs on-device, no key, no billing)
|
|
11
15
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
16
|
+
* DISCOVERY. Online providers are enumerated live from their model APIs and
|
|
17
|
+
* scoped to the last 12 months (see anthropic/openai/openrouter-probe.ts); the
|
|
18
|
+
* effort levels each model supports come from model-efforts.ts. Ollama is
|
|
19
|
+
* discovered from whatever is installed locally (every model, no date filter).
|
|
20
|
+
* The static {@link FALLBACK_MODELS} below is only used for a provider whose
|
|
21
|
+
* live probe returned nothing — no API key, or an unreachable endpoint — so the
|
|
22
|
+
* picker is never empty. `id` is the exact string handed to the backend.
|
|
23
|
+
*
|
|
24
|
+
* The Dart mirror is packages/immediacy_core/lib/models.dart (ModelInfo /
|
|
25
|
+
* ModelEffort shape only).
|
|
15
26
|
*/
|
|
16
27
|
import type { ModelInfo, ModelProvider } from "./protocol.js";
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
*/
|
|
22
|
-
export declare const MODELS: ModelInfo[];
|
|
23
|
-
export declare const DEFAULT_MODEL: ModelInfo;
|
|
28
|
+
import type { CredentialsStore } from "./credentials.js";
|
|
29
|
+
/** The id backing new workspaces when a client doesn't pick a model. */
|
|
30
|
+
export declare const DEFAULT_MODEL_ID = "claude-opus-4-8";
|
|
31
|
+
export declare const FALLBACK_MODELS: ModelInfo[];
|
|
24
32
|
/**
|
|
25
33
|
* Sentinel Codex model id meaning "don't pass -m; use the account's default".
|
|
26
34
|
* Passing an explicit model id requires API-key billing; a ChatGPT-login Codex
|
|
27
35
|
* only accepts its plan default, so this is the safe cross-setup choice.
|
|
28
36
|
*/
|
|
29
37
|
export declare const CODEX_DEFAULT_MODEL = "codex";
|
|
30
|
-
/**
|
|
38
|
+
/**
|
|
39
|
+
* The full catalog surfaced to clients: live-discovered online models (Claude /
|
|
40
|
+
* Codex / OpenRouter, scoped to the last 12 months) plus every locally-installed
|
|
41
|
+
* Ollama model. A provider with no live results falls back to its curated static
|
|
42
|
+
* entries so the picker is never empty. Recomputed on each read so a fresh probe
|
|
43
|
+
* shows up without restarting the daemon.
|
|
44
|
+
*/
|
|
45
|
+
export declare function allModels(): ModelInfo[];
|
|
46
|
+
/** The model that backs new workspaces when a client doesn't pick one. */
|
|
47
|
+
export declare function defaultModel(): ModelInfo;
|
|
48
|
+
/**
|
|
49
|
+
* Refresh every provider's catalog from its live API, using the resolved key
|
|
50
|
+
* for each (Anthropic/OpenAI from CredentialsStore; OpenRouter listing is
|
|
51
|
+
* keyless; Ollama is local). Runs the four probes concurrently; each is
|
|
52
|
+
* independently best-effort and never throws.
|
|
53
|
+
*/
|
|
54
|
+
export declare function refreshAllModels(credentials?: CredentialsStore, force?: boolean): Promise<void>;
|
|
55
|
+
/** Look up a model by id (undefined id → the default). Includes discovered
|
|
56
|
+
* online + Ollama models so a workspace resolves to the right backend. */
|
|
31
57
|
export declare function modelById(id?: string): ModelInfo | undefined;
|
|
32
58
|
/**
|
|
33
59
|
* Which backend runs a given model id. Unknown or missing ids fall back to
|
|
34
60
|
* "claude" so restored/legacy workspaces keep working.
|
|
35
61
|
*/
|
|
36
62
|
export declare function providerFor(id?: string): ModelProvider;
|
|
63
|
+
/**
|
|
64
|
+
* Resolve a client-supplied effort id against a model's supported set: returns
|
|
65
|
+
* the id only if the model actually offers it, else undefined (so an invalid or
|
|
66
|
+
* stale effort never reaches a backend). Falls back to the model's `defaultEffort`
|
|
67
|
+
* when `effortId` is absent.
|
|
68
|
+
*/
|
|
69
|
+
export declare function resolveEffort(modelId: string | undefined, effortId: string | undefined): string | undefined;
|
package/dist/src/models.js
CHANGED
|
@@ -1,34 +1,66 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Model catalog — the daemon's source of truth for which agent models
|
|
3
|
-
* may pick from.
|
|
2
|
+
* Model catalog — the daemon's source of truth for which agent models (and, for
|
|
3
|
+
* models that support it, which reasoning-effort levels) the app may pick from.
|
|
4
4
|
*
|
|
5
5
|
* A model's `provider` decides which agent backend runs it:
|
|
6
|
-
* - "claude" → ClaudeAgent (Agent SDK, `model`
|
|
7
|
-
* - "codex" → CodexAgent (OpenAI Codex CLI, `-m`
|
|
6
|
+
* - "claude" → ClaudeAgent (Agent SDK, `model` + `effort` options)
|
|
7
|
+
* - "codex" → CodexAgent (OpenAI Codex CLI, `-m` + `-c
|
|
8
|
+
* model_reasoning_effort=<level>`)
|
|
8
9
|
* - "openrouter" → OpenRouterAgent (Agent SDK against OpenRouter's
|
|
9
|
-
* Anthropic-compatible endpoint;
|
|
10
|
-
* `vendor/model` slug
|
|
10
|
+
* Anthropic-compatible endpoint; `id` is an OpenRouter
|
|
11
|
+
* `vendor/model` slug)
|
|
12
|
+
* - "ollama" → OllamaAgent (Agent SDK against a local Ollama's
|
|
13
|
+
* Anthropic-compatible endpoint; `id` is an Ollama model tag.
|
|
14
|
+
* Runs on-device, no key, no billing)
|
|
11
15
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
16
|
+
* DISCOVERY. Online providers are enumerated live from their model APIs and
|
|
17
|
+
* scoped to the last 12 months (see anthropic/openai/openrouter-probe.ts); the
|
|
18
|
+
* effort levels each model supports come from model-efforts.ts. Ollama is
|
|
19
|
+
* discovered from whatever is installed locally (every model, no date filter).
|
|
20
|
+
* The static {@link FALLBACK_MODELS} below is only used for a provider whose
|
|
21
|
+
* live probe returned nothing — no API key, or an unreachable endpoint — so the
|
|
22
|
+
* picker is never empty. `id` is the exact string handed to the backend.
|
|
23
|
+
*
|
|
24
|
+
* The Dart mirror is packages/immediacy_core/lib/models.dart (ModelInfo /
|
|
25
|
+
* ModelEffort shape only).
|
|
15
26
|
*/
|
|
27
|
+
import { ollamaModels, refreshOllamaModels } from "./agent/ollama-probe.js";
|
|
28
|
+
import { anthropicModels, refreshAnthropicModels, } from "./agent/anthropic-probe.js";
|
|
29
|
+
import { openaiModels, refreshOpenAIModels } from "./agent/openai-probe.js";
|
|
30
|
+
import { openrouterModels, refreshOpenRouterModels, } from "./agent/openrouter-probe.js";
|
|
31
|
+
import { effortsForClaude, effortsForCodex, DEFAULT_CLAUDE_EFFORT, DEFAULT_CODEX_EFFORT, } from "./model-efforts.js";
|
|
32
|
+
/** The id backing new workspaces when a client doesn't pick a model. */
|
|
33
|
+
export const DEFAULT_MODEL_ID = "claude-opus-4-8";
|
|
34
|
+
/** Attach the effort set for a static Claude/Codex entry (keeps it in sync). */
|
|
35
|
+
function withClaudeEfforts(m) {
|
|
36
|
+
const efforts = effortsForClaude(m.id);
|
|
37
|
+
return efforts
|
|
38
|
+
? { ...m, efforts, defaultEffort: DEFAULT_CLAUDE_EFFORT(efforts) }
|
|
39
|
+
: m;
|
|
40
|
+
}
|
|
41
|
+
function withCodexEfforts(m) {
|
|
42
|
+
const efforts = effortsForCodex(m.id);
|
|
43
|
+
return efforts
|
|
44
|
+
? { ...m, efforts, defaultEffort: DEFAULT_CODEX_EFFORT(efforts) }
|
|
45
|
+
: m;
|
|
46
|
+
}
|
|
16
47
|
/**
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
48
|
+
* Curated fallback catalog (release-scoped to roughly the last year), used only
|
|
49
|
+
* for a provider whose live probe yielded nothing. Effort metadata is attached
|
|
50
|
+
* from the shared policy so a fallback entry matches its discovered twin.
|
|
20
51
|
*/
|
|
21
|
-
|
|
52
|
+
const FALLBACK_CLAUDE = [
|
|
22
53
|
// Anthropic — Claude (Agent SDK).
|
|
23
54
|
{ id: "claude-opus-4-8", label: "Claude Opus 4.8", provider: "claude", default: true },
|
|
24
55
|
{ id: "claude-fable-5", label: "Claude Fable 5", provider: "claude" },
|
|
25
56
|
{ id: "claude-opus-4-7", label: "Claude Opus 4.7", provider: "claude" },
|
|
26
57
|
{ id: "claude-opus-4-6", label: "Claude Opus 4.6", provider: "claude" },
|
|
27
58
|
{ id: "claude-opus-4-5", label: "Claude Opus 4.5", provider: "claude" },
|
|
28
|
-
{ id: "claude-sonnet-5", label: "Claude Sonnet 5", provider: "claude" },
|
|
29
59
|
{ id: "claude-sonnet-4-6", label: "Claude Sonnet 4.6", provider: "claude" },
|
|
30
60
|
{ id: "claude-sonnet-4-5", label: "Claude Sonnet 4.5", provider: "claude" },
|
|
31
61
|
{ id: "claude-haiku-4-5", label: "Claude Haiku 4.5", provider: "claude" },
|
|
62
|
+
].map((m) => withClaudeEfforts(m));
|
|
63
|
+
const FALLBACK_CODEX = [
|
|
32
64
|
// OpenAI — Codex CLI. "codex" is a sentinel meaning "let Codex pick the
|
|
33
65
|
// account's default model" — the only option that works on a ChatGPT login
|
|
34
66
|
// (explicit ids require API-key billing). See CODEX_DEFAULT_MODEL.
|
|
@@ -38,28 +70,78 @@ export const MODELS = [
|
|
|
38
70
|
{ id: "gpt-5-mini", label: "GPT-5 mini", provider: "codex" },
|
|
39
71
|
{ id: "o4-mini", label: "OpenAI o4-mini", provider: "codex" },
|
|
40
72
|
{ id: "o3", label: "OpenAI o3", provider: "codex" },
|
|
73
|
+
].map((m) => withCodexEfforts(m));
|
|
74
|
+
const FALLBACK_OPENROUTER = [
|
|
41
75
|
// OpenRouter — routed through the Agent SDK against OpenRouter's
|
|
42
76
|
// Anthropic-compatible endpoint (needs OPENROUTER_API_KEY). `id` is the exact
|
|
43
|
-
// OpenRouter `vendor/model` slug;
|
|
44
|
-
//
|
|
45
|
-
// any slug from https://openrouter.ai/models here.
|
|
77
|
+
// OpenRouter `vendor/model` slug; a curated starter set the native
|
|
78
|
+
// Claude/Codex backends don't already cover.
|
|
46
79
|
{ id: "google/gemini-3.7-flash", label: "Gemini 3.7 Flash", provider: "openrouter" },
|
|
47
80
|
{ id: "deepseek/deepseek-v4-pro-0813", label: "DeepSeek V4 Pro", provider: "openrouter" },
|
|
48
81
|
{ id: "x-ai/grok-4.6", label: "Grok 4.6", provider: "openrouter" },
|
|
49
82
|
{ id: "qwen/qwen3.8-max", label: "Qwen3.8 Max", provider: "openrouter" },
|
|
50
83
|
];
|
|
51
|
-
export const
|
|
84
|
+
export const FALLBACK_MODELS = [
|
|
85
|
+
...FALLBACK_CLAUDE,
|
|
86
|
+
...FALLBACK_CODEX,
|
|
87
|
+
...FALLBACK_OPENROUTER,
|
|
88
|
+
];
|
|
52
89
|
/**
|
|
53
90
|
* Sentinel Codex model id meaning "don't pass -m; use the account's default".
|
|
54
91
|
* Passing an explicit model id requires API-key billing; a ChatGPT-login Codex
|
|
55
92
|
* only accepts its plan default, so this is the safe cross-setup choice.
|
|
56
93
|
*/
|
|
57
94
|
export const CODEX_DEFAULT_MODEL = "codex";
|
|
58
|
-
/**
|
|
95
|
+
/** Fallback entries for one provider (used when its live probe is empty). */
|
|
96
|
+
function fallbackFor(provider) {
|
|
97
|
+
return FALLBACK_MODELS.filter((m) => m.provider === provider);
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* The full catalog surfaced to clients: live-discovered online models (Claude /
|
|
101
|
+
* Codex / OpenRouter, scoped to the last 12 months) plus every locally-installed
|
|
102
|
+
* Ollama model. A provider with no live results falls back to its curated static
|
|
103
|
+
* entries so the picker is never empty. Recomputed on each read so a fresh probe
|
|
104
|
+
* shows up without restarting the daemon.
|
|
105
|
+
*/
|
|
106
|
+
export function allModels() {
|
|
107
|
+
const claude = anthropicModels();
|
|
108
|
+
const codex = openaiModels();
|
|
109
|
+
const openrouter = openrouterModels();
|
|
110
|
+
return [
|
|
111
|
+
...(claude.length ? claude : fallbackFor("claude")),
|
|
112
|
+
...(codex.length ? codex : fallbackFor("codex")),
|
|
113
|
+
...(openrouter.length ? openrouter : fallbackFor("openrouter")),
|
|
114
|
+
...ollamaModels(),
|
|
115
|
+
];
|
|
116
|
+
}
|
|
117
|
+
/** The model that backs new workspaces when a client doesn't pick one. */
|
|
118
|
+
export function defaultModel() {
|
|
119
|
+
const models = allModels();
|
|
120
|
+
return (models.find((m) => m.id === DEFAULT_MODEL_ID) ??
|
|
121
|
+
models.find((m) => m.default) ??
|
|
122
|
+
models[0] ??
|
|
123
|
+
FALLBACK_MODELS[0]);
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Refresh every provider's catalog from its live API, using the resolved key
|
|
127
|
+
* for each (Anthropic/OpenAI from CredentialsStore; OpenRouter listing is
|
|
128
|
+
* keyless; Ollama is local). Runs the four probes concurrently; each is
|
|
129
|
+
* independently best-effort and never throws.
|
|
130
|
+
*/
|
|
131
|
+
export async function refreshAllModels(credentials, force = false) {
|
|
132
|
+
await Promise.allSettled([
|
|
133
|
+
refreshAnthropicModels(credentials?.getKey("anthropic"), force),
|
|
134
|
+
refreshOpenAIModels(credentials?.getKey("openai"), force),
|
|
135
|
+
refreshOpenRouterModels(credentials?.getKey("openrouter"), force),
|
|
136
|
+
refreshOllamaModels(force),
|
|
137
|
+
]);
|
|
138
|
+
}
|
|
139
|
+
/** Look up a model by id (undefined id → the default). Includes discovered
|
|
140
|
+
* online + Ollama models so a workspace resolves to the right backend. */
|
|
59
141
|
export function modelById(id) {
|
|
60
142
|
if (!id)
|
|
61
|
-
return
|
|
62
|
-
return
|
|
143
|
+
return defaultModel();
|
|
144
|
+
return allModels().find((m) => m.id === id);
|
|
63
145
|
}
|
|
64
146
|
/**
|
|
65
147
|
* Which backend runs a given model id. Unknown or missing ids fall back to
|
|
@@ -68,4 +150,20 @@ export function modelById(id) {
|
|
|
68
150
|
export function providerFor(id) {
|
|
69
151
|
return modelById(id)?.provider ?? "claude";
|
|
70
152
|
}
|
|
153
|
+
/**
|
|
154
|
+
* Resolve a client-supplied effort id against a model's supported set: returns
|
|
155
|
+
* the id only if the model actually offers it, else undefined (so an invalid or
|
|
156
|
+
* stale effort never reaches a backend). Falls back to the model's `defaultEffort`
|
|
157
|
+
* when `effortId` is absent.
|
|
158
|
+
*/
|
|
159
|
+
export function resolveEffort(modelId, effortId) {
|
|
160
|
+
const model = modelById(modelId);
|
|
161
|
+
if (!model?.efforts?.length)
|
|
162
|
+
return undefined;
|
|
163
|
+
if (effortId && model.efforts.some((e) => e.id === effortId))
|
|
164
|
+
return effortId;
|
|
165
|
+
if (!effortId)
|
|
166
|
+
return model.defaultEffort;
|
|
167
|
+
return undefined;
|
|
168
|
+
}
|
|
71
169
|
//# sourceMappingURL=models.js.map
|
package/dist/src/models.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"models.js","sourceRoot":"","sources":["../../src/models.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"models.js","sourceRoot":"","sources":["../../src/models.ts"],"names":[],"mappings":"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"}
|
package/dist/src/projects.d.ts
CHANGED
|
@@ -72,6 +72,13 @@ export declare class ProjectStore {
|
|
|
72
72
|
ensureForSource(src: ProjectSource): Promise<ProjectRecord>;
|
|
73
73
|
/** Remove a project. The caller guards that no worktrees still reference it. */
|
|
74
74
|
remove(id: string): Promise<void>;
|
|
75
|
+
/**
|
|
76
|
+
* Rename a project — display name only. The on-disk managed dir (`slugFor`) is
|
|
77
|
+
* derived from the name at create time and never recomputed, so it is left as
|
|
78
|
+
* is (matching existing behavior). No-op on an unknown id, a blank name, or an
|
|
79
|
+
* unchanged name; persists only when the name actually changes.
|
|
80
|
+
*/
|
|
81
|
+
rename(id: string, name: string): Promise<void>;
|
|
75
82
|
/**
|
|
76
83
|
* Rewrite the stored project order. `list()` returns projects in Map insertion
|
|
77
84
|
* order, so we rebuild the Map in the requested order. Unknown ids are ignored;
|