Skip to content

Commit 76957dc

Browse files
committed
fix: stream forwarder silently drops events on send failure
When the stream receiver's buffer was full or the receiver was dropped, the forwarder would set `forward_enabled = false` but continue consuming events from `runtime_rx` without forwarding them. This caused the final `End` event (containing the response text) to be silently discarded, resulting in empty output from session.stream. Fix: break out of the forwarder loop immediately when `tx.send()` fails rather than continuing to consume events. Also add a warn log for debugging. Also bump version to 1.9.2 and fix a3s-code-node dependency on core (was pointing to 1.9.0 instead of matching workspace version).
1 parent 3ea2666 commit 76957dc

10 files changed

Lines changed: 41 additions & 33 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

core/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "a3s-code-core"
3-
version = "1.9.1"
3+
version = "1.9.2"
44
edition = "2021"
55
authors = ["A3S Lab Team"]
66
license = "MIT"

core/src/agent_api.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2056,11 +2056,13 @@ impl AgentSession {
20562056
let agent_loop = self.build_agent_loop();
20572057
let runtime_state = Arc::clone(&self.active_tools);
20582058
let forwarder = tokio::spawn(async move {
2059-
let mut forward_enabled = true;
20602059
while let Some(event) = runtime_rx.recv().await {
20612060
AgentSession::apply_runtime_event(&runtime_state, &event).await;
2062-
if forward_enabled && tx.send(event).await.is_err() {
2063-
forward_enabled = false;
2061+
if tx.send(event).await.is_err() {
2062+
// Receiver dropped or buffer full — stop forwarding to avoid
2063+
// silently dropping subsequent events (e.g., the final `End`).
2064+
tracing::warn!("stream forwarder: receiver dropped, stopping event forward");
2065+
break;
20642066
}
20652067
}
20662068
});
@@ -2177,11 +2179,13 @@ impl AgentSession {
21772179
let token_clone = cancel_token.clone();
21782180
let runtime_state = Arc::clone(&self.active_tools);
21792181
let forwarder = tokio::spawn(async move {
2180-
let mut forward_enabled = true;
21812182
while let Some(event) = runtime_rx.recv().await {
21822183
AgentSession::apply_runtime_event(&runtime_state, &event).await;
2183-
if forward_enabled && tx.send(event).await.is_err() {
2184-
forward_enabled = false;
2184+
if tx.send(event).await.is_err() {
2185+
// Receiver dropped or buffer full — stop forwarding to avoid
2186+
// silently dropping subsequent events (e.g., the final `End`).
2187+
tracing::warn!("stream forwarder: receiver dropped, stopping event forward");
2188+
break;
21852189
}
21862190
}
21872191
});

sdk/node/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "a3s-code-node"
3-
version = "1.9.1"
3+
version = "1.9.2"
44
edition = "2021"
55
authors = ["A3S Lab Team"]
66
license = "MIT"
@@ -11,7 +11,7 @@ description = "A3S Code Node.js bindings - Native addon via napi-rs"
1111
crate-type = ["cdylib"]
1212

1313
[dependencies]
14-
a3s-code-core = { version = "1.9.0", path = "../../core", features = ["ahp"] }
14+
a3s-code-core = { version = "1.9.2", path = "../../core", features = ["ahp"] }
1515
napi = { version = "2", features = ["async", "napi6", "serde-json"] }
1616
napi-derive = "2"
1717
tokio = { version = "1.35", features = ["full"] }

sdk/node/examples/streaming/stream_fix_test.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#!/usr/bin/env npx tsx
22
/**
3-
* Stream fix verification test.
4-
* Uses kimi model from config and logs ALL event types to verify no "unknown" appears.
3+
* Stream fix verification test - matches user's issue code exactly.
4+
* Uses kimi model and maxToolRounds: 0 (no tool calls) as reported.
55
*/
66

77
import { Agent, Session } from '../../index.js';
@@ -12,12 +12,16 @@ async function main(): Promise<void> {
1212
const configPath = process.env.A3S_CONFIG || path.join(os.homedir(), '.a3s', 'config.hcl');
1313
console.log(`Using config: ${configPath}\n`);
1414
console.log('='.repeat(80));
15-
console.log('Stream Fix Verification Test');
15+
console.log('Stream Fix Verification Test (maxToolRounds: 0, no tools)');
1616
console.log('='.repeat(80));
1717
console.log();
1818

1919
const agent = await Agent.create(configPath);
20-
const session = agent.session('.');
20+
// User's exact code: maxToolRounds: 0 to disable tool calls
21+
const session = agent.session('.', {
22+
permissive: true,
23+
max_tool_rounds: 0,
24+
});
2125

2226
console.log('Streaming with prompt: "Say hello in 5 words"\n');
2327

sdk/node/package-lock.json

Lines changed: 8 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

sdk/node/package.json

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@a3s-lab/code",
3-
"version": "1.9.1",
3+
"version": "1.9.2",
44
"description": "A3S Code - Native AI coding agent library for Node.js",
55
"main": "index.js",
66
"types": "index.d.ts",
@@ -44,11 +44,11 @@
4444
"test:loop": "tsx --tsconfig examples/tsconfig.json examples/test_loop_commands.ts"
4545
},
4646
"optionalDependencies": {
47-
"@a3s-lab/code-darwin-arm64": "1.9.1",
48-
"@a3s-lab/code-linux-x64-gnu": "1.9.1",
49-
"@a3s-lab/code-linux-x64-musl": "1.9.1",
50-
"@a3s-lab/code-linux-arm64-gnu": "1.9.1",
51-
"@a3s-lab/code-linux-arm64-musl": "1.9.1",
52-
"@a3s-lab/code-win32-x64-msvc": "1.9.1"
47+
"@a3s-lab/code-darwin-arm64": "1.9.2",
48+
"@a3s-lab/code-linux-x64-gnu": "1.9.2",
49+
"@a3s-lab/code-linux-x64-musl": "1.9.2",
50+
"@a3s-lab/code-linux-arm64-gnu": "1.9.2",
51+
"@a3s-lab/code-linux-arm64-musl": "1.9.2",
52+
"@a3s-lab/code-win32-x64-msvc": "1.9.2"
5353
}
5454
}

sdk/python-bootstrap/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
44

55
[project]
66
name = "a3s-code"
7-
version = "1.9.1"
7+
version = "1.9.2"
88
description = "A3S Code Python bootstrap package that fetches platform-native binaries from GitHub Releases"
99
readme = "../python/README.md"
1010
license = { text = "MIT" }

sdk/python/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "a3s-code-py"
3-
version = "1.9.1"
3+
version = "1.9.2"
44
edition = "2021"
55
authors = ["A3S Lab Team"]
66
license = "MIT"
@@ -12,7 +12,7 @@ name = "a3s_code"
1212
crate-type = ["cdylib"]
1313

1414
[dependencies]
15-
a3s-code-core = { version = "1.9.1", path = "../../core", features = ["ahp"] }
15+
a3s-code-core = { version = "1.9.2", path = "../../core", features = ["ahp"] }
1616
pyo3 = "0.23"
1717
tokio = { version = "1.35", features = ["full"] }
1818
serde_json = "1.0"

sdk/python/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "maturin"
44

55
[project]
66
name = "a3s-code"
7-
version = "1.9.1"
7+
version = "1.9.2"
88
description = "A3S Code - Native Python bindings for the AI coding agent"
99
readme = "README.md"
1010
license = {text = "MIT"}

0 commit comments

Comments
 (0)