mirror of
https://github.com/hanzoai/dev.git
synced 2026-10-25 03:32:32 +00:00
Our history is just-every's with author emails rewritten, so the graphs are
disjoint and git finds no merge base. Supplied one by hand: d1f1f51a41, the
just-every commit matching our Oct-2025 fork point (22 files apart). 9618
upstream commits, 7004 files, +1.81M/-159k, 37 conflicts.
Resolution:
- Upstream code where our side was the Oct-2025 prototype of a feature they
have since reimplemented 3-5x larger (agent_runs, browser_sessions,
history_cell/{agent,browser}, the vt100 harness and its snapshots).
- Upstream's config.rs module split (builder/defaults/sources/validation)
kept; zen5-coder and the provider-follows-model rule re-applied on top.
- Ours where the file IS the identity: README, package.json, postinstall,
release notes pipeline, integration-zed.
- Hybrid where upstream improved a file we had branded: updates.rs (their
release-repo migration, our hanzoai/dev), release.yml (their fail-fast npm
auth check, our package name), chatwidget.rs (their turn handling, our
HANZO_USER_KEY hint), exec human output (their 237 lines, our banner).
Superseded and dropped deliberately: our resume_command_name() coder-alias
hack — upstream's derive_resume_command_name() reads the invocation basename
generically, which yields "dev" for us.
LLM.md now records the real topology and the sync point; AGENTS.md and
CLAUDE.md are symlinks to it again. Single parent on purpose: adopting
jecode/main as a second parent would re-import 13,742 commits carrying the
upstream author emails a prior rewrite deliberately removed.
Version 0.2.188 -> 0.2.189.
Co-authored-by: Hanzo Dev <[email protected]>
148 lines
5.2 KiB
Rust
148 lines
5.2 KiB
Rust
use codex_api::AuthProvider;
|
|
use codex_api::ModelsClient;
|
|
use codex_api::Provider;
|
|
use codex_api::RetryConfig;
|
|
use codex_client::ReqwestTransport;
|
|
use codex_http_client::HttpClientBuilder;
|
|
use codex_protocol::config_types::ReasoningSummary;
|
|
use codex_protocol::openai_models::ConfigShellToolType;
|
|
use codex_protocol::openai_models::ModelInfo;
|
|
use codex_protocol::openai_models::ModelVisibility;
|
|
use codex_protocol::openai_models::ModelsResponse;
|
|
use codex_protocol::openai_models::ReasoningEffort;
|
|
use codex_protocol::openai_models::ReasoningEffortPreset;
|
|
use codex_protocol::openai_models::TruncationPolicyConfig;
|
|
use codex_protocol::openai_models::default_input_modalities;
|
|
use http::HeaderMap;
|
|
use http::Method;
|
|
use std::sync::Arc;
|
|
use wiremock::Mock;
|
|
use wiremock::MockServer;
|
|
use wiremock::ResponseTemplate;
|
|
use wiremock::matchers::method;
|
|
use wiremock::matchers::path;
|
|
|
|
#[derive(Clone, Default)]
|
|
struct DummyAuth;
|
|
|
|
impl AuthProvider for DummyAuth {
|
|
fn add_auth_headers(&self, _headers: &mut HeaderMap) {}
|
|
}
|
|
|
|
fn provider(base_url: &str) -> Provider {
|
|
Provider {
|
|
name: "test".to_string(),
|
|
base_url: base_url.to_string(),
|
|
query_params: None,
|
|
headers: HeaderMap::new(),
|
|
retry: RetryConfig {
|
|
max_attempts: 1,
|
|
base_delay: std::time::Duration::from_millis(1),
|
|
retry_429: false,
|
|
retry_5xx: true,
|
|
retry_transport: true,
|
|
},
|
|
stream_idle_timeout: std::time::Duration::from_secs(1),
|
|
}
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn models_client_hits_models_endpoint() {
|
|
let server = MockServer::start().await;
|
|
let base_url = format!("{}/api/codex", server.uri());
|
|
|
|
let response = ModelsResponse {
|
|
models: vec![ModelInfo {
|
|
slug: "gpt-test".to_string(),
|
|
display_name: "gpt-test".to_string(),
|
|
description: Some("desc".to_string()),
|
|
default_reasoning_level: Some(ReasoningEffort::Medium),
|
|
supported_reasoning_levels: vec![
|
|
ReasoningEffortPreset {
|
|
effort: ReasoningEffort::Low,
|
|
description: ReasoningEffort::Low.to_string(),
|
|
},
|
|
ReasoningEffortPreset {
|
|
effort: ReasoningEffort::Medium,
|
|
description: ReasoningEffort::Medium.to_string(),
|
|
},
|
|
ReasoningEffortPreset {
|
|
effort: ReasoningEffort::High,
|
|
description: ReasoningEffort::High.to_string(),
|
|
},
|
|
],
|
|
shell_type: ConfigShellToolType::ShellCommand,
|
|
visibility: ModelVisibility::List,
|
|
supported_in_api: true,
|
|
priority: 1,
|
|
additional_speed_tiers: Vec::new(),
|
|
service_tiers: Vec::new(),
|
|
default_service_tier: None,
|
|
upgrade: None,
|
|
model_messages: None,
|
|
include_skills_usage_instructions: false,
|
|
include_plugin_usage_instructions: false,
|
|
include_apps_usage_instructions: false,
|
|
supports_reasoning_summary_parameter: true,
|
|
default_reasoning_summary: ReasoningSummary::Auto,
|
|
support_verbosity: false,
|
|
default_verbosity: None,
|
|
availability_nux: None,
|
|
apply_patch_tool_type: None,
|
|
web_search_tool_type: Default::default(),
|
|
truncation_policy: TruncationPolicyConfig::bytes(/*limit*/ 10_000),
|
|
supports_parallel_tool_calls: false,
|
|
supports_image_detail_original: false,
|
|
context_window: Some(272_000),
|
|
max_context_window: None,
|
|
auto_compact_token_limit: None,
|
|
comp_hash: None,
|
|
effective_context_window_percent: 95,
|
|
experimental_supported_tools: Vec::new(),
|
|
input_modalities: default_input_modalities(),
|
|
used_fallback_model_metadata: false,
|
|
supports_search_tool: false,
|
|
use_responses_lite: false,
|
|
auto_review_model_override: None,
|
|
model_specialty: None,
|
|
tool_mode: None,
|
|
multi_agent_version: None,
|
|
}],
|
|
};
|
|
|
|
Mock::given(method("GET"))
|
|
.and(path("/api/codex/models"))
|
|
.respond_with(
|
|
ResponseTemplate::new(200)
|
|
.insert_header("content-type", "application/json")
|
|
.set_body_json(&response),
|
|
)
|
|
.mount(&server)
|
|
.await;
|
|
|
|
let transport = ReqwestTransport::from_http_client(
|
|
HttpClientBuilder::new()
|
|
.build_direct()
|
|
.expect("test HTTP client should build"),
|
|
);
|
|
let provider = provider(&base_url);
|
|
let request_url = ModelsClient::<ReqwestTransport>::request_url(&provider, "0.1.0");
|
|
let client = ModelsClient::new(transport, provider, Arc::new(DummyAuth));
|
|
|
|
let (models, _) = client
|
|
.list_models(request_url, HeaderMap::new())
|
|
.await
|
|
.expect("models request should succeed");
|
|
|
|
assert_eq!(models.len(), 1);
|
|
assert_eq!(models[0].slug, "gpt-test");
|
|
|
|
let received = server
|
|
.received_requests()
|
|
.await
|
|
.expect("should capture requests");
|
|
assert_eq!(received.len(), 1);
|
|
assert_eq!(received[0].method, Method::GET.as_str());
|
|
assert_eq!(received[0].url.path(), "/api/codex/models");
|
|
}
|