Skip to content

Commit a38e45c

Browse files
authored
Merge pull request #424 from AgentWorkforce/feat/additive-broker-sdk
feat: add Rust broker and sdk-ts (additive, no removals)
2 parents 67c679d + 421a8c9 commit a38e45c

84 files changed

Lines changed: 22521 additions & 4607 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.beads/issues.jsonl

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,20 @@
221221
{"id":"agent-relay-546","title":"Storage troubleshooting docs","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-28T13:07:54.784208+01:00","created_by":"khaliqgant","updated_at":"2026-01-28T13:10:21.19387+01:00","closed_at":"2026-01-28T13:10:21.19387+01:00","close_reason":"Documentation structure complete with placeholders for implementation details"}
222222
{"id":"agent-relay-547","title":"Add JSONL ledger to relay-pty for durability","description":"## Background\n\nThe relay-pty OutboxMonitor currently uses in-memory HashMap tracking. When relay-pty crashes or restarts, pending/in-flight messages are lost.\n\nPreviously, RelayLedger (TypeScript + SQLite) provided:\n- Crash recovery (reset processing → pending on startup)\n- Retry logic with configurable max retries\n- Audit trail for debugging\n- Content hash deduplication\n\nRelayLedger was removed because relay-pty handles the primary file-based message flow. But we lost durability features.\n\n## Proposal\n\nAdd JSONL-based ledger to relay-pty at `.agent-relay/meta/outbox-ledger.jsonl`:\n\n```json\n{\"file_id\":\"msg-001\",\"path\":\"/...\",\"status\":\"pending\",\"discovered_at\":1706540000000,\"retries\":0}\n{\"file_id\":\"msg-001\",\"status\":\"delivered\",\"processed_at\":1706540001000}\n{\"file_id\":\"msg-002\",\"status\":\"failed\",\"retries\":1,\"error\":\"daemon unreachable\"}\n```\n\n## Features to implement\n\n1. **Crash recovery** - On startup, scan JSONL for pending/processing records, retry them\n2. **Retry logic** - Track retries count, re-attempt failed deliveries up to max (3)\n3. **Audit trail** - Append delivered/failed records for debugging\n4. **Deduplication** - Check if file_id already processed before re-processing\n5. **Compaction** - Periodic compaction to keep file size manageable\n\n## Implementation\n\n1. Add `outbox_ledger.rs` module (~200-300 lines)\n2. Integrate with OutboxMonitor and parser.rs\n3. Add tests for crash recovery scenarios","status":"open","priority":2,"issue_type":"feature","created_at":"2026-01-29T09:54:06.750753+01:00","created_by":"khaliqgant","updated_at":"2026-01-29T09:54:18.992309+01:00"}
223223
{"id":"agent-relay-548","title":"Add getAllAgentSummaries and getStats to JSONL adapter","description":"The JSONL adapter currently lacks getAllAgentSummaries and getStats methods that exist in the SQLite adapter. These are used by the dashboard for: 1) Agent summaries: 'Recent Work' section in AgentProfilePanel 2) Stats: /api/history/stats endpoint showing message counts. The dashboard currently gracefully hides these sections when data is unavailable, but full parity would provide better UX for local users.","status":"open","priority":2,"issue_type":"task","created_at":"2026-01-29T10:46:10.962538+01:00","created_by":"khaliqgant","updated_at":"2026-01-29T10:46:20.463476+01:00"}
224+
{"id":"agent-relay-549","title":"Verified PTY delivery in Rust broker","status":"closed","priority":0,"issue_type":"feature","created_at":"2026-02-16T10:16:04.973451+01:00","created_by":"khaliqgant","updated_at":"2026-02-16T13:50:58.692578+01:00","closed_at":"2026-02-16T13:50:58.692578+01:00","close_reason":"Wave 2: Echo verification implemented in commits cf93556f and 845b9ece. PTY delivery now includes echo buffer matching for verified injection.","dependencies":[{"issue_id":"agent-relay-549","depends_on_id":"agent-relay-555","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
225+
{"id":"agent-relay-550","title":"Enable local send_message with async Relaycast publish","status":"closed","priority":0,"issue_type":"feature","created_at":"2026-02-16T10:16:05.791673+01:00","created_by":"khaliqgant","updated_at":"2026-02-16T13:50:58.742089+01:00","closed_at":"2026-02-16T13:50:58.742089+01:00","close_reason":"Wave 3: send_message handler now forwards to Relaycast REST API when target is not a local worker. RelaycastHttpClient implemented with register, send_dm, send_to_channel. Protocol events RelaycastPublished/RelaycastPublishFailed added. All 98 tests pass.","dependencies":[{"issue_id":"agent-relay-550","depends_on_id":"agent-relay-549","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
226+
{"id":"agent-relay-551","title":"Broker crash recovery with PID tracking","status":"in_progress","priority":0,"issue_type":"feature","created_at":"2026-02-16T10:16:07.049221+01:00","created_by":"khaliqgant","updated_at":"2026-02-16T14:08:27.900283+01:00"}
227+
{"id":"agent-relay-552","title":"Activity confirmation after PTY injection","status":"open","priority":1,"issue_type":"feature","created_at":"2026-02-16T10:16:07.824585+01:00","created_by":"khaliqgant","updated_at":"2026-02-16T10:16:07.824585+01:00","dependencies":[{"issue_id":"agent-relay-552","depends_on_id":"agent-relay-549","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
228+
{"id":"agent-relay-553","title":"Adaptive throttling for PTY injection","status":"open","priority":1,"issue_type":"feature","created_at":"2026-02-16T10:16:09.041173+01:00","created_by":"khaliqgant","updated_at":"2026-02-16T10:16:09.041173+01:00","dependencies":[{"issue_id":"agent-relay-553","depends_on_id":"agent-relay-552","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
229+
{"id":"agent-relay-554","title":"Delivery receipts from broker to SDK","status":"open","priority":1,"issue_type":"feature","created_at":"2026-02-16T10:16:09.954487+01:00","created_by":"khaliqgant","updated_at":"2026-02-16T10:16:09.954487+01:00","dependencies":[{"issue_id":"agent-relay-554","depends_on_id":"agent-relay-549","type":"blocks","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"agent-relay-554","depends_on_id":"agent-relay-550","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
230+
{"id":"agent-relay-555","title":"TDD integration tests for broker delivery guarantees","status":"open","priority":1,"issue_type":"task","created_at":"2026-02-16T10:16:10.878661+01:00","created_by":"khaliqgant","updated_at":"2026-02-16T10:21:22.32265+01:00"}
231+
{"id":"agent-relay-556","title":"Benchmark suite: broker vs old stack","status":"open","priority":1,"issue_type":"task","created_at":"2026-02-16T10:24:07.558772+01:00","created_by":"khaliqgant","updated_at":"2026-02-16T10:24:07.558772+01:00","dependencies":[{"issue_id":"agent-relay-556","depends_on_id":"agent-relay-550","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
232+
{"id":"agent-relay-557","title":"Stdio pipe bottleneck: add concurrency or switch to Unix socket","status":"open","priority":1,"issue_type":"bug","created_at":"2026-02-16T10:25:10.799822+01:00","created_by":"khaliqgant","updated_at":"2026-02-16T10:25:10.799822+01:00"}
233+
{"id":"agent-relay-558","title":"Move auth token out of WebSocket URL query string","status":"open","priority":2,"issue_type":"bug","created_at":"2026-02-16T10:25:11.656551+01:00","created_by":"khaliqgant","updated_at":"2026-02-16T10:25:11.656551+01:00"}
234+
{"id":"agent-relay-559","title":"Add flock guard to prevent multi-broker conflicts","status":"open","priority":2,"issue_type":"bug","created_at":"2026-02-16T10:25:12.493286+01:00","created_by":"khaliqgant","updated_at":"2026-02-16T10:25:12.493286+01:00"}
235+
{"id":"agent-relay-560","title":"Decompose main.rs into modules","status":"open","priority":3,"issue_type":"task","created_at":"2026-02-16T10:25:13.270209+01:00","created_by":"khaliqgant","updated_at":"2026-02-16T10:25:13.270209+01:00"}
236+
{"id":"agent-relay-561","title":"Make PTY auto-response patterns configurable","status":"open","priority":2,"issue_type":"task","created_at":"2026-02-16T10:25:14.688369+01:00","created_by":"khaliqgant","updated_at":"2026-02-16T10:25:14.688369+01:00"}
237+
{"id":"agent-relay-562","title":"Atomic state persistence with tmp+rename","status":"open","priority":2,"issue_type":"bug","created_at":"2026-02-16T10:25:15.484908+01:00","created_by":"khaliqgant","updated_at":"2026-02-16T10:25:15.484908+01:00"}
224238
{"id":"agent-relay-5af","title":"Hook doesn't integrate with daemon-based messaging","description":"hooks/inbox-check/hook.ts reads from file-based inbox but the daemon uses SQLite. When using daemon mode, the hook won't see messages. Need to: (1) Query daemon storage, (2) Or ensure inbox files are written in daemon mode too.","status":"open","priority":2,"issue_type":"bug","created_at":"2025-12-20T00:18:35.503078+01:00","updated_at":"2025-12-20T00:18:35.503078+01:00"}
225239
{"id":"agent-relay-5fa","title":"Add exponential backoff for daemon reconnection","description":"Implement graceful reconnection with exponential backoff delays [100, 500, 1000, 2000, 5000ms]. After max attempts, operate offline gracefully. See docs/TMUX_IMPROVEMENTS.md for implementation details.","status":"closed","priority":2,"issue_type":"feature","created_at":"2025-12-20T21:28:48.055013+01:00","updated_at":"2025-12-20T21:33:42.229756+01:00","closed_at":"2025-12-20T21:33:42.229756+01:00"}
226240
{"id":"agent-relay-5g0","title":"Heartbeat timeout could be more configurable","description":"In connection.ts:196, heartbeat timeout is hardcoded as 2x heartbeatMs. This should be independently configurable. Also, heartbeat failures immediately kill the connection - could implement exponential backoff for transient issues.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-20T00:18:03.556614+01:00","updated_at":"2025-12-23T23:03:07.563273+01:00","closed_at":"2025-12-23T23:03:07.563273+01:00"}

.beads/phase6-execution-plan.md

Lines changed: 0 additions & 235 deletions
This file was deleted.

.claude/rules/rust.md

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# Rust Conventions
2+
3+
This rule applies to all Rust files in `src/` and `tests/`.
4+
5+
## Error Handling
6+
7+
- Use `anyhow::Result` for application-level errors (CLI, main, tests)
8+
- Use `thiserror` for library-level error types that callers match on
9+
- Never `unwrap()` in production code — use `?` or handle explicitly
10+
- Telemetry and logging must be infallible — silently ignore errors
11+
12+
## Logging
13+
14+
- Use `tracing` macros: `tracing::info!`, `tracing::warn!`, `tracing::error!`
15+
- Use structured fields: `tracing::info!(agent = %name, "spawned")`
16+
- Set log levels via `RUST_LOG` env var (uses `tracing-subscriber` with `env-filter`)
17+
18+
## Async
19+
20+
- All async code uses `tokio` runtime
21+
- Prefer `tokio::select!` for concurrent operations
22+
- Use `tokio::spawn` for background tasks that should not block the main loop
23+
- Cancel safety: document whether async functions are cancel-safe
24+
25+
## Naming
26+
27+
- Modules: snake_case
28+
- Types/Structs/Enums: PascalCase
29+
- Functions/Methods: snake_case
30+
- Constants: UPPER_SNAKE_CASE
31+
- Enum variants: PascalCase
32+
33+
## Module Organization
34+
35+
- `lib.rs` re-exports public modules
36+
- `main.rs` contains CLI entry point and runtime orchestration
37+
- One concern per module (e.g., `auth.rs`, `dedup.rs`, `scheduler.rs`)
38+
39+
## Dependencies
40+
41+
- Minimize new dependencies — prefer what's already in `Cargo.toml`
42+
- Use feature flags to keep binary size small
43+
- Unix-only dependencies go under `[target.'cfg(unix)'.dependencies]`
44+
45+
## Testing
46+
47+
- Unit tests go in `#[cfg(test)] mod tests` within the source file
48+
- Integration tests go in `tests/` directory
49+
- Stress tests use `#[ignore]` attribute and run separately
50+
51+
## Serialization
52+
53+
- Use `serde` derive macros for JSON serialization
54+
- Use `#[serde(rename_all = "snake_case")]` for enum variants
55+
- Protocol types must match the TypeScript SDK definitions in `packages/sdk-ts/src/protocol.ts`

.github/workflows/rust-ci.yml

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
name: CI
2+
3+
on:
4+
pull_request:
5+
push:
6+
branches: [main]
7+
8+
env:
9+
CARGO_TERM_COLOR: always
10+
11+
jobs:
12+
rust-test:
13+
name: Rust Tests (${{ matrix.os }})
14+
runs-on: ${{ matrix.os }}
15+
strategy:
16+
fail-fast: false
17+
matrix:
18+
os: [ubuntu-latest, macos-latest]
19+
steps:
20+
- uses: actions/checkout@v4
21+
- uses: dtolnay/rust-toolchain@stable
22+
- uses: Swatinem/rust-cache@v2
23+
- run: cargo test
24+
25+
rust-clippy:
26+
name: Clippy
27+
runs-on: ubuntu-latest
28+
steps:
29+
- uses: actions/checkout@v4
30+
- uses: dtolnay/rust-toolchain@stable
31+
with:
32+
components: clippy
33+
- uses: Swatinem/rust-cache@v2
34+
- run: cargo clippy -- -D warnings
35+
36+
rust-fmt:
37+
name: Format
38+
runs-on: ubuntu-latest
39+
steps:
40+
- uses: actions/checkout@v4
41+
- uses: dtolnay/rust-toolchain@stable
42+
with:
43+
components: rustfmt
44+
- run: cargo fmt -- --check
45+
46+
sdk-check:
47+
name: SDK TypeScript Check
48+
runs-on: ubuntu-latest
49+
defaults:
50+
run:
51+
working-directory: packages/sdk-ts
52+
steps:
53+
- uses: actions/checkout@v4
54+
- uses: actions/setup-node@v4
55+
with:
56+
node-version: "22"
57+
- run: npm install
58+
- run: npx tsc --noEmit

0 commit comments

Comments
 (0)