@tuned-tensor/cli 0.12.0-beta.0 → 0.12.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -583,7 +583,7 @@ function resolveAgentModel(runtime, selection) {
583
583
  const resolved = resolveAgentModelDefinition(runtime, selection);
584
584
  if (!runtime.hasConfiguredAuth(selection.provider)) {
585
585
  throw new Error(
586
- `Authenticate Pi provider "${selection.provider}" first (for example with Pi's /login), then retry. Provider secrets are never accepted by tt flags.`
586
+ `Authenticate provider "${selection.provider}" first, then retry. Provider secrets are never accepted by tt flags.`
587
587
  );
588
588
  }
589
589
  return resolved;
@@ -594,7 +594,7 @@ function resolveAgentModelDefinition(runtime, selection) {
594
594
  );
595
595
  if (!provider) {
596
596
  throw new Error(
597
- `Unknown Pi provider "${selection.provider}". Run \`tt agent models --all\` to list providers and models.`
597
+ `Unknown provider "${selection.provider}". Run \`tt agent models --all\` to list providers and models.`
598
598
  );
599
599
  }
600
600
  const model = runtime.getModel(selection.provider, selection.model);
@@ -1127,7 +1127,7 @@ You have no general filesystem tools. The only workspace-scoped local spec capab
1127
1127
  }
