@tuned-tensor/cli 0.11.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/README.md +44 -29
- package/dist/{chunk-DAP2Z7EZ.js → chunk-HDGBDHOB.js} +474 -74
- package/dist/chunk-HDGBDHOB.js.map +1 -0
- package/dist/index.js +366 -199
- package/dist/index.js.map +1 -1
- package/dist/local-runtime.js +52 -19
- package/dist/local-runtime.js.map +1 -1
- package/docs/local-runtime/architecture.md +8 -2
- package/docs/local-runtime/spark.md +39 -2
- package/package.json +6 -2
- package/training/local-runner/pyproject.toml +2 -2
- package/training/local-runner/src/evaluate.py +44 -18
- package/training/local-runner/src/model_contract.py +134 -14
- package/training/local-runner/src/prefetch.py +25 -8
- package/training/local-runner/src/serve.py +14 -6
- package/training/local-runner/src/sft_data.py +7 -3
- package/training/local-runner/src/train.py +48 -14
- package/training/local-runner/uv.lock +54 -54
- package/dist/chunk-DAP2Z7EZ.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
+
TRAINING_MODELS,
|
|
3
4
|
assertLocalRunInputReady,
|
|
4
5
|
loadLocalRunInput,
|
|
5
6
|
loadLocalRunnerConfig,
|
|
6
7
|
runLocalPipeline
|
|
7
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-HDGBDHOB.js";
|
|
8
9
|
|
|
9
10
|
// src/cli.ts
|
|
10
11
|
import { spawn as spawn4 } from "child_process";
|
|
@@ -24,76 +25,6 @@ import { join } from "path";
|
|
|
24
25
|
import { Type } from "typebox";
|
|
25
26
|
import { Value } from "typebox/value";
|
|
26
27
|
|
|
27
|
-
// src/base-models.ts
|
|
28
|
-
var SUPPORTED_BASE_MODELS = [
|
|
29
|
-
"google/gemma-4-E2B-it",
|
|
30
|
-
"google/gemma-4-E4B-it",
|
|
31
|
-
"Qwen/Qwen3.5-2B",
|
|
32
|
-
"Qwen/Qwen3-VL-2B-Instruct",
|
|
33
|
-
"Qwen/Qwen3.5-4B",
|
|
34
|
-
"meta-llama/Llama-3.2-3B-Instruct",
|
|
35
|
-
"microsoft/Phi-4-mini-instruct",
|
|
36
|
-
"ibm-granite/granite-3.3-2b-instruct",
|
|
37
|
-
"bigcode/starcoder2-3b"
|
|
38
|
-
];
|
|
39
|
-
var BASE_MODEL_ALIASES = /* @__PURE__ */ new Map();
|
|
40
|
-
for (const model of SUPPORTED_BASE_MODELS) {
|
|
41
|
-
BASE_MODEL_ALIASES.set(model.toLowerCase(), model);
|
|
42
|
-
}
|
|
43
|
-
for (const [alias, model] of [
|
|
44
|
-
["google/gemma-4-E2B", "google/gemma-4-E2B-it"],
|
|
45
|
-
["google/gemma-4-e2b", "google/gemma-4-E2B-it"],
|
|
46
|
-
["google/gemma-4-e2b-it", "google/gemma-4-E2B-it"],
|
|
47
|
-
["google/gemma-4-E4B", "google/gemma-4-E4B-it"],
|
|
48
|
-
["google/gemma-4-e4b", "google/gemma-4-E4B-it"],
|
|
49
|
-
["google/gemma-4-e4b-it", "google/gemma-4-E4B-it"],
|
|
50
|
-
["qwen/qwen3.5-2b", "Qwen/Qwen3.5-2B"],
|
|
51
|
-
["Qwen/Qwen3.5-2B-Base", "Qwen/Qwen3.5-2B"],
|
|
52
|
-
["qwen/qwen3.5-2b-base", "Qwen/Qwen3.5-2B"],
|
|
53
|
-
["qwen/qwen3-vl-2b-instruct", "Qwen/Qwen3-VL-2B-Instruct"],
|
|
54
|
-
["Qwen/Qwen3-VL-2B", "Qwen/Qwen3-VL-2B-Instruct"],
|
|
55
|
-
["qwen/qwen3-vl-2b", "Qwen/Qwen3-VL-2B-Instruct"],
|
|
56
|
-
["qwen/qwen3.5-4b", "Qwen/Qwen3.5-4B"],
|
|
57
|
-
["Qwen/Qwen3.5-4B-Base", "Qwen/Qwen3.5-4B"],
|
|
58
|
-
["qwen/qwen3.5-4b-base", "Qwen/Qwen3.5-4B"],
|
|
59
|
-
["meta-llama/llama-3.2-3b-instruct", "meta-llama/Llama-3.2-3B-Instruct"],
|
|
60
|
-
["meta-llama/Llama-3.2-3B", "meta-llama/Llama-3.2-3B-Instruct"],
|
|
61
|
-
["meta-llama/llama-3.2-3b", "meta-llama/Llama-3.2-3B-Instruct"],
|
|
62
|
-
["microsoft/phi-4-mini-instruct", "microsoft/Phi-4-mini-instruct"],
|
|
63
|
-
["phi-4-mini-instruct", "microsoft/Phi-4-mini-instruct"],
|
|
64
|
-
["ibm-granite/granite-3.3-2b-instruct", "ibm-granite/granite-3.3-2b-instruct"],
|
|
65
|
-
["granite-3.3-2b-instruct", "ibm-granite/granite-3.3-2b-instruct"],
|
|
66
|
-
["bigcode/starcoder2-3b", "bigcode/starcoder2-3b"],
|
|
67
|
-
["starcoder2-3b", "bigcode/starcoder2-3b"]
|
|
68
|
-
]) {
|
|
69
|
-
BASE_MODEL_ALIASES.set(alias.toLowerCase(), model);
|
|
70
|
-
}
|
|
71
|
-
var UnsupportedBaseModelError = class extends Error {
|
|
72
|
-
constructor(model) {
|
|
73
|
-
const supported = SUPPORTED_BASE_MODELS.join(", ");
|
|
74
|
-
super(
|
|
75
|
-
`Unsupported base_model "${String(model)}". Supported base models: ${supported}`
|
|
76
|
-
);
|
|
77
|
-
this.name = "UnsupportedBaseModelError";
|
|
78
|
-
}
|
|
79
|
-
};
|
|
80
|
-
function canonicalizeBaseModel(model) {
|
|
81
|
-
if (typeof model !== "string" || !model.trim()) {
|
|
82
|
-
throw new UnsupportedBaseModelError(model);
|
|
83
|
-
}
|
|
84
|
-
const canonical = BASE_MODEL_ALIASES.get(model.trim().toLowerCase());
|
|
85
|
-
if (!canonical) {
|
|
86
|
-
throw new UnsupportedBaseModelError(model);
|
|
87
|
-
}
|
|
88
|
-
return canonical;
|
|
89
|
-
}
|
|
90
|
-
function canonicalizeSpecBaseModel(body) {
|
|
91
|
-
if ("base_model" in body && body.base_model !== void 0) {
|
|
92
|
-
return { ...body, base_model: canonicalizeBaseModel(body.base_model) };
|
|
93
|
-
}
|
|
94
|
-
return body;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
28
|
// src/eval/rules.ts
|
|
98
29
|
function validateSpec(spec) {
|
|
99
30
|
const checks = [];
|
|
@@ -258,15 +189,15 @@ var FolderName = Type.String({
|
|
|
258
189
|
pattern: "^[A-Za-z0-9][A-Za-z0-9._-]*$",
|
|
259
190
|
description: "One new folder name directly beneath the current workspace"
|
|
260
191
|
});
|
|
261
|
-
var
|
|
192
|
+
var LocalBaseModel = Type.String({
|
|
262
193
|
type: "string",
|
|
263
|
-
enum:
|
|
194
|
+
enum: TRAINING_MODELS.map((model) => model.id)
|
|
264
195
|
});
|
|
265
196
|
var NonEmptyText = Type.String({ minLength: 1, maxLength: 1e3 });
|
|
266
197
|
var LocalProjectSpecSchema = Type.Object({
|
|
267
198
|
name: Type.String({ minLength: 1, maxLength: 255 }),
|
|
268
199
|
description: Type.Optional(Type.String({ maxLength: 5e3 })),
|
|
269
|
-
base_model:
|
|
200
|
+
base_model: LocalBaseModel,
|
|
270
201
|
system_prompt: Type.String({ minLength: 1, maxLength: 1e4 }),
|
|
271
202
|
guidelines: Type.Array(NonEmptyText, { minItems: 1, maxItems: 50 }),
|
|
272
203
|
constraints: Type.Optional(Type.Array(NonEmptyText, { maxItems: 50 })),
|
|
@@ -652,7 +583,7 @@ function resolveAgentModel(runtime, selection) {
|
|
|
652
583
|
const resolved = resolveAgentModelDefinition(runtime, selection);
|
|
653
584
|
if (!runtime.hasConfiguredAuth(selection.provider)) {
|
|
654
585
|
throw new Error(
|
|
655
|
-
`Authenticate
|
|
586
|
+
`Authenticate provider "${selection.provider}" first, then retry. Provider secrets are never accepted by tt flags.`
|
|
656
587
|
);
|
|
657
588
|
}
|
|
658
589
|
return resolved;
|
|
@@ -663,7 +594,7 @@ function resolveAgentModelDefinition(runtime, selection) {
|
|
|
663
594
|
);
|
|
664
595
|
if (!provider) {
|
|
665
596
|
throw new Error(
|
|
666
|
-
`Unknown
|
|
597
|
+
`Unknown provider "${selection.provider}". Run \`tt agent models --all\` to list providers and models.`
|
|
667
598
|
);
|
|
668
599
|
}
|
|
669
600
|
const model = runtime.getModel(selection.provider, selection.model);
|
|
@@ -721,6 +652,83 @@ function ensureOpenRouterAppHeaders(modelsPath) {
|
|
|
721
652
|
import { randomUUID } from "crypto";
|
|
722
653
|
import { Type as Type2 } from "typebox";
|
|
723
654
|
|
|
655
|
+
// src/base-models.ts
|
|
656
|
+
var SUPPORTED_BASE_MODELS = [
|
|
657
|
+
"google/gemma-4-E2B-it",
|
|
658
|
+
"google/gemma-4-E4B-it",
|
|
659
|
+
"Qwen/Qwen3.5-2B",
|
|
660
|
+
"Qwen/Qwen3-VL-2B-Instruct",
|
|
661
|
+
"Qwen/Qwen3.5-4B",
|
|
662
|
+
"nvidia/NVIDIA-Nemotron-3.5-Lightning-30B-A3B-BF16",
|
|
663
|
+
"meta-models/Muse-Glimmer-30B",
|
|
664
|
+
"meta-llama/Llama-3.2-3B-Instruct",
|
|
665
|
+
"microsoft/Phi-4-mini-instruct",
|
|
666
|
+
"ibm-granite/granite-3.3-2b-instruct",
|
|
667
|
+
"bigcode/starcoder2-3b"
|
|
668
|
+
];
|
|
669
|
+
var BASE_MODEL_ALIASES = /* @__PURE__ */ new Map();
|
|
670
|
+
for (const model of SUPPORTED_BASE_MODELS) {
|
|
671
|
+
BASE_MODEL_ALIASES.set(model.toLowerCase(), model);
|
|
672
|
+
}
|
|
673
|
+
for (const [alias, model] of [
|
|
674
|
+
["google/gemma-4-E2B", "google/gemma-4-E2B-it"],
|
|
675
|
+
["google/gemma-4-e2b", "google/gemma-4-E2B-it"],
|
|
676
|
+
["google/gemma-4-e2b-it", "google/gemma-4-E2B-it"],
|
|
677
|
+
["google/gemma-4-E4B", "google/gemma-4-E4B-it"],
|
|
678
|
+
["google/gemma-4-e4b", "google/gemma-4-E4B-it"],
|
|
679
|
+
["google/gemma-4-e4b-it", "google/gemma-4-E4B-it"],
|
|
680
|
+
["qwen/qwen3.5-2b", "Qwen/Qwen3.5-2B"],
|
|
681
|
+
["Qwen/Qwen3.5-2B-Base", "Qwen/Qwen3.5-2B"],
|
|
682
|
+
["qwen/qwen3.5-2b-base", "Qwen/Qwen3.5-2B"],
|
|
683
|
+
["qwen/qwen3-vl-2b-instruct", "Qwen/Qwen3-VL-2B-Instruct"],
|
|
684
|
+
["Qwen/Qwen3-VL-2B", "Qwen/Qwen3-VL-2B-Instruct"],
|
|
685
|
+
["qwen/qwen3-vl-2b", "Qwen/Qwen3-VL-2B-Instruct"],
|
|
686
|
+
["qwen/qwen3.5-4b", "Qwen/Qwen3.5-4B"],
|
|
687
|
+
["Qwen/Qwen3.5-4B-Base", "Qwen/Qwen3.5-4B"],
|
|
688
|
+
["qwen/qwen3.5-4b-base", "Qwen/Qwen3.5-4B"],
|
|
689
|
+
[
|
|
690
|
+
"nvidia/nvidia-nemotron-3.5-lightning-30b-a3b-bf16",
|
|
691
|
+
"nvidia/NVIDIA-Nemotron-3.5-Lightning-30B-A3B-BF16"
|
|
692
|
+
],
|
|
693
|
+
["meta-models/muse-glimmer-30b", "meta-models/Muse-Glimmer-30B"],
|
|
694
|
+
["meta-llama/llama-3.2-3b-instruct", "meta-llama/Llama-3.2-3B-Instruct"],
|
|
695
|
+
["meta-llama/Llama-3.2-3B", "meta-llama/Llama-3.2-3B-Instruct"],
|
|
696
|
+
["meta-llama/llama-3.2-3b", "meta-llama/Llama-3.2-3B-Instruct"],
|
|
697
|
+
["microsoft/phi-4-mini-instruct", "microsoft/Phi-4-mini-instruct"],
|
|
698
|
+
["phi-4-mini-instruct", "microsoft/Phi-4-mini-instruct"],
|
|
699
|
+
["ibm-granite/granite-3.3-2b-instruct", "ibm-granite/granite-3.3-2b-instruct"],
|
|
700
|
+
["granite-3.3-2b-instruct", "ibm-granite/granite-3.3-2b-instruct"],
|
|
701
|
+
["bigcode/starcoder2-3b", "bigcode/starcoder2-3b"],
|
|
702
|
+
["starcoder2-3b", "bigcode/starcoder2-3b"]
|
|
703
|
+
]) {
|
|
704
|
+
BASE_MODEL_ALIASES.set(alias.toLowerCase(), model);
|
|
705
|
+
}
|
|
706
|
+
var UnsupportedBaseModelError = class extends Error {
|
|
707
|
+
constructor(model) {
|
|
708
|
+
const supported = SUPPORTED_BASE_MODELS.join(", ");
|
|
709
|
+
super(
|
|
710
|
+
`Unsupported base_model "${String(model)}". Supported base models: ${supported}`
|
|
711
|
+
);
|
|
712
|
+
this.name = "UnsupportedBaseModelError";
|
|
713
|
+
}
|
|
714
|
+
};
|
|
715
|
+
function canonicalizeBaseModel(model) {
|
|
716
|
+
if (typeof model !== "string" || !model.trim()) {
|
|
717
|
+
throw new UnsupportedBaseModelError(model);
|
|
718
|
+
}
|
|
719
|
+
const canonical = BASE_MODEL_ALIASES.get(model.trim().toLowerCase());
|
|
720
|
+
if (!canonical) {
|
|
721
|
+
throw new UnsupportedBaseModelError(model);
|
|
722
|
+
}
|
|
723
|
+
return canonical;
|
|
724
|
+
}
|
|
725
|
+
function canonicalizeSpecBaseModel(body) {
|
|
726
|
+
if ("base_model" in body && body.base_model !== void 0) {
|
|
727
|
+
return { ...body, base_model: canonicalizeBaseModel(body.base_model) };
|
|
728
|
+
}
|
|
729
|
+
return body;
|
|
730
|
+
}
|
|
731
|
+
|
|
724
732
|
// src/pipeline.ts
|
|
725
733
|
import {
|
|
726
734
|
canonicalPipeline as canonicalPortablePipeline,
|
|
@@ -837,7 +845,7 @@ var RunBody = Type2.Object({
|
|
|
837
845
|
}, { additionalProperties: false })),
|
|
838
846
|
split_ratios: Type2.Optional(SplitRatios)
|
|
839
847
|
}, { additionalProperties: false });
|
|
840
|
-
var
|
|
848
|
+
var BaseModel = Type2.Union(
|
|
841
849
|
SUPPORTED_BASE_MODELS.map((model) => Type2.Literal(model))
|
|
842
850
|
);
|
|
843
851
|
var PipelineDocument = Type2.Object({
|
|
@@ -864,7 +872,7 @@ var CreateSpecBody = Type2.Object({
|
|
|
864
872
|
guidelines: Type2.Optional(Guidelines),
|
|
865
873
|
examples: Examples,
|
|
866
874
|
constraints: Type2.Optional(Guidelines),
|
|
867
|
-
base_model: Type2.Optional(
|
|
875
|
+
base_model: Type2.Optional(BaseModel)
|
|
868
876
|
}, { additionalProperties: false });
|
|
869
877
|
var UpdateSpecBody = Type2.Object({
|
|
870
878
|
name: Type2.Optional(Type2.String({ minLength: 1, maxLength: 255 })),
|
|
@@ -873,7 +881,7 @@ var UpdateSpecBody = Type2.Object({
|
|
|
873
881
|
guidelines: Type2.Optional(Guidelines),
|
|
874
882
|
examples: Type2.Optional(Examples),
|
|
875
883
|
constraints: Type2.Optional(Guidelines),
|
|
876
|
-
base_model: Type2.Optional(
|
|
884
|
+
base_model: Type2.Optional(BaseModel)
|
|
877
885
|
}, { additionalProperties: false });
|
|
878
886
|
function record2(value) {
|
|
879
887
|
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
@@ -1119,7 +1127,7 @@ You have no general filesystem tools. The only workspace-scoped local spec capab
|
|
|
1119
1127
|
}
|
|
1120
1128
|
function defaultAgent(options) {
|
|
1121
1129
|
if (!options.streamSimple) {
|
|
1122
|
-
throw new Error("The configured
|
|
1130
|
+
throw new Error("The configured model runtime cannot stream this model.");
|
|
1123
1131
|
}
|
|
1124
1132
|
let calls = 0;
|
|
1125
1133
|
return new Agent({
|
|
@@ -1562,6 +1570,10 @@ function readConfig() {
|
|
|
1562
1570
|
return {};
|
|
1563
1571
|
}
|
|
1564
1572
|
}
|
|
1573
|
+
var configRevision = 0;
|
|
1574
|
+
function getConfigRevision() {
|
|
1575
|
+
return configRevision;
|
|
1576
|
+
}
|
|
1565
1577
|
function writeConfig(config) {
|
|
1566
1578
|
const dir = getConfigDir();
|
|
1567
1579
|
if (!existsSync2(dir)) mkdirSync2(dir, { recursive: true, mode: 448 });
|
|
@@ -1571,6 +1583,7 @@ function writeConfig(config) {
|
|
|
1571
1583
|
mode: 384
|
|
1572
1584
|
});
|
|
1573
1585
|
chmodSync(path, 384);
|
|
1586
|
+
configRevision += 1;
|
|
1574
1587
|
}
|
|
1575
1588
|
function updateConfig(partial) {
|
|
1576
1589
|
const current = readConfig();
|
|
@@ -1762,9 +1775,7 @@ var SLASH_COMMANDS = [
|
|
|
1762
1775
|
{ path: "/help", description: "Show commands; add a word to filter." },
|
|
1763
1776
|
{ path: "/status", description: "Show lightweight workflow status." },
|
|
1764
1777
|
{ path: "/context", description: "Show the current project and backend context." },
|
|
1765
|
-
{ path: "/
|
|
1766
|
-
{ path: "/mode local", description: "Use the local GPU workflow." },
|
|
1767
|
-
{ path: "/model", description: "Show the active model; /model <id> activates a local model." },
|
|
1778
|
+
{ path: "/model", description: "Show or change the TT agent model." },
|
|
1768
1779
|
{ path: "/cd", description: "Change the shell's working directory." },
|
|
1769
1780
|
{ path: "/clear", description: "Clear the terminal." },
|
|
1770
1781
|
{ path: "/exit", description: "Exit the TT shell." }
|
|
@@ -1874,6 +1885,14 @@ function cloudConfigPath(env, homeDirectory) {
|
|
|
1874
1885
|
const configHome = env.XDG_CONFIG_HOME ? resolve(env.XDG_CONFIG_HOME) : join5(homeDirectory, ".config");
|
|
1875
1886
|
return join5(configHome, "tuned-tensor", "config.json");
|
|
1876
1887
|
}
|
|
1888
|
+
function agentSelectionFrom(env, configAgent) {
|
|
1889
|
+
const stored = configAgent && typeof configAgent === "object" && !Array.isArray(configAgent) ? configAgent : {};
|
|
1890
|
+
const provider = env.TUNED_TENSOR_AGENT_PROVIDER?.trim() || stringField(stored, "provider");
|
|
1891
|
+
const model = env.TUNED_TENSOR_AGENT_MODEL?.trim() || stringField(stored, "model");
|
|
1892
|
+
const thinking = env.TUNED_TENSOR_AGENT_THINKING?.trim() || stringField(stored, "thinking");
|
|
1893
|
+
if (!provider && !model && !thinking) return void 0;
|
|
1894
|
+
return { provider, model, thinking };
|
|
1895
|
+
}
|
|
1877
1896
|
function redactApiKey(key) {
|
|
1878
1897
|
if (!key) return void 0;
|
|
1879
1898
|
if (key.length <= 4) return "\u2026";
|
|
@@ -1971,12 +1990,13 @@ async function discoverShellContext(options = {}) {
|
|
|
1971
1990
|
const storedApiKey = stringField(cloudConfigJson.value, "api_key");
|
|
1972
1991
|
const apiKey = environmentApiKey || storedApiKey;
|
|
1973
1992
|
const baseUrl = env.TUNED_TENSOR_URL?.trim() || stringField(cloudConfigJson.value, "base_url") || "https://tunedtensor.com";
|
|
1993
|
+
const agent = agentSelectionFrom(env, cloudConfigJson.value?.agent);
|
|
1974
1994
|
const environmentTarget = targetFromEnvironment(env);
|
|
1975
1995
|
if (env.TT_TARGET && !environmentTarget) {
|
|
1976
1996
|
warnings.push(`Ignoring invalid TT_TARGET=${JSON.stringify(env.TT_TARGET)}; use cloud or local.`);
|
|
1977
1997
|
}
|
|
1978
|
-
const inferredTarget = environmentTarget ??
|
|
1979
|
-
const targetSource = environmentTarget ? "environment" :
|
|
1998
|
+
const inferredTarget = environmentTarget ?? "local";
|
|
1999
|
+
const targetSource = environmentTarget ? "environment" : "default-local";
|
|
1980
2000
|
const [activeModelId, latestRun] = await Promise.all([
|
|
1981
2001
|
readActiveModelId(storeRoot),
|
|
1982
2002
|
readLatestRun(storeRoot)
|
|
@@ -2001,25 +2021,30 @@ async function discoverShellContext(options = {}) {
|
|
|
2001
2021
|
activeModelId,
|
|
2002
2022
|
latestRun
|
|
2003
2023
|
},
|
|
2024
|
+
agent,
|
|
2004
2025
|
warnings
|
|
2005
2026
|
};
|
|
2006
2027
|
}
|
|
2007
2028
|
function valueOrDash(value) {
|
|
2008
2029
|
return value === void 0 || value === "" ? "\u2014" : String(value);
|
|
2009
2030
|
}
|
|
2031
|
+
function agentLabel(context) {
|
|
2032
|
+
const agent = context.agent;
|
|
2033
|
+
if (!agent?.provider && !agent?.model) return "not configured";
|
|
2034
|
+
const id = [agent.provider, agent.model].filter(Boolean).join("/");
|
|
2035
|
+
return agent.thinking ? `${id} (thinking ${agent.thinking})` : id;
|
|
2036
|
+
}
|
|
2010
2037
|
function targetSourceLabel(source) {
|
|
2011
2038
|
switch (source) {
|
|
2012
2039
|
case "environment":
|
|
2013
2040
|
return "TT_TARGET";
|
|
2014
|
-
case "adjacent-config":
|
|
2015
|
-
return "adjacent local-runner.json";
|
|
2016
2041
|
default:
|
|
2017
2042
|
return "default";
|
|
2018
2043
|
}
|
|
2019
2044
|
}
|
|
2020
2045
|
function formatShellContext(context, selectedTarget, targetSource) {
|
|
2021
2046
|
const specLabel = context.spec ? context.spec.parseError ? `${context.spec.path} (invalid JSON)` : context.spec.path : "not found";
|
|
2022
|
-
const sourceLabel = targetSource === "
|
|
2047
|
+
const sourceLabel = targetSource === "command-option" ? "--target" : targetSourceLabel(targetSource);
|
|
2023
2048
|
const lines = [
|
|
2024
2049
|
`Target ${selectedTarget} (${sourceLabel})`,
|
|
2025
2050
|
`Project ${context.projectName}`,
|
|
@@ -2028,6 +2053,7 @@ function formatShellContext(context, selectedTarget, targetSource) {
|
|
|
2028
2053
|
`Spec ID ${valueOrDash(context.spec?.id)}`,
|
|
2029
2054
|
`Base model ${valueOrDash(context.spec?.baseModel)}`,
|
|
2030
2055
|
`Examples ${valueOrDash(context.spec?.exampleCount)}`,
|
|
2056
|
+
`Agent model ${agentLabel(context)}`,
|
|
2031
2057
|
`Cloud endpoint ${context.cloud.baseUrl}`,
|
|
2032
2058
|
`Cloud auth ${context.cloud.authenticated ? `yes (${context.cloud.keyPrefix})` : "no"}`,
|
|
2033
2059
|
`Local config ${context.local.configPath ?? "not found"}`,
|
|
@@ -2040,7 +2066,8 @@ function formatShellContext(context, selectedTarget, targetSource) {
|
|
|
2040
2066
|
function formatShellStatus(context, selectedTarget) {
|
|
2041
2067
|
const lines = [
|
|
2042
2068
|
`Workflow ${selectedTarget}`,
|
|
2043
|
-
`Spec ${context.spec?.name ?? (context.spec ? "unnamed" : "not found")}
|
|
2069
|
+
`Spec ${context.spec?.name ?? (context.spec ? "unnamed" : "not found")}`,
|
|
2070
|
+
`Agent model ${agentLabel(context)}`
|
|
2044
2071
|
];
|
|
2045
2072
|
if (selectedTarget === "cloud") {
|
|
2046
2073
|
lines.push(
|
|
@@ -2059,6 +2086,103 @@ function formatShellStatus(context, selectedTarget) {
|
|
|
2059
2086
|
return lines;
|
|
2060
2087
|
}
|
|
2061
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
|
+
|
|
2062
2186
|
// src/shell.ts
|
|
2063
2187
|
var AGENT_SLASH_COMMANDS = /* @__PURE__ */ new Set([
|
|
2064
2188
|
"new",
|
|
@@ -2189,7 +2313,7 @@ function routeShellCommand(input, activeMode) {
|
|
|
2189
2313
|
const override = args2[0];
|
|
2190
2314
|
if (override === "cloud" || override === "local") {
|
|
2191
2315
|
if (args2.length === 1) {
|
|
2192
|
-
throw new ShellParseError(`Add a ${override} command,
|
|
2316
|
+
throw new ShellParseError(`Add a ${override} command, e.g. \`${override} runs list\`.`);
|
|
2193
2317
|
}
|
|
2194
2318
|
return { target: override, args: args2.slice(1) };
|
|
2195
2319
|
}
|
|
@@ -2218,7 +2342,6 @@ var SLASH_NAMES = /* @__PURE__ */ new Set([
|
|
|
2218
2342
|
"help",
|
|
2219
2343
|
"status",
|
|
2220
2344
|
"context",
|
|
2221
|
-
"mode",
|
|
2222
2345
|
"model",
|
|
2223
2346
|
"clear",
|
|
2224
2347
|
"cd",
|
|
@@ -2380,7 +2503,12 @@ function helpText(mode, query, palette = false) {
|
|
|
2380
2503
|
`;
|
|
2381
2504
|
}
|
|
2382
2505
|
function activeModelLabel(snapshot) {
|
|
2383
|
-
return snapshot.
|
|
2506
|
+
return snapshot.context.local.activeModelId ?? "base";
|
|
2507
|
+
}
|
|
2508
|
+
function agentModelLabel(context) {
|
|
2509
|
+
const agent = context.agent;
|
|
2510
|
+
if (!agent?.provider && !agent?.model) return "not configured";
|
|
2511
|
+
return [agent.provider, agent.model].filter(Boolean).join("/") || "not configured";
|
|
2384
2512
|
}
|
|
2385
2513
|
function renderShellBanner(snapshot) {
|
|
2386
2514
|
const spec = snapshot.context.spec?.name ?? snapshot.context.spec?.path ?? "no spec";
|
|
@@ -2388,8 +2516,11 @@ function renderShellBanner(snapshot) {
|
|
|
2388
2516
|
const lines = [
|
|
2389
2517
|
heading,
|
|
2390
2518
|
`${accent(snapshot.mode)}${chalk.dim(
|
|
2391
|
-
` \xB7 ${snapshot.context.projectName} \xB7 ${spec}
|
|
2519
|
+
` \xB7 ${snapshot.context.projectName} \xB7 ${spec}`
|
|
2392
2520
|
)}`,
|
|
2521
|
+
chalk.dim(
|
|
2522
|
+
`agent ${agentModelLabel(snapshot.context)} \xB7 workflow model ${activeModelLabel(snapshot)}`
|
|
2523
|
+
),
|
|
2393
2524
|
chalk.dim("ctrl+c stop/clear \xB7 ctrl+d exit \xB7 /help commands \xB7 tab complete"),
|
|
2394
2525
|
"",
|
|
2395
2526
|
chalk.dim("Ask TT anything. Known commands run directly.")
|
|
@@ -2427,20 +2558,19 @@ function resetShellPromptStyle() {
|
|
|
2427
2558
|
return "";
|
|
2428
2559
|
}
|
|
2429
2560
|
var TunedTensorShellSession = class _TunedTensorShellSession {
|
|
2430
|
-
constructor(runner, io, agent, env, contextProvider, version, initialContext) {
|
|
2561
|
+
constructor(runner, io, agent, env, contextProvider, version, agentModelRuntime, initialContext) {
|
|
2431
2562
|
this.runner = runner;
|
|
2432
2563
|
this.io = io;
|
|
2433
2564
|
this.agent = agent;
|
|
2434
2565
|
this.env = env;
|
|
2435
2566
|
this.contextProvider = contextProvider;
|
|
2436
2567
|
this.version = version;
|
|
2437
|
-
this.
|
|
2438
|
-
this.modeSource = initialContext.targetSource;
|
|
2568
|
+
this.agentModelRuntime = agentModelRuntime;
|
|
2439
2569
|
this.cwd = initialContext.cwd;
|
|
2440
2570
|
this.context = initialContext;
|
|
2441
2571
|
}
|
|
2442
|
-
mode;
|
|
2443
|
-
modeSource;
|
|
2572
|
+
mode = "local";
|
|
2573
|
+
modeSource = "default-local";
|
|
2444
2574
|
cwd;
|
|
2445
2575
|
context;
|
|
2446
2576
|
static async create(options) {
|
|
@@ -2455,6 +2585,7 @@ var TunedTensorShellSession = class _TunedTensorShellSession {
|
|
|
2455
2585
|
env,
|
|
2456
2586
|
contextProvider,
|
|
2457
2587
|
options.version,
|
|
2588
|
+
options.agentModelRuntime,
|
|
2458
2589
|
initialContext
|
|
2459
2590
|
);
|
|
2460
2591
|
}
|
|
@@ -2479,26 +2610,67 @@ var TunedTensorShellSession = class _TunedTensorShellSession {
|
|
|
2479
2610
|
async refreshContext() {
|
|
2480
2611
|
this.context = await this.contextProvider({ cwd: this.cwd, env: this.env });
|
|
2481
2612
|
this.cwd = this.context.cwd;
|
|
2482
|
-
if (this.modeSource !== "session" && this.modeSource !== "environment") {
|
|
2483
|
-
this.mode = this.context.inferredTarget;
|
|
2484
|
-
this.modeSource = this.context.targetSource;
|
|
2485
|
-
}
|
|
2486
2613
|
}
|
|
2487
2614
|
writeLines(lines) {
|
|
2488
2615
|
this.io.write(`${lines.join("\n")}
|
|
2489
2616
|
`);
|
|
2490
2617
|
}
|
|
2491
|
-
|
|
2492
|
-
if (this.
|
|
2493
|
-
|
|
2494
|
-
detailLine("Active model", this.context.local.activeModelId ?? "base"),
|
|
2495
|
-
detailLine("Change", "/model <id> to activate a verified local model")
|
|
2496
|
-
]);
|
|
2618
|
+
async requireAgentModelRuntime() {
|
|
2619
|
+
if (!this.agentModelRuntime) {
|
|
2620
|
+
throw new ShellParseError("The local agent model runtime is unavailable.");
|
|
2497
2621
|
}
|
|
2498
|
-
return
|
|
2499
|
-
|
|
2500
|
-
|
|
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>")
|
|
2501
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)") : ""}`;
|
|
2502
2674
|
}
|
|
2503
2675
|
async handleSlash(command) {
|
|
2504
2676
|
switch (command.name) {
|
|
@@ -2520,41 +2692,37 @@ var TunedTensorShellSession = class _TunedTensorShellSession {
|
|
|
2520
2692
|
formatShellContext(this.context, this.mode, this.modeSource)
|
|
2521
2693
|
));
|
|
2522
2694
|
return "continue";
|
|
2523
|
-
case "mode": {
|
|
2524
|
-
if (command.args.length === 0) {
|
|
2525
|
-
this.io.write(`Current workflow: ${this.mode}
|
|
2526
|
-
`);
|
|
2527
|
-
return "continue";
|
|
2528
|
-
}
|
|
2529
|
-
if (command.args.length !== 1 || !["cloud", "local"].includes(command.args[0])) {
|
|
2530
|
-
throw new ShellParseError("Usage: /mode cloud|local");
|
|
2531
|
-
}
|
|
2532
|
-
this.mode = command.args[0];
|
|
2533
|
-
this.modeSource = "session";
|
|
2534
|
-
this.io.write(`${successMark()} Workflow switched to ${this.mode}.
|
|
2535
|
-
`);
|
|
2536
|
-
return "continue";
|
|
2537
|
-
}
|
|
2538
2695
|
case "model": {
|
|
2696
|
+
const runtime = await this.requireAgentModelRuntime();
|
|
2539
2697
|
if (command.args.length === 0) {
|
|
2540
2698
|
await this.refreshContext();
|
|
2541
|
-
this.writeLines(this.
|
|
2699
|
+
this.writeLines(this.renderAgentModel(runtime));
|
|
2542
2700
|
return "continue";
|
|
2543
2701
|
}
|
|
2544
2702
|
if (command.args.length !== 1) {
|
|
2545
|
-
throw new ShellParseError("Usage: /model [model
|
|
2703
|
+
throw new ShellParseError("Usage: /model [<query> | <provider>/<model>]");
|
|
2704
|
+
}
|
|
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";
|
|
2546
2711
|
}
|
|
2547
|
-
if (
|
|
2712
|
+
if (slash === target.length - 1) {
|
|
2548
2713
|
throw new ShellParseError(
|
|
2549
|
-
"
|
|
2714
|
+
"Usage: /model <provider>/<model>, e.g. /model anthropic/claude-sonnet-4-5"
|
|
2550
2715
|
);
|
|
2551
2716
|
}
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
cwd: this.cwd
|
|
2556
|
-
});
|
|
2717
|
+
const provider = target.slice(0, slash);
|
|
2718
|
+
const model = target.slice(slash + 1);
|
|
2719
|
+
const result2 = setAgentModel(runtime, this.env, provider, model);
|
|
2557
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
|
+
);
|
|
2558
2726
|
return "continue";
|
|
2559
2727
|
}
|
|
2560
2728
|
case "clear":
|
|
@@ -2694,7 +2862,8 @@ async function startInteractiveShell(options) {
|
|
|
2694
2862
|
agent: options.agent,
|
|
2695
2863
|
cwd: options.cwd,
|
|
2696
2864
|
env: options.env,
|
|
2697
|
-
version: options.version
|
|
2865
|
+
version: options.version,
|
|
2866
|
+
agentModelRuntime: options.agentModelRuntime
|
|
2698
2867
|
});
|
|
2699
2868
|
const completer = createCommandCompleter(() => session.snapshot().mode);
|
|
2700
2869
|
readline = createInterface({
|
|
@@ -8064,55 +8233,47 @@ function registerPushCommand(parent) {
|
|
|
8064
8233
|
}
|
|
8065
8234
|
|
|
8066
8235
|
// src/commands/agent.ts
|
|
8067
|
-
function selectionOrHint(env) {
|
|
8068
|
-
const selection = getAgentSelection(env);
|
|
8069
|
-
if (!selection) {
|
|
8070
|
-
throw new Error(
|
|
8071
|
-
"The local agent is not configured. Run `tt agent configure --provider <provider> --model <model>`."
|
|
8072
|
-
);
|
|
8073
|
-
}
|
|
8074
|
-
return selection;
|
|
8075
|
-
}
|
|
8076
8236
|
function registerAgentCommands(parent, options) {
|
|
8077
|
-
const agent = parent.command("agent").description("Configure the laptop-local
|
|
8237
|
+
const agent = parent.command("agent").description("Configure the laptop-local TT agent");
|
|
8078
8238
|
agent.command("status").description("Show the selected local provider, model, thinking, and auth state").action(async () => {
|
|
8079
|
-
const selection = selectionOrHint(options.env);
|
|
8080
8239
|
const runtime = await options.getRuntime();
|
|
8081
|
-
const
|
|
8082
|
-
|
|
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
|
+
}
|
|
8083
8246
|
const value = {
|
|
8084
8247
|
execution: "local",
|
|
8085
|
-
provider:
|
|
8086
|
-
|
|
8087
|
-
|
|
8088
|
-
|
|
8089
|
-
|
|
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
|
|
8090
8255
|
};
|
|
8256
|
+
const modelLabel = summary.modelName && summary.modelName !== summary.model ? `${summary.modelName} (${summary.provider}/${summary.model})` : `${summary.provider}/${summary.model}`;
|
|
8091
8257
|
options.output.write(isJsonMode() ? `${JSON.stringify(value, null, 2)}
|
|
8092
|
-
` : `Local agent: ${
|
|
8258
|
+
` : `Local agent: ${modelLabel} (thinking: ${value.thinking}, auth: ${value.authenticated ? "configured" : "required"})
|
|
8093
8259
|
`);
|
|
8094
8260
|
});
|
|
8095
|
-
agent.command("models").description("List
|
|
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) => {
|
|
8096
8262
|
const runtime = await options.getRuntime();
|
|
8097
8263
|
if (commandOptions.provider && !runtime.getProviders().some((provider) => provider.id === commandOptions.provider)) {
|
|
8098
|
-
throw new Error(`Unknown
|
|
8099
|
-
}
|
|
8100
|
-
const models = runtime
|
|
8101
|
-
|
|
8102
|
-
|
|
8103
|
-
|
|
8104
|
-
id: model.id,
|
|
8105
|
-
name: model.name ?? model.id,
|
|
8106
|
-
authenticated: runtime.hasConfiguredAuth(model.provider),
|
|
8107
|
-
thinking: model.reasoning !== false
|
|
8108
|
-
}));
|
|
8264
|
+
throw new Error(`Unknown provider "${commandOptions.provider}".`);
|
|
8265
|
+
}
|
|
8266
|
+
const models = listAgentModels(runtime, {
|
|
8267
|
+
provider: commandOptions.provider,
|
|
8268
|
+
includeUnauthenticated: commandOptions.all
|
|
8269
|
+
});
|
|
8109
8270
|
if (isJsonMode()) {
|
|
8110
8271
|
options.output.write(`${JSON.stringify({ data: models }, null, 2)}
|
|
8111
8272
|
`);
|
|
8112
8273
|
return;
|
|
8113
8274
|
}
|
|
8114
8275
|
if (models.length === 0) {
|
|
8115
|
-
options.output.write("No matching authenticated
|
|
8276
|
+
options.output.write("No matching authenticated models. Use --all to inspect the full catalog.\n");
|
|
8116
8277
|
return;
|
|
8117
8278
|
}
|
|
8118
8279
|
for (const model of models) {
|
|
@@ -8120,20 +8281,17 @@ function registerAgentCommands(parent, options) {
|
|
|
8120
8281
|
`);
|
|
8121
8282
|
}
|
|
8122
8283
|
});
|
|
8123
|
-
agent.command("configure").description("Select the local
|
|
8124
|
-
|
|
8125
|
-
|
|
8126
|
-
|
|
8127
|
-
|
|
8128
|
-
|
|
8129
|
-
|
|
8130
|
-
|
|
8131
|
-
};
|
|
8132
|
-
resolveAgentModel(await options.getRuntime(), selection);
|
|
8133
|
-
updateConfig({ agent: selection });
|
|
8134
|
-
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 };
|
|
8135
8293
|
options.output.write(isJsonMode() ? `${JSON.stringify(value, null, 2)}
|
|
8136
|
-
` : `Configured local agent: ${selection.provider}/${selection.model} (thinking: ${selection.thinking}).
|
|
8294
|
+
` : `Configured local agent: ${result2.selection.provider}/${result2.selection.model} (thinking: ${result2.selection.thinking}).
|
|
8137
8295
|
`);
|
|
8138
8296
|
});
|
|
8139
8297
|
}
|
|
@@ -8303,14 +8461,14 @@ function formatCliUpdateNotice(update) {
|
|
|
8303
8461
|
}
|
|
8304
8462
|
|
|
8305
8463
|
// src/cli.ts
|
|
8306
|
-
async function createDefaultAgentClient(runtime, env, cloud, workspaceRoot) {
|
|
8464
|
+
async function createDefaultAgentClient(runtime, env, cloud, workspaceRoot, getModelRuntime) {
|
|
8307
8465
|
const selection = getAgentSelection(env);
|
|
8308
8466
|
if (!selection) {
|
|
8309
8467
|
throw new Error(
|
|
8310
8468
|
"The laptop-local agent is not configured. Run `tt agent models --all`, then `tt agent configure --provider <provider> --model <model>`."
|
|
8311
8469
|
);
|
|
8312
8470
|
}
|
|
8313
|
-
const modelRuntime =
|
|
8471
|
+
const modelRuntime = await getModelRuntime();
|
|
8314
8472
|
const clientOpts = { apiKey: cloud.apiKey, baseUrl: cloud.baseUrl };
|
|
8315
8473
|
const toolApi = runtime.agentToolApi ?? {
|
|
8316
8474
|
get: async (path, query) => await get(path, query, clientOpts),
|
|
@@ -8343,11 +8501,23 @@ async function createDefaultAgentClient(runtime, env, cloud, workspaceRoot) {
|
|
|
8343
8501
|
createAgent: runtime.createPiAgent
|
|
8344
8502
|
});
|
|
8345
8503
|
}
|
|
8346
|
-
function
|
|
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) {
|
|
8347
8514
|
let pending;
|
|
8515
|
+
let builtRevision = -1;
|
|
8348
8516
|
const client = () => {
|
|
8349
|
-
|
|
8350
|
-
|
|
8517
|
+
const revision = getConfigRevision();
|
|
8518
|
+
if (!pending || builtRevision !== revision) {
|
|
8519
|
+
builtRevision = revision;
|
|
8520
|
+
const attempt = createDefaultAgentClient(runtime, env, cloud, workspaceRoot, getModelRuntime);
|
|
8351
8521
|
pending = attempt;
|
|
8352
8522
|
attempt.catch(() => {
|
|
8353
8523
|
if (pending === attempt) pending = void 0;
|
|
@@ -8447,13 +8617,7 @@ function createProgram(version, runtime = {}) {
|
|
|
8447
8617
|
const invokeLocal = runtime.runLocalCommand ?? executeLocalCommand;
|
|
8448
8618
|
const launchShell = runtime.startShell ?? startInteractiveShell;
|
|
8449
8619
|
const cwd = runtime.cwd ?? process.cwd();
|
|
8450
|
-
const
|
|
8451
|
-
let modelRuntimePromise;
|
|
8452
|
-
const getModelRuntime = async () => {
|
|
8453
|
-
if (injectedModelRuntime) return injectedModelRuntime;
|
|
8454
|
-
modelRuntimePromise ??= createPiModelRuntime();
|
|
8455
|
-
return await modelRuntimePromise;
|
|
8456
|
-
};
|
|
8620
|
+
const getModelRuntime = createModelRuntimeGetter(runtime);
|
|
8457
8621
|
const shellRunner = async (request2) => {
|
|
8458
8622
|
const root = program.opts();
|
|
8459
8623
|
const args2 = request2.target === "local" ? ["local", ...request2.args] : request2.args;
|
|
@@ -8472,7 +8636,7 @@ function createProgram(version, runtime = {}) {
|
|
|
8472
8636
|
client: runtime.agentClient ?? createLazyDefaultAgentClient(runtime, shellEnvironment, {
|
|
8473
8637
|
apiKey: root.apiKey ?? shellEnvironment.TUNED_TENSOR_API_KEY,
|
|
8474
8638
|
baseUrl: root.baseUrl ?? shellEnvironment.TUNED_TENSOR_URL
|
|
8475
|
-
}, cwd),
|
|
8639
|
+
}, cwd, getModelRuntime),
|
|
8476
8640
|
output,
|
|
8477
8641
|
error
|
|
8478
8642
|
});
|
|
@@ -8484,7 +8648,8 @@ function createProgram(version, runtime = {}) {
|
|
|
8484
8648
|
error,
|
|
8485
8649
|
cwd,
|
|
8486
8650
|
env: shellEnvironment,
|
|
8487
|
-
version
|
|
8651
|
+
version,
|
|
8652
|
+
agentModelRuntime: getModelRuntime
|
|
8488
8653
|
});
|
|
8489
8654
|
};
|
|
8490
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(
|
|
@@ -8588,7 +8753,7 @@ function createProgram(version, runtime = {}) {
|
|
|
8588
8753
|
});
|
|
8589
8754
|
applyExitCode(result2);
|
|
8590
8755
|
});
|
|
8591
|
-
program.command("shell").description("Open the
|
|
8756
|
+
program.command("shell").description("Open the conversational terminal (local by default)").action(openShell);
|
|
8592
8757
|
program.addHelpText(
|
|
8593
8758
|
"after",
|
|
8594
8759
|
`
|
|
@@ -8645,11 +8810,12 @@ async function runCli(version, runtime = {}) {
|
|
|
8645
8810
|
`);
|
|
8646
8811
|
}
|
|
8647
8812
|
const invokeSelf = runtime.runSelfCommand ?? runSelfCommand;
|
|
8813
|
+
const getModelRuntime = createModelRuntimeGetter(runtime);
|
|
8648
8814
|
const agent = createShellAgent({
|
|
8649
8815
|
client: runtime.agentClient ?? createLazyDefaultAgentClient(runtime, env, {
|
|
8650
8816
|
apiKey: env.TUNED_TENSOR_API_KEY,
|
|
8651
8817
|
baseUrl: env.TUNED_TENSOR_URL
|
|
8652
|
-
}, runtime.cwd ?? process.cwd()),
|
|
8818
|
+
}, runtime.cwd ?? process.cwd(), getModelRuntime),
|
|
8653
8819
|
output,
|
|
8654
8820
|
error
|
|
8655
8821
|
});
|
|
@@ -8668,7 +8834,8 @@ async function runCli(version, runtime = {}) {
|
|
|
8668
8834
|
error,
|
|
8669
8835
|
cwd: runtime.cwd ?? process.cwd(),
|
|
8670
8836
|
env,
|
|
8671
|
-
version
|
|
8837
|
+
version,
|
|
8838
|
+
agentModelRuntime: getModelRuntime
|
|
8672
8839
|
});
|
|
8673
8840
|
return;
|
|
8674
8841
|
}
|
|
@@ -8677,7 +8844,7 @@ async function runCli(version, runtime = {}) {
|
|
|
8677
8844
|
}
|
|
8678
8845
|
|
|
8679
8846
|
// src/index.ts
|
|
8680
|
-
runCli("0.
|
|
8847
|
+
runCli("0.12.0-beta.1").catch((err) => {
|
|
8681
8848
|
reportError(err);
|
|
8682
8849
|
process.exit(1);
|
|
8683
8850
|
});
|