thincoder 0.12.61 → 0.12.63
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/CHANGELOG.md +34 -1
- package/README.md +13 -12
- package/bin/thincoder.mjs +63 -28
- package/package.json +6 -5
- package/src/acp/bridge.mjs +35 -15
- package/src/acp/client-caps.mjs +86 -0
- package/src/acp/ext.mjs +86 -0
- package/src/acp/handlers-session.mjs +240 -0
- package/src/acp/handlers-slots.mjs +196 -0
- package/src/acp/login.mjs +48 -0
- package/src/acp/session.mjs +6 -4
- package/src/acp.mjs +67 -371
- package/src/cli/distill-command.mjs +3 -3
- package/src/cli/make-agent.mjs +59 -17
- package/src/cli/memory-command.mjs +3 -3
- package/src/cli/permission.mjs +4 -48
- package/src/cli/setup-wizard.mjs +1 -1
- package/src/completions.mjs +3 -1
- package/src/crash-reports.mjs +32 -10
- package/src/distill.mjs +4 -4
- package/src/heap-watch.mjs +88 -0
- package/src/prompt-injections.mjs +20 -0
- package/src/tui/agent-turn.mjs +40 -9
- package/src/tui/cmd-advisor.mjs +5 -5
- package/src/tui/cmd-clear.mjs +2 -0
- package/src/tui/cmd-config.mjs +8 -8
- package/src/tui/cmd-eng.mjs +25 -9
- package/src/tui/cmd-mcp.mjs +9 -8
- package/src/tui/cmd-model.mjs +1 -1
- package/src/tui/cmd-new.mjs +10 -5
- package/src/tui/cmd-reindex.mjs +1 -1
- package/src/tui/cmd-restore.mjs +2 -2
- package/src/tui/cmd-session.mjs +31 -4
- package/src/tui/cmd-skills.mjs +1 -1
- package/src/tui/cmd-think.mjs +22 -9
- package/src/tui/config-helpers.mjs +1 -1
- package/src/tui/display-budget.mjs +206 -0
- package/src/tui/index.mjs +40 -12
- package/src/tui/interaction.mjs +16 -7
- package/src/tui/key-handler-search.mjs +9 -1
- package/src/tui/key-modes.mjs +9 -4
- package/src/tui/ledger-surface.mjs +85 -0
- package/src/tui/model-catalog.mjs +4 -4
- package/src/tui/model-picker.mjs +8 -7
- package/src/tui/mouse.mjs +11 -6
- package/src/tui/pickers.mjs +15 -2
- package/src/tui/render-conversation.mjs +1 -1
- package/src/tui/render-frame.mjs +17 -6
- package/src/tui/render-loop.mjs +1 -1
- package/src/tui/render-segments.mjs +3 -1
- package/src/tui/slash-commands.mjs +1 -1
- package/src/tui/startup.mjs +49 -17
- package/src/tui/subagent-blocks.mjs +21 -3
- package/src/tui/subagent-children.mjs +86 -14
- package/src/tui/subagent-freeze.mjs +80 -3
- package/src/tui/suspension-drive.mjs +48 -22
- package/src/tui/tool-args.mjs +5 -2
- package/src/tui/tool-display.mjs +16 -2
- package/src/tui/tool-events.mjs +64 -22
- package/src/tui/tui-lifecycle.mjs +9 -2
- package/src/tui/wizard.mjs +3 -3
- package/src/tui/wrapped-spawn.mjs +21 -5
- package/src/abort-provenance.mjs +0 -116
- package/src/advisor/citations.mjs +0 -139
- package/src/advisor/compaction.mjs +0 -174
- package/src/advisor/convergence.mjs +0 -80
- package/src/advisor/history.mjs +0 -77
- package/src/advisor/loop.mjs +0 -293
- package/src/advisor/messages.mjs +0 -299
- package/src/advisor/project-context.mjs +0 -194
- package/src/advisor/repos.mjs +0 -150
- package/src/advisor/run.mjs +0 -293
- package/src/advisor/truncate.mjs +0 -57
- package/src/advisor.mjs +0 -290
- package/src/agent/completion.mjs +0 -146
- package/src/agent/dispatch.mjs +0 -489
- package/src/agent/helpers.mjs +0 -384
- package/src/agent/post-turn.mjs +0 -70
- package/src/agent/record-results.mjs +0 -174
- package/src/agent/relay-prefix.mjs +0 -39
- package/src/agent/run-stages.mjs +0 -242
- package/src/agent/setup-reminders.mjs +0 -69
- package/src/agent/setup.mjs +0 -354
- package/src/agent/spawn-child.mjs +0 -228
- package/src/agent-tools/advisor-async.mjs +0 -346
- package/src/agent-tools/advisor-settle.mjs +0 -231
- package/src/agent-tools/advisor.mjs +0 -260
- package/src/agent-tools/async-settle.mjs +0 -191
- package/src/agent-tools/batch-segment.mjs +0 -195
- package/src/agent-tools/consult.mjs +0 -468
- package/src/agent-tools/design-token.mjs +0 -117
- package/src/agent-tools/digest-budget.mjs +0 -76
- package/src/agent-tools/eng.mjs +0 -67
- package/src/agent-tools/escalate-async.mjs +0 -289
- package/src/agent-tools/goal.mjs +0 -119
- package/src/agent-tools/plan.mjs +0 -81
- package/src/agent-tools/read-history.mjs +0 -294
- package/src/agent-tools/recent-changes.mjs +0 -24
- package/src/agent-tools/review-streak.mjs +0 -93
- package/src/agent-tools/settings.mjs +0 -265
- package/src/agent-tools/skill.mjs +0 -47
- package/src/agent-tools/subagent-actions.mjs +0 -479
- package/src/agent-tools/subagent-async.mjs +0 -434
- package/src/agent-tools/subagent-panel.mjs +0 -160
- package/src/agent-tools/subagent-run.mjs +0 -205
- package/src/agent-tools/subagent-scheduler.mjs +0 -392
- package/src/agent-tools/subagent-spawn.mjs +0 -453
- package/src/agent-tools/subagent.mjs +0 -404
- package/src/agent-tools/task.mjs +0 -87
- package/src/agent-tools/timer.mjs +0 -46
- package/src/agent-tools/verify.mjs +0 -271
- package/src/agent-tools.mjs +0 -17
- package/src/agent.mjs +0 -413
- package/src/auto-think.mjs +0 -115
- package/src/config-migrate.mjs +0 -70
- package/src/config.mjs +0 -496
- package/src/context.mjs +0 -381
- package/src/conventions.mjs +0 -223
- package/src/embedding.mjs +0 -120
- package/src/escape.mjs +0 -152
- package/src/expand-home.mjs +0 -16
- package/src/explore-distill.mjs +0 -155
- package/src/generate-title.mjs +0 -83
- package/src/git/checkpoint.mjs +0 -448
- package/src/git/gitmem.mjs +0 -100
- package/src/hooks.mjs +0 -97
- package/src/log.mjs +0 -195
- package/src/markdown.mjs +0 -106
- package/src/mcp/helpers.mjs +0 -51
- package/src/mcp/transport-http.mjs +0 -248
- package/src/mcp/transport-stdio.mjs +0 -140
- package/src/mcp/transport-ws.mjs +0 -122
- package/src/mcp.mjs +0 -295
- package/src/memory/code-index.mjs +0 -219
- package/src/memory/code-sync.mjs +0 -413
- package/src/memory/core.mjs +0 -300
- package/src/memory/delete.mjs +0 -236
- package/src/memory/docs.mjs +0 -417
- package/src/memory/file-walk.mjs +0 -109
- package/src/memory/schema.mjs +0 -452
- package/src/memory.mjs +0 -21
- package/src/model-ref.mjs +0 -66
- package/src/model-specs.mjs +0 -179
- package/src/peer-domains.mjs +0 -265
- package/src/peer-instances.mjs +0 -231
- package/src/prompt-overlays.mjs +0 -82
- package/src/prompts/advisor-design.md +0 -41
- package/src/prompts/advisor-round1.md +0 -41
- package/src/prompts/advisor-round2.md +0 -46
- package/src/prompts/advisor-round3.md +0 -42
- package/src/prompts/common.md +0 -115
- package/src/prompts/consult-base.md +0 -19
- package/src/prompts/discipline-engineering.md +0 -217
- package/src/prompts/discipline-normal.md +0 -179
- package/src/prompts/persona-coder.md +0 -21
- package/src/prompts/persona-eng-coder.md +0 -37
- package/src/prompts/persona-eng-designer.md +0 -55
- package/src/prompts/persona-engineering.md +0 -54
- package/src/prompts/persona-explore.md +0 -15
- package/src/prompts/persona-normal.md +0 -27
- package/src/prompts/persona-plan.md +0 -26
- package/src/provider/anthropic.mjs +0 -225
- package/src/provider/core.mjs +0 -476
- package/src/provider/errors.mjs +0 -101
- package/src/provider/google.mjs +0 -257
- package/src/provider/index.mjs +0 -7
- package/src/provider/list-models.mjs +0 -93
- package/src/provider/normalize.mjs +0 -81
- package/src/provider/rate.mjs +0 -108
- package/src/provider/responses.mjs +0 -495
- package/src/provider/retry.mjs +0 -88
- package/src/provider/sse.mjs +0 -264
- package/src/proxy.mjs +0 -261
- package/src/rules.mjs +0 -53
- package/src/session-gc.mjs +0 -214
- package/src/session-guard.mjs +0 -47
- package/src/session-migrate.mjs +0 -48
- package/src/session-rename.mjs +0 -38
- package/src/session-slots.mjs +0 -489
- package/src/session.mjs +0 -475
- package/src/skills.mjs +0 -153
- package/src/token-ttl.mjs +0 -274
- package/src/tools/apply_patch.md +0 -15
- package/src/tools/bash.md +0 -37
- package/src/tools/bash.mjs +0 -268
- package/src/tools/checklist-sync.mjs +0 -181
- package/src/tools/checklist.md +0 -13
- package/src/tools/checklist.mjs +0 -299
- package/src/tools/delete.md +0 -13
- package/src/tools/edit-batch.mjs +0 -191
- package/src/tools/edit-diff.mjs +0 -348
- package/src/tools/edit.md +0 -30
- package/src/tools/execute.md +0 -21
- package/src/tools/execute.mjs +0 -228
- package/src/tools/fetch.md +0 -12
- package/src/tools/file.mjs +0 -469
- package/src/tools/file_ops.md +0 -17
- package/src/tools/get_current_time.md +0 -8
- package/src/tools/git-checkpoint.mjs +0 -143
- package/src/tools/git-ext.mjs +0 -173
- package/src/tools/git.md +0 -54
- package/src/tools/git.mjs +0 -356
- package/src/tools/glob-dialect.mjs +0 -130
- package/src/tools/glob.md +0 -11
- package/src/tools/grep.md +0 -19
- package/src/tools/hashline_edit.md +0 -14
- package/src/tools/index.mjs +0 -36
- package/src/tools/insert_after.md +0 -15
- package/src/tools/lint.md +0 -10
- package/src/tools/linter.mjs +0 -128
- package/src/tools/ls.md +0 -12
- package/src/tools/lsp.md +0 -10
- package/src/tools/lsp.mjs +0 -316
- package/src/tools/ops.mjs +0 -299
- package/src/tools/patch.mjs +0 -282
- package/src/tools/process.md +0 -10
- package/src/tools/question.md +0 -16
- package/src/tools/question.mjs +0 -26
- package/src/tools/read.md +0 -20
- package/src/tools/read_image.md +0 -8
- package/src/tools/repomap.mjs +0 -314
- package/src/tools/search.mjs +0 -236
- package/src/tools/shared.mjs +0 -446
- package/src/tools/tree.md +0 -14
- package/src/tools/tree.mjs +0 -66
- package/src/tools/wait_for.md +0 -22
- package/src/tools/web.mjs +0 -224
- package/src/tools/websearch.md +0 -16
- package/src/tools/write.md +0 -11
- package/src/traces/trace-store.mjs +0 -224
package/src/memory/schema.mjs
DELETED
|
@@ -1,452 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* memory/schema.mjs — database schema definition, migration, CJK segmentation
|
|
3
|
-
* v1: node:sqlite + FTS5 standalone implementation, zero dependencies.
|
|
4
|
-
*
|
|
5
|
-
* Chinese search strategy: FTS5 unicode61 tokenizer + CJK character-by-character spacing (applied to both write and query sides).
|
|
6
|
-
* Effect: Chinese indexed by character; two-character words like "分号" still match; ASCII stays whole-word.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { DatabaseSync } from "node:sqlite"
|
|
10
|
-
import { mkdirSync } from "node:fs"
|
|
11
|
-
import { dirname } from "node:path"
|
|
12
|
-
|
|
13
|
-
export const VALID_TYPES = new Set(["rule", "knowledge", "decision", "pattern"])
|
|
14
|
-
export const SCHEMA_VERSION = 9
|
|
15
|
-
export const SQLITE_BUSY_TIMEOUT = 3000
|
|
16
|
-
|
|
17
|
-
// Code index: source file extensions. Curated DEFAULTS — a project can declare
|
|
18
|
-
// more (union) through .thincoder/conventions.json → index.codeExtensions
|
|
19
|
-
// (PORTABILITY PO-9: an unlisted extension used to be invisible AND undeclarable).
|
|
20
|
-
export const CODE_EXTS = new Set([
|
|
21
|
-
".mjs", ".js", ".cjs", ".mts", ".cts", ".ts", ".tsx", ".jsx",
|
|
22
|
-
".py", ".rs", ".go", ".java", ".c", ".h", ".cpp", ".hpp",
|
|
23
|
-
".rb", ".swift", ".kt", ".dart", ".lua", ".cs", ".fs", ".fsx",
|
|
24
|
-
".clj", ".cljs", ".ex", ".exs", ".erl", ".hrl", ".scala", ".groovy",
|
|
25
|
-
".pl", ".pm", ".r", ".jl", ".zig", ".ps1",
|
|
26
|
-
".sh", ".bash", ".sql", ".yaml", ".yml", ".toml", ".json",
|
|
27
|
-
".proto", ".graphql", ".tf", ".hcl",
|
|
28
|
-
".css", ".html", ".vue", ".svelte",
|
|
29
|
-
])
|
|
30
|
-
// Doc index: markdown / plain text (separate index makes it easier for LLM to distinguish "design specs" from "existing code")
|
|
31
|
-
// Same declaration rule as CODE_EXTS (index.docExtensions).
|
|
32
|
-
export const DOC_EXTS = new Set([".md", ".mdc", ".mdx", ".txt", ".rst", ".adoc", ".org", ".wiki", ".tex"])
|
|
33
|
-
// Directory names always skipped during code/doc indexing
|
|
34
|
-
// NOTE: these are case-sensitive basename matches; add common platform-specific dirs
|
|
35
|
-
export const SKIP_DIRS = new Set([
|
|
36
|
-
"node_modules", ".git", "dist", "build", ".turbo", "coverage",
|
|
37
|
-
"__pycache__", ".venv", "venv", "target", ".next", ".nuxt", ".svelte-kit",
|
|
38
|
-
// Windows user profile directories (never contain project code)
|
|
39
|
-
"AppData", "Application Data", "Desktop", "Documents", "Downloads",
|
|
40
|
-
"Music", "Pictures", "Videos", "OneDrive", "Contacts", "Favorites",
|
|
41
|
-
"Links", "Saved Games", "Searches",
|
|
42
|
-
// Other common non-code directories
|
|
43
|
-
"Program Files", "Program Files (x86)", "Windows", "$Recycle.Bin",
|
|
44
|
-
])
|
|
45
|
-
// Files larger than these limits are skipped during bulk indexing
|
|
46
|
-
// (minified bundles, test fixtures, generated code, etc.)
|
|
47
|
-
export const MAX_CODE_FILE_BYTES = 1024 * 1024 // 1 MB
|
|
48
|
-
export const MAX_DOC_FILE_BYTES = 512 * 1024 // 512 KB
|
|
49
|
-
export const BIG_FILE_LINES = 2000
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* CJK character-by-character spacing: makes unicode61 treat each Han/Kana/Hangul character as an independent token.
|
|
53
|
-
* Both write and query must use the same processing for retrieval to match.
|
|
54
|
-
*/
|
|
55
|
-
export function segmentCJK(text) {
|
|
56
|
-
return text.replace(
|
|
57
|
-
/[-ヿ㐀-䶿一-鿿豈-가-]+/g,
|
|
58
|
-
(run) => [...run].join(" "),
|
|
59
|
-
)
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Open/initialize the memory store. dbPath is auto-created if missing.
|
|
64
|
-
* The returned memory object is the interface; all subsequent functions take it as their first argument.
|
|
65
|
-
*/
|
|
66
|
-
export function createMemory({ dbPath }) {
|
|
67
|
-
mkdirSync(dirname(dbPath), { recursive: true })
|
|
68
|
-
const db = new DatabaseSync(dbPath)
|
|
69
|
-
// WAL: reads and writes don't block each other (TUI search and background indexing can run concurrently); busy_timeout prevents SQLITE_BUSY from multi-process same-db access
|
|
70
|
-
db.exec(`PRAGMA journal_mode = WAL`)
|
|
71
|
-
db.exec(`PRAGMA busy_timeout = ${SQLITE_BUSY_TIMEOUT}`)
|
|
72
|
-
|
|
73
|
-
db.exec(`
|
|
74
|
-
CREATE TABLE IF NOT EXISTS entries (
|
|
75
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
76
|
-
type TEXT NOT NULL CHECK(type IN ('rule','knowledge','decision','pattern')),
|
|
77
|
-
title TEXT NOT NULL,
|
|
78
|
-
content TEXT NOT NULL,
|
|
79
|
-
tags TEXT NOT NULL DEFAULT '',
|
|
80
|
-
seg_title TEXT NOT NULL DEFAULT '',
|
|
81
|
-
seg_content TEXT NOT NULL DEFAULT '',
|
|
82
|
-
seg_tags TEXT NOT NULL DEFAULT '',
|
|
83
|
-
created_at INTEGER NOT NULL,
|
|
84
|
-
updated_at INTEGER NOT NULL
|
|
85
|
-
)
|
|
86
|
-
`)
|
|
87
|
-
|
|
88
|
-
migrate(db)
|
|
89
|
-
return { db }
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/** Step-by-step migration by user_version. Single transaction — any step failure rolls back, no half-finished schema left behind. */
|
|
93
|
-
export function migrate(db) {
|
|
94
|
-
const { user_version: version } = db.prepare(`PRAGMA user_version`).get()
|
|
95
|
-
if (version >= SCHEMA_VERSION) return
|
|
96
|
-
|
|
97
|
-
db.exec("BEGIN IMMEDIATE")
|
|
98
|
-
try {
|
|
99
|
-
if (version < 2) {
|
|
100
|
-
// v1 (trigram) or empty DB → v2 (unicode61 + CJK char-by-char): rebuild FTS and triggers
|
|
101
|
-
db.exec(`
|
|
102
|
-
DROP TRIGGER IF EXISTS entries_ai;
|
|
103
|
-
DROP TRIGGER IF EXISTS entries_ad;
|
|
104
|
-
DROP TRIGGER IF EXISTS entries_au;
|
|
105
|
-
DROP TABLE IF EXISTS entries_fts;
|
|
106
|
-
`)
|
|
107
|
-
// Old DB (v1) has no seg columns — add them
|
|
108
|
-
const columns = db.prepare(`PRAGMA table_info(entries)`).all().map((c) => c.name)
|
|
109
|
-
for (const col of ["seg_title", "seg_content", "seg_tags"]) {
|
|
110
|
-
if (!columns.includes(col)) {
|
|
111
|
-
db.exec(`ALTER TABLE entries ADD COLUMN ${col} TEXT NOT NULL DEFAULT ''`)
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
// Backfill seg columns (segmentation done in JS; SQL can't do it)
|
|
115
|
-
const rows = db.prepare(`SELECT id, title, content, tags FROM entries`).all()
|
|
116
|
-
const update = db.prepare(`UPDATE entries SET seg_title = ?, seg_content = ?, seg_tags = ? WHERE id = ?`)
|
|
117
|
-
for (const r of rows) {
|
|
118
|
-
update.run(segmentCJK(r.title), segmentCJK(r.content), segmentCJK(r.tags), r.id)
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
db.exec(`
|
|
122
|
-
CREATE VIRTUAL TABLE entries_fts USING fts5(
|
|
123
|
-
seg_title, seg_content, seg_tags,
|
|
124
|
-
content='entries', content_rowid='id',
|
|
125
|
-
tokenize='unicode61'
|
|
126
|
-
)
|
|
127
|
-
`)
|
|
128
|
-
db.exec(`
|
|
129
|
-
CREATE TRIGGER entries_ai AFTER INSERT ON entries BEGIN
|
|
130
|
-
INSERT INTO entries_fts(rowid, seg_title, seg_content, seg_tags)
|
|
131
|
-
VALUES (new.id, new.seg_title, new.seg_content, new.seg_tags);
|
|
132
|
-
END;
|
|
133
|
-
CREATE TRIGGER entries_ad AFTER DELETE ON entries BEGIN
|
|
134
|
-
INSERT INTO entries_fts(entries_fts, rowid, seg_title, seg_content, seg_tags)
|
|
135
|
-
VALUES ('delete', old.id, old.seg_title, old.seg_content, old.seg_tags);
|
|
136
|
-
END;
|
|
137
|
-
CREATE TRIGGER entries_au AFTER UPDATE ON entries BEGIN
|
|
138
|
-
INSERT INTO entries_fts(entries_fts, rowid, seg_title, seg_content, seg_tags)
|
|
139
|
-
VALUES ('delete', old.id, old.seg_title, old.seg_content, old.seg_tags);
|
|
140
|
-
INSERT INTO entries_fts(rowid, seg_title, seg_content, seg_tags)
|
|
141
|
-
VALUES (new.id, new.seg_title, new.seg_content, new.seg_tags);
|
|
142
|
-
END;
|
|
143
|
-
`)
|
|
144
|
-
db.exec(`INSERT INTO entries_fts(entries_fts) VALUES('rebuild')`)
|
|
145
|
-
db.exec(`PRAGMA user_version = 2`)
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
if (version < 3) {
|
|
149
|
-
// v3: markdown layer (project/team) files table + FTS + triggers
|
|
150
|
-
db.exec(`
|
|
151
|
-
CREATE TABLE IF NOT EXISTS files (
|
|
152
|
-
layer TEXT NOT NULL CHECK(layer IN ('project','team')),
|
|
153
|
-
path TEXT NOT NULL,
|
|
154
|
-
type TEXT NOT NULL CHECK(type IN ('rule','knowledge','decision','pattern')),
|
|
155
|
-
title TEXT NOT NULL,
|
|
156
|
-
content TEXT NOT NULL,
|
|
157
|
-
tags TEXT NOT NULL DEFAULT '',
|
|
158
|
-
author TEXT NOT NULL DEFAULT '',
|
|
159
|
-
embedding BLOB,
|
|
160
|
-
mtime_ms INTEGER NOT NULL DEFAULT 0,
|
|
161
|
-
seg_title TEXT NOT NULL DEFAULT '',
|
|
162
|
-
seg_content TEXT NOT NULL DEFAULT '',
|
|
163
|
-
seg_tags TEXT NOT NULL DEFAULT '',
|
|
164
|
-
updated_at INTEGER NOT NULL,
|
|
165
|
-
PRIMARY KEY (layer, path)
|
|
166
|
-
)
|
|
167
|
-
`)
|
|
168
|
-
db.exec(`
|
|
169
|
-
CREATE VIRTUAL TABLE IF NOT EXISTS files_fts USING fts5(
|
|
170
|
-
seg_title, seg_content, seg_tags,
|
|
171
|
-
content='files', content_rowid='rowid',
|
|
172
|
-
tokenize='unicode61'
|
|
173
|
-
)
|
|
174
|
-
`)
|
|
175
|
-
db.exec(`
|
|
176
|
-
CREATE TRIGGER files_ai AFTER INSERT ON files BEGIN
|
|
177
|
-
INSERT INTO files_fts(rowid, seg_title, seg_content, seg_tags)
|
|
178
|
-
VALUES (new.rowid, new.seg_title, new.seg_content, new.seg_tags);
|
|
179
|
-
END;
|
|
180
|
-
CREATE TRIGGER files_ad AFTER DELETE ON files BEGIN
|
|
181
|
-
INSERT INTO files_fts(files_fts, rowid, seg_title, seg_content, seg_tags)
|
|
182
|
-
VALUES ('delete', old.rowid, old.seg_title, old.seg_content, old.seg_tags);
|
|
183
|
-
END;
|
|
184
|
-
CREATE TRIGGER files_au AFTER UPDATE ON files BEGIN
|
|
185
|
-
INSERT INTO files_fts(files_fts, rowid, seg_title, seg_content, seg_tags)
|
|
186
|
-
VALUES ('delete', old.rowid, old.seg_title, old.seg_content, old.seg_tags);
|
|
187
|
-
INSERT INTO files_fts(rowid, seg_title, seg_content, seg_tags)
|
|
188
|
-
VALUES (new.rowid, new.seg_title, new.seg_content, new.seg_tags);
|
|
189
|
-
END;
|
|
190
|
-
`)
|
|
191
|
-
db.exec(`PRAGMA user_version = 3`)
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
if (version < 4) {
|
|
195
|
-
// v4: add vector column to personal entries table (files table already had it since v3); meta table stores embedding model name
|
|
196
|
-
const columns = db.prepare(`PRAGMA table_info(entries)`).all().map((c) => c.name)
|
|
197
|
-
if (!columns.includes("embedding")) {
|
|
198
|
-
db.exec(`ALTER TABLE entries ADD COLUMN embedding BLOB`)
|
|
199
|
-
}
|
|
200
|
-
db.exec(`CREATE TABLE IF NOT EXISTS meta (key TEXT PRIMARY KEY, value TEXT)`)
|
|
201
|
-
db.exec(`PRAGMA user_version = 4`)
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
if (version < 5) {
|
|
205
|
-
// v5: add origin column to files table (absolute project path), prevent cross-project memory collision
|
|
206
|
-
const columns = db.prepare(`PRAGMA table_info(files)`).all().map((c) => c.name)
|
|
207
|
-
if (!columns.includes("origin")) {
|
|
208
|
-
db.exec(`ALTER TABLE files ADD COLUMN origin TEXT NOT NULL DEFAULT ''`)
|
|
209
|
-
}
|
|
210
|
-
db.exec(`PRAGMA user_version = 5`)
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
if (version < 6) {
|
|
214
|
-
// v6: code index — code_chunks table + FTS5 (same pattern as files table)
|
|
215
|
-
db.exec(`
|
|
216
|
-
CREATE TABLE IF NOT EXISTS code_chunks (
|
|
217
|
-
path TEXT NOT NULL,
|
|
218
|
-
language TEXT NOT NULL,
|
|
219
|
-
chunk_type TEXT NOT NULL CHECK(chunk_type IN ('file','symbol')),
|
|
220
|
-
symbol_name TEXT NOT NULL DEFAULT '',
|
|
221
|
-
content TEXT NOT NULL,
|
|
222
|
-
line_start INTEGER NOT NULL DEFAULT 0,
|
|
223
|
-
line_end INTEGER NOT NULL DEFAULT 0,
|
|
224
|
-
mtime_ms INTEGER NOT NULL DEFAULT 0,
|
|
225
|
-
embedding BLOB,
|
|
226
|
-
seg_content TEXT NOT NULL DEFAULT '',
|
|
227
|
-
PRIMARY KEY (path, line_start)
|
|
228
|
-
)
|
|
229
|
-
`)
|
|
230
|
-
db.exec(`
|
|
231
|
-
CREATE VIRTUAL TABLE IF NOT EXISTS code_chunks_fts USING fts5(
|
|
232
|
-
path, symbol_name, seg_content,
|
|
233
|
-
content='code_chunks', content_rowid='rowid',
|
|
234
|
-
tokenize='unicode61'
|
|
235
|
-
)
|
|
236
|
-
`)
|
|
237
|
-
db.exec(`
|
|
238
|
-
CREATE TRIGGER code_chunks_ai AFTER INSERT ON code_chunks BEGIN
|
|
239
|
-
INSERT INTO code_chunks_fts(rowid, path, symbol_name, seg_content)
|
|
240
|
-
VALUES (new.rowid, new.path, new.symbol_name, new.seg_content);
|
|
241
|
-
END;
|
|
242
|
-
CREATE TRIGGER code_chunks_ad AFTER DELETE ON code_chunks BEGIN
|
|
243
|
-
INSERT INTO code_chunks_fts(code_chunks_fts, rowid, path, symbol_name, seg_content)
|
|
244
|
-
VALUES ('delete', old.rowid, old.path, old.symbol_name, old.seg_content);
|
|
245
|
-
END;
|
|
246
|
-
CREATE TRIGGER code_chunks_au AFTER UPDATE ON code_chunks BEGIN
|
|
247
|
-
INSERT INTO code_chunks_fts(code_chunks_fts, rowid, path, symbol_name, seg_content)
|
|
248
|
-
VALUES ('delete', old.rowid, old.path, old.symbol_name, old.seg_content);
|
|
249
|
-
INSERT INTO code_chunks_fts(rowid, path, symbol_name, seg_content)
|
|
250
|
-
VALUES (new.rowid, new.path, new.symbol_name, new.seg_content);
|
|
251
|
-
END;
|
|
252
|
-
`)
|
|
253
|
-
db.exec(`PRAGMA user_version = 6`)
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
if (version < 7) {
|
|
257
|
-
// v7: doc index — doc_chunks table + FTS5 (same pattern as code_chunks), markdown chunked by ## headings
|
|
258
|
-
db.exec(`
|
|
259
|
-
CREATE TABLE IF NOT EXISTS doc_chunks (
|
|
260
|
-
path TEXT NOT NULL,
|
|
261
|
-
language TEXT NOT NULL DEFAULT 'markdown',
|
|
262
|
-
heading TEXT NOT NULL DEFAULT '',
|
|
263
|
-
content TEXT NOT NULL,
|
|
264
|
-
line_start INTEGER NOT NULL DEFAULT 0,
|
|
265
|
-
line_end INTEGER NOT NULL DEFAULT 0,
|
|
266
|
-
mtime_ms INTEGER NOT NULL DEFAULT 0,
|
|
267
|
-
embedding BLOB,
|
|
268
|
-
seg_content TEXT NOT NULL DEFAULT '',
|
|
269
|
-
PRIMARY KEY (path, line_start)
|
|
270
|
-
)
|
|
271
|
-
`)
|
|
272
|
-
db.exec(`
|
|
273
|
-
CREATE VIRTUAL TABLE IF NOT EXISTS doc_chunks_fts USING fts5(
|
|
274
|
-
path, heading, seg_content,
|
|
275
|
-
content='doc_chunks', content_rowid='rowid',
|
|
276
|
-
tokenize='unicode61'
|
|
277
|
-
)
|
|
278
|
-
`)
|
|
279
|
-
db.exec(`
|
|
280
|
-
CREATE TRIGGER doc_chunks_ai AFTER INSERT ON doc_chunks BEGIN
|
|
281
|
-
INSERT INTO doc_chunks_fts(rowid, path, heading, seg_content)
|
|
282
|
-
VALUES (new.rowid, new.path, new.heading, new.seg_content);
|
|
283
|
-
END;
|
|
284
|
-
CREATE TRIGGER doc_chunks_ad AFTER DELETE ON doc_chunks BEGIN
|
|
285
|
-
INSERT INTO doc_chunks_fts(doc_chunks_fts, rowid, path, heading, seg_content)
|
|
286
|
-
VALUES ('delete', old.rowid, old.path, old.heading, old.seg_content);
|
|
287
|
-
END;
|
|
288
|
-
CREATE TRIGGER doc_chunks_au AFTER UPDATE ON doc_chunks BEGIN
|
|
289
|
-
INSERT INTO doc_chunks_fts(doc_chunks_fts, rowid, path, heading, seg_content)
|
|
290
|
-
VALUES ('delete', old.rowid, old.path, old.heading, old.seg_content);
|
|
291
|
-
INSERT INTO doc_chunks_fts(rowid, path, heading, seg_content)
|
|
292
|
-
VALUES (new.rowid, new.path, new.heading, new.seg_content);
|
|
293
|
-
END;
|
|
294
|
-
`)
|
|
295
|
-
db.exec(`PRAGMA user_version = 7`)
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
if (version < 8) {
|
|
299
|
-
// v8: add origin column to code_chunks/doc_chunks (absolute project root), PK changed to (origin, path, line_start).
|
|
300
|
-
// SQLite can't ALTER primary key → drop and recreate table (auto-reindexed by next codeSync/docSync).
|
|
301
|
-
db.exec(`
|
|
302
|
-
DROP TRIGGER IF EXISTS code_chunks_ai;
|
|
303
|
-
DROP TRIGGER IF EXISTS code_chunks_ad;
|
|
304
|
-
DROP TRIGGER IF EXISTS code_chunks_au;
|
|
305
|
-
DROP TABLE IF EXISTS code_chunks_fts;
|
|
306
|
-
DROP TABLE IF EXISTS code_chunks;
|
|
307
|
-
DROP TRIGGER IF EXISTS doc_chunks_ai;
|
|
308
|
-
DROP TRIGGER IF EXISTS doc_chunks_ad;
|
|
309
|
-
DROP TRIGGER IF EXISTS doc_chunks_au;
|
|
310
|
-
DROP TABLE IF EXISTS doc_chunks_fts;
|
|
311
|
-
DROP TABLE IF EXISTS doc_chunks;
|
|
312
|
-
`)
|
|
313
|
-
db.exec(`
|
|
314
|
-
CREATE TABLE code_chunks (
|
|
315
|
-
origin TEXT NOT NULL DEFAULT '',
|
|
316
|
-
path TEXT NOT NULL,
|
|
317
|
-
language TEXT NOT NULL,
|
|
318
|
-
chunk_type TEXT NOT NULL CHECK(chunk_type IN ('file','symbol')),
|
|
319
|
-
symbol_name TEXT NOT NULL DEFAULT '',
|
|
320
|
-
content TEXT NOT NULL,
|
|
321
|
-
line_start INTEGER NOT NULL DEFAULT 0,
|
|
322
|
-
line_end INTEGER NOT NULL DEFAULT 0,
|
|
323
|
-
mtime_ms INTEGER NOT NULL DEFAULT 0,
|
|
324
|
-
embedding BLOB,
|
|
325
|
-
seg_content TEXT NOT NULL DEFAULT '',
|
|
326
|
-
PRIMARY KEY (origin, path, line_start)
|
|
327
|
-
)
|
|
328
|
-
`)
|
|
329
|
-
db.exec(`
|
|
330
|
-
CREATE VIRTUAL TABLE code_chunks_fts USING fts5(
|
|
331
|
-
path, symbol_name, seg_content,
|
|
332
|
-
content='code_chunks', content_rowid='rowid',
|
|
333
|
-
tokenize='unicode61'
|
|
334
|
-
)
|
|
335
|
-
`)
|
|
336
|
-
db.exec(`
|
|
337
|
-
CREATE TRIGGER code_chunks_ai AFTER INSERT ON code_chunks BEGIN
|
|
338
|
-
INSERT INTO code_chunks_fts(rowid, path, symbol_name, seg_content)
|
|
339
|
-
VALUES (new.rowid, new.path, new.symbol_name, new.seg_content);
|
|
340
|
-
END;
|
|
341
|
-
CREATE TRIGGER code_chunks_ad AFTER DELETE ON code_chunks BEGIN
|
|
342
|
-
INSERT INTO code_chunks_fts(code_chunks_fts, rowid, path, symbol_name, seg_content)
|
|
343
|
-
VALUES ('delete', old.rowid, old.path, old.symbol_name, old.seg_content);
|
|
344
|
-
END;
|
|
345
|
-
CREATE TRIGGER code_chunks_au AFTER UPDATE ON code_chunks BEGIN
|
|
346
|
-
INSERT INTO code_chunks_fts(code_chunks_fts, rowid, path, symbol_name, seg_content)
|
|
347
|
-
VALUES ('delete', old.rowid, old.path, old.symbol_name, old.seg_content);
|
|
348
|
-
INSERT INTO code_chunks_fts(rowid, path, symbol_name, seg_content)
|
|
349
|
-
VALUES (new.rowid, new.path, new.symbol_name, new.seg_content);
|
|
350
|
-
END;
|
|
351
|
-
`)
|
|
352
|
-
db.exec(`
|
|
353
|
-
CREATE TABLE doc_chunks (
|
|
354
|
-
origin TEXT NOT NULL DEFAULT '',
|
|
355
|
-
path TEXT NOT NULL,
|
|
356
|
-
language TEXT NOT NULL DEFAULT 'markdown',
|
|
357
|
-
heading TEXT NOT NULL DEFAULT '',
|
|
358
|
-
content TEXT NOT NULL,
|
|
359
|
-
line_start INTEGER NOT NULL DEFAULT 0,
|
|
360
|
-
line_end INTEGER NOT NULL DEFAULT 0,
|
|
361
|
-
mtime_ms INTEGER NOT NULL DEFAULT 0,
|
|
362
|
-
embedding BLOB,
|
|
363
|
-
seg_content TEXT NOT NULL DEFAULT '',
|
|
364
|
-
PRIMARY KEY (origin, path, line_start)
|
|
365
|
-
)
|
|
366
|
-
`)
|
|
367
|
-
db.exec(`
|
|
368
|
-
CREATE VIRTUAL TABLE doc_chunks_fts USING fts5(
|
|
369
|
-
path, heading, seg_content,
|
|
370
|
-
content='doc_chunks', content_rowid='rowid',
|
|
371
|
-
tokenize='unicode61'
|
|
372
|
-
)
|
|
373
|
-
`)
|
|
374
|
-
db.exec(`
|
|
375
|
-
CREATE TRIGGER doc_chunks_ai AFTER INSERT ON doc_chunks BEGIN
|
|
376
|
-
INSERT INTO doc_chunks_fts(rowid, path, heading, seg_content)
|
|
377
|
-
VALUES (new.rowid, new.path, new.heading, new.seg_content);
|
|
378
|
-
END;
|
|
379
|
-
CREATE TRIGGER doc_chunks_ad AFTER DELETE ON doc_chunks BEGIN
|
|
380
|
-
INSERT INTO doc_chunks_fts(doc_chunks_fts, rowid, path, heading, seg_content)
|
|
381
|
-
VALUES ('delete', old.rowid, old.path, old.heading, old.seg_content);
|
|
382
|
-
END;
|
|
383
|
-
CREATE TRIGGER doc_chunks_au AFTER UPDATE ON doc_chunks BEGIN
|
|
384
|
-
INSERT INTO doc_chunks_fts(doc_chunks_fts, rowid, path, heading, seg_content)
|
|
385
|
-
VALUES ('delete', old.rowid, old.path, old.heading, old.seg_content);
|
|
386
|
-
INSERT INTO doc_chunks_fts(rowid, path, heading, seg_content)
|
|
387
|
-
VALUES (new.rowid, new.path, new.heading, new.seg_content);
|
|
388
|
-
END;
|
|
389
|
-
`)
|
|
390
|
-
db.exec(`PRAGMA user_version = 8`)
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
if (version < 9) {
|
|
394
|
-
// v9: files table PK gains origin, prevents cross-project project-layer memory overwrite
|
|
395
|
-
// SQLite can't ALTER primary key → drop and recreate table (auto-reindexed by next syncDir)
|
|
396
|
-
db.exec(`
|
|
397
|
-
DROP TRIGGER IF EXISTS files_ai;
|
|
398
|
-
DROP TRIGGER IF EXISTS files_ad;
|
|
399
|
-
DROP TRIGGER IF EXISTS files_au;
|
|
400
|
-
DROP TABLE IF EXISTS files_fts;
|
|
401
|
-
DROP TABLE IF EXISTS files;
|
|
402
|
-
`)
|
|
403
|
-
db.exec(`
|
|
404
|
-
CREATE TABLE files (
|
|
405
|
-
layer TEXT NOT NULL CHECK(layer IN ('project','team')),
|
|
406
|
-
origin TEXT NOT NULL DEFAULT '',
|
|
407
|
-
path TEXT NOT NULL,
|
|
408
|
-
type TEXT NOT NULL CHECK(type IN ('rule','knowledge','decision','pattern')),
|
|
409
|
-
title TEXT NOT NULL,
|
|
410
|
-
content TEXT NOT NULL,
|
|
411
|
-
tags TEXT NOT NULL DEFAULT '',
|
|
412
|
-
author TEXT NOT NULL DEFAULT '',
|
|
413
|
-
embedding BLOB,
|
|
414
|
-
mtime_ms INTEGER NOT NULL DEFAULT 0,
|
|
415
|
-
seg_title TEXT NOT NULL DEFAULT '',
|
|
416
|
-
seg_content TEXT NOT NULL DEFAULT '',
|
|
417
|
-
seg_tags TEXT NOT NULL DEFAULT '',
|
|
418
|
-
updated_at INTEGER NOT NULL,
|
|
419
|
-
PRIMARY KEY (layer, origin, path)
|
|
420
|
-
)
|
|
421
|
-
`)
|
|
422
|
-
db.exec(`
|
|
423
|
-
CREATE VIRTUAL TABLE files_fts USING fts5(
|
|
424
|
-
seg_title, seg_content, seg_tags,
|
|
425
|
-
content='files', content_rowid='rowid',
|
|
426
|
-
tokenize='unicode61'
|
|
427
|
-
)
|
|
428
|
-
`)
|
|
429
|
-
db.exec(`
|
|
430
|
-
CREATE TRIGGER files_ai AFTER INSERT ON files BEGIN
|
|
431
|
-
INSERT INTO files_fts(rowid, seg_title, seg_content, seg_tags)
|
|
432
|
-
VALUES (new.rowid, new.seg_title, new.seg_content, new.seg_tags);
|
|
433
|
-
END;
|
|
434
|
-
CREATE TRIGGER files_ad AFTER DELETE ON files BEGIN
|
|
435
|
-
INSERT INTO files_fts(files_fts, rowid, seg_title, seg_content, seg_tags)
|
|
436
|
-
VALUES ('delete', old.rowid, old.seg_title, old.seg_content, old.seg_tags);
|
|
437
|
-
END;
|
|
438
|
-
CREATE TRIGGER files_au AFTER UPDATE ON files BEGIN
|
|
439
|
-
INSERT INTO files_fts(files_fts, rowid, seg_title, seg_content, seg_tags)
|
|
440
|
-
VALUES ('delete', old.rowid, old.seg_title, old.seg_content, old.seg_tags);
|
|
441
|
-
INSERT INTO files_fts(rowid, seg_title, seg_content, seg_tags)
|
|
442
|
-
VALUES (new.rowid, new.seg_title, new.seg_content, new.seg_tags);
|
|
443
|
-
END;
|
|
444
|
-
`)
|
|
445
|
-
db.exec(`PRAGMA user_version = 9`)
|
|
446
|
-
}
|
|
447
|
-
db.exec("COMMIT")
|
|
448
|
-
} catch (err) {
|
|
449
|
-
db.exec("ROLLBACK")
|
|
450
|
-
throw err
|
|
451
|
-
}
|
|
452
|
-
}
|
package/src/memory.mjs
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* memory.mjs — memory system re-export hub
|
|
3
|
-
* Submodules in src/memory/ directory, split by responsibility.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
// schema + constants
|
|
7
|
-
export { createMemory, migrate, segmentCJK, VALID_TYPES, SCHEMA_VERSION, CODE_EXTS, DOC_EXTS, SKIP_DIRS, BIG_FILE_LINES } from "./memory/schema.mjs"
|
|
8
|
-
|
|
9
|
-
// CRUD + search + ensureEmbeddings
|
|
10
|
-
// (delete.mjs owns the disk-truth row match + deletion family — see its header)
|
|
11
|
-
export { put, search, ftsSearch, fetchEntry, ensureEmbeddings, putMarkdown, syncDir, indexMarkdownFile, list, clearPersonal, buildFtsQuery } from "./memory/core.mjs"
|
|
12
|
-
export { matchMemoryRows, deleteWhere, deleteByUid, remove } from "./memory/delete.mjs"
|
|
13
|
-
|
|
14
|
-
// code chunking + markdown chunking
|
|
15
|
-
export { detectLanguage, extractSymbols, extractPySymbols, chunkCode, extractLeadingDoc, yieldTick, _upsertCodeFile, chunkMarkdown, _upsertDocFile } from "./memory/code-index.mjs"
|
|
16
|
-
|
|
17
|
-
// code sync + search + reindex
|
|
18
|
-
export { gitSync, codeSync, markIndexedCommit, codeSearch, ensureCodeEmbeddings, codeSearchTool, reindexFile } from "./memory/code-sync.mjs"
|
|
19
|
-
|
|
20
|
-
// doc sync + search + memoryTools
|
|
21
|
-
export { docSync, docSearch, ensureDocEmbeddings, docSearchTool, memoryTools } from "./memory/docs.mjs"
|
package/src/model-ref.mjs
DELETED
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* model-ref.mjs — composite model reference parser (MODEL-MERGE-SESSION; v2 2026-09-10).
|
|
3
|
-
* A model is an explicit "provider:model" composite — config.defaultModel (top level,
|
|
4
|
-
* new-session starting point) and session slots both speak this language. 有效域 = **provider 存在
|
|
5
|
-
* + 双段非空**:清单不再人工维护(模型清单由 provider 运行期 `GET /models` 拉取决定——
|
|
6
|
-
* PROVIDER.md §16),候选成员校验**已废除**——显式 `p:m` 一律放行(含多冒号首分割)。
|
|
7
|
-
* providers[].model 是渠道默认模型(单值)——候选清单字段 models[] 已整字段退场。
|
|
8
|
-
*
|
|
9
|
-
* Strict first-colon split — deliberately does NOT reuse resolveChildProvider's loose
|
|
10
|
-
* three-state resolution: ① legacy single-provider configs and ② model-name-only refs
|
|
11
|
-
* are gone with activeProvider/activeModel (F-1), so a bare provider or bare model is
|
|
12
|
-
* invalid everywhere (裁定③——裸 provider 拒——显式 p:m)。
|
|
13
|
-
*
|
|
14
|
-
* Runtime model resolution:
|
|
15
|
-
* parseModelRef(ref, providers) → { ok, provider, model } | { ok:false, reason }
|
|
16
|
-
* resolveRuntimeProvider(providers, defaultModel)
|
|
17
|
-
* → provider object with `.model` set, or {} when
|
|
18
|
-
* defaultModel is null/invalid (D-S1: callers mark
|
|
19
|
-
* _providerInvalid — never throws)
|
|
20
|
-
* defaultModelReason(providers, defaultModel) → human reason for the D-S1 marker
|
|
21
|
-
*
|
|
22
|
-
* Consumers: config.mjs loadConfig (re-exported as the config hub), make-agent.mjs.
|
|
23
|
-
*/
|
|
24
|
-
export function parseModelRef(ref, providers) {
|
|
25
|
-
if (typeof ref !== "string" || !ref.trim()) {
|
|
26
|
-
return { ok: false, reason: 'model reference expected as "provider:model" (e.g. deepseek:deepseek-v4-pro)' }
|
|
27
|
-
}
|
|
28
|
-
// 首冒号分割——`a:b:c` → provider=a、model=`b:c`(`ollama:llama3:70b` 式模型名可用,M4)
|
|
29
|
-
const sep = ref.indexOf(":")
|
|
30
|
-
if (sep <= 0) {
|
|
31
|
-
return { ok: false, reason: `invalid model reference "${ref}" — expected provider:model (bare provider/model names are not accepted)` }
|
|
32
|
-
}
|
|
33
|
-
const providerName = ref.slice(0, sep)
|
|
34
|
-
const model = ref.slice(sep + 1)
|
|
35
|
-
if (!model) {
|
|
36
|
-
return { ok: false, reason: `invalid model reference "${ref}" — model part is empty (expected provider:model)` }
|
|
37
|
-
}
|
|
38
|
-
const list = Array.isArray(providers) ? providers : []
|
|
39
|
-
const provider = list.find((p) => p?.name === providerName)
|
|
40
|
-
if (!provider) {
|
|
41
|
-
const available = list.map((p) => p.name).join(", ") || "(none)"
|
|
42
|
-
return { ok: false, reason: `unknown provider "${providerName}" in model reference (available: ${available})` }
|
|
43
|
-
}
|
|
44
|
-
return { ok: true, provider, model }
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/** Resolve the runtime provider object for config.defaultModel: provider clone carrying
|
|
48
|
-
* `.model` = the parsed concrete model (API/spec consumers read provider.model unchanged).
|
|
49
|
-
* Invalid/missing defaultModel → {} (D-S1 shape — name/model/baseURL absent so
|
|
50
|
-
* validateProvider flags it; TUI/headless surface the reason from defaultModelReason). */
|
|
51
|
-
export function resolveRuntimeProvider(providers, defaultModel) {
|
|
52
|
-
const r = parseModelRef(defaultModel, providers)
|
|
53
|
-
if (!r.ok) return {}
|
|
54
|
-
return { ...r.provider, model: r.model }
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/** Human-readable reason behind an invalid/empty runtime resolution (D-S1 原因). */
|
|
58
|
-
export function defaultModelReason(providers, defaultModel) {
|
|
59
|
-
const list = Array.isArray(providers) ? providers : []
|
|
60
|
-
if (!defaultModel) {
|
|
61
|
-
return list.length > 0
|
|
62
|
-
? "defaultModel 未设置(config 顶层 defaultModel — 新会话起点;/config → 默认模型 设置)"
|
|
63
|
-
: "未配置任何 provider"
|
|
64
|
-
}
|
|
65
|
-
return parseModelRef(defaultModel, list).reason ?? `defaultModel "${defaultModel}" 无效`
|
|
66
|
-
}
|