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",
|
"libc",
|
||||||
"model-connector",
|
"model-connector",
|
||||||
"rmp-serde",
|
"rmp-serde",
|
||||||
|
"rmpv",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"sha2",
|
"sha2",
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,9 @@ use std::sync::{Arc, Mutex};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use model_connector::{
|
use model_connector::{
|
||||||
CallerAdmission, PlanQuotaSnapshot, ReasoningEffort, StopReason, ToolDefinition, TransportAdmission, TransportDisposition, TransportInvocation,
|
CallerAdmission, PlanQuotaSnapshot, ReasoningEffort, StopReason, ToolDefinition,
|
||||||
TransportKey, TransportReceipt, TransportService, decrypt_result, encrypt_invocation,
|
TransportAdmission, TransportDisposition, TransportInvocation, TransportKey, TransportReceipt,
|
||||||
|
TransportService, decrypt_result, encrypt_invocation,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
@ -480,8 +481,7 @@ impl Door {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
});
|
});
|
||||||
let service =
|
let service =
|
||||||
TransportService::open(&dir.join("replay.cc"), PROVIDER, callers, 5_000)
|
TransportService::open(&dir.join("replay.cc"), PROVIDER, callers, 5_000).unwrap();
|
||||||
.unwrap();
|
|
||||||
Self { dir, service }
|
Self { dir, service }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -498,13 +498,13 @@ impl Door {
|
||||||
request: ProviderRequest,
|
request: ProviderRequest,
|
||||||
) -> (model_connector::ExecutionClaim, TransportInvocation) {
|
) -> (model_connector::ExecutionClaim, TransportInvocation) {
|
||||||
let key = TransportKey::from_connection_secret(&format!("{caller}-key")).unwrap();
|
let key = TransportKey::from_connection_secret(&format!("{caller}-key")).unwrap();
|
||||||
let invocation =
|
let invocation = TransportInvocation::new(caller, 2_000, [7; 32], request).unwrap();
|
||||||
TransportInvocation::new(caller, 2_000, [7; 32], request).unwrap();
|
|
||||||
let envelope = encrypt_invocation(&invocation, &key).unwrap();
|
let envelope = encrypt_invocation(&invocation, &key).unwrap();
|
||||||
match self
|
match self
|
||||||
.service
|
.service
|
||||||
.begin(&envelope, 1_000, &PlanQuotaSnapshot::default(), FRAME)
|
.begin(&envelope, 1_000, &PlanQuotaSnapshot::default(), FRAME)
|
||||||
.unwrap() {
|
.unwrap()
|
||||||
|
{
|
||||||
TransportAdmission::Execute(claim) => (*claim, invocation),
|
TransportAdmission::Execute(claim) => (*claim, invocation),
|
||||||
TransportAdmission::Reply(_) => panic!("the door answered instead of admitting"),
|
TransportAdmission::Reply(_) => panic!("the door answered instead of admitting"),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,8 @@ use std::time::Duration;
|
||||||
|
|
||||||
use cultcache_rs::{CultCache, DatabaseEntry, SingleFileMessagePackBackingStore};
|
use cultcache_rs::{CultCache, DatabaseEntry, SingleFileMessagePackBackingStore};
|
||||||
use model_connector::{
|
use model_connector::{
|
||||||
CallerAdmission, CallerConfig, LeaseTurn, MIN_PAYLOAD_BYTES, ProviderBackend,
|
CallerAdmission, CallerConfig, LeaseTurn, MIN_PAYLOAD_BYTES, ProviderBackend, ServeError,
|
||||||
ServeError, ServeLimits, ServiceError, TransportService, load_admissions, serve_service,
|
ServeLimits, ServiceError, TransportService, load_admissions, serve_service,
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
@ -230,9 +230,7 @@ impl ClaudeConnectorConfig {
|
||||||
}
|
}
|
||||||
let mut seen = BTreeSet::new();
|
let mut seen = BTreeSet::new();
|
||||||
for model in &caller.allowed_models {
|
for model in &caller.allowed_models {
|
||||||
if !has_model_id_form(model)
|
if !has_model_id_form(model) || !seen.insert(model.as_str()) {
|
||||||
|| !seen.insert(model.as_str())
|
|
||||||
{
|
|
||||||
return Err(ConfigError::Invalid("allowed_models"));
|
return Err(ConfigError::Invalid("allowed_models"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -344,7 +342,6 @@ fn has_model_id_form(model: &str) -> bool {
|
||||||
&& after_ok
|
&& after_ok
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// One file name under `$CREDENTIALS_DIRECTORY`, never a path.
|
/// One file name under `$CREDENTIALS_DIRECTORY`, never a path.
|
||||||
fn is_credential_name(name: &str) -> bool {
|
fn is_credential_name(name: &str) -> bool {
|
||||||
!name.is_empty()
|
!name.is_empty()
|
||||||
|
|
|
||||||
|
|
@ -671,9 +671,9 @@ mod tests {
|
||||||
fn a_frame_that_trickles_past_its_deadline_is_refused_however_small_each_read() {
|
fn a_frame_that_trickles_past_its_deadline_is_refused_however_small_each_read() {
|
||||||
let (mut reader, mut writer) = UnixStream::pair().unwrap();
|
let (mut reader, mut writer) = UnixStream::pair().unwrap();
|
||||||
let frame = encode_frame(&LeaseMessage::ClaudeLeaseRefusal(LeaseRefused {
|
let frame = encode_frame(&LeaseMessage::ClaudeLeaseRefusal(LeaseRefused {
|
||||||
kind: LeaseRefusalKind::Busy,
|
kind: LeaseRefusalKind::Busy,
|
||||||
detail: "lease:x".to_string(),
|
detail: "lease:x".to_string(),
|
||||||
}));
|
}));
|
||||||
let trickle = thread::spawn(move || {
|
let trickle = thread::spawn(move || {
|
||||||
for byte in frame {
|
for byte in frame {
|
||||||
if writer.write_all(&[byte]).is_err() {
|
if writer.write_all(&[byte]).is_err() {
|
||||||
|
|
|
||||||
|
|
@ -28,8 +28,8 @@ pub use launch::ChildEnv;
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
pub use lease::{
|
pub use lease::{
|
||||||
LeaseCaller, LeaseGranted, LeaseLimits, LeaseMessage, LeaseRefusalKind, LeaseRefused,
|
LeaseCaller, LeaseGranted, LeaseLimits, LeaseMessage, LeaseRefusalKind, LeaseRefused,
|
||||||
LeaseRequest, MAX_LEASE_FRAME_BYTES, PeerCredentials, PeerUnit,
|
LeaseRequest, MAX_LEASE_FRAME_BYTES, PeerCredentials, PeerUnit, PeerUnits, decode_frame,
|
||||||
PeerUnits, decode_frame, encode_frame, peer_credentials, serve_leases, user_uid,
|
encode_frame, peer_credentials, serve_leases, user_uid,
|
||||||
};
|
};
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
pub use process::StdProcessPort;
|
pub use process::StdProcessPort;
|
||||||
|
|
|
||||||
|
|
@ -280,6 +280,9 @@ fn the_dollar_flags_are_not_flags() {
|
||||||
let scratch = Scratch::new();
|
let scratch = Scratch::new();
|
||||||
let made = init(&scratch, &init_flags(&scratch, extra));
|
let made = init(&scratch, &init_flags(&scratch, extra));
|
||||||
assert!(!made.status.success(), "{extra:?} was accepted");
|
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 quota = Arc::new(QuotaCell::new());
|
||||||
let listener = UnixListener::bind(&socket).unwrap();
|
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 {
|
let caller = LeaseCaller {
|
||||||
uid: setup.uid,
|
uid: setup.uid,
|
||||||
caller_id: CALLER.to_string(),
|
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() {
|
fn a_grant_passes_one_fd_holding_the_token_then_end_of_file() {
|
||||||
let harness = start(setup());
|
let harness = start(setup());
|
||||||
let mut answer = ask(&harness, 60_000);
|
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);
|
assert_eq!(answer.fds.len(), 1);
|
||||||
let mut read = Vec::new();
|
let mut read = Vec::new();
|
||||||
File::from(answer.fds.remove(0))
|
File::from(answer.fds.remove(0))
|
||||||
|
|
@ -351,7 +359,10 @@ fn a_grant_passes_one_fd_holding_the_token_then_end_of_file() {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(read, TOKEN.as_bytes());
|
assert_eq!(read, TOKEN.as_bytes());
|
||||||
assert_eq!(harness.tokens.reads.load(Ordering::SeqCst), 1);
|
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]
|
#[test]
|
||||||
|
|
@ -416,7 +427,10 @@ fn a_rejected_window_refuses_the_lease_until_its_reset() {
|
||||||
.quota
|
.quota
|
||||||
.observe([window("five_hour", 1_000, "rejected", reset)]);
|
.observe([window("five_hour", 1_000, "rejected", reset)]);
|
||||||
let refused = ask(&harness, 60_000);
|
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!(refused.fds.is_empty());
|
||||||
assert_eq!(harness.tokens.reads.load(Ordering::SeqCst), 0);
|
assert_eq!(harness.tokens.reads.load(Ordering::SeqCst), 0);
|
||||||
// At the provider's own reset the refusal lifts, with no one lifting it.
|
// At the provider's own reset the refusal lifts, with no one lifting it.
|
||||||
|
|
|
||||||
|
|
@ -762,8 +762,15 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn the_invocations_identity_covers_its_request() {
|
fn the_invocations_identity_covers_its_request() {
|
||||||
let one = invocation();
|
let one = invocation();
|
||||||
let mut other = one.clone();
|
let mut request = one.request.clone();
|
||||||
other.request.max_output_tokens += 1;
|
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!(
|
assert_ne!(
|
||||||
canonical_invocation_bytes(&one).unwrap(),
|
canonical_invocation_bytes(&one).unwrap(),
|
||||||
canonical_invocation_bytes(&other).unwrap()
|
canonical_invocation_bytes(&other).unwrap()
|
||||||
|
|
|
||||||
|
|
@ -67,14 +67,6 @@ impl FlakyStore {
|
||||||
pub(crate) fn allowance(&self) -> Arc<AtomicUsize> {
|
pub(crate) fn allowance(&self) -> Arc<AtomicUsize> {
|
||||||
self.pushes_allowed.clone()
|
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")]
|
#[cfg(feature = "daemon")]
|
||||||
|
|
@ -133,7 +125,6 @@ pub(crate) fn request() -> ProviderRequest {
|
||||||
request
|
request
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub(crate) fn invocation() -> TransportInvocation {
|
pub(crate) fn invocation() -> TransportInvocation {
|
||||||
TransportInvocation::new("epiphany-yggdrasil", 2_000, [7; 32], request()).unwrap()
|
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";
|
pub const USAGE_READOUT_SCHEMA_ID: &str = "gamecult.model.usage_readout.v1";
|
||||||
|
|
||||||
|
|
||||||
/// One window of the subscription plan, as the provider reported it.
|
/// One window of the subscription plan, as the provider reported it.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
|
|
|
||||||
|
|
@ -382,10 +382,7 @@ mod tests {
|
||||||
FailureKind, Refusal, TransportDisposition, TransportEvent, TransportEventPayload,
|
FailureKind, Refusal, TransportDisposition, TransportEvent, TransportEventPayload,
|
||||||
TransportInvocation, TransportOutcome, TransportResult,
|
TransportInvocation, TransportOutcome, TransportResult,
|
||||||
};
|
};
|
||||||
use crate::fixtures::{
|
use crate::fixtures::{TestStore, caller, invocation_for, receipt, request};
|
||||||
TestStore, caller, invocation_for, receipt,
|
|
||||||
request,
|
|
||||||
};
|
|
||||||
|
|
||||||
const CALLER: &str = "epiphany-yggdrasil";
|
const CALLER: &str = "epiphany-yggdrasil";
|
||||||
const KEY: &str = "epiphany-distinct-test-key";
|
const KEY: &str = "epiphany-distinct-test-key";
|
||||||
|
|
@ -461,13 +458,7 @@ mod tests {
|
||||||
let (sender, receiver) = std::sync::mpsc::channel();
|
let (sender, receiver) = std::sync::mpsc::channel();
|
||||||
let path = path.to_path_buf();
|
let path = path.to_path_buf();
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
let _ = sender.send(serve(
|
let _ = sender.send(serve(listener, limits, admissions, &path, backend));
|
||||||
listener,
|
|
||||||
limits,
|
|
||||||
admissions,
|
|
||||||
&path,
|
|
||||||
backend,
|
|
||||||
));
|
|
||||||
});
|
});
|
||||||
receiver.recv_timeout(Duration::from_secs(2)).ok()
|
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 listener = TcpListener::bind("127.0.0.1:0").unwrap();
|
||||||
let endpoint = listener.local_addr().unwrap();
|
let endpoint = listener.local_addr().unwrap();
|
||||||
let path = store.path.clone();
|
let path = store.path.clone();
|
||||||
thread::spawn(move || {
|
thread::spawn(move || serve(listener, limits(), admissions, &path, backend));
|
||||||
serve(
|
|
||||||
listener,
|
|
||||||
limits(),
|
|
||||||
admissions,
|
|
||||||
&path,
|
|
||||||
backend,
|
|
||||||
)
|
|
||||||
});
|
|
||||||
let client =
|
let client =
|
||||||
ConnectorClient::new(endpoint, KEY, FRAME, Some(Duration::from_secs(5))).unwrap();
|
ConnectorClient::new(endpoint, KEY, FRAME, Some(Duration::from_secs(5))).unwrap();
|
||||||
(client, endpoint)
|
(client, endpoint)
|
||||||
|
|
@ -770,10 +753,9 @@ mod tests {
|
||||||
let envelope =
|
let envelope =
|
||||||
crate::envelope::encrypt_invocation(&invocation, &crate::fixtures::security(KEY))
|
crate::envelope::encrypt_invocation(&invocation, &crate::fixtures::security(KEY))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let TransportAdmission::Execute(claim) =
|
let TransportAdmission::Execute(claim) = service
|
||||||
service
|
.begin(&envelope, now_ms(), &PlanQuotaSnapshot::default(), 1 << 20)
|
||||||
.begin(&envelope, now_ms(), &PlanQuotaSnapshot::default(), 1 << 20)
|
.unwrap()
|
||||||
.unwrap()
|
|
||||||
else {
|
else {
|
||||||
panic!("a fresh request must execute");
|
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() {
|
fn the_smallest_frame_also_carries_the_failure_that_stands_in_for_a_result() {
|
||||||
let long = "x".repeat(crate::envelope::MAX_IDENTITY_BYTES);
|
let long = "x".repeat(crate::envelope::MAX_IDENTITY_BYTES);
|
||||||
let plaintext = crate::contract::wire_encode(&crate::service::result_size_failure(
|
let plaintext = crate::contract::wire_encode(&crate::service::result_size_failure(
|
||||||
&long,
|
&long, &long, &long, [0xff; 32], [0xff; 32], 0,
|
||||||
&long,
|
|
||||||
&long,
|
|
||||||
[0xff; 32],
|
|
||||||
[0xff; 32],
|
|
||||||
0,
|
|
||||||
))
|
))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.len();
|
.len();
|
||||||
|
|
@ -994,16 +971,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn admission(id: &str, key: &str, slots: usize, payload: usize) -> CallerAdmission {
|
fn admission(id: &str, key: &str, slots: usize, payload: usize) -> CallerAdmission {
|
||||||
CallerAdmission::new(
|
CallerAdmission::new(id, key, 1, ["gpt-5.4".to_string()], slots, payload, 32_768).unwrap()
|
||||||
id,
|
|
||||||
key,
|
|
||||||
1,
|
|
||||||
["gpt-5.4".to_string()],
|
|
||||||
slots,
|
|
||||||
payload,
|
|
||||||
32_768,
|
|
||||||
)
|
|
||||||
.unwrap()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `Some(field)` when serve refused the configuration, `None` while it serves.
|
/// `Some(field)` when serve refused the configuration, `None` while it serves.
|
||||||
|
|
@ -1233,10 +1201,9 @@ mod tests {
|
||||||
&crate::fixtures::security(KEY),
|
&crate::fixtures::security(KEY),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let TransportAdmission::Execute(claim) =
|
let TransportAdmission::Execute(claim) = service
|
||||||
service
|
.begin(&envelope, now_ms(), &PlanQuotaSnapshot::default(), 1 << 20)
|
||||||
.begin(&envelope, now_ms(), &PlanQuotaSnapshot::default(), 1 << 20)
|
.unwrap()
|
||||||
.unwrap()
|
|
||||||
else {
|
else {
|
||||||
panic!("a fresh request must execute");
|
panic!("a fresh request must execute");
|
||||||
};
|
};
|
||||||
|
|
@ -1385,15 +1352,7 @@ mod tests {
|
||||||
let backend = CountingBackend::new(true);
|
let backend = CountingBackend::new(true);
|
||||||
let path = store.path.clone();
|
let path = store.path.clone();
|
||||||
let served = backend.clone();
|
let served = backend.clone();
|
||||||
thread::spawn(move || {
|
thread::spawn(move || serve(listener, limits(), admissions, &path, served));
|
||||||
serve(
|
|
||||||
listener,
|
|
||||||
limits(),
|
|
||||||
admissions,
|
|
||||||
&path,
|
|
||||||
served,
|
|
||||||
)
|
|
||||||
});
|
|
||||||
let client =
|
let client =
|
||||||
ConnectorClient::new(endpoint, KEY, FRAME, Some(Duration::from_secs(5))).unwrap();
|
ConnectorClient::new(endpoint, KEY, FRAME, Some(Duration::from_secs(5))).unwrap();
|
||||||
client.execute(&fresh("request-key")).unwrap();
|
client.execute(&fresh("request-key")).unwrap();
|
||||||
|
|
|
||||||
|
|
@ -524,7 +524,8 @@ impl TransportService {
|
||||||
.get::<ReplayRecord>(&replay_key(&identity))
|
.get::<ReplayRecord>(&replay_key(&identity))
|
||||||
.map_err(replay_store_error)?
|
.map_err(replay_store_error)?
|
||||||
.ok_or(ServiceError::NoActiveRequest)?;
|
.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);
|
return Err(ServiceError::ActiveRequestMismatch);
|
||||||
}
|
}
|
||||||
|
|
@ -897,13 +898,9 @@ mod tests {
|
||||||
|
|
||||||
let mut changed_request = request();
|
let mut changed_request = request();
|
||||||
changed_request.instructions.push_str(" Different cargo.");
|
changed_request.instructions.push_str(" Different cargo.");
|
||||||
let conflicting = TransportInvocation::new(
|
let conflicting =
|
||||||
"epiphany-yggdrasil",
|
TransportInvocation::new("epiphany-yggdrasil", 2_000, [7; 32], changed_request)
|
||||||
2_000,
|
.unwrap();
|
||||||
[7; 32],
|
|
||||||
changed_request,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
let refusal = match service
|
let refusal = match service
|
||||||
.begin_unplanned(
|
.begin_unplanned(
|
||||||
&encrypt_invocation(&conflicting, &security).unwrap(),
|
&encrypt_invocation(&conflicting, &security).unwrap(),
|
||||||
|
|
@ -932,7 +929,9 @@ mod tests {
|
||||||
let mut service = open_service(&store, 1);
|
let mut service = open_service(&store, 1);
|
||||||
let first_envelope = encrypt_invocation(&first, &security).unwrap();
|
let first_envelope = encrypt_invocation(&first, &security).unwrap();
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
service.begin_unplanned(&first_envelope, 1_000, FRAME).unwrap(),
|
service
|
||||||
|
.begin_unplanned(&first_envelope, 1_000, FRAME)
|
||||||
|
.unwrap(),
|
||||||
TransportAdmission::Execute(_)
|
TransportAdmission::Execute(_)
|
||||||
));
|
));
|
||||||
|
|
||||||
|
|
@ -1035,10 +1034,12 @@ mod tests {
|
||||||
) -> (TransportAdmission, TransportInvocation) {
|
) -> (TransportAdmission, TransportInvocation) {
|
||||||
let mut request = invocation_for(CALLER, request_id).request;
|
let mut request = invocation_for(CALLER, request_id).request;
|
||||||
edit(&mut request);
|
edit(&mut request);
|
||||||
let invocation =
|
let invocation = TransportInvocation::new(CALLER, 2_000, [7; 32], request).unwrap();
|
||||||
TransportInvocation::new(CALLER, 2_000, [7; 32], request).unwrap();
|
|
||||||
let envelope = encrypt_invocation(&invocation, &security(KEY)).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 {
|
fn refusal_of(admission: TransportAdmission, invocation: &TransportInvocation) -> Refusal {
|
||||||
|
|
@ -1118,14 +1119,9 @@ mod tests {
|
||||||
32_768,
|
32_768,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
TransportService::open(
|
TransportService::open(&store.path, "fixture-sse", [admission], 5_000)
|
||||||
&store.path,
|
.unwrap()
|
||||||
"fixture-sse",
|
.begin_unplanned(&envelope, 1_000, FRAME)
|
||||||
[admission],
|
|
||||||
5_000,
|
|
||||||
)
|
|
||||||
.unwrap()
|
|
||||||
.begin_unplanned(&envelope, 1_000, FRAME)
|
|
||||||
};
|
};
|
||||||
assert!(matches!(admit(size), Ok(TransportAdmission::Execute(_))));
|
assert!(matches!(admit(size), Ok(TransportAdmission::Execute(_))));
|
||||||
let refused = admit(size - 1).unwrap();
|
let refused = admit(size - 1).unwrap();
|
||||||
|
|
@ -1272,15 +1268,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn identities_are_bounded_at_admission_and_on_the_request() {
|
fn identities_are_bounded_at_admission_and_on_the_request() {
|
||||||
let admit = |caller_id: String, model: String| {
|
let admit = |caller_id: String, model: String| {
|
||||||
CallerAdmission::new(
|
CallerAdmission::new(caller_id, KEY, 1, [model], 4, 64 * 1024, 32_768)
|
||||||
caller_id,
|
|
||||||
KEY,
|
|
||||||
1,
|
|
||||||
[model],
|
|
||||||
4,
|
|
||||||
64 * 1024,
|
|
||||||
32_768,
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
let at = "i".repeat(MAX_IDENTITY_BYTES);
|
let at = "i".repeat(MAX_IDENTITY_BYTES);
|
||||||
let over = "i".repeat(MAX_IDENTITY_BYTES + 1);
|
let over = "i".repeat(MAX_IDENTITY_BYTES + 1);
|
||||||
|
|
@ -1298,7 +1286,9 @@ mod tests {
|
||||||
let mut service = open_service(&store, 8);
|
let mut service = open_service(&store, 8);
|
||||||
let ok = invocation_for(CALLER, &at);
|
let ok = invocation_for(CALLER, &at);
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
service.begin_unplanned(&raw_envelope(&ok), 1_000, FRAME).unwrap(),
|
service
|
||||||
|
.begin_unplanned(&raw_envelope(&ok), 1_000, FRAME)
|
||||||
|
.unwrap(),
|
||||||
TransportAdmission::Execute(_)
|
TransportAdmission::Execute(_)
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
@ -1315,8 +1305,9 @@ mod tests {
|
||||||
let mut service = open_service(&store, 1);
|
let mut service = open_service(&store, 1);
|
||||||
let id = "i".repeat(length);
|
let id = "i".repeat(length);
|
||||||
let long = invocation_for(CALLER, &id);
|
let long = invocation_for(CALLER, &id);
|
||||||
let TransportAdmission::Reply(reply) =
|
let TransportAdmission::Reply(reply) = service
|
||||||
service.begin_unplanned(&raw_envelope(&long), 1_000, FRAME).unwrap()
|
.begin_unplanned(&raw_envelope(&long), 1_000, FRAME)
|
||||||
|
.unwrap()
|
||||||
else {
|
else {
|
||||||
panic!("an over-long id must be refused, not executed ({length})");
|
panic!("an over-long id must be refused, not executed ({length})");
|
||||||
};
|
};
|
||||||
|
|
@ -1353,7 +1344,9 @@ mod tests {
|
||||||
let store = TestStore::new();
|
let store = TestStore::new();
|
||||||
let mut service = open_service(&store, 1);
|
let mut service = open_service(&store, 1);
|
||||||
assert!(matches!(
|
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(_)
|
TransportAdmission::Reply(_)
|
||||||
));
|
));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|
@ -1543,7 +1536,9 @@ mod tests {
|
||||||
let big = text_result(claim.call(), "y");
|
let big = text_result(claim.call(), "y");
|
||||||
service.complete(*claim, big, FRAME).unwrap();
|
service.complete(*claim, big, FRAME).unwrap();
|
||||||
assert_eq!(
|
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)
|
Some(ServiceError::FrameBound)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -1758,25 +1753,15 @@ mod tests {
|
||||||
for tag in ["", " ", STAND_IN_PROVIDER] {
|
for tag in ["", " ", STAND_IN_PROVIDER] {
|
||||||
assert!(
|
assert!(
|
||||||
matches!(
|
matches!(
|
||||||
TransportService::open(
|
TransportService::open(&store.path, tag, [caller(CALLER, KEY, 1)], 5_000),
|
||||||
&store.path,
|
|
||||||
tag,
|
|
||||||
[caller(CALLER, KEY, 1)],
|
|
||||||
5_000
|
|
||||||
),
|
|
||||||
Err(ServiceError::InvalidAdmission)
|
Err(ServiceError::InvalidAdmission)
|
||||||
),
|
),
|
||||||
"{tag:?}"
|
"{tag:?}"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
assert!(
|
assert!(
|
||||||
TransportService::open(
|
TransportService::open(&store.path, "fixture-sse", [caller(CALLER, KEY, 1)], 5_000)
|
||||||
&store.path,
|
.is_ok()
|
||||||
"fixture-sse",
|
|
||||||
[caller(CALLER, KEY, 1)],
|
|
||||||
5_000
|
|
||||||
)
|
|
||||||
.is_ok()
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2060,12 +2045,7 @@ mod tests {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
TransportService::open(
|
TransportService::open(&store.path, "fixture-sse", [caller(CALLER, KEY, 1)], 5_000),
|
||||||
&store.path,
|
|
||||||
"fixture-sse",
|
|
||||||
[caller(CALLER, KEY, 1)],
|
|
||||||
5_000
|
|
||||||
),
|
|
||||||
Err(ServiceError::ReplayStore(_))
|
Err(ServiceError::ReplayStore(_))
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -128,16 +128,10 @@ mod tests {
|
||||||
TransportService::open(
|
TransportService::open(
|
||||||
&store.path,
|
&store.path,
|
||||||
"fixture-sse",
|
"fixture-sse",
|
||||||
[CallerAdmission::new(
|
[
|
||||||
CALLER,
|
CallerAdmission::new(CALLER, KEY, 1, ["gpt-5.4".to_string()], 1, 65_536, 32_768)
|
||||||
KEY,
|
.unwrap(),
|
||||||
1,
|
],
|
||||||
["gpt-5.4".to_string()],
|
|
||||||
1,
|
|
||||||
65_536,
|
|
||||||
32_768,
|
|
||||||
)
|
|
||||||
.unwrap()],
|
|
||||||
5_000,
|
5_000,
|
||||||
)
|
)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
|
@ -185,7 +179,10 @@ mod tests {
|
||||||
fn a_lease_is_named_by_its_invocation() {
|
fn a_lease_is_named_by_its_invocation() {
|
||||||
let store = TestStore::new();
|
let store = TestStore::new();
|
||||||
let mut service = open(&store);
|
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]
|
#[test]
|
||||||
|
|
@ -231,14 +228,28 @@ mod tests {
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
service
|
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(),
|
.unwrap(),
|
||||||
LeaseAdmission::Refused(LeaseRefusal::Busy),
|
LeaseAdmission::Refused(LeaseRefusal::Busy),
|
||||||
"one millisecond before its expiry the lease still holds"
|
"one millisecond before its expiry the lease still holds"
|
||||||
);
|
);
|
||||||
granted(
|
granted(
|
||||||
service
|
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(),
|
.unwrap(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -249,7 +260,14 @@ mod tests {
|
||||||
let mut service = open(&store);
|
let mut service = open(&store);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
service
|
service
|
||||||
.begin_lease("stranger", LeaseTurn::SelfRun, "run-1", NOW + 1, NOW, &none())
|
.begin_lease(
|
||||||
|
"stranger",
|
||||||
|
LeaseTurn::SelfRun,
|
||||||
|
"run-1",
|
||||||
|
NOW + 1,
|
||||||
|
NOW,
|
||||||
|
&none()
|
||||||
|
)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
LeaseAdmission::Refused(LeaseRefusal::UnknownCaller)
|
LeaseAdmission::Refused(LeaseRefusal::UnknownCaller)
|
||||||
);
|
);
|
||||||
|
|
@ -286,8 +304,7 @@ mod tests {
|
||||||
let call = |service: &mut TransportService, now: u64, plan: &PlanQuotaSnapshot| {
|
let call = |service: &mut TransportService, now: u64, plan: &PlanQuotaSnapshot| {
|
||||||
let mut asked = request();
|
let mut asked = request();
|
||||||
asked.request_id = format!("call-{now}");
|
asked.request_id = format!("call-{now}");
|
||||||
let invocation =
|
let invocation = TransportInvocation::new(CALLER, now + 1_000, [7; 32], asked).unwrap();
|
||||||
TransportInvocation::new(CALLER, now + 1_000, [7; 32], asked).unwrap();
|
|
||||||
let sealed = crate::envelope::encrypt_message(
|
let sealed = crate::envelope::encrypt_message(
|
||||||
CALLER,
|
CALLER,
|
||||||
invocation.request_id(),
|
invocation.request_id(),
|
||||||
|
|
@ -301,7 +318,8 @@ mod tests {
|
||||||
else {
|
else {
|
||||||
return None;
|
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 {
|
match result.disposition {
|
||||||
TransportDisposition::Refused(refusal) => Some(refusal),
|
TransportDisposition::Refused(refusal) => Some(refusal),
|
||||||
other => panic!("unexpected {other:?}"),
|
other => panic!("unexpected {other:?}"),
|
||||||
|
|
@ -361,7 +379,12 @@ mod tests {
|
||||||
let store = TestStore::new();
|
let store = TestStore::new();
|
||||||
let mut service = open(&store);
|
let mut service = open(&store);
|
||||||
let longest = "r".repeat(MAX_IDENTITY_BYTES - LEASE_PREFIX.len() - PERSONA_SUFFIX.len());
|
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_eq!(grant.lease_id.len(), MAX_IDENTITY_BYTES);
|
||||||
assert!(lease_try(&mut service, LeaseTurn::PersonaTurn, &format!("{longest}r")).is_err());
|
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",
|
"format": "uint64",
|
||||||
"minimum": 0
|
"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": {
|
"native_request_sha256": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
|
|
@ -53,7 +47,6 @@
|
||||||
"expires_at_unix_ms",
|
"expires_at_unix_ms",
|
||||||
"native_request_sha256",
|
"native_request_sha256",
|
||||||
"provider_request_sha256",
|
"provider_request_sha256",
|
||||||
"max_cost_micro_usd",
|
|
||||||
"request"
|
"request"
|
||||||
],
|
],
|
||||||
"$defs": {
|
"$defs": {
|
||||||
|
|
|
||||||
|
|
@ -6,12 +6,6 @@
|
||||||
"caller_runtime_id": {
|
"caller_runtime_id": {
|
||||||
"type": "string"
|
"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": {
|
"foreign_reasoning_dropped": {
|
||||||
"description": "How many foreign `ReasoningState` items the service removed from the\nrequest before the backend saw it.",
|
"description": "How many foreign `ReasoningState` items the service removed from the\nrequest before the backend saw it.",
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
|
|
@ -35,12 +29,6 @@
|
||||||
"outcome": {
|
"outcome": {
|
||||||
"$ref": "#/$defs/TransportOutcome"
|
"$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": {
|
"provider": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
|
@ -72,8 +60,6 @@
|
||||||
"model",
|
"model",
|
||||||
"provider",
|
"provider",
|
||||||
"foreign_reasoning_dropped",
|
"foreign_reasoning_dropped",
|
||||||
"cost_micro_usd",
|
|
||||||
"overrun_micro_usd",
|
|
||||||
"outcome"
|
"outcome"
|
||||||
],
|
],
|
||||||
"$defs": {
|
"$defs": {
|
||||||
|
|
@ -174,7 +160,7 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"Usage": {
|
"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",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"cache_read_tokens": {
|
"cache_read_tokens": {
|
||||||
|
|
|
||||||
|
|
@ -46,15 +46,13 @@
|
||||||
"ModelNotAllowed",
|
"ModelNotAllowed",
|
||||||
"OutputBound",
|
"OutputBound",
|
||||||
"PayloadBound",
|
"PayloadBound",
|
||||||
"CostBound",
|
|
||||||
"SpendCeiling",
|
|
||||||
"Capacity",
|
"Capacity",
|
||||||
"InFlight",
|
"InFlight",
|
||||||
"Indeterminate",
|
"Indeterminate",
|
||||||
"ReplayConflict",
|
"ReplayConflict",
|
||||||
"Malformed",
|
"Malformed",
|
||||||
"ForeignReasoningState",
|
"ForeignReasoningState",
|
||||||
"ClockBehindAdmissionWindow"
|
"ProviderRejected"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"StopReason": {
|
"StopReason": {
|
||||||
|
|
@ -286,12 +284,6 @@
|
||||||
"caller_runtime_id": {
|
"caller_runtime_id": {
|
||||||
"type": "string"
|
"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": {
|
"foreign_reasoning_dropped": {
|
||||||
"description": "How many foreign `ReasoningState` items the service removed from the\nrequest before the backend saw it.",
|
"description": "How many foreign `ReasoningState` items the service removed from the\nrequest before the backend saw it.",
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
|
|
@ -315,12 +307,6 @@
|
||||||
"outcome": {
|
"outcome": {
|
||||||
"$ref": "#/$defs/TransportOutcome"
|
"$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": {
|
"provider": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
|
@ -352,13 +338,11 @@
|
||||||
"model",
|
"model",
|
||||||
"provider",
|
"provider",
|
||||||
"foreign_reasoning_dropped",
|
"foreign_reasoning_dropped",
|
||||||
"cost_micro_usd",
|
|
||||||
"overrun_micro_usd",
|
|
||||||
"outcome"
|
"outcome"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"Usage": {
|
"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",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"cache_read_tokens": {
|
"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