Previous `tests/common/mod.rs` spawned a mock Anthropic upstream via hand-rolled axum + std:🧵:spawn + own current-thread tokio runtime bound to 127.0.0.1:0. Stable on Linux runner; flaked on macOS GitHub Actions runners: thread 'streaming_responses_runs_real_loop_not_stub' panicked at kei-cortex/tests/openai_loop_wiring.rs:277:5: no responses delta event in stream: event: response.error data: {"error":"model: anthropic request: error sending request for url (http://127.0.0.1:49312/v1/messages)"} Root cause traced to macOS-runner loopback / fd-limit pressure on the dedicated-thread current-thread runtime. wiremock crate runs a production-quality hyper-based mock server, manages its own listener lifecycle, and survives the macOS runner constraints. ## Change - `Cargo.toml`: add wiremock = workspace dev-dep (already 0.6 in workspace) - `tests/common/mod.rs::MockAnthropicServer` rebuilt over wiremock::MockServer - `build_mock(text)` mounts `POST /v1/messages → 200 + canned body` on a wiremock instance - `mock_anthropic_responding_with()` spins one per call on a parked helper thread (preserves `MockAnthropicServer: 'static` lifetime for `shared_mock_anthropic` `OnceLock` singleton) - `shared_mock_anthropic()` API unchanged; existing test sites in `tests/openai_loop_wiring.rs` + `tests/openai_compat.rs` continue to work without modification ## Verification `cargo test -p kei-cortex --test openai_loop_wiring`: 7/7 pass locally `cargo test -p kei-cortex`: full suite green (428 lib + integration) Also includes DNA-INDEX regenerate (auto-encyclopedia hook artefact; 0 vortex matches preserved).
69 lines
2.2 KiB
TOML
69 lines
2.2 KiB
TOML
[package]
|
|
name = "kei-cortex"
|
|
version = "0.1.0"
|
|
edition.workspace = true
|
|
rust-version.workspace = true
|
|
description = "Local HTTP daemon exposing cortex state for UI consumption"
|
|
authors.workspace = true
|
|
license.workspace = true
|
|
|
|
[[bin]]
|
|
name = "kei-cortex"
|
|
path = "src/main.rs"
|
|
|
|
[lib]
|
|
name = "kei_cortex"
|
|
path = "src/lib.rs"
|
|
|
|
[dependencies]
|
|
axum = { version = "0.7", features = ["multipart", "ws"] }
|
|
tokio = { workspace = true }
|
|
tokio-util = { version = "0.7", features = ["rt"] }
|
|
tower = { workspace = true }
|
|
tower-http = { version = "0.5", features = ["cors", "trace"] }
|
|
serde = { workspace = true }
|
|
serde_json = { workspace = true }
|
|
clap = { workspace = true }
|
|
thiserror = { workspace = true }
|
|
rusqlite = { workspace = true }
|
|
anyhow = { workspace = true }
|
|
rand = "0.8"
|
|
reqwest = { workspace = true }
|
|
tokio-stream = { workspace = true }
|
|
futures = { workspace = true }
|
|
uuid = { version = "1", features = ["v4"] }
|
|
async-stream = "0.3"
|
|
toml = { workspace = true }
|
|
bytes = { workspace = true }
|
|
tempfile = { workspace = true }
|
|
dashmap = { workspace = true }
|
|
walkdir = { workspace = true }
|
|
which = "6"
|
|
once_cell = "1"
|
|
regex = { workspace = true }
|
|
portable-pty = { workspace = true }
|
|
# Wave 44a — tool-sandbox hardening
|
|
shell-words = { workspace = true }
|
|
url = { workspace = true }
|
|
lru = { workspace = true }
|
|
# Wave 44b — symlink-safe writes
|
|
nix = { workspace = true }
|
|
# Wave 44d — calendar usage boundaries
|
|
chrono = { workspace = true }
|
|
kei-pet = { path = "../kei-pet" }
|
|
kei-router = { path = "../kei-router" }
|
|
kei-shared = { path = "../kei-shared" }
|
|
kei-ledger = { path = "../kei-ledger" }
|
|
# Wave 55 Stage 2 — universal model registry. `default_model()` in
|
|
# `anthropic.rs` consults this for the `kei-cortex-default` role before
|
|
# falling back to the literal pin.
|
|
kei-model = { path = "../kei-model" }
|
|
# Phase 2 — per-turn token telemetry. Every chat handler fires a
|
|
# fire-and-forget `Store::record_event` after Done so sleep-report has
|
|
# real data. Open lazily on AppState init; tracker IO failures must
|
|
# never break the chat call.
|
|
kei-token-tracker = { path = "../kei-token-tracker" }
|
|
|
|
[dev-dependencies]
|
|
reqwest = { workspace = true, features = ["blocking"] }
|
|
wiremock = { workspace = true }
|