@caupulican/pi-adaptative 0.81.13 → 0.81.16

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.
Files changed (55) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/bundled-resources/runtimes/hf-transformers-openai-server.py +427 -0
  3. package/dist/bundled-resources/skills/tool-call-repair/SKILL.md +13 -11
  4. package/dist/bundled-resources/skills/tool-call-repair/references/failure-grammar.md +16 -10
  5. package/dist/bundled-resources/skills/tool-call-repair/references/text-protocol-grammar.md +14 -7
  6. package/dist/core/agent-session.d.ts +11 -3
  7. package/dist/core/agent-session.d.ts.map +1 -1
  8. package/dist/core/agent-session.js +132 -23
  9. package/dist/core/agent-session.js.map +1 -1
  10. package/dist/core/local-runtime-controller.d.ts +17 -9
  11. package/dist/core/local-runtime-controller.d.ts.map +1 -1
  12. package/dist/core/local-runtime-controller.js +124 -20
  13. package/dist/core/local-runtime-controller.js.map +1 -1
  14. package/dist/core/models/adaptation-store.d.ts +2 -0
  15. package/dist/core/models/adaptation-store.d.ts.map +1 -1
  16. package/dist/core/models/adaptation-store.js +4 -0
  17. package/dist/core/models/adaptation-store.js.map +1 -1
  18. package/dist/core/models/default-model-suggestions.d.ts +4 -4
  19. package/dist/core/models/default-model-suggestions.d.ts.map +1 -1
  20. package/dist/core/models/default-model-suggestions.js +9 -0
  21. package/dist/core/models/default-model-suggestions.js.map +1 -1
  22. package/dist/core/models/local-registration.d.ts +12 -0
  23. package/dist/core/models/local-registration.d.ts.map +1 -1
  24. package/dist/core/models/local-registration.js +68 -0
  25. package/dist/core/models/local-registration.js.map +1 -1
  26. package/dist/core/models/local-runtime.d.ts +77 -1
  27. package/dist/core/models/local-runtime.d.ts.map +1 -1
  28. package/dist/core/models/local-runtime.js +295 -4
  29. package/dist/core/models/local-runtime.js.map +1 -1
  30. package/dist/core/models/model-ref.d.ts +4 -0
  31. package/dist/core/models/model-ref.d.ts.map +1 -1
  32. package/dist/core/models/model-ref.js +12 -3
  33. package/dist/core/models/model-ref.js.map +1 -1
  34. package/dist/core/tool-repair-health.d.ts.map +1 -1
  35. package/dist/core/tool-repair-health.js +2 -1
  36. package/dist/core/tool-repair-health.js.map +1 -1
  37. package/dist/modes/interactive/interactive-mode.d.ts +1 -0
  38. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  39. package/dist/modes/interactive/interactive-mode.js +4 -0
  40. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  41. package/dist/modes/interactive/local-model-commands.d.ts +3 -1
  42. package/dist/modes/interactive/local-model-commands.d.ts.map +1 -1
  43. package/dist/modes/interactive/local-model-commands.js +133 -19
  44. package/dist/modes/interactive/local-model-commands.js.map +1 -1
  45. package/docs/models.md +19 -1
  46. package/docs/tool-repair.md +2 -0
  47. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  48. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  49. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  50. package/examples/extensions/sandbox/package-lock.json +2 -2
  51. package/examples/extensions/sandbox/package.json +1 -1
  52. package/examples/extensions/with-deps/package-lock.json +2 -2
  53. package/examples/extensions/with-deps/package.json +1 -1
  54. package/npm-shrinkwrap.json +12 -12
  55. package/package.json +4 -4
@@ -13,7 +13,7 @@
13
13
  import { type Component, Container, type TUI } from "@caupulican/pi-tui";
14
14
  import type { AgentSession } from "../../core/agent-session.ts";
15
15
  import type { ModelRegistry } from "../../core/model-registry.ts";
16
- import type { OllamaRuntime } from "../../core/models/local-runtime.ts";
16
+ import type { OllamaRuntime, TransformersRuntime } from "../../core/models/local-runtime.ts";
17
17
  import type { SettingsManager } from "../../core/settings-manager.ts";
18
18
  import { type FitnessRole } from "./components/fitness-role-selector.ts";
