@tuned-tensor/cli 0.18.0 → 0.19.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/dist/index.js CHANGED
@@ -39,10 +39,11 @@ import {
39
39
  runReportSchema,
40
40
  specHash,
41
41
  validateBehaviorSpec,
42
+ validateEvalCases,
42
43
  validatePipeline,
43
44
  warningsFromSnapshot,
44
45
  withFoundationPythonEnvironment
45
- } from "./chunk-U5HNS367.js";
46
+ } from "./chunk-4Q54NHKR.js";
46
47
 
47
48
  // src/cli.ts
48
49
  import { spawn as spawn4 } from "child_process";
@@ -51,183 +52,22 @@ import { Command } from "commander";
51
52
  import chalk9 from "chalk";
52
53
 
53
54
  // src/local-agent-client.ts
54
- import { randomUUID as randomUUID4 } from "crypto";
55
+ import { randomUUID as randomUUID5 } from "crypto";
55
56
  import { Agent } from "@earendil-works/pi-agent-core";
56
57
 
57
58
  // src/spec-workspace.ts
58
- import { randomUUID } from "crypto";
59
+ import { randomUUID as randomUUID2 } from "crypto";
59
60
  import { constants as constants2 } from "fs";
60
61
  import { lstat as lstat2, mkdir as mkdir2, open as open2, readdir, rename, unlink } from "fs/promises";
61
62
  import { isAbsolute, join as join2, relative, sep } from "path";
62
63
 
63
64
  // src/local-spec-workspace.ts
64
- import { createHash } from "crypto";
65
+ import { createHash, randomUUID } from "crypto";
65
66
  import { constants } from "fs";
66
67
  import { lstat, mkdir, open, realpath, rmdir, writeFile } from "fs/promises";
67
68
  import { join } from "path";
68
69
  import { Type } from "typebox";
69
70
  import { Value } from "typebox/value";
