feat(engine): compact answers; a reply cut off at the output ceiling drops no work and never ends COMPLETE #114
Open
james.maes
wants to merge 10 commits from
feat/compact-answers-and-output-ceiling into develop
pull from: feat/compact-answers-and-output-ceiling
merge into: QRun-IO:develop
QRun-IO:develop
QRun-IO:feat/one-card-for-a-set
QRun-IO:fix/render-widget-follows-data-access
QRun-IO:release/0.1
QRun-IO:rc/develop-into-release-0.1-registry
QRun-IO:feat/process-tools
QRun-IO:feat/writes-follow-the-person
QRun-IO:fix/atomic-confirm-and-closed-surface
QRun-IO:fix/tool-service-owns-policy-and-identity
QRun-IO:fix/tool-call-service-enforces-its-checks
QRun-IO:feat/tool-registry
QRun-IO:docs/actions-and-mcp-design
QRun-IO:rc/develop-into-release-0.1-everyone
QRun-IO:feat/store-reads-as-trusted-code
QRun-IO:rc/develop-into-release-0.1-weekly
QRun-IO:feat/weekly-budget
QRun-IO:rc/develop-into-release-0.1-save
QRun-IO:feat/save-and-schedule-analysis
QRun-IO:rc/develop-into-release-0.1-analyze
QRun-IO:feat/analyze-records
QRun-IO:fix/turn-watchdog-never-hangs-develop
QRun-IO:fix/turn-watchdog-never-hangs
QRun-IO:fix/live-thread-placeholders
QRun-IO:merge/develop-into-release-0.1
QRun-IO:automation/qbit-rc-pending
QRun-IO:fix/transcript-stored-before-message-end-develop
QRun-IO:fix/transcript-stored-before-message-end
QRun-IO:main
QRun-IO:archive/qrun-github-cutover-20261101/ca9212731dc2/develop
QRun-IO:feat/openai-compatible-provider
QRun-IO:dependabot/maven/develop/maven-minor-and-patch-634f43d868
QRun-IO:dependabot/github_actions/develop/github-actions-0fdda1077f
QRun-IO:feature/orb-0.8-track
QRun-IO:feature/orb-0.7.18
QRun-IO:feature/orb-0.7.17
QRun-IO:feature/orb-standardize-release-0.1
QRun-IO:feature/orb-main-standardization
QRun-IO:feature/shared-codeql
QRun-IO:feature/orb-0712-stable-gate
QRun-IO:feature/orb-rc-worker
QRun-IO:feature/orb-0.7.11
QRun-IO:feature/central-ci
QRun-IO:feature/conversation-management
QRun-IO:feature/starter-prompts-from-access
QRun-IO:feature/turns-not-jobs
QRun-IO:feature/assistant-attachments
QRun-IO:feature/assistant-optional-provider-health
QRun-IO:fix/assistant-health-tile-wording
QRun-IO:feature/fail-soft-renders
QRun-IO:fix/records-render-and-stream-context
QRun-IO:ci/release-rc-secrets-inherit
QRun-IO:feature/ui-api-1.6
QRun-IO:fix/shutdown-hook-weak-runtime
QRun-IO:fix/help-bundle-version
QRun-IO:feature/health-checks
QRun-IO:feature/jobs-tray
QRun-IO:feature/help-bundle
QRun-IO:feature/transcript-redaction
QRun-IO:feature/foreign-keys
QRun-IO:feature/schema-indexes
QRun-IO:fix/assistant-defaults-rollback
QRun-IO:feature/durable-turns
QRun-IO:fix/assistant-defaults-guards
QRun-IO:feature/tables-populated-defaults
QRun-IO:feature/provider-spi-package
QRun-IO:feature/email-api
QRun-IO:feature/orb-0.6.9
QRun-IO:feature/write-mode
QRun-IO:feature/x1-y1-channel-wall
QRun-IO:feature/email-qbit
QRun-IO:feature/spec-endpoints-core-invoker
QRun-IO:feature/provider-api-module
QRun-IO:feature/p7-scheduled-tasks
QRun-IO:feature/bulk-load-tools
QRun-IO:feature/p6-rag
QRun-IO:feature/presentation-demo-shots
QRun-IO:feature/answer-presentation
QRun-IO:fix/core-alerts-rc5
QRun-IO:feature/p5-routing-fallback
QRun-IO:feature/p4-budgets
QRun-IO:feature/p3-hipaa-routing
QRun-IO:feature/p2-bedrock-vertex
QRun-IO:feature/p1-provider-registry
QRun-IO:feature/spec-providers-write-mode-wall
QRun-IO:feature/demo-pending-card
QRun-IO:feature/release-rc-automation
QRun-IO:feature/demo-screens
QRun-IO:feature/profiles-skills-access
QRun-IO:feature/ui-api-tools
QRun-IO:feature/strict-tools-grammar-fix
QRun-IO:feature/app-home-settings
QRun-IO:feature/fix-rename-version-labels
QRun-IO:feature/note-burned-rc
QRun-IO:feature/assistant-record-screens
QRun-IO:feature/robustness-test-flake
QRun-IO:feature/ga-only-release-tags
QRun-IO:feature/snake-case-table-names
QRun-IO:chore/qrun-repo-standard
QRun-IO:feature/pom-revision-comment
QRun-IO:feature/phase-0-1-assistant
No Reviewers
Labels
Clear labels
architecture
bug
dependencies
documentation
duplicate
enhancement
github_actions
good first issue
help wanted
invalid
java
question
release:rc
secuurity
ux
wontfix
Architecture review: coupling, cohesion, UI API
Something isn't working
Improvements or additions to documentation
This issue or pull request already exists
New feature or request
Pull requests that update GitHub Actions code
Good for newcomers
Extra attention is needed
This doesn't seem right
Pull requests that update java code
Further information is requested
Merging this develop PR cuts the next release candidate
Admin UX / information architecture
This will not be worked on
No labels
Milestone
No items
No Milestone
Projects
Clear projects
No projects
No Assignees
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: QRun-IO/qbit-assistant#114
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
What
Answers stay compact, and a reply that stops at the output ceiling of one reply no longer drops work silently.
Design:
docs/one-card-for-a-set.md, section 5.Stacked on #113 (which is stacked on #112) (
feat/one-card-for-a-set): merge that one first; until then this diff shows its commits too.Part D: the output ceiling
max_tokenswas not read for tool calls. Calls the model had completely formed never ran, and the answer endedCOMPLETEwith a warning._invalid_argumentsor, for a call with no arguments yet, an empty input: both can look complete) and any call whose input could not be read. Those never run; each gets an error result saying so, which keeps one result per call, in order, and the provider's own state of the reply valid (TurnEngine.unfinishedToolUses,executeTools).maxOutputContinuations(2) times: the next model call sees what ran and what did not. A reply cut off in its text is given back with an instruction to go on. Each continuation is a model call under the spending limit, the kill switch and the time limit.INCOMPLETE, neverCOMPLETE: a notice says how many steps were done, how many were cut off and not run, and to say "continue". The unfinished answer stays in the conversation's history.minOutputTokensPerRequest(4,096, never abovemodels.mainMaxOutputTokens). Why not leave it as it was: a row is data an administrator types; one small number cut off every answer with a tool call in it, and nothing in code bounded it.Part C: compact output
maxRecordCardsPerTurn(3) record cards andmaxRecordChipsPerTurn(8) record links. Further ones are left out; every step is still listed; a list of records stays one table; a confirmation card is never left out. The model is told once when an answer is full.get_recordper record of a set, a plain sentence when the person lacks the permission, and re-issuing a call that was cut off. The cached request prefix changes once.What a host must change
Nothing.
INCOMPLETEis a new value ofassistant_turn.statusandassistant_message.status(text columns) and ofmessage.end; a provider row below 4,096 output tokens is read as 4,096 (seeUPGRADE.md).Tests
OutputCeilingTest,CompactOutputTest;TurnEngineTestandAssistantSettingsTestchanged in the one case each that asserted the old behaviour (a cut reply ended the answer; a row of 500 output tokens was taken as it was).Full gated build of this branch's head
4bf102c(./mvnw verify: Checkstyle, SpotBugs, PMD, tests, coverage; no gate skipped): BUILD SUCCESS, 748 tests (625 inqbit-assistant), 0 failures, every coverage check met.🤖 Generated with Claude Code
Note on hosted CI: the first run of this branch failed, and its rerun (the same commit, alone on the runner) passed.
The first run shared the runner with the build of the pull request below it in the stack (#113). Four existing tests and one of this change (
CompactOutputTest, twelve calls in one reply) that send several tool calls in one reply (TurnEngineTest.testParallelToolResultsInOneMessage,GoldenEvalTest.golden[7],RedTeamTest.testNoPermissionNoLeak,PresentResultsToolTest.testPersistenceAndReplay) each waited 61 seconds and failed. That is reproducible ondevelopwithout this change, with two processors:Cause, read in code:
ToolCallService.executeholdssynchronized(admission)while the first offer of a scope waits for a task it submitted to the runtime's virtual-thread executor; a virtual thread that blocks holding or entering a monitor is pinned to its carrier, so with two carriers the task never runs and every call of the batch waits fortoolCallTimeoutSeconds. It is not changed here (it is the lock of the tool-call service and deserves its own review); it is written up as a follow-up.View command line instructions
Checkout
From your project repository, check out a new branch and test the changes.