@tuned-tensor/cli 0.13.1 → 0.15.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.
@@ -1,8 +1,12 @@
1
1
  # Architecture
2
2
 
3
- This repository is the local CUDA runtime behind the unified `tt`
4
- workflow. The standalone `tt-local` product surface is deprecated.
5
- Its supported runtime boundary is text SFT of a registry-certified
3
+ This document describes the local CUDA runtime bundled with the unified `tt`
4
+ agent and CLI. The standalone `tt-local` product surface is deprecated. Local
5
+ workflow commands need no TT token. Managed agent inference reuses a TT access
6
+ token; BYO inference uses the selected provider's credentials. Cloud operations
7
+ are explicit through `tt cloud` and use the TT account token.
8
+
9
+ The local adapter runtime boundary is text SFT of a registry-certified
6
10
  Transformers causal LM into a LoRA adapter on CUDA. Certified checkpoints
7
11
  are `Qwen/Qwen3.5-2B` (pinned to Hugging Face snapshot
8
12
  `15852e8c16360a2fea060d615a32b45270f8a8fc`),
@@ -28,7 +32,7 @@ implementation details, not a public plugin framework.
28
32
 
29
33
  ## Boundaries
30
34
 
31
- The first version intentionally excludes:
35
+ The local adapter runtime excludes:
32
36
 
33
37
  - arbitrary training or evaluation commands;
34
38
  - DPO, continued pretraining, and multimodal training;
@@ -40,7 +44,7 @@ The first version intentionally excludes:
40
44
  The next model or method should arrive with its own locked dependencies,
41
45
  resource defaults, data contract, and real CUDA acceptance test.
42
46
 
43
- TT Local currently ships two such methods:
47
+ TT bundles two local training methods:
44
48
 
45
49
  - **Adapter** (`training/adapter`): certified Transformers checkpoints and
46
50
  PEFT LoRA SFT. Driven by `tt pipeline run`.
@@ -90,7 +94,7 @@ The bundled Python project owns four small operations:
90
94
  - `prefetch.py`: download and verify the pinned Hugging Face snapshot;
91
95
  - `evaluate.py`: generate predictions without receiving reference answers;
92
96
  - `train.py`: perform CUDA-only, model-specific LoRA SFT;
93
- - `serve.py`: load the base model and verified adapter for inference.
97
+ - `serve.py`: prepare the verified base model and adapter for the vLLM serving runtime.
94
98
 
95
99
  Training uses assistant-only loss. Prompt tokens have label `-100`, and
96
100
  truncation removes older prompt tokens before it removes any answer token.
@@ -126,7 +130,7 @@ hide a valid artifact. Serving verifies the manifest again.
126
130
  The runner config controls only:
127
131
 
128
132
  - state, artifact, and Hugging Face cache paths;
129
- - CUDA or CPU inference for evaluation and serving;
133
+ - CUDA or CPU evaluation, with local serving through the CUDA vLLM runtime;
130
134
  - deterministic generation and scoring limits.
131
135
 
132
136
  The training project, Python entrypoints, working directory, and child
