@tuned-tensor/cli 0.9.0 → 0.9.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 +37 -0
- package/dist/chunk-DAP2Z7EZ.js +4400 -0
- package/dist/chunk-DAP2Z7EZ.js.map +1 -0
- package/dist/index.js +356 -128
- package/dist/index.js.map +1 -1
- package/dist/local-runtime.js +1630 -0
- package/dist/local-runtime.js.map +1 -0
- package/docs/local-runtime/architecture.md +91 -0
- package/docs/local-runtime/spark.md +107 -0
- package/examples/local-runtime/dry-runner.json +14 -0
- package/examples/local-runtime/general-regression.jsonl +4 -0
- package/examples/local-runtime/local-runner.json +25 -0
- package/examples/local-runtime/smoke-spec.json +41 -0
- package/package.json +16 -5
- package/training/local-runner/pyproject.toml +25 -0
- package/training/local-runner/src/evaluate.py +274 -0
- package/training/local-runner/src/model_contract.py +47 -0
- package/training/local-runner/src/prefetch.py +192 -0
- package/training/local-runner/src/serve.py +272 -0
- package/training/local-runner/src/sft_data.py +97 -0
- package/training/local-runner/src/train.py +289 -0
- package/training/local-runner/uv.lock +1204 -0
package/dist/index.js
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
assertLocalRunInputReady,
|
|
4
|
+
loadLocalRunInput,
|
|
5
|
+
loadLocalRunnerConfig,
|
|
6
|
+
runLocalPipeline
|
|
7
|
+
} from "./chunk-DAP2Z7EZ.js";
|
|
2
8
|
|
|
3
9
|
// src/cli.ts
|
|
4
10
|
import { spawn as spawn4 } from "child_process";
|
|
@@ -120,7 +126,8 @@ import {
|
|
|
120
126
|
getAgentDir,
|
|
121
127
|
ModelRuntime
|
|
122
128
|
} from "@earendil-works/pi-coding-agent";
|
|
123
|
-
import {
|
|
129
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
130
|
+
import { dirname, join } from "path";
|
|
124
131
|
function resolveAgentModel(runtime, selection) {
|
|
125
132
|
const resolved = resolveAgentModelDefinition(runtime, selection);
|
|
126
133
|
if (!runtime.hasConfiguredAuth(selection.provider)) {
|
|
@@ -154,12 +161,41 @@ function resolveAgentModelDefinition(runtime, selection) {
|
|
|
154
161
|
}
|
|
155
162
|
async function createPiModelRuntime() {
|
|
156
163
|
const agentDir = getAgentDir();
|
|
164
|
+
const modelsPath = join(agentDir, "models.json");
|
|
165
|
+
ensureOpenRouterAppHeaders(modelsPath);
|
|
157
166
|
return await ModelRuntime.create({
|
|
158
167
|
authPath: join(agentDir, "auth.json"),
|
|
159
|
-
modelsPath
|
|
168
|
+
modelsPath,
|
|
160
169
|
allowModelNetwork: false
|
|
161
170
|
});
|
|
162
171
|
}
|
|
172
|
+
var OPENROUTER_APP_HEADERS = {
|
|
173
|
+
"HTTP-Referer": "https://tunedtensor.com",
|
|
174
|
+
"X-Title": "Tuned Tensor"
|
|
175
|
+
};
|
|
176
|
+
function ensureOpenRouterAppHeaders(modelsPath) {
|
|
177
|
+
let config = {};
|
|
178
|
+
if (existsSync(modelsPath)) {
|
|
179
|
+
try {
|
|
180
|
+
const parsed = JSON.parse(readFileSync(modelsPath, "utf-8"));
|
|
181
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
182
|
+
config = parsed;
|
|
183
|
+
}
|
|
184
|
+
} catch {
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
const before = JSON.stringify(config);
|
|
189
|
+
const asRecord = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
190
|
+
const empty = () => ({});
|
|
191
|
+
const providers = asRecord(config.providers) ?? (config.providers = empty());
|
|
192
|
+
const openrouter = asRecord(providers.openrouter) ?? (providers.openrouter = empty());
|
|
193
|
+
const headers = asRecord(openrouter.headers) ?? (openrouter.headers = empty());
|
|
194
|
+
Object.assign(headers, OPENROUTER_APP_HEADERS);
|
|
195
|
+
if (JSON.stringify(config) === before) return;
|
|
196
|
+
mkdirSync(dirname(modelsPath), { recursive: true });
|
|
197
|
+
writeFileSync(modelsPath, JSON.stringify(config, null, 2) + "\n");
|
|
198
|
+
}
|
|
163
199
|
|
|
164
200
|
// src/agent-tools.ts
|
|
165
201
|
import { randomUUID } from "crypto";
|
|
@@ -235,6 +271,77 @@ function canonicalizeSpecBaseModel(body) {
|
|
|
235
271
|
return body;
|
|
236
272
|
}
|
|
237
273
|
|
|
274
|
+
// src/pipeline.ts
|
|
275
|
+
import {
|
|
276
|
+
canonicalPipeline as canonicalPortablePipeline,
|
|
277
|
+
parsePipeline,
|
|
278
|
+
pipelineDocumentSchema
|
|
279
|
+
} from "@tuned-tensor/pipeline-contract";
|
|
280
|
+
import {
|
|
281
|
+
PIPELINE_DOCUMENT_VERSION,
|
|
282
|
+
PIPELINE_EVALUATORS,
|
|
283
|
+
PIPELINE_MAX_STEPS,
|
|
284
|
+
PIPELINE_MAX_TRAIN_STEPS,
|
|
285
|
+
PIPELINE_STEP_CAPABILITIES,
|
|
286
|
+
PIPELINE_STEP_USES,
|
|
287
|
+
PIPELINE_TARGETS,
|
|
288
|
+
canonicalJson,
|
|
289
|
+
parsePipeline as parsePipeline2,
|
|
290
|
+
pipelineDocumentSchema as pipelineDocumentSchema2,
|
|
291
|
+
pipelineHash
|
|
292
|
+
} from "@tuned-tensor/pipeline-contract";
|
|
293
|
+
function stepReferences(step) {
|
|
294
|
+
if (step.uses === "evaluate") return step.with.model === "base" ? [] : [step.with.model];
|
|
295
|
+
if (step.uses === "compare") return [step.with.before, step.with.after];
|
|
296
|
+
return [];
|
|
297
|
+
}
|
|
298
|
+
function producerId(reference) {
|
|
299
|
+
return reference.from.slice(0, reference.from.lastIndexOf("."));
|
|
300
|
+
}
|
|
301
|
+
function validatePipeline(pipeline2) {
|
|
302
|
+
const structural = pipelineDocumentSchema.safeParse(pipeline2);
|
|
303
|
+
if (!structural.success) {
|
|
304
|
+
return structural.error.issues.map((issue) => {
|
|
305
|
+
const path = issue.path.map(String).join(".");
|
|
306
|
+
return path ? `${path}: ${issue.message}` : issue.message;
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
try {
|
|
310
|
+
parsePipeline(pipeline2);
|
|
311
|
+
return [];
|
|
312
|
+
} catch (error) {
|
|
313
|
+
return [error instanceof Error ? error.message : String(error)];
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
function canonicalPipeline(target = "local") {
|
|
317
|
+
return canonicalPortablePipeline(target);
|
|
318
|
+
}
|
|
319
|
+
function createExecutionPlan(pipeline2, selection = {}) {
|
|
320
|
+
const errors = validatePipeline(pipeline2);
|
|
321
|
+
if (errors.length) throw new Error(`Invalid pipeline:
|
|
322
|
+
- ${errors.join("\n- ")}`);
|
|
323
|
+
const normalized = parsePipeline(pipeline2);
|
|
324
|
+
const allIds = new Set(normalized.steps.map((step) => step.id));
|
|
325
|
+
for (const id of [...selection.only ?? [], ...selection.skip ?? []]) {
|
|
326
|
+
if (!allIds.has(id)) throw new Error(`Unknown pipeline step: ${id}.`);
|
|
327
|
+
}
|
|
328
|
+
const only = selection.only?.length ? new Set(selection.only) : void 0;
|
|
329
|
+
const skip = new Set(selection.skip ?? []);
|
|
330
|
+
const steps = normalized.steps.filter((step) => (!only || only.has(step.id)) && !skip.has(step.id));
|
|
331
|
+
if (!steps.length) throw new Error("Selection leaves no pipeline steps to run.");
|
|
332
|
+
const retained = new Map(steps.map((step) => [step.id, step]));
|
|
333
|
+
const resolved = steps.map((step) => {
|
|
334
|
+
const transfers = [];
|
|
335
|
+
for (const reference of stepReferences(step)) {
|
|
336
|
+
const producer = retained.get(producerId(reference));
|
|
337
|
+
if (!producer) throw new Error(`Step ${step.id} has a dependency on ${producerId(reference)}, which was omitted by --only or --skip.`);
|
|
338
|
+
if (producer.target !== step.target) transfers.push({ from: reference.from, from_target: producer.target, to_target: step.target });
|
|
339
|
+
}
|
|
340
|
+
return { ...step, transfers };
|
|
341
|
+
});
|
|
342
|
+
return { version: 1, ...normalized.name ? { name: normalized.name } : {}, steps: resolved };
|
|
343
|
+
}
|
|
344
|
+
|
|
238
345
|
// src/agent-tools.ts
|
|
239
346
|
var MAX_TOOL_OUTPUT = 32e3;
|
|
240
347
|
var MAX_PREPARED_ACTION = 24e3;
|
|
@@ -283,6 +390,17 @@ var RunBody = Type.Object({
|
|
|
283
390
|
var BaseModel = Type.Union(
|
|
284
391
|
SUPPORTED_BASE_MODELS.map((model) => Type.Literal(model))
|
|
285
392
|
);
|
|
393
|
+
var PipelineDocument = Type.Object({
|
|
394
|
+
version: Type.Literal(1),
|
|
395
|
+
name: Type.Optional(Type.String({ minLength: 1, maxLength: 120 })),
|
|
396
|
+
target: Type.Optional(Type.Union([Type.Literal("local"), Type.Literal("cloud")])),
|
|
397
|
+
steps: Type.Array(Type.Object({
|
|
398
|
+
id: Type.String({ minLength: 1, maxLength: 64, pattern: "^[a-z][a-z0-9_-]*$" }),
|
|
399
|
+
uses: Type.Union([Type.Literal("train"), Type.Literal("evaluate"), Type.Literal("compare")]),
|
|
400
|
+
target: Type.Optional(Type.Union([Type.Literal("local"), Type.Literal("cloud")])),
|
|
401
|
+
with: Type.Optional(Type.Record(Type.String(), Type.Unknown()))
|
|
402
|
+
}, { additionalProperties: false }), { minItems: 1, maxItems: 16 })
|
|
403
|
+
}, { additionalProperties: false });
|
|
286
404
|
var Example = Type.Object({
|
|
287
405
|
input: Type.String({ minLength: 1, maxLength: 1e5 }),
|
|
288
406
|
output: Type.String({ minLength: 1, maxLength: 1e5 })
|
|
@@ -460,7 +578,18 @@ function createTunedTensorTools(api) {
|
|
|
460
578
|
}, { additionalProperties: false }), async (p) => await api.get("/billing/transactions", {
|
|
461
579
|
page: p.page ?? 1,
|
|
462
580
|
per_page: p.per_page ?? 10
|
|
463
|
-
}))
|
|
581
|
+
})),
|
|
582
|
+
define("describe_pipeline", "Describe pipeline", "Describe the built-in v1 pipeline contract and canonical recipe. This never executes anything.", Type.Object({
|
|
583
|
+
target: Type.Optional(Type.Union([Type.Literal("local"), Type.Literal("cloud")]))
|
|
584
|
+
}, { additionalProperties: false }), async (p) => ({
|
|
585
|
+
version: 1,
|
|
586
|
+
components: ["train", "evaluate", "compare"],
|
|
587
|
+
canonical: canonicalPipeline(p.target ?? "local")
|
|
588
|
+
})),
|
|
589
|
+
define("validate_pipeline", "Validate pipeline", "Validate an ordered pipeline and resolve targets/transfers without filesystem, network, or execution side effects.", Type.Object({ pipeline: PipelineDocument }, { additionalProperties: false }), async (p) => {
|
|
590
|
+
const errors = validatePipeline(p.pipeline);
|
|
591
|
+
return { valid: errors.length === 0, errors, ...errors.length ? {} : { plan: createExecutionPlan(p.pipeline) } };
|
|
592
|
+
})
|
|
464
593
|
];
|
|
465
594
|
const mutations = [
|
|
466
595
|
define("prepare_create_spec", "Prepare create spec", "Prepare creating a spec. This never mutates; /approve is required.", Type.Object({
|
|
@@ -480,6 +609,19 @@ function createTunedTensorTools(api) {
|
|
|
480
609
|
changes: p.changes,
|
|
481
610
|
expected_spec_updated_at: current.updated_at
|
|
482
611
|
}));
|
|
612
|
+
}),
|
|
613
|
+
define("prepare_pipeline_run", "Prepare pipeline run", "Prepare a pipeline action for review only. It never executes a step, transfers an artifact, or reserves credits.", Type.Object({
|
|
614
|
+
pipeline: PipelineDocument,
|
|
615
|
+
dry_run: Type.Optional(Type.Boolean())
|
|
616
|
+
}, { additionalProperties: false }), async (p) => {
|
|
617
|
+
const errors = validatePipeline(p.pipeline);
|
|
618
|
+
if (errors.length) throw new Error(`Invalid pipeline:
|
|
619
|
+
- ${errors.join("\n- ")}`);
|
|
620
|
+
const plan = createExecutionPlan(p.pipeline);
|
|
621
|
+
return await api.propose(proposal("run_pipeline", "Run pipeline", "Review the resolved pipeline before any separate execution approval flow.", {
|
|
622
|
+
pipeline: p.pipeline,
|
|
623
|
+
dry_run: p.dry_run ?? true
|
|
624
|
+
}, { plan, execution: "not started" }));
|
|
483
625
|
})
|
|
484
626
|
];
|
|
485
627
|
return [...reads, ...mutations];
|
|
@@ -876,16 +1018,16 @@ var LocalAgentStore = class {
|
|
|
876
1018
|
};
|
|
877
1019
|
|
|
878
1020
|
// src/client.ts
|
|
879
|
-
import { readFileSync as
|
|
1021
|
+
import { readFileSync as readFileSync3, statSync } from "fs";
|
|
880
1022
|
import { basename } from "path";
|
|
881
1023
|
|
|
882
1024
|
// src/config.ts
|
|
883
1025
|
import {
|
|
884
1026
|
chmodSync,
|
|
885
|
-
existsSync,
|
|
886
|
-
mkdirSync,
|
|
887
|
-
readFileSync,
|
|
888
|
-
writeFileSync
|
|
1027
|
+
existsSync as existsSync2,
|
|
1028
|
+
mkdirSync as mkdirSync2,
|
|
1029
|
+
readFileSync as readFileSync2,
|
|
1030
|
+
writeFileSync as writeFileSync2
|
|
889
1031
|
} from "fs";
|
|
890
1032
|
import { homedir } from "os";
|
|
891
1033
|
import { join as join3 } from "path";
|
|
@@ -910,19 +1052,19 @@ function getConfigPath() {
|
|
|
910
1052
|
}
|
|
911
1053
|
function readConfig() {
|
|
912
1054
|
const path = getConfigPath();
|
|
913
|
-
if (!
|
|
1055
|
+
if (!existsSync2(path)) return {};
|
|
914
1056
|
try {
|
|
915
|
-
return JSON.parse(
|
|
1057
|
+
return JSON.parse(readFileSync2(path, "utf-8"));
|
|
916
1058
|
} catch {
|
|
917
1059
|
return {};
|
|
918
1060
|
}
|
|
919
1061
|
}
|
|
920
1062
|
function writeConfig(config) {
|
|
921
1063
|
const dir = getConfigDir();
|
|
922
|
-
if (!
|
|
1064
|
+
if (!existsSync2(dir)) mkdirSync2(dir, { recursive: true, mode: 448 });
|
|
923
1065
|
chmodSync(dir, 448);
|
|
924
1066
|
const path = getConfigPath();
|
|
925
|
-
|
|
1067
|
+
writeFileSync2(path, JSON.stringify(config, null, 2) + "\n", {
|
|
926
1068
|
mode: 384
|
|
927
1069
|
});
|
|
928
1070
|
chmodSync(path, 384);
|
|
@@ -933,7 +1075,7 @@ function updateConfig(partial) {
|
|
|
933
1075
|
}
|
|
934
1076
|
function clearConfig() {
|
|
935
1077
|
const path = getConfigPath();
|
|
936
|
-
if (
|
|
1078
|
+
if (existsSync2(path)) writeConfig({});
|
|
937
1079
|
}
|
|
938
1080
|
var DEFAULT_BASE_URL = "https://tunedtensor.com";
|
|
939
1081
|
function getBaseUrl(opts) {
|
|
@@ -963,10 +1105,10 @@ function getAgentSelection(env = process.env) {
|
|
|
963
1105
|
|
|
964
1106
|
// src/client.ts
|
|
965
1107
|
var ApiError = class extends Error {
|
|
966
|
-
constructor(status2,
|
|
1108
|
+
constructor(status2, code2, message) {
|
|
967
1109
|
super(message);
|
|
968
1110
|
this.status = status2;
|
|
969
|
-
this.code =
|
|
1111
|
+
this.code = code2;
|
|
970
1112
|
this.name = "ApiError";
|
|
971
1113
|
}
|
|
972
1114
|
};
|
|
@@ -1194,7 +1336,7 @@ function createCommandCompleter(getMode) {
|
|
|
1194
1336
|
// src/shell-context.ts
|
|
1195
1337
|
import { readFile as readFile2, readdir as readdir2, stat as stat2 } from "fs/promises";
|
|
1196
1338
|
import { homedir as homedir2 } from "os";
|
|
1197
|
-
import { basename as basename2, dirname, isAbsolute, join as join4, resolve } from "path";
|
|
1339
|
+
import { basename as basename2, dirname as dirname2, isAbsolute, join as join4, resolve } from "path";
|
|
1198
1340
|
async function readJsonObject(path) {
|
|
1199
1341
|
try {
|
|
1200
1342
|
const parsed = JSON.parse(await readFile2(path, "utf8"));
|
|
@@ -1312,7 +1454,7 @@ async function discoverShellContext(options = {}) {
|
|
|
1312
1454
|
if (localConfigJson.invalid) {
|
|
1313
1455
|
warnings.push("local-runner.json could not be parsed.");
|
|
1314
1456
|
}
|
|
1315
|
-
const localConfigDirectory = hasAdjacentLocalConfig ?
|
|
1457
|
+
const localConfigDirectory = hasAdjacentLocalConfig ? dirname2(localConfigPath) : cwd;
|
|
1316
1458
|
const configuredArtifactRoot = stringField(localConfigJson.value, "artifactRoot");
|
|
1317
1459
|
const configuredStoreRoot = stringField(localConfigJson.value, "storeRoot");
|
|
1318
1460
|
const artifactRoot = configuredArtifactRoot ? expandPath(configuredArtifactRoot, localConfigDirectory, homeDirectory) : resolve(cwd, ".tt-local", "artifacts");
|
|
@@ -1742,9 +1884,9 @@ function renderShellBanner(snapshot) {
|
|
|
1742
1884
|
const heading = snapshot.version ? `${accent.bold("tt")} ${chalk.dim(`v${snapshot.version}`)}` : accent.bold("tt");
|
|
1743
1885
|
const lines = [
|
|
1744
1886
|
heading,
|
|
1745
|
-
chalk.dim(
|
|
1746
|
-
|
|
1747
|
-
)
|
|
1887
|
+
`${accent(snapshot.mode)}${chalk.dim(
|
|
1888
|
+
` \xB7 ${snapshot.context.projectName} \xB7 ${spec} \xB7 model ${activeModelLabel(snapshot)}`
|
|
1889
|
+
)}`,
|
|
1748
1890
|
chalk.dim("ctrl+c stop/clear \xB7 ctrl+d exit \xB7 /help commands \xB7 tab complete"),
|
|
1749
1891
|
"",
|
|
1750
1892
|
chalk.dim("Ask TT anything. Known commands run directly.")
|
|
@@ -2101,6 +2243,7 @@ function shouldStartInteractiveShell(options) {
|
|
|
2101
2243
|
import chalk2 from "chalk";
|
|
2102
2244
|
import { stripVTControlCharacters as stripVTControlCharacters2 } from "util";
|
|
2103
2245
|
var accent2 = chalk2.hex("#8B5CF6");
|
|
2246
|
+
var code = chalk2.hex("#A78BFA");
|
|
2104
2247
|
function sanitizeTerminalText(text2) {
|
|
2105
2248
|
return stripVTControlCharacters2(text2).replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f-\u009f]/g, "");
|
|
2106
2249
|
}
|
|
@@ -2138,7 +2281,7 @@ function renderInlineMarkdown(text2) {
|
|
|
2138
2281
|
if (text2[index] === "`") {
|
|
2139
2282
|
const close = closingDelimiter(text2, "`", index);
|
|
2140
2283
|
if (close > index + 1) {
|
|
2141
|
-
rendered +=
|
|
2284
|
+
rendered += code(text2.slice(index + 1, close));
|
|
2142
2285
|
index = close + 1;
|
|
2143
2286
|
continue;
|
|
2144
2287
|
}
|
|
@@ -2160,7 +2303,7 @@ function renderInlineMarkdown(text2) {
|
|
|
2160
2303
|
return rendered;
|
|
2161
2304
|
}
|
|
2162
2305
|
function renderMarkdownLine(line, inCodeBlock) {
|
|
2163
|
-
if (inCodeBlock) return
|
|
2306
|
+
if (inCodeBlock) return code(` ${line}`);
|
|
2164
2307
|
const heading = line.match(/^\s{0,3}#{1,6}\s+(.+)$/);
|
|
2165
2308
|
if (heading) return chalk2.bold(renderInlineMarkdown(heading[1]));
|
|
2166
2309
|
const bullet = line.match(/^(\s*)[-+*]\s+(.+)$/);
|
|
@@ -2646,8 +2789,9 @@ ${chalk3.yellow.bold("Approval required")} ${chalk3.dim(action.id.slice(0, 8))}
|
|
|
2646
2789
|
// src/local-runner.ts
|
|
2647
2790
|
import { constants as osConstants } from "os";
|
|
2648
2791
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
2649
|
-
import { createRequire } from "module";
|
|
2650
2792
|
import { spawn } from "child_process";
|
|
2793
|
+
import { existsSync as existsSync3 } from "fs";
|
|
2794
|
+
import { fileURLToPath } from "url";
|
|
2651
2795
|
import {
|
|
2652
2796
|
readFile as readFile3,
|
|
2653
2797
|
rm,
|
|
@@ -2656,7 +2800,7 @@ import {
|
|
|
2656
2800
|
} from "fs/promises";
|
|
2657
2801
|
import {
|
|
2658
2802
|
basename as basename3,
|
|
2659
|
-
dirname as
|
|
2803
|
+
dirname as dirname3,
|
|
2660
2804
|
isAbsolute as isAbsolute3,
|
|
2661
2805
|
join as join5,
|
|
2662
2806
|
resolve as resolve3
|
|
@@ -2728,6 +2872,7 @@ function unknownProjectSpecKeys(raw) {
|
|
|
2728
2872
|
// src/output.ts
|
|
2729
2873
|
import chalk4 from "chalk";
|
|
2730
2874
|
import Table from "cli-table3";
|
|
2875
|
+
var labelStyle = chalk4.bold.hex("#A78BFA");
|
|
2731
2876
|
var jsonMode = false;
|
|
2732
2877
|
function setJsonMode(enabled) {
|
|
2733
2878
|
jsonMode = enabled;
|
|
@@ -2740,7 +2885,7 @@ function printJson(data3) {
|
|
|
2740
2885
|
}
|
|
2741
2886
|
function printTable(headers, rows2, meta) {
|
|
2742
2887
|
const table = new Table({
|
|
2743
|
-
head: headers.map((h) =>
|
|
2888
|
+
head: headers.map((h) => labelStyle(h)),
|
|
2744
2889
|
style: { head: [], border: [] }
|
|
2745
2890
|
});
|
|
2746
2891
|
for (const row of rows2) {
|
|
@@ -2761,7 +2906,7 @@ function printDetail(fields) {
|
|
|
2761
2906
|
const maxLabel = Math.max(...fields.map(([l]) => l.length));
|
|
2762
2907
|
for (const [label, value] of fields) {
|
|
2763
2908
|
const paddedLabel = label.padEnd(maxLabel);
|
|
2764
|
-
console.log(`${
|
|
2909
|
+
console.log(`${labelStyle(paddedLabel)} ${value ?? chalk4.dim("\u2014")}`);
|
|
2765
2910
|
}
|
|
2766
2911
|
}
|
|
2767
2912
|
function printSuccess(message) {
|
|
@@ -2797,9 +2942,9 @@ function formatDate(iso) {
|
|
|
2797
2942
|
function formatStatus(status2) {
|
|
2798
2943
|
const map = {
|
|
2799
2944
|
completed: chalk4.green,
|
|
2800
|
-
running: chalk4.
|
|
2801
|
-
training: chalk4.
|
|
2802
|
-
evaluating: chalk4.
|
|
2945
|
+
running: chalk4.hex("#A78BFA"),
|
|
2946
|
+
training: chalk4.hex("#A78BFA"),
|
|
2947
|
+
evaluating: chalk4.hex("#A78BFA"),
|
|
2803
2948
|
preparing: chalk4.yellow,
|
|
2804
2949
|
pending: chalk4.yellow,
|
|
2805
2950
|
uploading: chalk4.yellow,
|
|
@@ -3274,7 +3419,6 @@ function renderLocalOutput(payload, options = {}) {
|
|
|
3274
3419
|
}
|
|
3275
3420
|
|
|
3276
3421
|
// src/local-runner.ts
|
|
3277
|
-
var localRequire = createRequire(import.meta.url);
|
|
3278
3422
|
var DEFAULT_SPEC_NAME = "tunedtensor.json";
|
|
3279
3423
|
var VALUE_OPTIONS = /* @__PURE__ */ new Set([
|
|
3280
3424
|
"--config",
|
|
@@ -3439,7 +3583,7 @@ async function projectSpecArguments(originalArgs, cwd) {
|
|
|
3439
3583
|
};
|
|
3440
3584
|
}
|
|
3441
3585
|
const temporaryPath = join5(
|
|
3442
|
-
|
|
3586
|
+
dirname3(sourcePath),
|
|
3443
3587
|
`.${basename3(sourcePath)}.tt-local-${process.pid}-${randomUUID4()}.json`
|
|
3444
3588
|
);
|
|
3445
3589
|
await writeFile2(
|
|
@@ -3460,14 +3604,13 @@ async function projectSpecArguments(originalArgs, cwd) {
|
|
|
3460
3604
|
};
|
|
3461
3605
|
}
|
|
3462
3606
|
function resolveLocalCliEntrypoint() {
|
|
3463
|
-
|
|
3464
|
-
|
|
3465
|
-
} catch (error) {
|
|
3607
|
+
const entrypoint = fileURLToPath(new URL("./local-runtime.js", import.meta.url));
|
|
3608
|
+
if (!existsSync3(entrypoint)) {
|
|
3466
3609
|
throw new Error(
|
|
3467
|
-
"
|
|
3468
|
-
{ cause: error }
|
|
3610
|
+
"The bundled local runtime is missing. Rebuild or reinstall @tuned-tensor/cli."
|
|
3469
3611
|
);
|
|
3470
3612
|
}
|
|
3613
|
+
return entrypoint;
|
|
3471
3614
|
}
|
|
3472
3615
|
function localCommandStreamsStdout(args2) {
|
|
3473
3616
|
const serves = args2[0] === "serve" || args2[0] === "models" && args2[1] === "serve";
|
|
@@ -3572,10 +3715,10 @@ async function spawnLocalCli(args2) {
|
|
|
3572
3715
|
child.once("error", (error) => {
|
|
3573
3716
|
spawnError = error;
|
|
3574
3717
|
});
|
|
3575
|
-
child.once("close", (
|
|
3718
|
+
child.once("close", (code2, signal) => {
|
|
3576
3719
|
cleanup();
|
|
3577
3720
|
resolveChild({
|
|
3578
|
-
exitCode: spawnError ? 1 :
|
|
3721
|
+
exitCode: spawnError ? 1 : code2 ?? signalExitCode(signal),
|
|
3579
3722
|
signal,
|
|
3580
3723
|
stdout: stdout2,
|
|
3581
3724
|
stderr,
|
|
@@ -3695,7 +3838,7 @@ function registerAuthCommands(parent) {
|
|
|
3695
3838
|
console.log(
|
|
3696
3839
|
` To get your API key, go to ${chalk5.bold("Settings \u2192 API Keys")} in the Tuned Tensor dashboard:`
|
|
3697
3840
|
);
|
|
3698
|
-
console.log(` ${chalk5.
|
|
3841
|
+
console.log(` ${chalk5.hex("#A78BFA").underline(settingsUrl)}`);
|
|
3699
3842
|
console.log();
|
|
3700
3843
|
apiKey = await promptForApiKey();
|
|
3701
3844
|
}
|
|
@@ -3754,7 +3897,7 @@ function registerAuthCommands(parent) {
|
|
|
3754
3897
|
}
|
|
3755
3898
|
|
|
3756
3899
|
// src/commands/specs.ts
|
|
3757
|
-
import { readFileSync as
|
|
3900
|
+
import { readFileSync as readFileSync4 } from "fs";
|
|
3758
3901
|
|
|
3759
3902
|
// src/resolve.ts
|
|
3760
3903
|
var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
@@ -3858,7 +4001,7 @@ var SpecBodyError = class extends Error {
|
|
|
3858
4001
|
function loadSpecBody(filePath, mode) {
|
|
3859
4002
|
let parsed;
|
|
3860
4003
|
try {
|
|
3861
|
-
parsed = JSON.parse(
|
|
4004
|
+
parsed = JSON.parse(readFileSync4(filePath, "utf-8"));
|
|
3862
4005
|
} catch (e) {
|
|
3863
4006
|
throw new SpecBodyError(
|
|
3864
4007
|
`Could not parse ${filePath}: ${e.message}`
|
|
@@ -4527,7 +4670,7 @@ Eval Results (${data3._evals.length}):`);
|
|
|
4527
4670
|
}
|
|
4528
4671
|
|
|
4529
4672
|
// src/commands/datasets.ts
|
|
4530
|
-
import { existsSync as
|
|
4673
|
+
import { existsSync as existsSync4, readFileSync as readFileSync5, statSync as statSync2 } from "fs";
|
|
4531
4674
|
var DOCUMENT_OCR_MIME_TYPES = /* @__PURE__ */ new Set(["image/png", "image/jpeg", "image/webp"]);
|
|
4532
4675
|
function formatBytes(bytes) {
|
|
4533
4676
|
if (bytes < 1024) return `${bytes} B`;
|
|
@@ -4563,24 +4706,24 @@ var FORBIDDEN_CONTROL_CODEPOINTS = [
|
|
|
4563
4706
|
];
|
|
4564
4707
|
function findControlChar(value) {
|
|
4565
4708
|
for (let i = 0; i < value.length; i++) {
|
|
4566
|
-
const
|
|
4567
|
-
if (
|
|
4568
|
-
const named = FORBIDDEN_CONTROL_CODEPOINTS.find((entry) => entry.code ===
|
|
4569
|
-
return { codepoint:
|
|
4709
|
+
const code2 = value.charCodeAt(i);
|
|
4710
|
+
if (code2 < 32 && code2 !== 9 && code2 !== 10 && code2 !== 13) {
|
|
4711
|
+
const named = FORBIDDEN_CONTROL_CODEPOINTS.find((entry) => entry.code === code2);
|
|
4712
|
+
return { codepoint: code2, offset: i, name: named?.name ?? "CONTROL CHARACTER" };
|
|
4570
4713
|
}
|
|
4571
|
-
if (
|
|
4572
|
-
const named = FORBIDDEN_CONTROL_CODEPOINTS.find((entry) => entry.code ===
|
|
4573
|
-
return { codepoint:
|
|
4714
|
+
if (code2 >= 128 && code2 <= 159) {
|
|
4715
|
+
const named = FORBIDDEN_CONTROL_CODEPOINTS.find((entry) => entry.code === code2);
|
|
4716
|
+
return { codepoint: code2, offset: i, name: named?.name ?? "C1 CONTROL CHARACTER" };
|
|
4574
4717
|
}
|
|
4575
|
-
if (
|
|
4576
|
-
const named = FORBIDDEN_CONTROL_CODEPOINTS.find((entry) => entry.code ===
|
|
4577
|
-
return { codepoint:
|
|
4718
|
+
if (code2 === 8232 || code2 === 8233) {
|
|
4719
|
+
const named = FORBIDDEN_CONTROL_CODEPOINTS.find((entry) => entry.code === code2);
|
|
4720
|
+
return { codepoint: code2, offset: i, name: named?.name ?? "LINE BREAK" };
|
|
4578
4721
|
}
|
|
4579
4722
|
}
|
|
4580
4723
|
return null;
|
|
4581
4724
|
}
|
|
4582
|
-
function formatCodepoint(
|
|
4583
|
-
return `U+${
|
|
4725
|
+
function formatCodepoint(code2) {
|
|
4726
|
+
return `U+${code2.toString(16).toUpperCase().padStart(4, "0")}`;
|
|
4584
4727
|
}
|
|
4585
4728
|
function detectRowFormat(record4) {
|
|
4586
4729
|
const input = record4.input;
|
|
@@ -4657,7 +4800,7 @@ function parseDatasetFormat(value) {
|
|
|
4657
4800
|
throw new Error("--format must be one of: jsonl, document_ocr_jsonl");
|
|
4658
4801
|
}
|
|
4659
4802
|
function validateDatasetFile(file, requestedFormat) {
|
|
4660
|
-
const lines =
|
|
4803
|
+
const lines = readFileSync5(file, "utf8").split(/\r?\n/);
|
|
4661
4804
|
const errors = [];
|
|
4662
4805
|
let rowCount = 0;
|
|
4663
4806
|
let detectedFormat = null;
|
|
@@ -4783,13 +4926,13 @@ function registerDatasetsCommands(parent) {
|
|
|
4783
4926
|
});
|
|
4784
4927
|
datasets.command("upload").description("Upload a JSONL dataset file").argument("<file>", "Path to JSONL file").option("-n, --name <name>", "Dataset name (defaults to filename)").option("-d, --description <desc>", "Dataset description").option("--format <format>", "Dataset format: jsonl or document_ocr_jsonl").action(async (file, cmdOpts) => {
|
|
4785
4928
|
const opts = parent.opts();
|
|
4786
|
-
if (!
|
|
4929
|
+
if (!existsSync4(file)) {
|
|
4787
4930
|
printError(`File not found: ${file}`);
|
|
4788
4931
|
process.exit(1);
|
|
4789
4932
|
}
|
|
4790
4933
|
const format = validateDatasetFile(file, parseDatasetFormat(cmdOpts.format));
|
|
4791
4934
|
const name = cmdOpts.name || file.split("/").pop().replace(/\.jsonl?$/, "");
|
|
4792
|
-
const fileBytes =
|
|
4935
|
+
const fileBytes = readFileSync5(file);
|
|
4793
4936
|
const uploadUrl = await post(
|
|
4794
4937
|
"/datasets/upload-url",
|
|
4795
4938
|
{
|
|
@@ -4834,12 +4977,12 @@ function registerDatasetsCommands(parent) {
|
|
|
4834
4977
|
}
|
|
4835
4978
|
|
|
4836
4979
|
// src/commands/label.ts
|
|
4837
|
-
import { existsSync as
|
|
4980
|
+
import { existsSync as existsSync5, readFileSync as readFileSync6, statSync as statSync3 } from "fs";
|
|
4838
4981
|
function formatCents2(cents) {
|
|
4839
4982
|
return `$${(cents / 100).toFixed(2)}`;
|
|
4840
4983
|
}
|
|
4841
4984
|
function sleep(ms) {
|
|
4842
|
-
return new Promise((
|
|
4985
|
+
return new Promise((resolve8) => setTimeout(resolve8, ms));
|
|
4843
4986
|
}
|
|
4844
4987
|
function parseCsvHeader(line) {
|
|
4845
4988
|
const fields = [];
|
|
@@ -4878,7 +5021,7 @@ function validateUnlabeledFile(file, inputColumn) {
|
|
|
4878
5021
|
"CSV uploads need --input-column <name> to say which column holds the input text."
|
|
4879
5022
|
);
|
|
4880
5023
|
}
|
|
4881
|
-
const firstLine =
|
|
5024
|
+
const firstLine = readFileSync6(file, "utf8").split(/\r?\n/, 1)[0] ?? "";
|
|
4882
5025
|
const columns = parseCsvHeader(firstLine);
|
|
4883
5026
|
if (!columns.includes(inputColumn)) {
|
|
4884
5027
|
throw new Error(
|
|
@@ -4890,7 +5033,7 @@ function validateUnlabeledFile(file, inputColumn) {
|
|
|
4890
5033
|
if (!lower.endsWith(".jsonl") && !lower.endsWith(".json")) {
|
|
4891
5034
|
throw new Error("Labeling source file must be .jsonl or .csv");
|
|
4892
5035
|
}
|
|
4893
|
-
const lines =
|
|
5036
|
+
const lines = readFileSync6(file, "utf8").split(/\r?\n/);
|
|
4894
5037
|
const errors = [];
|
|
4895
5038
|
let rowCount = 0;
|
|
4896
5039
|
for (const [index, rawLine] of lines.entries()) {
|
|
@@ -5006,14 +5149,14 @@ function registerLabelCommands(parent) {
|
|
|
5006
5149
|
const label = parent.command("label").description("Teacher-label real data into training datasets");
|
|
5007
5150
|
label.command("upload").description("Upload unlabeled inputs (.jsonl or .csv) and start a labeling job").argument("<file>", 'Path to JSONL ({"input": ...} per line) or CSV file').requiredOption("-s, --spec <id>", "Behaviour spec the teacher labels under").option("-c, --input-column <name>", "CSV column that holds the input text").option("-n, --name <name>", "Job name (defaults to filename)").option("--watch", "Block and show progress until labeling finishes").action(async (file, cmdOpts) => {
|
|
5008
5151
|
const opts = parent.opts();
|
|
5009
|
-
if (!
|
|
5152
|
+
if (!existsSync5(file)) {
|
|
5010
5153
|
printError(`File not found: ${file}`);
|
|
5011
5154
|
process.exit(1);
|
|
5012
5155
|
}
|
|
5013
5156
|
const { format } = validateUnlabeledFile(file, cmdOpts.inputColumn);
|
|
5014
5157
|
const specId = await resolveSpecId(cmdOpts.spec, opts);
|
|
5015
5158
|
const name = cmdOpts.name || file.split("/").pop().replace(/\.(jsonl|json|csv)$/, "");
|
|
5016
|
-
const fileBytes =
|
|
5159
|
+
const fileBytes = readFileSync6(file);
|
|
5017
5160
|
const contentType = format === "csv" ? "text/csv" : "application/jsonl";
|
|
5018
5161
|
const { data: uploadUrl } = await post(
|
|
5019
5162
|
"/labeling-jobs/upload-url",
|
|
@@ -5186,7 +5329,7 @@ function registerLabelCommands(parent) {
|
|
|
5186
5329
|
printError("Provide --output <text> or --file <path>.");
|
|
5187
5330
|
process.exit(1);
|
|
5188
5331
|
}
|
|
5189
|
-
const output = cmdOpts.output ??
|
|
5332
|
+
const output = cmdOpts.output ?? readFileSync6(cmdOpts.file, "utf8");
|
|
5190
5333
|
const jobId = await resolveLabelingJobId(id, opts);
|
|
5191
5334
|
const indexes = parseIndexList(cmdOpts.row);
|
|
5192
5335
|
const rowIds = await resolveRowIds(jobId, indexes, opts);
|
|
@@ -5235,23 +5378,23 @@ function registerLabelCommands(parent) {
|
|
|
5235
5378
|
import { spawn as spawn3, execFileSync } from "child_process";
|
|
5236
5379
|
import { createHash } from "crypto";
|
|
5237
5380
|
import {
|
|
5238
|
-
existsSync as
|
|
5239
|
-
mkdirSync as
|
|
5381
|
+
existsSync as existsSync7,
|
|
5382
|
+
mkdirSync as mkdirSync4,
|
|
5240
5383
|
statSync as statSync4,
|
|
5241
5384
|
createWriteStream,
|
|
5242
5385
|
unlinkSync,
|
|
5243
|
-
readFileSync as
|
|
5244
|
-
writeFileSync as
|
|
5386
|
+
readFileSync as readFileSync8,
|
|
5387
|
+
writeFileSync as writeFileSync4,
|
|
5245
5388
|
readdirSync,
|
|
5246
5389
|
rmSync
|
|
5247
5390
|
} from "fs";
|
|
5248
5391
|
import { homedir as homedir4 } from "os";
|
|
5249
|
-
import { dirname as
|
|
5392
|
+
import { dirname as dirname5, join as join6, resolve as resolve5, basename as basename4, normalize, isAbsolute as isAbsolute4 } from "path";
|
|
5250
5393
|
import { Readable, Transform } from "stream";
|
|
5251
5394
|
import { pipeline } from "stream/promises";
|
|
5252
5395
|
|
|
5253
5396
|
// src/commands/init.ts
|
|
5254
|
-
import { existsSync as
|
|
5397
|
+
import { existsSync as existsSync6, readFileSync as readFileSync7, writeFileSync as writeFileSync3 } from "fs";
|
|
5255
5398
|
import { resolve as resolve4 } from "path";
|
|
5256
5399
|
var DEFAULT_SPEC_FILE = "tunedtensor.json";
|
|
5257
5400
|
var SCAFFOLD = {
|
|
@@ -5272,7 +5415,7 @@ var SCAFFOLD = {
|
|
|
5272
5415
|
function registerInitCommand(parent) {
|
|
5273
5416
|
parent.command("init").description("Create a behaviour spec project file").option("-n, --name <name>", "Spec name").option("--model <model>", "Base model ID").option("-f, --file <path>", "Output file path", DEFAULT_SPEC_FILE).action(async (cmdOpts) => {
|
|
5274
5417
|
const filePath = resolve4(cmdOpts.file);
|
|
5275
|
-
if (
|
|
5418
|
+
if (existsSync6(filePath)) {
|
|
5276
5419
|
if (isJsonMode()) {
|
|
5277
5420
|
printJson({ created: false, path: filePath });
|
|
5278
5421
|
return;
|
|
@@ -5286,7 +5429,7 @@ function registerInitCommand(parent) {
|
|
|
5286
5429
|
};
|
|
5287
5430
|
if (cmdOpts.name) spec.name = cmdOpts.name;
|
|
5288
5431
|
if (cmdOpts.model) spec.base_model = canonicalizeBaseModel(cmdOpts.model);
|
|
5289
|
-
|
|
5432
|
+
writeFileSync3(filePath, JSON.stringify(spec, null, 2) + "\n");
|
|
5290
5433
|
if (isJsonMode()) {
|
|
5291
5434
|
printJson({ created: true, path: filePath, spec });
|
|
5292
5435
|
return;
|
|
@@ -5301,36 +5444,36 @@ function registerInitCommand(parent) {
|
|
|
5301
5444
|
}
|
|
5302
5445
|
function loadSpec(filePath) {
|
|
5303
5446
|
const resolved = resolve4(filePath || DEFAULT_SPEC_FILE);
|
|
5304
|
-
if (!
|
|
5447
|
+
if (!existsSync6(resolved)) {
|
|
5305
5448
|
printError(
|
|
5306
5449
|
`Spec file not found: ${filePath || DEFAULT_SPEC_FILE}
|
|
5307
5450
|
Run \`tt init\` to create one.`
|
|
5308
5451
|
);
|
|
5309
5452
|
process.exit(1);
|
|
5310
5453
|
}
|
|
5311
|
-
const raw = JSON.parse(
|
|
5454
|
+
const raw = JSON.parse(readFileSync7(resolved, "utf-8"));
|
|
5312
5455
|
return raw;
|
|
5313
5456
|
}
|
|
5314
5457
|
|
|
5315
5458
|
// src/serve-manager.ts
|
|
5316
5459
|
import { spawn as spawn2 } from "child_process";
|
|
5317
5460
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
5318
|
-
import { appendFileSync, mkdirSync as
|
|
5461
|
+
import { appendFileSync, mkdirSync as mkdirSync3 } from "fs";
|
|
5319
5462
|
import { createServer } from "http";
|
|
5320
5463
|
import { createServer as createNetServer } from "net";
|
|
5321
|
-
import { dirname as
|
|
5464
|
+
import { dirname as dirname4 } from "path";
|
|
5322
5465
|
var COMPLETION_ROUTES = /* @__PURE__ */ new Set(["/v1/chat/completions", "/chat/completions"]);
|
|
5323
5466
|
function parsePositiveInteger(value, fallback) {
|
|
5324
5467
|
return Number.isInteger(value) && value >= 0 ? value : fallback;
|
|
5325
5468
|
}
|
|
5326
5469
|
function sleep2(ms) {
|
|
5327
|
-
return new Promise((
|
|
5470
|
+
return new Promise((resolve8) => setTimeout(resolve8, ms));
|
|
5328
5471
|
}
|
|
5329
5472
|
function readRequestBody(req) {
|
|
5330
|
-
return new Promise((
|
|
5473
|
+
return new Promise((resolve8, reject) => {
|
|
5331
5474
|
const chunks = [];
|
|
5332
5475
|
req.on("data", (chunk) => chunks.push(Buffer.from(chunk)));
|
|
5333
|
-
req.on("end", () =>
|
|
5476
|
+
req.on("end", () => resolve8(Buffer.concat(chunks)));
|
|
5334
5477
|
req.on("error", reject);
|
|
5335
5478
|
});
|
|
5336
5479
|
}
|
|
@@ -5398,7 +5541,7 @@ function errorSummary(response, fallback) {
|
|
|
5398
5541
|
return typeof message === "string" ? message : fallback;
|
|
5399
5542
|
}
|
|
5400
5543
|
async function allocatePort(host) {
|
|
5401
|
-
return new Promise((
|
|
5544
|
+
return new Promise((resolve8, reject) => {
|
|
5402
5545
|
const server = createNetServer();
|
|
5403
5546
|
server.on("error", reject);
|
|
5404
5547
|
server.listen(0, host, () => {
|
|
@@ -5408,7 +5551,7 @@ async function allocatePort(host) {
|
|
|
5408
5551
|
return;
|
|
5409
5552
|
}
|
|
5410
5553
|
const port = address.port;
|
|
5411
|
-
server.close(() =>
|
|
5554
|
+
server.close(() => resolve8(port));
|
|
5412
5555
|
});
|
|
5413
5556
|
});
|
|
5414
5557
|
}
|
|
@@ -5448,11 +5591,11 @@ var ManagedModelServer = class {
|
|
|
5448
5591
|
sendJson(res, 500, { error: { message: err instanceof Error ? err.message : String(err) } });
|
|
5449
5592
|
});
|
|
5450
5593
|
});
|
|
5451
|
-
await new Promise((
|
|
5594
|
+
await new Promise((resolve8, reject) => {
|
|
5452
5595
|
this.server?.once("error", reject);
|
|
5453
5596
|
this.server?.listen(this.options.publicPort, this.options.publicHost, () => {
|
|
5454
5597
|
this.server?.off("error", reject);
|
|
5455
|
-
|
|
5598
|
+
resolve8();
|
|
5456
5599
|
});
|
|
5457
5600
|
});
|
|
5458
5601
|
}
|
|
@@ -5462,15 +5605,15 @@ var ManagedModelServer = class {
|
|
|
5462
5605
|
if (!this.server) return;
|
|
5463
5606
|
const server = this.server;
|
|
5464
5607
|
this.server = null;
|
|
5465
|
-
await new Promise((
|
|
5466
|
-
server.close((err) => err ? reject(err) :
|
|
5608
|
+
await new Promise((resolve8, reject) => {
|
|
5609
|
+
server.close((err) => err ? reject(err) : resolve8());
|
|
5467
5610
|
});
|
|
5468
5611
|
}
|
|
5469
5612
|
async run() {
|
|
5470
5613
|
await this.start();
|
|
5471
|
-
await new Promise((
|
|
5614
|
+
await new Promise((resolve8, reject) => {
|
|
5472
5615
|
this.server?.once("error", reject);
|
|
5473
|
-
this.server?.once("close",
|
|
5616
|
+
this.server?.once("close", resolve8);
|
|
5474
5617
|
});
|
|
5475
5618
|
}
|
|
5476
5619
|
async handle(req, res) {
|
|
@@ -5644,7 +5787,7 @@ var ManagedModelServer = class {
|
|
|
5644
5787
|
try {
|
|
5645
5788
|
child.kill("SIGTERM");
|
|
5646
5789
|
await Promise.race([
|
|
5647
|
-
new Promise((
|
|
5790
|
+
new Promise((resolve8) => child.once("exit", () => resolve8())),
|
|
5648
5791
|
sleep2(5e3).then(() => {
|
|
5649
5792
|
if (child.exitCode == null && child.signalCode == null) child.kill("SIGKILL");
|
|
5650
5793
|
})
|
|
@@ -5722,7 +5865,7 @@ var ManagedModelServer = class {
|
|
|
5722
5865
|
const line = `${JSON.stringify(record4)}
|
|
5723
5866
|
`;
|
|
5724
5867
|
if (this.options.logFile) {
|
|
5725
|
-
|
|
5868
|
+
mkdirSync3(dirname4(this.options.logFile), { recursive: true });
|
|
5726
5869
|
appendFileSync(this.options.logFile, line, "utf8");
|
|
5727
5870
|
return;
|
|
5728
5871
|
}
|
|
@@ -6269,7 +6412,7 @@ if __name__ == "__main__":
|
|
|
6269
6412
|
`;
|
|
6270
6413
|
function resolveOutputPath(output, filename) {
|
|
6271
6414
|
if (!output) return filename;
|
|
6272
|
-
if (
|
|
6415
|
+
if (existsSync7(output) && statSync4(output).isDirectory()) {
|
|
6273
6416
|
return join6(output, filename);
|
|
6274
6417
|
}
|
|
6275
6418
|
return output;
|
|
@@ -6346,7 +6489,7 @@ async function downloadUrlToFile(url, outputPath) {
|
|
|
6346
6489
|
if (!res.body) {
|
|
6347
6490
|
throw new Error("Download failed: response body was empty");
|
|
6348
6491
|
}
|
|
6349
|
-
|
|
6492
|
+
mkdirSync4(dirname5(outputPath), { recursive: true });
|
|
6350
6493
|
const file = createWriteStream(outputPath);
|
|
6351
6494
|
const contentLength = parseContentLength(res.headers.get("content-length"));
|
|
6352
6495
|
const progress = createDownloadProgress(
|
|
@@ -6390,7 +6533,7 @@ function runtimePythonPath(cacheDir) {
|
|
|
6390
6533
|
function resolveServePython(cacheDir, explicitPython) {
|
|
6391
6534
|
if (explicitPython) return explicitPython;
|
|
6392
6535
|
const managedPython = runtimePythonPath(cacheDir);
|
|
6393
|
-
return
|
|
6536
|
+
return existsSync7(managedPython) ? managedPython : "python3";
|
|
6394
6537
|
}
|
|
6395
6538
|
function commandExists(command) {
|
|
6396
6539
|
try {
|
|
@@ -6469,7 +6612,7 @@ function safeSegment(value) {
|
|
|
6469
6612
|
return value.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "model";
|
|
6470
6613
|
}
|
|
6471
6614
|
function directoryHasFiles(path) {
|
|
6472
|
-
return
|
|
6615
|
+
return existsSync7(path) && statSync4(path).isDirectory() && readdirSync(path).length > 0;
|
|
6473
6616
|
}
|
|
6474
6617
|
function validateArchiveEntryPath(entry) {
|
|
6475
6618
|
const normalized = normalize(entry).replace(/^[\\/]+/, "");
|
|
@@ -6490,8 +6633,8 @@ function validateArchiveEntries(archivePath) {
|
|
|
6490
6633
|
function extractArchive(archivePath, targetDir, force) {
|
|
6491
6634
|
if (directoryHasFiles(targetDir) && !force) return targetDir;
|
|
6492
6635
|
validateArchiveEntries(archivePath);
|
|
6493
|
-
if (
|
|
6494
|
-
|
|
6636
|
+
if (existsSync7(targetDir)) rmSync(targetDir, { recursive: true, force: true });
|
|
6637
|
+
mkdirSync4(targetDir, { recursive: true });
|
|
6495
6638
|
execFileSync("tar", ["-xzf", archivePath, "-C", targetDir], { stdio: "inherit" });
|
|
6496
6639
|
return targetDir;
|
|
6497
6640
|
}
|
|
@@ -6517,21 +6660,21 @@ function findSpecPath(explicitPath, modelPath) {
|
|
|
6517
6660
|
const candidates = explicitPath ? [explicitPath] : [join6(process.cwd(), DEFAULT_SPEC_FILE), join6(modelPath, DEFAULT_SPEC_FILE)];
|
|
6518
6661
|
for (const candidate of candidates) {
|
|
6519
6662
|
const resolved = resolve5(candidate);
|
|
6520
|
-
if (
|
|
6663
|
+
if (existsSync7(resolved) && statSync4(resolved).isFile()) return resolved;
|
|
6521
6664
|
}
|
|
6522
6665
|
return null;
|
|
6523
6666
|
}
|
|
6524
6667
|
function loadSystemPromptFromSpec(specPath) {
|
|
6525
|
-
const spec = JSON.parse(
|
|
6668
|
+
const spec = JSON.parse(readFileSync8(specPath, "utf8"));
|
|
6526
6669
|
return buildSystemPrompt(spec);
|
|
6527
6670
|
}
|
|
6528
6671
|
function loadJsonSchemaForServe(schemaPath) {
|
|
6529
6672
|
const resolved = resolve5(schemaPath);
|
|
6530
|
-
if (!
|
|
6673
|
+
if (!existsSync7(resolved) || !statSync4(resolved).isFile()) {
|
|
6531
6674
|
throw new Error(`JSON schema file not found: ${schemaPath}`);
|
|
6532
6675
|
}
|
|
6533
6676
|
try {
|
|
6534
|
-
const schema = JSON.parse(
|
|
6677
|
+
const schema = JSON.parse(readFileSync8(resolved, "utf8"));
|
|
6535
6678
|
return JSON.stringify(schema);
|
|
6536
6679
|
} catch (err) {
|
|
6537
6680
|
throw new Error(`JSON schema file is not valid JSON: ${schemaPath}`);
|
|
@@ -6539,13 +6682,13 @@ function loadJsonSchemaForServe(schemaPath) {
|
|
|
6539
6682
|
}
|
|
6540
6683
|
function writeReferenceServerScript(cacheDir) {
|
|
6541
6684
|
const scriptDir = join6(cacheDir, "_server");
|
|
6542
|
-
|
|
6685
|
+
mkdirSync4(scriptDir, { recursive: true });
|
|
6543
6686
|
const scriptPath = join6(scriptDir, "openai_reference_server.py");
|
|
6544
|
-
|
|
6687
|
+
writeFileSync4(scriptPath, REFERENCE_SERVER_SCRIPT, "utf8");
|
|
6545
6688
|
return scriptPath;
|
|
6546
6689
|
}
|
|
6547
6690
|
async function resolveServeTarget(target, opts, cacheDir, forceDownload) {
|
|
6548
|
-
if (
|
|
6691
|
+
if (existsSync7(target)) {
|
|
6549
6692
|
const resolved = resolve5(target);
|
|
6550
6693
|
const stats = statSync4(resolved);
|
|
6551
6694
|
if (stats.isDirectory()) {
|
|
@@ -6571,7 +6714,7 @@ async function resolveServeTarget(target, opts, cacheDir, forceDownload) {
|
|
|
6571
6714
|
const modelCacheDir = join6(cacheDir, fullId);
|
|
6572
6715
|
const archivePath = join6(modelCacheDir, data3.filename);
|
|
6573
6716
|
const extractDir = join6(modelCacheDir, "model");
|
|
6574
|
-
if (!
|
|
6717
|
+
if (!existsSync7(archivePath) || forceDownload) {
|
|
6575
6718
|
await downloadUrlToFile(data3.url, archivePath);
|
|
6576
6719
|
}
|
|
6577
6720
|
extractArchive(archivePath, extractDir, forceDownload);
|
|
@@ -6675,7 +6818,7 @@ function ollamaSlug(name) {
|
|
|
6675
6818
|
}
|
|
6676
6819
|
function firstExisting(candidates) {
|
|
6677
6820
|
for (const candidate of candidates) {
|
|
6678
|
-
if (candidate &&
|
|
6821
|
+
if (candidate && existsSync7(candidate) && statSync4(candidate).isFile()) {
|
|
6679
6822
|
return resolve5(candidate);
|
|
6680
6823
|
}
|
|
6681
6824
|
}
|
|
@@ -6687,7 +6830,7 @@ function llamaCppDir(explicit) {
|
|
|
6687
6830
|
function resolveConvertScript(opts, required) {
|
|
6688
6831
|
if (opts.convertScript) {
|
|
6689
6832
|
const resolved = resolve5(opts.convertScript);
|
|
6690
|
-
if (required && !
|
|
6833
|
+
if (required && !existsSync7(resolved)) {
|
|
6691
6834
|
throw new Error(`Conversion script not found: ${opts.convertScript}`);
|
|
6692
6835
|
}
|
|
6693
6836
|
return resolved;
|
|
@@ -6706,7 +6849,7 @@ function resolveConvertScript(opts, required) {
|
|
|
6706
6849
|
function resolveQuantizeBin(opts, required) {
|
|
6707
6850
|
if (opts.quantizeBin) {
|
|
6708
6851
|
const resolved = resolve5(opts.quantizeBin);
|
|
6709
|
-
if (required && !
|
|
6852
|
+
if (required && !existsSync7(resolved)) {
|
|
6710
6853
|
throw new Error(`llama-quantize binary not found: ${opts.quantizeBin}`);
|
|
6711
6854
|
}
|
|
6712
6855
|
return resolved;
|
|
@@ -6841,7 +6984,7 @@ function registerModelsCommands(parent) {
|
|
|
6841
6984
|
opts
|
|
6842
6985
|
);
|
|
6843
6986
|
const outputPath = resolveOutputPath(cmdOpts.output, data3.filename);
|
|
6844
|
-
if (
|
|
6987
|
+
if (existsSync7(outputPath) && !cmdOpts.force) {
|
|
6845
6988
|
throw new Error(`Output file already exists: ${outputPath}. Use --force to overwrite.`);
|
|
6846
6989
|
}
|
|
6847
6990
|
const bytes = await downloadUrlToFile(data3.url, outputPath);
|
|
@@ -6866,7 +7009,7 @@ function registerModelsCommands(parent) {
|
|
|
6866
7009
|
const quantPlan = planQuant(String(cmdOpts.quant));
|
|
6867
7010
|
const printOnly = Boolean(cmdOpts.printCommand);
|
|
6868
7011
|
const cacheDir = resolve5(cmdOpts.cacheDir || defaultCacheDir());
|
|
6869
|
-
|
|
7012
|
+
mkdirSync4(cacheDir, { recursive: true });
|
|
6870
7013
|
const serveTarget = await resolveServeTarget(
|
|
6871
7014
|
target,
|
|
6872
7015
|
opts,
|
|
@@ -6950,10 +7093,10 @@ function registerModelsCommands(parent) {
|
|
|
6950
7093
|
ollama: ollamaInfo
|
|
6951
7094
|
};
|
|
6952
7095
|
if (printOnly) return printExportPlan(plan);
|
|
6953
|
-
if (
|
|
7096
|
+
if (existsSync7(finalPath) && !cmdOpts.force) {
|
|
6954
7097
|
throw new Error(`Output already exists: ${finalPath}. Use --force to overwrite.`);
|
|
6955
7098
|
}
|
|
6956
|
-
|
|
7099
|
+
mkdirSync4(outputDir, { recursive: true });
|
|
6957
7100
|
const runStep = (command, args2) => execFileSync(command, args2, { stdio: "inherit" });
|
|
6958
7101
|
if (!isJsonMode()) printSuccess(`Converting ${serveTarget.modelName} \u2192 ${quantPlan.convertOuttype} GGUF`);
|
|
6959
7102
|
runStep(cmdOpts.python, [
|
|
@@ -6971,12 +7114,12 @@ function registerModelsCommands(parent) {
|
|
|
6971
7114
|
finalPath,
|
|
6972
7115
|
quantPlan.quantizeType
|
|
6973
7116
|
]);
|
|
6974
|
-
if (!cmdOpts.keepIntermediate && intermediatePath &&
|
|
7117
|
+
if (!cmdOpts.keepIntermediate && intermediatePath && existsSync7(intermediatePath)) {
|
|
6975
7118
|
rmSync(intermediatePath, { force: true });
|
|
6976
7119
|
}
|
|
6977
7120
|
}
|
|
6978
7121
|
if (ollamaInfo) {
|
|
6979
|
-
|
|
7122
|
+
writeFileSync4(modelfilePath, modelfileContent, "utf8");
|
|
6980
7123
|
if (!isJsonMode()) printSuccess(`Wrote Modelfile to ${modelfilePath}`);
|
|
6981
7124
|
if (ollamaInfo.create) {
|
|
6982
7125
|
if (!isJsonMode()) printSuccess(`Creating Ollama model ${ollamaName}`);
|
|
@@ -7024,11 +7167,11 @@ function registerModelsCommands(parent) {
|
|
|
7024
7167
|
]);
|
|
7025
7168
|
return;
|
|
7026
7169
|
}
|
|
7027
|
-
if (
|
|
7170
|
+
if (existsSync7(venvDir) && cmdOpts.force) {
|
|
7028
7171
|
rmSync(venvDir, { recursive: true, force: true });
|
|
7029
7172
|
}
|
|
7030
|
-
if (!
|
|
7031
|
-
|
|
7173
|
+
if (!existsSync7(venvPython)) {
|
|
7174
|
+
mkdirSync4(cacheDir, { recursive: true });
|
|
7032
7175
|
execFileSync(commands[0][0], commands[0].slice(1), { stdio: "inherit" });
|
|
7033
7176
|
}
|
|
7034
7177
|
execFileSync(commands[1][0], commands[1].slice(1), { stdio: "inherit" });
|
|
@@ -7048,7 +7191,7 @@ function registerModelsCommands(parent) {
|
|
|
7048
7191
|
models.command("serve").description("Serve a downloaded model with an OpenAI-compatible local API").argument("<target>", "Model ID/prefix, model directory, or .tar.gz artifact").option("--spec <path>", "Behavior spec JSON to apply as the default system prompt").option("--no-spec-prompt", "Do not auto-apply a behavior spec system prompt").option("--host <host>", "Host to bind", "127.0.0.1").option("--port <port>", "Port to bind", "8000").option("--python <path>", "Python executable").option("--cache-dir <path>", "Cache directory for downloaded/extracted models").option("--device <device>", "Inference device: auto, cpu, cuda, or mps", "auto").option("--force-download", "Re-download and re-extract model artifacts").option("--max-tokens <n>", "Default max completion tokens", "512").option("--temperature <n>", "Default sampling temperature", "0.7").option("--json-schema <path>", "JSON Schema file to enforce by default for chat completions").option("--json-repair-attempts <n>", "Number of JSON/schema repair retries", "1").option("--trust-remote-code", "Pass trust_remote_code=True to transformers").option("--managed", "Run a local lifecycle manager in front of the model server").option("--idle-timeout <seconds>", "Managed mode idle timeout before stopping the model", "300").option("--restart-after-requests <n>", "Managed mode restart threshold; 0 disables request-count restarts", "100").option("--gate-field <field>", "Response JSON field to log as the managed serving gate result", "should_process").option("--log-file <path>", "Write managed serving JSONL request logs to a file").option("--print-command", "Print the underlying Python command without starting it").action(async (target, cmdOpts) => {
|
|
7049
7192
|
const opts = parent.opts();
|
|
7050
7193
|
const cacheDir = resolve5(cmdOpts.cacheDir || defaultCacheDir());
|
|
7051
|
-
|
|
7194
|
+
mkdirSync4(cacheDir, { recursive: true });
|
|
7052
7195
|
const python = resolveServePython(cacheDir, cmdOpts.python);
|
|
7053
7196
|
if (!cmdOpts.printCommand) ensureServingRuntime(python, cacheDir);
|
|
7054
7197
|
const serveTarget = await resolveServeTarget(
|
|
@@ -7143,9 +7286,9 @@ function registerModelsCommands(parent) {
|
|
|
7143
7286
|
env: { ...process.env, ...env }
|
|
7144
7287
|
});
|
|
7145
7288
|
child.on("error", reject);
|
|
7146
|
-
child.on("exit", (
|
|
7147
|
-
if (
|
|
7148
|
-
reject(new Error(`Model server exited with ${signal ?? `code ${
|
|
7289
|
+
child.on("exit", (code2, signal) => {
|
|
7290
|
+
if (code2 === 0) return resolvePromise();
|
|
7291
|
+
reject(new Error(`Model server exited with ${signal ?? `code ${code2}`}`));
|
|
7149
7292
|
});
|
|
7150
7293
|
});
|
|
7151
7294
|
});
|
|
@@ -7302,7 +7445,7 @@ function registerTopupCommands(parent) {
|
|
|
7302
7445
|
}
|
|
7303
7446
|
const url = data3.checkout_url;
|
|
7304
7447
|
console.log(
|
|
7305
|
-
`${chalk7.bold("Checkout URL:")} ${chalk7.
|
|
7448
|
+
`${chalk7.bold("Checkout URL:")} ${chalk7.hex("#A78BFA")(url)}
|
|
7306
7449
|
` + chalk7.dim("Complete the payment to credit your account.")
|
|
7307
7450
|
);
|
|
7308
7451
|
if (options.open !== false) {
|
|
@@ -7510,12 +7653,12 @@ function printValidation(checks) {
|
|
|
7510
7653
|
}
|
|
7511
7654
|
|
|
7512
7655
|
// src/commands/push.ts
|
|
7513
|
-
import { readFileSync as
|
|
7656
|
+
import { readFileSync as readFileSync9, writeFileSync as writeFileSync5 } from "fs";
|
|
7514
7657
|
import { resolve as resolve6 } from "path";
|
|
7515
7658
|
function persistRemoteId(filePath, id) {
|
|
7516
|
-
const raw = JSON.parse(
|
|
7659
|
+
const raw = JSON.parse(readFileSync9(filePath, "utf-8"));
|
|
7517
7660
|
raw.id = id;
|
|
7518
|
-
|
|
7661
|
+
writeFileSync5(filePath, JSON.stringify(raw, null, 2) + "\n");
|
|
7519
7662
|
}
|
|
7520
7663
|
function registerPushCommand(parent) {
|
|
7521
7664
|
parent.command("push").description("Push local spec to the Tuned Tensor API").option("-f, --file <path>", "Spec file path", DEFAULT_SPEC_FILE).action(async (cmdOpts) => {
|
|
@@ -7639,6 +7782,81 @@ function registerAgentCommands(parent, options) {
|
|
|
7639
7782
|
});
|
|
7640
7783
|
}
|
|
7641
7784
|
|
|
7785
|
+
// src/commands/pipeline.ts
|
|
7786
|
+
import { existsSync as existsSync8, readFileSync as readFileSync10, writeFileSync as writeFileSync6 } from "fs";
|
|
7787
|
+
import { resolve as resolve7 } from "path";
|
|
7788
|
+
var DEFAULT_PIPELINE_FILE = "tunedtensor.pipeline.json";
|
|
7789
|
+
function parseList(value) {
|
|
7790
|
+
if (!value) return void 0;
|
|
7791
|
+
const ids = value.split(",").map((id) => id.trim()).filter(Boolean);
|
|
7792
|
+
if (!ids.length) throw new Error("Step selection must name at least one step.");
|
|
7793
|
+
return ids;
|
|
7794
|
+
}
|
|
7795
|
+
function loadPipeline(path) {
|
|
7796
|
+
const resolved = resolve7(path);
|
|
7797
|
+
if (!existsSync8(resolved)) throw new Error(`Pipeline file not found: ${path}. Run \`tt pipeline init\` to create one.`);
|
|
7798
|
+
try {
|
|
7799
|
+
return JSON.parse(readFileSync10(resolved, "utf8"));
|
|
7800
|
+
} catch (error) {
|
|
7801
|
+
throw new Error(`Pipeline file must be JSON: ${error.message}`);
|
|
7802
|
+
}
|
|
7803
|
+
}
|
|
7804
|
+
function outputPlan(plan) {
|
|
7805
|
+
if (isJsonMode()) return printJson(plan);
|
|
7806
|
+
const typed = plan;
|
|
7807
|
+
for (const step of typed.steps) {
|
|
7808
|
+
console.log(`${step.id.padEnd(16)} ${step.uses.padEnd(10)} ${step.target}`);
|
|
7809
|
+
for (const transfer of step.transfers) console.log(` transfer ${transfer.from}: ${transfer.from_target} -> ${transfer.to_target}`);
|
|
7810
|
+
}
|
|
7811
|
+
}
|
|
7812
|
+
function registerPipelineCommands(parent) {
|
|
7813
|
+
const pipeline2 = parent.command("pipeline").description("Create, validate, inspect, and safely dry-run ordered pipeline recipes");
|
|
7814
|
+
pipeline2.command("init").description("Write a canonical v1 pipeline recipe").option("-f, --file <path>", "Output file", DEFAULT_PIPELINE_FILE).option("--target <target>", "Default target: local or cloud", "local").action((options) => {
|
|
7815
|
+
if (!PIPELINE_TARGETS.includes(options.target)) throw new Error("--target must be local or cloud.");
|
|
7816
|
+
const path = resolve7(options.file);
|
|
7817
|
+
if (existsSync8(path)) throw new Error(`Pipeline file already exists: ${options.file}.`);
|
|
7818
|
+
const recipe = canonicalPipeline(options.target);
|
|
7819
|
+
writeFileSync6(path, `${JSON.stringify(recipe, null, 2)}
|
|
7820
|
+
`);
|
|
7821
|
+
if (isJsonMode()) return printJson({ created: true, path, pipeline: recipe });
|
|
7822
|
+
printSuccess(`Created ${options.file}`);
|
|
7823
|
+
});
|
|
7824
|
+
pipeline2.command("validate").description("Validate a pipeline without any execution or transfer").option("-f, --file <path>", "Pipeline file", DEFAULT_PIPELINE_FILE).action((options) => {
|
|
7825
|
+
const errors = validatePipeline(loadPipeline(options.file));
|
|
7826
|
+
const result2 = { valid: errors.length === 0, errors };
|
|
7827
|
+
if (isJsonMode()) return printJson(result2);
|
|
7828
|
+
if (errors.length) throw new Error(`Invalid pipeline:
|
|
7829
|
+
- ${errors.join("\n- ")}`);
|
|
7830
|
+
printSuccess("Pipeline is valid.");
|
|
7831
|
+
});
|
|
7832
|
+
pipeline2.command("plan").description("Resolve step targets and required artifact transfers").option("-f, --file <path>", "Pipeline file", DEFAULT_PIPELINE_FILE).option("--only <ids>", "Comma-separated step IDs to include").option("--skip <ids>", "Comma-separated step IDs to omit").action((options) => {
|
|
7833
|
+
outputPlan(createExecutionPlan(loadPipeline(options.file), { only: parseList(options.only), skip: parseList(options.skip) }));
|
|
7834
|
+
});
|
|
7835
|
+
pipeline2.command("run").description("Run an ordered local pipeline, or safely preview any pipeline").option("--dry-run", "Resolve and display only; never execute, transfer, or reserve credits").option("-f, --file <path>", "Pipeline file", DEFAULT_PIPELINE_FILE).option("--spec <path>", "Local behavior spec", "tunedtensor.json").option("--config <path>", "Local runtime config").option("--only <ids>", "Comma-separated step IDs to include").option("--skip <ids>", "Comma-separated step IDs to omit").action(async (options) => {
|
|
7836
|
+
const plan = createExecutionPlan(loadPipeline(options.file), { only: parseList(options.only), skip: parseList(options.skip) });
|
|
7837
|
+
if (options.dryRun) {
|
|
7838
|
+
if (isJsonMode()) return printJson({ dry_run: true, ...plan });
|
|
7839
|
+
console.log("Dry run only \u2014 no execution, artifact transfer, or credit reservation will occur.");
|
|
7840
|
+
return outputPlan(plan);
|
|
7841
|
+
}
|
|
7842
|
+
const remote = plan.steps.find((step) => step.target !== "local");
|
|
7843
|
+
if (remote) {
|
|
7844
|
+
throw new Error(`Step "${remote.id}" targets cloud execution. Hosted and mixed pipeline execution is not enabled by this CLI build; use --dry-run.`);
|
|
7845
|
+
}
|
|
7846
|
+
const input = await loadLocalRunInput(resolve7(options.spec));
|
|
7847
|
+
assertLocalRunInputReady(input.request);
|
|
7848
|
+
const config = await loadLocalRunnerConfig(options.config ? resolve7(options.config) : void 0);
|
|
7849
|
+
const localPipeline = {
|
|
7850
|
+
version: 1,
|
|
7851
|
+
...plan.name ? { name: plan.name } : {},
|
|
7852
|
+
steps: plan.steps.map(({ transfers: _transfers, ...step }) => step)
|
|
7853
|
+
};
|
|
7854
|
+
const result2 = await runLocalPipeline({ request: input.request, config, pipeline: localPipeline });
|
|
7855
|
+
if (isJsonMode()) return printJson(result2);
|
|
7856
|
+
printSuccess(`Pipeline completed with status ${result2.status}.`);
|
|
7857
|
+
});
|
|
7858
|
+
}
|
|
7859
|
+
|
|
7642
7860
|
// src/cli.ts
|
|
7643
7861
|
async function createDefaultAgentClient(runtime, env, cloud) {
|
|
7644
7862
|
const selection = getAgentSelection(env);
|
|
@@ -7681,7 +7899,16 @@ async function createDefaultAgentClient(runtime, env, cloud) {
|
|
|
7681
7899
|
}
|
|
7682
7900
|
function createLazyDefaultAgentClient(runtime, env, cloud) {
|
|
7683
7901
|
let pending;
|
|
7684
|
-
const client = () =>
|
|
7902
|
+
const client = () => {
|
|
7903
|
+
if (!pending) {
|
|
7904
|
+
const attempt = createDefaultAgentClient(runtime, env, cloud);
|
|
7905
|
+
pending = attempt;
|
|
7906
|
+
attempt.catch(() => {
|
|
7907
|
+
if (pending === attempt) pending = void 0;
|
|
7908
|
+
});
|
|
7909
|
+
}
|
|
7910
|
+
return pending;
|
|
7911
|
+
};
|
|
7685
7912
|
return {
|
|
7686
7913
|
createThread: async () => await (await client()).createThread(),
|
|
7687
7914
|
listThreads: async () => await (await client()).listThreads(),
|
|
@@ -7696,7 +7923,7 @@ async function runSelfCommand(args2, options = {}) {
|
|
|
7696
7923
|
if (!entrypoint) {
|
|
7697
7924
|
throw new Error("Cannot locate the tt CLI entrypoint.");
|
|
7698
7925
|
}
|
|
7699
|
-
return await new Promise((
|
|
7926
|
+
return await new Promise((resolve8, reject) => {
|
|
7700
7927
|
const child = spawn4(process.execPath, [entrypoint, ...args2], {
|
|
7701
7928
|
cwd: options.cwd,
|
|
7702
7929
|
env: options.env ?? process.env,
|
|
@@ -7732,7 +7959,7 @@ async function runSelfCommand(args2, options = {}) {
|
|
|
7732
7959
|
child.once("close", (exitCode, signal) => {
|
|
7733
7960
|
cleanup();
|
|
7734
7961
|
const signalNumber = signal ? osConstants2.signals[signal] : void 0;
|
|
7735
|
-
|
|
7962
|
+
resolve8({
|
|
7736
7963
|
exitCode: exitCode ?? (typeof signalNumber === "number" ? 128 + signalNumber : 1),
|
|
7737
7964
|
signal
|
|
7738
7965
|
});
|
|
@@ -7836,6 +8063,7 @@ function createProgram(version, runtime = {}) {
|
|
|
7836
8063
|
registerInitCommand(program);
|
|
7837
8064
|
registerEvalCommand(program);
|
|
7838
8065
|
registerPushCommand(program);
|
|
8066
|
+
registerPipelineCommands(program);
|
|
7839
8067
|
registerAgentCommands(program, {
|
|
7840
8068
|
env,
|
|
7841
8069
|
output: runtime.stdout ?? process.stdout,
|
|
@@ -7860,7 +8088,7 @@ function createProgram(version, runtime = {}) {
|
|
|
7860
8088
|
`);
|
|
7861
8089
|
return;
|
|
7862
8090
|
}
|
|
7863
|
-
output.write(`${chalk9.bold.
|
|
8091
|
+
output.write(`${chalk9.bold.hex("#8B5CF6")("Tuned Tensor status")}
|
|
7864
8092
|
`);
|
|
7865
8093
|
output.write(`${formatShellStatus(context, target).join("\n")}
|
|
7866
8094
|
|
|
@@ -7993,7 +8221,7 @@ async function runCli(version, runtime = {}) {
|
|
|
7993
8221
|
}
|
|
7994
8222
|
|
|
7995
8223
|
// src/index.ts
|
|
7996
|
-
runCli("0.9.
|
|
8224
|
+
runCli("0.9.2").catch((err) => {
|
|
7997
8225
|
reportError(err);
|
|
7998
8226
|
process.exit(1);
|
|
7999
8227
|
});
|