slowSseLineBytesKeepIdleWatchdogAlive drove the event out in 20-byte steps
50ms apart against a 150ms idle timeout, so any observed gap above 150ms
tripped the watchdog. Each idle close restarts the whole event from the
handler, and the 3s observation budget only covered about three attempts, so a
few slow steps exhausted the reconnects. The test failed this way on macOS
runners repeatedly, most recently on main.
Send the event in 8-byte steps and raise the idle timeout to 500ms, which
keeps the property under test intact: the event now needs about a second of
50ms steps to arrive, so a watchdog fed only by whole frames still expires
well inside the run. Raise the observation timeout so a single slow step is
absorbed by a reconnect instead of ending the prompt.
Locally the old test starts failing once steps reach 260ms; the new one
survives 400ms steps and still fails, as it should, when SseReader stops
reporting per-byte activity.
A prompt reserves both a prompt slot and a stream-cleanup slot in
DaemonClient.submit, but releases them at different times: the prompt slot is
released synchronously in FutureTask.done(), immediately before the terminal
publication gate opens, while the stream-cleanup slot is only released once the
SSE stream has finished closing on the stream-close executor. The terminal path
in observe() closes that stream asynchronously and does not wait for it.
Both semaphores were sized to maximumConcurrentPrompts, so a caller chaining
prompts off completionFuture() at full capacity races the previous prompt's
close: when the close had not finished by the time the terminal was published,
startPrompt failed with DaemonClientCapacityException("Stream cleanup capacity
is exhausted"). This is how the documented chaining pattern behaves under load,
and it made terminalContinuationCanStartNextPromptAtClientCapacity flaky in CI.
Size the stream-cleanup semaphore to allow one draining cleanup per prompt
slot, which is exactly the overlap the release ordering can produce. Admission
backpressure is unchanged in kind: cleanups that stay stalled beyond that
headroom still fail fast, now after two generations instead of one.
The stream-close executor queue is derived from the same capacity, so it still
absorbs every reservation without rejecting work.
The constant was defined as new Timeout(60L, TimeUnit.MINUTES) in both
the client and qwencode modules, i.e. 60 minutes, contradicting its name
and Javadoc ("A timeout of 30 minutes."). It is the fallback turn timeout
in ProcessTransport and the timeout used by QwenCodeCli.simpleQuery, so
callers waited twice the documented default. The 30-minute intent is
corroborated by TransportOptionsAdapter.DEFAULT_TURN_TIMEOUT (30 min).
Change the literal to 30L in both modules.
The two catch blocks in AcpClient's constructor threw a new
AgentInitializeException with only a message, discarding the caught
IOException/ExecutionException/InterruptedException/TimeoutException.
AgentInitializeException already has a (String, Throwable) constructor,
so pass the caught exception as the cause to keep the root failure and
its stack trace in the exception chain.
* feat(cli): implement non-interactive /context output and diagnostic
- Extract collectContextData() from contextCommand.ts for shared usage.
- Register /context in ALLOWED_BUILTIN_COMMANDS_NON_INTERACTIVE.
- Extend SDK control protocol with GET_CONTEXT_USAGE request.
- Implement handleGetContextUsage in SystemController for programmatic token queries.
- Expose getContextUsage() method in the TypeScript SDK Query interface.
* fix: address review feedback and fix critical bugs in context usage feature
- Add missing `get_context_usage` route in ControlDispatcher (SDK calls would throw)
- Fix `executionMode` defaulting: use `?? 'interactive'` to match other commands
- Validate dynamic import of `collectContextData` before invoking
- Preserve original error message in handleGetContextUsage catch block
- Add ControlDispatcher test for get_context_usage routing
- Add JSDoc comment for context command in non-interactive allowlist
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: re-check abort signal after async operations in handleGetContextUsage
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* docs: add getContextUsage() to SDK TypeScript documentation
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* docs: clarify getContextUsage showDetails is a display hint, not a data filter
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: make showDetails affect response shape, add getContextUsage test
- When showDetails is false, return empty detail arrays instead of full
data so /context and /context detail produce different payloads
- Add unit test for Query.getContextUsage() covering request payload
and response handling
* fix: strip UI type from SDK response, sync Java SDK protocol
- Remove leaked `type: 'context_usage'` from control response payload
- Add GET_CONTEXT_USAGE to Java SDK protocol mirror (enum, interface,
union type)
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Refactor subagent model configuration from nested modelConfig object to a simple model string field for better UX and clarity.
Changes:
- Replace modelConfig object with model string in SubagentConfig interface
- Add model-selection.ts utility for parsing and validating model selectors
- Support 'inherit' keyword and bare model IDs (e.g., 'glm-5', 'claude-sonnet-4-6')
- Maintain backward compatibility by parsing legacy modelConfig frontmatter
- Update validation to reject cross-provider authType-prefixed selectors
- Update SDK types (TypeScript and Java) to reflect new schema
- Add comprehensive tests for model selection and validation
- Update documentation with model selection examples
Breaking changes:
- modelConfig.frontmatter field deprecated in favor of model field
- Cross-provider model selectors (e.g., 'openai:gpt-4') not supported for subagents
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>