From 99b011e399e708661c0eed7e1a7536e925c119d9 Mon Sep 17 00:00:00 2001 From: jaakko Date: Mon, 6 Apr 2026 13:40:19 +0300 Subject: [PATCH] Isomman qwen-mallin lataus --- docker-errors.log | 475 ++++++++++++++++++++++++++++++++++ network-poc/static/index.html | 26 +- 2 files changed, 500 insertions(+), 1 deletion(-) create mode 100644 docker-errors.log diff --git a/docker-errors.log b/docker-errors.log new file mode 100644 index 0000000..e4d0b66 --- /dev/null +++ b/docker-errors.log @@ -0,0 +1,475 @@ +[INFO]: Checking for the Wasm target... +info: downloading component rust-std +[INFO]: Compiling to Wasm... + Compiling node v0.1.0 (/app/node) +warning: unused imports: `DType`, `Device`, and `Tensor` + --> node/src/smollm.rs:1:19 + | +1 | use candle_core::{Device, Tensor, DType}; + | ^^^^^^ ^^^^^^ ^^^^^ + | + = note: `#[warn(unused_imports)]` (part of `#[warn(unused)]`) on by default + +warning: unused import: `candle_nn::VarBuilder` + --> node/src/smollm.rs:2:5 + | +2 | use candle_nn::VarBuilder; + | ^^^^^^^^^^^^^^^^^^^^^ + +warning: unused imports: `Cache`, `LlamaConfig`, `LlamaEosToks`, and `Llama` + --> node/src/smollm.rs:3:42 + | +3 | use candle_transformers::models::llama::{Llama, LlamaConfig, LlamaEosToks, Cache}; + | ^^^^^ ^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^ + +warning: unused imports: `DType`, `Device`, and `Tensor` + --> node/src/phi3.rs:1:19 + | +1 | use candle_core::{Device, Tensor, DType}; + | ^^^^^^ ^^^^^^ ^^^^^ + +warning: unused import: `candle_nn::VarBuilder` + --> node/src/phi3.rs:2:5 + | +2 | use candle_nn::VarBuilder; + | ^^^^^^^^^^^^^^^^^^^^^ + +warning: unused imports: `Config as Phi3Config` and `Model as Phi3Model` + --> node/src/phi3.rs:3:41 + | +3 | use candle_transformers::models::phi3::{Config as Phi3Config, Model as Phi3Model}; + | ^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^ + +warning: unused import: `wasm_bindgen::JsCast` + --> node/src/phi3.rs:4:5 + | +4 | use wasm_bindgen::JsCast; + | ^^^^^^^^^^^^^^^^^^^^ + +warning: unused import: `crate::storage` + --> node/src/phi3.rs:9:5 + | +9 | use crate::storage; + | ^^^^^^^^^^^^^^ + +warning: unused import: `Int` + --> node/src/burn_smollm/attention.rs:2:46 + | +2 | use burn::tensor::{backend::Backend, Tensor, Int}; + | ^^^ + +warning: unused imports: `Mlp` and `RmsNorm` + --> node/src/burn_smollm/attention.rs:4:22 + | +4 | use super::modules::{RmsNorm, Mlp}; + | ^^^^^^^ ^^^ + +warning: use of deprecated struct `burn::tensor::Data`: the internal data format has changed, please use `TensorData` instead + --> node/src/smollm.rs:174:23 + | +174 | burn::tensor::Data::new(input_ids.iter().map(|&x| x as i32).collect::>(), [input_len].into()), + | ^^^^ + | + = note: `#[warn(deprecated)]` on by default + +warning: use of deprecated struct `burn::tensor::Data`: the internal data format has changed, please use `TensorData` instead + --> node/src/smollm.rs:200:27 + | +200 | burn::tensor::Data::new(vec![next_token as i32], [1].into()), + | ^^^^ + +warning: use of deprecated struct `burn::tensor::Data`: the internal data format has changed, please use `TensorData` instead + --> node/src/burn_smollm/loader.rs:1:46 + | +1 | use burn::tensor::{backend::Backend, Tensor, Data}; + | ^^^^ + +warning: use of deprecated struct `burn::tensor::Data`: the internal data format has changed, please use `TensorData` instead + --> node/src/burn_smollm/loader.rs:17:16 + | +17 | let data = Data::new(vec, shape_out_in.into()); + | ^^^^ + +warning: use of deprecated struct `burn::tensor::Data`: the internal data format has changed, please use `TensorData` instead + --> node/src/burn_smollm/loader.rs:32:16 + | +32 | let data = Data::new(vec, shape.into()); + | ^^^^ + +warning: use of deprecated struct `burn::tensor::Data`: the internal data format has changed, please use `TensorData` instead + --> node/src/burn_smollm/loader.rs:45:16 + | +45 | let data = Data::new(vec, shape.into()); + | ^^^^ + +error[E0061]: this function takes 2 arguments but 1 argument was supplied + --> node/src/smollm.rs:124:9 + | +124 | burn_wgpu::init_async::(&Default::default()).await; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--------------------- argument #2 of type `RuntimeOptions` is missing + | +note: function defined here + --> /usr/local/cargo/registry/src/index.crates.io-1949cf8c6b5b557f/cubecl-wgpu-0.2.0/src/runtime.rs:116:14 + | +116 | pub async fn init_async(device: &WgpuDevice, options: RuntimeOptions) { + | ^^^^^^^^^^ +help: provide the argument + | +124 | burn_wgpu::init_async::(&Default::default(), /* RuntimeOptions */).await; + | ++++++++++++++++++++++ + +error[E0277]: the trait bound `TensorData: From>` is not satisfied + --> node/src/smollm.rs:174:9 + | +173 | let mut input_tensor = burn::tensor::Tensor::::from_data( + | ---------------------------------------------------------- required by a bound introduced by this call +174 | burn::tensor::Data::new(input_ids.iter().map(|&x| x as i32).collect::>(), [input_len].into()), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `From>` is not implemented for `TensorData` + | + = help: the following other types implement trait `From`: + `TensorData` implements `From<&[E]>` + `TensorData` implements `From<&[usize]>` + `TensorData` implements `From<[E; A]>` + `TensorData` implements `From<[[E; B]; A]>` + `TensorData` implements `From<[[[E; C]; B]; A]>` + `TensorData` implements `From<[[[[E; D]; C]; B]; A]>` + `TensorData` implements `From<[[[[[Elem; E]; D]; C]; B]; A]>` + `TensorData` implements `From<[usize; A]>` + = note: required for `burn::tensor::Data` to implement `Into` +note: required by a bound in `burn::tensor::Tensor::::from_data` + --> /usr/local/cargo/registry/src/index.crates.io-1949cf8c6b5b557f/burn-tensor-0.14.0/src/tensor/api/base.rs:719:12 + | +717 | pub fn from_data(data: T, device: &B::Device) -> Self + | --------- required by a bound in this associated function +718 | where +719 | T: Into, + | ^^^^^^^^^^^^^^^^ required by this bound in `Tensor::::from_data` + +error[E0061]: this method takes 2 arguments but 0 arguments were supplied + --> node/src/smollm.rs:183:51 + | +183 | let next_token_tensor = last_logits.argmax(2).flatten::<1>(); + | ^^^^^^^^^^^^-- two arguments of type `usize` and `usize` are missing + | +note: method defined here + --> /usr/local/cargo/registry/src/index.crates.io-1949cf8c6b5b557f/burn-tensor-0.14.0/src/tensor/api/base.rs:292:12 + | +292 | pub fn flatten(self, start_dim: usize, end_dim: usize) -> Tensor { + | ^^^^^^^ +help: provide the arguments + | +183 | let next_token_tensor = last_logits.argmax(2).flatten::<1>(/* usize */, /* usize */); + | ++++++++++++++++++++++++ + +error[E0277]: the trait bound `TensorData: From>` is not satisfied + --> node/src/smollm.rs:200:13 + | +199 | let mut input_tensor = burn::tensor::Tensor::::from_data( + | ---------------------------------------------------------- required by a bound introduced by this call +200 | burn::tensor::Data::new(vec![next_token as i32], [1].into()), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `From>` is not implemented for `TensorData` + | + = help: the following other types implement trait `From`: + `TensorData` implements `From<&[E]>` + `TensorData` implements `From<&[usize]>` + `TensorData` implements `From<[E; A]>` + `TensorData` implements `From<[[E; B]; A]>` + `TensorData` implements `From<[[[E; C]; B]; A]>` + `TensorData` implements `From<[[[[E; D]; C]; B]; A]>` + `TensorData` implements `From<[[[[[Elem; E]; D]; C]; B]; A]>` + `TensorData` implements `From<[usize; A]>` + = note: required for `burn::tensor::Data` to implement `Into` +note: required by a bound in `burn::tensor::Tensor::::from_data` + --> /usr/local/cargo/registry/src/index.crates.io-1949cf8c6b5b557f/burn-tensor-0.14.0/src/tensor/api/base.rs:719:12 + | +717 | pub fn from_data(data: T, device: &B::Device) -> Self + | --------- required by a bound in this associated function +718 | where +719 | T: Into, + | ^^^^^^^^^^^^^^^^ required by this bound in `Tensor::::from_data` + +error[E0061]: this method takes 2 arguments but 0 arguments were supplied + --> node/src/smollm.rs:207:50 + | +207 | let next_token_tensor = logits.argmax(2).flatten::<1>(); + | ^^^^^^^^^^^^-- two arguments of type `usize` and `usize` are missing + | +note: method defined here + --> /usr/local/cargo/registry/src/index.crates.io-1949cf8c6b5b557f/burn-tensor-0.14.0/src/tensor/api/base.rs:292:12 + | +292 | pub fn flatten(self, start_dim: usize, end_dim: usize) -> Tensor { + | ^^^^^^^ +help: provide the arguments + | +207 | let next_token_tensor = logits.argmax(2).flatten::<1>(/* usize */, /* usize */); + | ++++++++++++++++++++++++ + +error[E0308]: mismatched types + --> node/src/burn_smollm/attention.rs:58:13 + | +58 | q = q.reshape([batch, seq_len, self.num_heads, self.head_dim]).swap_dims(1, 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `3`, found `4` + | + = note: expected struct `burn::tensor::Tensor<_, 3>` + found struct `burn::tensor::Tensor<_, 4>` + +error[E0308]: mismatched types + --> node/src/burn_smollm/attention.rs:59:13 + | +59 | k = k.reshape([batch, seq_len, self.num_kv_heads, self.head_dim]).swap_dims(1, 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `3`, found `4` + | + = note: expected struct `burn::tensor::Tensor<_, 3>` + found struct `burn::tensor::Tensor<_, 4>` + +error[E0308]: mismatched types + --> node/src/burn_smollm/attention.rs:60:13 + | +60 | v = v.reshape([batch, seq_len, self.num_kv_heads, self.head_dim]).swap_dims(1, 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `3`, found `4` + | + = note: expected struct `burn::tensor::Tensor<_, 3>` + found struct `burn::tensor::Tensor<_, 4>` + +error[E0308]: mismatched types + --> node/src/burn_smollm/attention.rs:63:31 + | +63 | q = self.rope.forward(q, offset); + | ------- ^ expected `4`, found `3` + | | + | arguments to this method are incorrect + | + = note: expected struct `burn::tensor::Tensor<_, 4>` + found struct `burn::tensor::Tensor<_, 3>` +note: method defined here + --> node/src/burn_smollm/rope.rs:35:12 + | +35 | pub fn forward(&self, x: Tensor, offset: usize) -> Tensor { + | ^^^^^^^ --------------- + +error[E0308]: mismatched types + --> node/src/burn_smollm/attention.rs:63:13 + | +63 | q = self.rope.forward(q, offset); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `3`, found `4` + | + = note: expected struct `burn::tensor::Tensor<_, 3>` + found struct `burn::tensor::Tensor<_, 4>` + +error[E0308]: mismatched types + --> node/src/burn_smollm/attention.rs:64:31 + | +64 | k = self.rope.forward(k, offset); + | ------- ^ expected `4`, found `3` + | | + | arguments to this method are incorrect + | + = note: expected struct `burn::tensor::Tensor<_, 4>` + found struct `burn::tensor::Tensor<_, 3>` +note: method defined here + --> node/src/burn_smollm/rope.rs:35:12 + | +35 | pub fn forward(&self, x: Tensor, offset: usize) -> Tensor { + | ^^^^^^^ --------------- + +error[E0308]: mismatched types + --> node/src/burn_smollm/attention.rs:64:13 + | +64 | k = self.rope.forward(k, offset); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `3`, found `4` + | + = note: expected struct `burn::tensor::Tensor<_, 3>` + found struct `burn::tensor::Tensor<_, 4>` + +error[E0308]: mismatched types + --> node/src/burn_smollm/attention.rs:68:41 + | +68 | c.k = Tensor::cat(vec![c.k, k], 2); + | ^ expected `4`, found `3` + | + = note: expected struct `burn::tensor::Tensor<_, 4>` + found struct `burn::tensor::Tensor<_, 3>` + +error[E0308]: mismatched types + --> node/src/burn_smollm/attention.rs:69:41 + | +69 | c.v = Tensor::cat(vec![c.v, v], 2); + | ^ expected `4`, found `3` + | + = note: expected struct `burn::tensor::Tensor<_, 4>` + found struct `burn::tensor::Tensor<_, 3>` + +error[E0308]: `if` and `else` have incompatible types + --> node/src/burn_smollm/attention.rs:72:13 + | +67 | let (k, v) = if let Some(mut c) = cache { + | ______________________- +68 | | c.k = Tensor::cat(vec![c.k, k], 2); +69 | | c.v = Tensor::cat(vec![c.v, v], 2); +70 | | (c.k.clone(), c.v.clone()) + | | -------------------------- expected because of this +71 | | } else { +72 | | (k.clone(), v.clone()) + | | ^^^^^^^^^^^^^^^^^^^^^^ expected `4`, found `3` +73 | | }; + | |_________- `if` and `else` have incompatible types + | + = note: expected tuple `(burn::tensor::Tensor<_, 4>, burn::tensor::Tensor<_, 4>)` + found tuple `(burn::tensor::Tensor<_, 3>, burn::tensor::Tensor<_, 3>)` + +error[E0282]: type annotations needed + --> node/src/burn_smollm/attention.rs:75:38 + | +75 | let new_cache = KVCache { k: k.clone(), v: v.clone() }; + | ^ cannot infer type + +error[E0282]: type annotations needed + --> node/src/burn_smollm/attention.rs:75:52 + | +75 | let new_cache = KVCache { k: k.clone(), v: v.clone() }; + | ^ cannot infer type + +error[E0277]: the trait bound `TensorData: From>` is not satisfied + --> node/src/burn_smollm/loader.rs:18:44 + | + 18 | let t_burn = Tensor::::from_data(data, device); + | ------------------------- ^^^^ the trait `From>` is not implemented for `TensorData` + | | + | required by a bound introduced by this call + | + = help: the following other types implement trait `From`: + `TensorData` implements `From<&[E]>` + `TensorData` implements `From<&[usize]>` + `TensorData` implements `From<[E; A]>` + `TensorData` implements `From<[[E; B]; A]>` + `TensorData` implements `From<[[[E; C]; B]; A]>` + `TensorData` implements `From<[[[[E; D]; C]; B]; A]>` + `TensorData` implements `From<[[[[[Elem; E]; D]; C]; B]; A]>` + `TensorData` implements `From<[usize; A]>` + = note: required for `burn::tensor::Data` to implement `Into` +note: required by a bound in `burn::tensor::Tensor::::from_data` + --> /usr/local/cargo/registry/src/index.crates.io-1949cf8c6b5b557f/burn-tensor-0.14.0/src/tensor/api/base.rs:719:12 + | +717 | pub fn from_data(data: T, device: &B::Device) -> Self + | --------- required by a bound in this associated function +718 | where +719 | T: Into, + | ^^^^^^^^^^^^^^^^ required by this bound in `Tensor::::from_data` + +error[E0277]: the trait bound `TensorData: From>` is not satisfied + --> node/src/burn_smollm/loader.rs:33:53 + | + 33 | Ok(Param::from_tensor(Tensor::::from_data(data, device))) + | ------------------------- ^^^^ the trait `From>` is not implemented for `TensorData` + | | + | required by a bound introduced by this call + | + = help: the following other types implement trait `From`: + `TensorData` implements `From<&[E]>` + `TensorData` implements `From<&[usize]>` + `TensorData` implements `From<[E; A]>` + `TensorData` implements `From<[[E; B]; A]>` + `TensorData` implements `From<[[[E; C]; B]; A]>` + `TensorData` implements `From<[[[[E; D]; C]; B]; A]>` + `TensorData` implements `From<[[[[[Elem; E]; D]; C]; B]; A]>` + `TensorData` implements `From<[usize; A]>` + = note: required for `burn::tensor::Data` to implement `Into` +note: required by a bound in `burn::tensor::Tensor::::from_data` + --> /usr/local/cargo/registry/src/index.crates.io-1949cf8c6b5b557f/burn-tensor-0.14.0/src/tensor/api/base.rs:719:12 + | +717 | pub fn from_data(data: T, device: &B::Device) -> Self + | --------- required by a bound in this associated function +718 | where +719 | T: Into, + | ^^^^^^^^^^^^^^^^ required by this bound in `Tensor::::from_data` + +error[E0277]: the trait bound `TensorData: From>` is not satisfied + --> node/src/burn_smollm/loader.rs:47:53 + | + 47 | Ok(Param::from_tensor(Tensor::::from_data(data, device))) + | ------------------------- ^^^^ the trait `From>` is not implemented for `TensorData` + | | + | required by a bound introduced by this call + | + = help: the following other types implement trait `From`: + `TensorData` implements `From<&[E]>` + `TensorData` implements `From<&[usize]>` + `TensorData` implements `From<[E; A]>` + `TensorData` implements `From<[[E; B]; A]>` + `TensorData` implements `From<[[[E; C]; B]; A]>` + `TensorData` implements `From<[[[[E; D]; C]; B]; A]>` + `TensorData` implements `From<[[[[[Elem; E]; D]; C]; B]; A]>` + `TensorData` implements `From<[usize; A]>` + = note: required for `burn::tensor::Data` to implement `Into` +note: required by a bound in `burn::tensor::Tensor::::from_data` + --> /usr/local/cargo/registry/src/index.crates.io-1949cf8c6b5b557f/burn-tensor-0.14.0/src/tensor/api/base.rs:719:12 + | +717 | pub fn from_data(data: T, device: &B::Device) -> Self + | --------- required by a bound in this associated function +718 | where +719 | T: Into, + | ^^^^^^^^^^^^^^^^ required by this bound in `Tensor::::from_data` + +error[E0599]: no function or associated item named `arange` found for struct `burn::tensor::Tensor` in the current scope + --> node/src/burn_smollm/rope.rs:19:33 + | + 19 | let t = Tensor::::arange(0..max_seq_len as i64, device).float().unsqueeze::<2>().transpose(); + | ^^^^^^ function or associated item not found in `burn::tensor::Tensor` + | +note: if you're trying to build a new `burn::tensor::Tensor` consider using one of the following associated functions: + burn::tensor::Tensor::::new + burn::tensor::Tensor::::from_primitive + burn::tensor::Tensor::::empty + burn::tensor::Tensor::::from_data + and 9 others + --> /usr/local/cargo/registry/src/index.crates.io-1949cf8c6b5b557f/burn-tensor-0.14.0/src/tensor/api/base.rs:24:10 + | + 24 | #[derive(new, Clone, Debug)] + | ^^^ +... + 55 | pub fn from_primitive(tensor: K::Primitive) -> Self { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... + 60 | pub fn empty>>(shape: S, device: &B::Device) -> Self { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +717 | / pub fn from_data(data: T, device: &B::Device) -> Self +718 | | where +719 | | T: Into, + | |____________________________^ + = note: the function or associated item was found for + - `burn::tensor::Tensor` + = note: this error originates in the derive macro `new` (in Nightly builds, run with -Z macro-backtrace for more info) + +warning: variable does not need to be mutable + --> node/src/burn_smollm/loader.rs:70:13 + | +70 | let mut layer = &mut model.layers[i]; + | ----^^^^^ + | | + | help: remove this `mut` + | + = note: `#[warn(unused_mut)]` (part of `#[warn(unused)]`) on by default + +warning: unused variable: `batch` + --> node/src/burn_smollm/model.rs:79:14 + | +79 | let [batch, seq_len] = input_ids.dims(); + | ^^^^^ help: if this is intentional, prefix it with an underscore: `_batch` + | + = note: `#[warn(unused_variables)]` (part of `#[warn(unused)]`) on by default + +warning: unused variable: `seq_len` + --> node/src/burn_smollm/model.rs:79:21 + | +79 | let [batch, seq_len] = input_ids.dims(); + | ^^^^^^^ help: if this is intentional, prefix it with an underscore: `_seq_len` + +Some errors have detailed explanations: E0061, E0277, E0282, E0308, E0599. +For more information about an error, try `rustc --explain E0061`. +warning: `node` (lib) generated 19 warnings +error: could not compile `node` (lib) due to 21 previous errors; 19 warnings emitted +Error: Compiling your crate to WebAssembly failed +Caused by: Compiling your crate to WebAssembly failed +Caused by: failed to execute `cargo build`: exited with exit status: 101 + full command: cd "/app/node" && "cargo" "build" "--lib" "--release" "--target" "wasm32-unknown-unknown" diff --git a/network-poc/static/index.html b/network-poc/static/index.html index c7d898a..7330a23 100644 --- a/network-poc/static/index.html +++ b/network-poc/static/index.html @@ -2552,7 +2552,7 @@ Write the corrected code.`; uiSocket.onmessage = (event) => { try { const raw = event.data; - if (raw.includes('"single_tokenize"') || raw.includes('"download_progress"')) return; + if (raw.includes('"single_tokenize"')) return; const data = JSON.parse(raw); if (data.type === "stats") { @@ -2577,6 +2577,24 @@ Write the corrected code.`; } else { dlBar.style.display = 'none'; } + // Terminaaliin latauksen edistyminen + const term = document.getElementById('agent-terminal'); + if (term) { + let dlLine = term.querySelector('.term-download'); + if (data.pct >= 100) { + if (dlLine) dlLine.remove(); + termLog(` ${data.file} ladattu`, '#a5d6ff'); + } else { + if (!dlLine) { + dlLine = document.createElement('div'); + dlLine.className = 'terminal-line term-download'; + term.appendChild(dlLine); + } + const bar = '█'.repeat(Math.floor(data.pct / 5)) + '░'.repeat(20 - Math.floor(data.pct / 5)); + dlLine.innerHTML = ` ${data.file} ${bar} ${data.pct}% ${data.loaded_mb}/${data.total_mb} MB`; + term.scrollTop = term.scrollHeight; + } + } } else if (data.type === "single_tokenize_done") { chatBox.classList.remove('hidden'); const r = data.result || {}; @@ -3160,6 +3178,12 @@ Write the corrected code.`; if (cl) { cl.textContent = 'Qwen2.5-Coder:' + (coderSize === '3b' ? '3B' : '0.5B'); cl.style.color = '#3fb950'; cl.title = sizeLabel + ' · Candle Wasm · CPU · max 512 tok'; } if (btn) { btn.dataset.state = 'ready'; btn.textContent = '✓ Valmis'; btn.style.borderColor = '#3fb950'; btn.style.color = '#3fb950'; btn.style.cursor = 'default'; btn.title = 'Kielimalli ladattu — oma kone on valmis laskentaan'; } localStorage.setItem('kpn-coder-loaded', 'true'); + // Terminaaliin valmis-viesti + const term = document.getElementById('agent-terminal'); + if (term) { + const sLabel = coderSize === '3b' ? 'Qwen2.5-Coder:3B' : 'Qwen2.5-Coder:0.5B'; + termLog(` ${sLabel} valmis — kpn run coder "prompti"`, '#3fb950'); + } } if (msg.includes('[Coder]') && msg.includes('Syöte:')) { // Pipeline piiloon kun generointi alkaa