1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
//! # talon-http — CoPilot HTTP API channel
//!
//! See `docs/RUST_ARCHITECTURE.md` §3.4 (untrusted data) and §3.5 (audit).
//!
//! An axum server that CoPilot talks to (plus the MemPalace bridge), exposed
//! to the host as a [`talon_core::channel::Channel`] owning every
//! `http:copilot*` JID.
//!
//! ## Lanes
//! - `http:copilot` — the shared chat lane (callers that name no user).
//! - `http:copilot:investigate` — investigations; ephemeral session, its
//! output reaches CoPilot through the MCP write-back tools, not SSE.
//! - `http:copilot:u:<id>` — one in-memory lane per CoPilot user, cloned
//! from the base group (same folder/mounts, own session + IPC namespace
//! `copilot-u-<lowercased id, ≤ 20 chars>-<32 hex of sha256(exact id)>`,
//! e.g. `copilot-u-bob-81b637d8fcd2c6da6359e6963113a117`), dropped again
//! by the idle-lane sweep. Ids must match `^[A-Za-z0-9_-]{1,48}$`; anything
//! else is rejected with 400 rather than stripped into another user's lane.
//! The 128-bit hash makes it infeasible to choose an id whose key collides
//! with another user's (N-8).
//!
//! ## Endpoints
//! | Method | Path | Notes |
//! |---|---|---|
//! | GET | `/health` | unauthenticated liveness |
//! | GET | `/status` | uptime, lanes, sessions, scheduled tasks, queue |
//! | GET | `/metrics` | Prometheus text exposition |
//! | POST | `/session/reset` | `{scope: chat\|investigate\|all, user_id?}` |
//! | POST | `/investigate` | `{alert_id, customer_code, triggered_by?, template_override?}` |
//! | GET | `/investigations` | `?limit=` recent investigation jobs |
//! | GET | `/investigations/{id}` | one job |
//! | GET | `/evals/{alert_id}` | eval JSON written by the investigation lane (`<data_dir>/sessions/copilot-investigate/evals/`) |
//! | GET | `/templates` | prompt templates available for overrides |
//! | POST | `/palace/lesson` | MemPalace `add_drawer` (503 unless a palace runner is configured) |
//! | GET | `/palace/search` | MemPalace `search` (503 unless configured) |
//! | POST | `/palace/forget` | MemPalace `delete_drawer` (503 unless configured) |
//! | POST | `/message` | chat; answers stream back as SSE |
//!
//! ## Security
//! Fail-closed API key (an unset `HTTP_API_KEY` rejects every request but
//! `/health`), constant-time comparison via [`talon_security::auth`],
//! per-IP auth-failure throttling, request body limit, strict input
//! validation, security headers, allowlist-based CORS, audit events and
//! investigation de-duplication. Served with [`talon_net::serve`]
//! (header-read timeout, connection caps), bound to `127.0.0.1` unless
//! configured otherwise. MemPalace code never runs on the host by default
//! (see [`palace`]); agent-writable `evals/` and `prompts/` are read without
//! following symlinks. Eval records come from the investigation lane's
//! private state directory, so no other CoPilot lane can forge them (N-2);
//! the shared `groups/<folder>/evals/` is read only with
//! `COPILOT_EVALS_LEGACY_GROUP_DIR=true` (migration).
//!
//! ## Testing
//! [`router`] builds the full axum [`axum::Router`] from an [`HttpState`];
//! drive it with `tower::ServiceExt::oneshot`. The database and key
//! verification are reached through the [`HttpStore`] and [`KeyVerifier`]
//! seams so the server can be exercised without the real backends.
pub use ;
pub use HttpChannel;
pub use ;
pub use ;
pub use ;
pub use ;
pub use HttpStore;