1128
1128
  function defaultAgent(options) {
1129
1129
  if (!options.streamSimple) {
1130
- throw new Error("The configured Pi model runtime cannot stream this model.");
1130
+ throw new Error("The configured model runtime cannot stream this model.");
1131
1131
  }
1132
1132
  let calls = 0;
1133
1133
  return new Agent({
@@ -1570,6 +1570,10 @@ function readConfig() {
1570
1570
  return {};
1571
1571
  }
1572
1572
  }
1573
+ var configRevision = 0;
1574
+ function getConfigRevision() {
1575
+ return configRevision;
1576
+ }
1573
1577
  function writeConfig(config) {
1574
1578
  const dir = getConfigDir();
1575
1579
  if (!existsSync2(dir)) mkdirSync2(dir, { recursive: true, mode: 448 });
@@ -1579,6 +1583,7 @@ function writeConfig(config) {
1579
1583
  mode: 384
1580
1584
  });
1581
1585
  chmodSync(path, 384);
1586
+ configRevision += 1;
1582
1587
  }
1583
1588
  function updateConfig(partial) {
1584
1589
  const current = readConfig();
@@ -1770,11 +1775,7 @@ var SLASH_COMMANDS = [
1770
1775
  { path: "/help", description: "Show commands; add a word to filter." },
1771
1776
  { path: "/status", description: "Show lightweight workflow status." },
1772
1777
  { path: "/context", description: "Show the current project and backend context." },
1773
- { path: "/cloud", description: "Switch to the managed cloud workflow." },
1774
- { path: "/local", description: "Switch to the local GPU workflow." },
1775
- { path: "/mode cloud", description: "Alias for /cloud." },
1776
- { path: "/mode local", description: "Alias for /local." },
1777
- { path: "/model", description: "Show the active model; /model <id> activates a local model." },
1778
+ { path: "/model", description: "Show or change the TT agent model." },
1778
1779
  { path: "/cd", description: "Change the shell's working directory." },
1779
1780
  { path: "/clear", description: "Clear the terminal." },
1780
1781
  { path: "/exit", description: "Exit the TT shell." }
@@ -1994,8 +1995,8 @@ async function discoverShellContext(options = {}) {
1994
1995
  if (env.TT_TARGET && !environmentTarget) {
1995
1996
  warnings.push(`Ignoring invalid TT_TARGET=${JSON.stringify(env.TT_TARGET)}; use cloud or local.`);
1996
1997
  }
1997
- const inferredTarget = environmentTarget ?? (hasAdjacentLocalConfig ? "local" : "cloud");
1998
- const targetSource = environmentTarget ? "environment" : hasAdjacentLocalConfig ? "adjacent-config" : "default-cloud";
1998
+ const inferredTarget = environmentTarget ?? "local";
1999
+ const targetSource = environmentTarget ? "environment" : "default-local";
1999
2000
  const [activeModelId, latestRun] = await Promise.all([
2000
2001
  readActiveModelId(storeRoot),
2001
2002
  readLatestRun(storeRoot)
@@ -2037,15 +2038,13 @@ function targetSourceLabel(source) {
2037
2038
  switch (source) {
2038
2039
  case "environment":
2039
2040
  return "TT_TARGET";
2040
- case "adjacent-config":
2041
- return "adjacent local-runner.json";
2042
2041
  default:
2043
2042
  return "default";
2044
2043
  }
2045
2044
  }
2046
2045
  function formatShellContext(context, selectedTarget, targetSource) {
2047
2046
  const specLabel = context.spec ? context.spec.parseError ? `${context.spec.path} (invalid JSON)` : context.spec.path : "not found";
2048
- const sourceLabel = targetSource === "session" ? "session" : targetSource === "command-option" ? "--target" : targetSourceLabel(targetSource);
2047
+ const sourceLabel = targetSource === "command-option" ? "--target" : targetSourceLabel(targetSource);
2049
2048
  const lines = [
2050
2049
  `Target ${selectedTarget} (${sourceLabel})`,
2051
2050
  `Project ${context.projectName}`,
@@ -2087,6 +2086,103 @@ function formatShellStatus(context, selectedTarget) {
2087
2086
  return lines;
2088
2087
  }
2089
2088
 
2089
+ // src/agent-control.ts
2090
+ function modelKey(model) {
2091
+ return `${model.provider}/${model.id}`;
2092
+ }
2093
+ function modelRelevance(model, query) {
2094
+ const q = query.trim().toLowerCase();
2095
+ if (!q) return void 0;
2096
+ const fullId = modelKey(model).toLowerCase();
2097
+ const bareId = model.id.toLowerCase();
2098
+ const name = model.name.toLowerCase();
2099
+ if (fullId === q || bareId === q) return 0;
2100
+ if (fullId.startsWith(q)) return 1;
2101
+ if (bareId.startsWith(q)) return 2;
2102
+ if (fullId.includes(q)) return 3;
2103
+ if (name.includes(q)) return 4;
2104
+ return void 0;
2105
+ }
2106
+ function listAgentModels(runtime, options = {}) {
2107
+ let models = runtime.getModels(options.provider).filter(
2108
+ (model) => options.includeUnauthenticated || runtime.hasConfiguredAuth(model.provider)
2109
+ ).map((model) => ({
2110
+ provider: model.provider,
2111
+ id: model.id,
2112
+ name: model.name ?? model.id,
2113
+ authenticated: runtime.hasConfiguredAuth(model.provider),
2114
+ thinking: model.reasoning !== false
2115
+ }));
2116
+ const query = options.query?.trim().toLowerCase();
2117
+ if (query) {
2118
+ const scored = [];
2119
+ for (const model of models) {
2120
+ const score = modelRelevance(model, query);
2121
+ if (score !== void 0) scored.push({ model, score });
2122
+ }
2123
+ scored.sort(
2124
+ (left, right) => left.score - right.score || modelKey(left.model).localeCompare(modelKey(right.model))
2125
+ );
2126
+ models = scored.map((entry) => entry.model);
2127
+ } else {
2128
+ models.sort((left, right) => modelKey(left).localeCompare(modelKey(right)));
2129
+ }
2130
+ if (options.limit !== void 0 && options.limit > 0) {
2131
+ models = models.slice(0, options.limit);
2132
+ }
2133
+ return models;
2134
+ }
2135
+ function describeAgentModel(runtime, env) {
2136
+ const selection = getAgentSelection(env);
2137
+ if (!selection) return void 0;
2138
+ const resolved = resolveAgentModelDefinition(runtime, selection);
2139
+ const providerName = runtime.getProviders().find((provider) => provider.id === selection.provider)?.name;
2140
+ return {
2141
+ provider: selection.provider,
2142
+ providerName,
2143
+ model: selection.model,
2144
+ modelName: resolved.model.name,
2145
+ thinking: selection.thinking,
2146
+ authenticated: runtime.hasConfiguredAuth(selection.provider),
2147
+ supportsThinking: resolved.model.reasoning !== false
2148
+ };
2149
+ }
2150
+ function setAgentModel(runtime, env, provider, model, options = {}) {
2151
+ const current = getAgentSelection(env);
2152
+ const requestedThinking = options.thinking ?? current?.thinking ?? "medium";
2153
+ if (!AGENT_THINKING_LEVELS.includes(requestedThinking)) {
2154
+ throw new Error(
2155
+ `Agent thinking must be one of: ${AGENT_THINKING_LEVELS.join(", ")}`
2156
+ );
2157
+ }
2158
+ const adjust = options.adjustThinking ?? true;
2159
+ if (!adjust) {
2160
+ const selection2 = {
2161
+ provider,
2162
+ model,
2163
+ thinking: requestedThinking
2164
+ };
2165
+ resolveAgentModel(runtime, selection2);
2166
+ updateConfig({ agent: selection2 });
2167
+ return { selection: selection2, adjustedThinking: false };
2168
+ }
2169
+ const definition = resolveAgentModelDefinition(runtime, {
2170
+ provider,
2171
+ model,
2172
+ thinking: "off"
2173
+ });
2174
+ const supportsThinking = definition.model.reasoning !== false;
2175
+ const effectiveThinking = supportsThinking ? requestedThinking : "off";
2176
+ const selection = {
2177
+ provider,
2178
+ model,
2179
+ thinking: effectiveThinking
2180
+ };
2181
+ resolveAgentModel(runtime, selection);
2182
+ updateConfig({ agent: selection });
2183
+ return { selection, adjustedThinking: effectiveThinking !== requestedThinking };
2184
+ }
2185
+
2090
2186
  // src/shell.ts
2091
2187
  var AGENT_SLASH_COMMANDS = /* @__PURE__ */ new Set([
2092
2188
  "new",
@@ -2217,7 +2313,7 @@ function routeShellCommand(input, activeMode) {
2217
2313
  const override = args2[0];
2218
2314
  if (override === "cloud" || override === "local") {
2219
2315
  if (args2.length === 1) {
2220
- throw new ShellParseError(`Add a ${override} command, or use \`/mode ${override}\` to switch workflows.`);
2316
+ throw new ShellParseError(`Add a ${override} command, e.g. \`${override} runs list\`.`);
2221
2317
  }
2222
2318
  return { target: override, args: args2.slice(1) };
2223
2319
  }
@@ -2246,9 +2342,6 @@ var SLASH_NAMES = /* @__PURE__ */ new Set([
2246
2342
  "help",
2247
2343
  "status",
2248
2344
  "context",
2249
- "mode",
2250
- "cloud",
2251
- "local",
2252
2345
  "model",
2253
2346
  "clear",
2254
2347
  "cd",
@@ -2410,7 +2503,7 @@ function helpText(mode, query, palette = false) {
2410
2503
  `;
2411
2504
  }
2412
2505
  function activeModelLabel(snapshot) {
2413
- return snapshot.mode === "local" ? snapshot.context.local.activeModelId ?? "base" : snapshot.context.spec?.baseModel ?? "\u2014";
2506
+ return snapshot.context.local.activeModelId ?? "base";
2414
2507
  }
2415
2508
  function agentModelLabel(context) {
2416
2509
  const agent = context.agent;
@@ -2465,20 +2558,19 @@ function resetShellPromptStyle() {
2465
2558
  return "";
2466
2559
  }
2467
2560
  var TunedTensorShellSession = class _TunedTensorShellSession {
2468
- constructor(runner, io, agent, env, contextProvider, version, initialContext) {
2561
+ constructor(runner, io, agent, env, contextProvider, version, agentModelRuntime, initialContext) {
2469
2562
  this.runner = runner;
2470
2563
  this.io = io;
2471
2564
  this.agent = agent;
2472
2565
  this.env = env;
2473
2566
  this.contextProvider = contextProvider;
2474
2567
  this.version = version;
2475
- this.mode = initialContext.inferredTarget;
2476
- this.modeSource = initialContext.targetSource;
2568
+ this.agentModelRuntime = agentModelRuntime;
2477
2569
  this.cwd = initialContext.cwd;
2478
2570
  this.context = initialContext;
2479
2571
  }
2480
- mode;
2481
- modeSource;
2572
+ mode = "local";
2573
+ modeSource = "default-local";
2482
2574
  cwd;
2483
2575
  context;
2484
2576
  static async create(options) {
@@ -2493,6 +2585,7 @@ var TunedTensorShellSession = class _TunedTensorShellSession {
2493
2585
  env,
2494
2586
  contextProvider,
2495
2587
  options.version,
2588
+ options.agentModelRuntime,
2496
2589
  initialContext
2497
2590
  );
2498
2591
  }
@@ -2517,26 +2610,67 @@ var TunedTensorShellSession = class _TunedTensorShellSession {
2517
2610
  async refreshContext() {
2518
2611
  this.context = await this.contextProvider({ cwd: this.cwd, env: this.env });
2519
2612
  this.cwd = this.context.cwd;
2520
- if (this.modeSource !== "session" && this.modeSource !== "environment") {
2521
- this.mode = this.context.inferredTarget;
2522
- this.modeSource = this.context.targetSource;
2523
- }
2524
2613
  }
2525
2614
  writeLines(lines) {
2526
2615
  this.io.write(`${lines.join("\n")}
2527
2616
  `);
2528
2617
  }
2529
- modelLines() {
2530
- if (this.mode === "local") {
2531
- return styleDetailLines([
2532
- detailLine("Active model", this.context.local.activeModelId ?? "base"),
2533
- detailLine("Change", "/model <id> to activate a verified local model")
2534
- ]);
2618
+ async requireAgentModelRuntime() {
2619
+ if (!this.agentModelRuntime) {
2620
+ throw new ShellParseError("The local agent model runtime is unavailable.");
2535
2621
  }
2536
- return styleDetailLines([
2537
- detailLine("Base model", this.context.spec?.baseModel ?? "\u2014"),
2538
- detailLine("Change", "edit base_model in tunedtensor.json, then run push")
2622
+ return await this.agentModelRuntime();
2623
+ }
2624
+ renderAgentModel(runtime, query) {
2625
+ let summary;
2626
+ try {
2627
+ summary = describeAgentModel(runtime, this.env);
2628
+ } catch {
2629
+ summary = void 0;
2630
+ }
2631
+ const label = summary ? `${summary.provider}/${summary.model}${summary.modelName && summary.modelName !== summary.model ? ` (${summary.modelName})` : ""} \u2014 thinking ${summary.thinking}, auth ${summary.authenticated ? "configured" : "required"}` : "not configured";
2632
+ const lines = styleDetailLines([
2633
+ detailLine("Agent model", label),
2634
+ detailLine("Change", "/model <provider>/<model>"),
2635
+ detailLine("Search", "/model <query>")
2539
2636
  ]);
2637
+ const all = listAgentModels(runtime);
2638
+ if (all.length === 0) {
2639
+ lines.push("", chalk.dim(" no authenticated models \u2014 run `tt agent models --all` for the full catalog"));
2640
+ return lines;
2641
+ }
2642
+ if (query) {
2643
+ const matches = listAgentModels(runtime, { query });
2644
+ lines.push("", chalk.bold(`Models matching ${JSON.stringify(query)}`));
2645
+ if (matches.length === 0) {
2646
+ lines.push(chalk.dim(" no matches"));
2647
+ } else {
2648
+ const shown2 = matches.slice(0, 10);
2649
+ for (const model of shown2) {
2650
+ lines.push(this.formatAgentModelChoice(model, summary));
2651
+ }
2652
+ if (matches.length > shown2.length) {
2653
+ lines.push(chalk.dim(` \u2026 ${matches.length - shown2.length} more \u2014 refine the query`));
2654
+ }
2655
+ }
2656
+ return lines;
2657
+ }
2658
+ const preferred = summary ? all.filter((model) => model.provider === summary.provider) : [];
2659
+ const rest = summary ? all.filter((model) => model.provider !== summary.provider) : all;
2660
+ const shown = [...preferred, ...rest].slice(0, 8);
2661
+ lines.push("", chalk.bold(summary ? "Suggestions" : "Available models"));
2662
+ for (const model of shown) {
2663
+ lines.push(this.formatAgentModelChoice(model, summary));
2664
+ }
2665
+ if (all.length > shown.length) {
2666
+ lines.push(chalk.dim(` \u2026 ${all.length - shown.length} more \u2014 /model <query> to search`));
2667
+ }
2668
+ return lines;
2669
+ }
2670
+ formatAgentModelChoice(model, summary) {
2671
+ const active = summary?.provider === model.provider && summary?.model === model.id;
2672
+ const displayName = model.name !== model.id ? ` ${model.name}` : "";
2673
+ return ` ${accent(`${model.provider}/${model.id}`)}${displayName}${active ? chalk.dim(" (active)") : ""}`;
2540
2674
  }
2541
2675
  async handleSlash(command) {
2542
2676
  switch (command.name) {
@@ -2558,49 +2692,37 @@ var TunedTensorShellSession = class _TunedTensorShellSession {
2558
2692
  formatShellContext(this.context, this.mode, this.modeSource)
2559
2693
  ));
2560
2694
  return "continue";
2561
- case "mode": {
2562
- if (command.args.length === 0) {
2563
- this.io.write(`Current workflow: ${this.mode}
2564
- `);
2565
- return "continue";
2566
- }
2567
- if (command.args.length !== 1 || !["cloud", "local"].includes(command.args[0])) {
2568
- throw new ShellParseError("Usage: /mode cloud|local");
2569
- }
2570
- this.mode = command.args[0];
2571
- this.modeSource = "session";
2572
- this.io.write(`${successMark()} Workflow switched to ${this.mode}.
2573
- `);
2574
- return "continue";
2575
- }
2576
- case "cloud":
2577
- case "local":
2578
- assertNoArgs(command.name, command.args);
2579
- this.mode = command.name;
2580
- this.modeSource = "session";
2581
- this.io.write(`${successMark()} Workflow switched to ${this.mode}.
2582
- `);
2583
- return "continue";
2584
2695
  case "model": {
2696
+ const runtime = await this.requireAgentModelRuntime();
2585
2697
  if (command.args.length === 0) {
2586
2698
  await this.refreshContext();
2587
- this.writeLines(this.modelLines());
2699
+ this.writeLines(this.renderAgentModel(runtime));
2588
2700
  return "continue";
2589
2701
  }
2590
2702
  if (command.args.length !== 1) {
2591
- throw new ShellParseError("Usage: /model [model-id]");
2703
+ throw new ShellParseError("Usage: /model [<query> | <provider>/<model>]");
2592
2704
  }
2593
- if (this.mode !== "local") {
2705
+ const target = command.args[0];
2706
+ const slash = target.indexOf("/");
2707
+ if (slash <= 0) {
2708
+ await this.refreshContext();
2709
+ this.writeLines(this.renderAgentModel(runtime, target));
2710
+ return "continue";
2711
+ }
2712
+ if (slash === target.length - 1) {
2594
2713
  throw new ShellParseError(
2595
- "Activating models is a local workflow action. Use /mode local first; cloud specs change base_model in tunedtensor.json."
2714
+ "Usage: /model <provider>/<model>, e.g. /model anthropic/claude-sonnet-4-5"
2596
2715
  );
2597
2716
  }
2598
- await this.runner({
2599
- target: "local",
2600
- args: ["models", "activate", command.args[0]],
2601
- cwd: this.cwd
2602
- });
2717
+ const provider = target.slice(0, slash);
2718
+ const model = target.slice(slash + 1);
2719
+ const result2 = setAgentModel(runtime, this.env, provider, model);
2603
2720
  await this.refreshContext();
2721
+ const note = result2.adjustedThinking ? " \u2014 thinking set to off for this model" : "";
2722
+ this.io.write(
2723
+ `${successMark()} Agent model: ${result2.selection.provider}/${result2.selection.model} (thinking ${result2.selection.thinking})${note}.
2724
+ `
2725
+ );
2604
2726
  return "continue";
2605
2727
  }
2606
2728
  case "clear":
@@ -2740,7 +2862,8 @@ async function startInteractiveShell(options) {
2740
2862
  agent: options.agent,
2741
2863
  cwd: options.cwd,
2742
2864
  env: options.env,
2743
- version: options.version
2865
+ version: options.version,
2866
+ agentModelRuntime: options.agentModelRuntime
2744
2867
  });
2745
2868
  const completer = createCommandCompleter(() => session.snapshot().mode);
2746
2869
  readline = createInterface({
@@ -8110,61 +8233,47 @@ function registerPushCommand(parent) {
8110
8233
  }
8111
8234
 
8112
8235
  // src/commands/agent.ts
8113
- function selectionOrHint(env) {
8114
- const selection = getAgentSelection(env);
8115
- if (!selection) {
8116
- throw new Error(
8117
- "The local agent is not configured. Run `tt agent configure --provider <provider> --model <model>`."
8118
- );
8119
- }
8120
- return selection;
8121
- }
8122
8236
  function registerAgentCommands(parent, options) {
8123
- const agent = parent.command("agent").description("Configure the laptop-local Pi agent");
8237
+ const agent = parent.command("agent").description("Configure the laptop-local TT agent");
8124
8238
  agent.command("status").description("Show the selected local provider, model, thinking, and auth state").action(async () => {
8125
- const selection = selectionOrHint(options.env);
8126
8239
  const runtime = await options.getRuntime();
8127
- const resolved = resolveAgentModelDefinition(runtime, selection);
8128
- const authenticated = runtime.hasConfiguredAuth(selection.provider);
8129
- const providerName = runtime.getProviders().find(
8130
- (provider) => provider.id === selection.provider
8131
- )?.name;
8240
+ const summary = describeAgentModel(runtime, options.env);
8241
+ if (!summary) {
8242
+ throw new Error(
8243
+ "The local agent is not configured. Run `tt agent configure --provider <provider> --model <model>`."
8244
+ );
8245
+ }
8132
8246
  const value = {
8133
8247
  execution: "local",
8134
- provider: selection.provider,
8135
- provider_name: providerName,
8136
- model: selection.model,
8137
- model_name: resolved.model.name,
8138
- thinking: selection.thinking,
8139
- authenticated,
8140
- supports_thinking: resolved.model.reasoning !== false
8248
+ provider: summary.provider,
8249
+ provider_name: summary.providerName,
8250
+ model: summary.model,
8251
+ model_name: summary.modelName,
8252
+ thinking: summary.thinking,
8253
+ authenticated: summary.authenticated,
8254
+ supports_thinking: summary.supportsThinking
8141
8255
  };
8142
- const modelLabel = resolved.model.name && resolved.model.name !== selection.model ? `${resolved.model.name} (${selection.provider}/${selection.model})` : `${selection.provider}/${selection.model}`;
8256
+ const modelLabel = summary.modelName && summary.modelName !== summary.model ? `${summary.modelName} (${summary.provider}/${summary.model})` : `${summary.provider}/${summary.model}`;
8143
8257
  options.output.write(isJsonMode() ? `${JSON.stringify(value, null, 2)}
8144
- ` : `Local agent: ${modelLabel} (thinking: ${value.thinking}, auth: ${authenticated ? "configured" : "required"})
8258
+ ` : `Local agent: ${modelLabel} (thinking: ${value.thinking}, auth: ${value.authenticated ? "configured" : "required"})
8145
8259
  `);
8146
8260
  });
8147
- agent.command("models").description("List Pi provider models available to the local agent").option("--provider <provider>", "Filter by Pi provider ID").option("--all", "Include models whose provider auth is not configured").action(async (commandOptions) => {
8261
+ agent.command("models").description("List provider models available to the local agent").option("--provider <provider>", "Filter by provider ID").option("--all", "Include models whose provider auth is not configured").action(async (commandOptions) => {
8148
8262
  const runtime = await options.getRuntime();
8149
8263
  if (commandOptions.provider && !runtime.getProviders().some((provider) => provider.id === commandOptions.provider)) {
8150
- throw new Error(`Unknown Pi provider "${commandOptions.provider}".`);
8151
- }
8152
- const models = runtime.getModels(commandOptions.provider).filter(
8153
- (model) => commandOptions.all || runtime.hasConfiguredAuth(model.provider)
8154
- ).map((model) => ({
8155
- provider: model.provider,
8156
- id: model.id,
8157
- name: model.name ?? model.id,
8158
- authenticated: runtime.hasConfiguredAuth(model.provider),
8159
- thinking: model.reasoning !== false
8160
- }));
8264
+ throw new Error(`Unknown provider "${commandOptions.provider}".`);
8265
+ }
8266
+ const models = listAgentModels(runtime, {
8267
+ provider: commandOptions.provider,
8268
+ includeUnauthenticated: commandOptions.all
8269
+ });
8161
8270
  if (isJsonMode()) {
8162
8271
  options.output.write(`${JSON.stringify({ data: models }, null, 2)}
8163
8272
  `);
8164
8273
  return;
8165
8274
  }
8166
8275
  if (models.length === 0) {
8167
- options.output.write("No matching authenticated Pi models. Use --all to inspect the full catalog.\n");
8276
+ options.output.write("No matching authenticated models. Use --all to inspect the full catalog.\n");
8168
8277
  return;
8169
8278
  }
8170
8279
  for (const model of models) {
@@ -8172,20 +8281,17 @@ function registerAgentCommands(parent, options) {
8172
8281
  `);
8173
8282
  }
8174
8283
  });
8175
- agent.command("configure").description("Select the local Pi provider, model, and thinking level").requiredOption("--provider <provider>", "Pi provider ID").requiredOption("--model <model>", "Pi model ID").option("--thinking <level>", "off, minimal, low, medium, high, xhigh, or max", "medium").action(async (commandOptions) => {
8176
- if (!AGENT_THINKING_LEVELS.includes(commandOptions.thinking)) {
8177
- throw new Error(`--thinking must be one of: ${AGENT_THINKING_LEVELS.join(", ")}`);
8178
- }
8179
- const selection = {
8180
- provider: commandOptions.provider,
8181
- model: commandOptions.model,
8182
- thinking: commandOptions.thinking
8183
- };
8184
- resolveAgentModel(await options.getRuntime(), selection);
8185
- updateConfig({ agent: selection });
8186
- const value = { execution: "local", ...selection };
8284
+ agent.command("configure").description("Select the local provider, model, and thinking level").requiredOption("--provider <provider>", "Provider ID").requiredOption("--model <model>", "Model ID").option("--thinking <level>", "off, minimal, low, medium, high, xhigh, or max", "medium").action(async (commandOptions) => {
8285
+ const result2 = setAgentModel(
8286
+ await options.getRuntime(),
8287
+ options.env,
8288
+ commandOptions.provider,
8289
+ commandOptions.model,
8290
+ { thinking: commandOptions.thinking, adjustThinking: false }
8291
+ );
8292
+ const value = { execution: "local", ...result2.selection };
8187
8293
  options.output.write(isJsonMode() ? `${JSON.stringify(value, null, 2)}
8188
- ` : `Configured local agent: ${selection.provider}/${selection.model} (thinking: ${selection.thinking}).
8294
+ ` : `Configured local agent: ${result2.selection.provider}/${result2.selection.model} (thinking: ${result2.selection.thinking}).
8189
8295
  `);
8190
8296
  });
8191
8297
  }
@@ -8355,14 +8461,14 @@ function formatCliUpdateNotice(update) {
8355
8461
  }
8356
8462
 
8357
8463
  // src/cli.ts
8358
- async function createDefaultAgentClient(runtime, env, cloud, workspaceRoot) {
8464
+ async function createDefaultAgentClient(runtime, env, cloud, workspaceRoot, getModelRuntime) {
8359
8465
  const selection = getAgentSelection(env);
8360
8466
  if (!selection) {
8361
8467
  throw new Error(
8362
8468
  "The laptop-local agent is not configured. Run `tt agent models --all`, then `tt agent configure --provider <provider> --model <model>`."
8363
8469
  );
8364
8470
  }
8365
- const modelRuntime = runtime.modelRuntime ?? await createPiModelRuntime();
8471
+ const modelRuntime = await getModelRuntime();
8366
8472
  const clientOpts = { apiKey: cloud.apiKey, baseUrl: cloud.baseUrl };
8367
8473
  const toolApi = runtime.agentToolApi ?? {
8368
8474
  get: async (path, query) => await get(path, query, clientOpts),
@@ -8395,11 +8501,23 @@ async function createDefaultAgentClient(runtime, env, cloud, workspaceRoot) {
8395
8501
  createAgent: runtime.createPiAgent
8396
8502
  });
8397
8503
  }
8398
- function createLazyDefaultAgentClient(runtime, env, cloud, workspaceRoot) {
8504
+ function createModelRuntimeGetter(runtime) {
8505
+ const injected = runtime.modelRuntime;
8506
+ let promise;
8507
+ return async () => {
8508
+ if (injected) return injected;
8509
+ promise ??= createPiModelRuntime();
8510
+ return await promise;
8511
+ };
8512
+ }
8513
+ function createLazyDefaultAgentClient(runtime, env, cloud, workspaceRoot, getModelRuntime) {
8399
8514
  let pending;
8515
+ let builtRevision = -1;
8400
8516
  const client = () => {
8401
- if (!pending) {
8402
- const attempt = createDefaultAgentClient(runtime, env, cloud, workspaceRoot);
8517
+ const revision = getConfigRevision();
8518
+ if (!pending || builtRevision !== revision) {
8519
+ builtRevision = revision;
8520
+ const attempt = createDefaultAgentClient(runtime, env, cloud, workspaceRoot, getModelRuntime);
8403
8521
  pending = attempt;
8404
8522
  attempt.catch(() => {
8405
8523
  if (pending === attempt) pending = void 0;
@@ -8499,13 +8617,7 @@ function createProgram(version, runtime = {}) {
8499
8617
  const invokeLocal = runtime.runLocalCommand ?? executeLocalCommand;
8500
8618
  const launchShell = runtime.startShell ?? startInteractiveShell;
8501
8619
  const cwd = runtime.cwd ?? process.cwd();
8502
- const injectedModelRuntime = runtime.modelRuntime;
8503
- let modelRuntimePromise;
8504
- const getModelRuntime = async () => {
8505
- if (injectedModelRuntime) return injectedModelRuntime;
8506
- modelRuntimePromise ??= createPiModelRuntime();
8507
- return await modelRuntimePromise;
8508
- };
8620
+ const getModelRuntime = createModelRuntimeGetter(runtime);
8509
8621
  const shellRunner = async (request2) => {
8510
8622
  const root = program.opts();
8511
8623
  const args2 = request2.target === "local" ? ["local", ...request2.args] : request2.args;
@@ -8524,7 +8636,7 @@ function createProgram(version, runtime = {}) {
8524
8636
  client: runtime.agentClient ?? createLazyDefaultAgentClient(runtime, shellEnvironment, {
8525
8637
  apiKey: root.apiKey ?? shellEnvironment.TUNED_TENSOR_API_KEY,
8526
8638
  baseUrl: root.baseUrl ?? shellEnvironment.TUNED_TENSOR_URL
8527
- }, cwd),
8639
+ }, cwd, getModelRuntime),
8528
8640
  output,
8529
8641
  error
8530
8642
  });
@@ -8536,7 +8648,8 @@ function createProgram(version, runtime = {}) {
8536
8648
  error,
8537
8649
  cwd,
8538
8650
  env: shellEnvironment,
8539
- version
8651
+ version,
8652
+ agentModelRuntime: getModelRuntime
8540
8653
  });
8541
8654
  };
8542
8655
  program.name("tt").description("Tuned Tensor \u2014 converse, train, and inspect from one terminal").version(version).option("-k, --api-key <key>", "API key (overrides stored key)").option(
@@ -8640,7 +8753,7 @@ function createProgram(version, runtime = {}) {
8640
8753
  });
8641
8754
  applyExitCode(result2);
8642
8755
  });
8643
- program.command("shell").description("Open the interactive cloud/local terminal").action(openShell);
8756
+ program.command("shell").description("Open the conversational terminal (local by default)").action(openShell);
8644
8757
  program.addHelpText(
8645
8758
  "after",
8646
8759
  `
@@ -8697,11 +8810,12 @@ async function runCli(version, runtime = {}) {
8697
8810
  `);
8698
8811
  }
8699
8812
  const invokeSelf = runtime.runSelfCommand ?? runSelfCommand;
8813
+ const getModelRuntime = createModelRuntimeGetter(runtime);
8700
8814
  const agent = createShellAgent({
8701
8815
  client: runtime.agentClient ?? createLazyDefaultAgentClient(runtime, env, {
8702
8816
  apiKey: env.TUNED_TENSOR_API_KEY,
8703
8817
  baseUrl: env.TUNED_TENSOR_URL
8704
- }, runtime.cwd ?? process.cwd()),
8818
+ }, runtime.cwd ?? process.cwd(), getModelRuntime),
8705
8819
  output,
8706
8820
  error
8707
8821
  });
@@ -8720,7 +8834,8 @@ async function runCli(version, runtime = {}) {
8720
8834
  error,
8721
8835
  cwd: runtime.cwd ?? process.cwd(),
8722
8836
  env,
8723
- version
8837
+ version,
8838
+ agentModelRuntime: getModelRuntime
8724
8839
  });
8725
8840
  return;
8726
8841
  }
@@ -8729,7 +8844,7 @@ async function runCli(version, runtime = {}) {
8729
8844
  }
8730
8845
 
8731
8846
  // src/index.ts
8732
- runCli("0.12.0-beta.0").catch((err) => {
8847
+ runCli("0.12.0-beta.1").catch((err) => {
8733
8848
  reportError(err);
8734
8849
  process.exit(1);
8735
8850
  });