@tuned-tensor/cli 0.13.1-beta.1 → 0.13.1-beta.2

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 CHANGED
@@ -84,7 +84,7 @@ such as `runs list` and `doctor` work immediately. Chat waits until you choose
84
84
  a provider and model from inside the shell:
85
85
 
86
86
  ```text
87
- tt v0.13.1-beta.1
87
+ tt v0.13.1-beta.2
88
88
  agent not configured · workflow model base
89
89
  ctrl+c stop/clear · ctrl+d exit · /help commands · tab complete
90
90
 
@@ -113,7 +113,7 @@ After a model is selected, the banner shows it and ordinary sentences go to
113
113
  the agent:
114
114
 
115
115
  ```text
116
- tt v0.13.1-beta.1
116
+ tt v0.13.1-beta.2
117
117
  agent anthropic/claude-sonnet-4-5 · workflow model base
118
118
  ctrl+c stop/clear · ctrl+d exit · /help commands · tab complete
119
119
 
@@ -174,28 +174,47 @@ explicitly.
174
174
 
175
175
  ## Composable pipelines (v1)
176
176
 
177
- A pipeline is an ordered JSON recipe. Version 1 supports `train`, `evaluate`,
178
- and `compare` steps. This CLI executes local plans only. The v1 evaluator is
179
- `evaluate.with.evaluator: "behavior"`. `evaluate.with.model` is `"base"` or
180
- `{ "from": "step.model" }`; `compare.with.before` and
181
- `after` are `{ "from": "step.report" }`. References must point to an earlier
182
- step and to an output the producer actually exposes. The document contract
183
- itself is defined by the published `@tuned-tensor/pipeline-contract` package;
184
- the CLI adds only execution planning (step selection) on top of it.
177
+ A pipeline is an ordered JSON recipe. This CLI executes local plans only. The
178
+ portable document contract lives in `@tuned-tensor/pipeline-contract`. The CLI
179
+ adds execution planning (step selection) on top of it.
180
+
181
+ Two local engines share that document version:
182
+
183
+ - **Adapter** (default): LoRA SFT on a certified Hugging Face checkpoint.
184
+ `tt run` and `tt pipeline` both work. Uses `train` / `evaluate` / `compare`
185
+ with `evaluate.with.evaluator: "behavior"`.
186
+ - **Foundation**: from-scratch tokenizer + GPT. `tt pipeline` only. Uses
187
+ `tokenize` / `pretrain` / `finetune` / optional `rl` plus `bpb`, `chat`, and
188
+ `inference` evaluators. Requires a foundation `tunedtensor.json`
189
+ (`engine: "foundation"`, at least two examples, no `base_model`).
190
+
191
+ The foundation engine is a small, readable local baseline inspired by Andrej
192
+ Karpathy's [nanochat](https://github.com/karpathy/nanochat), not a port of its
193
+ compute-optimal training stack. The first version deliberately builds a bounded
194
+ pretraining corpus from the spec prompt and examples, reports chat accuracy on
195
+ those same contract examples, and supports one training process. Foundation
196
+ plans reject `compare` before creating run artifacts; comparison remains an
197
+ adapter-engine capability. Optional RL samples one seeded on-policy completion
198
+ per step with a sparse last-number exact reward and therefore requires a numeric
199
+ expected output for every example. Treat those metrics as an end-to-end
200
+ execution and overfit check—not held-out capability or multi-GPU evidence.
185
201
 
186
202
  ```bash
187
203
  tt pipeline init --file pipeline.json
204
+ tt pipeline init --engine foundation --file foundation.pipeline.json
188
205
  tt pipeline validate --file pipeline.json
189
206
  tt --json pipeline plan --file pipeline.json
190
207
  tt --json pipeline run --dry-run --file pipeline.json --only baseline
191
208
  tt --json pipeline run --file pipeline.json \
192
209
  --spec tunedtensor.json --config local-runner.json
210
+ tt init --engine foundation --name "Tiny GPT"
211
+ tt --json pipeline run --spec tunedtensor.json --dry-run
193
212
  ```
194
213
 
195
214
  `--only` and `--skip` preserve dependency safety: a selected step cannot refer
196
215
  to an omitted predecessor. Cloud-targeted steps fail closed unless you pass
197
- `--dry-run`. The TT agent may describe, validate, and prepare a plan, but has
198
- no direct pipeline-execute tool.
216
+ `--dry-run`. Foundation documents are local-only. The TT agent may describe,
217
+ validate, and prepare a plan, but has no direct pipeline-execute tool.
199
218
 
