connector-contract-v3: delete the v2 golden test and fixtures
Ruling connector-v3-only: no v2 peer is kept. The test's header already named this cut as its deletion line. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
ec0519d9ff
commit
685f449ddb
24 changed files with 0 additions and 517 deletions
|
|
@ -1,2 +0,0 @@
|
|||
*.mp binary
|
||||
*.bin binary
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
# Golden v2 wire fixtures
|
||||
|
||||
Bytes of the v2 connector wire, produced once by CodexConnector at commit
|
||||
`fd7cec4176f4e3f9a5aaa75e77ba10ce5e1522f8`. Ghostlight pins CodexConnector
|
||||
`68fe94b`, not that commit; `src/lib.rs`, the whole v2 wire, is identical in
|
||||
both, so these bytes are Ghostlight's wire. They are pinned by `tests/wire_golden_v2.rs`, so the kit cannot drift from
|
||||
them. No CodexConnector code or dependency is part of this repository.
|
||||
|
||||
Generator: `generator.rs` (not compiled here). Command, run in a clone of
|
||||
CodexConnector at that commit:
|
||||
|
||||
cp <ModelConnector>/crates/model-connector/tests/fixtures/wire_v2/generator.rs examples/gen_wire_v2.rs
|
||||
cargo run --locked -q --example gen_wire_v2
|
||||
|
||||
It prints `FIXTURE <name> <hex>` lines; each file is the hex decoded. It was
|
||||
run on Yggdrasil through the verify container with codex-connector at that
|
||||
commit as a dev-dependency of the kit at d1d28f0 (same source). The `.mp`
|
||||
files are rmp-serde output; `envelope_*` files carry random nonces and
|
||||
AES-256-GCM ciphertext sealed under the connection key
|
||||
`parity-distinct-test-key`. Regenerating changes the envelopes' bytes; the
|
||||
plaintext fixtures must regenerate byte-identically.
|
||||
Binary file not shown.
Binary file not shown.
|
|
@ -1,6 +0,0 @@
|
|||
栙$gamecult.codex.transport_envelope.v2璸arity-caller﹔equest-1狪nvocation溙<6E>塘h虄虒抬x泰Y探<1B>環谭听题虠虆3陶
糖烃虘誊h抬台涕[酞藤!A屉虊甜铁疼;屉铁| 酞躺`!铁铁虤抬虗
|
||||
虂k剔'vCZ锑號虒虉
8J抬汤d蹋虠N炭F炭zm6<6D><36>
|
||||
眺添甜\\NMq號套虠贴1替苔摊惕4*{趟胎瘫
|
||||
讨苔e糖台虖
|
||||
贪虇i贪G*S虂坛碳桃胎坍誊!N汤萄虪虃太虣7虂糖贪天虄汤态c苔趟桃滩1k提~h踢3$腾虪K踢贪贴誊4{逃踢碳泰U.)烫汰踏r虪听天唐^bbI虉y^坛踢烫虂躺:虪虤-体YXo逃桃[Qy虡太
|
||||
X逃I:3探淘贪D&V'-舔uf虒X1跳桃.虧|4c蹄虌E体A踢替虩掏Q梯L虃-提w贪u檀3坦>田$Qz汤km'+绦挞G 檀s坍00 f)谭C摊虣*虇虙疼y~贴Hz跳体听"糖挞*%挑o躺摊藤x處}虌滔梯Y倘C填檀炭u厅谈x/g屉恬虡X-藤搪坍虇N天RI):H恬躺虙汤虊虠f疼虪'\s台 虧s虊棠GVa逃潭滩C\\`=p 虨w處H讨4唐特>lfL蹋烃啼讨v炭剔J屉
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
–Ù$gamecult.codex.transport_envelope.v2parity-caller©request-1¦ResultœÌ…Ì¢ÌÇ"̇Ì<E280A1>GÌ©ÜCÌôÌË Ì<>ÌéHÌßÌ—ÌÿÌÐÌ´ÌÝÌá\Ìö]2/ÌÎe"̘
|
||||
Ì¿ÌáÌìÌü{GÌÚṴ̧^b3Ìûj̢̗̟ÌÃÌ’sÌ•*Ì» ÌøÌä≠̄<ÌÁ{ÌýÌã.ÌØ8~̫̓CÌâ
|
||||
̱̘ÌË
|
||||
[Ì‚ÌÉoÌ–(47ÌÌBML̲Ìó̢̳Ì<C2A2>hp,ÌîÌ®wÌê6DHÌðbÌÏÌÌb̹@a̧ÌÑ̵̴̎Ì<>kÌäÌ’ÌáÌóÌ€ÌÑN+ÌüMÌÀjG%Ìß/Ìô
|
||||
ÌÁÌò̸%Ì»Ì<C2BB>@sT`ÌâÌ’}P̈ÌÒ ÌëÌÊÌÞÌ«Ìâ:ÌÚ̟̖̔Ìû^Ìô>ÌûX.x
|
||||
r]F8Ì<38>ÌÛÌ‹Ì÷Ì<C3B7>5ÌÚGÌÆÌºÌÃÌ®C@(ÌóÌÓ̾{̾ÌÙMÌÓ~)Ìà7ÌÐÌòI+'vÌøUnP̈$U(NÌêÌçÌüsÌ¢T^[ÌÊYÌæÌ<C3A6>zÌâ.wÌÆeÌ™C̦̿̄"U^trÌöÌ<C3B6>ÌÙ̦Ìï̯̬ÌçÌÜÌž+ÌÑ/b̯Ì̼Ìî*$Ì×̲̘̊ÌÕ\K5̧f
|
||||
Ìò̃b}̦̬o.Ẁ̧&Ìå̶̑[
|
||||
Binary file not shown.
Binary file not shown.
|
|
@ -1,171 +0,0 @@
|
|||
//! Generator of the golden v2 wire fixtures beside it. It is not compiled by this
|
||||
//! workspace: it was run once, as an example of CodexConnector at commit
|
||||
//! fd7cec4176f4e3f9a5aaa75e77ba10ce5e1522f8 (see README.md here for the command).
|
||||
//! It prints one `FIXTURE <name> <hex>` line per file.
|
||||
|
||||
use codex_connector as v2;
|
||||
use serde::Serialize;
|
||||
|
||||
const KEY: &str = "parity-distinct-test-key";
|
||||
const CALLER: &str = "parity-caller";
|
||||
|
||||
fn bytes<T: Serialize>(value: &T) -> Vec<u8> {
|
||||
rmp_serde::to_vec(value).unwrap()
|
||||
}
|
||||
|
||||
fn emit(name: &str, data: &[u8]) {
|
||||
let hex: String = data.iter().map(|byte| format!("{byte:02x}")).collect();
|
||||
println!("FIXTURE {name} {hex}");
|
||||
}
|
||||
|
||||
fn request(choice: v2::CodexToolChoice) -> v2::CodexProviderRequest {
|
||||
let mut request =
|
||||
v2::CodexProviderRequest::new("request-1", "conversation-1", "gpt-5.4", "Be exact.");
|
||||
request.input = vec![
|
||||
v2::CodexInputItem::UserText {
|
||||
text: "state".to_string(),
|
||||
},
|
||||
v2::CodexInputItem::AssistantText {
|
||||
text: "reply".to_string(),
|
||||
},
|
||||
v2::CodexInputItem::ToolCall {
|
||||
call_id: "call-1".to_string(),
|
||||
name: "read_source".to_string(),
|
||||
arguments: "{}".to_string(),
|
||||
},
|
||||
v2::CodexInputItem::ToolResult {
|
||||
call_id: "call-1".to_string(),
|
||||
output: "ok".to_string(),
|
||||
},
|
||||
];
|
||||
request.tools = vec![v2::CodexToolDefinition {
|
||||
name: "read_source".to_string(),
|
||||
description: "Read one admitted source.".to_string(),
|
||||
parameters_json: r#"{"type":"object"}"#.to_string(),
|
||||
}];
|
||||
request.tool_choice = choice;
|
||||
request.reasoning_effort = Some("high".to_string());
|
||||
request.parallel_tool_calls = true;
|
||||
request.max_output_tokens = Some(512);
|
||||
request.prompt_cache_key = Some("cache-1".to_string());
|
||||
request
|
||||
}
|
||||
|
||||
fn invocation(choice: v2::CodexToolChoice) -> v2::CodexTransportInvocation {
|
||||
v2::CodexTransportInvocation::new(CALLER, 2_000, [7; 32], request(choice)).unwrap()
|
||||
}
|
||||
|
||||
fn receipt(
|
||||
invocation: &v2::CodexTransportInvocation,
|
||||
outcome: v2::CodexTransportOutcome,
|
||||
) -> v2::CodexTransportReceipt {
|
||||
v2::CodexTransportReceipt {
|
||||
schema_id: v2::RECEIPT_SCHEMA_ID.to_string(),
|
||||
request_id: invocation.request_id().to_string(),
|
||||
caller_runtime_id: invocation.caller_runtime_id.clone(),
|
||||
native_request_sha256: invocation.native_request_sha256,
|
||||
provider_request_sha256: invocation.provider_request_sha256,
|
||||
model: invocation.request.model.clone(),
|
||||
transport: "parity-sse".to_string(),
|
||||
outcome,
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let key = v2::CodexTransportKey::from_connection_secret(KEY).unwrap();
|
||||
let auto = invocation(v2::CodexToolChoice::Auto);
|
||||
let required = invocation(v2::CodexToolChoice::Required);
|
||||
emit("invocation_auto.mp", &bytes(&auto));
|
||||
emit("invocation_required.mp", &bytes(&required));
|
||||
emit(
|
||||
"canonical_invocation.bin",
|
||||
&v2::canonical_invocation_bytes(&required).unwrap(),
|
||||
);
|
||||
emit(
|
||||
"canonical_provider_request.bin",
|
||||
&v2::canonical_provider_request_bytes(&required.request).unwrap(),
|
||||
);
|
||||
emit(
|
||||
"provider_request_sha256.bin",
|
||||
&v2::provider_request_sha256(&required.request).unwrap(),
|
||||
);
|
||||
emit(
|
||||
"envelope_invocation.mp",
|
||||
&bytes(&v2::encrypt_invocation(&required, &key).unwrap()),
|
||||
);
|
||||
|
||||
let completed = v2::CodexTransportResult::transported(
|
||||
&required,
|
||||
vec![
|
||||
v2::CodexTransportEvent {
|
||||
sequence: 0,
|
||||
payload: v2::CodexTransportEventPayload::TextDelta {
|
||||
text: "hello".to_string(),
|
||||
},
|
||||
},
|
||||
v2::CodexTransportEvent {
|
||||
sequence: 1,
|
||||
payload: v2::CodexTransportEventPayload::ToolCall {
|
||||
call_id: "call-2".to_string(),
|
||||
name: "read_source".to_string(),
|
||||
arguments: "{}".to_string(),
|
||||
},
|
||||
},
|
||||
],
|
||||
receipt(
|
||||
&required,
|
||||
v2::CodexTransportOutcome::Completed {
|
||||
provider_response_id: Some("response-1".to_string()),
|
||||
input_tokens: Some(10),
|
||||
output_tokens: Some(3),
|
||||
reasoning_output_tokens: Some(1),
|
||||
cached_input_tokens: Some(4),
|
||||
},
|
||||
),
|
||||
);
|
||||
emit("result_transported.mp", &bytes(&completed));
|
||||
emit(
|
||||
"envelope_result_transported.mp",
|
||||
&bytes(&v2::encrypt_result(&completed, &key).unwrap()),
|
||||
);
|
||||
|
||||
let failed = v2::CodexTransportResult::transported(
|
||||
&required,
|
||||
Vec::new(),
|
||||
receipt(
|
||||
&required,
|
||||
v2::CodexTransportOutcome::Failed {
|
||||
failure_kind: "result_size".to_string(),
|
||||
message: "provider result exceeded its byte bound".to_string(),
|
||||
},
|
||||
),
|
||||
);
|
||||
emit("result_failed.mp", &bytes(&failed));
|
||||
emit(
|
||||
"envelope_result_failed.mp",
|
||||
&bytes(&v2::encrypt_result(&failed, &key).unwrap()),
|
||||
);
|
||||
|
||||
use v2::CodexRefusal as R;
|
||||
let refusals = [
|
||||
("expired", R::Expired),
|
||||
("identity_substitution", R::IdentitySubstitution),
|
||||
("provider_digest_substitution", R::ProviderDigestSubstitution),
|
||||
("policy", R::Policy),
|
||||
("capacity", R::Capacity),
|
||||
("in_flight", R::InFlight),
|
||||
("indeterminate", R::Indeterminate),
|
||||
("replay_conflict", R::ReplayConflict),
|
||||
("malformed", R::Malformed),
|
||||
];
|
||||
for (name, refusal) in refusals {
|
||||
let refused = v2::CodexTransportResult::refused(&required, refusal);
|
||||
emit(&format!("result_refused_{name}.mp"), &bytes(&refused));
|
||||
if name == "replay_conflict" {
|
||||
emit(
|
||||
"envelope_result_refused_replay_conflict.mp",
|
||||
&bytes(&v2::encrypt_result(&refused, &key).unwrap()),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -1 +0,0 @@
|
|||
”Ù"gamecult.codex.transport_result.v2©request-1parity-caller<65>§Refused¨Capacity
|
||||
|
|
@ -1 +0,0 @@
|
|||
”Ù"gamecult.codex.transport_result.v2©request-1parity-caller<65>§Refused§Expired
|
||||
|
|
@ -1 +0,0 @@
|
|||
”Ù"gamecult.codex.transport_result.v2©request-1parity-caller<65>§Refused´IdentitySubstitution
|
||||
|
|
@ -1 +0,0 @@
|
|||
”Ù"gamecult.codex.transport_result.v2©request-1parity-caller<65>§Refused¨InFlight
|
||||
|
|
@ -1 +0,0 @@
|
|||
”Ù"gamecult.codex.transport_result.v2©request-1parity-caller<65>§RefusedIndeterminate
|
||||
|
|
@ -1 +0,0 @@
|
|||
”Ù"gamecult.codex.transport_result.v2©request-1parity-caller<65>§Refused©Malformed
|
||||
|
|
@ -1 +0,0 @@
|
|||
”Ù"gamecult.codex.transport_result.v2©request-1parity-caller<65>§Refused¦Policy
|
||||
|
|
@ -1 +0,0 @@
|
|||
”Ù"gamecult.codex.transport_result.v2©request-1parity-caller<65>§RefusedºProviderDigestSubstitution
|
||||
|
|
@ -1 +0,0 @@
|
|||
”Ù"gamecult.codex.transport_result.v2©request-1parity-caller<65>§Refused®ReplayConflict
|
||||
Binary file not shown.
|
|
@ -1,301 +0,0 @@
|
|||
//! The kit speaks the v2 wire of CodexConnector fd7cec4, the library Ghostlight pins.
|
||||
//! The golden bytes in `fixtures/wire_v2` were produced by that library (see its README);
|
||||
//! nothing of it is linked here. Deleted with the fixtures by cut connector-contract-v3,
|
||||
//! which changes the wire.
|
||||
|
||||
use model_connector as kit;
|
||||
use serde::Serialize;
|
||||
use serde::de::DeserializeOwned;
|
||||
|
||||
const KEY: &str = "parity-distinct-test-key";
|
||||
const CALLER: &str = "parity-caller";
|
||||
|
||||
macro_rules! golden {
|
||||
($name:literal) => {
|
||||
include_bytes!(concat!("fixtures/wire_v2/", $name)) as &[u8]
|
||||
};
|
||||
}
|
||||
|
||||
fn bytes<T: Serialize>(value: &T) -> Vec<u8> {
|
||||
rmp_serde::to_vec(value).unwrap()
|
||||
}
|
||||
|
||||
/// The value serializes to the golden bytes and the golden bytes decode back to it.
|
||||
fn assert_wire<T: Serialize + DeserializeOwned + PartialEq + std::fmt::Debug>(
|
||||
name: &str,
|
||||
value: &T,
|
||||
golden: &[u8],
|
||||
) {
|
||||
assert_eq!(bytes(value), golden, "{name}: serialized bytes");
|
||||
let decoded: T = rmp_serde::from_slice(golden).unwrap();
|
||||
assert_eq!(&decoded, value, "{name}: decoded value");
|
||||
}
|
||||
|
||||
fn request(choice: kit::ToolChoice) -> kit::ProviderRequest {
|
||||
let mut request =
|
||||
kit::ProviderRequest::new("request-1", "conversation-1", "gpt-5.4", "Be exact.");
|
||||
request.input = vec![
|
||||
kit::InputItem::UserText {
|
||||
text: "state".to_string(),
|
||||
},
|
||||
kit::InputItem::AssistantText {
|
||||
text: "reply".to_string(),
|
||||
},
|
||||
kit::InputItem::ToolCall {
|
||||
call_id: "call-1".to_string(),
|
||||
name: "read_source".to_string(),
|
||||
arguments: "{}".to_string(),
|
||||
},
|
||||
kit::InputItem::ToolResult {
|
||||
call_id: "call-1".to_string(),
|
||||
output: "ok".to_string(),
|
||||
},
|
||||
];
|
||||
request.tools = vec![kit::ToolDefinition {
|
||||
name: "read_source".to_string(),
|
||||
description: "Read one admitted source.".to_string(),
|
||||
parameters_json: r#"{"type":"object"}"#.to_string(),
|
||||
}];
|
||||
request.tool_choice = choice;
|
||||
request.reasoning_effort = Some("high".to_string());
|
||||
request.parallel_tool_calls = true;
|
||||
request.max_output_tokens = Some(512);
|
||||
request.prompt_cache_key = Some("cache-1".to_string());
|
||||
request
|
||||
}
|
||||
|
||||
fn invocation(choice: kit::ToolChoice) -> kit::TransportInvocation {
|
||||
kit::TransportInvocation::new(CALLER, 2_000, [7; 32], request(choice)).unwrap()
|
||||
}
|
||||
|
||||
fn receipt(
|
||||
invocation: &kit::TransportInvocation,
|
||||
outcome: kit::TransportOutcome,
|
||||
) -> kit::TransportReceipt {
|
||||
kit::TransportReceipt {
|
||||
schema_id: kit::RECEIPT_SCHEMA_ID.to_string(),
|
||||
request_id: invocation.request_id().to_string(),
|
||||
caller_runtime_id: invocation.caller_runtime_id.clone(),
|
||||
native_request_sha256: invocation.native_request_sha256,
|
||||
provider_request_sha256: invocation.provider_request_sha256,
|
||||
model: invocation.request.model.clone(),
|
||||
transport: "parity-sse".to_string(),
|
||||
outcome,
|
||||
}
|
||||
}
|
||||
|
||||
fn completed(invocation: &kit::TransportInvocation) -> kit::TransportResult {
|
||||
kit::TransportResult::transported(
|
||||
invocation,
|
||||
vec![
|
||||
kit::TransportEvent {
|
||||
sequence: 0,
|
||||
payload: kit::TransportEventPayload::TextDelta {
|
||||
text: "hello".to_string(),
|
||||
},
|
||||
},
|
||||
kit::TransportEvent {
|
||||
sequence: 1,
|
||||
payload: kit::TransportEventPayload::ToolCall {
|
||||
call_id: "call-2".to_string(),
|
||||
name: "read_source".to_string(),
|
||||
arguments: "{}".to_string(),
|
||||
},
|
||||
},
|
||||
],
|
||||
receipt(
|
||||
invocation,
|
||||
kit::TransportOutcome::Completed {
|
||||
provider_response_id: Some("response-1".to_string()),
|
||||
input_tokens: Some(10),
|
||||
output_tokens: Some(3),
|
||||
reasoning_output_tokens: Some(1),
|
||||
cached_input_tokens: Some(4),
|
||||
},
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
fn failed(invocation: &kit::TransportInvocation) -> kit::TransportResult {
|
||||
kit::TransportResult::transported(
|
||||
invocation,
|
||||
Vec::new(),
|
||||
receipt(
|
||||
invocation,
|
||||
kit::TransportOutcome::Failed {
|
||||
failure_kind: "result_size".to_string(),
|
||||
message: "provider result exceeded its byte bound".to_string(),
|
||||
},
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
fn key() -> kit::TransportKey {
|
||||
kit::TransportKey::from_connection_secret(KEY).unwrap()
|
||||
}
|
||||
|
||||
fn refusals() -> [(&'static str, kit::Refusal, &'static [u8]); 9] {
|
||||
use kit::Refusal as R;
|
||||
[
|
||||
("expired", R::Expired, golden!("result_refused_expired.mp")),
|
||||
(
|
||||
"identity_substitution",
|
||||
R::IdentitySubstitution,
|
||||
golden!("result_refused_identity_substitution.mp"),
|
||||
),
|
||||
(
|
||||
"provider_digest_substitution",
|
||||
R::ProviderDigestSubstitution,
|
||||
golden!("result_refused_provider_digest_substitution.mp"),
|
||||
),
|
||||
("policy", R::Policy, golden!("result_refused_policy.mp")),
|
||||
(
|
||||
"capacity",
|
||||
R::Capacity,
|
||||
golden!("result_refused_capacity.mp"),
|
||||
),
|
||||
(
|
||||
"in_flight",
|
||||
R::InFlight,
|
||||
golden!("result_refused_in_flight.mp"),
|
||||
),
|
||||
(
|
||||
"indeterminate",
|
||||
R::Indeterminate,
|
||||
golden!("result_refused_indeterminate.mp"),
|
||||
),
|
||||
(
|
||||
"replay_conflict",
|
||||
R::ReplayConflict,
|
||||
golden!("result_refused_replay_conflict.mp"),
|
||||
),
|
||||
(
|
||||
"malformed",
|
||||
R::Malformed,
|
||||
golden!("result_refused_malformed.mp"),
|
||||
),
|
||||
]
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn schema_ids_are_the_v2_ids() {
|
||||
assert_eq!(
|
||||
kit::PROVIDER_REQUEST_SCHEMA_ID,
|
||||
"gamecult.codex.provider_request.v2"
|
||||
);
|
||||
assert_eq!(
|
||||
kit::INVOCATION_SCHEMA_ID,
|
||||
"gamecult.codex.transport_invocation.v2"
|
||||
);
|
||||
assert_eq!(kit::RESULT_SCHEMA_ID, "gamecult.codex.transport_result.v2");
|
||||
assert_eq!(
|
||||
kit::RECEIPT_SCHEMA_ID,
|
||||
"gamecult.codex.transport_receipt.v2"
|
||||
);
|
||||
assert_eq!(
|
||||
kit::ENVELOPE_SCHEMA_ID,
|
||||
"gamecult.codex.transport_envelope.v2"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invocations_carry_the_v2_bytes_for_each_tool_choice() {
|
||||
assert_wire(
|
||||
"auto",
|
||||
&invocation(kit::ToolChoice::Auto),
|
||||
golden!("invocation_auto.mp"),
|
||||
);
|
||||
assert_wire(
|
||||
"required",
|
||||
&invocation(kit::ToolChoice::Required),
|
||||
golden!("invocation_required.mp"),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn results_carry_the_v2_bytes_for_success_and_failure() {
|
||||
let invocation = invocation(kit::ToolChoice::Required);
|
||||
assert_wire(
|
||||
"transported",
|
||||
&completed(&invocation),
|
||||
golden!("result_transported.mp"),
|
||||
);
|
||||
assert_wire("failed", &failed(&invocation), golden!("result_failed.mp"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn every_refusal_carries_its_v2_bytes() {
|
||||
let invocation = invocation(kit::ToolChoice::Required);
|
||||
for (name, refusal, golden) in refusals() {
|
||||
assert_wire(
|
||||
name,
|
||||
&kit::TransportResult::refused(&invocation, refusal),
|
||||
golden,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn canonical_bytes_and_provider_digest_are_the_v2_bytes() {
|
||||
let invocation = invocation(kit::ToolChoice::Required);
|
||||
assert_eq!(
|
||||
kit::canonical_invocation_bytes(&invocation).unwrap(),
|
||||
golden!("canonical_invocation.bin")
|
||||
);
|
||||
assert_eq!(
|
||||
kit::canonical_provider_request_bytes(&invocation.request).unwrap(),
|
||||
golden!("canonical_provider_request.bin")
|
||||
);
|
||||
assert_eq!(
|
||||
kit::provider_request_sha256(&invocation.request)
|
||||
.unwrap()
|
||||
.as_slice(),
|
||||
golden!("provider_request_sha256.bin")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn v2_sealed_envelopes_decrypt_and_validate_under_the_kit() {
|
||||
let invocation = invocation(kit::ToolChoice::Required);
|
||||
let envelope: kit::TransportEnvelope =
|
||||
rmp_serde::from_slice(golden!("envelope_invocation.mp")).unwrap();
|
||||
let received = kit::decrypt_invocation(&envelope, &key()).unwrap();
|
||||
assert_eq!(bytes(&received), bytes(&invocation));
|
||||
|
||||
let results = [
|
||||
(
|
||||
golden!("envelope_result_transported.mp"),
|
||||
completed(&invocation),
|
||||
),
|
||||
(golden!("envelope_result_failed.mp"), failed(&invocation)),
|
||||
(
|
||||
golden!("envelope_result_refused_replay_conflict.mp"),
|
||||
kit::TransportResult::refused(&invocation, kit::Refusal::ReplayConflict),
|
||||
),
|
||||
];
|
||||
for (sealed, expected) in results {
|
||||
let envelope: kit::TransportEnvelope = rmp_serde::from_slice(sealed).unwrap();
|
||||
let received = kit::decrypt_result(&envelope, &key(), &invocation).unwrap();
|
||||
assert_eq!(bytes(&received), bytes(&expected));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn kit_sealed_envelopes_have_the_v2_shape() {
|
||||
let invocation = invocation(kit::ToolChoice::Required);
|
||||
let golden: kit::TransportEnvelope =
|
||||
rmp_serde::from_slice(golden!("envelope_invocation.mp")).unwrap();
|
||||
let sealed = kit::encrypt_invocation(&invocation, &key()).unwrap();
|
||||
assert_eq!(sealed.schema_id, golden.schema_id);
|
||||
assert_eq!(sealed.caller_runtime_id, golden.caller_runtime_id);
|
||||
assert_eq!(sealed.request_id, golden.request_id);
|
||||
assert_eq!(sealed.message_kind, golden.message_kind);
|
||||
assert_eq!(sealed.ciphertext.len(), golden.ciphertext.len());
|
||||
assert_ne!(sealed.nonce, golden.nonce, "nonces are fresh per seal");
|
||||
|
||||
let golden: kit::TransportEnvelope =
|
||||
rmp_serde::from_slice(golden!("envelope_result_transported.mp")).unwrap();
|
||||
let sealed = kit::encrypt_result(&completed(&invocation), &key()).unwrap();
|
||||
assert_eq!(sealed.message_kind, golden.message_kind);
|
||||
assert_eq!(sealed.ciphertext.len(), golden.ciphertext.len());
|
||||
}
|
||||
Loading…
Reference in a new issue