@tuned-tensor/cli 0.10.0 → 0.12.0-beta.0
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 +21 -6
- package/dist/{chunk-DAP2Z7EZ.js → chunk-HDGBDHOB.js} +474 -74
- package/dist/chunk-HDGBDHOB.js.map +1 -0
- package/dist/index.js +235 -84
- 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 +5 -1
- 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 })),
|
|
@@ -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;
|
|
@@ -1762,8 +1770,10 @@ var SLASH_COMMANDS = [
|
|
|
1762
1770
|
{ path: "/help", description: "Show commands; add a word to filter." },
|
|
1763
1771
|
{ path: "/status", description: "Show lightweight workflow status." },
|
|
1764
1772
|
{ path: "/context", description: "Show the current project and backend context." },
|
|
1765
|
-
{ path: "/
|
|
1766
|
-
{ path: "/
|
|
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." },
|
|
1767
1777
|
{ path: "/model", description: "Show the active model; /model <id> activates a local model." },
|
|
1768
1778
|
{ path: "/cd", description: "Change the shell's working directory." },
|
|
1769
1779
|
{ path: "/clear", description: "Clear the terminal." },
|
|
@@ -1874,6 +1884,14 @@ function cloudConfigPath(env, homeDirectory) {
|
|
|
1874
1884
|
const configHome = env.XDG_CONFIG_HOME ? resolve(env.XDG_CONFIG_HOME) : join5(homeDirectory, ".config");
|
|
1875
1885
|
return join5(configHome, "tuned-tensor", "config.json");
|
|
1876
1886
|
}
|
|
1887
|
+
function agentSelectionFrom(env, configAgent) {
|
|
1888
|
+
const stored = configAgent && typeof configAgent === "object" && !Array.isArray(configAgent) ? configAgent : {};
|
|
1889
|
+
const provider = env.TUNED_TENSOR_AGENT_PROVIDER?.trim() || stringField(stored, "provider");
|
|
1890
|
+
const model = env.TUNED_TENSOR_AGENT_MODEL?.trim() || stringField(stored, "model");
|
|
1891
|
+
const thinking = env.TUNED_TENSOR_AGENT_THINKING?.trim() || stringField(stored, "thinking");
|
|
1892
|
+
if (!provider && !model && !thinking) return void 0;
|
|
1893
|
+
return { provider, model, thinking };
|
|
1894
|
+
}
|
|
1877
1895
|
function redactApiKey(key) {
|
|
1878
1896
|
if (!key) return void 0;
|
|
1879
1897
|
if (key.length <= 4) return "\u2026";
|
|
@@ -1971,6 +1989,7 @@ async function discoverShellContext(options = {}) {
|
|
|
1971
1989
|
const storedApiKey = stringField(cloudConfigJson.value, "api_key");
|
|
1972
1990
|
const apiKey = environmentApiKey || storedApiKey;
|
|
1973
1991
|
const baseUrl = env.TUNED_TENSOR_URL?.trim() || stringField(cloudConfigJson.value, "base_url") || "https://tunedtensor.com";
|
|
1992
|
+
const agent = agentSelectionFrom(env, cloudConfigJson.value?.agent);
|
|
1974
1993
|
const environmentTarget = targetFromEnvironment(env);
|
|
1975
1994
|
if (env.TT_TARGET && !environmentTarget) {
|
|
1976
1995
|
warnings.push(`Ignoring invalid TT_TARGET=${JSON.stringify(env.TT_TARGET)}; use cloud or local.`);
|
|
@@ -2001,12 +2020,19 @@ async function discoverShellContext(options = {}) {
|
|
|
2001
2020
|
activeModelId,
|
|
2002
2021
|
latestRun
|
|
2003
2022
|
},
|
|
2023
|
+
agent,
|
|
2004
2024
|
warnings
|
|
2005
2025
|
};
|
|
2006
2026
|
}
|
|
2007
2027
|
function valueOrDash(value) {
|
|
2008
2028
|
return value === void 0 || value === "" ? "\u2014" : String(value);
|
|
2009
2029
|
}
|
|
2030
|
+
function agentLabel(context) {
|
|
2031
|
+
const agent = context.agent;
|
|
2032
|
+
if (!agent?.provider && !agent?.model) return "not configured";
|
|
2033
|
+
const id = [agent.provider, agent.model].filter(Boolean).join("/");
|
|
2034
|
+
return agent.thinking ? `${id} (thinking ${agent.thinking})` : id;
|
|
2035
|
+
}
|
|
2010
2036
|
function targetSourceLabel(source) {
|
|
2011
2037
|
switch (source) {
|
|
2012
2038
|
case "environment":
|
|
@@ -2028,6 +2054,7 @@ function formatShellContext(context, selectedTarget, targetSource) {
|
|
|
2028
2054
|
`Spec ID ${valueOrDash(context.spec?.id)}`,
|
|
2029
2055
|
`Base model ${valueOrDash(context.spec?.baseModel)}`,
|
|
2030
2056
|
`Examples ${valueOrDash(context.spec?.exampleCount)}`,
|
|
2057
|
+
`Agent model ${agentLabel(context)}`,
|
|
2031
2058
|
`Cloud endpoint ${context.cloud.baseUrl}`,
|
|
2032
2059
|
`Cloud auth ${context.cloud.authenticated ? `yes (${context.cloud.keyPrefix})` : "no"}`,
|
|
2033
2060
|
`Local config ${context.local.configPath ?? "not found"}`,
|
|
@@ -2040,7 +2067,8 @@ function formatShellContext(context, selectedTarget, targetSource) {
|
|
|
2040
2067
|
function formatShellStatus(context, selectedTarget) {
|
|
2041
2068
|
const lines = [
|
|
2042
2069
|
`Workflow ${selectedTarget}`,
|
|
2043
|
-
`Spec ${context.spec?.name ?? (context.spec ? "unnamed" : "not found")}
|
|
2070
|
+
`Spec ${context.spec?.name ?? (context.spec ? "unnamed" : "not found")}`,
|
|
2071
|
+
`Agent model ${agentLabel(context)}`
|
|
2044
2072
|
];
|
|
2045
2073
|
if (selectedTarget === "cloud") {
|
|
2046
2074
|
lines.push(
|
|
@@ -2219,6 +2247,8 @@ var SLASH_NAMES = /* @__PURE__ */ new Set([
|
|
|
2219
2247
|
"status",
|
|
2220
2248
|
"context",
|
|
2221
2249
|
"mode",
|
|
2250
|
+
"cloud",
|
|
2251
|
+
"local",
|
|
2222
2252
|
"model",
|
|
2223
2253
|
"clear",
|
|
2224
2254
|
"cd",
|
|
@@ -2382,14 +2412,22 @@ function helpText(mode, query, palette = false) {
|
|
|
2382
2412
|
function activeModelLabel(snapshot) {
|
|
2383
2413
|
return snapshot.mode === "local" ? snapshot.context.local.activeModelId ?? "base" : snapshot.context.spec?.baseModel ?? "\u2014";
|
|
2384
2414
|
}
|
|
2415
|
+
function agentModelLabel(context) {
|
|
2416
|
+
const agent = context.agent;
|
|
2417
|
+
if (!agent?.provider && !agent?.model) return "not configured";
|
|
2418
|
+
return [agent.provider, agent.model].filter(Boolean).join("/") || "not configured";
|
|
2419
|
+
}
|
|
2385
2420
|
function renderShellBanner(snapshot) {
|
|
2386
2421
|
const spec = snapshot.context.spec?.name ?? snapshot.context.spec?.path ?? "no spec";
|
|
2387
2422
|
const heading = snapshot.version ? `${accent.bold("tt")} ${chalk.dim(`v${snapshot.version}`)}` : accent.bold("tt");
|
|
2388
2423
|
const lines = [
|
|
2389
2424
|
heading,
|
|
2390
2425
|
`${accent(snapshot.mode)}${chalk.dim(
|
|
2391
|
-
` \xB7 ${snapshot.context.projectName} \xB7 ${spec}
|
|
2426
|
+
` \xB7 ${snapshot.context.projectName} \xB7 ${spec}`
|
|
2392
2427
|
)}`,
|
|
2428
|
+
chalk.dim(
|
|
2429
|
+
`agent ${agentModelLabel(snapshot.context)} \xB7 workflow model ${activeModelLabel(snapshot)}`
|
|
2430
|
+
),
|
|
2393
2431
|
chalk.dim("ctrl+c stop/clear \xB7 ctrl+d exit \xB7 /help commands \xB7 tab complete"),
|
|
2394
2432
|
"",
|
|
2395
2433
|
chalk.dim("Ask TT anything. Known commands run directly.")
|
|
@@ -2535,6 +2573,14 @@ var TunedTensorShellSession = class _TunedTensorShellSession {
|
|
|
2535
2573
|
`);
|
|
2536
2574
|
return "continue";
|
|
2537
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";
|
|
2538
2584
|
case "model": {
|
|
2539
2585
|
if (command.args.length === 0) {
|
|
2540
2586
|
await this.refreshContext();
|
|
@@ -8080,16 +8126,22 @@ function registerAgentCommands(parent, options) {
|
|
|
8080
8126
|
const runtime = await options.getRuntime();
|
|
8081
8127
|
const resolved = resolveAgentModelDefinition(runtime, selection);
|
|
8082
8128
|
const authenticated = runtime.hasConfiguredAuth(selection.provider);
|
|
8129
|
+
const providerName = runtime.getProviders().find(
|
|
8130
|
+
(provider) => provider.id === selection.provider
|
|
8131
|
+
)?.name;
|
|
8083
8132
|
const value = {
|
|
8084
8133
|
execution: "local",
|
|
8085
8134
|
provider: selection.provider,
|
|
8135
|
+
provider_name: providerName,
|
|
8086
8136
|
model: selection.model,
|
|
8137
|
+
model_name: resolved.model.name,
|
|
8087
8138
|
thinking: selection.thinking,
|
|
8088
8139
|
authenticated,
|
|
8089
8140
|
supports_thinking: resolved.model.reasoning !== false
|
|
8090
8141
|
};
|
|
8142
|
+
const modelLabel = resolved.model.name && resolved.model.name !== selection.model ? `${resolved.model.name} (${selection.provider}/${selection.model})` : `${selection.provider}/${selection.model}`;
|
|
8091
8143
|
options.output.write(isJsonMode() ? `${JSON.stringify(value, null, 2)}
|
|
8092
|
-
` : `Local agent: ${
|
|
8144
|
+
` : `Local agent: ${modelLabel} (thinking: ${value.thinking}, auth: ${authenticated ? "configured" : "required"})
|
|
8093
8145
|
`);
|
|
8094
8146
|
});
|
|
8095
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) => {
|
|
@@ -8213,6 +8265,95 @@ function registerPipelineCommands(parent) {
|
|
|
8213
8265
|
});
|
|
8214
8266
|
}
|
|
8215
8267
|
|
|
8268
|
+
// src/update-check.ts
|
|
8269
|
+
var PACKAGE_LATEST_URL = "https://registry.npmjs.org/@tuned-tensor%2fcli/latest";
|
|
8270
|
+
function parseVersion(version) {
|
|
8271
|
+
const match = version.trim().match(
|
|
8272
|
+
/^v?(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/
|
|
8273
|
+
);
|
|
8274
|
+
if (!match) return null;
|
|
8275
|
+
const prerelease = match[4]?.split(".") ?? [];
|
|
8276
|
+
if (prerelease.some((part) => /^0\d+$/.test(part))) return null;
|
|
8277
|
+
return {
|
|
8278
|
+
major: BigInt(match[1]),
|
|
8279
|
+
minor: BigInt(match[2]),
|
|
8280
|
+
patch: BigInt(match[3]),
|
|
8281
|
+
prerelease
|
|
8282
|
+
};
|
|
8283
|
+
}
|
|
8284
|
+
function comparePrerelease(left, right) {
|
|
8285
|
+
if (left.length === 0 && right.length === 0) return 0;
|
|
8286
|
+
if (left.length === 0) return 1;
|
|
8287
|
+
if (right.length === 0) return -1;
|
|
8288
|
+
for (let index = 0; index < Math.max(left.length, right.length); index += 1) {
|
|
8289
|
+
const leftPart = left[index];
|
|
8290
|
+
const rightPart = right[index];
|
|
8291
|
+
if (leftPart === void 0) return -1;
|
|
8292
|
+
if (rightPart === void 0) return 1;
|
|
8293
|
+
if (leftPart === rightPart) continue;
|
|
8294
|
+
const leftNumeric = /^\d+$/.test(leftPart);
|
|
8295
|
+
const rightNumeric = /^\d+$/.test(rightPart);
|
|
8296
|
+
if (leftNumeric && rightNumeric) {
|
|
8297
|
+
if (leftPart.length !== rightPart.length) {
|
|
8298
|
+
return leftPart.length > rightPart.length ? 1 : -1;
|
|
8299
|
+
}
|
|
8300
|
+
return leftPart > rightPart ? 1 : -1;
|
|
8301
|
+
}
|
|
8302
|
+
if (leftNumeric !== rightNumeric) return leftNumeric ? -1 : 1;
|
|
8303
|
+
return leftPart > rightPart ? 1 : -1;
|
|
8304
|
+
}
|
|
8305
|
+
return 0;
|
|
8306
|
+
}
|
|
8307
|
+
function compareVersions(left, right) {
|
|
8308
|
+
for (const key of ["major", "minor", "patch"]) {
|
|
8309
|
+
if (left[key] !== right[key]) return left[key] > right[key] ? 1 : -1;
|
|
8310
|
+
}
|
|
8311
|
+
return comparePrerelease(left.prerelease, right.prerelease);
|
|
8312
|
+
}
|
|
8313
|
+
async function checkForCliUpdate(currentVersion, options = {}) {
|
|
8314
|
+
const current = parseVersion(currentVersion);
|
|
8315
|
+
if (!current) return null;
|
|
8316
|
+
const controller = new AbortController();
|
|
8317
|
+
const timeoutMs = options.timeoutMs ?? 750;
|
|
8318
|
+
let timeout;
|
|
8319
|
+
const request2 = (async () => {
|
|
8320
|
+
try {
|
|
8321
|
+
const response = await (options.fetchImpl ?? fetch)(PACKAGE_LATEST_URL, {
|
|
8322
|
+
headers: { accept: "application/json" },
|
|
8323
|
+
signal: controller.signal
|
|
8324
|
+
});
|
|
8325
|
+
if (!response.ok) return null;
|
|
8326
|
+
const payload = await response.json();
|
|
8327
|
+
if (typeof payload.version !== "string") return null;
|
|
8328
|
+
const latest = parseVersion(payload.version);
|
|
8329
|
+
if (!latest || latest.prerelease.length > 0 || compareVersions(latest, current) <= 0) return null;
|
|
8330
|
+
return {
|
|
8331
|
+
currentVersion,
|
|
8332
|
+
latestVersion: payload.version
|
|
8333
|
+
};
|
|
8334
|
+
} catch {
|
|
8335
|
+
return null;
|
|
8336
|
+
}
|
|
8337
|
+
})();
|
|
8338
|
+
const deadline = new Promise((resolve8) => {
|
|
8339
|
+
timeout = setTimeout(() => {
|
|
8340
|
+
controller.abort();
|
|
8341
|
+
resolve8(null);
|
|
8342
|
+
}, timeoutMs);
|
|
8343
|
+
});
|
|
8344
|
+
try {
|
|
8345
|
+
return await Promise.race([request2, deadline]);
|
|
8346
|
+
} finally {
|
|
8347
|
+
if (timeout) clearTimeout(timeout);
|
|
8348
|
+
}
|
|
8349
|
+
}
|
|
8350
|
+
function formatCliUpdateNotice(update) {
|
|
8351
|
+
return [
|
|
8352
|
+
`Update available: tt ${update.currentVersion} \u2192 ${update.latestVersion}`,
|
|
8353
|
+
"Upgrade with: npm install -g @tuned-tensor/cli@latest"
|
|
8354
|
+
].join("\n");
|
|
8355
|
+
}
|
|
8356
|
+
|
|
8216
8357
|
// src/cli.ts
|
|
8217
8358
|
async function createDefaultAgentClient(runtime, env, cloud, workspaceRoot) {
|
|
8218
8359
|
const selection = getAgentSelection(env);
|
|
@@ -8543,9 +8684,19 @@ async function runCli(version, runtime = {}) {
|
|
|
8543
8684
|
stdoutIsTTY: runtime.stdoutIsTTY ?? process.stdout.isTTY,
|
|
8544
8685
|
env
|
|
8545
8686
|
})) {
|
|
8546
|
-
const invokeSelf = runtime.runSelfCommand ?? runSelfCommand;
|
|
8547
8687
|
const output = runtime.stdout ?? process.stdout;
|
|
8548
8688
|
const error = runtime.stderr ?? process.stderr;
|
|
8689
|
+
let update = null;
|
|
8690
|
+
try {
|
|
8691
|
+
update = await (runtime.checkForUpdate ?? checkForCliUpdate)(version);
|
|
8692
|
+
} catch {
|
|
8693
|
+
}
|
|
8694
|
+
if (update) {
|
|
8695
|
+
error.write(`${formatCliUpdateNotice(update)}
|
|
8696
|
+
|
|
8697
|
+
`);
|
|
8698
|
+
}
|
|
8699
|
+
const invokeSelf = runtime.runSelfCommand ?? runSelfCommand;
|
|
8549
8700
|
const agent = createShellAgent({
|
|
8550
8701
|
client: runtime.agentClient ?? createLazyDefaultAgentClient(runtime, env, {
|
|
8551
8702
|
apiKey: env.TUNED_TENSOR_API_KEY,
|
|
@@ -8578,7 +8729,7 @@ async function runCli(version, runtime = {}) {
|
|
|
8578
8729
|
}
|
|
8579
8730
|
|
|
8580
8731
|
// src/index.ts
|
|
8581
|
-
runCli("0.
|
|
8732
|
+
runCli("0.12.0-beta.0").catch((err) => {
|
|
8582
8733
|
reportError(err);
|
|
8583
8734
|
process.exit(1);
|
|
8584
8735
|
});
|