19
19
  type SelectorFactory = (done: () => void) => {
@@ -44,6 +44,7 @@ export interface LocalModelHost {
44
44
  readonly settingsManager: SettingsManager;
45
45
  readonly ui: TUI;
46
46
  readonly chatContainer: Container;
47
+ getTransformersRuntime(modelId: string, baseUrl?: string): TransformersRuntime;
47
48
  showStatus(message: string): void;
48
49
  showError(message: string): void;
49
50
  showSelector(create: SelectorFactory): void;
@@ -57,6 +58,7 @@ export declare function handleModelsCommand(host: LocalModelHost, argsText: stri
57
58
  export declare function ensureLocalServer(host: LocalModelHost): Promise<boolean>;
58
59
  export declare function listLocalModels(host: LocalModelHost): Promise<void>;
59
60
  export declare function addLocalModel(host: LocalModelHost, pullRef: string, preselectRole?: FitnessRole): Promise<void>;
61
+ export declare function addTransformersModel(host: LocalModelHost, modelId: string, preselectRole?: FitnessRole): Promise<void>;
60
62
  export declare function removeLocalModel(host: LocalModelHost, ref: string, confirmed: boolean): Promise<void>;
61
63
  /** /fitness with no args: pick a model from the configured registry, probe it, assign a role. */
62
64
  /** Pick a validated suggestion → install it → probe on this host → land its shaped role. */
@@ -1 +1 @@
1
- {"version":3,"file":"local-model-commands.d.ts","sourceRoot":"","sources":["../../../src/modes/interactive/local-model-commands.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `/models` local-model lifecycle and `/fitness` probe/role-assignment flows\n * extracted from interactive-mode.\n *\n * `/models` is a USER-invoked local-model manager (list/add/remove/stop, never a\n * model-invokable tool); the fitness helpers probe a model on the current host\n * and land a shaped role. The server/selector flows share a `LocalModelHost`\n * seam, while `runFitnessAndAssign`/`assignFitnessRole` take narrow host shapes\n * matching their prototype-driven behaviour tests (fitness-probe-gate,\n * fitness-role-assignment), which keep exercising interactive-mode's thin\n * wrappers unchanged.\n */\n\nimport type { ThinkingLevel } from \"@caupulican/pi-agent-core\";\nimport { getSupportedThinkingLevels } from \"@caupulican/pi-ai\";\nimport {\n\ttype Component,\n\tContainer,\n\ttype SelectItem,\n\tSelectList,\n\ttype SelectListLayoutOptions,\n\tSpacer,\n\tText,\n\ttype TUI,\n} from \"@caupulican/pi-tui\";\nimport { getAgentDir } from \"../../config.ts\";\nimport type { AgentSession } from \"../../core/agent-session.ts\";\nimport type { ModelRegistry } from \"../../core/model-registry.ts\";\nimport { resolveCliModel } from \"../../core/model-resolver.ts\";\nimport { evaluateSurfaceFitness } from \"../../core/model-router/fitness-gate.ts\";\nimport { DEFAULT_MODEL_SUGGESTIONS } from \"../../core/models/default-model-suggestions.ts\";\nimport { FitnessStore } from \"../../core/models/fitness-store.ts\";\nimport { registerLocalModel, unregisterLocalModel } from \"../../core/models/local-registration.ts\";\nimport type { OllamaRuntime } from \"../../core/models/local-runtime.ts\";\nimport { matchesInstalledLocalModel, normalizeModelSource } from \"../../core/models/model-ref.ts\";\nimport { formatModelFitnessReport, isProbeAllFailed } from \"../../core/research/model-fitness.ts\";\nimport type { SettingsManager } from \"../../core/settings-manager.ts\";\nimport { DynamicBorder } from \"./components/dynamic-border.ts\";\nimport { type FitnessRole, FitnessRoleSelectorComponent } from \"./components/fitness-role-selector.ts\";\nimport { ModelSelectorComponent } from \"./components/model-selector.ts\";\nimport { ModelSuggestionSelectorComponent } from \"./components/model-suggestion-selector.ts\";\nimport { getSelectListTheme } from \"./theme/theme.ts\";\n\ntype SelectorFactory = (done: () => void) => { component: Component; focus: Component };\n\nconst MODEL_ROUTER_THINKING_SELECT_LIST_LAYOUT: SelectListLayoutOptions = {\n\tminPrimaryColumnWidth: 12,\n\tmaxPrimaryColumnWidth: 32,\n};\n\nconst MODEL_ROUTER_THINKING_INHERIT_VALUE = \"__inherit_model_router_thinking__\";\nconst MODEL_ROUTER_THINKING_INHERIT_LABEL = \"(inherit)\";\n\nconst THINKING_LEVEL_DESCRIPTIONS: Record<ThinkingLevel, string> = {\n\toff: \"No reasoning\",\n\tminimal: \"Very brief reasoning (~1k tokens)\",\n\tlow: \"Light reasoning (~2k tokens)\",\n\tmedium: \"Moderate reasoning (~8k tokens)\",\n\thigh: \"Deep reasoning (~16k tokens)\",\n\txhigh: \"Maximum reasoning (~32k tokens)\",\n};\n\nconst MODEL_ROUTER_THINKING_FALLBACK_LEVELS: readonly ThinkingLevel[] = [\n\t\"off\",\n\t\"minimal\",\n\t\"low\",\n\t\"medium\",\n\t\"high\",\n\t\"xhigh\",\n];\n\ntype RouterThinkingLevel = ThinkingLevel | typeof MODEL_ROUTER_THINKING_INHERIT_VALUE;\ntype ModelRouterThinkingField =\n\t| \"cheapThinking\"\n\t| \"mediumThinking\"\n\t| \"expensiveThinking\"\n\t| \"executorThinking\"\n\t| \"judgeThinking\";\n\n/** Narrow seam for persisting a probed model's role — matches the fitness-role test. */\nexport interface AssignRoleHost {\n\treadonly settingsManager: SettingsManager;\n\tshowStatus(message: string): void;\n}\n\n/** Seam for the fitness probe + role-selector flow — matches the fitness-probe-gate test. */\nexport interface RunFitnessHost {\n\treadonly session: Pick<AgentSession, \"runModelFitness\"> & { modelRegistry?: ModelRegistry };\n\treadonly settingsManager: SettingsManager;\n\treadonly chatContainer: Container;\n\treadonly ui: TUI;\n\tshowStatus(message: string): void;\n\tshowError(message: string): void;\n\tshowSelector(create: SelectorFactory): void;\n}\n\n/** Full seam for the `/models` server/selector flows. */\nexport interface LocalModelHost {\n\treadonly localRuntime: OllamaRuntime;\n\treadonly session: AgentSession;\n\treadonly settingsManager: SettingsManager;\n\treadonly ui: TUI;\n\treadonly chatContainer: Container;\n\tshowStatus(message: string): void;\n\tshowError(message: string): void;\n\tshowSelector(create: SelectorFactory): void;\n}\n\nclass ModelRouterThinkingSelectorComponent extends Container {\n\tprivate selectList: SelectList;\n\n\tconstructor(\n\t\tcurrentLevel: RouterThinkingLevel,\n\t\tavailableLevels: ThinkingLevel[],\n\t\tonSelect: (level: RouterThinkingLevel) => void,\n\t\tonCancel: () => void,\n\t) {\n\t\tsuper();\n\n\t\tconst thinkingOptions: SelectItem[] = [\n\t\t\t{\n\t\t\t\tvalue: MODEL_ROUTER_THINKING_INHERIT_VALUE,\n\t\t\t\tlabel: MODEL_ROUTER_THINKING_INHERIT_LABEL,\n\t\t\t\tdescription: \"Use current session default for this tier.\",\n\t\t\t},\n\t\t\t...availableLevels.map((level) => ({\n\t\t\t\tvalue: level,\n\t\t\t\tlabel: level,\n\t\t\t\tdescription: THINKING_LEVEL_DESCRIPTIONS[level],\n\t\t\t})),\n\t\t];\n\n\t\tthis.addChild(new DynamicBorder());\n\n\t\tthis.selectList = new SelectList(\n\t\t\tthinkingOptions,\n\t\t\tthinkingOptions.length,\n\t\t\tgetSelectListTheme(),\n\t\t\tMODEL_ROUTER_THINKING_SELECT_LIST_LAYOUT,\n\t\t);\n\n\t\tconst index = thinkingOptions.findIndex((item) => item.value === currentLevel);\n\t\tif (index !== -1) {\n\t\t\tthis.selectList.setSelectedIndex(index);\n\t\t}\n\n\t\tthis.selectList.onSelect = (item) => {\n\t\t\tonSelect(item.value as RouterThinkingLevel);\n\t\t};\n\t\tthis.selectList.onCancel = () => {\n\t\t\tonCancel();\n\t\t};\n\n\t\tthis.addChild(this.selectList);\n\t\tthis.addChild(new DynamicBorder());\n\t}\n}\n/**\n * /models — USER-invoked local model lifecycle (never a model-invokable tool):\n * list/add/remove/stop per local-model-lifecycle-design.md. Removal is explicit-only with\n * full disclosure; a pasted install command is parsed for its ref, never executed.\n */\nexport async function handleModelsCommand(host: LocalModelHost, argsText: string): Promise<void> {\n\tconst [action = \"list\", ...rest] = argsText.split(/\\s+/).filter(Boolean);\n\ttry {\n\t\tif (action === \"suggest\" || action === \"suggestions\") {\n\t\t\tshowModelSuggestionSelector(host);\n\t\t\treturn;\n\t\t}\n\t\tif (action === \"stop\") {\n\t\t\tconst stopped = host.localRuntime.stop();\n\t\t\thost.showStatus(\n\t\t\t\tstopped.stopped\n\t\t\t\t\t? \"Pi-managed local model server stopped (models remain installed).\"\n\t\t\t\t\t: \"No pi-managed server running (a system server, if any, is not pi's to stop).\",\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\tif (action === \"add\") {\n\t\t\tconst rawRef = rest.join(\" \");\n\t\t\tif (!rawRef) {\n\t\t\t\thost.showStatus(\n\t\t\t\t\t\"Usage: /models add <ollama-tag | hf.co/org/repo[:quant] | huggingface URL | pasted install command>\",\n\t\t\t\t);\n\t\t\t\thost.showStatus(\"Or start from a validated suggestion: /models suggest\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst source = normalizeModelSource(rawRef);\n\t\t\tif (source.type === \"rejected\") {\n\t\t\t\thost.showStatus(`Not added: ${source.reason}`);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (source.type === \"api\") {\n\t\t\t\thost.showStatus(\n\t\t\t\t\t`${source.ref} is an API model — nothing to install. Configure auth for the provider, then probe it with /fitness ${source.ref}.`,\n\t\t\t\t);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tawait addLocalModel(host, source.pullRef);\n\t\t\treturn;\n\t\t}\n\n\t\tif (action === \"remove\") {\n\t\t\tconst ref = rest[0];\n\t\t\tconst confirmed = rest[1] === \"confirm\";\n\t\t\tif (!ref) {\n\t\t\t\thost.showStatus(\"Usage: /models remove <ref> confirm\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tawait removeLocalModel(host, ref, confirmed);\n\t\t\treturn;\n\t\t}\n\n\t\tawait listLocalModels(host);\n\t} catch (error) {\n\t\thost.showError(error instanceof Error ? error.message : String(error));\n\t}\n}\n\nexport async function ensureLocalServer(host: LocalModelHost): Promise<boolean> {\n\tconst status = await host.localRuntime.detect();\n\tif (status.serverUp) return true;\n\tif (!status.binaryPath) {\n\t\tfor (const line of host.localRuntime.installGuide()) host.showStatus(line);\n\t\treturn false;\n\t}\n\thost.showStatus(\n\t\t`Starting local model server (${status.binarySource} binary, owned storage: ${status.ownedModelsDir})…`,\n\t);\n\tconst started = await host.localRuntime.start();\n\tif (!started.started) {\n\t\thost.showStatus(`Could not start the local server: ${started.reason}`);\n\t\treturn false;\n\t}\n\treturn true;\n}\n\nexport async function listLocalModels(host: LocalModelHost): Promise<void> {\n\tconst status = await host.localRuntime.detect();\n\tif (!status.serverUp) {\n\t\tif (!status.binaryPath) {\n\t\t\tfor (const line of host.localRuntime.installGuide()) host.showStatus(line);\n\t\t\treturn;\n\t\t}\n\t\thost.showStatus(\n\t\t\t`Local server not running (binary: ${status.binarySource}). /models add starts it on demand; /fitness probes registered models.`,\n\t\t);\n\t\treturn;\n\t}\n\tconst models = await host.localRuntime.list();\n\tconst fitness = FitnessStore.forAgentDir(getAgentDir()).getForHost();\n\tconst lines = [\n\t\t`Local models (${status.managedByPi ? `pi-managed server, storage: ${status.ownedModelsDir}` : \"system server — storage owned by the system daemon\"}):`,\n\t\t...(models.length === 0\n\t\t\t? [\" (none installed — /models add <ref>, or /models suggest for a validated roster)\"]\n\t\t\t: []),\n\t\t...models.map((model) => {\n\t\t\tconst report = fitness.find((entry) => entry.model === `ollama/${model.name}`);\n\t\t\tconst gb = (model.sizeBytes / 1e9).toFixed(2);\n\t\t\tconst probe = report\n\t\t\t\t? `probed ${report.at.slice(0, 10)}: digest ${report.report.digest?.succeeded ?? \"?\"}/${report.report.digest?.total ?? \"?\"}, tool-calls ${report.report.toolCall.succeeded}/${report.report.toolCall.total}${report.report.tokensPerSecond ? `, ~${report.report.tokensPerSecond} tok/s` : \"\"}`\n\t\t\t\t: `unprobed — run /fitness ollama/${model.name}`;\n\t\t\treturn ` - ${model.name} (${gb} GB) · ${probe}`;\n\t\t}),\n\t\t\"Commands: /models add <ref> · /models remove <ref> confirm · /models stop\",\n\t];\n\tfor (const line of lines) host.showStatus(line);\n}\n\nexport async function addLocalModel(host: LocalModelHost, pullRef: string, preselectRole?: FitnessRole): Promise<void> {\n\tif (!(await ensureLocalServer(host))) return;\n\thost.showStatus(`Pulling ${pullRef}… (weights land in the server's model storage)`);\n\tlet lastShown = 0;\n\tconst pulled = await host.localRuntime.pull(pullRef, (progress) => {\n\t\tconst now = Date.now();\n\t\tif (now - lastShown > 2000) {\n\t\t\tlastShown = now;\n\t\t\thost.showStatus(` ${pullRef}: ${progress}`);\n\t\t}\n\t});\n\tif (!pulled.ok) {\n\t\thost.showStatus(`Pull failed: ${pulled.error}`);\n\t\treturn;\n\t}\n\tconst registration = registerLocalModel({\n\t\tagentDir: getAgentDir(),\n\t\tref: pullRef,\n\t\tbaseUrl: host.localRuntime.baseUrl,\n\t});\n\tif (!registration.ok) {\n\t\thost.showStatus(`Pulled, but not auto-registered: ${registration.reason}`);\n\t\tif (registration.manualSnippet) {\n\t\t\thost.showStatus(`Add this to ${registration.modelsJsonPath} yourself:\\n${registration.manualSnippet}`);\n\t\t}\n\t\treturn;\n\t}\n\thost.session.modelRegistry.refresh();\n\thost.showStatus(`${pullRef} installed and registered as ollama/${pullRef}. Probing fitness…`);\n\tawait runFitnessAndAssign(host, `ollama/${pullRef}`, preselectRole);\n}\n\nexport async function removeLocalModel(host: LocalModelHost, ref: string, confirmed: boolean): Promise<void> {\n\tconst status = await host.localRuntime.detect();\n\tif (!status.serverUp) {\n\t\thost.showStatus(\"Local server not running — start it (any /models action) before removing.\");\n\t\treturn;\n\t}\n\tconst models = await host.localRuntime.list();\n\tconst target = models.find((model) => matchesInstalledLocalModel(ref, model.name));\n\tif (!target) {\n\t\thost.showStatus(\n\t\t\t`${ref} is not installed. Installed: ${models.map((model) => model.name).join(\", \") || \"(none)\"}`,\n\t\t);\n\t\treturn;\n\t}\n\tif (!confirmed) {\n\t\t// EXPLICIT USER ACTION ONLY: full disclosure, then require the confirm token.\n\t\tconst gb = (target.sizeBytes / 1e9).toFixed(2);\n\t\thost.showStatus(\n\t\t\t[\n\t\t\t\t`Removing ${ref} will delete:`,\n\t\t\t\t` - model weights (${gb} GB) from ${status.managedByPi ? status.ownedModelsDir : \"the system server's storage\"}`,\n\t\t\t\t` - the ollama/${ref} entry in models.json`,\n\t\t\t\t` - its cached fitness report for this host`,\n\t\t\t\t`Run: /models remove ${ref} confirm`,\n\t\t\t].join(\"\\n\"),\n\t\t);\n\t\treturn;\n\t}\n\tconst removed = await host.localRuntime.remove(ref);\n\tif (!removed.ok) {\n\t\thost.showStatus(`Remove failed: ${removed.error}`);\n\t\treturn;\n\t}\n\tunregisterLocalModel({ agentDir: getAgentDir(), ref });\n\tFitnessStore.forAgentDir(getAgentDir()).remove(`ollama/${ref}`);\n\thost.session.modelRegistry.refresh();\n\thost.showStatus(`${ref} removed: weights deleted, registration and fitness report dropped.`);\n}\n\n/** /fitness with no args: pick a model from the configured registry, probe it, assign a role. */\n/** Pick a validated suggestion → install it → probe on this host → land its shaped role. */\nexport function showModelSuggestionSelector(host: LocalModelHost): void {\n\thost.showSelector((done) => {\n\t\tconst selector = new ModelSuggestionSelectorComponent(\n\t\t\tDEFAULT_MODEL_SUGGESTIONS,\n\t\t\tasync (suggestion) => {\n\t\t\t\tdone();\n\t\t\t\t// The shaped role rides along so the post-probe selector lands on it pre-selected;\n\t\t\t\t// non-tool-callers carry curator/judge/none, never executor, so this can't footgun.\n\t\t\t\tawait addLocalModel(host, suggestion.pullRef, suggestion.assignRole);\n\t\t\t},\n\t\t\t() => {\n\t\t\t\tdone();\n\t\t\t\thost.ui.requestRender();\n\t\t\t},\n\t\t);\n\t\treturn { component: selector, focus: selector };\n\t});\n}\n\nexport function showFitnessModelSelector(host: LocalModelHost): void {\n\thost.showSelector((done) => {\n\t\tconst selector = new ModelSelectorComponent(\n\t\t\thost.ui,\n\t\t\thost.session.model,\n\t\t\thost.settingsManager,\n\t\t\thost.session.modelRegistry,\n\t\t\thost.session.scopedModels,\n\t\t\tasync (model) => {\n\t\t\t\tdone();\n\t\t\t\tawait runFitnessAndAssign(host, `${model.provider}/${model.id}`);\n\t\t\t},\n\t\t\t() => {\n\t\t\t\tdone();\n\t\t\t\thost.ui.requestRender();\n\t\t\t},\n\t\t);\n\t\treturn { component: selector, focus: selector };\n\t});\n}\n\n/** Resolve the routed model's supported thinking levels for a fitness-assignment flow, with a safe fallback. */\nfunction getModelThinkingLevels(modelRegistry: ModelRegistry | undefined, modelRef: string): ThinkingLevel[] {\n\tif (!modelRegistry) {\n\t\treturn [...MODEL_ROUTER_THINKING_FALLBACK_LEVELS];\n\t}\n\tconst resolved = resolveCliModel({ cliModel: modelRef, modelRegistry });\n\tif (!resolved.model) {\n\t\treturn [...MODEL_ROUTER_THINKING_FALLBACK_LEVELS];\n\t}\n\treturn getSupportedThinkingLevels(resolved.model);\n}\n\nfunction getModelRouterThinkingField(role: FitnessRole): ModelRouterThinkingField | undefined {\n\tif (role === \"router-cheap\") {\n\t\treturn \"cheapThinking\";\n\t}\n\tif (role === \"router-medium\") {\n\t\treturn \"mediumThinking\";\n\t}\n\tif (role === \"router-expensive\") {\n\t\treturn \"expensiveThinking\";\n\t}\n\tif (role === \"executor\") {\n\t\treturn \"executorThinking\";\n\t}\n\tif (role === \"judge\") {\n\t\treturn \"judgeThinking\";\n\t}\n\treturn undefined;\n}\n\nfunction promptForModelRouterThinking(host: RunFitnessHost, modelRef: string, role: FitnessRole): void {\n\tconst thinkingField = getModelRouterThinkingField(role);\n\tif (!thinkingField) {\n\t\treturn;\n\t}\n\n\tconst modelRegistry = host.session.modelRegistry;\n\tconst availableLevels = getModelThinkingLevels(modelRegistry, modelRef);\n\tconst settings = host.settingsManager.getModelRouterSettings();\n\tconst configuredThinking = settings[thinkingField];\n\tconst currentThinking =\n\t\tconfiguredThinking && availableLevels.includes(configuredThinking)\n\t\t\t? configuredThinking\n\t\t\t: MODEL_ROUTER_THINKING_INHERIT_VALUE;\n\n\thost.showSelector((done) => {\n\t\tconst selector = new ModelRouterThinkingSelectorComponent(\n\t\t\tcurrentThinking,\n\t\t\tavailableLevels,\n\t\t\t(level) => {\n\t\t\t\tdone();\n\t\t\t\thost.settingsManager.setModelRouterSettings({\n\t\t\t\t\t...settings,\n\t\t\t\t\t[thinkingField]: level === MODEL_ROUTER_THINKING_INHERIT_VALUE ? undefined : level,\n\t\t\t\t});\n\t\t\t},\n\t\t\t() => {\n\t\t\t\tdone();\n\t\t\t\thost.ui.requestRender();\n\t\t\t},\n\t\t);\n\t\treturn { component: selector, focus: selector };\n\t});\n}\n\n/** Probe a model's fitness, show the report, then offer one-step role assignment. When the model\n * came from a validated suggestion, `preselectRole` lands its shaped role already highlighted. */\nexport async function runFitnessAndAssign(\n\thost: RunFitnessHost,\n\tmodelRef: string,\n\tpreselectRole?: FitnessRole,\n): Promise<void> {\n\thost.showStatus(`Model fitness probe running on ${modelRef}… (6 surfaces; local models may take a few minutes)`);\n\ttry {\n\t\tconst outcome = await host.session.runModelFitness({ model: modelRef });\n\t\tif (!outcome.started) {\n\t\t\thost.showStatus(`Model fitness skipped: ${outcome.skipReason}`);\n\t\t\treturn;\n\t\t}\n\t\thost.chatContainer.addChild(new Spacer(1));\n\t\thost.chatContainer.addChild(new Text(formatModelFitnessReport(outcome.model, outcome.report), 1, 0));\n\t\thost.ui.requestRender();\n\t\t// Validate-before-load: zero successes on every probed surface means the model cannot\n\t\t// drive any of the harness's subagent contracts on this host — refuse adoption instead\n\t\t// of landing a role selector the user might reflexively confirm (this is the reported\n\t\t// bug: a 0/3-everywhere model still got set as judge model and saved to Model Router).\n\t\tif (isProbeAllFailed(outcome.report)) {\n\t\t\thost.showStatus(\n\t\t\t\t`${outcome.model} failed the fitness probe on all surfaces — not configured. Use /model to set it manually if you accept the risk.`,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\t\thost.showSelector((done) => {\n\t\t\tconst selector = new FitnessRoleSelectorComponent(\n\t\t\t\toutcome.model,\n\t\t\t\t(role) => {\n\t\t\t\t\tdone();\n\t\t\t\t\tif (role === \"scout\") {\n\t\t\t\t\t\tconst verdict = evaluateSurfaceFitness(\"scout_auto\", outcome.report);\n\t\t\t\t\t\tif (!verdict.fit) {\n\t\t\t\t\t\t\tconst reason = verdict.reason === \"lane_failed\" ? `failed ${verdict.lane}` : \"was not probed\";\n\t\t\t\t\t\t\thost.showStatus(\n\t\t\t\t\t\t\t\t`${outcome.model} not assigned as scout: ${reason} on the scout_auto fitness exam. Use the docs/scout.md Modelfile recipe, then rerun /fitness.`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tassignFitnessRole(host, outcome.model, role);\n\t\t\t\t\tpromptForModelRouterThinking(host, outcome.model, role);\n\t\t\t\t},\n\t\t\t\t() => {\n\t\t\t\t\tdone();\n\t\t\t\t\thost.ui.requestRender();\n\t\t\t\t},\n\t\t\t\tpreselectRole,\n\t\t\t);\n\t\t\treturn { component: selector, focus: selector };\n\t\t});\n\t} catch (error) {\n\t\thost.showError(error instanceof Error ? error.message : String(error));\n\t}\n}\n\n/** Persist a role assignment from the post-probe selector into the matching settings. */\nexport function assignFitnessRole(host: AssignRoleHost, modelRef: string, role: FitnessRole): void {\n\tif (role === \"none\") {\n\t\thost.showStatus(`Fitness result for ${modelRef} saved. Assign a role later from /settings.`);\n\t\treturn;\n\t}\n\tif (role === \"curator\") {\n\t\tconst current = host.settingsManager.getContextCurationSettings();\n\t\thost.settingsManager.setContextCurationSettings({ ...current, enabled: true, model: modelRef });\n\t\thost.showStatus(`Context curation enabled with ${modelRef} as the curator.`);\n\t\treturn;\n\t}\n\tif (role === \"executor\") {\n\t\tconst router = host.settingsManager.getModelRouterSettings();\n\t\thost.settingsManager.setModelRouterSettings({ ...router, executorModel: modelRef });\n\t\tconst hint = router.enabled ? \"\" : \" Model router is currently disabled — enable it in /settings → Model Router.\";\n\t\thost.showStatus(`${modelRef} set as the toolkit executor (direct Level-0 hits route to it).${hint}`);\n\t\treturn;\n\t}\n\tif (role === \"scout\") {\n\t\thost.settingsManager.setScoutSettings({ enabled: true, model: modelRef });\n\t\thost.showStatus(`${modelRef} set as the repository scout (context_scout enabled).`);\n\t\treturn;\n\t}\n\tconst router = host.settingsManager.getModelRouterSettings();\n\tconst field =\n\t\trole === \"router-cheap\"\n\t\t\t? \"cheapModel\"\n\t\t\t: role === \"router-medium\"\n\t\t\t\t? \"mediumModel\"\n\t\t\t\t: role === \"router-expensive\"\n\t\t\t\t\t? \"expensiveModel\"\n\t\t\t\t\t: role === \"judge\"\n\t\t\t\t\t\t? \"judgeModel\"\n\t\t\t\t\t\t: \"learningModel\";\n\thost.settingsManager.setModelRouterSettings({ ...router, [field]: modelRef });\n\tconst hint = router.enabled ? \"\" : \" Model router is currently disabled — enable it in /settings → Model Router.\";\n\thost.showStatus(`${modelRef} set as ${role.replace(\"router-\", \"router \")} model.${hint}`);\n}\n"]}
1
+ {"version":3,"file":"local-model-commands.d.ts","sourceRoot":"","sources":["../../../src/modes/interactive/local-model-commands.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `/models` local-model lifecycle and `/fitness` probe/role-assignment flows\n * extracted from interactive-mode.\n *\n * `/models` is a USER-invoked local-model manager (list/add/remove/stop, never a\n * model-invokable tool); the fitness helpers probe a model on the current host\n * and land a shaped role. The server/selector flows share a `LocalModelHost`\n * seam, while `runFitnessAndAssign`/`assignFitnessRole` take narrow host shapes\n * matching their prototype-driven behaviour tests (fitness-probe-gate,\n * fitness-role-assignment), which keep exercising interactive-mode's thin\n * wrappers unchanged.\n */\n\nimport type { ThinkingLevel } from \"@caupulican/pi-agent-core\";\nimport { getSupportedThinkingLevels } from \"@caupulican/pi-ai\";\nimport {\n\ttype Component,\n\tContainer,\n\ttype SelectItem,\n\tSelectList,\n\ttype SelectListLayoutOptions,\n\tSpacer,\n\tText,\n\ttype TUI,\n} from \"@caupulican/pi-tui\";\nimport { getAgentDir } from \"../../config.ts\";\nimport type { AgentSession } from \"../../core/agent-session.ts\";\nimport type { ModelRegistry } from \"../../core/model-registry.ts\";\nimport { resolveCliModel } from \"../../core/model-resolver.ts\";\nimport { evaluateSurfaceFitness } from \"../../core/model-router/fitness-gate.ts\";\nimport { DEFAULT_MODEL_SUGGESTIONS } from \"../../core/models/default-model-suggestions.ts\";\nimport { FitnessStore } from \"../../core/models/fitness-store.ts\";\nimport {\n\tHF_TRANSFORMERS_PROVIDER,\n\tregisterLocalModel,\n\tregisterTransformersModel,\n\tunregisterLocalModel,\n\tunregisterTransformersModel,\n} from \"../../core/models/local-registration.ts\";\nimport type { OllamaRuntime, TransformersRuntime } from \"../../core/models/local-runtime.ts\";\nimport { matchesInstalledLocalModel, normalizeModelSource } from \"../../core/models/model-ref.ts\";\nimport { formatModelFitnessReport, isProbeAllFailed } from \"../../core/research/model-fitness.ts\";\nimport type { SettingsManager } from \"../../core/settings-manager.ts\";\nimport { DynamicBorder } from \"./components/dynamic-border.ts\";\nimport { type FitnessRole, FitnessRoleSelectorComponent } from \"./components/fitness-role-selector.ts\";\nimport { ModelSelectorComponent } from \"./components/model-selector.ts\";\nimport { ModelSuggestionSelectorComponent } from \"./components/model-suggestion-selector.ts\";\nimport { getSelectListTheme } from \"./theme/theme.ts\";\n\ntype SelectorFactory = (done: () => void) => { component: Component; focus: Component };\n\nconst MODEL_ROUTER_THINKING_SELECT_LIST_LAYOUT: SelectListLayoutOptions = {\n\tminPrimaryColumnWidth: 12,\n\tmaxPrimaryColumnWidth: 32,\n};\n\nconst MODEL_ROUTER_THINKING_INHERIT_VALUE = \"__inherit_model_router_thinking__\";\nconst MODEL_ROUTER_THINKING_INHERIT_LABEL = \"(inherit)\";\n\nconst THINKING_LEVEL_DESCRIPTIONS: Record<ThinkingLevel, string> = {\n\toff: \"No reasoning\",\n\tminimal: \"Very brief reasoning (~1k tokens)\",\n\tlow: \"Light reasoning (~2k tokens)\",\n\tmedium: \"Moderate reasoning (~8k tokens)\",\n\thigh: \"Deep reasoning (~16k tokens)\",\n\txhigh: \"Maximum reasoning (~32k tokens)\",\n};\n\nconst MODEL_ROUTER_THINKING_FALLBACK_LEVELS: readonly ThinkingLevel[] = [\n\t\"off\",\n\t\"minimal\",\n\t\"low\",\n\t\"medium\",\n\t\"high\",\n\t\"xhigh\",\n];\n\ntype RouterThinkingLevel = ThinkingLevel | typeof MODEL_ROUTER_THINKING_INHERIT_VALUE;\ntype ModelRouterThinkingField =\n\t| \"cheapThinking\"\n\t| \"mediumThinking\"\n\t| \"expensiveThinking\"\n\t| \"executorThinking\"\n\t| \"judgeThinking\";\n\n/** Narrow seam for persisting a probed model's role — matches the fitness-role test. */\nexport interface AssignRoleHost {\n\treadonly settingsManager: SettingsManager;\n\tshowStatus(message: string): void;\n}\n\n/** Seam for the fitness probe + role-selector flow — matches the fitness-probe-gate test. */\nexport interface RunFitnessHost {\n\treadonly session: Pick<AgentSession, \"runModelFitness\"> & { modelRegistry?: ModelRegistry };\n\treadonly settingsManager: SettingsManager;\n\treadonly chatContainer: Container;\n\treadonly ui: TUI;\n\tshowStatus(message: string): void;\n\tshowError(message: string): void;\n\tshowSelector(create: SelectorFactory): void;\n}\n\n/** Full seam for the `/models` server/selector flows. */\nexport interface LocalModelHost {\n\treadonly localRuntime: OllamaRuntime;\n\treadonly session: AgentSession;\n\treadonly settingsManager: SettingsManager;\n\treadonly ui: TUI;\n\treadonly chatContainer: Container;\n\tgetTransformersRuntime(modelId: string, baseUrl?: string): TransformersRuntime;\n\tshowStatus(message: string): void;\n\tshowError(message: string): void;\n\tshowSelector(create: SelectorFactory): void;\n}\n\nclass ModelRouterThinkingSelectorComponent extends Container {\n\tprivate selectList: SelectList;\n\n\tconstructor(\n\t\tcurrentLevel: RouterThinkingLevel,\n\t\tavailableLevels: ThinkingLevel[],\n\t\tonSelect: (level: RouterThinkingLevel) => void,\n\t\tonCancel: () => void,\n\t) {\n\t\tsuper();\n\n\t\tconst thinkingOptions: SelectItem[] = [\n\t\t\t{\n\t\t\t\tvalue: MODEL_ROUTER_THINKING_INHERIT_VALUE,\n\t\t\t\tlabel: MODEL_ROUTER_THINKING_INHERIT_LABEL,\n\t\t\t\tdescription: \"Use current session default for this tier.\",\n\t\t\t},\n\t\t\t...availableLevels.map((level) => ({\n\t\t\t\tvalue: level,\n\t\t\t\tlabel: level,\n\t\t\t\tdescription: THINKING_LEVEL_DESCRIPTIONS[level],\n\t\t\t})),\n\t\t];\n\n\t\tthis.addChild(new DynamicBorder());\n\n\t\tthis.selectList = new SelectList(\n\t\t\tthinkingOptions,\n\t\t\tthinkingOptions.length,\n\t\t\tgetSelectListTheme(),\n\t\t\tMODEL_ROUTER_THINKING_SELECT_LIST_LAYOUT,\n\t\t);\n\n\t\tconst index = thinkingOptions.findIndex((item) => item.value === currentLevel);\n\t\tif (index !== -1) {\n\t\t\tthis.selectList.setSelectedIndex(index);\n\t\t}\n\n\t\tthis.selectList.onSelect = (item) => {\n\t\t\tonSelect(item.value as RouterThinkingLevel);\n\t\t};\n\t\tthis.selectList.onCancel = () => {\n\t\t\tonCancel();\n\t\t};\n\n\t\tthis.addChild(this.selectList);\n\t\tthis.addChild(new DynamicBorder());\n\t}\n}\n/**\n * /models — USER-invoked local model lifecycle (never a model-invokable tool):\n * list/add/remove/stop per local-model-lifecycle-design.md. Removal is explicit-only with\n * full disclosure; a pasted install command is parsed for its ref, never executed.\n */\nexport async function handleModelsCommand(host: LocalModelHost, argsText: string): Promise<void> {\n\tconst [action = \"list\", ...rest] = argsText.split(/\\s+/).filter(Boolean);\n\ttry {\n\t\tif (action === \"suggest\" || action === \"suggestions\") {\n\t\t\tshowModelSuggestionSelector(host);\n\t\t\treturn;\n\t\t}\n\t\tif (action === \"stop\") {\n\t\t\tconst stopped = host.localRuntime.stop();\n\t\t\tlet stoppedTransformers = 0;\n\t\t\tfor (const model of host.session.modelRegistry\n\t\t\t\t.getAll()\n\t\t\t\t.filter((entry) => entry.provider === HF_TRANSFORMERS_PROVIDER)) {\n\t\t\t\tconst serverUrl = model.baseUrl.replace(/\\/v1\\/?$/, \"\");\n\t\t\t\tif (host.getTransformersRuntime(model.id, serverUrl).stop().stopped) stoppedTransformers++;\n\t\t\t}\n\t\t\tconst stoppedAny = stopped.stopped || stoppedTransformers > 0;\n\t\t\thost.showStatus(\n\t\t\t\tstoppedAny\n\t\t\t\t\t? `Pi-managed local model server stopped${stoppedTransformers > 0 ? ` (${stoppedTransformers} Transformers sidecar(s))` : \"\"}; models remain installed.`\n\t\t\t\t\t: \"No pi-managed server running (a system server, if any, is not pi's to stop).\",\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\tif (action === \"add\") {\n\t\t\tconst rawRef = rest.join(\" \");\n\t\t\tif (!rawRef) {\n\t\t\t\thost.showStatus(\n\t\t\t\t\t\"Usage: /models add <ollama-tag | hf.co/org/repo[:quant] | curated HF full-base ref | huggingface URL | pasted install command>\",\n\t\t\t\t);\n\t\t\t\thost.showStatus(\"Or start from a validated suggestion: /models suggest\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst source = normalizeModelSource(rawRef);\n\t\t\tif (source.type === \"rejected\") {\n\t\t\t\thost.showStatus(`Not added: ${source.reason}`);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (source.type === \"api\") {\n\t\t\t\thost.showStatus(\n\t\t\t\t\t`${source.ref} is an API model — nothing to install. Configure auth for the provider, then probe it with /fitness ${source.ref}.`,\n\t\t\t\t);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (source.type === \"transformers\") {\n\t\t\t\tawait addTransformersModel(host, source.modelId);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tawait addLocalModel(host, source.pullRef);\n\t\t\treturn;\n\t\t}\n\n\t\tif (action === \"remove\") {\n\t\t\tconst ref = rest[0];\n\t\t\tconst confirmed = rest[1] === \"confirm\";\n\t\t\tif (!ref) {\n\t\t\t\thost.showStatus(\"Usage: /models remove <ref> confirm\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst source = normalizeModelSource(ref);\n\t\t\tif (source.type === \"transformers\") {\n\t\t\t\tawait removeTransformersModel(host, source.modelId, confirmed);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tawait removeLocalModel(host, ref, confirmed);\n\t\t\treturn;\n\t\t}\n\n\t\tawait listLocalModels(host);\n\t} catch (error) {\n\t\thost.showError(error instanceof Error ? error.message : String(error));\n\t}\n}\n\nexport async function ensureLocalServer(host: LocalModelHost): Promise<boolean> {\n\tconst status = await host.localRuntime.detect();\n\tif (status.serverUp) return true;\n\tif (!status.binaryPath) {\n\t\tfor (const line of host.localRuntime.installGuide()) host.showStatus(line);\n\t\treturn false;\n\t}\n\thost.showStatus(\n\t\t`Starting local model server (${status.binarySource} binary, owned storage: ${status.ownedModelsDir})…`,\n\t);\n\tconst started = await host.localRuntime.start();\n\tif (!started.started) {\n\t\thost.showStatus(`Could not start the local server: ${started.reason}`);\n\t\treturn false;\n\t}\n\treturn true;\n}\n\nexport async function listLocalModels(host: LocalModelHost): Promise<void> {\n\tconst status = await host.localRuntime.detect();\n\tconst models = status.serverUp ? await host.localRuntime.list() : [];\n\tconst ollamaLines = status.serverUp\n\t\t? [\n\t\t\t\t`Ollama models (${status.managedByPi ? `pi-managed server, storage: ${status.ownedModelsDir}` : \"system server — storage owned by the system daemon\"}):`,\n\t\t\t\t...(models.length === 0\n\t\t\t\t\t? [\" (none installed — /models add <ref>, or /models suggest for a validated roster)\"]\n\t\t\t\t\t: []),\n\t\t\t]\n\t\t: [\n\t\t\t\t\"Ollama models:\",\n\t\t\t\t...(status.binaryPath\n\t\t\t\t\t? [\n\t\t\t\t\t\t\t` server not running (binary: ${status.binarySource}). /models add starts it on demand; /fitness probes registered models.`,\n\t\t\t\t\t\t]\n\t\t\t\t\t: host.localRuntime.installGuide().map((line) => ` ${line}`)),\n\t\t\t];\n\tconst fitness = FitnessStore.forAgentDir(getAgentDir()).getForHost();\n\tconst transformersModels = host.session.modelRegistry\n\t\t.getAll()\n\t\t.filter((model) => model.provider === HF_TRANSFORMERS_PROVIDER);\n\tconst transformersLines = await Promise.all(\n\t\ttransformersModels.map(async (model) => {\n\t\t\tconst serverUrl = model.baseUrl.replace(/\\/v1\\/?$/, \"\");\n\t\t\tconst runtime = host.getTransformersRuntime(model.id, serverUrl);\n\t\t\tconst runtimeStatus = await runtime.detect();\n\t\t\tconst report = fitness.find((entry) => entry.model === `${HF_TRANSFORMERS_PROVIDER}/${model.id}`);\n\t\t\tconst readiness = runtimeStatus.serverUp\n\t\t\t\t? \"server running\"\n\t\t\t\t: runtimeStatus.runtimeInstalled\n\t\t\t\t\t? \"runtime installed\"\n\t\t\t\t\t: \"runtime missing\";\n\t\t\tconst probe = report\n\t\t\t\t? `probed ${report.at.slice(0, 10)}: digest ${report.report.digest?.succeeded ?? \"?\"}/${report.report.digest?.total ?? \"?\"}, tool-calls ${report.report.toolCall.succeeded}/${report.report.toolCall.total}${report.report.tokensPerSecond ? `, ~${report.report.tokensPerSecond} tok/s` : \"\"}`\n\t\t\t\t: `unprobed — run /fitness ${HF_TRANSFORMERS_PROVIDER}/${model.id}`;\n\t\t\treturn ` - ${model.id} (${readiness}, cache: ${runtimeStatus.cacheDir}) · ${probe}`;\n\t\t}),\n\t);\n\tconst lines = [\n\t\t...ollamaLines,\n\t\t...models.map((model) => {\n\t\t\tconst report = fitness.find((entry) => entry.model === `ollama/${model.name}`);\n\t\t\tconst gb = (model.sizeBytes / 1e9).toFixed(2);\n\t\t\tconst probe = report\n\t\t\t\t? `probed ${report.at.slice(0, 10)}: digest ${report.report.digest?.succeeded ?? \"?\"}/${report.report.digest?.total ?? \"?\"}, tool-calls ${report.report.toolCall.succeeded}/${report.report.toolCall.total}${report.report.tokensPerSecond ? `, ~${report.report.tokensPerSecond} tok/s` : \"\"}`\n\t\t\t\t: `unprobed — run /fitness ollama/${model.name}`;\n\t\t\treturn ` - ${model.name} (${gb} GB) · ${probe}`;\n\t\t}),\n\t\t...(transformersLines.length > 0 ? [\"Pi-managed Transformers models:\", ...transformersLines] : []),\n\t\t\"Commands: /models add <ref> · /models remove <ref> confirm · /models stop\",\n\t];\n\tfor (const line of lines) host.showStatus(line);\n}\n\nexport async function addLocalModel(host: LocalModelHost, pullRef: string, preselectRole?: FitnessRole): Promise<void> {\n\tif (!(await ensureLocalServer(host))) return;\n\thost.showStatus(`Pulling ${pullRef}… (weights land in the server's model storage)`);\n\tlet lastShown = 0;\n\tconst pulled = await host.localRuntime.pull(pullRef, (progress) => {\n\t\tconst now = Date.now();\n\t\tif (now - lastShown > 2000) {\n\t\t\tlastShown = now;\n\t\t\thost.showStatus(` ${pullRef}: ${progress}`);\n\t\t}\n\t});\n\tif (!pulled.ok) {\n\t\thost.showStatus(`Pull failed: ${pulled.error}`);\n\t\treturn;\n\t}\n\tconst registration = registerLocalModel({\n\t\tagentDir: getAgentDir(),\n\t\tref: pullRef,\n\t\tbaseUrl: host.localRuntime.baseUrl,\n\t});\n\tif (!registration.ok) {\n\t\thost.showStatus(`Pulled, but not auto-registered: ${registration.reason}`);\n\t\tif (registration.manualSnippet) {\n\t\t\thost.showStatus(`Add this to ${registration.modelsJsonPath} yourself:\\n${registration.manualSnippet}`);\n\t\t}\n\t\treturn;\n\t}\n\thost.session.modelRegistry.refresh();\n\thost.showStatus(`${pullRef} installed and registered as ollama/${pullRef}. Probing fitness…`);\n\tawait runFitnessAndAssign(host, `ollama/${pullRef}`, preselectRole);\n}\n\nexport async function addTransformersModel(\n\thost: LocalModelHost,\n\tmodelId: string,\n\tpreselectRole?: FitnessRole,\n): Promise<void> {\n\tconst runtime = host.getTransformersRuntime(modelId);\n\tlet status = await runtime.detect();\n\tif (!status.runtimeInstalled) {\n\t\thost.showStatus(`Installing isolated Transformers runtime for ${modelId} at ${status.venvDir}…`);\n\t\tconst installed = await runtime.installManaged((progress) => host.showStatus(` transformers: ${progress}`));\n\t\tif (!installed.ok) {\n\t\t\thost.showStatus(`Transformers runtime install failed: ${installed.error}`);\n\t\t\treturn;\n\t\t}\n\t\tstatus = await runtime.detect();\n\t}\n\tif (!status.runtimeInstalled) {\n\t\thost.showStatus(`Transformers runtime is still unavailable at ${status.venvDir}.`);\n\t\treturn;\n\t}\n\n\tconst downloaded = await runtime.downloadModel((progress) => host.showStatus(` ${modelId}: ${progress}`));\n\tif (!downloaded.ok) {\n\t\thost.showStatus(`Model download failed: ${downloaded.error}`);\n\t\treturn;\n\t}\n\n\tconst started = await runtime.start();\n\tif (!started.started && started.reason !== \"already_running\") {\n\t\thost.showStatus(`Could not start Transformers sidecar: ${started.reason}`);\n\t\treturn;\n\t}\n\n\tconst registration = registerTransformersModel({\n\t\tagentDir: getAgentDir(),\n\t\tmodelId,\n\t\tbaseUrl: runtime.baseUrl,\n\t});\n\tif (!registration.ok) {\n\t\thost.showStatus(`Installed, but not auto-registered: ${registration.reason}`);\n\t\tif (registration.manualSnippet) {\n\t\t\thost.showStatus(`Add this to ${registration.modelsJsonPath} yourself:\\n${registration.manualSnippet}`);\n\t\t}\n\t\treturn;\n\t}\n\thost.session.modelRegistry.refresh();\n\thost.showStatus(\n\t\t`${modelId} installed in pi-managed Transformers and registered as ${HF_TRANSFORMERS_PROVIDER}/${modelId}. Probing fitness…`,\n\t);\n\tawait runFitnessAndAssign(host, `${HF_TRANSFORMERS_PROVIDER}/${modelId}`, preselectRole);\n}\n\nexport async function removeLocalModel(host: LocalModelHost, ref: string, confirmed: boolean): Promise<void> {\n\tconst status = await host.localRuntime.detect();\n\tif (!status.serverUp) {\n\t\thost.showStatus(\"Local server not running — start it (any /models action) before removing.\");\n\t\treturn;\n\t}\n\tconst models = await host.localRuntime.list();\n\tconst target = models.find((model) => matchesInstalledLocalModel(ref, model.name));\n\tif (!target) {\n\t\thost.showStatus(\n\t\t\t`${ref} is not installed. Installed: ${models.map((model) => model.name).join(\", \") || \"(none)\"}`,\n\t\t);\n\t\treturn;\n\t}\n\tif (!confirmed) {\n\t\t// EXPLICIT USER ACTION ONLY: full disclosure, then require the confirm token.\n\t\tconst gb = (target.sizeBytes / 1e9).toFixed(2);\n\t\thost.showStatus(\n\t\t\t[\n\t\t\t\t`Removing ${ref} will delete:`,\n\t\t\t\t` - model weights (${gb} GB) from ${status.managedByPi ? status.ownedModelsDir : \"the system server's storage\"}`,\n\t\t\t\t` - the ollama/${ref} entry in models.json`,\n\t\t\t\t` - its cached fitness report for this host`,\n\t\t\t\t`Run: /models remove ${ref} confirm`,\n\t\t\t].join(\"\\n\"),\n\t\t);\n\t\treturn;\n\t}\n\tconst removed = await host.localRuntime.remove(ref);\n\tif (!removed.ok) {\n\t\thost.showStatus(`Remove failed: ${removed.error}`);\n\t\treturn;\n\t}\n\tunregisterLocalModel({ agentDir: getAgentDir(), ref });\n\tFitnessStore.forAgentDir(getAgentDir()).remove(`ollama/${ref}`);\n\thost.session.modelRegistry.refresh();\n\thost.showStatus(`${ref} removed: weights deleted, registration and fitness report dropped.`);\n}\n\nasync function removeTransformersModel(host: LocalModelHost, modelId: string, confirmed: boolean): Promise<void> {\n\tconst runtime = host.getTransformersRuntime(modelId);\n\tconst status = await runtime.detect();\n\tif (!confirmed) {\n\t\thost.showStatus(\n\t\t\t[\n\t\t\t\t`Removing ${modelId} will delete:`,\n\t\t\t\t` - the ${HF_TRANSFORMERS_PROVIDER}/${modelId} entry in models.json`,\n\t\t\t\t` - its cached fitness report for this host`,\n\t\t\t\t`It will stop this session's Transformers sidecar if running. Cached weights remain under ${status.cacheDir}.`,\n\t\t\t\t`Run: /models remove hf.co/${modelId} confirm`,\n\t\t\t].join(\"\\n\"),\n\t\t);\n\t\treturn;\n\t}\n\truntime.stop();\n\tconst registration = unregisterTransformersModel({ agentDir: getAgentDir(), modelId });\n\tif (!registration.ok) {\n\t\thost.showStatus(`Remove failed: ${registration.reason}`);\n\t\treturn;\n\t}\n\tFitnessStore.forAgentDir(getAgentDir()).remove(`${HF_TRANSFORMERS_PROVIDER}/${modelId}`);\n\thost.session.modelRegistry.refresh();\n\thost.showStatus(\n\t\t`${modelId} registration and fitness report dropped; cached weights remain under ${status.cacheDir}.`,\n\t);\n}\n\n/** /fitness with no args: pick a model from the configured registry, probe it, assign a role. */\n/** Pick a validated suggestion → install it → probe on this host → land its shaped role. */\nexport function showModelSuggestionSelector(host: LocalModelHost): void {\n\thost.showSelector((done) => {\n\t\tconst selector = new ModelSuggestionSelectorComponent(\n\t\t\tDEFAULT_MODEL_SUGGESTIONS,\n\t\t\tasync (suggestion) => {\n\t\t\t\tdone();\n\t\t\t\t// The shaped role rides along so the post-probe selector lands on it pre-selected;\n\t\t\t\t// non-tool-callers carry curator/judge/none, never executor, so this can't footgun.\n\t\t\t\tconst source = normalizeModelSource(suggestion.pullRef);\n\t\t\t\tif (source.type === \"transformers\") {\n\t\t\t\t\tawait addTransformersModel(host, source.modelId, suggestion.assignRole);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (source.type === \"local\") {\n\t\t\t\t\tawait addLocalModel(host, source.pullRef, suggestion.assignRole);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\thost.showStatus(\n\t\t\t\t\t`Suggestion ${suggestion.name} is not installable: ${source.type === \"rejected\" ? source.reason : source.ref}`,\n\t\t\t\t);\n\t\t\t},\n\t\t\t() => {\n\t\t\t\tdone();\n\t\t\t\thost.ui.requestRender();\n\t\t\t},\n\t\t);\n\t\treturn { component: selector, focus: selector };\n\t});\n}\n\nexport function showFitnessModelSelector(host: LocalModelHost): void {\n\thost.showSelector((done) => {\n\t\tconst selector = new ModelSelectorComponent(\n\t\t\thost.ui,\n\t\t\thost.session.model,\n\t\t\thost.settingsManager,\n\t\t\thost.session.modelRegistry,\n\t\t\thost.session.scopedModels,\n\t\t\tasync (model) => {\n\t\t\t\tdone();\n\t\t\t\tawait runFitnessAndAssign(host, `${model.provider}/${model.id}`);\n\t\t\t},\n\t\t\t() => {\n\t\t\t\tdone();\n\t\t\t\thost.ui.requestRender();\n\t\t\t},\n\t\t);\n\t\treturn { component: selector, focus: selector };\n\t});\n}\n\n/** Resolve the routed model's supported thinking levels for a fitness-assignment flow, with a safe fallback. */\nfunction getModelThinkingLevels(modelRegistry: ModelRegistry | undefined, modelRef: string): ThinkingLevel[] {\n\tif (!modelRegistry) {\n\t\treturn [...MODEL_ROUTER_THINKING_FALLBACK_LEVELS];\n\t}\n\tconst resolved = resolveCliModel({ cliModel: modelRef, modelRegistry });\n\tif (!resolved.model) {\n\t\treturn [...MODEL_ROUTER_THINKING_FALLBACK_LEVELS];\n\t}\n\treturn getSupportedThinkingLevels(resolved.model);\n}\n\nfunction getModelRouterThinkingField(role: FitnessRole): ModelRouterThinkingField | undefined {\n\tif (role === \"router-cheap\") {\n\t\treturn \"cheapThinking\";\n\t}\n\tif (role === \"router-medium\") {\n\t\treturn \"mediumThinking\";\n\t}\n\tif (role === \"router-expensive\") {\n\t\treturn \"expensiveThinking\";\n\t}\n\tif (role === \"executor\") {\n\t\treturn \"executorThinking\";\n\t}\n\tif (role === \"judge\") {\n\t\treturn \"judgeThinking\";\n\t}\n\treturn undefined;\n}\n\nfunction promptForModelRouterThinking(host: RunFitnessHost, modelRef: string, role: FitnessRole): void {\n\tconst thinkingField = getModelRouterThinkingField(role);\n\tif (!thinkingField) {\n\t\treturn;\n\t}\n\n\tconst modelRegistry = host.session.modelRegistry;\n\tconst availableLevels = getModelThinkingLevels(modelRegistry, modelRef);\n\tconst settings = host.settingsManager.getModelRouterSettings();\n\tconst configuredThinking = settings[thinkingField];\n\tconst currentThinking =\n\t\tconfiguredThinking && availableLevels.includes(configuredThinking)\n\t\t\t? configuredThinking\n\t\t\t: MODEL_ROUTER_THINKING_INHERIT_VALUE;\n\n\thost.showSelector((done) => {\n\t\tconst selector = new ModelRouterThinkingSelectorComponent(\n\t\t\tcurrentThinking,\n\t\t\tavailableLevels,\n\t\t\t(level) => {\n\t\t\t\tdone();\n\t\t\t\thost.settingsManager.setModelRouterSettings({\n\t\t\t\t\t...settings,\n\t\t\t\t\t[thinkingField]: level === MODEL_ROUTER_THINKING_INHERIT_VALUE ? undefined : level,\n\t\t\t\t});\n\t\t\t},\n\t\t\t() => {\n\t\t\t\tdone();\n\t\t\t\thost.ui.requestRender();\n\t\t\t},\n\t\t);\n\t\treturn { component: selector, focus: selector };\n\t});\n}\n\n/** Probe a model's fitness, show the report, then offer one-step role assignment. When the model\n * came from a validated suggestion, `preselectRole` lands its shaped role already highlighted. */\nexport async function runFitnessAndAssign(\n\thost: RunFitnessHost,\n\tmodelRef: string,\n\tpreselectRole?: FitnessRole,\n): Promise<void> {\n\thost.showStatus(`Model fitness probe running on ${modelRef}… (6 surfaces; local models may take a few minutes)`);\n\ttry {\n\t\tconst outcome = await host.session.runModelFitness({ model: modelRef });\n\t\tif (!outcome.started) {\n\t\t\thost.showStatus(`Model fitness skipped: ${outcome.skipReason}`);\n\t\t\treturn;\n\t\t}\n\t\thost.chatContainer.addChild(new Spacer(1));\n\t\thost.chatContainer.addChild(new Text(formatModelFitnessReport(outcome.model, outcome.report), 1, 0));\n\t\thost.ui.requestRender();\n\t\t// Validate-before-load: zero successes on every probed surface means the model cannot\n\t\t// drive any of the harness's subagent contracts on this host — refuse adoption instead\n\t\t// of landing a role selector the user might reflexively confirm (this is the reported\n\t\t// bug: a 0/3-everywhere model still got set as judge model and saved to Model Router).\n\t\tif (isProbeAllFailed(outcome.report)) {\n\t\t\thost.showStatus(\n\t\t\t\t`${outcome.model} failed the fitness probe on all surfaces — not configured. Use /model to set it manually if you accept the risk.`,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\t\thost.showSelector((done) => {\n\t\t\tconst selector = new FitnessRoleSelectorComponent(\n\t\t\t\toutcome.model,\n\t\t\t\t(role) => {\n\t\t\t\t\tdone();\n\t\t\t\t\tif (role === \"scout\") {\n\t\t\t\t\t\tconst verdict = evaluateSurfaceFitness(\"scout_auto\", outcome.report);\n\t\t\t\t\t\tif (!verdict.fit) {\n\t\t\t\t\t\t\tconst reason = verdict.reason === \"lane_failed\" ? `failed ${verdict.lane}` : \"was not probed\";\n\t\t\t\t\t\t\thost.showStatus(\n\t\t\t\t\t\t\t\t`${outcome.model} not assigned as scout: ${reason} on the scout_auto fitness exam. Use the docs/scout.md Modelfile recipe, then rerun /fitness.`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tassignFitnessRole(host, outcome.model, role);\n\t\t\t\t\tpromptForModelRouterThinking(host, outcome.model, role);\n\t\t\t\t},\n\t\t\t\t() => {\n\t\t\t\t\tdone();\n\t\t\t\t\thost.ui.requestRender();\n\t\t\t\t},\n\t\t\t\tpreselectRole,\n\t\t\t);\n\t\t\treturn { component: selector, focus: selector };\n\t\t});\n\t} catch (error) {\n\t\thost.showError(error instanceof Error ? error.message : String(error));\n\t}\n}\n\n/** Persist a role assignment from the post-probe selector into the matching settings. */\nexport function assignFitnessRole(host: AssignRoleHost, modelRef: string, role: FitnessRole): void {\n\tif (role === \"none\") {\n\t\thost.showStatus(`Fitness result for ${modelRef} saved. Assign a role later from /settings.`);\n\t\treturn;\n\t}\n\tif (role === \"curator\") {\n\t\tconst current = host.settingsManager.getContextCurationSettings();\n\t\thost.settingsManager.setContextCurationSettings({ ...current, enabled: true, model: modelRef });\n\t\thost.showStatus(`Context curation enabled with ${modelRef} as the curator.`);\n\t\treturn;\n\t}\n\tif (role === \"executor\") {\n\t\tconst router = host.settingsManager.getModelRouterSettings();\n\t\thost.settingsManager.setModelRouterSettings({ ...router, executorModel: modelRef });\n\t\tconst hint = router.enabled ? \"\" : \" Model router is currently disabled — enable it in /settings → Model Router.\";\n\t\thost.showStatus(`${modelRef} set as the toolkit executor (direct Level-0 hits route to it).${hint}`);\n\t\treturn;\n\t}\n\tif (role === \"scout\") {\n\t\thost.settingsManager.setScoutSettings({ enabled: true, model: modelRef });\n\t\thost.showStatus(`${modelRef} set as the repository scout (context_scout enabled).`);\n\t\treturn;\n\t}\n\tconst router = host.settingsManager.getModelRouterSettings();\n\tconst field =\n\t\trole === \"router-cheap\"\n\t\t\t? \"cheapModel\"\n\t\t\t: role === \"router-medium\"\n\t\t\t\t? \"mediumModel\"\n\t\t\t\t: role === \"router-expensive\"\n\t\t\t\t\t? \"expensiveModel\"\n\t\t\t\t\t: role === \"judge\"\n\t\t\t\t\t\t? \"judgeModel\"\n\t\t\t\t\t\t: \"learningModel\";\n\thost.settingsManager.setModelRouterSettings({ ...router, [field]: modelRef });\n\tconst hint = router.enabled ? \"\" : \" Model router is currently disabled — enable it in /settings → Model Router.\";\n\thost.showStatus(`${modelRef} set as ${role.replace(\"router-\", \"router \")} model.${hint}`);\n}\n"]}
@@ -17,7 +17,7 @@ import { resolveCliModel } from "../../core/model-resolver.js";
17
17
  import { evaluateSurfaceFitness } from "../../core/model-router/fitness-gate.js";
18
18
  import { DEFAULT_MODEL_SUGGESTIONS } from "../../core/models/default-model-suggestions.js";
19
19
  import { FitnessStore } from "../../core/models/fitness-store.js";
20
- import { registerLocalModel, unregisterLocalModel } from "../../core/models/local-registration.js";
20
+ import { HF_TRANSFORMERS_PROVIDER, registerLocalModel, registerTransformersModel, unregisterLocalModel, unregisterTransformersModel, } from "../../core/models/local-registration.js";
21
21
  import { matchesInstalledLocalModel, normalizeModelSource } from "../../core/models/model-ref.js";
22
22
  import { formatModelFitnessReport, isProbeAllFailed } from "../../core/research/model-fitness.js";
23
23
  import { DynamicBorder } from "./components/dynamic-border.js";
@@ -93,15 +93,24 @@ export async function handleModelsCommand(host, argsText) {
93
93
  }
94
94
  if (action === "stop") {
95
95
  const stopped = host.localRuntime.stop();
96
- host.showStatus(stopped.stopped
97
- ? "Pi-managed local model server stopped (models remain installed)."
96
+ let stoppedTransformers = 0;
97
+ for (const model of host.session.modelRegistry
98
+ .getAll()
99
+ .filter((entry) => entry.provider === HF_TRANSFORMERS_PROVIDER)) {
100
+ const serverUrl = model.baseUrl.replace(/\/v1\/?$/, "");
101
+ if (host.getTransformersRuntime(model.id, serverUrl).stop().stopped)
102
+ stoppedTransformers++;
103
+ }
104
+ const stoppedAny = stopped.stopped || stoppedTransformers > 0;
105
+ host.showStatus(stoppedAny
106
+ ? `Pi-managed local model server stopped${stoppedTransformers > 0 ? ` (${stoppedTransformers} Transformers sidecar(s))` : ""}; models remain installed.`
98
107
  : "No pi-managed server running (a system server, if any, is not pi's to stop).");
99
108
  return;
100
109
  }
101
110
  if (action === "add") {
102
111
  const rawRef = rest.join(" ");
103
112
  if (!rawRef) {
104
- host.showStatus("Usage: /models add <ollama-tag | hf.co/org/repo[:quant] | huggingface URL | pasted install command>");
113
+ host.showStatus("Usage: /models add <ollama-tag | hf.co/org/repo[:quant] | curated HF full-base ref | huggingface URL | pasted install command>");
105
114
  host.showStatus("Or start from a validated suggestion: /models suggest");
106
115
  return;
107
116
  }
@@ -114,6 +123,10 @@ export async function handleModelsCommand(host, argsText) {
114
123
  host.showStatus(`${source.ref} is an API model — nothing to install. Configure auth for the provider, then probe it with /fitness ${source.ref}.`);
115
124
  return;
116
125
  }
126
+ if (source.type === "transformers") {
127
+ await addTransformersModel(host, source.modelId);
128
+ return;
129
+ }
117
130
  await addLocalModel(host, source.pullRef);
118
131
  return;
119
132
  }
@@ -124,6 +137,11 @@ export async function handleModelsCommand(host, argsText) {
124
137
  host.showStatus("Usage: /models remove <ref> confirm");
125
138
  return;
126
139
  }
140
+ const source = normalizeModelSource(ref);
141
+ if (source.type === "transformers") {
142
+ await removeTransformersModel(host, source.modelId, confirmed);
143
+ return;
144
+ }
127
145
  await removeLocalModel(host, ref, confirmed);
128
146
  return;
129
147
  }
@@ -152,22 +170,43 @@ export async function ensureLocalServer(host) {
152
170
  }
153
171
  export async function listLocalModels(host) {
154
172
  const status = await host.localRuntime.detect();
155
- if (!status.serverUp) {
156
- if (!status.binaryPath) {
157
- for (const line of host.localRuntime.installGuide())
158
- host.showStatus(line);
159
- return;
160
- }
161
- host.showStatus(`Local server not running (binary: ${status.binarySource}). /models add starts it on demand; /fitness probes registered models.`);
162
- return;
163
- }
164
- const models = await host.localRuntime.list();
173
+ const models = status.serverUp ? await host.localRuntime.list() : [];
174
+ const ollamaLines = status.serverUp
175
+ ? [
176
+ `Ollama models (${status.managedByPi ? `pi-managed server, storage: ${status.ownedModelsDir}` : "system server — storage owned by the system daemon"}):`,
177
+ ...(models.length === 0
178
+ ? [" (none installed — /models add <ref>, or /models suggest for a validated roster)"]
179
+ : []),
180
+ ]
181
+ : [
182
+ "Ollama models:",
183
+ ...(status.binaryPath
184
+ ? [
185
+ ` server not running (binary: ${status.binarySource}). /models add starts it on demand; /fitness probes registered models.`,
186
+ ]
187
+ : host.localRuntime.installGuide().map((line) => ` ${line}`)),
188
+ ];
165
189
  const fitness = FitnessStore.forAgentDir(getAgentDir()).getForHost();
190
+ const transformersModels = host.session.modelRegistry
191
+ .getAll()
192
+ .filter((model) => model.provider === HF_TRANSFORMERS_PROVIDER);
193
+ const transformersLines = await Promise.all(transformersModels.map(async (model) => {
194
+ const serverUrl = model.baseUrl.replace(/\/v1\/?$/, "");
195
+ const runtime = host.getTransformersRuntime(model.id, serverUrl);
196
+ const runtimeStatus = await runtime.detect();
197
+ const report = fitness.find((entry) => entry.model === `${HF_TRANSFORMERS_PROVIDER}/${model.id}`);
198
+ const readiness = runtimeStatus.serverUp
199
+ ? "server running"
200
+ : runtimeStatus.runtimeInstalled
201
+ ? "runtime installed"
202
+ : "runtime missing";
203
+ const probe = report
204
+ ? `probed ${report.at.slice(0, 10)}: digest ${report.report.digest?.succeeded ?? "?"}/${report.report.digest?.total ?? "?"}, tool-calls ${report.report.toolCall.succeeded}/${report.report.toolCall.total}${report.report.tokensPerSecond ? `, ~${report.report.tokensPerSecond} tok/s` : ""}`
205
+ : `unprobed — run /fitness ${HF_TRANSFORMERS_PROVIDER}/${model.id}`;
206
+ return ` - ${model.id} (${readiness}, cache: ${runtimeStatus.cacheDir}) · ${probe}`;
207
+ }));
166
208
  const lines = [
167
- `Local models (${status.managedByPi ? `pi-managed server, storage: ${status.ownedModelsDir}` : "system server — storage owned by the system daemon"}):`,
168
- ...(models.length === 0
169
- ? [" (none installed — /models add <ref>, or /models suggest for a validated roster)"]
170
- : []),
209
+ ...ollamaLines,
171
210
  ...models.map((model) => {
172
211
  const report = fitness.find((entry) => entry.model === `ollama/${model.name}`);
173
212
  const gb = (model.sizeBytes / 1e9).toFixed(2);
@@ -176,6 +215,7 @@ export async function listLocalModels(host) {
176
215
  : `unprobed — run /fitness ollama/${model.name}`;
177
216
  return ` - ${model.name} (${gb} GB) · ${probe}`;
178
217
  }),
218
+ ...(transformersLines.length > 0 ? ["Pi-managed Transformers models:", ...transformersLines] : []),
179
219
  "Commands: /models add <ref> · /models remove <ref> confirm · /models stop",
180
220
  ];
181
221
  for (const line of lines)
@@ -213,6 +253,48 @@ export async function addLocalModel(host, pullRef, preselectRole) {
213
253
  host.showStatus(`${pullRef} installed and registered as ollama/${pullRef}. Probing fitness…`);
214
254
  await runFitnessAndAssign(host, `ollama/${pullRef}`, preselectRole);
215
255
  }
256
+ export async function addTransformersModel(host, modelId, preselectRole) {
257
+ const runtime = host.getTransformersRuntime(modelId);
258
+ let status = await runtime.detect();
259
+ if (!status.runtimeInstalled) {
260
+ host.showStatus(`Installing isolated Transformers runtime for ${modelId} at ${status.venvDir}…`);
261
+ const installed = await runtime.installManaged((progress) => host.showStatus(` transformers: ${progress}`));
262
+ if (!installed.ok) {
263
+ host.showStatus(`Transformers runtime install failed: ${installed.error}`);
264
+ return;
265
+ }
266
+ status = await runtime.detect();
267
+ }
268
+ if (!status.runtimeInstalled) {
269
+ host.showStatus(`Transformers runtime is still unavailable at ${status.venvDir}.`);
270
+ return;
271
+ }
272
+ const downloaded = await runtime.downloadModel((progress) => host.showStatus(` ${modelId}: ${progress}`));
273
+ if (!downloaded.ok) {
274
+ host.showStatus(`Model download failed: ${downloaded.error}`);
275
+ return;
276
+ }
277
+ const started = await runtime.start();
278
+ if (!started.started && started.reason !== "already_running") {
279
+ host.showStatus(`Could not start Transformers sidecar: ${started.reason}`);
280
+ return;
281
+ }
282
+ const registration = registerTransformersModel({
283
+ agentDir: getAgentDir(),
284
+ modelId,
285
+ baseUrl: runtime.baseUrl,
286
+ });
287
+ if (!registration.ok) {
288
+ host.showStatus(`Installed, but not auto-registered: ${registration.reason}`);
289
+ if (registration.manualSnippet) {
290
+ host.showStatus(`Add this to ${registration.modelsJsonPath} yourself:\n${registration.manualSnippet}`);
291
+ }
292
+ return;
293
+ }
294
+ host.session.modelRegistry.refresh();
295
+ host.showStatus(`${modelId} installed in pi-managed Transformers and registered as ${HF_TRANSFORMERS_PROVIDER}/${modelId}. Probing fitness…`);
296
+ await runFitnessAndAssign(host, `${HF_TRANSFORMERS_PROVIDER}/${modelId}`, preselectRole);
297
+ }
216
298
  export async function removeLocalModel(host, ref, confirmed) {
217
299
  const status = await host.localRuntime.detect();
218
300
  if (!status.serverUp) {
@@ -247,6 +329,29 @@ export async function removeLocalModel(host, ref, confirmed) {
247
329
  host.session.modelRegistry.refresh();
248
330
  host.showStatus(`${ref} removed: weights deleted, registration and fitness report dropped.`);
249
331
  }
332
+ async function removeTransformersModel(host, modelId, confirmed) {
333
+ const runtime = host.getTransformersRuntime(modelId);
334
+ const status = await runtime.detect();
335
+ if (!confirmed) {
336
+ host.showStatus([
337
+ `Removing ${modelId} will delete:`,
338
+ ` - the ${HF_TRANSFORMERS_PROVIDER}/${modelId} entry in models.json`,
339
+ ` - its cached fitness report for this host`,
340
+ `It will stop this session's Transformers sidecar if running. Cached weights remain under ${status.cacheDir}.`,
341
+ `Run: /models remove hf.co/${modelId} confirm`,
342
+ ].join("\n"));
343
+ return;
344
+ }
345
+ runtime.stop();
346
+ const registration = unregisterTransformersModel({ agentDir: getAgentDir(), modelId });
347
+ if (!registration.ok) {
348
+ host.showStatus(`Remove failed: ${registration.reason}`);
349
+ return;
350
+ }
351
+ FitnessStore.forAgentDir(getAgentDir()).remove(`${HF_TRANSFORMERS_PROVIDER}/${modelId}`);
352
+ host.session.modelRegistry.refresh();
353
+ host.showStatus(`${modelId} registration and fitness report dropped; cached weights remain under ${status.cacheDir}.`);
354
+ }
250
355
  /** /fitness with no args: pick a model from the configured registry, probe it, assign a role. */
251
356
  /** Pick a validated suggestion → install it → probe on this host → land its shaped role. */
252
357
  export function showModelSuggestionSelector(host) {
@@ -255,7 +360,16 @@ export function showModelSuggestionSelector(host) {
255
360
  done();
256
361
  // The shaped role rides along so the post-probe selector lands on it pre-selected;
257
362
  // non-tool-callers carry curator/judge/none, never executor, so this can't footgun.
258
- await addLocalModel(host, suggestion.pullRef, suggestion.assignRole);
363
+ const source = normalizeModelSource(suggestion.pullRef);
364
+ if (source.type === "transformers") {
365
+ await addTransformersModel(host, source.modelId, suggestion.assignRole);
366
+ return;
367
+ }
368
+ if (source.type === "local") {
369
+ await addLocalModel(host, source.pullRef, suggestion.assignRole);
370
+ return;
371
+ }
372
+ host.showStatus(`Suggestion ${suggestion.name} is not installable: ${source.type === "rejected" ? source.reason : source.ref}`);
259
373
  }, () => {
260
374
  done();
261
375
  host.ui.requestRender();
@@ -1 +1 @@
1
- {"version":3,"file":"local-model-commands.js","sourceRoot":"","sources":["../../../src/modes/interactive/local-model-commands.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `/models` local-model lifecycle and `/fitness` probe/role-assignment flows\n * extracted from interactive-mode.\n *\n * `/models` is a USER-invoked local-model manager (list/add/remove/stop, never a\n * model-invokable tool); the fitness helpers probe a model on the current host\n * and land a shaped role. The server/selector flows share a `LocalModelHost`\n * seam, while `runFitnessAndAssign`/`assignFitnessRole` take narrow host shapes\n * matching their prototype-driven behaviour tests (fitness-probe-gate,\n * fitness-role-assignment), which keep exercising interactive-mode's thin\n * wrappers unchanged.\n */\n\nimport type { ThinkingLevel } from \"@caupulican/pi-agent-core\";\nimport { getSupportedThinkingLevels } from \"@caupulican/pi-ai\";\nimport {\n\ttype Component,\n\tContainer,\n\ttype SelectItem,\n\tSelectList,\n\ttype SelectListLayoutOptions,\n\tSpacer,\n\tText,\n\ttype TUI,\n} from \"@caupulican/pi-tui\";\nimport { getAgentDir } from \"../../config.ts\";\nimport type { AgentSession } from \"../../core/agent-session.ts\";\nimport type { ModelRegistry } from \"../../core/model-registry.ts\";\nimport { resolveCliModel } from \"../../core/model-resolver.ts\";\nimport { evaluateSurfaceFitness } from \"../../core/model-router/fitness-gate.ts\";\nimport { DEFAULT_MODEL_SUGGESTIONS } from \"../../core/models/default-model-suggestions.ts\";\nimport { FitnessStore } from \"../../core/models/fitness-store.ts\";\nimport { registerLocalModel, unregisterLocalModel } from \"../../core/models/local-registration.ts\";\nimport type { OllamaRuntime } from \"../../core/models/local-runtime.ts\";\nimport { matchesInstalledLocalModel, normalizeModelSource } from \"../../core/models/model-ref.ts\";\nimport { formatModelFitnessReport, isProbeAllFailed } from \"../../core/research/model-fitness.ts\";\nimport type { SettingsManager } from \"../../core/settings-manager.ts\";\nimport { DynamicBorder } from \"./components/dynamic-border.ts\";\nimport { type FitnessRole, FitnessRoleSelectorComponent } from \"./components/fitness-role-selector.ts\";\nimport { ModelSelectorComponent } from \"./components/model-selector.ts\";\nimport { ModelSuggestionSelectorComponent } from \"./components/model-suggestion-selector.ts\";\nimport { getSelectListTheme } from \"./theme/theme.ts\";\n\ntype SelectorFactory = (done: () => void) => { component: Component; focus: Component };\n\nconst MODEL_ROUTER_THINKING_SELECT_LIST_LAYOUT: SelectListLayoutOptions = {\n\tminPrimaryColumnWidth: 12,\n\tmaxPrimaryColumnWidth: 32,\n};\n\nconst MODEL_ROUTER_THINKING_INHERIT_VALUE = \"__inherit_model_router_thinking__\";\nconst MODEL_ROUTER_THINKING_INHERIT_LABEL = \"(inherit)\";\n\nconst THINKING_LEVEL_DESCRIPTIONS: Record<ThinkingLevel, string> = {\n\toff: \"No reasoning\",\n\tminimal: \"Very brief reasoning (~1k tokens)\",\n\tlow: \"Light reasoning (~2k tokens)\",\n\tmedium: \"Moderate reasoning (~8k tokens)\",\n\thigh: \"Deep reasoning (~16k tokens)\",\n\txhigh: \"Maximum reasoning (~32k tokens)\",\n};\n\nconst MODEL_ROUTER_THINKING_FALLBACK_LEVELS: readonly ThinkingLevel[] = [\n\t\"off\",\n\t\"minimal\",\n\t\"low\",\n\t\"medium\",\n\t\"high\",\n\t\"xhigh\",\n];\n\ntype RouterThinkingLevel = ThinkingLevel | typeof MODEL_ROUTER_THINKING_INHERIT_VALUE;\ntype ModelRouterThinkingField =\n\t| \"cheapThinking\"\n\t| \"mediumThinking\"\n\t| \"expensiveThinking\"\n\t| \"executorThinking\"\n\t| \"judgeThinking\";\n\n/** Narrow seam for persisting a probed model's role — matches the fitness-role test. */\nexport interface AssignRoleHost {\n\treadonly settingsManager: SettingsManager;\n\tshowStatus(message: string): void;\n}\n\n/** Seam for the fitness probe + role-selector flow — matches the fitness-probe-gate test. */\nexport interface RunFitnessHost {\n\treadonly session: Pick<AgentSession, \"runModelFitness\"> & { modelRegistry?: ModelRegistry };\n\treadonly settingsManager: SettingsManager;\n\treadonly chatContainer: Container;\n\treadonly ui: TUI;\n\tshowStatus(message: string): void;\n\tshowError(message: string): void;\n\tshowSelector(create: SelectorFactory): void;\n}\n\n/** Full seam for the `/models` server/selector flows. */\nexport interface LocalModelHost {\n\treadonly localRuntime: OllamaRuntime;\n\treadonly session: AgentSession;\n\treadonly settingsManager: SettingsManager;\n\treadonly ui: TUI;\n\treadonly chatContainer: Container;\n\tshowStatus(message: string): void;\n\tshowError(message: string): void;\n\tshowSelector(create: SelectorFactory): void;\n}\n\nclass ModelRouterThinkingSelectorComponent extends Container {\n\tprivate selectList: SelectList;\n\n\tconstructor(\n\t\tcurrentLevel: RouterThinkingLevel,\n\t\tavailableLevels: ThinkingLevel[],\n\t\tonSelect: (level: RouterThinkingLevel) => void,\n\t\tonCancel: () => void,\n\t) {\n\t\tsuper();\n\n\t\tconst thinkingOptions: SelectItem[] = [\n\t\t\t{\n\t\t\t\tvalue: MODEL_ROUTER_THINKING_INHERIT_VALUE,\n\t\t\t\tlabel: MODEL_ROUTER_THINKING_INHERIT_LABEL,\n\t\t\t\tdescription: \"Use current session default for this tier.\",\n\t\t\t},\n\t\t\t...availableLevels.map((level) => ({\n\t\t\t\tvalue: level,\n\t\t\t\tlabel: level,\n\t\t\t\tdescription: THINKING_LEVEL_DESCRIPTIONS[level],\n\t\t\t})),\n\t\t];\n\n\t\tthis.addChild(new DynamicBorder());\n\n\t\tthis.selectList = new SelectList(\n\t\t\tthinkingOptions,\n\t\t\tthinkingOptions.length,\n\t\t\tgetSelectListTheme(),\n\t\t\tMODEL_ROUTER_THINKING_SELECT_LIST_LAYOUT,\n\t\t);\n\n\t\tconst index = thinkingOptions.findIndex((item) => item.value === currentLevel);\n\t\tif (index !== -1) {\n\t\t\tthis.selectList.setSelectedIndex(index);\n\t\t}\n\n\t\tthis.selectList.onSelect = (item) => {\n\t\t\tonSelect(item.value as RouterThinkingLevel);\n\t\t};\n\t\tthis.selectList.onCancel = () => {\n\t\t\tonCancel();\n\t\t};\n\n\t\tthis.addChild(this.selectList);\n\t\tthis.addChild(new DynamicBorder());\n\t}\n}\n/**\n * /models — USER-invoked local model lifecycle (never a model-invokable tool):\n * list/add/remove/stop per local-model-lifecycle-design.md. Removal is explicit-only with\n * full disclosure; a pasted install command is parsed for its ref, never executed.\n */\nexport async function handleModelsCommand(host: LocalModelHost, argsText: string): Promise<void> {\n\tconst [action = \"list\", ...rest] = argsText.split(/\\s+/).filter(Boolean);\n\ttry {\n\t\tif (action === \"suggest\" || action === \"suggestions\") {\n\t\t\tshowModelSuggestionSelector(host);\n\t\t\treturn;\n\t\t}\n\t\tif (action === \"stop\") {\n\t\t\tconst stopped = host.localRuntime.stop();\n\t\t\thost.showStatus(\n\t\t\t\tstopped.stopped\n\t\t\t\t\t? \"Pi-managed local model server stopped (models remain installed).\"\n\t\t\t\t\t: \"No pi-managed server running (a system server, if any, is not pi's to stop).\",\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\tif (action === \"add\") {\n\t\t\tconst rawRef = rest.join(\" \");\n\t\t\tif (!rawRef) {\n\t\t\t\thost.showStatus(\n\t\t\t\t\t\"Usage: /models add <ollama-tag | hf.co/org/repo[:quant] | huggingface URL | pasted install command>\",\n\t\t\t\t);\n\t\t\t\thost.showStatus(\"Or start from a validated suggestion: /models suggest\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst source = normalizeModelSource(rawRef);\n\t\t\tif (source.type === \"rejected\") {\n\t\t\t\thost.showStatus(`Not added: ${source.reason}`);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (source.type === \"api\") {\n\t\t\t\thost.showStatus(\n\t\t\t\t\t`${source.ref} is an API model — nothing to install. Configure auth for the provider, then probe it with /fitness ${source.ref}.`,\n\t\t\t\t);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tawait addLocalModel(host, source.pullRef);\n\t\t\treturn;\n\t\t}\n\n\t\tif (action === \"remove\") {\n\t\t\tconst ref = rest[0];\n\t\t\tconst confirmed = rest[1] === \"confirm\";\n\t\t\tif (!ref) {\n\t\t\t\thost.showStatus(\"Usage: /models remove <ref> confirm\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tawait removeLocalModel(host, ref, confirmed);\n\t\t\treturn;\n\t\t}\n\n\t\tawait listLocalModels(host);\n\t} catch (error) {\n\t\thost.showError(error instanceof Error ? error.message : String(error));\n\t}\n}\n\nexport async function ensureLocalServer(host: LocalModelHost): Promise<boolean> {\n\tconst status = await host.localRuntime.detect();\n\tif (status.serverUp) return true;\n\tif (!status.binaryPath) {\n\t\tfor (const line of host.localRuntime.installGuide()) host.showStatus(line);\n\t\treturn false;\n\t}\n\thost.showStatus(\n\t\t`Starting local model server (${status.binarySource} binary, owned storage: ${status.ownedModelsDir})…`,\n\t);\n\tconst started = await host.localRuntime.start();\n\tif (!started.started) {\n\t\thost.showStatus(`Could not start the local server: ${started.reason}`);\n\t\treturn false;\n\t}\n\treturn true;\n}\n\nexport async function listLocalModels(host: LocalModelHost): Promise<void> {\n\tconst status = await host.localRuntime.detect();\n\tif (!status.serverUp) {\n\t\tif (!status.binaryPath) {\n\t\t\tfor (const line of host.localRuntime.installGuide()) host.showStatus(line);\n\t\t\treturn;\n\t\t}\n\t\thost.showStatus(\n\t\t\t`Local server not running (binary: ${status.binarySource}). /models add starts it on demand; /fitness probes registered models.`,\n\t\t);\n\t\treturn;\n\t}\n\tconst models = await host.localRuntime.list();\n\tconst fitness = FitnessStore.forAgentDir(getAgentDir()).getForHost();\n\tconst lines = [\n\t\t`Local models (${status.managedByPi ? `pi-managed server, storage: ${status.ownedModelsDir}` : \"system server — storage owned by the system daemon\"}):`,\n\t\t...(models.length === 0\n\t\t\t? [\" (none installed — /models add <ref>, or /models suggest for a validated roster)\"]\n\t\t\t: []),\n\t\t...models.map((model) => {\n\t\t\tconst report = fitness.find((entry) => entry.model === `ollama/${model.name}`);\n\t\t\tconst gb = (model.sizeBytes / 1e9).toFixed(2);\n\t\t\tconst probe = report\n\t\t\t\t? `probed ${report.at.slice(0, 10)}: digest ${report.report.digest?.succeeded ?? \"?\"}/${report.report.digest?.total ?? \"?\"}, tool-calls ${report.report.toolCall.succeeded}/${report.report.toolCall.total}${report.report.tokensPerSecond ? `, ~${report.report.tokensPerSecond} tok/s` : \"\"}`\n\t\t\t\t: `unprobed — run /fitness ollama/${model.name}`;\n\t\t\treturn ` - ${model.name} (${gb} GB) · ${probe}`;\n\t\t}),\n\t\t\"Commands: /models add <ref> · /models remove <ref> confirm · /models stop\",\n\t];\n\tfor (const line of lines) host.showStatus(line);\n}\n\nexport async function addLocalModel(host: LocalModelHost, pullRef: string, preselectRole?: FitnessRole): Promise<void> {\n\tif (!(await ensureLocalServer(host))) return;\n\thost.showStatus(`Pulling ${pullRef}… (weights land in the server's model storage)`);\n\tlet lastShown = 0;\n\tconst pulled = await host.localRuntime.pull(pullRef, (progress) => {\n\t\tconst now = Date.now();\n\t\tif (now - lastShown > 2000) {\n\t\t\tlastShown = now;\n\t\t\thost.showStatus(` ${pullRef}: ${progress}`);\n\t\t}\n\t});\n\tif (!pulled.ok) {\n\t\thost.showStatus(`Pull failed: ${pulled.error}`);\n\t\treturn;\n\t}\n\tconst registration = registerLocalModel({\n\t\tagentDir: getAgentDir(),\n\t\tref: pullRef,\n\t\tbaseUrl: host.localRuntime.baseUrl,\n\t});\n\tif (!registration.ok) {\n\t\thost.showStatus(`Pulled, but not auto-registered: ${registration.reason}`);\n\t\tif (registration.manualSnippet) {\n\t\t\thost.showStatus(`Add this to ${registration.modelsJsonPath} yourself:\\n${registration.manualSnippet}`);\n\t\t}\n\t\treturn;\n\t}\n\thost.session.modelRegistry.refresh();\n\thost.showStatus(`${pullRef} installed and registered as ollama/${pullRef}. Probing fitness…`);\n\tawait runFitnessAndAssign(host, `ollama/${pullRef}`, preselectRole);\n}\n\nexport async function removeLocalModel(host: LocalModelHost, ref: string, confirmed: boolean): Promise<void> {\n\tconst status = await host.localRuntime.detect();\n\tif (!status.serverUp) {\n\t\thost.showStatus(\"Local server not running — start it (any /models action) before removing.\");\n\t\treturn;\n\t}\n\tconst models = await host.localRuntime.list();\n\tconst target = models.find((model) => matchesInstalledLocalModel(ref, model.name));\n\tif (!target) {\n\t\thost.showStatus(\n\t\t\t`${ref} is not installed. Installed: ${models.map((model) => model.name).join(\", \") || \"(none)\"}`,\n\t\t);\n\t\treturn;\n\t}\n\tif (!confirmed) {\n\t\t// EXPLICIT USER ACTION ONLY: full disclosure, then require the confirm token.\n\t\tconst gb = (target.sizeBytes / 1e9).toFixed(2);\n\t\thost.showStatus(\n\t\t\t[\n\t\t\t\t`Removing ${ref} will delete:`,\n\t\t\t\t` - model weights (${gb} GB) from ${status.managedByPi ? status.ownedModelsDir : \"the system server's storage\"}`,\n\t\t\t\t` - the ollama/${ref} entry in models.json`,\n\t\t\t\t` - its cached fitness report for this host`,\n\t\t\t\t`Run: /models remove ${ref} confirm`,\n\t\t\t].join(\"\\n\"),\n\t\t);\n\t\treturn;\n\t}\n\tconst removed = await host.localRuntime.remove(ref);\n\tif (!removed.ok) {\n\t\thost.showStatus(`Remove failed: ${removed.error}`);\n\t\treturn;\n\t}\n\tunregisterLocalModel({ agentDir: getAgentDir(), ref });\n\tFitnessStore.forAgentDir(getAgentDir()).remove(`ollama/${ref}`);\n\thost.session.modelRegistry.refresh();\n\thost.showStatus(`${ref} removed: weights deleted, registration and fitness report dropped.`);\n}\n\n/** /fitness with no args: pick a model from the configured registry, probe it, assign a role. */\n/** Pick a validated suggestion → install it → probe on this host → land its shaped role. */\nexport function showModelSuggestionSelector(host: LocalModelHost): void {\n\thost.showSelector((done) => {\n\t\tconst selector = new ModelSuggestionSelectorComponent(\n\t\t\tDEFAULT_MODEL_SUGGESTIONS,\n\t\t\tasync (suggestion) => {\n\t\t\t\tdone();\n\t\t\t\t// The shaped role rides along so the post-probe selector lands on it pre-selected;\n\t\t\t\t// non-tool-callers carry curator/judge/none, never executor, so this can't footgun.\n\t\t\t\tawait addLocalModel(host, suggestion.pullRef, suggestion.assignRole);\n\t\t\t},\n\t\t\t() => {\n\t\t\t\tdone();\n\t\t\t\thost.ui.requestRender();\n\t\t\t},\n\t\t);\n\t\treturn { component: selector, focus: selector };\n\t});\n}\n\nexport function showFitnessModelSelector(host: LocalModelHost): void {\n\thost.showSelector((done) => {\n\t\tconst selector = new ModelSelectorComponent(\n\t\t\thost.ui,\n\t\t\thost.session.model,\n\t\t\thost.settingsManager,\n\t\t\thost.session.modelRegistry,\n\t\t\thost.session.scopedModels,\n\t\t\tasync (model) => {\n\t\t\t\tdone();\n\t\t\t\tawait runFitnessAndAssign(host, `${model.provider}/${model.id}`);\n\t\t\t},\n\t\t\t() => {\n\t\t\t\tdone();\n\t\t\t\thost.ui.requestRender();\n\t\t\t},\n\t\t);\n\t\treturn { component: selector, focus: selector };\n\t});\n}\n\n/** Resolve the routed model's supported thinking levels for a fitness-assignment flow, with a safe fallback. */\nfunction getModelThinkingLevels(modelRegistry: ModelRegistry | undefined, modelRef: string): ThinkingLevel[] {\n\tif (!modelRegistry) {\n\t\treturn [...MODEL_ROUTER_THINKING_FALLBACK_LEVELS];\n\t}\n\tconst resolved = resolveCliModel({ cliModel: modelRef, modelRegistry });\n\tif (!resolved.model) {\n\t\treturn [...MODEL_ROUTER_THINKING_FALLBACK_LEVELS];\n\t}\n\treturn getSupportedThinkingLevels(resolved.model);\n}\n\nfunction getModelRouterThinkingField(role: FitnessRole): ModelRouterThinkingField | undefined {\n\tif (role === \"router-cheap\") {\n\t\treturn \"cheapThinking\";\n\t}\n\tif (role === \"router-medium\") {\n\t\treturn \"mediumThinking\";\n\t}\n\tif (role === \"router-expensive\") {\n\t\treturn \"expensiveThinking\";\n\t}\n\tif (role === \"executor\") {\n\t\treturn \"executorThinking\";\n\t}\n\tif (role === \"judge\") {\n\t\treturn \"judgeThinking\";\n\t}\n\treturn undefined;\n}\n\nfunction promptForModelRouterThinking(host: RunFitnessHost, modelRef: string, role: FitnessRole): void {\n\tconst thinkingField = getModelRouterThinkingField(role);\n\tif (!thinkingField) {\n\t\treturn;\n\t}\n\n\tconst modelRegistry = host.session.modelRegistry;\n\tconst availableLevels = getModelThinkingLevels(modelRegistry, modelRef);\n\tconst settings = host.settingsManager.getModelRouterSettings();\n\tconst configuredThinking = settings[thinkingField];\n\tconst currentThinking =\n\t\tconfiguredThinking && availableLevels.includes(configuredThinking)\n\t\t\t? configuredThinking\n\t\t\t: MODEL_ROUTER_THINKING_INHERIT_VALUE;\n\n\thost.showSelector((done) => {\n\t\tconst selector = new ModelRouterThinkingSelectorComponent(\n\t\t\tcurrentThinking,\n\t\t\tavailableLevels,\n\t\t\t(level) => {\n\t\t\t\tdone();\n\t\t\t\thost.settingsManager.setModelRouterSettings({\n\t\t\t\t\t...settings,\n\t\t\t\t\t[thinkingField]: level === MODEL_ROUTER_THINKING_INHERIT_VALUE ? undefined : level,\n\t\t\t\t});\n\t\t\t},\n\t\t\t() => {\n\t\t\t\tdone();\n\t\t\t\thost.ui.requestRender();\n\t\t\t},\n\t\t);\n\t\treturn { component: selector, focus: selector };\n\t});\n}\n\n/** Probe a model's fitness, show the report, then offer one-step role assignment. When the model\n * came from a validated suggestion, `preselectRole` lands its shaped role already highlighted. */\nexport async function runFitnessAndAssign(\n\thost: RunFitnessHost,\n\tmodelRef: string,\n\tpreselectRole?: FitnessRole,\n): Promise<void> {\n\thost.showStatus(`Model fitness probe running on ${modelRef}… (6 surfaces; local models may take a few minutes)`);\n\ttry {\n\t\tconst outcome = await host.session.runModelFitness({ model: modelRef });\n\t\tif (!outcome.started) {\n\t\t\thost.showStatus(`Model fitness skipped: ${outcome.skipReason}`);\n\t\t\treturn;\n\t\t}\n\t\thost.chatContainer.addChild(new Spacer(1));\n\t\thost.chatContainer.addChild(new Text(formatModelFitnessReport(outcome.model, outcome.report), 1, 0));\n\t\thost.ui.requestRender();\n\t\t// Validate-before-load: zero successes on every probed surface means the model cannot\n\t\t// drive any of the harness's subagent contracts on this host — refuse adoption instead\n\t\t// of landing a role selector the user might reflexively confirm (this is the reported\n\t\t// bug: a 0/3-everywhere model still got set as judge model and saved to Model Router).\n\t\tif (isProbeAllFailed(outcome.report)) {\n\t\t\thost.showStatus(\n\t\t\t\t`${outcome.model} failed the fitness probe on all surfaces — not configured. Use /model to set it manually if you accept the risk.`,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\t\thost.showSelector((done) => {\n\t\t\tconst selector = new FitnessRoleSelectorComponent(\n\t\t\t\toutcome.model,\n\t\t\t\t(role) => {\n\t\t\t\t\tdone();\n\t\t\t\t\tif (role === \"scout\") {\n\t\t\t\t\t\tconst verdict = evaluateSurfaceFitness(\"scout_auto\", outcome.report);\n\t\t\t\t\t\tif (!verdict.fit) {\n\t\t\t\t\t\t\tconst reason = verdict.reason === \"lane_failed\" ? `failed ${verdict.lane}` : \"was not probed\";\n\t\t\t\t\t\t\thost.showStatus(\n\t\t\t\t\t\t\t\t`${outcome.model} not assigned as scout: ${reason} on the scout_auto fitness exam. Use the docs/scout.md Modelfile recipe, then rerun /fitness.`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tassignFitnessRole(host, outcome.model, role);\n\t\t\t\t\tpromptForModelRouterThinking(host, outcome.model, role);\n\t\t\t\t},\n\t\t\t\t() => {\n\t\t\t\t\tdone();\n\t\t\t\t\thost.ui.requestRender();\n\t\t\t\t},\n\t\t\t\tpreselectRole,\n\t\t\t);\n\t\t\treturn { component: selector, focus: selector };\n\t\t});\n\t} catch (error) {\n\t\thost.showError(error instanceof Error ? error.message : String(error));\n\t}\n}\n\n/** Persist a role assignment from the post-probe selector into the matching settings. */\nexport function assignFitnessRole(host: AssignRoleHost, modelRef: string, role: FitnessRole): void {\n\tif (role === \"none\") {\n\t\thost.showStatus(`Fitness result for ${modelRef} saved. Assign a role later from /settings.`);\n\t\treturn;\n\t}\n\tif (role === \"curator\") {\n\t\tconst current = host.settingsManager.getContextCurationSettings();\n\t\thost.settingsManager.setContextCurationSettings({ ...current, enabled: true, model: modelRef });\n\t\thost.showStatus(`Context curation enabled with ${modelRef} as the curator.`);\n\t\treturn;\n\t}\n\tif (role === \"executor\") {\n\t\tconst router = host.settingsManager.getModelRouterSettings();\n\t\thost.settingsManager.setModelRouterSettings({ ...router, executorModel: modelRef });\n\t\tconst hint = router.enabled ? \"\" : \" Model router is currently disabled — enable it in /settings → Model Router.\";\n\t\thost.showStatus(`${modelRef} set as the toolkit executor (direct Level-0 hits route to it).${hint}`);\n\t\treturn;\n\t}\n\tif (role === \"scout\") {\n\t\thost.settingsManager.setScoutSettings({ enabled: true, model: modelRef });\n\t\thost.showStatus(`${modelRef} set as the repository scout (context_scout enabled).`);\n\t\treturn;\n\t}\n\tconst router = host.settingsManager.getModelRouterSettings();\n\tconst field =\n\t\trole === \"router-cheap\"\n\t\t\t? \"cheapModel\"\n\t\t\t: role === \"router-medium\"\n\t\t\t\t? \"mediumModel\"\n\t\t\t\t: role === \"router-expensive\"\n\t\t\t\t\t? \"expensiveModel\"\n\t\t\t\t\t: role === \"judge\"\n\t\t\t\t\t\t? \"judgeModel\"\n\t\t\t\t\t\t: \"learningModel\";\n\thost.settingsManager.setModelRouterSettings({ ...router, [field]: modelRef });\n\tconst hint = router.enabled ? \"\" : \" Model router is currently disabled — enable it in /settings → Model Router.\";\n\thost.showStatus(`${modelRef} set as ${role.replace(\"router-\", \"router \")} model.${hint}`);\n}\n"]}
1
+ {"version":3,"file":"local-model-commands.js","sourceRoot":"","sources":["../../../src/modes/interactive/local-model-commands.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `/models` local-model lifecycle and `/fitness` probe/role-assignment flows\n * extracted from interactive-mode.\n *\n * `/models` is a USER-invoked local-model manager (list/add/remove/stop, never a\n * model-invokable tool); the fitness helpers probe a model on the current host\n * and land a shaped role. The server/selector flows share a `LocalModelHost`\n * seam, while `runFitnessAndAssign`/`assignFitnessRole` take narrow host shapes\n * matching their prototype-driven behaviour tests (fitness-probe-gate,\n * fitness-role-assignment), which keep exercising interactive-mode's thin\n * wrappers unchanged.\n */\n\nimport type { ThinkingLevel } from \"@caupulican/pi-agent-core\";\nimport { getSupportedThinkingLevels } from \"@caupulican/pi-ai\";\nimport {\n\ttype Component,\n\tContainer,\n\ttype SelectItem,\n\tSelectList,\n\ttype SelectListLayoutOptions,\n\tSpacer,\n\tText,\n\ttype TUI,\n} from \"@caupulican/pi-tui\";\nimport { getAgentDir } from \"../../config.ts\";\nimport type { AgentSession } from \"../../core/agent-session.ts\";\nimport type { ModelRegistry } from \"../../core/model-registry.ts\";\nimport { resolveCliModel } from \"../../core/model-resolver.ts\";\nimport { evaluateSurfaceFitness } from \"../../core/model-router/fitness-gate.ts\";\nimport { DEFAULT_MODEL_SUGGESTIONS } from \"../../core/models/default-model-suggestions.ts\";\nimport { FitnessStore } from \"../../core/models/fitness-store.ts\";\nimport {\n\tHF_TRANSFORMERS_PROVIDER,\n\tregisterLocalModel,\n\tregisterTransformersModel,\n\tunregisterLocalModel,\n\tunregisterTransformersModel,\n} from \"../../core/models/local-registration.ts\";\nimport type { OllamaRuntime, TransformersRuntime } from \"../../core/models/local-runtime.ts\";\nimport { matchesInstalledLocalModel, normalizeModelSource } from \"../../core/models/model-ref.ts\";\nimport { formatModelFitnessReport, isProbeAllFailed } from \"../../core/research/model-fitness.ts\";\nimport type { SettingsManager } from \"../../core/settings-manager.ts\";\nimport { DynamicBorder } from \"./components/dynamic-border.ts\";\nimport { type FitnessRole, FitnessRoleSelectorComponent } from \"./components/fitness-role-selector.ts\";\nimport { ModelSelectorComponent } from \"./components/model-selector.ts\";\nimport { ModelSuggestionSelectorComponent } from \"./components/model-suggestion-selector.ts\";\nimport { getSelectListTheme } from \"./theme/theme.ts\";\n\ntype SelectorFactory = (done: () => void) => { component: Component; focus: Component };\n\nconst MODEL_ROUTER_THINKING_SELECT_LIST_LAYOUT: SelectListLayoutOptions = {\n\tminPrimaryColumnWidth: 12,\n\tmaxPrimaryColumnWidth: 32,\n};\n\nconst MODEL_ROUTER_THINKING_INHERIT_VALUE = \"__inherit_model_router_thinking__\";\nconst MODEL_ROUTER_THINKING_INHERIT_LABEL = \"(inherit)\";\n\nconst THINKING_LEVEL_DESCRIPTIONS: Record<ThinkingLevel, string> = {\n\toff: \"No reasoning\",\n\tminimal: \"Very brief reasoning (~1k tokens)\",\n\tlow: \"Light reasoning (~2k tokens)\",\n\tmedium: \"Moderate reasoning (~8k tokens)\",\n\thigh: \"Deep reasoning (~16k tokens)\",\n\txhigh: \"Maximum reasoning (~32k tokens)\",\n};\n\nconst MODEL_ROUTER_THINKING_FALLBACK_LEVELS: readonly ThinkingLevel[] = [\n\t\"off\",\n\t\"minimal\",\n\t\"low\",\n\t\"medium\",\n\t\"high\",\n\t\"xhigh\",\n];\n\ntype RouterThinkingLevel = ThinkingLevel | typeof MODEL_ROUTER_THINKING_INHERIT_VALUE;\ntype ModelRouterThinkingField =\n\t| \"cheapThinking\"\n\t| \"mediumThinking\"\n\t| \"expensiveThinking\"\n\t| \"executorThinking\"\n\t| \"judgeThinking\";\n\n/** Narrow seam for persisting a probed model's role — matches the fitness-role test. */\nexport interface AssignRoleHost {\n\treadonly settingsManager: SettingsManager;\n\tshowStatus(message: string): void;\n}\n\n/** Seam for the fitness probe + role-selector flow — matches the fitness-probe-gate test. */\nexport interface RunFitnessHost {\n\treadonly session: Pick<AgentSession, \"runModelFitness\"> & { modelRegistry?: ModelRegistry };\n\treadonly settingsManager: SettingsManager;\n\treadonly chatContainer: Container;\n\treadonly ui: TUI;\n\tshowStatus(message: string): void;\n\tshowError(message: string): void;\n\tshowSelector(create: SelectorFactory): void;\n}\n\n/** Full seam for the `/models` server/selector flows. */\nexport interface LocalModelHost {\n\treadonly localRuntime: OllamaRuntime;\n\treadonly session: AgentSession;\n\treadonly settingsManager: SettingsManager;\n\treadonly ui: TUI;\n\treadonly chatContainer: Container;\n\tgetTransformersRuntime(modelId: string, baseUrl?: string): TransformersRuntime;\n\tshowStatus(message: string): void;\n\tshowError(message: string): void;\n\tshowSelector(create: SelectorFactory): void;\n}\n\nclass ModelRouterThinkingSelectorComponent extends Container {\n\tprivate selectList: SelectList;\n\n\tconstructor(\n\t\tcurrentLevel: RouterThinkingLevel,\n\t\tavailableLevels: ThinkingLevel[],\n\t\tonSelect: (level: RouterThinkingLevel) => void,\n\t\tonCancel: () => void,\n\t) {\n\t\tsuper();\n\n\t\tconst thinkingOptions: SelectItem[] = [\n\t\t\t{\n\t\t\t\tvalue: MODEL_ROUTER_THINKING_INHERIT_VALUE,\n\t\t\t\tlabel: MODEL_ROUTER_THINKING_INHERIT_LABEL,\n\t\t\t\tdescription: \"Use current session default for this tier.\",\n\t\t\t},\n\t\t\t...availableLevels.map((level) => ({\n\t\t\t\tvalue: level,\n\t\t\t\tlabel: level,\n\t\t\t\tdescription: THINKING_LEVEL_DESCRIPTIONS[level],\n\t\t\t})),\n\t\t];\n\n\t\tthis.addChild(new DynamicBorder());\n\n\t\tthis.selectList = new SelectList(\n\t\t\tthinkingOptions,\n\t\t\tthinkingOptions.length,\n\t\t\tgetSelectListTheme(),\n\t\t\tMODEL_ROUTER_THINKING_SELECT_LIST_LAYOUT,\n\t\t);\n\n\t\tconst index = thinkingOptions.findIndex((item) => item.value === currentLevel);\n\t\tif (index !== -1) {\n\t\t\tthis.selectList.setSelectedIndex(index);\n\t\t}\n\n\t\tthis.selectList.onSelect = (item) => {\n\t\t\tonSelect(item.value as RouterThinkingLevel);\n\t\t};\n\t\tthis.selectList.onCancel = () => {\n\t\t\tonCancel();\n\t\t};\n\n\t\tthis.addChild(this.selectList);\n\t\tthis.addChild(new DynamicBorder());\n\t}\n}\n/**\n * /models — USER-invoked local model lifecycle (never a model-invokable tool):\n * list/add/remove/stop per local-model-lifecycle-design.md. Removal is explicit-only with\n * full disclosure; a pasted install command is parsed for its ref, never executed.\n */\nexport async function handleModelsCommand(host: LocalModelHost, argsText: string): Promise<void> {\n\tconst [action = \"list\", ...rest] = argsText.split(/\\s+/).filter(Boolean);\n\ttry {\n\t\tif (action === \"suggest\" || action === \"suggestions\") {\n\t\t\tshowModelSuggestionSelector(host);\n\t\t\treturn;\n\t\t}\n\t\tif (action === \"stop\") {\n\t\t\tconst stopped = host.localRuntime.stop();\n\t\t\tlet stoppedTransformers = 0;\n\t\t\tfor (const model of host.session.modelRegistry\n\t\t\t\t.getAll()\n\t\t\t\t.filter((entry) => entry.provider === HF_TRANSFORMERS_PROVIDER)) {\n\t\t\t\tconst serverUrl = model.baseUrl.replace(/\\/v1\\/?$/, \"\");\n\t\t\t\tif (host.getTransformersRuntime(model.id, serverUrl).stop().stopped) stoppedTransformers++;\n\t\t\t}\n\t\t\tconst stoppedAny = stopped.stopped || stoppedTransformers > 0;\n\t\t\thost.showStatus(\n\t\t\t\tstoppedAny\n\t\t\t\t\t? `Pi-managed local model server stopped${stoppedTransformers > 0 ? ` (${stoppedTransformers} Transformers sidecar(s))` : \"\"}; models remain installed.`\n\t\t\t\t\t: \"No pi-managed server running (a system server, if any, is not pi's to stop).\",\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\tif (action === \"add\") {\n\t\t\tconst rawRef = rest.join(\" \");\n\t\t\tif (!rawRef) {\n\t\t\t\thost.showStatus(\n\t\t\t\t\t\"Usage: /models add <ollama-tag | hf.co/org/repo[:quant] | curated HF full-base ref | huggingface URL | pasted install command>\",\n\t\t\t\t);\n\t\t\t\thost.showStatus(\"Or start from a validated suggestion: /models suggest\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst source = normalizeModelSource(rawRef);\n\t\t\tif (source.type === \"rejected\") {\n\t\t\t\thost.showStatus(`Not added: ${source.reason}`);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (source.type === \"api\") {\n\t\t\t\thost.showStatus(\n\t\t\t\t\t`${source.ref} is an API model — nothing to install. Configure auth for the provider, then probe it with /fitness ${source.ref}.`,\n\t\t\t\t);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (source.type === \"transformers\") {\n\t\t\t\tawait addTransformersModel(host, source.modelId);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tawait addLocalModel(host, source.pullRef);\n\t\t\treturn;\n\t\t}\n\n\t\tif (action === \"remove\") {\n\t\t\tconst ref = rest[0];\n\t\t\tconst confirmed = rest[1] === \"confirm\";\n\t\t\tif (!ref) {\n\t\t\t\thost.showStatus(\"Usage: /models remove <ref> confirm\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst source = normalizeModelSource(ref);\n\t\t\tif (source.type === \"transformers\") {\n\t\t\t\tawait removeTransformersModel(host, source.modelId, confirmed);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tawait removeLocalModel(host, ref, confirmed);\n\t\t\treturn;\n\t\t}\n\n\t\tawait listLocalModels(host);\n\t} catch (error) {\n\t\thost.showError(error instanceof Error ? error.message : String(error));\n\t}\n}\n\nexport async function ensureLocalServer(host: LocalModelHost): Promise<boolean> {\n\tconst status = await host.localRuntime.detect();\n\tif (status.serverUp) return true;\n\tif (!status.binaryPath) {\n\t\tfor (const line of host.localRuntime.installGuide()) host.showStatus(line);\n\t\treturn false;\n\t}\n\thost.showStatus(\n\t\t`Starting local model server (${status.binarySource} binary, owned storage: ${status.ownedModelsDir})…`,\n\t);\n\tconst started = await host.localRuntime.start();\n\tif (!started.started) {\n\t\thost.showStatus(`Could not start the local server: ${started.reason}`);\n\t\treturn false;\n\t}\n\treturn true;\n}\n\nexport async function listLocalModels(host: LocalModelHost): Promise<void> {\n\tconst status = await host.localRuntime.detect();\n\tconst models = status.serverUp ? await host.localRuntime.list() : [];\n\tconst ollamaLines = status.serverUp\n\t\t? [\n\t\t\t\t`Ollama models (${status.managedByPi ? `pi-managed server, storage: ${status.ownedModelsDir}` : \"system server — storage owned by the system daemon\"}):`,\n\t\t\t\t...(models.length === 0\n\t\t\t\t\t? [\" (none installed — /models add <ref>, or /models suggest for a validated roster)\"]\n\t\t\t\t\t: []),\n\t\t\t]\n\t\t: [\n\t\t\t\t\"Ollama models:\",\n\t\t\t\t...(status.binaryPath\n\t\t\t\t\t? [\n\t\t\t\t\t\t\t` server not running (binary: ${status.binarySource}). /models add starts it on demand; /fitness probes registered models.`,\n\t\t\t\t\t\t]\n\t\t\t\t\t: host.localRuntime.installGuide().map((line) => ` ${line}`)),\n\t\t\t];\n\tconst fitness = FitnessStore.forAgentDir(getAgentDir()).getForHost();\n\tconst transformersModels = host.session.modelRegistry\n\t\t.getAll()\n\t\t.filter((model) => model.provider === HF_TRANSFORMERS_PROVIDER);\n\tconst transformersLines = await Promise.all(\n\t\ttransformersModels.map(async (model) => {\n\t\t\tconst serverUrl = model.baseUrl.replace(/\\/v1\\/?$/, \"\");\n\t\t\tconst runtime = host.getTransformersRuntime(model.id, serverUrl);\n\t\t\tconst runtimeStatus = await runtime.detect();\n\t\t\tconst report = fitness.find((entry) => entry.model === `${HF_TRANSFORMERS_PROVIDER}/${model.id}`);\n\t\t\tconst readiness = runtimeStatus.serverUp\n\t\t\t\t? \"server running\"\n\t\t\t\t: runtimeStatus.runtimeInstalled\n\t\t\t\t\t? \"runtime installed\"\n\t\t\t\t\t: \"runtime missing\";\n\t\t\tconst probe = report\n\t\t\t\t? `probed ${report.at.slice(0, 10)}: digest ${report.report.digest?.succeeded ?? \"?\"}/${report.report.digest?.total ?? \"?\"}, tool-calls ${report.report.toolCall.succeeded}/${report.report.toolCall.total}${report.report.tokensPerSecond ? `, ~${report.report.tokensPerSecond} tok/s` : \"\"}`\n\t\t\t\t: `unprobed — run /fitness ${HF_TRANSFORMERS_PROVIDER}/${model.id}`;\n\t\t\treturn ` - ${model.id} (${readiness}, cache: ${runtimeStatus.cacheDir}) · ${probe}`;\n\t\t}),\n\t);\n\tconst lines = [\n\t\t...ollamaLines,\n\t\t...models.map((model) => {\n\t\t\tconst report = fitness.find((entry) => entry.model === `ollama/${model.name}`);\n\t\t\tconst gb = (model.sizeBytes / 1e9).toFixed(2);\n\t\t\tconst probe = report\n\t\t\t\t? `probed ${report.at.slice(0, 10)}: digest ${report.report.digest?.succeeded ?? \"?\"}/${report.report.digest?.total ?? \"?\"}, tool-calls ${report.report.toolCall.succeeded}/${report.report.toolCall.total}${report.report.tokensPerSecond ? `, ~${report.report.tokensPerSecond} tok/s` : \"\"}`\n\t\t\t\t: `unprobed — run /fitness ollama/${model.name}`;\n\t\t\treturn ` - ${model.name} (${gb} GB) · ${probe}`;\n\t\t}),\n\t\t...(transformersLines.length > 0 ? [\"Pi-managed Transformers models:\", ...transformersLines] : []),\n\t\t\"Commands: /models add <ref> · /models remove <ref> confirm · /models stop\",\n\t];\n\tfor (const line of lines) host.showStatus(line);\n}\n\nexport async function addLocalModel(host: LocalModelHost, pullRef: string, preselectRole?: FitnessRole): Promise<void> {\n\tif (!(await ensureLocalServer(host))) return;\n\thost.showStatus(`Pulling ${pullRef}… (weights land in the server's model storage)`);\n\tlet lastShown = 0;\n\tconst pulled = await host.localRuntime.pull(pullRef, (progress) => {\n\t\tconst now = Date.now();\n\t\tif (now - lastShown > 2000) {\n\t\t\tlastShown = now;\n\t\t\thost.showStatus(` ${pullRef}: ${progress}`);\n\t\t}\n\t});\n\tif (!pulled.ok) {\n\t\thost.showStatus(`Pull failed: ${pulled.error}`);\n\t\treturn;\n\t}\n\tconst registration = registerLocalModel({\n\t\tagentDir: getAgentDir(),\n\t\tref: pullRef,\n\t\tbaseUrl: host.localRuntime.baseUrl,\n\t});\n\tif (!registration.ok) {\n\t\thost.showStatus(`Pulled, but not auto-registered: ${registration.reason}`);\n\t\tif (registration.manualSnippet) {\n\t\t\thost.showStatus(`Add this to ${registration.modelsJsonPath} yourself:\\n${registration.manualSnippet}`);\n\t\t}\n\t\treturn;\n\t}\n\thost.session.modelRegistry.refresh();\n\thost.showStatus(`${pullRef} installed and registered as ollama/${pullRef}. Probing fitness…`);\n\tawait runFitnessAndAssign(host, `ollama/${pullRef}`, preselectRole);\n}\n\nexport async function addTransformersModel(\n\thost: LocalModelHost,\n\tmodelId: string,\n\tpreselectRole?: FitnessRole,\n): Promise<void> {\n\tconst runtime = host.getTransformersRuntime(modelId);\n\tlet status = await runtime.detect();\n\tif (!status.runtimeInstalled) {\n\t\thost.showStatus(`Installing isolated Transformers runtime for ${modelId} at ${status.venvDir}…`);\n\t\tconst installed = await runtime.installManaged((progress) => host.showStatus(` transformers: ${progress}`));\n\t\tif (!installed.ok) {\n\t\t\thost.showStatus(`Transformers runtime install failed: ${installed.error}`);\n\t\t\treturn;\n\t\t}\n\t\tstatus = await runtime.detect();\n\t}\n\tif (!status.runtimeInstalled) {\n\t\thost.showStatus(`Transformers runtime is still unavailable at ${status.venvDir}.`);\n\t\treturn;\n\t}\n\n\tconst downloaded = await runtime.downloadModel((progress) => host.showStatus(` ${modelId}: ${progress}`));\n\tif (!downloaded.ok) {\n\t\thost.showStatus(`Model download failed: ${downloaded.error}`);\n\t\treturn;\n\t}\n\n\tconst started = await runtime.start();\n\tif (!started.started && started.reason !== \"already_running\") {\n\t\thost.showStatus(`Could not start Transformers sidecar: ${started.reason}`);\n\t\treturn;\n\t}\n\n\tconst registration = registerTransformersModel({\n\t\tagentDir: getAgentDir(),\n\t\tmodelId,\n\t\tbaseUrl: runtime.baseUrl,\n\t});\n\tif (!registration.ok) {\n\t\thost.showStatus(`Installed, but not auto-registered: ${registration.reason}`);\n\t\tif (registration.manualSnippet) {\n\t\t\thost.showStatus(`Add this to ${registration.modelsJsonPath} yourself:\\n${registration.manualSnippet}`);\n\t\t}\n\t\treturn;\n\t}\n\thost.session.modelRegistry.refresh();\n\thost.showStatus(\n\t\t`${modelId} installed in pi-managed Transformers and registered as ${HF_TRANSFORMERS_PROVIDER}/${modelId}. Probing fitness…`,\n\t);\n\tawait runFitnessAndAssign(host, `${HF_TRANSFORMERS_PROVIDER}/${modelId}`, preselectRole);\n}\n\nexport async function removeLocalModel(host: LocalModelHost, ref: string, confirmed: boolean): Promise<void> {\n\tconst status = await host.localRuntime.detect();\n\tif (!status.serverUp) {\n\t\thost.showStatus(\"Local server not running — start it (any /models action) before removing.\");\n\t\treturn;\n\t}\n\tconst models = await host.localRuntime.list();\n\tconst target = models.find((model) => matchesInstalledLocalModel(ref, model.name));\n\tif (!target) {\n\t\thost.showStatus(\n\t\t\t`${ref} is not installed. Installed: ${models.map((model) => model.name).join(\", \") || \"(none)\"}`,\n\t\t);\n\t\treturn;\n\t}\n\tif (!confirmed) {\n\t\t// EXPLICIT USER ACTION ONLY: full disclosure, then require the confirm token.\n\t\tconst gb = (target.sizeBytes / 1e9).toFixed(2);\n\t\thost.showStatus(\n\t\t\t[\n\t\t\t\t`Removing ${ref} will delete:`,\n\t\t\t\t` - model weights (${gb} GB) from ${status.managedByPi ? status.ownedModelsDir : \"the system server's storage\"}`,\n\t\t\t\t` - the ollama/${ref} entry in models.json`,\n\t\t\t\t` - its cached fitness report for this host`,\n\t\t\t\t`Run: /models remove ${ref} confirm`,\n\t\t\t].join(\"\\n\"),\n\t\t);\n\t\treturn;\n\t}\n\tconst removed = await host.localRuntime.remove(ref);\n\tif (!removed.ok) {\n\t\thost.showStatus(`Remove failed: ${removed.error}`);\n\t\treturn;\n\t}\n\tunregisterLocalModel({ agentDir: getAgentDir(), ref });\n\tFitnessStore.forAgentDir(getAgentDir()).remove(`ollama/${ref}`);\n\thost.session.modelRegistry.refresh();\n\thost.showStatus(`${ref} removed: weights deleted, registration and fitness report dropped.`);\n}\n\nasync function removeTransformersModel(host: LocalModelHost, modelId: string, confirmed: boolean): Promise<void> {\n\tconst runtime = host.getTransformersRuntime(modelId);\n\tconst status = await runtime.detect();\n\tif (!confirmed) {\n\t\thost.showStatus(\n\t\t\t[\n\t\t\t\t`Removing ${modelId} will delete:`,\n\t\t\t\t` - the ${HF_TRANSFORMERS_PROVIDER}/${modelId} entry in models.json`,\n\t\t\t\t` - its cached fitness report for this host`,\n\t\t\t\t`It will stop this session's Transformers sidecar if running. Cached weights remain under ${status.cacheDir}.`,\n\t\t\t\t`Run: /models remove hf.co/${modelId} confirm`,\n\t\t\t].join(\"\\n\"),\n\t\t);\n\t\treturn;\n\t}\n\truntime.stop();\n\tconst registration = unregisterTransformersModel({ agentDir: getAgentDir(), modelId });\n\tif (!registration.ok) {\n\t\thost.showStatus(`Remove failed: ${registration.reason}`);\n\t\treturn;\n\t}\n\tFitnessStore.forAgentDir(getAgentDir()).remove(`${HF_TRANSFORMERS_PROVIDER}/${modelId}`);\n\thost.session.modelRegistry.refresh();\n\thost.showStatus(\n\t\t`${modelId} registration and fitness report dropped; cached weights remain under ${status.cacheDir}.`,\n\t);\n}\n\n/** /fitness with no args: pick a model from the configured registry, probe it, assign a role. */\n/** Pick a validated suggestion → install it → probe on this host → land its shaped role. */\nexport function showModelSuggestionSelector(host: LocalModelHost): void {\n\thost.showSelector((done) => {\n\t\tconst selector = new ModelSuggestionSelectorComponent(\n\t\t\tDEFAULT_MODEL_SUGGESTIONS,\n\t\t\tasync (suggestion) => {\n\t\t\t\tdone();\n\t\t\t\t// The shaped role rides along so the post-probe selector lands on it pre-selected;\n\t\t\t\t// non-tool-callers carry curator/judge/none, never executor, so this can't footgun.\n\t\t\t\tconst source = normalizeModelSource(suggestion.pullRef);\n\t\t\t\tif (source.type === \"transformers\") {\n\t\t\t\t\tawait addTransformersModel(host, source.modelId, suggestion.assignRole);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (source.type === \"local\") {\n\t\t\t\t\tawait addLocalModel(host, source.pullRef, suggestion.assignRole);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\thost.showStatus(\n\t\t\t\t\t`Suggestion ${suggestion.name} is not installable: ${source.type === \"rejected\" ? source.reason : source.ref}`,\n\t\t\t\t);\n\t\t\t},\n\t\t\t() => {\n\t\t\t\tdone();\n\t\t\t\thost.ui.requestRender();\n\t\t\t},\n\t\t);\n\t\treturn { component: selector, focus: selector };\n\t});\n}\n\nexport function showFitnessModelSelector(host: LocalModelHost): void {\n\thost.showSelector((done) => {\n\t\tconst selector = new ModelSelectorComponent(\n\t\t\thost.ui,\n\t\t\thost.session.model,\n\t\t\thost.settingsManager,\n\t\t\thost.session.modelRegistry,\n\t\t\thost.session.scopedModels,\n\t\t\tasync (model) => {\n\t\t\t\tdone();\n\t\t\t\tawait runFitnessAndAssign(host, `${model.provider}/${model.id}`);\n\t\t\t},\n\t\t\t() => {\n\t\t\t\tdone();\n\t\t\t\thost.ui.requestRender();\n\t\t\t},\n\t\t);\n\t\treturn { component: selector, focus: selector };\n\t});\n}\n\n/** Resolve the routed model's supported thinking levels for a fitness-assignment flow, with a safe fallback. */\nfunction getModelThinkingLevels(modelRegistry: ModelRegistry | undefined, modelRef: string): ThinkingLevel[] {\n\tif (!modelRegistry) {\n\t\treturn [...MODEL_ROUTER_THINKING_FALLBACK_LEVELS];\n\t}\n\tconst resolved = resolveCliModel({ cliModel: modelRef, modelRegistry });\n\tif (!resolved.model) {\n\t\treturn [...MODEL_ROUTER_THINKING_FALLBACK_LEVELS];\n\t}\n\treturn getSupportedThinkingLevels(resolved.model);\n}\n\nfunction getModelRouterThinkingField(role: FitnessRole): ModelRouterThinkingField | undefined {\n\tif (role === \"router-cheap\") {\n\t\treturn \"cheapThinking\";\n\t}\n\tif (role === \"router-medium\") {\n\t\treturn \"mediumThinking\";\n\t}\n\tif (role === \"router-expensive\") {\n\t\treturn \"expensiveThinking\";\n\t}\n\tif (role === \"executor\") {\n\t\treturn \"executorThinking\";\n\t}\n\tif (role === \"judge\") {\n\t\treturn \"judgeThinking\";\n\t}\n\treturn undefined;\n}\n\nfunction promptForModelRouterThinking(host: RunFitnessHost, modelRef: string, role: FitnessRole): void {\n\tconst thinkingField = getModelRouterThinkingField(role);\n\tif (!thinkingField) {\n\t\treturn;\n\t}\n\n\tconst modelRegistry = host.session.modelRegistry;\n\tconst availableLevels = getModelThinkingLevels(modelRegistry, modelRef);\n\tconst settings = host.settingsManager.getModelRouterSettings();\n\tconst configuredThinking = settings[thinkingField];\n\tconst currentThinking =\n\t\tconfiguredThinking && availableLevels.includes(configuredThinking)\n\t\t\t? configuredThinking\n\t\t\t: MODEL_ROUTER_THINKING_INHERIT_VALUE;\n\n\thost.showSelector((done) => {\n\t\tconst selector = new ModelRouterThinkingSelectorComponent(\n\t\t\tcurrentThinking,\n\t\t\tavailableLevels,\n\t\t\t(level) => {\n\t\t\t\tdone();\n\t\t\t\thost.settingsManager.setModelRouterSettings({\n\t\t\t\t\t...settings,\n\t\t\t\t\t[thinkingField]: level === MODEL_ROUTER_THINKING_INHERIT_VALUE ? undefined : level,\n\t\t\t\t});\n\t\t\t},\n\t\t\t() => {\n\t\t\t\tdone();\n\t\t\t\thost.ui.requestRender();\n\t\t\t},\n\t\t);\n\t\treturn { component: selector, focus: selector };\n\t});\n}\n\n/** Probe a model's fitness, show the report, then offer one-step role assignment. When the model\n * came from a validated suggestion, `preselectRole` lands its shaped role already highlighted. */\nexport async function runFitnessAndAssign(\n\thost: RunFitnessHost,\n\tmodelRef: string,\n\tpreselectRole?: FitnessRole,\n): Promise<void> {\n\thost.showStatus(`Model fitness probe running on ${modelRef}… (6 surfaces; local models may take a few minutes)`);\n\ttry {\n\t\tconst outcome = await host.session.runModelFitness({ model: modelRef });\n\t\tif (!outcome.started) {\n\t\t\thost.showStatus(`Model fitness skipped: ${outcome.skipReason}`);\n\t\t\treturn;\n\t\t}\n\t\thost.chatContainer.addChild(new Spacer(1));\n\t\thost.chatContainer.addChild(new Text(formatModelFitnessReport(outcome.model, outcome.report), 1, 0));\n\t\thost.ui.requestRender();\n\t\t// Validate-before-load: zero successes on every probed surface means the model cannot\n\t\t// drive any of the harness's subagent contracts on this host — refuse adoption instead\n\t\t// of landing a role selector the user might reflexively confirm (this is the reported\n\t\t// bug: a 0/3-everywhere model still got set as judge model and saved to Model Router).\n\t\tif (isProbeAllFailed(outcome.report)) {\n\t\t\thost.showStatus(\n\t\t\t\t`${outcome.model} failed the fitness probe on all surfaces — not configured. Use /model to set it manually if you accept the risk.`,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\t\thost.showSelector((done) => {\n\t\t\tconst selector = new FitnessRoleSelectorComponent(\n\t\t\t\toutcome.model,\n\t\t\t\t(role) => {\n\t\t\t\t\tdone();\n\t\t\t\t\tif (role === \"scout\") {\n\t\t\t\t\t\tconst verdict = evaluateSurfaceFitness(\"scout_auto\", outcome.report);\n\t\t\t\t\t\tif (!verdict.fit) {\n\t\t\t\t\t\t\tconst reason = verdict.reason === \"lane_failed\" ? `failed ${verdict.lane}` : \"was not probed\";\n\t\t\t\t\t\t\thost.showStatus(\n\t\t\t\t\t\t\t\t`${outcome.model} not assigned as scout: ${reason} on the scout_auto fitness exam. Use the docs/scout.md Modelfile recipe, then rerun /fitness.`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tassignFitnessRole(host, outcome.model, role);\n\t\t\t\t\tpromptForModelRouterThinking(host, outcome.model, role);\n\t\t\t\t},\n\t\t\t\t() => {\n\t\t\t\t\tdone();\n\t\t\t\t\thost.ui.requestRender();\n\t\t\t\t},\n\t\t\t\tpreselectRole,\n\t\t\t);\n\t\t\treturn { component: selector, focus: selector };\n\t\t});\n\t} catch (error) {\n\t\thost.showError(error instanceof Error ? error.message : String(error));\n\t}\n}\n\n/** Persist a role assignment from the post-probe selector into the matching settings. */\nexport function assignFitnessRole(host: AssignRoleHost, modelRef: string, role: FitnessRole): void {\n\tif (role === \"none\") {\n\t\thost.showStatus(`Fitness result for ${modelRef} saved. Assign a role later from /settings.`);\n\t\treturn;\n\t}\n\tif (role === \"curator\") {\n\t\tconst current = host.settingsManager.getContextCurationSettings();\n\t\thost.settingsManager.setContextCurationSettings({ ...current, enabled: true, model: modelRef });\n\t\thost.showStatus(`Context curation enabled with ${modelRef} as the curator.`);\n\t\treturn;\n\t}\n\tif (role === \"executor\") {\n\t\tconst router = host.settingsManager.getModelRouterSettings();\n\t\thost.settingsManager.setModelRouterSettings({ ...router, executorModel: modelRef });\n\t\tconst hint = router.enabled ? \"\" : \" Model router is currently disabled — enable it in /settings → Model Router.\";\n\t\thost.showStatus(`${modelRef} set as the toolkit executor (direct Level-0 hits route to it).${hint}`);\n\t\treturn;\n\t}\n\tif (role === \"scout\") {\n\t\thost.settingsManager.setScoutSettings({ enabled: true, model: modelRef });\n\t\thost.showStatus(`${modelRef} set as the repository scout (context_scout enabled).`);\n\t\treturn;\n\t}\n\tconst router = host.settingsManager.getModelRouterSettings();\n\tconst field =\n\t\trole === \"router-cheap\"\n\t\t\t? \"cheapModel\"\n\t\t\t: role === \"router-medium\"\n\t\t\t\t? \"mediumModel\"\n\t\t\t\t: role === \"router-expensive\"\n\t\t\t\t\t? \"expensiveModel\"\n\t\t\t\t\t: role === \"judge\"\n\t\t\t\t\t\t? \"judgeModel\"\n\t\t\t\t\t\t: \"learningModel\";\n\thost.settingsManager.setModelRouterSettings({ ...router, [field]: modelRef });\n\tconst hint = router.enabled ? \"\" : \" Model router is currently disabled — enable it in /settings → Model Router.\";\n\thost.showStatus(`${modelRef} set as ${role.replace(\"router-\", \"router \")} model.${hint}`);\n}\n"]}