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;i
prepared 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