@@ -0,0 +1,171 @@
1
+ # Local serving and coding harnesses
2
+
3
+ `tt serve` verifies TT artifacts and launches **vLLM 0.28.0**. vLLM owns model
4
+ execution, batching, KV/prefix caching, streaming, and native tool-call parsing.
5
+ This local serving path connects the harness directly to vLLM; TT's managed
6
+ agent proxy is a separate inference option. The serving dependencies are locked
7
+ separately from training, in an external cache environment; an npm upgrade does
8
+ not mutate the training runtime.
9
+
10
+ ## Requirements and scope
11
+
12
+ - The packaged serving runtime requires **Linux and NVIDIA CUDA**. CPU/macOS
13
+ serving is not supported by this runtime; CLI/package commands still work
14
+ there. Unsupported hardware or model/adapter combinations fail rather than
15
+ silently falling back to the old server.
16
+ - Install `uv` and prefetch the certified model with `tt models prefetch`.
17
+ First launch installs the locked serving dependencies and may compile kernels;
18
+ it needs substantially more time and disk than a warm request. CUDA JIT may
19
+ require a working CUDA toolkit/C++ toolchain. Model loading remains offline.
20
+ - Foundation checkpoints and image inputs are not supported by this path.
21
+ - Qwen3.5-2B base and a one-step, rank-16 `all-linear` TT-shaped adapter have been
22
+ exercised on GB10. The registry's Nemotron and Muse Glimmer architectures have
23
+ upstream support, but their exact adapters/hardware combinations are **not
24
+ certified by that Qwen smoke test**. No 70B model was tested here.
25
+
26
+ ## Serve once, compare base and tuned
27
+
28
+ ```bash
29
+ tt models prefetch tunedtensor.json
30
+
31
+ tt serve local-<run-id> --config local-runner.json \
32
+ --context-length 8192 --max-tokens 512
33
+ ```
34
+
35
+ This exposes **both** `local-<run-id>` and `base:<base-model-id>` at the same
36
+ endpoint, sharing the base weights. The adapter is registered at startup; TT
37
+ never enables runtime adapter upload/loading. There is no merge/export step
38
+ and no modification of the verified weights. `tt serve base` starts base-only.
39
+ `active` still fails when no adapter is activated.
40
+
41
+ Artifact integrity, certified base revisions, and stored behavior-prompt
42
+ fingerprints retain their verification. A stored adapter's behavior prompt is
43
+ applied to both model IDs for comparison. `tt serve base` without explicit
44
+ `--spec` does not inject the adjacent spec; use `--spec tunedtensor.json` for that.
45
+ `--no-spec-prompt` is the explicit opt-out. A small generated template prefix
46
+ preserves the owner instructions while leaving tool messages and upstream chat
47
+ formatting intact; it never changes the saved tokenizer/template.
48
+
49
+ ### Resource controls
50
+
51
+ - `--context-length`: total context budget, default 16,384 tokens. Keep it large
52
+ enough for the harness's instructions and tool results, not just the question.
53
+ - `--max-tokens`: generation budget, default 512. vLLM receives this through its
54
+ generation configuration; the upstream API owns per-request validation.
55
+ - `--gpu-memory-utilization`: fraction of device memory budgeted to vLLM,
56
+ default 0.8. On shared-memory machines leave room for the OS and other work.
57
+ For the small Qwen GB10 smoke we used **0.15**; this is not suitable for every
58
+ model size. Reduce the context or memory budget when upstream reports a fit
59
+ failure, and ensure the weights themselves still fit.
60
+ - `--max-concurrent-requests`: maximum sequences scheduled in a vLLM batch,
61
+ default one, maximum eight. This is upstream batching, **not** the previous
62
+ HTTP admission/429 contract; upstream may queue additional requests.
63
+
64
+ Health becomes ready after loading/warm-up. Ctrl-C terminates the process group.
65
+ A port conflict is checked before loading; upstream owns the final bind and any
66
+ race. The unreleased custom server's `--merge-adapter` flag is removed.
67
+
68
+ ## Pi
69
+
70
+ Export a new isolated configuration rather than replacing global settings:
71
+
72
+ ```bash
73
+ export PI_CODING_AGENT_DIR="$(mktemp -d)"
74
+ tt serve local-<run-id> --config local-runner.json \
75
+ --context-length 8192 --max-tokens 512 \
76
+ --print-client-config pi > "$PI_CODING_AGENT_DIR/models.json"
77
+ ```
78
+
79
+ Use the same launch options as the running server. Exporting config verifies the
80
+ TT target but does not start a server. Adapter exports include both model IDs.
81
+ The exported `tt-local` provider ID names this local endpoint; it is not a
82
+ separate CLI or package and uses no TT account token. For example, in a
83
+ disposable coding-fixture directory:
84
+
85
+ ```bash
86
+ pi --provider tt-local --model 'base:Qwen/Qwen3.5-2B' \
87
+ --tools read --no-extensions --no-skills --no-prompt-templates \
88
+ --no-context-files --no-session --offline --thinking off \
89
+ -p 'Read fixture.py and explain what its function returns.'
90
+ ```
91
+
92
+ Repeat with `--model local-<run-id>` in a fresh session. `--tools read` is a
93
+ read-only tool allowlist, **not a filesystem sandbox**. Use a disposable account
94
+ or an enforcing harness permission boundary for untrusted tasks. Enable edits
95
+ or shell commands only when you intend to grant those permissions.
96
+
97
+ For question-only comparisons, `--no-tools` remains an optional experiment
98
+ setting. It is no longer a server requirement. `reasoning: false` and
99
+ `supportsReasoningEffort: false` in the Pi export describe this endpoint's
100
+ reasoning-control contract; **neither disables tool calls or asserts that the
101
+ model cannot reason**.
102
+
103
+ ## OpenCode
104
+
105
+ OpenCode can connect directly using its existing custom provider support:
106
+
107
+ ```json
108
+ {
109
+ "$schema": "https://opencode.ai/config.json",
110
+ "provider": {
111
+ "tt-local": {
112
+ "npm": "@ai-sdk/openai-compatible",
113
+ "name": "TT local endpoint",
114
+ "options": { "baseURL": "http://127.0.0.1:8000/v1" },
115
+ "models": {
116
+ "base:Qwen/Qwen3.5-2B": {
117
+ "name": "TT base",
118
+ "limit": { "context": 8192, "output": 512 }
119
+ }
120
+ }
121
+ }
122
+ }
123
+ }
124
+ ```
125
+
126
+ Add the exact adapter ID from `/v1/models` to compare it. Set the actual server
127
+ budgets, configure OpenCode's permissions, and select
128
+ `opencode run --model 'tt-local/base:Qwen/Qwen3.5-2B' ...`. TT does not install a
129
+ second agent framework or change global OpenCode configuration.
130
+
131
+ ## Tool support and security
132
+
133
+ TT selects upstream parsers for the registered models:
134
+
135
+ - Qwen3.5-2B: `qwen3_xml`.
136
+ - Nemotron 3.5 Lightning: `qwen3_coder` (ordinary non-thinking template mode).
137
+ - Muse Glimmer: `muse_glimmer`.
138
+
139
+ These are protocol integrations, not guarantees that a model will choose the
140
+ right tool or produce correct code. A complete test must observe a tool call,
141
+ execute an allowed tool, send its result back, and verify the final answer.
142
+ The harness owns tool execution/permissions; vLLM only generates the calls.
143
+ Fine-tuning can change tool reliability, so compare the tuned model too.
144
+
145
+ The default bind is `127.0.0.1:8000`. Non-loopback binds require both
146
+ `--allow-remote` and `--api-key-env NAME`. An authentication-only middleware
147
+ extends the bearer check to **all** upstream HTTP routes, including health,
148
+ tokenization, and administrative routes; vLLM's built-in guard covers only
149
+ selected prefixes. No token is put in argv or exported client configuration.
150
+ Pi uses `${NAME}` interpolation; OpenCode can use `"apiKey": "{env:NAME}"`.
151
+ Provide the variable separately to each process. Without `--api-key-env`, local
152
+ serving is unauthenticated. Use a trusted host or encrypted tunnel, never expose
153
+ plain HTTP directly to the Internet. Request/output logging and vLLM usage
154
+ telemetry are disabled by the TT launcher.
155
+
156
+ ## API and measurement
157
+
158
+ Use `/health`, `/v1/models`, and `/v1/chat/completions`. API bodies, SSE events,
159
+ usage, tool calls, cancellation, and error semantics come from the pinned
160
+ upstream server, not a TT approximation. The old custom server's message/byte
161
+ limits, HTTP errors, and health JSON are not preserved as an API contract.
162
+
163
+ Measure startup and first-request compilation separately from steady-state
164
+ first-text latency and tokens/second. Compare identical prompts, templates,
165
+ budgets, and fresh harness sessions on an otherwise-idle machine. Test generated
166
+ code independently; a tiny one-step adapter proves integration, not better
167
+ coding. Pi's zero provider token prices do not mean zero hardware cost.
168
+
169
+ References: [vLLM LoRA](https://docs.vllm.ai/en/v0.28.0/features/lora/),
170
+ [Nemotron tool configuration](https://docs.nvidia.com/nim/large-language-models/latest/get-started/advanced/get-started-nemotron-3.5-lightning.html),
171
+ [OpenCode custom providers](https://opencode.ai/docs/providers/#custom-provider).
@@ -26,8 +26,10 @@ this GPU. Spark unified memory should show Nemotron and Muse Glimmer as
26
26
  trainable; consumer cards typically only fit Qwen LoRA. `tt status` and the
27
27
  shell agent reuse the cached report.
28
28
 
29
- TT Local requires Node 22+, `uv`, working CUDA PyTorch, and enough free space
30
- for the Hugging Face cache plus run artifacts.
29
+ Local TT training requires Node 22.19+, `uv`, working CUDA PyTorch, and enough free space
30
+ for the Hugging Face cache plus run artifacts. Local commands need no TT
31
+ access token. Agent inference can use your TT token through the managed proxy,
32
+ or your own provider credentials and model.
31
33
 
32
34
  ## Create a project
33
35
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tuned-tensor/cli",
3
- "version": "0.13.1",
3
+ "version": "0.15.0",
4
4
  "description": "Local TT agent and CUDA fine-tuning CLI for Tuned Tensor workflows",
5
5
  "repository": {
6
6
  "type": "git",
@@ -25,6 +25,8 @@
25
25
  "training/adapter/pyproject.toml",
26
26
  "training/adapter/uv.lock",
27
27
  "training/adapter/src/*.py",
28
+ "training/serving/pyproject.toml",
29
+ "training/serving/uv.lock",
28
30
  "training/foundation/pyproject.toml",
29
31
  "training/foundation/uv.lock",
30
32
  "training/foundation/src/*.py",
@@ -110,7 +110,7 @@ def assert_certified_model_config(
110
110
  )
111
111
  return
112
112
  else:
113
- raise ValueError(f"{label} is not a certified TT Local base-model architecture")
113
+ raise ValueError(f"{label} is not a certified TT base-model architecture")
114
114
 
115
115
  for name, expected in certified.items():
116
116
  actual = _field(text_config, name)
@@ -147,7 +147,7 @@ def verify_snapshot(snapshot: Path, expected_model_id: str | None = None) -> tup
147
147
 
148
148
 
149
149
  def main() -> None:
150
- parser = argparse.ArgumentParser(description="Prefetch a TT Local Hugging Face base model.")
150
+ parser = argparse.ArgumentParser(description="Prefetch a TT Hugging Face base model for local use.")
151
151
  parser.add_argument("--input", required=True)
152
152
  parser.add_argument("--output", required=True)
153
153
  args = parser.parse_args()