mirror of
https://wget.la/https://github.com/leookun/cursor-byok
synced 2026-10-06 05:12:03 +08:00
merge old config
This commit is contained in:
+25
-29
@@ -9,8 +9,8 @@ use cursor_server::{
|
||||
cursor::prompting::{PromptAssets, PromptCompiler},
|
||||
cursor::{connect, proto::agent::v1 as pb, CursorCommand, CursorSessionRegistry},
|
||||
model::{
|
||||
ContentPart, ConversationId, MessageContent, Origin, ProjectedContent,
|
||||
ProviderEndpointInput, ProviderModelInput, ProviderType, Role, Usage,
|
||||
ContentPart, ConversationId, MessageContent, ModelConfigInput, ModelType, Origin,
|
||||
ProjectedContent, Role, Usage, OPENAI_CHAT_ENDPOINT,
|
||||
},
|
||||
provider::{FinishReason, ModelEvent},
|
||||
};
|
||||
@@ -19,34 +19,30 @@ use prost::Message;
|
||||
#[tokio::test]
|
||||
async fn summarize_replaces_model_history_and_preserves_cursor_history() {
|
||||
let (_directory, store) = fixtures::temp_store().await;
|
||||
let endpoint = store
|
||||
.create_provider(&ProviderEndpointInput {
|
||||
name: "Test".into(),
|
||||
provider_type: ProviderType::OpenAiChat,
|
||||
base_url: "https://example.com/v1".into(),
|
||||
api_key: None,
|
||||
custom_headers: serde_json::json!({}),
|
||||
extra_params: serde_json::json!({}),
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
let model = store
|
||||
.save_provider_model(
|
||||
endpoint.provider_id,
|
||||
&ProviderModelInput {
|
||||
model_id: "test-model".into(),
|
||||
display_name: "Test Model".into(),
|
||||
endpoint_type: ProviderType::OpenAiChat,
|
||||
request_url: String::new(),
|
||||
enabled: true,
|
||||
sort_order: 0,
|
||||
context_window_tokens: None,
|
||||
max_output_tokens: None,
|
||||
reasoning_enabled: false,
|
||||
reasoning_effort: None,
|
||||
supports_image_generation: false,
|
||||
},
|
||||
)
|
||||
.create_model(&ModelConfigInput {
|
||||
sort_order: 0,
|
||||
display_name: "Test Model".into(),
|
||||
model_type: ModelType::OpenAi,
|
||||
base_url: "https://example.com/v1/chat/completions".into(),
|
||||
use_full_url: true,
|
||||
api_key: "test-key".into(),
|
||||
tooltip_data: "Test Model".into(),
|
||||
model_id: "test-model".into(),
|
||||
reasoning_effort: None,
|
||||
openai_endpoint: OPENAI_CHAT_ENDPOINT.into(),
|
||||
openai_extra_params_enabled: false,
|
||||
openai_extra_params: serde_json::json!({}),
|
||||
custom_headers_enabled: false,
|
||||
custom_headers: serde_json::json!({}),
|
||||
anthropic_extra_params_enabled: false,
|
||||
anthropic_extra_params: serde_json::json!({}),
|
||||
context_window_tokens: None,
|
||||
max_completion_tokens: None,
|
||||
anthropic_max_tokens: None,
|
||||
anthropic_thinking_effort: None,
|
||||
thinking_budget_tokens: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
let provider = fake_provider::FakeProvider::default();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use cursor_server::{
|
||||
model::{
|
||||
ConversationId, ModelSpec, NewLlmCall, PreparedRun, PromptSpec, ProviderEndpointInput,
|
||||
ProviderModelInput, ProviderType, RunAction, RunId, RunKind, Usage,
|
||||
ConversationId, ModelConfigInput, ModelSpec, ModelType, NewLlmCall, PreparedRun,
|
||||
PromptSpec, ProviderType, RunAction, RunId, RunKind, Usage, OPENAI_CHAT_ENDPOINT,
|
||||
},
|
||||
store::{RunStatus, Store},
|
||||
};
|
||||
@@ -13,107 +13,91 @@ async fn store() -> (tempfile::TempDir, Store) {
|
||||
(directory, store)
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn provider_secret_is_write_only_and_model_hash_is_stable() {
|
||||
let (_directory, store) = store().await;
|
||||
let provider = store
|
||||
.create_provider(&ProviderEndpointInput {
|
||||
name: "Local".into(),
|
||||
provider_type: ProviderType::OpenAiChat,
|
||||
base_url: "https://example.com/v1/".into(),
|
||||
api_key: Some("secret".into()),
|
||||
custom_headers: serde_json::json!({"x-route":"one", "authorization":"header-secret"}),
|
||||
extra_params: serde_json::json!({"temperature":0}),
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(provider.has_api_key);
|
||||
assert!(!serde_json::to_string(&provider).unwrap().contains("secret"));
|
||||
assert_eq!(
|
||||
provider.custom_headers["authorization"],
|
||||
serde_json::Value::Null
|
||||
);
|
||||
let updated = store
|
||||
.update_provider(
|
||||
provider.provider_id,
|
||||
&ProviderEndpointInput {
|
||||
name: "Renamed".into(),
|
||||
provider_type: provider.provider_type,
|
||||
base_url: provider.base_url.clone(),
|
||||
api_key: None,
|
||||
custom_headers: provider.custom_headers.clone(),
|
||||
extra_params: provider.extra_params.clone(),
|
||||
},
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(updated.name, "Renamed");
|
||||
assert_eq!(
|
||||
store
|
||||
.provider(provider.provider_id)
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.custom_headers["authorization"],
|
||||
"header-secret"
|
||||
);
|
||||
fn model_input() -> ModelConfigInput {
|
||||
ModelConfigInput {
|
||||
sort_order: 0,
|
||||
display_name: "Model A".into(),
|
||||
model_type: ModelType::OpenAi,
|
||||
base_url: "https://example.com/v1/chat/completions".into(),
|
||||
use_full_url: true,
|
||||
api_key: "secret".into(),
|
||||
tooltip_data: "Model A".into(),
|
||||
model_id: "model-a".into(),
|
||||
reasoning_effort: None,
|
||||
openai_endpoint: OPENAI_CHAT_ENDPOINT.into(),
|
||||
openai_extra_params_enabled: true,
|
||||
openai_extra_params: serde_json::json!({"temperature":0}),
|
||||
custom_headers_enabled: true,
|
||||
custom_headers: serde_json::json!({"x-route":"one"}),
|
||||
anthropic_extra_params_enabled: false,
|
||||
anthropic_extra_params: serde_json::json!({}),
|
||||
context_window_tokens: None,
|
||||
max_completion_tokens: None,
|
||||
anthropic_max_tokens: None,
|
||||
anthropic_thinking_effort: None,
|
||||
thinking_budget_tokens: None,
|
||||
}
|
||||
}
|
||||
|
||||
let model = store
|
||||
.save_provider_model(
|
||||
provider.provider_id,
|
||||
&ProviderModelInput {
|
||||
model_id: "model-a".into(),
|
||||
display_name: "Model A".into(),
|
||||
endpoint_type: ProviderType::OpenAiChat,
|
||||
request_url: String::new(),
|
||||
enabled: true,
|
||||
sort_order: 0,
|
||||
context_window_tokens: None,
|
||||
max_output_tokens: None,
|
||||
reasoning_enabled: false,
|
||||
reasoning_effort: None,
|
||||
supports_image_generation: true,
|
||||
},
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(model.model_hash, "bab5019a");
|
||||
assert!(model.supports_image_generation);
|
||||
#[tokio::test]
|
||||
async fn model_configuration_round_trips_and_hash_uses_v0049_identity() {
|
||||
let (_directory, store) = store().await;
|
||||
let model = store.create_model(&model_input()).await.unwrap();
|
||||
assert_eq!(model.model_hash.len(), 16);
|
||||
assert_eq!(model.api_key, "secret");
|
||||
assert_eq!(model.custom_headers["x-route"], "one");
|
||||
|
||||
let original_hash = model.model_hash.clone();
|
||||
let mut input = model_input();
|
||||
input.base_url = "https://example.com/v1/chat/completions".into();
|
||||
input.sort_order = 3;
|
||||
input.tooltip_data = "Updated tooltip".into();
|
||||
let updated = store.update_model(&original_hash, &input).await.unwrap();
|
||||
assert_eq!(updated.model_hash, original_hash);
|
||||
assert_eq!(updated.sort_order, 3);
|
||||
assert_eq!(updated.tooltip_data, "Updated tooltip");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn arbitrary_request_url_is_independent_from_openai_protocol() {
|
||||
let (_directory, store) = store().await;
|
||||
let mut input = model_input();
|
||||
input.base_url = "https://proxy.example.com/arbitrary/generate?api-version=2026-01-01".into();
|
||||
|
||||
let chat = store.create_model(&input).await.unwrap();
|
||||
assert_eq!(chat.provider_type(), ProviderType::OpenAiChat);
|
||||
assert_eq!(chat.request_url().unwrap(), input.base_url);
|
||||
|
||||
input.openai_endpoint = "/v1/responses".into();
|
||||
let responses = store.update_model(&chat.model_hash, &input).await.unwrap();
|
||||
assert_eq!(responses.provider_type(), ProviderType::OpenAiResponses);
|
||||
assert_eq!(responses.request_url().unwrap(), input.base_url);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn standard_server_address_resolves_to_the_same_model_identity_as_a_complete_url() {
|
||||
let (_directory, store) = store().await;
|
||||
let complete = model_input();
|
||||
let mut standard = complete.clone();
|
||||
standard.base_url = "https://example.com/v1".into();
|
||||
standard.use_full_url = false;
|
||||
|
||||
let model = store.create_model(&standard).await.unwrap();
|
||||
assert!(!model.use_full_url);
|
||||
assert_eq!(
|
||||
model.request_url().unwrap(),
|
||||
"https://example.com/v1/chat/completions"
|
||||
);
|
||||
assert_eq!(
|
||||
model.model_hash,
|
||||
cursor_server::model::model_hash(&complete).unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn call_summary_is_always_stored_and_payloads_follow_detailed_setting() {
|
||||
let (_directory, store) = store().await;
|
||||
let provider = store
|
||||
.create_provider(&ProviderEndpointInput {
|
||||
name: "Local".into(),
|
||||
provider_type: ProviderType::OpenAiChat,
|
||||
base_url: "https://example.com/v1".into(),
|
||||
api_key: None,
|
||||
custom_headers: serde_json::json!({}),
|
||||
extra_params: serde_json::json!({}),
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
let model = store
|
||||
.save_provider_model(
|
||||
provider.provider_id,
|
||||
&ProviderModelInput {
|
||||
model_id: "model-a".into(),
|
||||
display_name: "Model A".into(),
|
||||
endpoint_type: ProviderType::OpenAiChat,
|
||||
request_url: String::new(),
|
||||
enabled: true,
|
||||
sort_order: 0,
|
||||
context_window_tokens: None,
|
||||
max_output_tokens: None,
|
||||
reasoning_enabled: false,
|
||||
reasoning_effort: None,
|
||||
supports_image_generation: false,
|
||||
},
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
let model = store.create_model(&model_input()).await.unwrap();
|
||||
let call = NewLlmCall {
|
||||
call_id: "call-1".into(),
|
||||
run_id: "run-1".into(),
|
||||
@@ -121,7 +105,7 @@ async fn call_summary_is_always_stored_and_payloads_follow_detailed_setting() {
|
||||
provider_call_index: 0,
|
||||
model_hash: model.model_hash,
|
||||
provider_type: ProviderType::OpenAiChat,
|
||||
provider_url: provider.base_url,
|
||||
provider_url: model.base_url.clone(),
|
||||
request_type: ProviderType::OpenAiChat,
|
||||
request_url: "https://example.com/v1/chat/completions".into(),
|
||||
model_id: model.model_id,
|
||||
@@ -3,8 +3,8 @@ use std::time::Duration;
|
||||
use axum::{http::header, response::IntoResponse, routing::post, Router};
|
||||
use cursor_server::{
|
||||
model::{
|
||||
ModelInvocation, ModelRequest, ModelSpec, PromptSpec, ProviderEndpointInput,
|
||||
ProviderModelInput, ProviderType,
|
||||
ModelConfigInput, ModelInvocation, ModelRequest, ModelSpec, ModelType, PromptSpec,
|
||||
OPENAI_CHAT_ENDPOINT,
|
||||
},
|
||||
provider::{ModelEvent, Provider, ProviderRouter},
|
||||
store::Store,
|
||||
@@ -105,7 +105,7 @@ async fn cursor_trace_links_detailed_artifacts_to_the_logical_run() {
|
||||
#[tokio::test]
|
||||
async fn records_one_summary_and_raw_payloads_for_one_provider_request() {
|
||||
let app = Router::new().route(
|
||||
"/v1/chat/completions",
|
||||
"/proxy/generate",
|
||||
post(|| async {
|
||||
(
|
||||
[(header::CONTENT_TYPE, "text/event-stream")],
|
||||
@@ -124,34 +124,30 @@ async fn records_one_summary_and_raw_payloads_for_one_provider_request() {
|
||||
|
||||
let (_directory, store) = test_store("observability.db").await;
|
||||
store.set_detailed_logging(true).await.unwrap();
|
||||
let endpoint = store
|
||||
.create_provider(&ProviderEndpointInput {
|
||||
name: "test".into(),
|
||||
provider_type: ProviderType::OpenAiChat,
|
||||
base_url: format!("http://{address}/v1"),
|
||||
api_key: Some("not-recorded".into()),
|
||||
custom_headers: serde_json::json!({"x-safe":"visible","authorization":"hidden"}),
|
||||
extra_params: serde_json::json!({}),
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
let model = store
|
||||
.save_provider_model(
|
||||
endpoint.provider_id,
|
||||
&ProviderModelInput {
|
||||
model_id: "actual-model".into(),
|
||||
display_name: "Display Model".into(),
|
||||
endpoint_type: ProviderType::OpenAiChat,
|
||||
request_url: String::new(),
|
||||
enabled: true,
|
||||
sort_order: 0,
|
||||
context_window_tokens: None,
|
||||
max_output_tokens: None,
|
||||
reasoning_enabled: false,
|
||||
reasoning_effort: None,
|
||||
supports_image_generation: false,
|
||||
},
|
||||
)
|
||||
.create_model(&ModelConfigInput {
|
||||
sort_order: 0,
|
||||
display_name: "Display Model".into(),
|
||||
model_type: ModelType::OpenAi,
|
||||
base_url: format!("http://{address}/proxy/generate"),
|
||||
use_full_url: true,
|
||||
api_key: "not-recorded".into(),
|
||||
tooltip_data: "Display Model".into(),
|
||||
model_id: "actual-model".into(),
|
||||
reasoning_effort: None,
|
||||
openai_endpoint: OPENAI_CHAT_ENDPOINT.into(),
|
||||
openai_extra_params_enabled: false,
|
||||
openai_extra_params: serde_json::json!({}),
|
||||
custom_headers_enabled: true,
|
||||
custom_headers: serde_json::json!({"x-safe":"visible","authorization":"hidden"}),
|
||||
anthropic_extra_params_enabled: false,
|
||||
anthropic_extra_params: serde_json::json!({}),
|
||||
context_window_tokens: None,
|
||||
max_completion_tokens: None,
|
||||
anthropic_max_tokens: None,
|
||||
anthropic_thinking_effort: None,
|
||||
thinking_budget_tokens: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
let provider = ProviderRouter::new(store.clone(), Duration::from_secs(5));
|
||||
@@ -183,7 +179,7 @@ async fn records_one_summary_and_raw_payloads_for_one_provider_request() {
|
||||
let call = store.llm_call("call-1").await.unwrap().unwrap();
|
||||
assert_eq!(call.status, "completed");
|
||||
assert_eq!(call.request_type, "openai-chat");
|
||||
assert!(call.request_url.ends_with("/v1/chat/completions"));
|
||||
assert_eq!(call.request_url, format!("http://{address}/proxy/generate"));
|
||||
assert_eq!(call.total_tokens, Some(12));
|
||||
assert!(call.ttfb_ms.is_some());
|
||||
assert!(call.ttft_ms.is_some());
|
||||
|
||||
@@ -41,3 +41,174 @@ async fn version_two_database_upgrades_with_cursor_request_mapping() {
|
||||
.iter()
|
||||
.any(|column| column.get::<String, _>("name") == "cursor_request_id"));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn provider_and_model_rows_upgrade_to_flat_model_configuration() {
|
||||
let directory = tempfile::tempdir().unwrap();
|
||||
let database = directory.path().join("flat-model-upgrade.db");
|
||||
let pool = sqlx::SqlitePool::connect_with(
|
||||
SqliteConnectOptions::new()
|
||||
.filename(&database)
|
||||
.create_if_missing(true)
|
||||
.foreign_keys(true),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
let all = sqlx::migrate!("./migrations");
|
||||
let prior = Migrator {
|
||||
migrations: Cow::Owned(
|
||||
all.iter()
|
||||
.filter(|migration| migration.version <= 3)
|
||||
.cloned()
|
||||
.collect(),
|
||||
),
|
||||
ignore_missing: false,
|
||||
locking: true,
|
||||
no_tx: false,
|
||||
};
|
||||
prior.run(&pool).await.unwrap();
|
||||
sqlx::query(
|
||||
r#"INSERT INTO provider_endpoints(
|
||||
name, provider_type, base_url, api_key, custom_headers_json, extra_params_json,
|
||||
created_at_ms, updated_at_ms
|
||||
) VALUES ('Example', 'openai-chat', 'https://example.com/v1', 'secret',
|
||||
'{"x-client":"cursor-byok"}', '{"service_tier":"priority"}', 10, 11)"#,
|
||||
)
|
||||
.execute(&pool)
|
||||
.await
|
||||
.unwrap();
|
||||
sqlx::query(
|
||||
r#"INSERT INTO provider_models(
|
||||
model_hash, provider_id, model_id, display_name, endpoint_type, request_url,
|
||||
enabled, sort_order, reasoning_enabled, supports_image_generation,
|
||||
created_at_ms, updated_at_ms
|
||||
) VALUES
|
||||
('rspns001', 1, 'model-b', 'Model B', 'openai-responses',
|
||||
'https://proxy.example.com/arbitrary/generate?api-version=2026-01-01',
|
||||
1, 5, 0, 0, 12, 13),
|
||||
('anthr001', 1, 'model-c', 'Model C', 'anthropic', '/proxy/claude',
|
||||
1, 6, 0, 0, 12, 13),
|
||||
('anthstd1', 1, 'model-d', 'Model D', 'anthropic', '',
|
||||
1, 7, 0, 0, 12, 13)"#,
|
||||
)
|
||||
.execute(&pool)
|
||||
.await
|
||||
.unwrap();
|
||||
sqlx::query(
|
||||
r#"INSERT INTO provider_models(
|
||||
model_hash, provider_id, model_id, display_name, endpoint_type, request_url,
|
||||
enabled, sort_order, context_window_tokens, max_output_tokens,
|
||||
reasoning_enabled, reasoning_effort, supports_image_generation,
|
||||
created_at_ms, updated_at_ms
|
||||
) VALUES ('12345678', 1, 'model-a', 'Model A', 'openai-chat', '',
|
||||
1, 4, 200000, 8192, 1, 'high', 0, 12, 13)"#,
|
||||
)
|
||||
.execute(&pool)
|
||||
.await
|
||||
.unwrap();
|
||||
sqlx::query(
|
||||
r#"INSERT INTO llm_calls(
|
||||
call_id, run_id, conversation_id, provider_call_index, model_hash,
|
||||
provider_type, provider_url, request_type, request_url, model_id, display_name,
|
||||
status, created_at_ms, message_count, tool_count, detailed
|
||||
) VALUES ('call-1', 'run-1', 'conversation-1', 0, '12345678',
|
||||
'openai-chat', 'https://example.com/v1', 'openai-chat',
|
||||
'https://example.com/v1/chat/completions', 'model-a', 'Model A',
|
||||
'completed', 14, 1, 0, 0)"#,
|
||||
)
|
||||
.execute(&pool)
|
||||
.await
|
||||
.unwrap();
|
||||
all.run(&pool).await.unwrap();
|
||||
drop(pool);
|
||||
|
||||
let store = Store::connect(&format!("sqlite://{}", database.display()))
|
||||
.await
|
||||
.unwrap();
|
||||
let row = sqlx::query(
|
||||
r#"SELECT model_hash, sort_order, display_name, model_type, base_url, api_key,
|
||||
tooltip_data, model_id, reasoning_effort, openai_endpoint, use_full_url,
|
||||
openai_extra_params_enabled, openai_extra_params_json,
|
||||
custom_headers_enabled, custom_headers_json, context_window_tokens,
|
||||
max_completion_tokens
|
||||
FROM model_configs WHERE model_hash = '12345678'"#,
|
||||
)
|
||||
.fetch_one(store.pool())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(row.get::<String, _>("model_hash"), "12345678");
|
||||
assert_eq!(row.get::<i64, _>("sort_order"), 4);
|
||||
assert_eq!(row.get::<String, _>("model_type"), "openai");
|
||||
assert_eq!(row.get::<String, _>("base_url"), "https://example.com/v1");
|
||||
assert_eq!(row.get::<String, _>("api_key"), "secret");
|
||||
assert_eq!(row.get::<i64, _>("use_full_url"), 0);
|
||||
assert_eq!(row.get::<String, _>("reasoning_effort"), "high");
|
||||
assert_eq!(
|
||||
row.get::<String, _>("openai_endpoint"),
|
||||
"/v1/chat/completions"
|
||||
);
|
||||
assert_eq!(row.get::<i64, _>("openai_extra_params_enabled"), 1);
|
||||
assert_eq!(
|
||||
row.get::<String, _>("openai_extra_params_json"),
|
||||
r#"{"service_tier":"priority"}"#
|
||||
);
|
||||
assert_eq!(row.get::<i64, _>("custom_headers_enabled"), 1);
|
||||
assert_eq!(row.get::<i64, _>("context_window_tokens"), 200000);
|
||||
assert_eq!(row.get::<i64, _>("max_completion_tokens"), 8192);
|
||||
let migrated_rows = sqlx::query(
|
||||
"SELECT model_hash, model_type, base_url, use_full_url, openai_endpoint FROM model_configs WHERE model_hash IN ('rspns001', 'anthr001', 'anthstd1') ORDER BY model_hash",
|
||||
)
|
||||
.fetch_all(store.pool())
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(migrated_rows[0].get::<String, _>("model_hash"), "anthr001");
|
||||
assert_eq!(migrated_rows[0].get::<String, _>("model_type"), "anthropic");
|
||||
assert_eq!(
|
||||
migrated_rows[0].get::<String, _>("base_url"),
|
||||
"https://example.com/v1/proxy/claude"
|
||||
);
|
||||
assert_eq!(migrated_rows[0].get::<i64, _>("use_full_url"), 1);
|
||||
assert_eq!(migrated_rows[0].get::<String, _>("openai_endpoint"), "");
|
||||
assert_eq!(migrated_rows[1].get::<String, _>("model_hash"), "anthstd1");
|
||||
assert_eq!(migrated_rows[1].get::<String, _>("model_type"), "anthropic");
|
||||
assert_eq!(
|
||||
migrated_rows[1].get::<String, _>("base_url"),
|
||||
"https://example.com/v1"
|
||||
);
|
||||
assert_eq!(migrated_rows[1].get::<i64, _>("use_full_url"), 0);
|
||||
assert_eq!(migrated_rows[1].get::<String, _>("openai_endpoint"), "");
|
||||
assert_eq!(migrated_rows[2].get::<String, _>("model_hash"), "rspns001");
|
||||
assert_eq!(migrated_rows[2].get::<String, _>("model_type"), "openai");
|
||||
assert_eq!(
|
||||
migrated_rows[2].get::<String, _>("base_url"),
|
||||
"https://proxy.example.com/arbitrary/generate?api-version=2026-01-01"
|
||||
);
|
||||
assert_eq!(migrated_rows[2].get::<i64, _>("use_full_url"), 1);
|
||||
assert_eq!(
|
||||
migrated_rows[2].get::<String, _>("openai_endpoint"),
|
||||
"/v1/responses"
|
||||
);
|
||||
assert_eq!(
|
||||
sqlx::query_scalar::<_, String>(
|
||||
"SELECT model_hash FROM llm_calls WHERE call_id = 'call-1'"
|
||||
)
|
||||
.fetch_one(store.pool())
|
||||
.await
|
||||
.unwrap(),
|
||||
"12345678"
|
||||
);
|
||||
assert!(sqlx::query("SELECT 1 FROM provider_endpoints")
|
||||
.fetch_one(store.pool())
|
||||
.await
|
||||
.is_err());
|
||||
assert!(sqlx::query("SELECT 1 FROM provider_models")
|
||||
.fetch_one(store.pool())
|
||||
.await
|
||||
.is_err());
|
||||
assert!(sqlx::query("PRAGMA foreign_key_check")
|
||||
.fetch_all(store.pool())
|
||||
.await
|
||||
.unwrap()
|
||||
.is_empty());
|
||||
}
|
||||
|
||||
+24
-30
@@ -12,9 +12,7 @@ use cursor_server::{
|
||||
cursor::prompting::{PromptAssets, PromptCompiler},
|
||||
cursor::{connect, proto::agent::v1 as pb},
|
||||
cursor::{CursorCommand, CursorSessionRegistry},
|
||||
model::{
|
||||
ProjectedContent, ProviderEndpointInput, ProviderModelInput, ProviderType, Role, Usage,
|
||||
},
|
||||
model::{ModelConfigInput, ModelType, ProjectedContent, Role, Usage, OPENAI_CHAT_ENDPOINT},
|
||||
provider::{FinishReason, ModelEvent},
|
||||
};
|
||||
use prost::Message;
|
||||
@@ -22,34 +20,30 @@ use prost::Message;
|
||||
#[tokio::test]
|
||||
async fn text_turn_runs_from_bidi_request_through_checkpoint_and_end_stream() {
|
||||
let (_directory, store) = fixtures::temp_store().await;
|
||||
let endpoint = store
|
||||
.create_provider(&ProviderEndpointInput {
|
||||
name: "Test".into(),
|
||||
provider_type: ProviderType::OpenAiChat,
|
||||
base_url: "https://example.com/v1".into(),
|
||||
api_key: None,
|
||||
custom_headers: serde_json::json!({}),
|
||||
extra_params: serde_json::json!({}),
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
let configured_model = store
|
||||
.save_provider_model(
|
||||
endpoint.provider_id,
|
||||
&ProviderModelInput {
|
||||
model_id: "test-model".into(),
|
||||
display_name: "Test Model".into(),
|
||||
endpoint_type: ProviderType::OpenAiChat,
|
||||
request_url: String::new(),
|
||||
enabled: true,
|
||||
sort_order: 0,
|
||||
context_window_tokens: None,
|
||||
max_output_tokens: None,
|
||||
reasoning_enabled: false,
|
||||
reasoning_effort: None,
|
||||
supports_image_generation: false,
|
||||
},
|
||||
)
|
||||
.create_model(&ModelConfigInput {
|
||||
sort_order: 0,
|
||||
display_name: "Test Model".into(),
|
||||
model_type: ModelType::OpenAi,
|
||||
base_url: "https://example.com/v1/chat/completions".into(),
|
||||
use_full_url: true,
|
||||
api_key: "test-key".into(),
|
||||
tooltip_data: "Test Model".into(),
|
||||
model_id: "test-model".into(),
|
||||
reasoning_effort: None,
|
||||
openai_endpoint: OPENAI_CHAT_ENDPOINT.into(),
|
||||
openai_extra_params_enabled: false,
|
||||
openai_extra_params: serde_json::json!({}),
|
||||
custom_headers_enabled: false,
|
||||
custom_headers: serde_json::json!({}),
|
||||
anthropic_extra_params_enabled: false,
|
||||
anthropic_extra_params: serde_json::json!({}),
|
||||
context_window_tokens: None,
|
||||
max_completion_tokens: None,
|
||||
anthropic_max_tokens: None,
|
||||
anthropic_thinking_effort: None,
|
||||
thinking_budget_tokens: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
let provider = fake_provider::FakeProvider::default();
|
||||
|
||||
Reference in New Issue
Block a user