Repository navigation
samples: add ops-assistant, one agent behind six response formats - #50
ishanaggarwal04 wants to merge 1 commit into
Conversation
A sample agent that returns the same answer as JSON, plain text, an async job, NDJSON, SSE and WebSocket, with one Rook profile and one scenario per format. It shows how Rook profiles adapt to each response shape. The Rook workspace (.testmuai) is not committed; the README describes the profiles and the hand edits made to the generated scenarios. .mcp.json declares data-server so a text scenario can declare verification_requires on summarize_incident and let the judge query the tool itself. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
f96d45b to
4b5458e
Compare
Continuous Review — Round 1 —
|
| Reviewer | Verdict | CRIT | HIGH | MED | LOW | Duration |
|---|---|---|---|---|---|---|
claude |
ABSTAIN_ERROR | 0 | 0 | 0 | 0 | 1s |
glm |
PASS | 0 | 0 | 2 | 2 | 216s |
Findings
glm — 2 finding(s)
[MED] Selfcheck never reads the X-Tool-Calls header the text profile depends on
- File:
samples/ops-assistant/scripts/selfcheck.mjs:109 - Scenario: The /v1/chat/text case checks status, content-type and body text, then returns toolCalls: null; the harness then marks summarize_incident as '(inferred)' so coverage passes. The X-Tool-Calls header is the load-bearing mechanism for the text Rook profile (README: 'Script: scripts/text.mjs reads that header and returns it as calls'; profile declares capabilities: calls: true), yet nothing in the sample validates it. If the agent stopped sending the header or sent it malformed (e.g. a serialization regression in tool_calls_header), selfcheck still prints 7/7 passed, and the failure only surfaces later as lost tool-call checks in a paid Rook run. The case also cannot distinguish a hallucinated answer (model never called the tool) from a grounded one — exactly the 'doesn't invent incident details' behavior SC-003 exists to catch.
[MED] done.output omits text streamed in earlier tool rounds, so joined deltas and done disagree
- File:
samples/ops-assistant/agent/server.py:139 - Scenario: run() yields every text content_block_delta from every LLM round, but result.output is set only on the final no-tool round (line 144, result.output = ''.join(text) after the break). If the model emits any narration alongside a tool_use in an intermediate round ("Let me look up A-100…"), NDJSON/SSE/WS clients that join deltas receive text that done.output omits. selfcheck asserts text === events.at(-1).output (scripts/selfcheck.mjs:57), so the PR's '7/7 endpoint checks pass' verification is one chatty model response away from failing on all three streaming endpoints, and the Streamlit transcript (built from deltas via st.write_stream) diverges from the done event Rook's scripts consume.
Auto-posted by continuous-review-agent v1.3 (findings now include a suggested fix / code snippet). Contact @vipulkv for feedback.
Continuous Review — Round 2 —
|
| Reviewer | Verdict | CRIT | HIGH | MED | LOW | Duration |
|---|---|---|---|---|---|---|
claude |
ABSTAIN_ERROR | 0 | 0 | 0 | 0 | 1s |
glm |
PASS | 0 | 0 | 2 | 0 | 141s |
Findings
glm — 2 finding(s)
[MED] done.output omits text streamed in earlier tool rounds, so joined deltas and done disagree
- File:
samples/ops-assistant/agent/server.py:143 - Scenario: The model emits text ('Let me check that order…') in the same round as a tool_use: delta events are yielded for every round (server.py:138) but result.output joins only the final round's text (server.py:143, since
textresets at server.py:129). The selfcheck's own checktext === events.at(-1).output(scripts/selfcheck.mjs:57) then fails spuriously, and the same request returns different answers by format — Rook's ndjson/sse/ws scripts report done.output while ui/app.py's stream_answer renders the joined deltas including the dropped preamble.
[MED] Text-endpoint case never reads the X-Tool-Calls header the text Rook profile depends on
- File:
samples/ops-assistant/scripts/selfcheck.mjs:113 - Scenario: The X-Tool-Calls header is the documented mechanism that makes the
textprofile's tool checks verifiable (server sends it via tool_calls_header/chat_text; Rook's scripts/text.mjs parses it). The selfcheck's text case reads only the body and returns toolCalls: null, then the harness marks summarize_incident '(inferred)' from the test's own expectation — its comment 'Text responses carry no tool list' is false for this server. If the header is dropped or emits invalid JSON, selfcheck still passes while the text profile silently loses its calls capability.
Auto-posted by continuous-review-agent v1.3 (findings now include a suggested fix / code snippet). Contact @vipulkv for feedback.
Adds
samples/ops-assistant: one ops agent (orders, incidents, logs, service status, reports) that returns the same answer in six response formats. Each format gets its own Rook profile and scenario, so the sample shows how profiles adapt to each response shape.POST /v1/chatjsonPOST /v1/chat/texttextPOST /v1/chat/async+GET /v1/jobs/{id}asyncPOST /v1/chat/ndjsonndjsonPOST /v1/chat/ssesseWS /v1/chat/wswsWhat's included
agent/server.py), two stdio MCP servers (mcp/), a mock backend (mock-api/), a Streamlit UI (ui/) and an endpoint selfcheck (scripts/selfcheck.mjs).rook/*.txt: the curl / wscat inputs used to create each profile withrook profile add --from..mcp.jsondeclaringdata-server. The text endpoint can't hand tool output to the judge, so a text scenario's "doesn't invent details" check comes back Unable to Verify. Declaringverification_requiresondata-server.summarize_incidentlets the judge query the tool itself.samples/README.md.The Rook workspace (
.testmuai/) is not committed. The README describes the profiles, the manual edit to thetextprofile, and the hand edits made to the generated scenarios.Verified
scripts/selfcheck.mjs: 7/7 endpoint checks pass.data-server.Notes for reviewers
GLM-5.3-Flash, through the Anthropic-format API). The setup commands in the README are PowerShell.🤖 Generated with Claude Code