Skip to content

Commit 15634a9

Browse files
committed
v51: stream owned inference and expose evidence-based commissioning
1 parent 81d5115 commit 15634a9

12 files changed

Lines changed: 488 additions & 9 deletions

‎V100_AUDIT.md‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -535,3 +535,29 @@ passed after replacing missing ML counters with explicitly unknown values. Tests
535535
cover archive pagination, goal attribution, incomplete tails, path/symlink rejection,
536536
HTTP action routes and goal-change separation while preserving verifiable replay.
537537
No hardware training improvement or universal goal oracle is certified.
538+
539+
## v51: observable streaming and commissioning evidence
540+
541+
Owned llama.cpp SSE and Ollama NDJSON transports now journal partial output and
542+
backend-returned local reasoning while generation is in progress. Both capture and
543+
stream preferences must be enabled; the upgrade enables these following the
544+
operator's request. Thinking modes remain unchanged. Deltas are flushed in bounded
545+
chunks; a lightweight read-only endpoint feeds the dashboard every two seconds
546+
without waiting for full hardware collection. Final token counts remain measured
547+
backend counters, not estimates from text. Incomplete streams are visible as
548+
partial output but never accepted as completed responses. Historical omitted
549+
reasoning, unrecorded actions and token IDs cannot be reconstructed.
550+
551+
The readiness endpoint and dashboard distinguish worker heartbeat, reported job
552+
execution, verified optimizer counters, accepted weights, resolved goal outcomes,
553+
layout publication and observed stream transport. Unknown evidence is explicitly
554+
unknown. This does not bypass independent acceptance or force poor candidates into
555+
production. A ready worker does not prove execution, and busy inference does not
556+
prove training. Hardware commissioning still requires the installed user backends.
557+
558+
Validation: full deterministic suite 1000 passed, 65 skipped, one resource-dependent
559+
owned-worker integration deselected and one existing PEFT warning. After adding a
560+
real framed-transport mock, focused streaming/helper/dashboard coverage passed
561+
115 tests. HTTP route checks also exercise the fast inference and readiness APIs.
562+
No user GPU, Windows workload or improved accepted production model was available
563+
for direct validation in this environment.

‎pyproject.toml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ name = "rlms"
33
authors = [
44
{name = "Alex Zhang", email = "altzhang@mit.edu"},
55
]
6-
version = "0.1.3+v100.50"
6+
version = "0.1.3+v100.51"
77
description = "Recursive Language Models."
88
readme = "README.md"
99
license = "MIT"

‎rlm/clients/llamacpp.py‎

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,13 @@ def request(self, endpoint: str, data: dict[str, Any] | None = None) -> dict[str
7777
**self.activity_context,
7878
)
7979
started = time.perf_counter()
80+
self.thread_state.activity_request_id = request_id
81+
self.thread_state.stream_buffer = {}
8082
try:
8183
result = self.http_request(endpoint, data)
84+
self.flush_stream()
8285
except Exception as error:
86+
self.flush_stream()
8387
journal.write(
8488
"errors", "inference-failed", {"error": type(error).__name__}, request_id=request_id
8589
)
@@ -134,6 +138,48 @@ def request(self, endpoint: str, data: dict[str, Any] | None = None) -> dict[str
134138
)
135139
return result
136140