70
-
71
- // src/eval/rules.ts
72
- function validateSpec(spec) {
73
- const checks = [];
74
- checks.push({
75
- name: "Has name",
76
- passed: Boolean(spec.name?.trim()),
77
- message: spec.name?.trim() ? void 0 : "Spec is missing a name"
78
- });
79
- checks.push({
80
- name: "Has system prompt",
81
- passed: Boolean(spec.system_prompt?.trim()),
82
- message: spec.system_prompt?.trim() ? void 0 : "Spec is missing a system_prompt"
83
- });
84
- const isFoundation = spec.engine === "foundation";
85
- checks.push({
86
- name: isFoundation ? "Has foundation engine" : "Has base model",
87
- passed: isFoundation ? spec.foundation != null && typeof spec.foundation === "object" : Boolean(spec.base_model?.trim()),
88
- message: isFoundation ? spec.foundation != null ? void 0 : "Foundation spec is missing a foundation block" : spec.base_model?.trim() ? void 0 : "Spec is missing a base_model"
89
- });
90
- const exCount = spec.examples?.length ?? 0;
91
- const minExamples = isFoundation ? 2 : 1;
92
- checks.push({
93
- name: "Has examples",
94
- passed: exCount >= minExamples,
95
- message: exCount >= minExamples ? `${exCount} example(s)` : isFoundation ? "Add at least two chat examples" : "Add at least one example"
96
- });
97
- checks.push({
98
- name: "Has guidelines",
99
- passed: (spec.guidelines?.length ?? 0) > 0,
100
- message: (spec.guidelines?.length ?? 0) > 0 ? void 0 : "Consider adding guidelines for better eval coverage"
101
- });
102
- if (spec.constraints?.length && spec.examples?.length) {
103
- const violations = checkExamplesAgainstConstraints(spec);
104
- checks.push({
105
- name: "Examples satisfy constraints",
106
- passed: violations.length === 0,
107
- message: violations.length === 0 ? void 0 : violations.join("; ")
108
- });
109
- }
110
- const evalCaseErrors = validateEvalCases(spec);
111
- checks.push({
112
- name: "Eval cases valid",
113
- passed: evalCaseErrors.length === 0,
114
- message: evalCaseErrors.length === 0 ? spec.eval_cases?.length ? `${spec.eval_cases.length} executable eval case(s)` : void 0 : evalCaseErrors.join("; ")
115
- });
116
- return {
117
- valid: checks.every((c) => c.passed),
118
- checks
119
- };
120
- }
121
- function validateEvalCases(spec) {
122
- const errors = [];
123
- const cases = spec.eval_cases ?? [];
124
- for (const [caseIndex, evalCase] of cases.entries()) {
125
- const label = `eval_cases[${caseIndex}]`;
126
- if (!evalCase || typeof evalCase !== "object") {
127
- errors.push(`${label} must be an object`);
128
- continue;
129
- }
130
- if (typeof evalCase.input !== "string" || evalCase.input.trim().length === 0) {
131
- errors.push(`${label}.input must be a non-empty string`);
132
- }
133
- if (evalCase.runtime !== "python") {
134
- errors.push(`${label}.runtime must be "python"`);
135
- }
136
- if (!Array.isArray(evalCase.tests) || evalCase.tests.length === 0) {
137
- errors.push(`${label}.tests must contain at least one test`);
138
- continue;
139
- }
140
- for (const [testIndex, test] of evalCase.tests.entries()) {
141
- const testLabel = `${label}.tests[${testIndex}]`;
142
- if (!test || typeof test !== "object") {
143
- errors.push(`${testLabel} must be an object`);
144
- continue;
145
- }
146
- if (test.name !== void 0 && (typeof test.name !== "string" || test.name.trim().length === 0)) {
147
- errors.push(`${testLabel}.name must be a non-empty string when provided`);
148
- }
149
- if (test.args !== void 0 && (!Array.isArray(test.args) || !test.args.every((arg) => typeof arg === "string"))) {
150
- errors.push(`${testLabel}.args must be an array of strings`);
151
- }
152
- if (test.stdin !== void 0 && typeof test.stdin !== "string") {
153
- errors.push(`${testLabel}.stdin must be a string`);
154
- }
155
- if (test.expected_exit_code !== void 0 && (typeof test.expected_exit_code !== "number" || !Number.isInteger(test.expected_exit_code) || test.expected_exit_code < 0 || test.expected_exit_code > 255)) {
156
- errors.push(`${testLabel}.expected_exit_code must be an integer between 0 and 255`);
157
- }
158
- if (test.expected_stdout !== void 0 && typeof test.expected_stdout !== "string") {
159
- errors.push(`${testLabel}.expected_stdout must be a string`);
160
- }
161
- validateFiles(test.files, `${testLabel}.files`, errors);
162
- validateFiles(test.expected_files, `${testLabel}.expected_files`, errors);
163
- }
164
- }
165
- return errors;
166
- }
167
- function validateFiles(files, label, errors) {
168
- if (files === void 0) return;
169
- if (!Array.isArray(files)) {
170
- errors.push(`${label} must be an array`);
171
- return;
172
- }
173
- for (const [index, file] of files.entries()) {
174
- const fileLabel = `${label}[${index}]`;
175
- if (!file || typeof file !== "object") {
176
- errors.push(`${fileLabel} must be an object`);
177
- continue;
178
- }
179
- const row = file;
180
- if (typeof row.path !== "string" || !isSafeRelativePath(row.path)) {
181
- errors.push(`${fileLabel}.path must be a safe relative path`);
182
- }
183
- if (row.content !== void 0 && typeof row.content !== "string") {
184
- errors.push(`${fileLabel}.content must be a string`);
185
- }
186
- }
187
- }
188
- function isSafeRelativePath(value) {
189
- if (value.length === 0 || value.length > 240) return false;
190
- if (value.includes("\0") || value.startsWith("/")) return false;
191
- const normalized = value.replace(/\\/g, "/");
192
- return !normalized.split("/").some((part) => part === "" || part === "." || part === "..");
193
- }
194
- function checkExamplesAgainstConstraints(spec) {
195
- const violations = [];
196
- for (const [i, ex] of spec.examples.entries()) {
197
- for (const constraint of spec.constraints) {
198
- const result2 = evaluateConstraint(ex.output, constraint);
199
- if (!result2.passed) {
200
- violations.push(`Example ${i + 1} violates "${constraint}": ${result2.message}`);
201
- }
202
- }
203
- }
204
- return violations;
205
- }
206
- function evaluateConstraint(text2, constraint) {
207
- const lower = constraint.toLowerCase();
208
- const neverMatch = lower.match(/^never (?:share|mention|include|reveal|use|say|output|return|give|provide|show|disclose|expose)\s+(.+)/);
209
- if (neverMatch) {
210
- const forbidden = neverMatch[1].replace(/['"]/g, "").trim();
211
- if (text2.toLowerCase().includes(forbidden.toLowerCase())) {
212
- return { passed: false, message: `Output contains "${forbidden}"` };
213
- }
214
- return { passed: true };
215
- }
216
- const alwaysMatch = lower.match(/^always (?:include|use|start with|end with|contain|respond in|reply in)\s+(.+)/);
217
- if (alwaysMatch) {
218
- const required = alwaysMatch[1].replace(/['"]/g, "").trim();
219
- if (!text2.toLowerCase().includes(required.toLowerCase())) {
220
- return { passed: false, message: `Output missing "${required}"` };
221
- }
222
- return { passed: true };
223
- }
224
- return {
225
- passed: true,
226
- message: `Constraint not enforceable by rules: "${constraint}" (will be checked by LLM judge if a provider is configured)`
227
- };
228
- }
229
-
230
- // src/local-spec-workspace.ts
231
71
  var FolderName = Type.String({
232
72
  minLength: 1,
233
73
  maxLength: 120,
@@ -286,17 +126,6 @@ function validateInputs(directory, spec) {
286
126
  throw new Error("Local spec content does not match the canonical tunedtensor.json schema.");
287
127
  }
288
128
  pipelineForRunInput(parseLocalRunInput(spec, join(directory, "tunedtensor.json")));
289
- if (spec.engine === "foundation") return;
290
- const validation = validateSpec({
291
- ...spec,
292
- description: spec.description ?? "",
293
- constraints: spec.constraints ?? []
294
- });
295
- if (!validation.valid) {
296
- const messages = validation.checks.filter((check) => !check.passed).map((check) => check.message ?? check.name);
297
- throw new Error(`Local spec validation failed:
298
- - ${messages.join("\n- ")}`);
299
- }
300
129
  }
301
130
  async function canonicalWorkspace(workspaceRoot) {
302
131
  const rootInfo = await lstat(workspaceRoot);
@@ -425,7 +254,7 @@ async function createLocalSpecProject(workspaceRoot, directory, spec, expectedWo
425
254
  }
426
255
  const stableSpecPath = join(`/proc/self/fd/${directoryHandle.fd}`, "tunedtensor.json");
427
256
  writeStarted = true;
428
- await operations.writeFile(stableSpecPath, `${JSON.stringify(spec, null, 2)}
257
+ await operations.writeFile(stableSpecPath, `${JSON.stringify({ id: randomUUID(), ...spec }, null, 2)}
429
258
  `, {
430
259
  encoding: "utf8",
431
260
  flag: "wx",
@@ -509,7 +338,8 @@ var EDIT_KEYS = /* @__PURE__ */ new Set([
509
338
  "dataset_prebuilt",
510
339
  "runtime",
511
340
  "evaluation",
512
- "pipeline"
341
+ "pipeline",
342
+ "add_examples"
513
343
  ]);
514
344
  function isObject(value) {
515
345
  return value !== null && typeof value === "object" && !Array.isArray(value);
@@ -599,6 +429,26 @@ async function inspectLocalSpec(workspaceRoot, specPath = "tunedtensor.json") {
599
429
  }
600
430
  return { ...location, source, sha256: specHash(source), document, validation };
601
431
  }
432
+ function arrayDiff(before, after) {
433
+ const added = after.map((item) => JSON.stringify(item));
434
+ const removed = [];
435
+ for (const item of before.map((value) => JSON.stringify(value))) {
436
+ const index = added.indexOf(item);
437
+ if (index === -1) removed.push(`- ${item}`);
438
+ else added.splice(index, 1);
439
+ }
440
+ const lines = [...removed, ...added.map((item) => `+ ${item}`)];
441
+ return lines.length ? lines : [" (order changed)"];
442
+ }
443
+ function derivedSpecId(document, path) {
444
+ if (document.id !== void 0) return void 0;
445
+ try {
446
+ const input = parseLocalRunInput(document, path);
447
+ return input.kind === "spec" ? input.request.behavior_spec_id : void 0;
448
+ } catch {
449
+ return void 0;
450
+ }
451
+ }
602
452
  function specDiff(before, after) {
603
453
  const left = isObject(before) ? before : {};
604
454
  const right = isObject(after) ? after : {};
@@ -606,6 +456,10 @@ function specDiff(before, after) {
606
456
  const lines = [];
607
457
  for (const key of keys) {
608
458
  if (JSON.stringify(left[key]) === JSON.stringify(right[key])) continue;
459
+ if (Array.isArray(left[key]) && Array.isArray(right[key])) {
460
+ lines.push(`@@ ${key} @@`, ...arrayDiff(left[key], right[key]));
461
+ continue;
462
+ }
609
463
  lines.push(
610
464
  `@@ ${key} @@`,
611
465
  ...JSON.stringify(left[key] ?? null, null, 2).split("\n").map((line) => `- ${line}`),
@@ -621,7 +475,14 @@ async function prepareSpecUpdate(workspaceRoot, specPath, expectedSha256, change
621
475
  if (!isObject(changes) || !Object.keys(changes).length || Object.keys(changes).some((key) => !EDIT_KEYS.has(key))) {
622
476
  throw new Error("Provide supported spec field changes; identity and engine cannot be changed by an edit.");
623
477
  }
624
- const next = { ...current.document, ...changes };
478
+ const { add_examples: added, ...fields } = changes;
479
+ if (added !== void 0) {
480
+ if (!Array.isArray(added) || "examples" in fields) throw new Error("Use add_examples to append examples, or examples to replace them, not both.");
481
+ const existing = Array.isArray(current.document.examples) ? current.document.examples : [];
482
+ fields.examples = [...existing, ...added];
483
+ }
484
+ const id = derivedSpecId(current.document, current.path);
485
+ const next = { ...id ? { id } : {}, ...current.document, ...fields };
625
486
  function mergeSettings(before, patch2) {
626
487
  const result2 = { ...before };
627
488
  for (const [key, value] of Object.entries(patch2)) {
@@ -631,13 +492,13 @@ async function prepareSpecUpdate(workspaceRoot, specPath, expectedSha256, change
631
492
  return result2;
632
493
  }
633
494
  for (const key of ["runtime", "evaluation", "pipeline"]) {
634
- if (changes[key] === null) delete next[key];
635
- else if (key !== "pipeline" && isObject(changes[key])) next[key] = mergeSettings(isObject(current.document[key]) ? current.document[key] : {}, changes[key]);
495
+ if (fields[key] === null) delete next[key];
496
+ else if (key !== "pipeline" && isObject(fields[key])) next[key] = mergeSettings(isObject(current.document[key]) ? current.document[key] : {}, fields[key]);
636
497
  }
637
498
  for (const key of ["hyperparameters", "foundation"]) {
638
- if (isObject(changes[key])) {
499
+ if (isObject(fields[key])) {
639
500
  const previous = isObject(current.document[key]) ? current.document[key] : {};
640
- next[key] = { ...previous, ...changes[key] };
501
+ next[key] = { ...previous, ...fields[key] };
641
502
  }
642
503
  }
643
504
  const validation = validateDocument(next, current.path);
@@ -686,7 +547,7 @@ async function privateChild(parent, name) {
686
547
  }
687
548
  async function atomicText(parent, name, source) {
688
549
  const base = `/proc/self/fd/${parent.fd}`;
689
- const temporary = join2(base, `.tt-${randomUUID()}.tmp`);
550
+ const temporary = join2(base, `.tt-${randomUUID2()}.tmp`);
690
551
  try {
691
552
  const file = await open2(temporary, "wx", 384);
692
553
  try {
@@ -726,7 +587,7 @@ async function applySpecUpdate(workspaceRoot, update) {
726
587
  handles.push(state);
727
588
  const history = await privateChild(state, "spec-history");
728
589
  handles.push(history);
729
- const id = `${Date.now()}-${randomUUID()}`;
590
+ const id = `${Date.now()}-${randomUUID2()}`;
730
591
  const revision = {
731
592
  id,
732
593
  status: "prepared",
@@ -778,7 +639,7 @@ async function readSpecHistory(workspaceRoot, specPath = "tunedtensor.json") {
778
639
  import { createHash as createHash3 } from "crypto";
779
640
 
780
641
  // src/local-pipeline-action.ts
781
- import { createHash as createHash2, randomUUID as randomUUID2 } from "crypto";
642
+ import { createHash as createHash2, randomUUID as randomUUID3 } from "crypto";
782
643
  import { lstat as lstat3, mkdtemp, readFile, realpath as realpath2, rm, writeFile as writeFile2 } from "fs/promises";
783
644
  import { tmpdir } from "os";
784
645
  import { dirname, isAbsolute as isAbsolute2, join as join3, relative as relative2, resolve, sep as sep2 } from "path";
@@ -959,7 +820,7 @@ async function validatePreparedLocalPipelineAction(args2) {
959
820
  async function executeLocalPipelineAction(args2) {
960
821
  const prepared = await validatePreparedLocalPipelineAction(args2);
961
822
  const temporaryDirectory = await mkdtemp(join3(tmpdir(), "tt-agent-pipeline-"));
962
- const temporaryId = randomUUID2();
823
+ const temporaryId = randomUUID3();
963
824
  const specPath = join3(temporaryDirectory, `${temporaryId}.spec.json`);
964
825
  const config = prepared.resolvedConfig;
965
826
  const { evaluation, dryRun: _dryRun, ...runtime } = config;
@@ -1583,7 +1444,7 @@ function ensureOpenRouterAppHeaders(modelsPath) {
1583
1444
  }
1584
1445
 
1585
1446
  // src/agent-tools.ts
1586
- import { createHash as createHash4, randomUUID as randomUUID3 } from "crypto";
1447
+ import { createHash as createHash4, randomUUID as randomUUID4 } from "crypto";
1587
1448
  import { lstatSync, readFileSync as readFileSync3 } from "fs";
1588
1449
  import { fileURLToPath } from "url";
1589
1450
  import { Type as Type2 } from "typebox";
@@ -1962,7 +1823,7 @@ function define(name, label, description, parameters, execute) {
1962
1823
  }
1963
1824
  function proposal(operation, title, summary, args2, preview) {
1964
1825
  const action = {
1965
- id: randomUUID3(),
1826
+ id: randomUUID4(),
1966
1827
  operation,
1967
1828
  title,
1968
1829
  summary,
@@ -2236,7 +2097,7 @@ function createTunedTensorTools(api, options = {}) {
2236
2097
  define(
2237
2098
  "prepare_update_local_spec",
2238
2099
  "Prepare behavior spec edit",
2239
- "Prepare a reviewed edit of the existing local spec using the SHA-256 from get_local_spec. Arrays and pipeline replace whole fields; hyperparameters and foundation settings merge by key. Runtime and evaluation objects merge recursively; null removes optional settings. Preserve unrelated fields. No write until /approve.",
2100
+ "Prepare a reviewed edit of the existing local spec using the SHA-256 from get_local_spec. Use add_examples to append examples without resending existing ones. Other arrays and pipeline replace whole fields; hyperparameters and foundation settings merge by key. Runtime and evaluation objects merge recursively; null removes optional settings. Preserve unrelated fields. No write until /approve.",
2240
2101
  Type2.Object({
2241
2102
  spec_path: Type2.Optional(Type2.String({ maxLength: 1e3 })),
2242
2103
  expected_sha256: Type2.String({ pattern: "^[a-f0-9]{64}$" }),
@@ -2251,6 +2112,10 @@ function createTunedTensorTools(api, options = {}) {
2251
2112
  input: Type2.String(),
2252
2113
  output: Type2.String()
2253
2114
  }, { additionalProperties: false }))),
2115
+ add_examples: Type2.Optional(Type2.Array(Type2.Object({
2116
+ input: Type2.String(),
2117
+ output: Type2.String()
2118
+ }, { additionalProperties: false }), { minItems: 1 })),
2254
2119
  hyperparameters: Type2.Optional(Type2.Record(Type2.String(), Type2.Unknown())),
2255
2120
  foundation: Type2.Optional(Type2.Record(Type2.String(), Type2.Unknown())),
2256
2121
  runtime: Type2.Optional(Type2.Union([Type2.Record(Type2.String(), Type2.Unknown()), Type2.Null()])),
@@ -2381,7 +2246,7 @@ function createTunedTensorTools(api, options = {}) {
2381
2246
  // src/local-agent-client.ts
2382
2247
  var MAX_TOOL_CALLS_PER_TURN = 12;
2383
2248
  var SYSTEM_PROMPT = `You are the local Tuned Tensor assistant running on the user's laptop.
2384
- The workspace tunedtensor.json behavior spec is the source of truth for model behavior, training, evaluation policy, runtime placement and optional pipeline settings. For requests to change the model's behavior, inspect it with get_local_spec first, then prepare_update_local_spec with the returned SHA-256 and only the requested field changes. Preserve unrelated examples, instructions, engine and training settings. Explain the proposed diff and validation; never claim an edit was saved before approval. Read-only questions about the current spec use get_local_spec without proposing an edit. If no spec exists, help prepare a new project. Malformed JSON must be repaired in an editor before prepare_update_local_spec can operate; never offer that tool as a way to reconstruct a truncated file. Use /spec, /spec diff, /spec validate and /spec history for direct review. General educational or inspection questions do not require a spec mutation.
2249
+ The workspace tunedtensor.json behavior spec is the source of truth for model behavior, training, evaluation policy, runtime placement and optional pipeline settings. For requests to change the model's behavior, inspect it with get_local_spec first, then prepare_update_local_spec with the returned SHA-256 and only the requested field changes; use add_examples to append examples. Preserve unrelated examples, instructions, engine and training settings. Explain the proposed diff and validation; never claim an edit was saved before approval. Read-only questions about the current spec use get_local_spec without proposing an edit. If no spec exists, help prepare a new project. Malformed JSON must be repaired in an editor before prepare_update_local_spec can operate; never offer that tool as a way to reconstruct a truncated file. Use /spec, /spec diff, /spec validate and /spec history for direct review. General educational or inspection questions do not require a spec mutation.
2385
2250
  Local workflow commands need no TT access token. For local inspection commands such as runs, models, or doctor, tell the user to run the matching TT command in this shell (for example \`runs list\` or \`doctor\`); those commands execute outside the agent. User-owned AWS GPU training uses \`tt pipeline run\` with runtime.gpu configuration in tunedtensor.json, without a TT token. \`tt cloud\` is for TT account records, not GPU execution; hosted training start/estimate are retired. AWS credentials authorize instance lookup; separate SSH access is required. The instance must already be running, and the user manages quota, capacity, costs and shutdown. Keep the laptop running until outputs return. Model-provider choice is independent of GPU placement.
2386
2251
  When the user requests commands to inspect a run or serve a result, provide the direct CLI handoff: \`tt runs list\` to find a run, \`tt runs get <run-id>\` for its details, \`tt runs report <run-id>\` for its evaluation report, \`tt models list\` to find the resulting model ID, and \`tt serve <model-id>\` to serve that model. Replace placeholders with actual IDs from those commands; never invent results or IDs. Until the user supplies command output, keep literal <run-id> and <model-id> placeholders; do not fabricate example IDs or prefixes. Local run IDs are UUIDs and adapter model IDs are local-<run-id>. Do not refresh hardware or propose spec edits merely to supply those commands; perform those actions only when requested.
2387
2252
  For accurate adapter and foundation workflow stages and commands, call \`describe_pipeline\` with the matching engine instead of relying on prior knowledge.
@@ -2453,7 +2318,7 @@ function createLocalAgentClient(options) {
2453
2318
  const timestamp = now();
2454
2319
  const state = {
2455
2320
  thread: {
2456
- id: randomUUID4(),
2321
+ id: randomUUID5(),
2457
2322
  title: "New conversation",
2458
2323
  status: "active",
2459
2324
  last_message_at: null,
@@ -2476,7 +2341,7 @@ function createLocalAgentClient(options) {
2476
2341
  async runTurn(threadId, prompt, onEvent, signal, context) {
2477
2342
  const state = await options.store.load(threadId);
2478
2343
  const actions = [];
2479
- const turnId = randomUUID4();
2344
+ const turnId = randomUUID5();
2480
2345
  let response = "";
2481
2346
  let failure;
2482
2347
  const effectiveToolApi = {
@@ -2630,7 +2495,7 @@ import {
2630
2495
  unlink as unlink2,
2631
2496
  writeFile as writeFile3
2632
2497
  } from "fs/promises";
2633
- import { randomUUID as randomUUID5 } from "crypto";
2498
+ import { randomUUID as randomUUID6 } from "crypto";
2634
2499
  import { join as join6 } from "path";
2635
2500
  var UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
2636
2501
  var DEFAULT_MAX_THREAD_BYTES = 1e6;
@@ -2763,7 +2628,7 @@ var LocalAgentStore = class {
2763
2628
  const destination = this.path(state.thread.id);
2764
2629
  const temporary = join6(
2765
2630
  this.threadsDir,
2766
- `.${state.thread.id}.${randomUUID5()}.tmp`
2631
+ `.${state.thread.id}.${randomUUID6()}.tmp`
2767
2632
  );
2768
2633
  let serialized;
2769
2634
  try {
@@ -3549,10 +3414,7 @@ var FEATURED_AGENT_PROVIDERS = [
3549
3414
  var RECOMMENDED_AGENT_MODELS = [
3550
3415
  { provider: "tunedtensor", ids: ["managed"] },
3551
3416
  { provider: "openai", ids: ["gpt-5.6-sol"] },
3552
- {
3553
- provider: "openrouter",
3554
- ids: ["deepseek/deepseek-v4-flash-0731", "deepseek/deepseek-v4-flash"]
3555
- }
3417
+ { provider: "openrouter", ids: ["anthropic/claude-sonnet-5"] }
3556
3418
  ];
3557
3419
  var FEATURED_PROVIDER_INDEX = new Map(
3558
3420
  FEATURED_AGENT_PROVIDERS.map((id, index) => [id, index])
@@ -4781,26 +4643,18 @@ ${chalk4.yellow.bold("Approval required")} ${chalk4.dim(action.id.slice(0, 8))}
4781
4643
  if (event.type === "text_delta") {
4782
4644
  const delta = stringValue(payload.delta) ?? stringValue(payload.text) ?? stringValue(payload.content);
4783
4645
  if (!delta) return;
4784
- if (this.reasoningActive) {
4785
- this.endOpenLine();
4786
- this.options.io.write("\n");
4787
- }
4646
+ this.reasoningActive = false;
4788
4647
  this.writeRenderedResponse(this.responseMarkdown.push(delta));
4789
4648
  return;
4790
4649
  }
4791
4650
  if (event.type === "reasoning_delta") {
4792
4651
  const delta = stringValue(payload.delta) ?? stringValue(payload.text) ?? stringValue(payload.content);
4793
4652
  if (!delta) return;
4794
- const safeDelta = sanitizeTerminalText(delta);
4795
- if (!safeDelta) return;
4796
- if (!this.reasoningActive) {
4797
- this.flushResponse();
4798
- this.endOpenLine();
4799
- this.options.io.write("\n");
4800
- this.reasoningActive = true;
4801
- }
4802
- this.options.io.write(chalk4.dim.italic(safeDelta));
4803
- this.lineOpen = !safeDelta.endsWith("\n");
4653
+ if (this.reasoningActive) return;
4654
+ this.flushResponse();
4655
+ this.endOpenLine();
4656
+ this.options.io.write(chalk4.dim(" \u25CB Thinking\u2026\n"));
4657
+ this.reasoningActive = true;
4804
4658
  return;
4805
4659
  }
4806
4660
  if (event.type === "tool_call") {
@@ -5062,7 +4916,7 @@ ${chalk4.yellow.bold("Approval required")} ${chalk4.dim(action.id.slice(0, 8))}
5062
4916
 
5063
4917
  // src/local-runner.ts
5064
4918
  import { constants as osConstants } from "os";
5065
- import { randomUUID as randomUUID6 } from "crypto";
4919
+ import { randomUUID as randomUUID7 } from "crypto";
5066
4920
  import { spawn } from "child_process";
5067
4921
  import { existsSync as existsSync3 } from "fs";
5068
4922
  import { fileURLToPath as fileURLToPath2 } from "url";
@@ -5817,7 +5671,7 @@ async function projectSpecArguments(originalArgs, cwd) {
5817
5671
  }
5818
5672
  const temporaryPath = join8(
5819
5673
  dirname4(sourcePath),
5820
- `.${basename3(sourcePath)}.tt-local-${process.pid}-${randomUUID6()}.json`
5674
+ `.${basename3(sourcePath)}.tt-local-${process.pid}-${randomUUID7()}.json`
5821
5675
  );
5822
5676
  await writeFile4(
5823
5677
  temporaryPath,
@@ -6258,7 +6112,7 @@ async function migrateProjectWorkflow(specPath) {
6258
6112
  }
6259
6113
 
6260
6114
  // src/local-runtime/foundation-runner.ts
6261
- import { createHash as createHash5, randomUUID as randomUUID7 } from "crypto";
6115
+ import { createHash as createHash5, randomUUID as randomUUID8 } from "crypto";
6262
6116
  import { createReadStream } from "fs";
6263
6117
  import { chmod as chmod2, lstat as lstat6, mkdir as mkdir4, open as open3, readdir as readdir4, readFile as readFile6, rename as rename4, rm as rm3 } from "fs/promises";
6264
6118
  import { basename as basename4, dirname as dirname6, join as join10, resolve as resolve5 } from "path";
@@ -6342,7 +6196,7 @@ async function readRequiredJsonObject(path, description) {
6342
6196
  return parsed;
6343
6197
  }
6344
6198
  async function writePrivateTextAtomic(path, content) {
6345
- const temporary = join10(dirname6(path), `.${basename4(path)}.${randomUUID7()}.tmp`);
6199
+ const temporary = join10(dirname6(path), `.${basename4(path)}.${randomUUID8()}.tmp`);
6346
6200
  const file = await open3(temporary, "wx", 384);
6347
6201
  let closed = false;
6348
6202
  try {
@@ -6458,7 +6312,7 @@ async function runFoundationPipeline(args2) {
6458
6312
  assertFoundationPlanSupported(args2.spec, args2.plan);
6459
6313
  assertFoundationSettingsMatch(args2.spec.foundation, args2.plan);
6460
6314
  const outputDir = resolve5(
6461
- args2.outputDir ?? (args2.spec.runtime?.artifactRoot ? join10(resolve5(dirname6(args2.specPath), args2.spec.runtime.artifactRoot), "foundation-runs", randomUUID7()) : join10(dirname6(resolve5(args2.specPath)), DEFAULT_FOUNDATION_RUNS_DIR, randomUUID7()))
6315
+ args2.outputDir ?? (args2.spec.runtime?.artifactRoot ? join10(resolve5(dirname6(args2.specPath), args2.spec.runtime.artifactRoot), "foundation-runs", randomUUID8()) : join10(dirname6(resolve5(args2.specPath)), DEFAULT_FOUNDATION_RUNS_DIR, randomUUID8()))
6462
6316
  );
6463
6317
  if (args2.gpu && args2.spec.foundation.checkpoint_backup_dir && localPathsOverlap(outputDir, args2.spec.foundation.checkpoint_backup_dir)) {
6464
6318
  throw new Error("AWS checkpoint_backup_dir must be separate from the foundation run directory; overlapping backups can overwrite returned checkpoints.");
@@ -8769,7 +8623,7 @@ Run \`tt init\` to create one.`
8769
8623
 
8770
8624
  // src/serve-manager.ts
8771
8625
  import { spawn as spawn2 } from "child_process";
8772
- import { randomUUID as randomUUID8 } from "crypto";
8626
+ import { randomUUID as randomUUID9 } from "crypto";
8773
8627
  import { appendFileSync, mkdirSync as mkdirSync3 } from "fs";
8774
8628
  import { createServer } from "http";
8775
8629
  import { createServer as createNetServer } from "net";
@@ -8993,7 +8847,7 @@ var ManagedModelServer = class {
8993
8847
  });
8994
8848
  }
8995
8849
  async processGeneration(route, body, res, receivedAt) {
8996
- const requestId = `ttreq-${randomUUID8()}`;
8850
+ const requestId = `ttreq-${randomUUID9()}`;
8997
8851
  const startedAt = Date.now();
8998
8852
  const queuedMs = startedAt - receivedAt;
8999
8853
  this.activeRequests += 1;
@@ -11142,7 +10996,7 @@ async function runCli(version, runtime = {}) {
11142
10996
  }
11143
10997
 
11144
10998
  // src/index.ts
11145
- runCli("0.18.0").catch((err) => {
10999
+ runCli("0.19.0").catch((err) => {
11146
11000
  reportError(err);
11147
11001
  process.exit(1);
11148
11002
  });