200
219
  ## Quick start
201
220
 
@@ -851,6 +851,28 @@ var specSnapshotSchema = z.object({
851
851
  constraints: z.array(z.string()).default([]),
852
852
  base_model: z.string().transform((value) => canonicalizeTrainingModel(value))
853
853
  }).strict();
854
+ var foundationHyperparametersSchema = z.object({
855
+ vocab_size: z.number().int().min(64).max(65536).default(256),
856
+ max_chars: z.number().int().min(1e3).max(2e9).default(2e4),
857
+ depth: z.number().int().min(1).max(64).default(2),
858
+ pretrain_steps: z.number().int().min(1).max(1e7).default(2),
859
+ finetune_steps: z.number().int().min(1).max(1e7).default(2),
860
+ rl_steps: z.number().int().min(0).max(1e7).default(0),
861
+ batch_size: z.number().int().min(1).max(1024).default(2),
862
+ sequence_length: z.number().int().min(16).max(8192).default(64),
863
+ nproc_per_node: z.number().int().min(1).max(16).default(1)
864
+ }).strict();
865
+ var localFoundationSpecFileSchema = z.object({
866
+ engine: z.literal("foundation"),
867
+ id: z.string().uuid().optional(),
868
+ name: z.string().min(1),
869
+ description: z.string().default(""),
870
+ system_prompt: z.string().default(""),
871
+ guidelines: z.array(z.string()).default([]),
872
+ examples: z.array(behaviorSpecExampleSchema).min(2),
873
+ constraints: z.array(z.string()).default([]),
874
+ foundation: foundationHyperparametersSchema
875
+ }).strict();
854
876
  var datasetPrebuiltSchema = z.object({
855
877
  training: z.string().min(1),
856
878
  validation: z.string().min(1).optional(),
@@ -895,11 +917,16 @@ var fineTuneRunRequestSchema = z.object({
895
917
  });
896
918
  }
897
919
  });