141+
def streaming_enabled(self) -> bool:
142+
if not self.activity_root:
143+
return False
144+
path = self.activity_root / "research/user-preferences.json"
145+
if not path.exists():
146+
return False
147+
preferences = json.loads(path.read_text())
148+
return (
149+
preferences.get("stream_local_model_trace") is True
150+
and preferences.get("capture_local_model_trace") is True
151+
)
152+
153+
def stream_delta(self, channel: str, text: str) -> None:
154+
self.remaining_timeout()
155+
buffer = getattr(self.thread_state, "stream_buffer", {})
156+
buffer[channel] = buffer.get(channel, "") + text
157+
self.thread_state.stream_buffer = buffer
158+
last = getattr(self.thread_state, "stream_flushed", 0)
159+
if time.monotonic() - last >= 0.5 or len(buffer[channel]) >= 1024:
160+
self.flush_stream()
161+
162+
def flush_stream(self) -> None:
163+
from rlm.v100.activity import ActivityLog
164+
165+
journal = ActivityLog(self.activity_root, self.research_owner, self.activity_actor)
166+
for channel, text in getattr(self.thread_state, "stream_buffer", {}).items():
167+
if text:
168+
journal.write(
169+
"steps",
170+
"inference-delta",
171+
{
172+
"channel": channel,
173+
"text": text,
174+
"model": self.model_name,
175+
"device": self.activity_context.get("device"),
176+
"partial": True,
177+
},
178+
request_id=getattr(self.thread_state, "activity_request_id", None),
179+
)
180+
self.thread_state.stream_buffer = {}
181+
self.thread_state.stream_flushed = time.monotonic()
182+
137183
def remaining_timeout(self) -> float:
138184
deadline = getattr(self, "request_deadline", None)
139185
if deadline is None:
@@ -145,6 +191,19 @@ def remaining_timeout(self) -> float:
145191

