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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
//! The documented HTTP API an orchestrating agent drives sessions with.
//!
//! The web viewer's own `/api/...` routes exist for the browser: they are
//! undocumented, cookie-only, and shaped around what a phone renders. These
//! `/api/v1/...` routes are the stable surface instead. They authenticate with
//! a bearer token from a file the same user can read, answer with a version
//! header so a client can tell which contract it reached, and — the point of
//! the whole module — let a caller block until one specific prompt finishes and
//! read a structured outcome for it.
//!
//! Everything that needs the daemon's live session actors or its SQLite store
//! reaches them through [`SubagentBackend`]. The daemon implements it in
//! `server_runtime::api`; the route tests implement it with a hand-written fake,
//! so the HTTP contract is tested without a running daemon.
//!
//! # The artifact routes are contract
//!
//! A caller that runs work somewhere other than this machine cannot read the
//! working tree to decide whether a change is safe to publish, so four routes
//! are part of the stable contract rather than conveniences. Changing any of
//! their media types, response bodies, or status meanings is a change to this
//! API:
//!
//! - `GET /sessions/{session_id}/diff` answers a unified diff as
//! `text/x-diff; charset=utf-8`, comparing from the revision the caller names
//! in `base` when it names one. With `json=true` it answers
//! `application/json` carrying `mj_checkpoint::archive::SessionDiff` instead,
//! a type that lives in the checkpoint crate, so changing its fields is also
//! a change here.
//! - `POST /sessions/{session_id}/export` answers the work in the form the
//! caller asks for: `kind: "patch"` as `text/x-diff`, `kind: "branch"` as
//! `{"branch", "remote"}`, and `kind: "bundle"` as
//! `application/octet-stream` with the bundle named in an attachment
//! filename.
//! - `GET` and `PUT /sessions/{session_id}/files` read one file as
//! `application/octet-stream` and inject one, answering `{"path", "bytes"}`.
//! Injection requires a live, idle session, because a write into a running
//! turn has no meaning.
//! - `GET /sessions/{session_id}/transcript` answers a page of the transcript,
//! with `next_after_seq` as the cursor to continue from and `latest_seq` to
//! tell whether the page reached the end.
//!
//! Where a route can refuse because of the session's own state — an export with
//! nothing to export, an injection into a session that is neither live nor idle
//! — it answers 409 with a sentence the caller can act on. A failure that is not
//! the caller's to fix is a 5xx. Keeping those apart is part of the contract,
//! because one is a decision for a person and the other is not.
use ;
use Arc;
use Duration;
use ;
use ;
use ;
use ;
use Next;
use ;
use ;
use ;
use ;
use ;
use CapacityRetry;
use ;
use ;
/// Response header naming the contract version this server speaks. A client
/// that understands only version 1 can refuse anything else without parsing a
/// body it may not recognize.
pub const API_VERSION_HEADER: &str = "mj-api-version";
pub const API_VERSION: &str = "1";
/// How long a wait blocks when the caller names no timeout, and the ceiling it
/// may ask for. Both are generous: a turn routinely runs for minutes, and the
/// caller is a program that reconnects rather than a person holding a page.
pub const DEFAULT_WAIT_SECS: u64 = 600;
pub use MAX_WAIT_SECONDS as MAX_WAIT_SECS;
/// How often a wait re-reads durable state for a session with no live actor.
const STOPPED_POLL_INTERVAL: Duration = from_millis;
const API_TOKEN_FILE: &str = "api-token";
const API_TOKEN_BYTES: usize = 32;
pub use *;
pub use *;
pub use *;
pub use *;
pub use *;
pub use *;
pub use *;
pub use EngineProbe;
pub use LocalEngineChecks;
use *;
use *;
pub use *;
pub use *;
pub use *;
use *;
use *;