blob: cd0c30ad6ac5d66bf0499c394e684e5ef9bd77dd [file]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
use super::*;
use maka_plugin_core::{contract::ResourceType, operation::RecoveryRef};
struct Text(String);
impl maka_capabilities::call::ReadResource for Text {
fn resource_type(&self) -> ResourceType {
ResourceType {
name: "maka.text.utf8".into(),
version: 1,
}
}
fn bytes(&self) -> usize {
self.0.len()
}
fn metadata(&self) -> Value {
json!({"private":"private-resource-metadata-marker"})
}
fn read(&self, range: std::ops::Range<usize>) -> Result<Vec<u8>, String> {
Ok(self.0.get(range).ok_or("range")?.as_bytes().to_vec())
}
}
async fn binding(fixture: &Fixture) -> Binding {
let client = fixture.app.client();
client
.bind(client.activation(&id(2)).unwrap(), "settings".into())
.await
.unwrap()
.remove(0)
}
async fn query(fixture: &Fixture, method: &str, input: Value) -> Value {
fixture
.app
.client()
.start(
binding(fixture).await,
method.into(),
input,
scope(&fixture.issuer, true),
Attachments::new().into(),
)
.await
.unwrap()
.result()
.await
.unwrap()
}
async fn mutate(
fixture: &Fixture,
method: &str,
input: Value,
secret: Option<&str>,
) -> (Value, RecoveryRef) {
let reply = mutate_reply(fixture, method, input, secret).await;
let Receipt::Recorded {
outcome: OperationOutcome::Returned { value },
..
} = reply.receipt
else {
panic!("unexpected operation receipt")
};
(value, reply.reference)
}
async fn mutate_reply(
fixture: &Fixture,
method: &str,
input: Value,
secret: Option<&str>,
) -> maka_plugin_core::operation::OperationReply {
let attachments = secret
.map(|value| {
BTreeMap::from([(
"secret".into(),
Arc::new(Text(value.into())) as Arc<dyn maka_capabilities::call::ReadResource>,
)])
})
.unwrap_or_default();
let client = fixture.app.client();
let prepared = client
.prepare_mutation(
binding(fixture).await,
method.into(),
input,
scope(&fixture.issuer, true),
Uuid::new_v4(),
attachments.into(),
)
.await
.unwrap();
let reference = prepared.reference().clone();
let recorded = fixture
.store
.record_application_intent(
reference.source.clone(),
prepared.consumer().instance().clone(),
reference.clone(),
serde_json::Value::Null,
)
.await
.unwrap();
client
.mutate(prepared, recorded)
.await
.unwrap()
.result()
.await
}
#[tokio::test]
async fn settings_confirmed_validation_rejections_do_not_downgrade_sql_uncertainty() {
let fixture = Fixture::new("http://127.0.0.1:1/v1", None).await;
let original = fixture.config.catalog().await.unwrap();
let row = &original.connections[0];
let basis = json!({"connectionId":row.connection_id,"revision":row.revision});
for (changes, reason) in [
(
json!({"enabledModelIds":["fixture-model","fixture-model"]}),
"invalid_input",
),
(
json!({"configuration":{"baseUrl":17}}),
"invalid_configuration",
),
// These individually valid limits are rejected after the original SQL
// CAS and merge. The transaction must finish rollback before replying.
(
json!({"name":"Not committed","modelOverrides":{"fixture-model":{"contextWindow":10,"inputLimit":11}}}),
"invalid_input",
),
] {
let (result, reference) = mutate(
&fixture,
"update",
json!({"expected":basis,"changes":changes}),
None,
)
.await;
assert_eq!(result, json!({"kind":"rejected","reason":reason}));
let observation = fixture
.store
.operation_observation(&reference)
.await
.unwrap()
.unwrap();
assert_eq!(
observation.outcome,
OperationOutcome::Returned { value: result }
);
assert_eq!(fixture.config.catalog().await.unwrap(), original);
}
let detail = query(&fixture, "connection", basis.clone()).await;
let locator = json!({"scope":"connection","connectionId":row.connection_id,"kind":"provider"});
let status = query(&fixture, "credentialStatus", json!({"locator":locator})).await;
let status: CredentialStatus = serde_json::from_value(status["status"].clone()).unwrap();
for secret in ["", "key-with\ncontrol"] {
let (result, _) = mutate(
&fixture,
"saveCredential",
json!({"expected":detail["target"],"expectedCredential":status.basis()}),
Some(secret),
)
.await;
assert_eq!(result, json!({"kind":"rejected","reason":"invalid_secret"}));
assert_eq!(fixture.config.catalog().await.unwrap(), original);
}
let (result, _) = mutate(&fixture,"create",json!({"expectedCatalogRevision":original.revision,"connection":{"slug":"unknown","name":"Unknown provider","provider":{"packageId":"maka.providers","entryId":"maka.providers","scope":"profile","name":"not-compiled"},"configuration":{},"enabled":true,"enabledModelIds":[]}}),None).await;
assert_eq!(
result,
json!({"kind":"rejected","reason":"provider_unavailable"})
);
assert_eq!(fixture.config.catalog().await.unwrap(), original);
// An actual SQLite failure is never interpreted as a validation rejection.
// Recovery observes the same original Unknown rather than retrying a write.
let db = rusqlite::Connection::open(fixture.root.join("configuration-rust.sqlite")).unwrap();
db.execute_batch("CREATE TRIGGER settings_write_fault BEFORE UPDATE ON connections BEGIN SELECT RAISE(ABORT, 'synthetic SQL fault'); END;").unwrap();
let reply = mutate_reply(
&fixture,
"update",
json!({"expected":basis,"changes":{"name":"SQL fault"}}),
None,
)
.await;
assert!(matches!(
reply.receipt,
Receipt::Recorded {
outcome: OperationOutcome::Unknown { .. },
..
}
));
let observation = fixture
.store
.operation_observation(&reply.reference)
.await
.unwrap()
.unwrap();
assert!(matches!(
observation.outcome,
OperationOutcome::Unknown { .. }
));
assert_eq!(fixture.config.catalog().await.unwrap(), original);
db.execute_batch("DROP TRIGGER settings_write_fault;")
.unwrap();
drop(db);
fixture.app.shutdown().await.unwrap();
fixture.config.shutdown().await.unwrap();
}
#[tokio::test]
async fn root_settings_create_partial_edit_save_capture_and_stale_vault_basis_use_original_journals()
{
let fixture = Fixture::new("http://127.0.0.1:1/v1", None).await;
let page = query(&fixture, "connections", json!({"kind":"start"})).await;
assert_eq!(page["connections"].as_array().unwrap().len(), 1);
let original = page["connections"][0]["basis"].clone();
let detail = query(&fixture, "connection", original.clone()).await;
assert_eq!(detail["kind"], "ready");
assert!(detail.get("editing").is_none());
let editable = query(&fixture, "connection", json!({"connectionId":original["connectionId"],"revision":original["revision"],"includeEditingFacts":true})).await;
assert_eq!(editable["target"], detail["target"]);
assert_eq!(
editable["editing"],
json!({"enabledModelIds":["fixture-model"],"modelOverrides":null,"requestBodyOverlay":null})
);
let locator = json!({"scope":"connection","connectionId":detail["target"]["connectionId"],"kind":"provider"});
let status = query(&fixture, "credentialStatus", json!({"locator":locator})).await;
let expected: CredentialStatus = serde_json::from_value(status["status"].clone()).unwrap();
let save = json!({"expected":detail["target"],"expectedCredential":expected.basis()});
const KEY: &str = "settings-native-fixture-key-7f35";
let (saved, reference) = mutate(&fixture, "saveCredential", save.clone(), Some(KEY)).await;
assert_eq!(saved["kind"], "saved");
let locator: CredentialLocator = serde_json::from_value(locator).unwrap();
let envelope: maka_agent_facts::provider::Credential = serde_json::from_str(
&fixture
.config
.credential_secret(&locator, None)
.await
.unwrap()
.unwrap(),
)
.unwrap();
assert_eq!(envelope.secret, KEY);
let (stale, _) = mutate(&fixture, "saveCredential", save, Some("old-stale-capture")).await;
assert_eq!(
stale,
json!({"kind":"rejected","reason":"connection_changed"})
);
let page = query(&fixture, "connections", json!({"kind":"start"})).await;
let detail = query(
&fixture,
"connection",
page["connections"][0]["basis"].clone(),
)
.await;
let status = query(&fixture, "credentialStatus", json!({"locator":locator})).await;
let current: CredentialStatus = serde_json::from_value(status["status"].clone()).unwrap();
let target: ConnectionCredentialTarget =
serde_json::from_value(detail["target"].clone()).unwrap();
let missing_input = json!({"expected":target});
let resource: Arc<dyn maka_capabilities::call::ReadResource> = Arc::new(Text(KEY.into()));
assert!(
fixture
.app
.client()
.prepare_mutation(
binding(&fixture).await,
"saveCredential".into(),
missing_input,
scope(&fixture.issuer, true),
Uuid::new_v4(),
BTreeMap::from([("secret".into(), resource)]).into()
)
.await
.is_err()
);
let delete = DeleteCredentialInput {
expected: current.basis().unwrap(),
expected_connection: Some(target.clone()),
};
assert!(matches!(
fixture.config.delete_credential(delete).await.unwrap(),
CredentialMutationResult::Committed { .. }
));
assert_eq!(
fixture.config.catalog().await.unwrap().connections[0].revision,
target.revision
);
let (stale, _) = mutate(
&fixture,
"saveCredential",
json!({"expected":target,"expectedCredential":current.basis()}),
Some("stale-generation-key"),
)
.await;
assert_eq!(
stale,
json!({"kind":"rejected","reason":"credential_changed"})
);
let renamed = mutate(&fixture,"update",json!({"expected":page["connections"][0]["basis"],"changes":{"name":"Renamed from plugin","enabledModelIds":["fixture-model","manual-other"],"modelOverrides":{"fixture-model":{"codeMode":false,"thinkingLevels":["high"]},"manual-other":{"displayName":"Kept manual declaration","contextWindow":12345}},"requestBodyOverlay":{"provider":{"only":["openrouter","deepseek"]},"temperature":0.22}}}),None).await.0;
assert_eq!(renamed["kind"], "committed");
let stale = query(&fixture, "connection", json!({"connectionId":detail["target"]["connectionId"],"revision":detail["target"]["revision"],"includeEditingFacts":true})).await;
assert_eq!(
stale,
json!({"kind":"stale","actual":renamed["connection"]})
);
let editable = query(&fixture, "connection", json!({"connectionId":renamed["connection"]["connectionId"],"revision":renamed["connection"]["revision"],"includeEditingFacts":true})).await;
assert_eq!(
editable["target"]["revision"],
renamed["connection"]["revision"]
);
assert_eq!(editable["name"], "Renamed from plugin");
assert_eq!(editable["enabledModelCount"], 2);
assert_eq!(
editable["editing"],
json!({"enabledModelIds":["fixture-model","manual-other"],"modelOverrides":{"fixture-model":{"codeMode":false,"thinkingLevels":["high"]},"manual-other":{"displayName":"Kept manual declaration","contextWindow":12345}},"requestBodyOverlay":{"provider":{"only":["openrouter","deepseek"]},"temperature":0.22}})
);
let row = fixture
.config
.catalog()
.await
.unwrap()
.connections
.remove(0);
assert_eq!(row.name, "Renamed from plugin");
assert_eq!(row.enabled_model_ids, vec!["fixture-model", "manual-other"]);
let basis = json!({"connectionId":row.connection_id,"revision":row.revision});
for changes in [
json!({"name":null}),
json!({"enabled":null}),
json!({"enabledModelIds":null}),
json!({"configuration":null}),
json!({"modelOverrides":{"fixture-model":{"vision":null}}}),
json!({"modelOverrides":{"fixture-model":{"capabilities":{"chat":null}}}}),
json!({"requestBodyOverlay":[]}),
] {
assert!(
fixture
.app
.client()
.prepare_mutation(
binding(&fixture).await,
"update".into(),
json!({"expected":basis,"changes":changes}),
scope(&fixture.issuer, true),
Uuid::new_v4(),
Attachments::new().into()
)
.await
.is_err()
);
}
let cleared = mutate(
&fixture,
"update",
json!({"expected":basis,"changes":{"modelOverrides":null,"requestBodyOverlay":null}}),
None,
)
.await
.0;
assert_eq!(cleared["kind"], "committed");
let editable = query(&fixture, "connection", json!({"connectionId":cleared["connection"]["connectionId"],"revision":cleared["connection"]["revision"],"includeEditingFacts":true})).await;
assert_eq!(
editable["editing"],
json!({"enabledModelIds":["fixture-model","manual-other"],"modelOverrides":null,"requestBodyOverlay":null})
);
let providers = query(&fixture, "providers", json!({"offset":0})).await;
assert!(!providers["providers"].as_array().unwrap().is_empty());
assert!(serde_json::to_vec(&providers).unwrap().len() <= 128 * 1024);
let revision = fixture.config.catalog().await.unwrap().revision;
assert!(fixture.app.client().prepare_mutation(binding(&fixture).await,"create".into(),json!({"expectedCatalogRevision":revision,"connection":{"slug":"invalid","name":"Invalid null","provider":row.provider,"configuration":{},"enabled":true,"enabledModelIds":[],"modelOverrides":null}}),scope(&fixture.issuer,true),Uuid::new_v4(),Attachments::new().into()).await.is_err());
let (created,_) = mutate(&fixture,"create",json!({"expectedCatalogRevision":revision,"connection":{"slug":"created","name":"Created through settings","provider":{"packageId":"maka.providers","entryId":"maka.providers","scope":"profile","name":"openai"},"configuration":{},"enabled":true,"enabledModelIds":["manual-model"]}}),None).await;
assert_eq!(created["kind"], "committed");
let catalog = fixture.config.catalog().await.unwrap();
let created_row = catalog
.connections
.iter()
.find(|row| row.slug == "created")
.unwrap();
assert!(
created_row.configuration["baseUrl"]
.as_str()
.unwrap()
.starts_with("https://")
);
let removed = mutate(
&fixture,
"remove",
json!({"expected":created["connection"]}),
None,
)
.await
.0;
assert_eq!(removed["kind"], "committed");
// Complete editing metadata and narrow credential reads share the same basis.
let large_overrides = (0..128)
.map(|index| {
(
format!("manual-{index}"),
ModelOverride {
description: Some("x".repeat(1024)),
..Default::default()
},
)
})
.collect::<BTreeMap<_, _>>();
selection::edit(&fixture, |changes| {
changes.model_overrides = Patch::Set(large_overrides.clone());
})
.await;
let before_read = fixture.config.catalog().await.unwrap();
let page = query(&fixture, "connections", json!({"kind":"start"})).await;
let basis = page["connections"][0]["basis"].clone();
let detail = query(&fixture, "connection", basis.clone()).await;
assert_eq!(detail["kind"], "ready");
assert!(detail.get("editing").is_none());
let editable = query(&fixture, "connection", json!({"connectionId":basis["connectionId"],"revision":basis["revision"],"includeEditingFacts":true})).await;
assert_eq!(editable["target"], detail["target"]);
assert_eq!(
editable["editing"]["enabledModelIds"],
json!(["fixture-model", "manual-other"])
);
assert_eq!(
editable["editing"]["modelOverrides"],
serde_json::to_value(&large_overrides).unwrap()
);
assert!(editable["editing"]["requestBodyOverlay"].is_null());
assert_eq!(fixture.config.catalog().await.unwrap(), before_read);
let status = query(&fixture, "credentialStatus", json!({"locator":locator})).await;
let current: CredentialStatus = serde_json::from_value(status["status"].clone()).unwrap();
let (saved, _) = mutate(
&fixture,
"saveCredential",
json!({"expected":detail["target"],"expectedCredential":current.basis()}),
Some(KEY),
)
.await;
assert_eq!(saved["kind"], "saved");
assert_eq!(
fixture.config.catalog().await.unwrap().connections[0]
.model_overrides
.as_ref(),
Some(&large_overrides)
);
// Read the actual persisted operation/caller/enrollment rows, excluding the
// vault table where storing the credential envelope is the intended effect.
for (database, sql) in [
(
"runtime-rust.sqlite",
"SELECT request_json || outcome_json || cleanup_json FROM application_operations",
),
(
"runtime-rust.sqlite",
"SELECT reference_json FROM application_intents",
),
(
"configuration-rust.sqlite",
"SELECT target || request_fingerprint || phase FROM oauth_login_receipts",
),
] {
let db = rusqlite::Connection::open_with_flags(
fixture.root.join(database),
rusqlite::OpenFlags::SQLITE_OPEN_READ_ONLY,
)
.unwrap();
let mut statement = db.prepare(sql).unwrap();
let rows = statement
.query_map([], |row| row.get::<_, String>(0))
.unwrap();
let mut count = 0;
for row in rows {
count += 1;
let row = row.unwrap();
for secret in [
KEY,
"old-stale-capture",
"stale-generation-key",
"private-resource-metadata-marker",
] {
assert!(
!row.contains(secret),
"private payload entered persisted journal"
);
}
}
assert!(count > 0, "actual journal must contain persisted facts");
}
assert!(
fixture
.store
.operation_observation(&reference)
.await
.unwrap()
.is_some()
);
fixture.app.shutdown().await.unwrap();
fixture.config.shutdown().await.unwrap();
}
#[tokio::test]
async fn assistant_preferences_and_capability_guidance_freeze_at_message_acceptance() {
tokio::time::timeout(Duration::from_secs(60), async {
let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
let fixture = Fixture::configured(
&format!("http://{}/v1", listener.local_addr().unwrap()), None, None, None,
|settings| settings.assistant = Some(AssistantConfiguration {
home: Some(settings.workspace_roots[0].path.parent().unwrap().to_str().unwrap().into()),
}),
).await;
let global = fixture._dir.path().join(".maka");
std::fs::create_dir(&global).unwrap();
std::fs::write(global.join("AGENTS.md"), "GLOBAL FIRST").unwrap();
std::fs::write(fixture.workspace.join("AGENTS.md"), "PROJECT FIRST").unwrap();
// A guidance filename is not authority to escape the selected directory.
#[cfg(unix)] {
let outside = fixture._dir.path().join("outside-guidance");
std::fs::write(&outside, "OUTSIDE SECRET").unwrap();
std::os::unix::fs::symlink(&outside, fixture.workspace.join("CLAUDE.md")).unwrap();
std::os::unix::fs::symlink(&outside, global.join("CLAUDE.md")).unwrap();
}
let initial = query(&fixture, "assistantPreferences", json!({})).await;
let (saved, reference) = mutate(&fixture, "updateAssistantPreferences", json!({
"expectedRevision":initial["revision"],
"mutation":{"kind":"personalization","displayName":"M4n5ter"}
}), None).await;
assert_eq!(saved["kind"], "committed");
let observation = fixture.store.operation_observation(&reference).await.unwrap().unwrap();
assert_eq!(observation.outcome, OperationOutcome::Returned { value: saved.clone() });
let (stale, _) = mutate(&fixture, "updateAssistantPreferences", json!({
"expectedRevision":initial["revision"],
"mutation":{"kind":"workspace_instructions","enabled":false}
}), None).await;
assert_eq!(stale["kind"], "revision_conflict");
let session = fixture.create("Assistant policy").await;
assert_eq!(fixture.send(&session).await.unwrap()["kind"], "started");
let (mut first, _) = listener.accept().await.unwrap();
let system = |sent: &Value| sent["messages"].as_array().unwrap().iter()
.filter(|message| message["role"] == "system")
.map(|message| message["content"].as_str().unwrap()).collect::<Vec<_>>().join("\n");
let original = system(&request(&mut first).await);
assert!(original.starts_with("You are [Maka](https://github.com/apache/maka), an AI agent.\n\n<global_instruction>\nGLOBAL FIRST\n</global_instruction>"));
for value in ["M4n5ter", "GLOBAL FIRST", "PROJECT FIRST"] {
assert!(original.contains(value), "missing {value}: {original}");
}
assert!(!original.contains("OUTSIDE SECRET"));
assert!(!original.contains("FIRST TONE"));
assert_eq!(fixture.send(&session).await.unwrap()["kind"], "queued");
std::fs::write(global.join("AGENTS.md"), "GLOBAL REPLACED").unwrap();
std::fs::write(fixture.workspace.join("AGENTS.md"), "PROJECT REPLACED").unwrap();
let (disabled, _) = mutate(&fixture, "updateAssistantPreferences", json!({
"expectedRevision":saved["revision"],
"mutation":{"kind":"workspace_instructions","enabled":false}
}), None).await;
assert_eq!(disabled["kind"], "committed");
response(&mut first).await;
let (mut second, _) = listener.accept().await.unwrap();
assert_eq!(system(&request(&mut second).await), original, "queued work uses its persisted acceptance basis");
response(&mut second).await;
fixture.drained().await;
assert_eq!(fixture.send(&session).await.unwrap()["kind"], "started");
let (mut third, _) = listener.accept().await.unwrap();
let current = system(&request(&mut third).await);
assert!(!current.contains("FIRST TONE"));
assert!(!current.contains("GLOBAL") && !current.contains("PROJECT"));
response(&mut third).await;
fixture.drained().await;
let current = query(&fixture, "assistantPreferences", json!({})).await;
assert_eq!(current["incognitoActive"], false);
let (privacy, reference) = mutate(&fixture, "updateAssistantPreferences", json!({
"expectedRevision":current["revision"],
"mutation":{"kind":"privacy","incognitoActive":true}
}), None).await;
assert_eq!(privacy["kind"], "committed");
assert_eq!(query(&fixture, "assistantPreferences", json!({})).await["incognitoActive"], true);
assert!(fixture.config.runtime_policy().await.unwrap().policy.privacy.incognito_active);
assert_eq!(fixture.store.operation_observation(&reference).await.unwrap().unwrap().outcome,
OperationOutcome::Returned { value: privacy });
let (stale, _) = mutate(&fixture, "updateAssistantPreferences", json!({
"expectedRevision":current["revision"],
"mutation":{"kind":"privacy","incognitoActive":false}
}), None).await;
assert_eq!(stale["kind"], "revision_conflict");
let current = query(&fixture, "assistantPreferences", json!({})).await;
assert_eq!(current["shellTitles"], true);
let (disabled, reference) = mutate(&fixture, "updateAssistantPreferences", json!({
"expectedRevision":current["revision"],
"mutation":{"kind":"shell_titles","enabled":false}
}), None).await;
assert_eq!(disabled["kind"], "committed");
assert_eq!(query(&fixture, "assistantPreferences", json!({})).await["shellTitles"], false);
assert!(!fixture.config.runtime_policy().await.unwrap().policy.shell.titles);
assert_eq!(fixture.store.operation_observation(&reference).await.unwrap().unwrap().outcome,
OperationOutcome::Returned { value: disabled });
let (stale, _) = mutate(&fixture, "updateAssistantPreferences", json!({
"expectedRevision":current["revision"],
"mutation":{"kind":"shell_titles","enabled":true}
}), None).await;
assert_eq!(stale["kind"], "revision_conflict");
assert_eq!(query(&fixture, "assistantPreferences", json!({})).await["shellTitles"], false);
fixture.app.shutdown().await.unwrap();
fixture.config.shutdown().await.unwrap();
}).await.unwrap();
}
#[tokio::test]
async fn native_usage_keeps_request_quotes_and_settlement_fences_across_price_changes() {
tokio::time::timeout(Duration::from_secs(60), async {
let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
let fixture = Fixture::new(&format!("http://{}/v1", listener.local_addr().unwrap()), None).await;
let page = query(&fixture, "prices", json!({"kind":"start"})).await;
let price = |revision: Value, input: f64| json!({
"expectedRevision": revision,
"mutation":{"kind":"upsert","pricing":{"modelKey":"openai-compatible:fixture-model","inputUsdPer1M":input,"outputUsdPer1M":20.0}}
});
let (saved, reference) = mutate(&fixture, "updatePrice", price(page["revision"].clone(), 10.0), None).await;
assert_eq!(saved["result"]["kind"], "committed");
assert_eq!(fixture.store.operation_observation(&reference).await.unwrap().unwrap().outcome,
OperationOutcome::Returned { value: saved.clone() });
let session = fixture.create("Physical usage").await;
fixture.send(&session).await.unwrap();
let (mut first, _) = listener.accept().await.unwrap();
request(&mut first).await;
// Change prices while the first provider request is still in flight.
let (changed, _) = mutate(&fixture, "updatePrice", price(saved["result"]["revision"].clone(), 100.0), None).await;
assert_eq!(changed["result"]["kind"], "committed");
let (stale, _) = mutate(&fixture, "updatePrice", price(saved["result"]["revision"].clone(), 1000.0), None).await;
assert_eq!(stale["result"]["kind"], "revision_conflict");
response(&mut first).await;
fixture.drained().await;
let range = json!({"from":0,"to":9_007_199_254_740_991u64,"sessionId":session,"through":null});
let original = query(&fixture, "usageSummary", json!({"range":range,"group":"byProvider","offset":0})).await;
assert_eq!(original["summary"]["models"]["calls"], 1);
let cost = original["summary"]["models"]["cost"]["knownUsd"].as_f64().unwrap();
assert!((cost - 0.00005).abs() < 1e-12, "first request must retain original quote: {original}");
let mut frozen = range.clone();
frozen["through"] = original["through"].clone();
fixture.send(&session).await.unwrap();
let (mut second, _) = listener.accept().await.unwrap();
request(&mut second).await;
response(&mut second).await;
fixture.drained().await;
assert_eq!(query(&fixture, "usageSummary", json!({"range":frozen,"group":"byProvider","offset":0})).await, original);
let activity = query(&fixture, "usage", json!({"range":frozen,"selection":{"kind":null,"status":null,"search":""},"offset":0})).await;
assert_eq!(activity["total"], 1);
assert_eq!(activity["attempts"][0]["attempt"]["quote"]["pricing"]["inputUsdPer1M"], 10.0);
let latest = query(&fixture, "usageSummary", json!({"range":range,"group":"byProvider","offset":0})).await;
assert_eq!(latest["summary"]["models"]["calls"], 2);
assert_eq!(latest["summary"]["models"]["input"]["known"], 2);
assert_eq!(latest["summary"]["models"]["output"]["known"], 4);
assert_eq!(latest["summary"]["models"]["cost"]["unvalued"], 0);
assert!((latest["summary"]["models"]["cost"]["knownUsd"].as_f64().unwrap() - 0.00019).abs() < 1e-12);
fixture.app.shutdown().await.unwrap();
fixture.config.shutdown().await.unwrap();
}).await.unwrap();
}
#[tokio::test]
async fn host_proxy_settings_route_model_requests_and_keep_atomic_credential_receipts() {
tokio::time::timeout(Duration::from_secs(30), async {
let proxy = TcpListener::bind("127.0.0.1:0").await.unwrap();
let fixture = Fixture::new("http://proxy-target.invalid/v1", None).await;
let original = query(&fixture, "network", json!({})).await;
assert_eq!(original["rootPath"], fixture.root.canonicalize().unwrap().to_str().unwrap());
assert_eq!(original["rootId"], fixture.store.owned_root().unwrap().root_id());
let mut policy = original["proxy"].clone();
policy["enabled"] = json!(true);
policy["protocol"] = json!("http");
policy["host"] = json!("127.0.0.1");
policy["port"] = json!(proxy.local_addr().unwrap().port());
policy["authEnabled"] = json!(true);
policy["username"] = json!("proxy-user");
policy["bypassList"] = json!([]);
policy["autoBypassDomains"] = json!([]);
let update = json!({"expectedPolicyRevision":original["revision"],"expectedCredential":null,"networkProxy":policy,"credential":"replace"});
let (saved, reference) = mutate(&fixture, "updateNetwork", update.clone(), Some("private-proxy-password")).await;
assert_eq!(saved["result"]["kind"], "committed");
let current = query(&fixture, "network", json!({})).await;
assert_eq!(current["proxy"], policy);
assert_eq!(current["credential"]["configured"], true);
assert!(!current.to_string().contains("private-proxy-password"));
assert_eq!(fixture.config.network_configuration().await.unwrap().password.as_deref(), Some("private-proxy-password"));
assert_eq!(fixture.store.operation_observation(&reference).await.unwrap().unwrap().outcome,
OperationOutcome::Returned { value: saved.clone() });
let (stale, _) = mutate(&fixture, "updateNetwork", update, Some("different-password")).await;
assert_eq!(stale["result"]["kind"], "revision_conflict");
let session = fixture.create("Proxy route").await;
fixture.send(&session).await.unwrap();
// This hostname is deliberately unresolvable. Receiving the request at
// the local proxy proves the actual native model transport uses settings.
let (mut stream, _) = proxy.accept().await.unwrap();
let sent = request(&mut stream).await;
assert_eq!(sent["model"], "fixture-model");
response(&mut stream).await;
fixture.drained().await;
let mut disabled = policy;
disabled["enabled"] = json!(false);
disabled["authEnabled"] = json!(false);
let delete = json!({"expectedPolicyRevision":current["revision"],"expectedCredential":{
"locator":current["credential"]["locator"],"credentialId":current["credential"]["credentialId"],"revision":current["credential"]["revision"]
},"networkProxy":disabled,"credential":"delete"});
let (removed, _) = mutate(&fixture, "updateNetwork", delete.clone(), None).await;
assert_eq!(removed["result"]["kind"], "committed");
let final_state = fixture.config.network_configuration().await.unwrap();
assert!(!final_state.proxy.enabled && !final_state.proxy.auth_enabled && final_state.password.is_none());
let mut stale_credential = delete;
stale_credential["expectedPolicyRevision"] = removed["result"]["revision"].clone();
let (stale, _) = mutate(&fixture, "updateNetwork", stale_credential, None).await;
assert_eq!(stale["result"]["kind"], "credential_stale");
let observation = fixture.store.operation_observation(&reference).await.unwrap().unwrap();
assert_eq!(observation.outcome, OperationOutcome::Returned { value: saved });
fixture.app.shutdown().await.unwrap();
fixture.config.shutdown().await.unwrap();
}).await.unwrap();
}
#[tokio::test]
async fn saved_model_survives_restart_and_resolves_locally_at_the_current_revision() {
tokio::time::timeout(Duration::from_secs(30), async {
let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
let mut f = Fixture::new(&format!("http://{}/v1", listener.local_addr().unwrap()), None).await;
let session = f.create("Remember my model").await;
let model = f.selection().await;
let backend = json!({"kind":"model","connectionId":model.connection_id,"modelId":model.model_id,"thinkingLevel":null});
let saved = f.mutation(2, "selectBackend", json!({"sessionId":session,"backend":backend}), Uuid::new_v4()).await.unwrap();
assert_eq!(saved["kind"], "committed");
todo_tests::reopen(&mut f).await;
let observed = f.query("observe", json!({"sessionId":session})).await.unwrap();
assert_eq!(observed["session"]["backend"], backend);
selection::edit(&f, |changes| changes.name = Some("Renamed connection".into())).await;
let target = json!({"connectionId":model.connection_id,"modelId":model.model_id});
let resolved = query(&f, "resolveModel", target.clone()).await;
assert_eq!(resolved["kind"], "ready");
assert_eq!(resolved["choice"]["connectionName"], "Renamed connection");
assert!(resolved["choice"]["selection"]["revision"].as_u64().unwrap() > model.revision);
selection::edit(&f, |changes| changes.model_overrides = Patch::Set(BTreeMap::from([
("fixture-model".into(), ModelOverride { thinking_levels: Some(vec![maka_agent_facts::execution::ThinkingLevel::High]), ..Default::default() }),
("other-model".into(), ModelOverride { code_mode: Some(true), ..Default::default() }),
]))).await;
let current = query(&f, "resolveModel", target.clone()).await;
let update = json!({"selection":current["choice"]["selection"],"tools":{"codeMode":false,"codeModeLanguage":"python","applyPatch":true},"limits":{"contextWindow":100000,"inputLimit":90000,"maxOutputTokens":4000,"compactionThreshold":80000}});
let (saved, _) = mutate(&f, "updateModelSettings", update.clone(), None).await;
assert_eq!(saved["kind"], "committed");
assert_eq!(mutate(&f, "updateModelSettings", update, None).await.0["kind"], "connection_stale");
todo_tests::reopen(&mut f).await;
let current = query(&f, "resolveModel", target.clone()).await;
assert_eq!(current["choice"]["tools"], json!({"codeMode":false,"codeModeLanguage":"python","applyPatch":true}));
let overrides = f.config.catalog().await.unwrap().connections.remove(0).model_overrides.unwrap();
assert_eq!(current["choice"]["limits"]["overrides"], json!({"contextWindow":100000,"inputLimit":90000,"maxOutputTokens":4000,"compactionThreshold":80000}));
assert_eq!(current["choice"]["limits"]["contextWindow"], 100000);
assert_eq!(overrides["fixture-model"].max_output_tokens, Some(4000));
let (_, prepared) = crate::model::Source::select(
f.config.clone(), f.owner.catalog.clone(), f.owner.credentials.clone(), f.selection().await,
None, session.clone(), f.owner.revision.clone(),
).await.unwrap();
assert_eq!(prepared.main_output_limit, Some(4000));
let context = prepared.context.unwrap();
assert_eq!(context.model_context_window, Some(100000));
assert_eq!(context.context_window, Some(90000));
assert_eq!(context.declared_window, Some(80000));
assert_eq!(overrides["other-model"].code_mode, Some(true));
assert_eq!(overrides["fixture-model"].thinking_levels, Some(vec![maka_agent_facts::execution::ThinkingLevel::High]));
let (reset, _) = mutate(&f, "updateModelSettings", json!({"selection":current["choice"]["selection"],"tools":{"codeMode":null,"codeModeLanguage":null,"applyPatch":null},"limits":{"contextWindow":null,"inputLimit":null,"maxOutputTokens":null,"compactionThreshold":null}}), None).await;
assert_eq!(reset["kind"], "committed");
let current = query(&f, "resolveModel", target.clone()).await;
assert_eq!(current["choice"]["tools"], json!({"codeMode":null,"codeModeLanguage":null,"applyPatch":null}));
selection::edit(&f, |changes| changes.enabled = Some(false)).await;
assert_eq!(query(&f, "resolveModel", target).await["kind"], "unavailable");
assert!(tokio::time::timeout(Duration::from_millis(50), listener.accept()).await.is_err(), "restore must not contact the provider");
f.app.shutdown().await.unwrap();
f.config.shutdown().await.unwrap();
}).await.unwrap();
}
#[tokio::test]
async fn compaction_preferences_accept_custom_prompt_and_reset_to_default() {
let f = Fixture::new("http://127.0.0.1:1/v1", None).await;
let initial = query(&f, "assistantPreferences", json!({})).await;
assert_eq!(
initial["compactionPrompt"],
initial["defaultCompactionPrompt"]
);
let (saved,_) = mutate(&f,"updateAssistantPreferences",json!({"expectedRevision":initial["revision"],"mutation":{"kind":"compaction_prompt","prompt":"Custom freeform instructions"}}),None).await;
assert_eq!(saved["kind"], "committed");
let custom = query(&f, "assistantPreferences", json!({})).await;
assert_eq!(custom["compactionPrompt"], "Custom freeform instructions");
let (reset,_) = mutate(&f,"updateAssistantPreferences",json!({"expectedRevision":custom["revision"],"mutation":{"kind":"compaction_prompt","prompt":null}}),None).await;
assert_eq!(reset["kind"], "committed");
let reset = query(&f, "assistantPreferences", json!({})).await;
assert_eq!(
reset["compactionPrompt"],
initial["defaultCompactionPrompt"]
);
f.app.shutdown().await.unwrap();
}
#[tokio::test]
async fn global_instruction_api_and_admission_share_one_selected_file() {
use futures_util::FutureExt;
use std::panic::AssertUnwindSafe;
let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
let f = Fixture::configured(
&format!("http://{}/v1", listener.local_addr().unwrap()),
None,
None,
None,
|settings| {
settings.assistant = Some(AssistantConfiguration {
home: Some(
settings.workspace_roots[0]
.path
.parent()
.unwrap()
.to_str()
.unwrap()
.into(),
),
})
},
)
.await;
let completed = tokio::time::timeout(Duration::from_secs(60), AssertUnwindSafe(async {
// Declare the controlled HTTP model's capacity for the full-file prompt.
// Ordinary model context admission remains active.
selection::edit(&f, |changes| {
changes.model_overrides = Patch::Set(BTreeMap::from([("fixture-model".into(), ModelOverride {
context_window: Some(1_000_000), input_limit: Some(900_000), ..Default::default()
})]));
}).await;
let home = f._dir.path();
std::fs::create_dir(home.join(".agents")).unwrap();
std::fs::create_dir(home.join(".maka")).unwrap();
std::fs::write(home.join(".agents/AGENTS.md"), "FALLBACK UNIQUE").unwrap();
std::fs::write(home.join(".maka/CLAUDE.md"), "OTHER GLOBAL GUIDANCE").unwrap();
std::fs::write(f.workspace.join("AGENTS.md"), "PROJECT GUIDANCE").unwrap();
let session = f.create("Global instructions").await;
let workspace = f.owner.session(&session).await.unwrap().configuration.workspace;
let policy = f.owner.configuration.runtime_policy().await.unwrap();
let language = f.owner.resolve_language(&policy);
let fallback = f.query("globalInstructions",json!({})).await.unwrap();
assert_eq!(fallback["source"],"agents");
assert_eq!(fallback["content"],"FALLBACK UNIQUE");
assert_eq!(fallback["path"], home.join(".agents/AGENTS.md").to_str().unwrap());
let prompt = f.owner.capture_behavior(&workspace, &policy, language).await.unwrap().unwrap().text;
assert!(prompt.starts_with("You are [Maka](https://github.com/apache/maka), an AI agent.\n\n<global_instruction>\nFALLBACK UNIQUE\n</global_instruction>\n\n"));
assert_eq!(prompt.matches("FALLBACK UNIQUE").count(), 1);
assert!(prompt.contains("<workspace-instructions file=\"CLAUDE.md\" scope=\"global\">\nOTHER GLOBAL GUIDANCE"));
assert!(prompt.contains("<workspace-instructions file=\"AGENTS.md\" scope=\"project\">\nPROJECT GUIDANCE"));
assert!(!prompt.contains("<workspace-instructions file=\"AGENTS.md\" scope=\"global\">"));
let mut disabled = policy.clone();
disabled.policy.workspace_instructions.enabled = false;
let without_instructions = f.owner.capture_behavior(&workspace, &disabled, language).await.unwrap().unwrap().text;
assert!(!without_instructions.contains("<global_instruction>"));
assert!(!without_instructions.contains("GUIDANCE"));
std::fs::write(home.join(".maka/AGENTS.md"), "").unwrap();
let empty = f.query("globalInstructions",json!({})).await.unwrap();
assert_eq!(empty["source"],"maka");
assert_eq!(empty["content"],"");
let prompt = f.owner.capture_behavior(&workspace, &policy, language).await.unwrap().unwrap().text;
assert!(!prompt.contains("FALLBACK UNIQUE"));
assert!(!prompt.contains("<global_instruction>"));
let stale = f.mutation(2,"updateGlobalInstructions",json!({"source":fallback["source"],"revision":fallback["revision"],"content":"STALE"}),Uuid::new_v4()).await.unwrap();
assert_eq!(stale["kind"],"changed");
assert_eq!(std::fs::read_to_string(home.join(".agents/AGENTS.md")).unwrap(),"FALLBACK UNIQUE");
let input = json!({"source":empty["source"],"revision":empty["revision"],"content":"SAVED GLOBAL UNIQUE"});
let operation = Uuid::new_v4();
let saved = f.mutation(2,"updateGlobalInstructions",input.clone(),operation).await.unwrap();
assert_eq!(saved["kind"],"saved");
assert_eq!(f.send(&session).await.unwrap()["kind"],"started");
let (mut socket,_) = listener.accept().await.unwrap();
let sent = request(&mut socket).await;
let system = sent["messages"].as_array().unwrap().iter().filter(|m|m["role"]=="system")
.map(|m|m["content"].as_str().unwrap()).collect::<Vec<_>>().join("\n");
assert!(system.starts_with("You are [Maka](https://github.com/apache/maka), an AI agent.\n\n<global_instruction>\nSAVED GLOBAL UNIQUE\n</global_instruction>\n\n"));
assert_eq!(system.matches("SAVED GLOBAL UNIQUE").count(), 1);
assert!(system.contains("OTHER GLOBAL GUIDANCE") && system.contains("PROJECT GUIDANCE"));
assert!(!system.contains("<workspace-instructions file=\"AGENTS.md\" scope=\"global\">"));
assert!(!system.contains("FALLBACK UNIQUE"));
response(&mut socket).await;
f.drained().await;
std::fs::write(home.join(".maka/AGENTS.md"),"EXTERNAL CHANGE").unwrap();
assert_eq!(f.mutation(2,"updateGlobalInstructions",input.clone(),operation).await.unwrap(),saved);
assert_eq!(std::fs::read_to_string(home.join(".maka/AGENTS.md")).unwrap(),"EXTERNAL CHANGE");
assert_eq!(f.mutation(2,"updateGlobalInstructions",input,Uuid::new_v4()).await.unwrap()["kind"],"changed");
// One selected, valid UTF-8 file beyond both former editor and prompt limits.
let large = format!("# GLOBAL ORIGINAL START\n{}GLOBAL ORIGINAL END",
"Preserve δΈ­ζ–‡πŸ˜€ exactly.\n".repeat(40_000));
assert!(large.len() > 1024 * 1024);
let path = home.join(".maka/AGENTS.md");
std::fs::write(&path, &large).unwrap();
let available = f.query("globalInstructions", json!({})).await.unwrap();
assert_eq!(available["kind"], "available", "the full selected file must be available through the native API");
assert_eq!(available["source"], "maka");
assert_eq!(available["path"], path.to_str().unwrap());
assert_eq!(available["exists"], true);
let content = available["content"].as_str().unwrap();
assert!(content.as_bytes() == large.as_bytes(),
"complete read differs: got {} bytes, expected {}", content.len(), large.len());
assert!(std::fs::read(&path).unwrap() == large.as_bytes(), "reading changed the selected file");
let edited = large.replace("ORIGINAL START", "EDITED START").replace("ORIGINAL END", "EDITED END");
let saved = f.mutation(2, "updateGlobalInstructions", json!({
"source":available["source"], "revision":available["revision"], "content":edited
}), Uuid::new_v4()).await.unwrap();
assert_eq!(saved["kind"], "saved");
assert!(std::fs::read(&path).unwrap() == edited.as_bytes(), "update did not save every edited byte");
let updated = f.query("globalInstructions", json!({})).await.unwrap();
assert_eq!(updated["kind"], "available");
let content = updated["content"].as_str().unwrap();
assert!(content.as_bytes() == edited.as_bytes(),
"complete saved read differs: got {} bytes, expected {}", content.len(), edited.len());
assert_eq!(f.send(&session).await.unwrap()["kind"], "started");
let (mut socket, _) = listener.accept().await.unwrap();
let sent = request(&mut socket).await;
response(&mut socket).await;
f.drained().await;
let system = sent["messages"].as_array().unwrap().iter().filter(|m| m["role"] == "system")
.map(|m| m["content"].as_str().unwrap()).collect::<Vec<_>>().join("\n");
let global = system.strip_prefix("You are [Maka](https://github.com/apache/maka), an AI agent.\n\n<global_instruction>\n")
.and_then(|body| body.split_once("\n</global_instruction>")).expect("selected global instruction block").0;
assert!(global.as_bytes() == edited.as_bytes(),
"HTTP global instructions differ: got {} bytes, expected {}", global.len(), edited.len());
assert_eq!(system.matches("<global_instruction>").count(), 1);
assert!(system.contains("OTHER GLOBAL GUIDANCE") && system.contains("PROJECT GUIDANCE"));
assert!(!system.contains("<workspace-instructions file=\"AGENTS.md\" scope=\"global\">"));
assert!(!system.contains("FALLBACK UNIQUE"));
assert_eq!(std::fs::read_to_string(home.join(".agents/AGENTS.md")).unwrap(), "FALLBACK UNIQUE");
assert_eq!(std::fs::read_to_string(home.join(".maka/CLAUDE.md")).unwrap(), "OTHER GLOBAL GUIDANCE");
assert_eq!(std::fs::read_to_string(f.workspace.join("AGENTS.md")).unwrap(), "PROJECT GUIDANCE");
}).catch_unwind()).await;
let app_shutdown = f.app.shutdown().await;
let config_shutdown = f.config.shutdown().await;
app_shutdown.unwrap();
config_shutdown.unwrap();
completed
.expect("global instruction API and prompt sequence timed out")
.unwrap_or_else(|panic| std::panic::resume_unwind(panic));
}