146192
def http_request(self, endpoint: str, data: dict[str, Any] | None = None) -> dict[str, Any]:
147193
# No environment proxy routing for local model traffic.
194+
if endpoint == "/v1/chat/completions" and data is not None and self.streaming_enabled():
195+
from rlm.v100.streaming import local_reply
196+
197+
with requests.Session() as session:
198+
session.trust_env = False
199+
with session.post(
200+
self.base_url + endpoint,
201+
json={**data, "stream": True, "stream_options": {"include_usage": True}},
202+
timeout=self.remaining_timeout(),
203+
stream=True,
204+
) as response:
205+
response.raise_for_status()
206+
return local_reply(response.iter_lines(chunk_size=128), self.stream_delta)
148207
with requests.Session() as session:
149208
session.trust_env = False
150209
response = (

‎rlm/v100/dashboard_layout.py‎

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
<details><summary>Dowody treningu i ostatnie błędy</summary><pre id="evidence"></pre></details>
2525
<script>
2626
const $=id=>document.getElementById(id), fmt=x=>x===null||x===undefined?'brak potwierdzonych danych':String(x), pct=x=>typeof x==='number'&&Number.isFinite(x)?(x*100).toFixed(2)+'%':'brak danych';
27-
const layoutVersion='__LAYOUT_SHA__';
27+
const layoutVersion='__LAYOUT_SHA__';let latestSnapshot=null;
2828
function card(label,value){const node=document.createElement('div');node.className='card';const title=document.createElement('small');title.textContent=label;const strong=document.createElement('strong');strong.className='value';strong.textContent=fmt(value);node.append(title,strong);$('cards').append(node)}
2929
function workView(data){
3030
for(const id of ['actors','goals','events']){if(!$(id)){const node=document.createElement(id==='goals'?'pre':'div');node.id=id;if(id==='actors')node.className='grid';$('cards').after(node)}}
@@ -51,17 +51,17 @@
5151
const plansPanel=panel('plan-panel','Mission plan',$('cards'));let planGrid=$('plan-grid');if(!planGrid){planGrid=document.createElement('div');planGrid.id='plan-grid';planGrid.className='plan-grid';plansPanel.append(planGrid)}planGrid.replaceChildren();
5252
for(const [key,label] of [['long','Long-term goal'],['mid','Medium-term plan'],['short','Next steps']]){const box=document.createElement('article');box.className='plan-item';const h=document.createElement('h3');h.textContent=label;box.append(h);const p=document.createElement('p');p.textContent=data.live?.goals?.[key]?.text||'No recorded plan';box.append(p);planGrid.append(box)}
5353
const resources=panel('resource-panel','Compute resources',plansPanel);resources.append($('actors'));$('actors').className='resource-grid';
54-
const agents=panel('agent-panel','Agent activity - tasks, decisions and evidence',resources);let grid=$('agent-grid');if(!grid){const note=document.createElement('p');note.className='muted';note.textContent='Recorded public output, tool results and token counts. Counts and opted-in local model reasoning arrive after a response finishes. Model reasoning is unverified, not evidence of execution.';grid=document.createElement('div');grid.id='agent-grid';agents.append(note,grid)}
54+
const agents=panel('agent-panel','Agent activity - tasks, decisions and evidence',resources);let grid=$('agent-grid');if(!grid){const note=document.createElement('p');note.className='muted';note.textContent='Recorded public output, tool results and token counts. Opted-in local output and reasoning stream during inference. Measured token counts arrive at completion. Model reasoning is unverified, not evidence of execution.';grid=document.createElement('div');grid.id='agent-grid';agents.append(note,grid)}
5555
grid.replaceChildren();
5656
for(const a of data.live?.agents||[]){const node=document.createElement('article');node.className='agent-row';const head=document.createElement('header');const h=document.createElement('h3');h.textContent=a.label;const badge=document.createElement('span');badge.className='state-badge';badge.textContent=a.state||'unknown';head.append(h,badge);node.append(head);
5757
textField(node,'Model / device',[a.model,a.device].filter(Boolean).join(' / '));
5858
const u=a.usage||{};textField(node,'Last response tokens',Object.keys(u).length?`Input ${fmt(u.prompt_tokens)} | Output ${fmt(u.completion_tokens)} | Total ${fmt(u.total_tokens)} | recorded ${a.usage_at||''}`:'Not reported for this actor');
5959
textField(node,'Duration',a.seconds===undefined?null:a.seconds+' s');
6060
detailsField(node,'Assigned task',a.task,a.label+'-task');textField(node,'Tool',a.tool);
61-
detailsField(node,'Returned local model reasoning (unverified)',a.returned_trace,a.label+'-trace');detailsField(node,'Public conclusion and next step',a.declaration,a.label+'-output');detailsField(node,'Observed result / error',a.result,a.label+'-result');detailsField(node,'Evidence',a.source,a.label+'-source');textField(node,'Last event',typeof a.updated==='number'?new Date(a.updated*1000).toLocaleString():a.updated);grid.append(node)}
61+
detailsField(node,'Live partial output - latest recorded window',a.stream_output,a.label+'-live-output');detailsField(node,'Live local reasoning - latest recorded window',a.stream_reasoning,a.label+'-live-trace');detailsField(node,'Returned local model reasoning (unverified)',a.returned_trace,a.label+'-trace');detailsField(node,'Public conclusion and next step',a.declaration,a.label+'-output');detailsField(node,'Observed result / error',a.result,a.label+'-result');detailsField(node,'Evidence',a.source,a.label+'-source');textField(node,'Last event',typeof a.updated==='number'?new Date(a.updated*1000).toLocaleString():a.updated);grid.append(node)}
6262
if(!grid.children.length)textField(grid,'Activity','No recent recorded agent events');
6363
const timeline=panel('timeline-panel','Action timeline - latest 200 recorded events',agents);timeline.append($('events'));$('events').replaceChildren();
64-
for(const e of [...(data.live?.events||[])].reverse()){const d=document.createElement('details');d.className='event-row';d.dataset.key=(e.request_id||e.time)+'-'+e.actor+'-'+e.kind;const h=document.createElement('summary');h.textContent=[e.time,e.branch,e.actor,e.kind,e.tool].filter(Boolean).join(' | ');d.append(h);textField(d,'Returned local reasoning (unverified)',e.returned_trace);textField(d,'Task / arguments',e.task);textField(d,'Public output / result',e.summary);textField(d,'Error / status',e.detail);if(e.usage&&Object.keys(e.usage).length)textField(d,'Tokens',JSON.stringify(e.usage));textField(d,'Seconds',e.seconds);textField(d,'Evidence',e.source);$('events').append(d)}
64+
for(const e of [...(data.live?.events||[])].reverse()){const d=document.createElement('details');d.className='event-row';d.dataset.key=(e.request_id||e.time)+'-'+e.actor+'-'+e.kind;const h=document.createElement('summary');h.textContent=[e.time,e.branch,e.actor,e.kind,e.tool].filter(Boolean).join(' | ');d.append(h);textField(d,'Live delta',e.delta_text);textField(d,'Returned local reasoning (unverified)',e.returned_trace);textField(d,'Task / arguments',e.task);textField(d,'Public output / result',e.summary);textField(d,'Error / status',e.detail);if(e.usage&&Object.keys(e.usage).length)textField(d,'Tokens',JSON.stringify(e.usage));textField(d,'Seconds',e.seconds);textField(d,'Evidence',e.source);$('events').append(d)}
6565
for(const n of document.querySelectorAll('details[data-key]'))if(opened.has(n.dataset.key))n.open=true;
6666
}
6767
function archivePanel(){
@@ -73,7 +73,7 @@
7373
}
7474
function learningPanel(data){const p=panel('goal-learning-panel','Goal-directed ML pipeline',$('plan-panel'));let body=$('goal-learning-view');if(!body){body=document.createElement('div');body.id='goal-learning-view';p.append(body)}body.replaceChildren();const evidence=data.report?.mission_evidence||{},g=evidence.goal_learning||{};textField(body,'Active goal ID',g.goal_id||'No goal recorded');for(const [k,v] of Object.entries(g.learning_task||{}))textField(body,k,v);textField(body,'Recent forecasts',fmt(g.forecasts?.length));textField(body,'Recent resolved forecasts',g.recent_resolved);textField(body,'Recent Brier score',g.recent_brier);textField(body,'Admitted training examples',g.training_admission?.admitted);textField(body,'Confirmed optimizer updates',fmt(evidence.optimizer_updates_observed));textField(body,'Accepted weight updates',fmt(evidence.accepted_weight_updates_this_run));detailsField(body,'Training admission evidence',JSON.stringify(g.training_admission||{}),'goal-admission')}
7575
function svg(tag,attrs,text){let node=document.createElementNS('http://www.w3.org/2000/svg',tag);for(const [key,val] of Object.entries(attrs))node.setAttribute(key,val);if(text!==undefined)node.textContent=text;return node}
76-
function render(data){const m=data.mission||{},r=data.report||{},ev=(m.state?.phase==='official-public-baseline'?r.mission_evidence?.official_benchmark:null)||m.evaluation||{},learn=m.learning||{},gpu=data.gpu||{};
76+
function render(data){latestSnapshot=data;const m=data.mission||{},r=data.report||{},ev=(m.state?.phase==='official-public-baseline'?r.mission_evidence?.official_benchmark:null)||m.evaluation||{},learn=m.learning||{},gpu=data.gpu||{};
7777
if(data.layout?.active_sha256&&layoutVersion!==data.layout.active_sha256){location.reload();return}$('layout').textContent='HTML mastera: /workspace/dashboard/index.html | '+(data.layout?.state||'oczekiwanie')+(data.layout?.error?' | '+data.layout.error:'');
7878
$('fresh').textContent='Zebrano: '+new Date(data.collected_at*1000).toLocaleString()+' | Raport zbierany co 20 s | Przebieg: '+fmt(m.run);
7979
workView(data);learningPanel(data);archivePanel();$('warning').textContent=(data.errors||[]).join('\n');$('cards').replaceChildren();card('Misja',m.running?'działa':'zatrzymana');card('Faza',m.state?.phase);card('Cykle uczenia',learn.completed_cycles);card('Zaakceptowane aktualizacje wag',r.accepted_weight_updates_this_run);card('Potwierdzone kroki optymalizatora',r.mission_evidence?.optimizer_updates_observed);card('Kontekst',m.state?.context_window);card('GPU - wykorzystanie',gpu.utilization===undefined?null:gpu.utilization+'%');card('VRAM zajęty / razem',gpu.memory_used===undefined?null:gpu.memory_used+' / '+gpu.memory_total+' MiB');card('GPU - temperatura / moc',gpu.temperature===undefined?null:gpu.temperature+' °C / '+gpu.power+' W');
@@ -83,7 +83,9 @@
8383
$('reports').replaceChildren();for(const id of data.paper_reports||[]){const row=document.createElement('p');row.append(document.createTextNode(id+' '));for(const [name,label] of [['report.html','HTML i wykresy'],['report.json','JSON'],['trades.csv','CSV']]){const a=document.createElement('a');a.href='/paper/'+encodeURIComponent(id)+'/'+name;a.target='_blank';a.rel='noopener';a.textContent=label;row.append(a,document.createTextNode(' · '))}$('reports').append(row)}
8484
}
8585
async function refresh(){try{let response=await fetch('/api/status',{cache:'no-store'});if(!response.ok)throw Error('HTTP '+response.status);render(await response.json())}catch(error){$('warning').textContent='Nie można odświeżyć: '+error.message}}
86-
$('reload').onclick=refresh;refresh();setInterval(refresh,5000);
86+
async function liveInference(){if(!latestSnapshot)return;try{const response=await fetch('/api/live-inference',{cache:'no-store'});if(!response.ok)throw Error('HTTP '+response.status);const live=await response.json();agentView({...latestSnapshot,live:{...latestSnapshot.live,events:live.events,agents:[...(live.agents||[]),...(latestSnapshot.live?.agents||[]).filter(a=>a.source==='research/state/drones.sqlite3')]}})}catch(error){$('warning').textContent='Live inference unavailable: '+error.message}}
87+
async function readinessView(){try{const response=await fetch('/api/readiness',{cache:'no-store'});if(!response.ok)throw Error('HTTP '+response.status);const data=await response.json();const p=panel('readiness-panel','Commissioning evidence',$('goal-learning-panel')||$('plan-panel'));let body=$('readiness-view');if(!body){body=document.createElement('div');body.id='readiness-view';p.append(body)}body.replaceChildren();for(const c of data.checks||[])textField(body,c.name,`${c.state} | ${c.detail} | ${c.source||''}`)}catch(error){$('warning').textContent='Readiness unavailable: '+error.message}}
88+
$('reload').onclick=refresh;refresh();setInterval(refresh,5000);setInterval(liveInference,2000);setInterval(readinessView,5000);
8789
</script></html>"""
8890

8991

‎rlm/v100/live_status.py‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,12 @@ def recent_events(root: Path, limit: int = 200) -> list[dict]:
7575
if row.get("kind") == "local-model-reasoning"
7676
else None,
7777
"trace_part": payload.get("part"),
78+
"delta_channel": payload.get("channel")
79+
if row.get("kind") == "inference-delta"
80+
else None,
81+
"delta_text": payload.get("text")
82+
if row.get("kind") == "inference-delta"
83+
else None,
7884
"source": str(path),
7985
"device": payload.get("device"),
8086
"model": payload.get("model"),
@@ -109,6 +115,14 @@ def agent_views(events: list[dict], jobs: list[dict]) -> list[dict]:
109115
if event.get("device"):
110116
view["device"] = event["device"]
111117
view["model"] = event.get("model")
118+
if event.get("delta_text"):
119+
if view.get("stream_request") != event.get("request_id"):
120+
view["stream_output"], view["stream_reasoning"] = "", ""
121+
view["stream_request"] = event.get("request_id")
122+
key = (
123+
"stream_reasoning" if event.get("delta_channel") == "reasoning" else "stream_output"
124+
)
125+
view[key] = (view.get(key, "") + event["delta_text"])[-16384:]
112126
if event.get("returned_trace"):
113127
if event.get("trace_part") == 0:
114128
view["returned_trace"] = ""

0 commit comments

Comments
 (0)