connector-usage-only: regenerate v4 goldens and schemas, format, fix tests
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
28f2e5d2e7
commit
bb8909f2c2
24 changed files with 206 additions and 201 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
|
@ -144,6 +144,7 @@ dependencies = [
|
|||
"libc",
|
||||
"model-connector",
|
||||
"rmp-serde",
|
||||
"rmpv",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2",
|
||||
|
|
|
|||
|
|
@ -5,8 +5,9 @@ use std::sync::{Arc, Mutex};
|
|||
use std::time::Duration;
|
||||
|
||||
use model_connector::{
|
||||
CallerAdmission, PlanQuotaSnapshot, ReasoningEffort, StopReason, ToolDefinition, TransportAdmission, TransportDisposition, TransportInvocation,
|
||||
TransportKey, TransportReceipt, TransportService, decrypt_result, encrypt_invocation,
|
||||
CallerAdmission, PlanQuotaSnapshot, ReasoningEffort, StopReason, ToolDefinition,
|
||||
TransportAdmission, TransportDisposition, TransportInvocation, TransportKey, TransportReceipt,
|
||||
TransportService, decrypt_result, encrypt_invocation,
|
||||
};
|
||||
|
||||
use super::*;
|
||||
|
|
@ -480,8 +481,7 @@ impl Door {
|
|||
.unwrap()
|
||||
});
|
||||
let service =
|
||||
TransportService::open(&dir.join("replay.cc"), PROVIDER, callers, 5_000)
|
||||
.unwrap();
|
||||
TransportService::open(&dir.join("replay.cc"), PROVIDER, callers, 5_000).unwrap();
|
||||
Self { dir, service }
|
||||
}
|
||||
|
||||
|
|
@ -498,13 +498,13 @@ impl Door {
|
|||
request: ProviderRequest,
|
||||
) -> (model_connector::ExecutionClaim, TransportInvocation) {
|
||||
let key = TransportKey::from_connection_secret(&format!("{caller}-key")).unwrap();
|
||||
let invocation =
|
||||
TransportInvocation::new(caller, 2_000, [7; 32], request).unwrap();
|
||||
let invocation = TransportInvocation::new(caller, 2_000, [7; 32], request).unwrap();
|
||||
let envelope = encrypt_invocation(&invocation, &key).unwrap();
|
||||
match self
|
||||
.service
|
||||
.begin(&envelope, 1_000, &PlanQuotaSnapshot::default(), FRAME)
|
||||
.unwrap() {
|
||||
.unwrap()
|
||||
{
|
||||
TransportAdmission::Execute(claim) => (*claim, invocation),
|
||||
TransportAdmission::Reply(_) => panic!("the door answered instead of admitting"),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@ use std::time::Duration;
|
|||
|
||||
use cultcache_rs::{CultCache, DatabaseEntry, SingleFileMessagePackBackingStore};
|
||||
use model_connector::{
|
||||
CallerAdmission, CallerConfig, LeaseTurn, MIN_PAYLOAD_BYTES, ProviderBackend,
|
||||
ServeError, ServeLimits, ServiceError, TransportService, load_admissions, serve_service,
|
||||
CallerAdmission, CallerConfig, LeaseTurn, MIN_PAYLOAD_BYTES, ProviderBackend, ServeError,
|
||||
ServeLimits, ServiceError, TransportService, load_admissions, serve_service,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use thiserror::Error;
|
||||
|
|
@ -230,9 +230,7 @@ impl ClaudeConnectorConfig {
|
|||
}
|
||||
let mut seen = BTreeSet::new();
|
||||
for model in &caller.allowed_models {
|
||||
if !has_model_id_form(model)
|
||||
|| !seen.insert(model.as_str())
|
||||
{
|
||||
if !has_model_id_form(model) || !seen.insert(model.as_str()) {
|
||||
return Err(ConfigError::Invalid("allowed_models"));
|
||||
}
|
||||
}
|
||||
|
|
@ -344,7 +342,6 @@ fn has_model_id_form(model: &str) -> bool {
|
|||
&& after_ok
|
||||
}
|
||||
|
||||
|
||||
/// One file name under `$CREDENTIALS_DIRECTORY`, never a path.
|
||||
fn is_credential_name(name: &str) -> bool {
|
||||
!name.is_empty()
|
||||
|
|
|
|||
|
|
@ -671,9 +671,9 @@ mod tests {
|
|||
fn a_frame_that_trickles_past_its_deadline_is_refused_however_small_each_read() {
|
||||
let (mut reader, mut writer) = UnixStream::pair().unwrap();
|
||||
let frame = encode_frame(&LeaseMessage::ClaudeLeaseRefusal(LeaseRefused {
|
||||
kind: LeaseRefusalKind::Busy,
|
||||
detail: "lease:x".to_string(),
|
||||
}));
|
||||
kind: LeaseRefusalKind::Busy,
|
||||
detail: "lease:x".to_string(),
|
||||
}));
|
||||
let trickle = thread::spawn(move || {
|
||||
for byte in frame {
|
||||
if writer.write_all(&[byte]).is_err() {
|
||||
|
|
|
|||
|
|
@ -28,8 +28,8 @@ pub use launch::ChildEnv;
|
|||
#[cfg(target_os = "linux")]
|
||||
pub use lease::{
|
||||
LeaseCaller, LeaseGranted, LeaseLimits, LeaseMessage, LeaseRefusalKind, LeaseRefused,
|
||||
LeaseRequest, MAX_LEASE_FRAME_BYTES, PeerCredentials, PeerUnit,
|
||||
PeerUnits, decode_frame, encode_frame, peer_credentials, serve_leases, user_uid,
|
||||
LeaseRequest, MAX_LEASE_FRAME_BYTES, PeerCredentials, PeerUnit, PeerUnits, decode_frame,
|
||||
encode_frame, peer_credentials, serve_leases, user_uid,
|
||||
};
|
||||
#[cfg(unix)]
|
||||
pub use process::StdProcessPort;
|
||||
|
|
|
|||
|
|
@ -280,6 +280,9 @@ fn the_dollar_flags_are_not_flags() {
|
|||
let scratch = Scratch::new();
|
||||
let made = init(&scratch, &init_flags(&scratch, extra));
|
||||
assert!(!made.status.success(), "{extra:?} was accepted");
|
||||
assert!(!Path::new(&scratch.path("connector.cc")).exists(), "{extra:?}");
|
||||
assert!(
|
||||
!Path::new(&scratch.path("connector.cc")).exists(),
|
||||
"{extra:?}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -279,7 +279,12 @@ fn start(setup: Setup) -> Harness {
|
|||
});
|
||||
let quota = Arc::new(QuotaCell::new());
|
||||
let listener = UnixListener::bind(&socket).unwrap();
|
||||
let serving = (service.clone(), quota.clone(), tokens.clone(), units.clone());
|
||||
let serving = (
|
||||
service.clone(),
|
||||
quota.clone(),
|
||||
tokens.clone(),
|
||||
units.clone(),
|
||||
);
|
||||
let caller = LeaseCaller {
|
||||
uid: setup.uid,
|
||||
caller_id: CALLER.to_string(),
|
||||
|
|
@ -343,7 +348,10 @@ fn ask_until_granted(harness: &Harness, first_invocation: u64) -> Answer {
|
|||
fn a_grant_passes_one_fd_holding_the_token_then_end_of_file() {
|
||||
let harness = start(setup());
|
||||
let mut answer = ask(&harness, 60_000);
|
||||
assert_eq!(granted(&answer).lease_id, format!("lease:{}", invocation(1)));
|
||||
assert_eq!(
|
||||
granted(&answer).lease_id,
|
||||
format!("lease:{}", invocation(1))
|
||||
);
|
||||
assert_eq!(answer.fds.len(), 1);
|
||||
let mut read = Vec::new();
|
||||
File::from(answer.fds.remove(0))
|
||||
|
|
@ -351,7 +359,10 @@ fn a_grant_passes_one_fd_holding_the_token_then_end_of_file() {
|
|||
.unwrap();
|
||||
assert_eq!(read, TOKEN.as_bytes());
|
||||
assert_eq!(harness.tokens.reads.load(Ordering::SeqCst), 1);
|
||||
assert!(!contains(&answer.raw, TOKEN), "the token is in the pipe only");
|
||||
assert!(
|
||||
!contains(&answer.raw, TOKEN),
|
||||
"the token is in the pipe only"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -416,7 +427,10 @@ fn a_rejected_window_refuses_the_lease_until_its_reset() {
|
|||
.quota
|
||||
.observe([window("five_hour", 1_000, "rejected", reset)]);
|
||||
let refused = ask(&harness, 60_000);
|
||||
assert_eq!(refusal_of(&refused), Some(LeaseRefusalKind::ProviderRejected));
|
||||
assert_eq!(
|
||||
refusal_of(&refused),
|
||||
Some(LeaseRefusalKind::ProviderRejected)
|
||||
);
|
||||
assert!(refused.fds.is_empty());
|
||||
assert_eq!(harness.tokens.reads.load(Ordering::SeqCst), 0);
|
||||
// At the provider's own reset the refusal lifts, with no one lifting it.
|
||||
|
|
|
|||
|
|
@ -762,8 +762,15 @@ mod tests {
|
|||
#[test]
|
||||
fn the_invocations_identity_covers_its_request() {
|
||||
let one = invocation();
|
||||
let mut other = one.clone();
|
||||
other.request.max_output_tokens += 1;
|
||||
let mut request = one.request.clone();
|
||||
request.max_output_tokens += 1;
|
||||
let other = TransportInvocation::new(
|
||||
one.caller_runtime_id.clone(),
|
||||
one.expires_at_unix_ms,
|
||||
one.native_request_sha256,
|
||||
request,
|
||||
)
|
||||
.unwrap();
|
||||
assert_ne!(
|
||||
canonical_invocation_bytes(&one).unwrap(),
|
||||
canonical_invocation_bytes(&other).unwrap()
|
||||
|
|
|
|||
|
|
@ -67,14 +67,6 @@ impl FlakyStore {
|
|||
pub(crate) fn allowance(&self) -> Arc<AtomicUsize> {
|
||||
self.pushes_allowed.clone()
|
||||
}
|
||||
|
||||
/// A store over the same records that accepts `pushes_allowed` more writes.
|
||||
pub(crate) fn reopened(&self, pushes_allowed: usize) -> Self {
|
||||
Self {
|
||||
held: self.held.clone(),
|
||||
pushes_allowed: Arc::new(AtomicUsize::new(pushes_allowed)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "daemon")]
|
||||
|
|
@ -133,7 +125,6 @@ pub(crate) fn request() -> ProviderRequest {
|
|||
request
|
||||
}
|
||||
|
||||
|
||||
pub(crate) fn invocation() -> TransportInvocation {
|
||||
TransportInvocation::new("epiphany-yggdrasil", 2_000, [7; 32], request()).unwrap()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ use crate::contract::ContractError;
|
|||
|
||||
pub const USAGE_READOUT_SCHEMA_ID: &str = "gamecult.model.usage_readout.v1";
|
||||
|
||||
|
||||
/// One window of the subscription plan, as the provider reported it.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
|
|
|
|||
|
|
@ -382,10 +382,7 @@ mod tests {
|
|||
FailureKind, Refusal, TransportDisposition, TransportEvent, TransportEventPayload,
|
||||
TransportInvocation, TransportOutcome, TransportResult,
|
||||
};
|
||||
use crate::fixtures::{
|
||||
TestStore, caller, invocation_for, receipt,
|
||||
request,
|
||||
};
|
||||
use crate::fixtures::{TestStore, caller, invocation_for, receipt, request};
|
||||
|
||||
const CALLER: &str = "epiphany-yggdrasil";
|
||||
const KEY: &str = "epiphany-distinct-test-key";
|
||||
|
|
@ -461,13 +458,7 @@ mod tests {
|
|||
let (sender, receiver) = std::sync::mpsc::channel();
|
||||
let path = path.to_path_buf();
|
||||
thread::spawn(move || {
|
||||
let _ = sender.send(serve(
|
||||
listener,
|
||||
limits,
|
||||
admissions,
|
||||
&path,
|
||||
backend,
|
||||
));
|
||||
let _ = sender.send(serve(listener, limits, admissions, &path, backend));
|
||||
});
|
||||
receiver.recv_timeout(Duration::from_secs(2)).ok()
|
||||
}
|
||||
|
|
@ -493,15 +484,7 @@ mod tests {
|
|||
let listener = TcpListener::bind("127.0.0.1:0").unwrap();
|
||||
let endpoint = listener.local_addr().unwrap();
|
||||
let path = store.path.clone();
|
||||
thread::spawn(move || {
|
||||
serve(
|
||||
listener,
|
||||
limits(),
|
||||
admissions,
|
||||
&path,
|
||||
backend,
|
||||
)
|
||||
});
|
||||
thread::spawn(move || serve(listener, limits(), admissions, &path, backend));
|
||||
let client =
|
||||
ConnectorClient::new(endpoint, KEY, FRAME, Some(Duration::from_secs(5))).unwrap();
|
||||
(client, endpoint)
|
||||
|
|
@ -770,10 +753,9 @@ mod tests {
|
|||
let envelope =
|
||||
crate::envelope::encrypt_invocation(&invocation, &crate::fixtures::security(KEY))
|
||||
.unwrap();
|
||||
let TransportAdmission::Execute(claim) =
|
||||
service
|
||||
.begin(&envelope, now_ms(), &PlanQuotaSnapshot::default(), 1 << 20)
|
||||
.unwrap()
|
||||
let TransportAdmission::Execute(claim) = service
|
||||
.begin(&envelope, now_ms(), &PlanQuotaSnapshot::default(), 1 << 20)
|
||||
.unwrap()
|
||||
else {
|
||||
panic!("a fresh request must execute");
|
||||
};
|
||||
|
|
@ -881,12 +863,7 @@ mod tests {
|
|||
fn the_smallest_frame_also_carries_the_failure_that_stands_in_for_a_result() {
|
||||
let long = "x".repeat(crate::envelope::MAX_IDENTITY_BYTES);
|
||||
let plaintext = crate::contract::wire_encode(&crate::service::result_size_failure(
|
||||
&long,
|
||||
&long,
|
||||
&long,
|
||||
[0xff; 32],
|
||||
[0xff; 32],
|
||||
0,
|
||||
&long, &long, &long, [0xff; 32], [0xff; 32], 0,
|
||||
))
|
||||
.unwrap()
|
||||
.len();
|
||||
|
|
@ -994,16 +971,7 @@ mod tests {
|
|||
}
|
||||
|
||||
fn admission(id: &str, key: &str, slots: usize, payload: usize) -> CallerAdmission {
|
||||
CallerAdmission::new(
|
||||
id,
|
||||
key,
|
||||
1,
|
||||
["gpt-5.4".to_string()],
|
||||
slots,
|
||||
payload,
|
||||
32_768,
|
||||
)
|
||||
.unwrap()
|
||||
CallerAdmission::new(id, key, 1, ["gpt-5.4".to_string()], slots, payload, 32_768).unwrap()
|
||||
}
|
||||
|
||||
/// `Some(field)` when serve refused the configuration, `None` while it serves.
|
||||
|
|
@ -1233,10 +1201,9 @@ mod tests {
|
|||
&crate::fixtures::security(KEY),
|
||||
)
|
||||
.unwrap();
|
||||
let TransportAdmission::Execute(claim) =
|
||||
service
|
||||
.begin(&envelope, now_ms(), &PlanQuotaSnapshot::default(), 1 << 20)
|
||||
.unwrap()
|
||||
let TransportAdmission::Execute(claim) = service
|
||||
.begin(&envelope, now_ms(), &PlanQuotaSnapshot::default(), 1 << 20)
|
||||
.unwrap()
|
||||
else {
|
||||
panic!("a fresh request must execute");
|
||||
};
|
||||
|
|
@ -1385,15 +1352,7 @@ mod tests {
|
|||
let backend = CountingBackend::new(true);
|
||||
let path = store.path.clone();
|
||||
let served = backend.clone();
|
||||
thread::spawn(move || {
|
||||
serve(
|
||||
listener,
|
||||
limits(),
|
||||
admissions,
|
||||
&path,
|
||||
served,
|
||||
)
|
||||
});
|
||||
thread::spawn(move || serve(listener, limits(), admissions, &path, served));
|
||||
let client =
|
||||
ConnectorClient::new(endpoint, KEY, FRAME, Some(Duration::from_secs(5))).unwrap();
|
||||
client.execute(&fresh("request-key")).unwrap();
|
||||
|
|
|
|||
|
|
@ -524,7 +524,8 @@ impl TransportService {
|
|||
.get::<ReplayRecord>(&replay_key(&identity))
|
||||
.map_err(replay_store_error)?
|
||||
.ok_or(ServiceError::NoActiveRequest)?;
|
||||
if active.state != ReplayState::Active || active.invocation_sha256 != claim.invocation_sha256
|
||||
if active.state != ReplayState::Active
|
||||
|| active.invocation_sha256 != claim.invocation_sha256
|
||||
{
|
||||
return Err(ServiceError::ActiveRequestMismatch);
|
||||
}
|
||||
|
|
@ -897,13 +898,9 @@ mod tests {
|
|||
|
||||
let mut changed_request = request();
|
||||
changed_request.instructions.push_str(" Different cargo.");
|
||||
let conflicting = TransportInvocation::new(
|
||||
"epiphany-yggdrasil",
|
||||
2_000,
|
||||
[7; 32],
|
||||
changed_request,
|
||||
)
|
||||
.unwrap();
|
||||
let conflicting =
|
||||
TransportInvocation::new("epiphany-yggdrasil", 2_000, [7; 32], changed_request)
|
||||
.unwrap();
|
||||
let refusal = match service
|
||||
.begin_unplanned(
|
||||
&encrypt_invocation(&conflicting, &security).unwrap(),
|
||||
|
|
@ -932,7 +929,9 @@ mod tests {
|
|||
let mut service = open_service(&store, 1);
|
||||
let first_envelope = encrypt_invocation(&first, &security).unwrap();
|
||||
assert!(matches!(
|
||||
service.begin_unplanned(&first_envelope, 1_000, FRAME).unwrap(),
|
||||
service
|
||||
.begin_unplanned(&first_envelope, 1_000, FRAME)
|
||||
.unwrap(),
|
||||
TransportAdmission::Execute(_)
|
||||
));
|
||||
|
||||
|
|
@ -1035,10 +1034,12 @@ mod tests {
|
|||
) -> (TransportAdmission, TransportInvocation) {
|
||||
let mut request = invocation_for(CALLER, request_id).request;
|
||||
edit(&mut request);
|
||||
let invocation =
|
||||
TransportInvocation::new(CALLER, 2_000, [7; 32], request).unwrap();
|
||||
let invocation = TransportInvocation::new(CALLER, 2_000, [7; 32], request).unwrap();
|
||||
let envelope = encrypt_invocation(&invocation, &security(KEY)).unwrap();
|
||||
(service.begin_unplanned(&envelope, 1_000, FRAME).unwrap(), invocation)
|
||||
(
|
||||
service.begin_unplanned(&envelope, 1_000, FRAME).unwrap(),
|
||||
invocation,
|
||||
)
|
||||
}
|
||||
|
||||
fn refusal_of(admission: TransportAdmission, invocation: &TransportInvocation) -> Refusal {
|
||||
|
|
@ -1118,14 +1119,9 @@ mod tests {
|
|||
32_768,
|
||||
)
|
||||
.unwrap();
|
||||
TransportService::open(
|
||||
&store.path,
|
||||
"fixture-sse",
|
||||
[admission],
|
||||
5_000,
|
||||
)
|
||||
.unwrap()
|
||||
.begin_unplanned(&envelope, 1_000, FRAME)
|
||||
TransportService::open(&store.path, "fixture-sse", [admission], 5_000)
|
||||
.unwrap()
|
||||
.begin_unplanned(&envelope, 1_000, FRAME)
|
||||
};
|
||||
assert!(matches!(admit(size), Ok(TransportAdmission::Execute(_))));
|
||||
let refused = admit(size - 1).unwrap();
|
||||
|
|
@ -1272,15 +1268,7 @@ mod tests {
|
|||
#[test]
|
||||
fn identities_are_bounded_at_admission_and_on_the_request() {
|
||||
let admit = |caller_id: String, model: String| {
|
||||
CallerAdmission::new(
|
||||
caller_id,
|
||||
KEY,
|
||||
1,
|
||||
[model],
|
||||
4,
|
||||
64 * 1024,
|
||||
32_768,
|
||||
)
|
||||
CallerAdmission::new(caller_id, KEY, 1, [model], 4, 64 * 1024, 32_768)
|
||||
};
|
||||
let at = "i".repeat(MAX_IDENTITY_BYTES);
|
||||
let over = "i".repeat(MAX_IDENTITY_BYTES + 1);
|
||||
|
|
@ -1298,7 +1286,9 @@ mod tests {
|
|||
let mut service = open_service(&store, 8);
|
||||
let ok = invocation_for(CALLER, &at);
|
||||
assert!(matches!(
|
||||
service.begin_unplanned(&raw_envelope(&ok), 1_000, FRAME).unwrap(),
|
||||
service
|
||||
.begin_unplanned(&raw_envelope(&ok), 1_000, FRAME)
|
||||
.unwrap(),
|
||||
TransportAdmission::Execute(_)
|
||||
));
|
||||
}
|
||||
|
|
@ -1315,8 +1305,9 @@ mod tests {
|
|||
let mut service = open_service(&store, 1);
|
||||
let id = "i".repeat(length);
|
||||
let long = invocation_for(CALLER, &id);
|
||||
let TransportAdmission::Reply(reply) =
|
||||
service.begin_unplanned(&raw_envelope(&long), 1_000, FRAME).unwrap()
|
||||
let TransportAdmission::Reply(reply) = service
|
||||
.begin_unplanned(&raw_envelope(&long), 1_000, FRAME)
|
||||
.unwrap()
|
||||
else {
|
||||
panic!("an over-long id must be refused, not executed ({length})");
|
||||
};
|
||||
|
|
@ -1353,7 +1344,9 @@ mod tests {
|
|||
let store = TestStore::new();
|
||||
let mut service = open_service(&store, 1);
|
||||
assert!(matches!(
|
||||
service.begin_unplanned(&raw_envelope(&long), 1_000, frame_cap).unwrap(),
|
||||
service
|
||||
.begin_unplanned(&raw_envelope(&long), 1_000, frame_cap)
|
||||
.unwrap(),
|
||||
TransportAdmission::Reply(_)
|
||||
));
|
||||
assert_eq!(
|
||||
|
|
@ -1543,7 +1536,9 @@ mod tests {
|
|||
let big = text_result(claim.call(), "y");
|
||||
service.complete(*claim, big, FRAME).unwrap();
|
||||
assert_eq!(
|
||||
service.begin_unplanned(&raw_envelope(&invocation), 1_000, 10).err(),
|
||||
service
|
||||
.begin_unplanned(&raw_envelope(&invocation), 1_000, 10)
|
||||
.err(),
|
||||
Some(ServiceError::FrameBound)
|
||||
);
|
||||
}
|
||||
|
|
@ -1758,25 +1753,15 @@ mod tests {
|
|||
for tag in ["", " ", STAND_IN_PROVIDER] {
|
||||
assert!(
|
||||
matches!(
|
||||
TransportService::open(
|
||||
&store.path,
|
||||
tag,
|
||||
[caller(CALLER, KEY, 1)],
|
||||
5_000
|
||||
),
|
||||
TransportService::open(&store.path, tag, [caller(CALLER, KEY, 1)], 5_000),
|
||||
Err(ServiceError::InvalidAdmission)
|
||||
),
|
||||
"{tag:?}"
|
||||
);
|
||||
}
|
||||
assert!(
|
||||
TransportService::open(
|
||||
&store.path,
|
||||
"fixture-sse",
|
||||
[caller(CALLER, KEY, 1)],
|
||||
5_000
|
||||
)
|
||||
.is_ok()
|
||||
TransportService::open(&store.path, "fixture-sse", [caller(CALLER, KEY, 1)], 5_000)
|
||||
.is_ok()
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -2060,12 +2045,7 @@ mod tests {
|
|||
.unwrap();
|
||||
}
|
||||
assert!(matches!(
|
||||
TransportService::open(
|
||||
&store.path,
|
||||
"fixture-sse",
|
||||
[caller(CALLER, KEY, 1)],
|
||||
5_000
|
||||
),
|
||||
TransportService::open(&store.path, "fixture-sse", [caller(CALLER, KEY, 1)], 5_000),
|
||||
Err(ServiceError::ReplayStore(_))
|
||||
));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -128,16 +128,10 @@ mod tests {
|
|||
TransportService::open(
|
||||
&store.path,
|
||||
"fixture-sse",
|
||||
[CallerAdmission::new(
|
||||
CALLER,
|
||||
KEY,
|
||||
1,
|
||||
["gpt-5.4".to_string()],
|
||||
1,
|
||||
65_536,
|
||||
32_768,
|
||||
)
|
||||
.unwrap()],
|
||||
[
|
||||
CallerAdmission::new(CALLER, KEY, 1, ["gpt-5.4".to_string()], 1, 65_536, 32_768)
|
||||
.unwrap(),
|
||||
],
|
||||
5_000,
|
||||
)
|
||||
.unwrap()
|
||||
|
|
@ -185,7 +179,10 @@ mod tests {
|
|||
fn a_lease_is_named_by_its_invocation() {
|
||||
let store = TestStore::new();
|
||||
let mut service = open(&store);
|
||||
assert_eq!(granted(lease(&mut service, "run-1")).lease_id, "lease:run-1");
|
||||
assert_eq!(
|
||||
granted(lease(&mut service, "run-1")).lease_id,
|
||||
"lease:run-1"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -231,14 +228,28 @@ mod tests {
|
|||
);
|
||||
assert_eq!(
|
||||
service
|
||||
.begin_lease(CALLER, LeaseTurn::SelfRun, "run-2", NOW + 99, NOW + 9, &none())
|
||||
.begin_lease(
|
||||
CALLER,
|
||||
LeaseTurn::SelfRun,
|
||||
"run-2",
|
||||
NOW + 99,
|
||||
NOW + 9,
|
||||
&none()
|
||||
)
|
||||
.unwrap(),
|
||||
LeaseAdmission::Refused(LeaseRefusal::Busy),
|
||||
"one millisecond before its expiry the lease still holds"
|
||||
);
|
||||
granted(
|
||||
service
|
||||
.begin_lease(CALLER, LeaseTurn::SelfRun, "run-2", NOW + 99, NOW + 10, &none())
|
||||
.begin_lease(
|
||||
CALLER,
|
||||
LeaseTurn::SelfRun,
|
||||
"run-2",
|
||||
NOW + 99,
|
||||
NOW + 10,
|
||||
&none(),
|
||||
)
|
||||
.unwrap(),
|
||||
);
|
||||
}
|
||||
|
|
@ -249,7 +260,14 @@ mod tests {
|
|||
let mut service = open(&store);
|
||||
assert_eq!(
|
||||
service
|
||||
.begin_lease("stranger", LeaseTurn::SelfRun, "run-1", NOW + 1, NOW, &none())
|
||||
.begin_lease(
|
||||
"stranger",
|
||||
LeaseTurn::SelfRun,
|
||||
"run-1",
|
||||
NOW + 1,
|
||||
NOW,
|
||||
&none()
|
||||
)
|
||||
.unwrap(),
|
||||
LeaseAdmission::Refused(LeaseRefusal::UnknownCaller)
|
||||
);
|
||||
|
|
@ -286,8 +304,7 @@ mod tests {
|
|||
let call = |service: &mut TransportService, now: u64, plan: &PlanQuotaSnapshot| {
|
||||
let mut asked = request();
|
||||
asked.request_id = format!("call-{now}");
|
||||
let invocation =
|
||||
TransportInvocation::new(CALLER, now + 1_000, [7; 32], asked).unwrap();
|
||||
let invocation = TransportInvocation::new(CALLER, now + 1_000, [7; 32], asked).unwrap();
|
||||
let sealed = crate::envelope::encrypt_message(
|
||||
CALLER,
|
||||
invocation.request_id(),
|
||||
|
|
@ -301,7 +318,8 @@ mod tests {
|
|||
else {
|
||||
return None;
|
||||
};
|
||||
let result = crate::envelope::decrypt_result(&reply, &security(KEY), &invocation).unwrap();
|
||||
let result =
|
||||
crate::envelope::decrypt_result(&reply, &security(KEY), &invocation).unwrap();
|
||||
match result.disposition {
|
||||
TransportDisposition::Refused(refusal) => Some(refusal),
|
||||
other => panic!("unexpected {other:?}"),
|
||||
|
|
@ -361,7 +379,12 @@ mod tests {
|
|||
let store = TestStore::new();
|
||||
let mut service = open(&store);
|
||||
let longest = "r".repeat(MAX_IDENTITY_BYTES - LEASE_PREFIX.len() - PERSONA_SUFFIX.len());
|
||||
let grant = granted(lease_in(&mut service, LeaseTurn::PersonaTurn, &longest, &none()));
|
||||
let grant = granted(lease_in(
|
||||
&mut service,
|
||||
LeaseTurn::PersonaTurn,
|
||||
&longest,
|
||||
&none(),
|
||||
));
|
||||
assert_eq!(grant.lease_id.len(), MAX_IDENTITY_BYTES);
|
||||
assert!(lease_try(&mut service, LeaseTurn::PersonaTurn, &format!("{longest}r")).is_err());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
<EFBFBD>messageIdョgolden-requestゥoperationヲinvokeァpayloadレDhqlzY2hlbWFfaWTZJGdhbWVjdWx0Lm1vZGVsLnRyYW5zcG9ydF9lbnZlbG9wZS52M7FjYWxsZXJfcnVudGltZV9pZK1nb2xkZW4tY2FsbGVyqnJlcXVlc3RfaWSuZ29sZGVuLXJlcXVlc3SsbWVzc2FnZV9raW5kqkludm9jYXRpb26lbm9uY2WczO7MxRrMxw7MhTh7SMzwzNB2qmNpcGhlcnRleHTFA0d65EskLG6kIwJ/G+XDK03gZOGtLFi6vZHJbI+/KpRLwnLT0TPF7RQa0KD98CrW+VwkKY3sRa4+Z9+/5OdPq1YmDFwbxvMVjZsFjXXw84tzvuLKHsb/3kQSEvAlFE4K6FXHvznLcMo4CnGUzoXwNGALf+xDTqFG0aFbdG4xGynV/kttsL6f34F4+l6xiXMUy87Q8/1UyOK/YaVxMMmlT3tdTllhq8YU8Dvfq0KuMaj/f9Anya8A5bJwlxafZPtc53RoH1/oNjLdaDqvwrTEnTB9TvKlnEOxKyyKhmmwGaC03qqPJXRaj8cDQO6EHDbML4J0zMN8TvssQISd5UCeVMkvDGjmvEOmRUoPk1/SnSrIHdha4+6rU4lUSumloLmlx5vv++Mq4AqzOdd/vPB6Ov/AoF32X27o4RI6H3xCKKHjKC4m3+cVjXCrOcGojuRf9yeDFkgbiPaC31hmSc8rAm6HO/NcaIHvx+G+6AaurAEhDLdF6DdrXb4xwjuv6yWQKihNvLXpnwmhRFkSeD5lS6FHW+CoOIdq/RBnFFyDrboTPWFoxQYIrBuqFoHDOajIz7dXYif0sf9sB9JBrDhlcbTpiGcyURfzDhW55NOPqKFGi6ropaJ1/SyLP3f7E57kA22aQ2Op7o36Tu06Pnzo2wI7UsL/Qz27F+AGAukQCvTJyjxARiGr3TRpChjVXx6GXhLrG1T9P+Mrhyrt9vwwhboN8qz1uvDZwKhGWBKXPXkxluq/NY1DwB3JTCCZfEwukWjMZbqiINLEKvW9BStcBR1kfXcK6sQvn/F0g9r81e9brbe+w3U24GERnHwgruOqytTeax/xPbQ7uISV48g5L8DAYf788KhUXwI43QDHNBdBUyo0rCsgoWJKeO05fcAgKgYYGsyLtMW10Vstw3q4POyn3o7rrBz4S2cnl2iZgr0ixg/KgF0V+loEVuj/6rYrcW0SLCHwV1+w1ClFMn0ZPsrz28EoZMA617G0Rrch66cS5uI9/Zf/wLX3z6n7xoPLNXk51ZsLSZ2bqEQkcBJbW/dT5MdH6anWVogRDvIW1coUbkIq9l+pkQSuelWsfakX4UQwYuUD0UwNbqxHiGwlEFj0f1bdhEj26Q==ッpayloadEncodingイmessagepack-base64ュpayloadSchemaル$gamecult.model.transport_envelope.v3ュschemaVersionシcultnet.operation_request.v0ゥserviceIdクgamecult.model.connector
|
||||
<EFBFBD>messageIdョgolden-requestゥoperationヲinvokeァpayloadレ(hqlzY2hlbWFfaWTZJGdhbWVjdWx0Lm1vZGVsLnRyYW5zcG9ydF9lbnZlbG9wZS52NLFjYWxsZXJfcnVudGltZV9pZK1nb2xkZW4tY2FsbGVyqnJlcXVlc3RfaWSuZ29sZGVuLXJlcXVlc3SsbWVzc2FnZV9raW5kqkludm9jYXRpb26lbm9uY2WcXSbMzU3MhsyCzLAtzKLMhcy8zMSqY2lwaGVydGV4dMUDMY816tn0FGQ9jqxE+KyDVcxmhufaQI7vzEXO8NXTQPOYpRuMcRDM/j/QzNF2Lb3Fak0G+hHRKrXDxJ3MeKpoELNYOEyxbKfxn88mjAyyc7BVPM7+0Bk9ye3m5oBF6hoyCgOHSTwESIfq0bim+9oQh1IDp+HdFjztK/XjM731GRzKJmGgxsKqQsz42zq8y9mjAXl3V1RR9ssdKvk2k5U56/3liOeHDU96kOa7IlVCBm6qnn06hg2DTtnBF4xGj6PihHj4KufVkAcuQhRCZWOKsploToXo7wy+jcQDrnhHIUCMN6sk3P9YJh1ejuleDM9rp3RYiXcnzRwMNXK1AGpNraTgWn91d6L/1Ff+gaQBgPxSjW6FATshJf9Iqk9pEhT8xeCQMmNj40CdlVFYNz/TsRJYW45BXm8g83Jnh3Wj0Z90WJ80bwwgZbjPWx6wCOCID6Jo8wiubF6411ygi+GUHTR9rZFhrsGo6TSmsbvIAuabUJcskqKHW7tqVkfpz5JdjyeSSDvKcZ3PQyVne7Lyo8nzNh0g06a7CEUvq9kvr4zfTCfwk/1YVSrZ+7U8ePGj27V3D8+BH/pafiLR5FxxBKWBTYe7n5irVP5gLw4WlzOrSriXpolmaPWujCm3apml45mhlYARdfJJbpQxnQGb6cI3D/vAxxI50BPLB82JqCjNFex9xwfP5jSRDYah9wLm4yVymBqZ8Wvn0maLz4OvF2EonJBwEtN73UBULkdeX6g9GTiu2MKtCjSMm33SkwiHfvDdwMDS11sINK+YQLF/3HobbnAk2n963JahlddNRg79T96GksjN0br8u1PNMC+/uBUHEQvUBfRnR4tKp+SeLF6zMn228orgHgWr7sxilMwTOP1DgXpbEE19M0P8XC0CA/pTeHr4eFHzakPLotxF8avQfPKAXbXWgNGK6uWj1NGPshD6EN3pLvePOc4uObqHMKz/dg52/7m1VTHhYMivSRenG6H/BrWfUXQvcgCPalg7C4KCPYINb3nnRxP0NIOBP+KJ4S2haU94ZNHVr2HB038xNzUm2HrONVBsxuuTckYDmHfCa6FmvVJv4she5wyuPHk=ッpayloadEncodingイmessagepack-base64ュpayloadSchemaル$gamecult.model.transport_envelope.v4ュschemaVersionシcultnet.operation_request.v0ゥserviceIdクgamecult.model.connector
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -1 +1 @@
|
|||
„©schema_idÙ"gamecult.model.transport_result.v3ªrequest_id®golden-request±caller_runtime_idgolden-caller«disposition<6F>§Refused«OutputBound
|
||||
„©schema_idÙ"gamecult.model.transport_result.v4ªrequest_id®golden-request±caller_runtime_idgolden-caller«disposition<6F>§Refused«OutputBound
|
||||
Binary file not shown.
|
|
@ -11,12 +11,6 @@
|
|||
"format": "uint64",
|
||||
"minimum": 0
|
||||
},
|
||||
"max_cost_micro_usd": {
|
||||
"description": "The most this request may cost, in micro-USD: the caller's own bound\non it. Required nonzero. It is part of the invocation's identity, so a\nchanged budget under a recorded request id is a `ReplayConflict`.",
|
||||
"type": "integer",
|
||||
"format": "uint64",
|
||||
"minimum": 0
|
||||
},
|
||||
"native_request_sha256": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
|
|
@ -53,7 +47,6 @@
|
|||
"expires_at_unix_ms",
|
||||
"native_request_sha256",
|
||||
"provider_request_sha256",
|
||||
"max_cost_micro_usd",
|
||||
"request"
|
||||
],
|
||||
"$defs": {
|
||||
|
|
|
|||
|
|
@ -6,12 +6,6 @@
|
|||
"caller_runtime_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"cost_micro_usd": {
|
||||
"description": "What the request cost, in micro-USD. The service derives it from the\noutcome's usage and its price table; a backend never writes it.",
|
||||
"type": "integer",
|
||||
"format": "uint64",
|
||||
"minimum": 0
|
||||
},
|
||||
"foreign_reasoning_dropped": {
|
||||
"description": "How many foreign `ReasoningState` items the service removed from the\nrequest before the backend saw it.",
|
||||
"type": "integer",
|
||||
|
|
@ -35,12 +29,6 @@
|
|||
"outcome": {
|
||||
"$ref": "#/$defs/TransportOutcome"
|
||||
},
|
||||
"overrun_micro_usd": {
|
||||
"description": "How far `cost_micro_usd` exceeds what the service reserved for the\nrequest: zero unless the backend reported usage above the worst case\nthe request allowed, which is a breach of the backend's contract. The\ncost is still the true one and the caller's window is charged all of\nit. The service derives this; a backend never writes it.",
|
||||
"type": "integer",
|
||||
"format": "uint64",
|
||||
"minimum": 0
|
||||
},
|
||||
"provider": {
|
||||
"type": "string"
|
||||
},
|
||||
|
|
@ -72,8 +60,6 @@
|
|||
"model",
|
||||
"provider",
|
||||
"foreign_reasoning_dropped",
|
||||
"cost_micro_usd",
|
||||
"overrun_micro_usd",
|
||||
"outcome"
|
||||
],
|
||||
"$defs": {
|
||||
|
|
@ -174,7 +160,7 @@
|
|||
]
|
||||
},
|
||||
"Usage": {
|
||||
"description": "Token accounting for one request, as the backend reports it; the service\nprices it. Cache reads and writes are counted apart from plain input.\n`output_tokens` includes reasoning tokens: `reasoning_tokens` is a detail\n(absent when the provider does not report it) and is never priced apart.",
|
||||
"description": "Token accounting for one request, as the backend reports it. Cache reads\nand writes are counted apart from plain input.\n`output_tokens` includes reasoning tokens: `reasoning_tokens` is a detail\n(absent when the provider does not report it) and is never counted apart.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"cache_read_tokens": {
|
||||
|
|
|
|||
|
|
@ -46,15 +46,13 @@
|
|||
"ModelNotAllowed",
|
||||
"OutputBound",
|
||||
"PayloadBound",
|
||||
"CostBound",
|
||||
"SpendCeiling",
|
||||
"Capacity",
|
||||
"InFlight",
|
||||
"Indeterminate",
|
||||
"ReplayConflict",
|
||||
"Malformed",
|
||||
"ForeignReasoningState",
|
||||
"ClockBehindAdmissionWindow"
|
||||
"ProviderRejected"
|
||||
]
|
||||
},
|
||||
"StopReason": {
|
||||
|
|
@ -286,12 +284,6 @@
|
|||
"caller_runtime_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"cost_micro_usd": {
|
||||
"description": "What the request cost, in micro-USD. The service derives it from the\noutcome's usage and its price table; a backend never writes it.",
|
||||
"type": "integer",
|
||||
"format": "uint64",
|
||||
"minimum": 0
|
||||
},
|
||||
"foreign_reasoning_dropped": {
|
||||
"description": "How many foreign `ReasoningState` items the service removed from the\nrequest before the backend saw it.",
|
||||
"type": "integer",
|
||||
|
|
@ -315,12 +307,6 @@
|
|||
"outcome": {
|
||||
"$ref": "#/$defs/TransportOutcome"
|
||||
},
|
||||
"overrun_micro_usd": {
|
||||
"description": "How far `cost_micro_usd` exceeds what the service reserved for the\nrequest: zero unless the backend reported usage above the worst case\nthe request allowed, which is a breach of the backend's contract. The\ncost is still the true one and the caller's window is charged all of\nit. The service derives this; a backend never writes it.",
|
||||
"type": "integer",
|
||||
"format": "uint64",
|
||||
"minimum": 0
|
||||
},
|
||||
"provider": {
|
||||
"type": "string"
|
||||
},
|
||||
|
|
@ -352,13 +338,11 @@
|
|||
"model",
|
||||
"provider",
|
||||
"foreign_reasoning_dropped",
|
||||
"cost_micro_usd",
|
||||
"overrun_micro_usd",
|
||||
"outcome"
|
||||
]
|
||||
},
|
||||
"Usage": {
|
||||
"description": "Token accounting for one request, as the backend reports it; the service\nprices it. Cache reads and writes are counted apart from plain input.\n`output_tokens` includes reasoning tokens: `reasoning_tokens` is a detail\n(absent when the provider does not report it) and is never priced apart.",
|
||||
"description": "Token accounting for one request, as the backend reports it. Cache reads\nand writes are counted apart from plain input.\n`output_tokens` includes reasoning tokens: `reasoning_tokens` is a detail\n(absent when the provider does not report it) and is never counted apart.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"cache_read_tokens": {
|
||||
|
|
|
|||
68
schemas/usage_readout.json
Normal file
68
schemas/usage_readout.json
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"title": "UsageReadout",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"at_unix_ms": {
|
||||
"type": "integer",
|
||||
"format": "uint64",
|
||||
"minimum": 0
|
||||
},
|
||||
"plan_quota": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/PlanQuota"
|
||||
}
|
||||
},
|
||||
"schema_id": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"schema_id",
|
||||
"at_unix_ms",
|
||||
"plan_quota"
|
||||
],
|
||||
"$defs": {
|
||||
"PlanQuota": {
|
||||
"description": "One window of the subscription plan, as the provider reported it.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"observed_at_unix_ms": {
|
||||
"description": "When this window was last reported. Its age in a readout is the\nreadout's `at_unix_ms` minus this.",
|
||||
"type": "integer",
|
||||
"format": "uint64",
|
||||
"minimum": 0
|
||||
},
|
||||
"resets_at_unix_ms": {
|
||||
"type": "integer",
|
||||
"format": "uint64",
|
||||
"minimum": 0
|
||||
},
|
||||
"status": {
|
||||
"type": "string"
|
||||
},
|
||||
"utilization_permille": {
|
||||
"description": "How much of the window was used when it was observed, in thousandths;\n`None` once the window has reset (`status` is then `expired`), because\nthe old reading says nothing about the new window.",
|
||||
"type": [
|
||||
"integer",
|
||||
"null"
|
||||
],
|
||||
"format": "uint32",
|
||||
"minimum": 0
|
||||
},
|
||||
"window": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"window",
|
||||
"resets_at_unix_ms",
|
||||
"status",
|
||||
"observed_at_unix_ms"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue