diff --git a/qitos/qita/_cli_app.py b/qitos/qita/_cli_app.py
index e1cb9a9..b23bc41 100644
--- a/qitos/qita/_cli_app.py
+++ b/qitos/qita/_cli_app.py
@@ -1466,6 +1466,61 @@ def _render_run_html(payload: Dict[str, Any], embedded: bool) -> str:
if(!thought) return (summary || '
No explicit thought.
');
return ''+esc(thought)+'
' + summary;
}}
+function modelInputPayloads(events){{
+ const out = [];
+ const es = Array.isArray(events) ? events : [];
+ for(const e of es){{
+ const payload = e && typeof e.payload === 'object' ? e.payload : null;
+ if(payload && String(payload.stage || '') === 'model_input') out.push(payload);
+ }}
+ return out;
+}}
+function renderModelMessagePreview(messages){{
+ const msgs = Array.isArray(messages) ? messages : [];
+ if(!msgs.length) return 'No message list recorded.
';
+ const blocks = [];
+ for(let i=0;i' +
+ 'message ' + i + ' ยท ' + esc(role) + '' +
+ '' + esc(typeof content === 'string' ? content : JSON.stringify(content, null, 2)) + '
' +
+ ''
+ );
+ }}
+ return blocks.join('');
+}}
+function renderModelInput(events){{
+ const inputs = modelInputPayloads(events);
+ if(!inputs.length){{
+ return 'No model input recorded for this step. This usually means the step was handled by the harness or a tool path without calling the model.
';
+ }}
+ const blocks = [];
+ for(let i=0;iprepared text from agent.prepare(state)
' + esc(String(prepared)) + '
'
+ : 'No prepared text recorded.
';
+ const messagesBlock =
+ 'Actual messages sent to model
' +
+ renderModelMessagePreview(payload.messages) +
+ ' ';
+ blocks.push('' + kvBlock(rows) + preparedBlock + messagesBlock + '
');
+ }}
+ return '' + blocks.join('') + '
';
+}}
function renderAction(actions){{
const label = firstActionLabel(actions);
if(!label) return 'No action.
';
@@ -1870,6 +1925,7 @@ def _render_run_html(payload: Dict[str, Any], embedded: bool) -> str:
let h = 'STEP ' + it.sid + '
events ' + it.events.length + '
';
if(showObs) h += sectionHtml('State', renderState(obsInput), obsInput, 'state', collapsedAll);
h += sectionHtml('Prompt', renderPromptMetadata(it.step.prompt_metadata || {{}}), it.step.prompt_metadata || {{}}, 'prompt', collapsedAll);
+ h += sectionHtml('Model Input', renderModelInput(it.events), modelInputPayloads(it.events), 'model_input', collapsedAll);
h += sectionHtml('Visual Assets', renderVisualAssets(it.step), {{visual_assets: it.step.visual_assets || [], observation_modalities: it.step.observation_modalities || [], model_input_modalities: it.step.model_input_modalities || [], model_input_visual_count: it.step.model_input_visual_count || 0}}, 'visual_assets', collapsedAll);
h += sectionHtml('Thought', renderThought(d, it.events, it.step), d, 'thought', collapsedAll);
h += sectionHtml('Parser Diagnostics', renderParserDiagnostics(it.step.parser_diagnostics || {{}}), it.step.parser_diagnostics || {{}}, 'parser', collapsedAll);
diff --git a/tests/test_qita_cli.py b/tests/test_qita_cli.py
index 9230e85..9c1f502 100644
--- a/tests/test_qita_cli.py
+++ b/tests/test_qita_cli.py
@@ -100,6 +100,7 @@ def _make_run(root: Path, run_id: str) -> Path:
)
(run / "events.jsonl").write_text(
'{"step_id":0,"phase":"INIT","ok":true,"ts":"x"}\n'
+ '{"step_id":0,"phase":"DECIDE","ok":true,"ts":"x1","payload":{"stage":"model_input","prepared":"Task: inspect the run","prepared_full":"Task: inspect the run\\nStep: 0","history_message_count":1,"messages":[{"role":"system","content":"You are an agent."},{"role":"user","content":"Task: inspect the run"}],"context":{"input_tokens_total":22,"prepared_tokens":6,"history_tokens":8,"occupancy_ratio":0.12}}}\n'
'{"step_id":0,"phase":"DECIDE","ok":true,"ts":"y","payload":{"stage":"model_output","raw_output":"Thought: inspect the run","model_response":{"text":"Thought: inspect the run","usage":{"prompt_tokens":10,"completion_tokens":4,"total_tokens":14},"finish_reason":"stop","tool_calls":[{"id":"call_1","type":"function","function":{"name":"visit_url","arguments":"{\\"url\\":\\"https://example.com\\"}"}}],"model_name":"demo-model","provider":"demo-provider","metadata":{}},"context":{"input_tokens_total":3200,"occupancy_ratio":0.74}}}\n',
encoding="utf-8",
)
@@ -251,6 +252,9 @@ def test_render_pages(tmp_path: Path):
assert "decision_source" in view
assert "native_tool_call_used" in view
assert "tool_delivery" in view
+ assert "Model Input" in view
+ assert "prepared text from agent.prepare(state)" in view
+ assert "Actual messages sent to model" in view
assert "Visual Assets" in view
assert "grounding metadata" in view
assert "critic retries" in view