898
- var localBehaviorSpecFileSchema = specSnapshotSchema.extend({
920
+ var localAdapterSpecFileSchema = specSnapshotSchema.extend({
921
+ engine: z.literal("adapter").optional(),
899
922
  id: z.string().uuid().optional(),
900
923
  hyperparameters: fineTuneHyperparametersSchema.optional(),
901
924
  dataset_prebuilt: datasetPrebuiltSchema.optional()
902
925
  }).strict();
926
+ var localBehaviorSpecFileSchema = z.union([
927
+ localFoundationSpecFileSchema,
928
+ localAdapterSpecFileSchema
929
+ ]);
903
930
  var evalExampleResultSchema = z.object({
904
931
  prompt: z.string(),
905
932
  expected: z.string(),
@@ -1080,6 +1107,9 @@ var localRunnerConfigSchema = z.object({
1080
1107
  baselineCache: true
1081
1108
  })
1082
1109
  }).strict();
1110
+ function isFoundationSpecFile(spec) {
1111
+ return spec.engine === "foundation";
1112
+ }
1083
1113
 
1084
1114
  // src/local-runtime/local-project.ts
1085
1115
  import { createHash as createHash2, randomUUID as randomUUID2 } from "crypto";
@@ -1121,7 +1151,48 @@ async function initLocalSpecFile(args) {
1121
1151
  if (!args.force && await exists(args.outputPath)) {
1122
1152
  throw new Error(`Refusing to overwrite existing file: ${args.outputPath}`);
1123
1153
  }
1124
- const spec = localBehaviorSpecFileSchema.parse({
1154
+ if (args.engine === "foundation") {
1155
+ const spec2 = localFoundationSpecFileSchema.parse({
1156
+ engine: "foundation",
1157
+ id: randomUUID2(),
1158
+ name: args.name,
1159
+ description: "From-scratch tokenizer, pretrain, chat SFT, and eval.",
1160
+ system_prompt: "You are a helpful assistant.",
1161
+ guidelines: [
1162
+ "Answer the user request directly."
1163
+ ],
1164
+ constraints: [],
1165
+ examples: [
1166
+ {
1167
+ input: "Replace this with representative chat input.",
1168
+ output: "Replace this with the expected assistant reply."
1169
+ },
1170
+ {
1171
+ input: "Replace this with a different chat input.",
1172
+ output: "Replace this with the expected assistant reply."
1173
+ }
1174
+ ],
1175
+ foundation: {
1176
+ depth: 2,
1177
+ pretrain_steps: 2,
1178
+ finetune_steps: 2,
1179
+ rl_steps: 0,
1180
+ vocab_size: 256,
1181
+ max_chars: 2e4,
1182
+ sequence_length: 64,
1183
+ batch_size: 2,
1184
+ nproc_per_node: 1
1185
+ }
1186
+ });
1187
+ await mkdir2(dirname2(args.outputPath), { recursive: true });
1188
+ await writeFile2(args.outputPath, `${JSON.stringify(spec2, null, 2)}
1189
+ `, "utf8");
1190
+ return spec2;
1191
+ }
1192
+ if (!args.baseModel) {
1193
+ throw new Error("Adapter specs require --model.");
1194
+ }
1195
+ const spec = localAdapterSpecFileSchema.parse({
1125
1196
  id: randomUUID2(),
1126
1197
  name: args.name,
1127
1198
  description: "",
@@ -1172,27 +1243,45 @@ async function initLocalRunnerConfigFile(args) {
1172
1243
  `, "utf8");
1173
1244
  return config;
1174
1245
  }
1175
- function generatedPlaceholderIssues(request) {
1246
+ function placeholderIssues(systemPrompt, examples) {
1176
1247
  const issues = [];
1177
- if (/describe the behavior this local model should learn/i.test(request.spec_snapshot.system_prompt)) {
1248
+ if (/describe the behavior this local model should learn/i.test(systemPrompt)) {
1178
1249
  issues.push("system_prompt still contains the generated placeholder");
1179
1250
  }
1180
- request.spec_snapshot.examples.forEach((example, index) => {
1251
+ examples.forEach((example, index) => {
1181
1252
  if (/replace this with/i.test(example.input) || /replace this with/i.test(example.output)) {
1182
1253
  issues.push(`examples[${index}] still contains generated placeholder text`);
1183
1254
  }
1184
1255
  });
1185
1256
  return issues;
1186
1257
  }
1258
+ function generatedPlaceholderIssues(request) {
1259
+ return placeholderIssues(request.spec_snapshot.system_prompt, request.spec_snapshot.examples);
1260
+ }
1187
1261
  function assertLocalRunInputReady(request) {
1188
1262
  const issues = generatedPlaceholderIssues(request);
1189
1263
  if (issues.length > 0) {
1190
1264
  throw new Error(`Edit the generated behavior spec before training: ${issues.join("; ")}.`);
1191
1265
  }
1192
1266
  }
1267
+ function foundationPlaceholderIssues(spec) {
1268
+ return placeholderIssues(spec.system_prompt, spec.examples);
1269
+ }
1270
+ function assertFoundationSpecReady(spec) {
1271
+ const issues = foundationPlaceholderIssues(spec);
1272
+ if (issues.length > 0) {
1273
+ throw new Error(`Edit the generated foundation spec before training: ${issues.join("; ")}.`);
1274
+ }
1275
+ }
1193
1276
  function runRequestFromLocalSpec(spec, options = {}) {
1277
+ if (isFoundationSpecFile(spec)) {
1278
+ throw new Error(
1279
+ "Foundation specs cannot be converted into a LoRA run request. Use `tt pipeline run --spec`."
1280
+ );
1281
+ }
1194
1282
  const {
1195
1283
  id,
1284
+ engine: _engine,
1196
1285
  hyperparameters,
1197
1286
  dataset_prebuilt: datasetPrebuilt,
1198
1287
  ...specSnapshot
@@ -1229,6 +1318,9 @@ async function loadLocalRunInput(path, options = {}) {
1229
1318
  return { kind: "request", path, request: request.data };
1230
1319
  }
1231
1320
  const spec = localBehaviorSpecFileSchema.parse(raw);
1321
+ if (isFoundationSpecFile(spec)) {
1322
+ return { kind: "foundation-spec", path, spec };
1323
+ }
1232
1324
  return {
1233
1325
  kind: "spec",
1234
1326
  path,
@@ -1914,6 +2006,20 @@ var BUNDLED_PYTHON_ENVIRONMENT = join3(
1914
2006
  "uv",
1915
2007
  bundledRuntimeHash
1916
2008
  );
2009
+ var foundationProject = join3(packageRoot, "training/foundation");
2010
+ var foundationRuntimeHash = (() => {
2011
+ const hash = createHash3("sha256");
2012
+ for (const name of ["pyproject.toml", "uv.lock"]) {
2013
+ hash.update(readFileSync(join3(foundationProject, name)));
2014
+ }
2015
+ return hash.digest("hex").slice(0, 20);
2016
+ })();
2017
+ var FOUNDATION_PYTHON_ENVIRONMENT = join3(
2018
+ resolve6(process.env.XDG_CACHE_HOME ?? join3(homedir3(), ".cache")),
2019
+ "tuned-tensor-local",
2020
+ "uv-foundation",
2021
+ foundationRuntimeHash
2022
+ );
1917
2023
  function buildBundledPythonCommand(entrypoint, args = []) {
1918
2024
  const target = entrypoint === "-c" ? entrypoint : join3(bundledProject, "src", entrypoint);
1919
2025
  const commandArgs = [
@@ -1938,6 +2044,29 @@ function withBundledPythonEnvironment(env) {
1938
2044
  UV_PROJECT_ENVIRONMENT: BUNDLED_PYTHON_ENVIRONMENT
1939
2045
  };
1940
2046
  }
2047
+ function buildFoundationPythonCommand(entrypoint, args = []) {
2048
+ const commandArgs = [
2049
+ "run",
2050
+ "--frozen",
2051
+ "--quiet",
2052
+ "--project",
2053
+ foundationProject,
2054
+ "python",
2055
+ join3(foundationProject, "src", entrypoint),
2056
+ ...args
2057
+ ];
2058
+ return {
2059
+ command: "uv",
2060
+ commandArgs,
2061
+ displayCommand: ["uv", ...commandArgs]
2062
+ };
2063
+ }
2064
+ function withFoundationPythonEnvironment(env) {
2065
+ return {
2066
+ ...env,
2067
+ UV_PROJECT_ENVIRONMENT: FOUNDATION_PYTHON_ENVIRONMENT
2068
+ };
2069
+ }
1941
2070
  var ProcessCancelledError = class extends Error {
1942
2071
  constructor(message = "Process cancelled.") {
1943
2072
  super(message);
@@ -4755,9 +4884,12 @@ export {
4755
4884
  baseModelRevisionSchema,
4756
4885
  behaviorSpecExampleSchema,
4757
4886
  specSnapshotSchema,
4887
+ foundationHyperparametersSchema,
4888
+ localFoundationSpecFileSchema,
4758
4889
  datasetPrebuiltSchema,
4759
4890
  fineTuneHyperparametersSchema,
4760
4891
  fineTuneRunRequestSchema,
4892
+ localAdapterSpecFileSchema,
4761
4893
  localBehaviorSpecFileSchema,
4762
4894
  evalExampleResultSchema,
4763
4895
  jsonFieldMetricsSchema,
@@ -4767,12 +4899,15 @@ export {
4767
4899
  trainingReportSchema,
4768
4900
  runReportSchema,
4769
4901
  localRunnerConfigSchema,
4902
+ isFoundationSpecFile,
4770
4903
  DEFAULT_LOCAL_SPEC_PATH,
4771
4904
  resolveLocalRunInputPaths,
4772
4905
  initLocalSpecFile,
4773
4906
  initLocalRunnerConfigFile,
4774
4907
  generatedPlaceholderIssues,
4775
4908
  assertLocalRunInputReady,
4909
+ foundationPlaceholderIssues,
4910
+ assertFoundationSpecReady,
4776
4911
  runRequestFromLocalSpec,
4777
4912
  loadLocalRunInput,
4778
4913
  normalizeChatJsonlForRelocation,
@@ -4788,6 +4923,9 @@ export {
4788
4923
  localRuntimePackageRoot,
4789
4924
  buildBundledPythonCommand,
4790
4925
  withBundledPythonEnvironment,
4926
+ buildFoundationPythonCommand,
4927
+ withFoundationPythonEnvironment,
4928
+ runLoggedProcess,
4791
4929
  isTerminalRunState,
4792
4930
  defaultLocalHome,
4793
4931
  localStorePaths,
@@ -4811,4 +4949,4 @@ export {
4811
4949
  runLocalPipeline,
4812
4950
  runLocalFineTune
4813
4951
  };
4814
- //# sourceMappingURL=chunk-YJYCGSHJ.js.map
4952
+ //# sourceMappingURL=chunk-2P2RL23O.js.map