mirror of
https://github.com/codewhale-hq/Codewhale.git
synced 2026-11-11 01:51:34 -10:00
fix(models): deepseek-flash reasons — stop leaking its reasoning into prose
The founder saw `deepseek-flash`'s reasoning rendered as ordinary assistant
text. Cause: `model_supports_reasoning("deepseek-flash")` returned **false**, so
the client never routed `reasoning_content` to the thinking channel and it fell
through into visible output.
Why it returned false is the interesting part. That function consults the
catalog first and then falls through to a hand-maintained pile —
`starts_with("kimi-")`, `starts_with("mistral-")`, and a ~20-entry `matches!`
list. `deepseek-flash` was in no catalog, does not start with `kimi-`, and is not
in the list. It was also deliberately kept out of
`canonical_official_deepseek_model_id` so it would not inherit V4 Pro's pricing —
and that same function is what grants DeepSeek models reasoning. Keeping it out
for a pricing reason silently cost it reasoning.
Fixed at the layer that should own the fact, not with another match arm: catalog
entries in `models_dev.bundled.json` and `model_catalog.bundled.json` carrying
`supports_reasoning: true`, `context_window: 1000000`, `max_output: 384000`.
That also let the hand-added context-window arm from `b73a7060c` be **deleted** —
net less special-casing than before.
Modalities are text-only, matching the V4 Flash sibling. Secondary reports
mention native image input but the vendor notice does not state it, and claiming
vision that is not there fails requests; understating only hides a capability.
No price fields in the catalog rows: the DeepSeek family's rates are
time-varying and owned by `pricing.rs`.
Also lands the `models` extraction: `crates/tui/src/models.rs` moves to the
`codewhale-models` crate (1,837 lines, 150 consumers repointed, no shim).
`crates/tui/src` is now 955,950 lines, from 973,442 at the start of this work.
Verified by a temporary probe against the real merged catalog (removed after):
reasoning `true`, context `1_000_000`, output `384_000`, all resolved from the
catalog with no hardcoded arm.
cargo test -p codewhale-models --locked 38 passed; 0 failed
cargo test -p codewhale-tui --lib -- pricing:: model_catalog::
80 passed; 0 failed
cargo test -p codewhale-config --locked 697 passed; 0 failed; 1 ignored
cargo test -p codewhale-tui --lib -- tui::views tui::widgets commands::
1610 passed; 0 failed
cargo check --workspace --all-targets 0 errors, 0 unused warnings
The hardcoded prefix pile still decides capability for every *other* unknown
model. That is the real defect and it is filed as #6032 for 0.9.14 — the durable
owner is the catalog plus the cloud-facts channel, which can publish a
capability for a model named an hour ago without a Rust release.
Refs: #6032, GitHub #6025.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01X57KRgwqYkmmtVQScczqiL
This commit is contained in:
1 parent
b73a7060ca
commit
10aa19570f
151 files changed
+856
-758
No files matched your search
Generated
+13
@@ -986,6 +986,18 @@ dependencies = [
|
||||
"windows",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "codewhale-models"
|
||||
version = "0.9.13"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"chrono",
|
||||
"codewhale-config",
|
||||
"codewhale-core",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "codewhale-palette"
|
||||
version = "0.9.13"
|
||||
@@ -1117,6 +1129,7 @@ dependencies = [
|
||||
"codewhale-hooks",
|
||||
"codewhale-lane",
|
||||
"codewhale-localization",
|
||||
"codewhale-models",
|
||||
"codewhale-palette",
|
||||
"codewhale-paths",
|
||||
"codewhale-protocol",
|
||||
|
||||
@@ -13,6 +13,7 @@ members = [
|
||||
"crates/lane",
|
||||
"crates/localization",
|
||||
"crates/mcp",
|
||||
"crates/models",
|
||||
"crates/palette",
|
||||
"crates/paths",
|
||||
"crates/protocol",
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"about": "Offline/stale fallback Models.dev-shaped catalog snapshot for Codewhale (#3385, demoted by #4188).",
|
||||
"schema": "Matches crates/config/src/models_dev.rs ModelsDevCatalog ({ models, providers }).",
|
||||
"role": "NOT a competing source of truth. Preferred metadata is the live Models.dev catalog published into ProviderLake (#4187). This asset is used only when live/cache rows are unavailable (offline startup, failed refresh, or empty cache).",
|
||||
"source": "Compact offline seed of verified in-repo defaults (context/output from crates/tui/src/models.rs; USD pricing from crates/tui/src/pricing.rs) for providers Codewhale ships with. It is intentionally smaller than a full Models.dev dump; live refresh supersedes these rows on (provider, wire_model_id) identity.",
|
||||
"source": "Compact offline seed of verified in-repo defaults (context/output from crates/models/src/lib.rs; USD pricing from crates/tui/src/pricing.rs) for providers Codewhale ships with. It is intentionally smaller than a full Models.dev dump; live refresh supersedes these rows on (provider, wire_model_id) identity.",
|
||||
"honesty": "Pricing is intentionally OMITTED where a flat catalog row would be misleading: DeepSeek-native rows (priced via the time-aware DeepSeek table elsewhere, kept UnknownOrStale at the route layer), Grok 4.6 (rates double once a prompt reaches 200K tokens), aggregator-hosted DeepSeek rows (aggregator account terms, not DeepSeek Platform pricing), Xiaomi MiMo rows (published PAYG rates apply only to sk- pay-as-you-go keys; the catalog cannot distinguish that billing surface from credit/quota Token Plan keys, so MiMo stays unpriced), and Alibaba Model Studio Token/Coding Plan rows (upstream lists zero per-token cost because usage draws on plan quota, not per-token billing; a zero here would read as 'free'). Absent pricing surfaces as PricingSku::UnknownOrStale, never a fabricated zero.",
|
||||
"default_rows": "Each provider's `default: true` wire id equals that provider's built-in DEFAULT_*_MODEL so RouteResolver::new() and the descriptor stay in agreement when offline.",
|
||||
"curated": "qwen3.8-max (GA) is curated ahead of upstream Models.dev, which as of 2026-08-03 lists only qwen3.8-max-preview; facts verified against the owner's Token Plan console (2026-08-03): ~1M context, 128K output, image understanding, always-on reasoning. deepseek-v4-flash-0731 keeps the console/in-repo wire id for the row upstream serves as deepseek-v4-flash. Coding Plan rows for qwen3.8-max-preview, deepseek-v4-pro, deepseek-v4-flash-0731, and glm-5.2 are curated from the Token Plan upstream entries (upstream alibaba-coding-plan does not list them yet); the in-repo route layer already offers the same model set on both plans. Upstream provider ids alibaba-token-plan(-cn) / alibaba-coding-plan(-cn) were merged onto the CodeWhale provider ids (live refresh normalizes them via ProviderKind aliases; the -cn regional variants stay upstream-id browse rows until Codewhale ships China endpoints).",
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
[package]
|
||||
name = "codewhale-models"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
rust-version.workspace = true
|
||||
license.workspace = true
|
||||
repository.workspace = true
|
||||
description = "Provider request/response models and the offline model metadata catalog for Codewhale."
|
||||
|
||||
[features]
|
||||
# Exposes the catalog test hooks (`test_catalog_lock`,
|
||||
# `replace_active_catalog_for_test`) that used to be reachable as `#[cfg(test)]`
|
||||
# items inside `codewhale-tui`. Enabled only from dev-dependencies.
|
||||
test-support = []
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[dependencies]
|
||||
anyhow.workspace = true
|
||||
chrono.workspace = true
|
||||
codewhale-config = { path = "../config", version = "0.9.13" }
|
||||
codewhale-core = { path = "../core", version = "0.9.13" }
|
||||
serde.workspace = true
|
||||
serde_json = { workspace = true, features = ["preserve_order"] }
|
||||
+13
@@ -101,6 +101,19 @@
|
||||
],
|
||||
"supports_reasoning": true
|
||||
},
|
||||
"deepseek-flash": {
|
||||
"context_window": 1000000,
|
||||
"id": "deepseek-flash",
|
||||
"max_output": 384000,
|
||||
"modalities": [
|
||||
"text"
|
||||
],
|
||||
"provenance": "bundled",
|
||||
"supported_parameters": [
|
||||
"reasoning"
|
||||
],
|
||||
"supports_reasoning": true
|
||||
},
|
||||
"deepseek-v4-flash-vision-exp": {
|
||||
"context_window": 1000000,
|
||||
"id": "deepseek-v4-flash-vision-exp",
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub mod model_catalog;
|
||||
|
||||
/// Context window used only for legacy DeepSeek model IDs that do not name a
|
||||
/// newer V4 alias and do not carry an explicit `*k` suffix.
|
||||
pub const LEGACY_DEEPSEEK_CONTEXT_WINDOW_TOKENS: u32 = 128_000;
|
||||
@@ -36,7 +38,7 @@ pub const DIRECT_KIMI_K3_MAX_OUTPUT_TOKENS: u32 = 1_048_576;
|
||||
/// models resolve to their own scaled value via
|
||||
/// `compaction_threshold_for_model` (#664).
|
||||
pub const DEFAULT_COMPACTION_TOKEN_THRESHOLD: usize = 102_400;
|
||||
pub(crate) fn canonical_official_deepseek_model_id(model: &str) -> Option<&'static str> {
|
||||
pub fn canonical_official_deepseek_model_id(model: &str) -> Option<&'static str> {
|
||||
match model.trim().to_ascii_lowercase().as_str() {
|
||||
"deepseek-v4-pro"
|
||||
| "deepseek-v4pro"
|
||||
@@ -54,7 +56,7 @@ pub(crate) fn canonical_official_deepseek_model_id(model: &str) -> Option<&'stat
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
const COMPACTION_THRESHOLD_PERCENT: u32 = 80;
|
||||
|
||||
// === Core Message Types ===
|
||||
@@ -109,7 +111,7 @@ pub struct MessageResponse {
|
||||
/// True when the provider ended generation because its output allowance was
|
||||
/// exhausted. Providers use several wire spellings for the same condition.
|
||||
#[must_use]
|
||||
pub(crate) fn is_output_limit_stop_reason(reason: Option<&str>) -> bool {
|
||||
pub fn is_output_limit_stop_reason(reason: Option<&str>) -> bool {
|
||||
reason.is_some_and(|reason| {
|
||||
let reason = reason
|
||||
.trim()
|
||||
@@ -126,7 +128,7 @@ pub(crate) fn is_output_limit_stop_reason(reason: Option<&str>) -> bool {
|
||||
/// response. Responses API reasons carry an `incomplete:` prefix so unknown
|
||||
/// future reasons cannot accidentally be accepted as a finished answer.
|
||||
#[must_use]
|
||||
pub(crate) fn is_incomplete_stop_reason(reason: Option<&str>) -> bool {
|
||||
pub fn is_incomplete_stop_reason(reason: Option<&str>) -> bool {
|
||||
is_output_limit_stop_reason(reason)
|
||||
|| reason.is_some_and(|reason| {
|
||||
let reason = reason.trim().to_ascii_lowercase();
|
||||
@@ -139,7 +141,7 @@ pub(crate) fn is_incomplete_stop_reason(reason: Option<&str>) -> bool {
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub(crate) fn stop_reason_detail(reason: Option<&str>) -> &str {
|
||||
pub fn stop_reason_detail(reason: Option<&str>) -> &str {
|
||||
reason
|
||||
.map(str::trim)
|
||||
.and_then(|reason| reason.strip_prefix("incomplete:").or(Some(reason)))
|
||||
@@ -570,7 +572,7 @@ pub fn effective_muse_wire_id(model: &str) -> &str {
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub(crate) fn model_is_openai_reasoning_family(model: &str) -> bool {
|
||||
pub fn model_is_openai_reasoning_family(model: &str) -> bool {
|
||||
let lower = model.to_lowercase();
|
||||
is_openai_gpt_55_api_model(&lower)
|
||||
|| is_openai_gpt_56_api_model(&lower)
|
||||
@@ -583,7 +585,7 @@ fn is_openai_gpt_55_api_model(model_lower: &str) -> bool {
|
||||
|| has_date_snapshot_suffix(model_lower, "gpt-5.5-pro-")
|
||||
}
|
||||
|
||||
pub(crate) fn is_openai_gpt_56_api_model(model_lower: &str) -> bool {
|
||||
pub fn is_openai_gpt_56_api_model(model_lower: &str) -> bool {
|
||||
matches!(
|
||||
model_lower,
|
||||
"gpt-5.6" | "gpt-5.6-sol" | "gpt-5.6-terra" | "gpt-5.6-luna"
|
||||
@@ -608,7 +610,7 @@ fn is_openai_codex_model(model_lower: &str) -> bool {
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn has_date_snapshot_suffix(model_lower: &str, prefix: &str) -> bool {
|
||||
pub fn has_date_snapshot_suffix(model_lower: &str, prefix: &str) -> bool {
|
||||
let Some(rest) = model_lower.strip_prefix(prefix) else {
|
||||
return false;
|
||||
};
|
||||
@@ -631,7 +633,7 @@ pub(crate) fn has_date_snapshot_suffix(model_lower: &str, prefix: &str) -> bool
|
||||
/// a fact about the route, and every surface that shows such a window must
|
||||
/// mark it unverified.
|
||||
#[must_use]
|
||||
pub(crate) fn name_suffix_context_window_hint(model: &str) -> Option<u32> {
|
||||
pub fn name_suffix_context_window_hint(model: &str) -> Option<u32> {
|
||||
if crate::model_catalog::resolved_context_window(model).is_some() {
|
||||
return None;
|
||||
}
|
||||
@@ -674,7 +676,7 @@ fn explicit_context_window_hint(model_lower: &str) -> Option<u32> {
|
||||
/// Derive a compaction token threshold from model context and a caller-supplied
|
||||
/// percentage.
|
||||
#[must_use]
|
||||
#[cfg(test)]
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
pub fn compaction_threshold_for_model_at_percent(model: &str, percent: f64) -> usize {
|
||||
let Some(window) = context_window_for_model(model) else {
|
||||
return DEFAULT_COMPACTION_TOKEN_THRESHOLD;
|
||||
@@ -75,7 +75,7 @@ impl CatalogCache {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct MergedCatalog {
|
||||
pub struct MergedCatalog {
|
||||
user_overrides: BTreeMap<String, CatalogEntry>,
|
||||
provider_cache: Option<CatalogCache>,
|
||||
bundled: CatalogCache,
|
||||
@@ -83,7 +83,7 @@ pub(crate) struct MergedCatalog {
|
||||
}
|
||||
|
||||
impl MergedCatalog {
|
||||
pub(crate) fn from_sources(
|
||||
pub fn from_sources(
|
||||
user_overrides: BTreeMap<String, CatalogEntry>,
|
||||
provider_cache: Option<CatalogCache>,
|
||||
bundled: CatalogCache,
|
||||
@@ -197,21 +197,21 @@ pub fn load_cached() -> Option<CatalogCache> {
|
||||
serde_json::from_str(&raw).ok()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
static TEST_CATALOG_LOCK: std::sync::LazyLock<std::sync::Mutex<()>> =
|
||||
std::sync::LazyLock::new(|| std::sync::Mutex::new(()));
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) fn test_catalog_lock() -> std::sync::MutexGuard<'static, ()> {
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
pub fn test_catalog_lock() -> std::sync::MutexGuard<'static, ()> {
|
||||
TEST_CATALOG_LOCK.lock().expect("model catalog test lock")
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) struct ActiveCatalogGuard {
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
pub struct ActiveCatalogGuard {
|
||||
previous: MergedCatalog,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
impl Drop for ActiveCatalogGuard {
|
||||
fn drop(&mut self) {
|
||||
let mut active = active_catalog().write().expect("active catalog write lock");
|
||||
@@ -219,8 +219,8 @@ impl Drop for ActiveCatalogGuard {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) fn replace_active_catalog_for_test(catalog: MergedCatalog) -> ActiveCatalogGuard {
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
pub fn replace_active_catalog_for_test(catalog: MergedCatalog) -> ActiveCatalogGuard {
|
||||
let mut active = active_catalog().write().expect("active catalog write lock");
|
||||
let previous = active.clone();
|
||||
*active = catalog;
|
||||
@@ -39,6 +39,7 @@ codewhale-core = { path = "../core", version = "0.9.13" }
|
||||
codewhale-execpolicy = { path = "../execpolicy", version = "0.9.13" }
|
||||
codewhale-hooks = { path = "../hooks", version = "0.9.13" }
|
||||
codewhale-lane = { path = "../lane", version = "0.9.13" }
|
||||
codewhale-models = { path = "../models", version = "0.9.13" }
|
||||
codewhale-palette = { path = "../palette", version = "0.9.13" }
|
||||
codewhale-paths = { path = "../paths", version = "0.9.13" }
|
||||
codewhale-protocol = { path = "../protocol", version = "0.9.13" }
|
||||
@@ -120,6 +121,9 @@ rusty_alloc-api = { workspace = true, optional = true }
|
||||
codewhale-build-support = { path = "../build-support", version = "0.9.13" }
|
||||
|
||||
[dev-dependencies]
|
||||
codewhale-models = { path = "../models", version = "0.9.13", features = [
|
||||
"test-support",
|
||||
] }
|
||||
cucumber = "0.23.0"
|
||||
jsonschema.workspace = true
|
||||
wiremock = "0.6"
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
mod models {
|
||||
pub use codewhale_core::request::{ContentBlock, Message};
|
||||
pub use codewhale_core::role::Role;
|
||||
}
|
||||
#[path = "../src/session_tree.rs"]
|
||||
#[allow(dead_code)] // The probe intentionally exercises only the journal hot paths.
|
||||
mod session_tree;
|
||||
|
||||
use models::Message;
|
||||
use codewhale_models::Message;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use session_tree::SessionJournal;
|
||||
use std::io::Write;
|
||||
|
||||
@@ -51,15 +51,15 @@ use crate::core::engine::{
|
||||
exec_shell_ask_rule_decision_for_policy, file_tool_ask_rule_decision_for_policy,
|
||||
};
|
||||
use crate::llm_client::{LlmClient, StreamEventBox};
|
||||
use crate::models::Role;
|
||||
use crate::models::{
|
||||
ContentBlock, ContentBlockStart, Delta, Message, MessageRequest, StreamEvent, SystemPrompt,
|
||||
};
|
||||
use crate::tools::spec::{ApprovalRequirement, PreparedToolCall, RichToolResult, ToolError};
|
||||
use crate::tools::{ToolContext, ToolRegistry, ToolRegistryBuilder};
|
||||
use crate::worker_profile::ShellPolicy;
|
||||
use codewhale_config::AppMode;
|
||||
use codewhale_execpolicy::ApprovalMode;
|
||||
use codewhale_models::Role;
|
||||
use codewhale_models::{
|
||||
ContentBlock, ContentBlockStart, Delta, Message, MessageRequest, StreamEvent, SystemPrompt,
|
||||
};
|
||||
|
||||
const ACP_PROTOCOL_VERSION: u64 = 1;
|
||||
|
||||
|
||||
+16
-14
@@ -41,8 +41,10 @@ use crate::llm_client::{
|
||||
mod catalog_tests;
|
||||
|
||||
use crate::logging;
|
||||
use crate::models::Role;
|
||||
use crate::models::{ContentBlock, Message, MessageRequest, MessageResponse, SystemPrompt, Usage};
|
||||
use codewhale_models::Role;
|
||||
use codewhale_models::{
|
||||
ContentBlock, Message, MessageRequest, MessageResponse, SystemPrompt, Usage,
|
||||
};
|
||||
|
||||
/// Every provider request that can feed the interactive TUI's attached CWC run
|
||||
/// takes a shared permit at this lowest common dispatch seam. Runtime Chat holds
|
||||
@@ -2701,7 +2703,7 @@ impl DeepSeekClient {
|
||||
omitted_tool_count: usize,
|
||||
) -> crate::llm_client::StreamEventBox {
|
||||
Box::pin(async_stream::stream! {
|
||||
yield Ok(crate::models::StreamEvent::ToolProjectionWarning {
|
||||
yield Ok(codewhale_models::StreamEvent::ToolProjectionWarning {
|
||||
provider,
|
||||
omitted_tool_names,
|
||||
omitted_tool_count,
|
||||
@@ -2763,10 +2765,10 @@ impl DeepSeekClient {
|
||||
};
|
||||
let usage = (response.usage != Usage::default()).then_some(response.usage.clone());
|
||||
let translated =
|
||||
if crate::models::is_incomplete_stop_reason(response.stop_reason.as_deref()) {
|
||||
if codewhale_models::is_incomplete_stop_reason(response.stop_reason.as_deref()) {
|
||||
Err(anyhow::anyhow!(
|
||||
"translate: provider response incomplete ({})",
|
||||
crate::models::stop_reason_detail(response.stop_reason.as_deref())
|
||||
codewhale_models::stop_reason_detail(response.stop_reason.as_deref())
|
||||
))
|
||||
} else {
|
||||
translation_text_from_response(&response)
|
||||
@@ -2837,10 +2839,10 @@ impl DeepSeekClient {
|
||||
let usage = parse_usage(value.get("usage"));
|
||||
let stop_reason = value["choices"][0]["finish_reason"].as_str();
|
||||
let usage = (usage_reported && usage != Usage::default()).then_some(usage);
|
||||
let translated = if crate::models::is_incomplete_stop_reason(stop_reason) {
|
||||
let translated = if codewhale_models::is_incomplete_stop_reason(stop_reason) {
|
||||
Err(anyhow::anyhow!(
|
||||
"translate: provider response incomplete ({})",
|
||||
crate::models::stop_reason_detail(stop_reason)
|
||||
codewhale_models::stop_reason_detail(stop_reason)
|
||||
))
|
||||
} else {
|
||||
value["choices"][0]["message"]["content"]
|
||||
@@ -5032,7 +5034,7 @@ pub(crate) fn responses_tool_output_for_test(
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) fn chat_messages_for_test(messages: &[crate::models::Message]) -> Vec<Value> {
|
||||
pub(crate) fn chat_messages_for_test(messages: &[codewhale_models::Message]) -> Vec<Value> {
|
||||
chat::build_chat_messages(None, messages, "gpt-4o")
|
||||
}
|
||||
|
||||
@@ -5074,13 +5076,13 @@ mod tests {
|
||||
DEFAULT_CONCENTRATE_BASE_URL, DEFAULT_CONCENTRATE_MODEL, DEFAULT_EDENAI_MODEL,
|
||||
DEFAULT_TELECOMJS_MODEL, OPENROUTER_QWEN_3_6_FLASH_MODEL, ProviderConfig, ProvidersConfig,
|
||||
};
|
||||
use crate::models::{
|
||||
ContentBlock, ContentBlockStart, Delta, Message, MessageRequest, MessageResponse,
|
||||
StreamEvent, Tool,
|
||||
};
|
||||
use crate::tools::apply_patch::ApplyPatchTool;
|
||||
use crate::tools::spec::ToolSpec;
|
||||
use crate::tools::{ToolContext, ToolRegistryBuilder};
|
||||
use codewhale_models::{
|
||||
ContentBlock, ContentBlockStart, Delta, Message, MessageRequest, MessageResponse,
|
||||
StreamEvent, Tool,
|
||||
};
|
||||
use codewhale_protocol::runtime::DynamicToolSpec;
|
||||
use serde_json::json;
|
||||
use wiremock::matchers::{header, method, path};
|
||||
@@ -7286,7 +7288,7 @@ mod tests {
|
||||
.expect("projection warning precedes provider SSE")
|
||||
.expect("projection warning is not a stream error");
|
||||
let (provider, omitted_tool_names, omitted_tool_count) = match first {
|
||||
crate::models::StreamEvent::ToolProjectionWarning {
|
||||
codewhale_models::StreamEvent::ToolProjectionWarning {
|
||||
provider,
|
||||
omitted_tool_names,
|
||||
omitted_tool_count,
|
||||
@@ -7301,7 +7303,7 @@ mod tests {
|
||||
while let Some(event) = stream.next().await {
|
||||
if matches!(
|
||||
event.expect("captured SSE response remains valid"),
|
||||
crate::models::StreamEvent::ToolProjectionWarning { .. }
|
||||
codewhale_models::StreamEvent::ToolProjectionWarning { .. }
|
||||
) {
|
||||
additional_warnings += 1;
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
//! non-cached `input_tokens`, and the normalized `input_tokens` is the sum
|
||||
//! of all three (total prompt, the DeepSeek convention);
|
||||
//! - signed-thinking handling: `signature_delta` is captured into
|
||||
//! [`crate::models::Delta::SignatureDelta`] and assistant thinking blocks
|
||||
//! [`codewhale_models::Delta::SignatureDelta`] and assistant thinking blocks
|
||||
//! replay verbatim (signature included); unsigned thinking blocks are
|
||||
//! dropped from replay because the API rejects them.
|
||||
//!
|
||||
@@ -30,8 +30,8 @@ use serde_json::{Value, json};
|
||||
use crate::config::{ApiProvider, wire_model_for_provider_route};
|
||||
use crate::llm_client::StreamEventBox;
|
||||
use crate::logging;
|
||||
use crate::models::{ContentBlock, MessageRequest, MessageResponse, StreamEvent, Usage};
|
||||
use crate::tools::schema_sanitize;
|
||||
use codewhale_models::{ContentBlock, MessageRequest, MessageResponse, StreamEvent, Usage};
|
||||
|
||||
use super::prepared::WireDialect;
|
||||
use super::role_placement::{RolePlacement, role_placement};
|
||||
@@ -54,8 +54,8 @@ impl DeepSeekClient {
|
||||
|
||||
if let Some(system) = request.system.as_ref() {
|
||||
body["system"] = match system {
|
||||
crate::models::SystemPrompt::Text(text) => json!(text),
|
||||
crate::models::SystemPrompt::Blocks(blocks) => json!(
|
||||
codewhale_models::SystemPrompt::Text(text) => json!(text),
|
||||
codewhale_models::SystemPrompt::Blocks(blocks) => json!(
|
||||
blocks
|
||||
.iter()
|
||||
.map(|block| {
|
||||
@@ -128,7 +128,7 @@ impl DeepSeekClient {
|
||||
// gateways (#4978, e.g. Sensenova) only accept the documented
|
||||
// enabled/disabled/auto thinking types, so non-native routes get the
|
||||
// portable `{"type":"enabled","budget_tokens":N}` shape instead.
|
||||
let thinking_capable = crate::models::model_supports_reasoning(&model);
|
||||
let thinking_capable = codewhale_models::model_supports_reasoning(&model);
|
||||
let is_minimax_provider = self.api_provider == ApiProvider::MinimaxAnthropic;
|
||||
let is_minimax = crate::config::is_exact_minimax_anthropic_m3_route(
|
||||
self.api_provider,
|
||||
@@ -558,7 +558,7 @@ fn anthropic_tool_choice(tool_choice: &Value) -> Value {
|
||||
/// `system` message ended up on the wire for the provider to 400 on. It now
|
||||
/// comes from the shared placement table, and pairs the table rejects are
|
||||
/// refused at the outbound seam before this function ever runs.
|
||||
pub(super) fn message_to_anthropic(message: &crate::models::Message) -> Option<Value> {
|
||||
pub(super) fn message_to_anthropic(message: &codewhale_models::Message) -> Option<Value> {
|
||||
let placement = role_placement(&message.role, WireDialect::AnthropicMessages);
|
||||
let wire_role = match placement {
|
||||
RolePlacement::User | RolePlacement::Developer => "user",
|
||||
@@ -588,7 +588,7 @@ pub(super) fn message_to_anthropic(message: &crate::models::Message) -> Option<V
|
||||
.to_string();
|
||||
text["text"] = json!(format!(
|
||||
"{}{}",
|
||||
crate::models::INTERRUPTED_ASSISTANT_CONTEXT_PREFIX,
|
||||
codewhale_models::INTERRUPTED_ASSISTANT_CONTEXT_PREFIX,
|
||||
existing
|
||||
));
|
||||
}
|
||||
@@ -896,8 +896,8 @@ fn anthropic_error_fields(error: &Value) -> (String, String) {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::models::Role;
|
||||
use crate::models::{CacheControl, Message, SystemBlock, SystemPrompt, Tool};
|
||||
use codewhale_models::Role;
|
||||
use codewhale_models::{CacheControl, Message, SystemBlock, SystemPrompt, Tool};
|
||||
|
||||
fn request_with(
|
||||
model: &str,
|
||||
@@ -1607,7 +1607,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn sse_fixture_decodes_text_thinking_signature_and_tool_use() {
|
||||
use crate::models::{ContentBlockStart, Delta};
|
||||
use codewhale_models::{ContentBlockStart, Delta};
|
||||
|
||||
let events = [
|
||||
r#"{"type":"message_start","message":{"id":"msg_01","type":"message","role":"assistant","content":[],"model":"claude-sonnet-4-6","stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":3,"cache_creation_input_tokens":2045,"cache_read_input_tokens":18000,"output_tokens":1}}}"#,
|
||||
@@ -1754,7 +1754,7 @@ mod tests {
|
||||
// whole reason the projection exists; if it regresses, every locally
|
||||
// attached screenshot 400s on the native route.
|
||||
let block = content_block_to_anthropic(&ContentBlock::ImageUrl {
|
||||
image_url: crate::models::ImageUrlContent {
|
||||
image_url: codewhale_models::ImageUrlContent {
|
||||
url: "data:image/png;base64,QUJD".to_string(),
|
||||
},
|
||||
})
|
||||
@@ -1795,7 +1795,7 @@ mod tests {
|
||||
#[test]
|
||||
fn remote_image_url_stays_a_url_source() {
|
||||
let block = content_block_to_anthropic(&ContentBlock::ImageUrl {
|
||||
image_url: crate::models::ImageUrlContent {
|
||||
image_url: codewhale_models::ImageUrlContent {
|
||||
url: "https://example.com/shot.png".to_string(),
|
||||
},
|
||||
})
|
||||
@@ -1814,7 +1814,7 @@ mod tests {
|
||||
"data:image/png,QUJD",
|
||||
] {
|
||||
let block = content_block_to_anthropic(&ContentBlock::ImageUrl {
|
||||
image_url: crate::models::ImageUrlContent {
|
||||
image_url: codewhale_models::ImageUrlContent {
|
||||
url: url.to_string(),
|
||||
},
|
||||
})
|
||||
|
||||
@@ -40,7 +40,7 @@ use crate::config::ApiProvider;
|
||||
use crate::llm_client::StreamEventBox;
|
||||
use crate::llm_client::sanitize_http_error_body;
|
||||
use crate::logging;
|
||||
use crate::models::{
|
||||
use codewhale_models::{
|
||||
ContentBlock, ContentBlockStart, Delta, Message, MessageDelta, MessageRequest, MessageResponse,
|
||||
StreamEvent, SystemPrompt, Tool, ToolCaller, Usage, is_openai_gpt_56_api_model,
|
||||
model_is_openai_reasoning_family, model_supports_reasoning,
|
||||
@@ -55,7 +55,7 @@ use super::{
|
||||
apply_reasoning_effort, bounded_error_text, from_api_tool_name, parse_usage,
|
||||
release_stream_buffer, system_to_instructions, to_api_tool_name,
|
||||
};
|
||||
use crate::models::Role;
|
||||
use codewhale_models::Role;
|
||||
|
||||
fn apply_provider_token_limit(
|
||||
body: &mut Value,
|
||||
@@ -1079,7 +1079,7 @@ pub(crate) fn build_chat_wire_body(
|
||||
build_chat_messages_for_request_and_provider_and_route(request, provider, base_url);
|
||||
let model = {
|
||||
let wire = wire_model_for_provider_route(provider, base_url, &request.model);
|
||||
crate::models::effective_muse_wire_id(&wire).to_string()
|
||||
codewhale_models::effective_muse_wire_id(&wire).to_string()
|
||||
};
|
||||
validate_google_thought_signature_replay(base_url, &model, &messages)?;
|
||||
let mut body = if stream {
|
||||
@@ -2693,7 +2693,7 @@ fn build_chat_messages_with_reasoning(
|
||||
let content = if placement == RolePlacement::InterruptedAssistant {
|
||||
format!(
|
||||
"{}{}",
|
||||
crate::models::INTERRUPTED_ASSISTANT_CONTEXT_PREFIX,
|
||||
codewhale_models::INTERRUPTED_ASSISTANT_CONTEXT_PREFIX,
|
||||
text_parts.join("\n")
|
||||
)
|
||||
} else {
|
||||
@@ -4440,7 +4440,7 @@ mod stream_diagnostics_tests {
|
||||
mod arcee_waf_message_encoding_tests {
|
||||
use super::build_chat_messages_for_request_and_provider;
|
||||
use crate::config::ApiProvider;
|
||||
use crate::models::{MessageRequest, SystemPrompt};
|
||||
use codewhale_models::{MessageRequest, SystemPrompt};
|
||||
use serde_json::Value;
|
||||
|
||||
fn request_with_system(system: &str) -> MessageRequest {
|
||||
@@ -4523,8 +4523,8 @@ mod minimax_reasoning_replay_tests {
|
||||
ApiProvider, DEFAULT_KIMI_CODE_BASE_URL, DEFAULT_MINIMAX_MODEL,
|
||||
DEFAULT_MODELSTUDIO_TOKEN_PLAN_BASE_URL, DEFAULT_MOONSHOT_BASE_URL, KIMI_CODE_K3_MODEL,
|
||||
};
|
||||
use crate::models::Role;
|
||||
use crate::models::{ContentBlock, Message, MessageRequest};
|
||||
use codewhale_models::Role;
|
||||
use codewhale_models::{ContentBlock, Message, MessageRequest};
|
||||
|
||||
fn request_with_assistant_thinking() -> MessageRequest {
|
||||
MessageRequest {
|
||||
@@ -6229,8 +6229,8 @@ mod image_block_wire_tests {
|
||||
//! message whose `content` is an array of parts, with the image as
|
||||
//! `{"type":"image_url","image_url":{"url":…}}`.
|
||||
use super::{ApiProvider, build_chat_messages, build_chat_wire_body};
|
||||
use crate::models::Role;
|
||||
use crate::models::{ContentBlock, ImageUrlContent, Message, MessageRequest};
|
||||
use codewhale_models::Role;
|
||||
use codewhale_models::{ContentBlock, ImageUrlContent, Message, MessageRequest};
|
||||
|
||||
const DATA_URL: &str = "data:image/png;base64,QUJD";
|
||||
|
||||
@@ -7116,10 +7116,13 @@ mod mistral_reasoning_tests {
|
||||
"mistral-small-latest",
|
||||
"magistral-small-latest",
|
||||
] {
|
||||
assert!(crate::models::model_supports_reasoning(model), "{model}");
|
||||
assert!(codewhale_models::model_supports_reasoning(model), "{model}");
|
||||
}
|
||||
for model in ["mistral-code-latest", "mistral-large-latest"] {
|
||||
assert!(!crate::models::model_supports_reasoning(model), "{model}");
|
||||
assert!(
|
||||
!codewhale_models::model_supports_reasoning(model),
|
||||
"{model}"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
//! directly to verify each "class of stream failure" the engine relies on.
|
||||
use super::*;
|
||||
use crate::client::wire::{InvalidSseUtf8, SseLineDecoder};
|
||||
use crate::models::{ContentBlockStart, Delta, StreamEvent};
|
||||
use codewhale_models::{ContentBlockStart, Delta, StreamEvent};
|
||||
|
||||
/// Decode a raw SSE-data JSON chunk into our internal events, mirroring
|
||||
/// the per-event call shape used by `handle_chat_completion_stream`.
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use super::DeepSeekClient;
|
||||
use super::chat::{parse_chat_message, parse_sse_chunk};
|
||||
use crate::config::{Config, ProviderConfig, ProvidersConfig};
|
||||
use crate::models::Role;
|
||||
use crate::models::{ContentBlock, Delta, Message, MessageRequest, StreamEvent, Tool};
|
||||
use anyhow::Result;
|
||||
use codewhale_models::Role;
|
||||
use codewhale_models::{ContentBlock, Delta, Message, MessageRequest, StreamEvent, Tool};
|
||||
use serde_json::{Value, json};
|
||||
|
||||
fn ds4_client() -> DeepSeekClient {
|
||||
|
||||
@@ -1235,8 +1235,8 @@ mod tests {
|
||||
mod dialect_seam_tests {
|
||||
use super::*;
|
||||
use crate::config::{Config, ProviderConfig, ProvidersConfig};
|
||||
use crate::models::Role;
|
||||
use crate::models::{ContentBlock, Message, MessageRequest, SystemPrompt, Tool};
|
||||
use codewhale_models::Role;
|
||||
use codewhale_models::{ContentBlock, Message, MessageRequest, SystemPrompt, Tool};
|
||||
use serde_json::json;
|
||||
|
||||
use super::super::DeepSeekClient;
|
||||
|
||||
@@ -13,11 +13,11 @@ use serde_json::{Value, json};
|
||||
use crate::config::ApiProvider;
|
||||
use crate::llm_client::StreamEventBox;
|
||||
use crate::logging;
|
||||
use crate::models::{
|
||||
use crate::tools::schema_sanitize;
|
||||
use codewhale_models::{
|
||||
ContentBlock, ContentBlockStart, Delta, MessageDelta, MessageRequest, MessageResponse,
|
||||
OpaqueReasoningState, StreamEvent, Tool, Usage,
|
||||
};
|
||||
use crate::tools::schema_sanitize;
|
||||
|
||||
use super::prepared::WireDialect;
|
||||
use super::role_placement::{RolePlacement, role_placement};
|
||||
@@ -776,7 +776,7 @@ pub(super) fn convert_messages_to_responses_input(
|
||||
let text = if placement == RolePlacement::InterruptedAssistant {
|
||||
format!(
|
||||
"{}{}",
|
||||
crate::models::INTERRUPTED_ASSISTANT_CONTEXT_PREFIX,
|
||||
codewhale_models::INTERRUPTED_ASSISTANT_CONTEXT_PREFIX,
|
||||
text
|
||||
)
|
||||
} else {
|
||||
|
||||
@@ -6,9 +6,9 @@ use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use futures_util::StreamExt;
|
||||
|
||||
use crate::config::{Config, ProviderConfig, ProvidersConfig, RetryConfig};
|
||||
use crate::models::Message;
|
||||
use crate::models::Role;
|
||||
use crate::models::SystemPrompt;
|
||||
use codewhale_models::Message;
|
||||
use codewhale_models::Role;
|
||||
use codewhale_models::SystemPrompt;
|
||||
use wiremock::matchers::{method, path};
|
||||
use wiremock::{Mock, MockServer, Request, Respond, ResponseTemplate};
|
||||
|
||||
@@ -1339,7 +1339,7 @@ fn user_image_becomes_an_input_image_item() {
|
||||
|
||||
let mut request = minimal_responses_request();
|
||||
request.messages[0].content.push(ContentBlock::ImageUrl {
|
||||
image_url: crate::models::ImageUrlContent {
|
||||
image_url: codewhale_models::ImageUrlContent {
|
||||
url: DATA_URL.to_string(),
|
||||
},
|
||||
});
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
//! bytes, never how much the model should trust them.
|
||||
|
||||
use super::prepared::WireDialect;
|
||||
use crate::models::{Message, Role};
|
||||
use codewhale_models::{Message, Role};
|
||||
|
||||
/// Which channel of a wire body a message renders into.
|
||||
///
|
||||
@@ -147,7 +147,7 @@ pub(crate) fn reject_unsupported_roles(
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{RolePlacement, WireDialect, reject_unsupported_roles, role_placement};
|
||||
use crate::models::{ContentBlock, Message, Role};
|
||||
use codewhale_models::{ContentBlock, Message, Role};
|
||||
|
||||
const DIALECTS: [WireDialect; 3] = [
|
||||
WireDialect::ChatCompletions,
|
||||
@@ -286,7 +286,7 @@ mod adapter_agreement_tests {
|
||||
|
||||
use super::super::{anthropic, chat, responses};
|
||||
use crate::config::ApiProvider;
|
||||
use crate::models::{
|
||||
use codewhale_models::{
|
||||
ContentBlock, INTERRUPTED_ASSISTANT_CONTEXT_PREFIX, Message, MessageRequest, Role,
|
||||
};
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
use anyhow::Result;
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::models::{ServerToolUsage, Usage};
|
||||
use codewhale_models::{ServerToolUsage, Usage};
|
||||
|
||||
pub(crate) fn saturating_u32(value: u64) -> u32 {
|
||||
u32::try_from(value).unwrap_or(u32::MAX)
|
||||
@@ -392,7 +392,7 @@ mod tests {
|
||||
|
||||
// Invariant 2: pricing does not add reasoning a second time. The same
|
||||
// usage with the reasoning field removed must cost the same.
|
||||
let without = crate::models::Usage {
|
||||
let without = codewhale_models::Usage {
|
||||
reasoning_tokens: None,
|
||||
..usage.clone()
|
||||
};
|
||||
|
||||
@@ -387,7 +387,7 @@ impl CommandSessionLifecycleContext for SessionLifecycleAdapter<'_> {
|
||||
.content
|
||||
.iter()
|
||||
.filter_map(|b| match b {
|
||||
crate::models::ContentBlock::Text { text, .. } => Some(text.as_str()),
|
||||
codewhale_models::ContentBlock::Text { text, .. } => Some(text.as_str()),
|
||||
_ => None,
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
@@ -627,7 +627,7 @@ impl CommandSessionLifecycleContext for SessionLifecycleAdapter<'_> {
|
||||
source_session
|
||||
.system_prompt
|
||||
.as_ref()
|
||||
.map(|s| crate::models::SystemPrompt::Text(s.clone()))
|
||||
.map(|s| codewhale_models::SystemPrompt::Text(s.clone()))
|
||||
.as_ref(),
|
||||
source_session.metadata.mode.as_deref(),
|
||||
);
|
||||
@@ -671,7 +671,7 @@ impl CommandSessionLifecycleContext for SessionLifecycleAdapter<'_> {
|
||||
system_prompt: forked
|
||||
.system_prompt
|
||||
.as_ref()
|
||||
.map(|s| crate::models::SystemPrompt::Text(s.clone())),
|
||||
.map(|s| codewhale_models::SystemPrompt::Text(s.clone())),
|
||||
model: forked.metadata.model.clone(),
|
||||
workspace: app.workspace.clone(),
|
||||
mode,
|
||||
@@ -4043,8 +4043,8 @@ impl App {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::models::Role;
|
||||
use codewhale_localization::Locale;
|
||||
use codewhale_models::Role;
|
||||
use tempfile::TempDir;
|
||||
|
||||
fn test_app() -> App {
|
||||
@@ -4711,9 +4711,9 @@ mod tests {
|
||||
app.session.total_conversation_tokens = 2_000;
|
||||
app.goal_continuation_waiting = true;
|
||||
app.is_loading = false;
|
||||
app.api_messages.push(crate::models::Message {
|
||||
role: crate::models::Role::User,
|
||||
content: vec![crate::models::ContentBlock::Text {
|
||||
app.api_messages.push(codewhale_models::Message {
|
||||
role: codewhale_models::Role::User,
|
||||
content: vec![codewhale_models::ContentBlock::Text {
|
||||
text: "work".to_string(),
|
||||
cache_control: None,
|
||||
}],
|
||||
@@ -5604,8 +5604,8 @@ mod tests {
|
||||
|
||||
fn user_message(text: &str) -> Message {
|
||||
Message {
|
||||
role: crate::models::Role::User,
|
||||
content: vec![crate::models::ContentBlock::Text {
|
||||
role: codewhale_models::Role::User,
|
||||
content: vec![codewhale_models::ContentBlock::Text {
|
||||
text: text.to_string(),
|
||||
cache_control: None,
|
||||
}],
|
||||
|
||||
@@ -518,17 +518,17 @@ fn localized(locale: Locale, id: MessageId, replacements: &[(&str, &str)]) -> St
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::models::Role;
|
||||
use codewhale_models::Role;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use tempfile::TempDir;
|
||||
|
||||
use super::*;
|
||||
use crate::config::{ApiProvider, Config};
|
||||
use crate::models::{ContentBlock, Message};
|
||||
use crate::tui::app::TuiOptions;
|
||||
use crate::tui::history::HistoryCell;
|
||||
use codewhale_config::AppMode;
|
||||
use codewhale_models::{ContentBlock, Message};
|
||||
|
||||
#[test]
|
||||
fn status_keeps_current_session_snapshot_remedy_after_notice_delivery() {
|
||||
|
||||
@@ -72,10 +72,10 @@ fn execute_copy(app: &mut App) -> CommandResult {
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::config::Config;
|
||||
use crate::models::{ContentBlock, Message, Role};
|
||||
use crate::tui::app::TuiOptions;
|
||||
use crate::tui::clipboard::ClipboardHandler;
|
||||
use crate::tui::history::{HistoryCell, history_cells_from_message};
|
||||
use codewhale_models::{ContentBlock, Message, Role};
|
||||
use std::path::{Path, PathBuf};
|
||||
use tempfile::TempDir;
|
||||
|
||||
|
||||
@@ -753,11 +753,11 @@ mod tests {
|
||||
use super::*;
|
||||
use crate::client::PromptInspection;
|
||||
use crate::config::Config;
|
||||
use crate::models::Message;
|
||||
use crate::models::Role;
|
||||
use crate::tui::app::{App, TuiOptions, TurnCacheRecord};
|
||||
use crate::tui::history::HistoryCell;
|
||||
use codewhale_config::AppMode;
|
||||
use codewhale_models::Message;
|
||||
use codewhale_models::Role;
|
||||
use std::ffi::OsString;
|
||||
use std::path::PathBuf;
|
||||
use std::time::Instant;
|
||||
|
||||
@@ -10,13 +10,13 @@
|
||||
//! `/workflow` alone.
|
||||
|
||||
use crate::commands::traits::{CommandInfo, RegisterCommand};
|
||||
use crate::models::ContentBlock;
|
||||
use crate::tui::app::WORKFLOW_DRAFT_INSTRUCTION_PREFIX;
|
||||
use crate::tui::app::{App, AppAction};
|
||||
use codewhale_config::AppMode;
|
||||
#[cfg(test)]
|
||||
use codewhale_execpolicy::ApprovalMode;
|
||||
use codewhale_localization::MessageId;
|
||||
use codewhale_models::ContentBlock;
|
||||
|
||||
use super::CommandResult;
|
||||
|
||||
@@ -132,7 +132,7 @@ fn envelope_from_instruction(prefix: &str, instruction: &str) -> Option<Workflow
|
||||
serde_json::from_str(encoded).ok()
|
||||
}
|
||||
|
||||
fn user_instruction(message: &crate::models::Message) -> Option<&str> {
|
||||
fn user_instruction(message: &codewhale_models::Message) -> Option<&str> {
|
||||
if message.role != "user" {
|
||||
return None;
|
||||
}
|
||||
@@ -505,7 +505,7 @@ pub fn auto(app: &mut App, arg: Option<&str>) -> CommandResult {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::models::Role;
|
||||
use codewhale_models::Role;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::tui::app::TuiOptions;
|
||||
@@ -596,14 +596,14 @@ mod tests {
|
||||
assert_eq!(objective.chars().count(), WORKFLOW_OBJECTIVE_MAX_CHARS);
|
||||
assert!(objective.ends_with('…'));
|
||||
|
||||
app.api_messages.push(crate::models::Message {
|
||||
app.api_messages.push(codewhale_models::Message {
|
||||
role: Role::User,
|
||||
content: vec![ContentBlock::Text {
|
||||
text: instruction,
|
||||
cache_control: None,
|
||||
}],
|
||||
});
|
||||
app.api_messages.push(crate::models::Message {
|
||||
app.api_messages.push(codewhale_models::Message {
|
||||
role: Role::Assistant,
|
||||
content: vec![ContentBlock::Text {
|
||||
text: "Reviewed bounded objective and proposed phases.".to_string(),
|
||||
@@ -637,14 +637,14 @@ mod tests {
|
||||
else {
|
||||
panic!("expected WorkflowInstruction action");
|
||||
};
|
||||
app.api_messages.push(crate::models::Message {
|
||||
app.api_messages.push(codewhale_models::Message {
|
||||
role: Role::User,
|
||||
content: vec![ContentBlock::Text {
|
||||
text: format!("{instruction}\n\n---\n\nUser request: {display}"),
|
||||
cache_control: None,
|
||||
}],
|
||||
});
|
||||
app.api_messages.push(crate::models::Message {
|
||||
app.api_messages.push(codewhale_models::Message {
|
||||
role: Role::Assistant,
|
||||
content: vec![ContentBlock::Text {
|
||||
text: "Objective, phases, workers, and risks. Run /workflow confirm to start."
|
||||
@@ -657,7 +657,7 @@ mod tests {
|
||||
// explicit confirm must still find the reviewed draft (regression: the
|
||||
// old supersede rule cancelled the draft on any ordinary message and
|
||||
// made repeated confirm attempts impossible).
|
||||
app.api_messages.push(crate::models::Message {
|
||||
app.api_messages.push(codewhale_models::Message {
|
||||
role: Role::User,
|
||||
content: vec![ContentBlock::Text {
|
||||
text: "hmm it won't let me confirm it lol".to_string(),
|
||||
@@ -680,7 +680,7 @@ mod tests {
|
||||
else {
|
||||
panic!("expected WorkflowInstruction action");
|
||||
};
|
||||
app.api_messages.push(crate::models::Message {
|
||||
app.api_messages.push(codewhale_models::Message {
|
||||
role: Role::User,
|
||||
content: vec![ContentBlock::Text {
|
||||
text: format!("{redraft_instruction}\n\n---\n\nUser request: {redraft_display}"),
|
||||
@@ -711,7 +711,7 @@ mod tests {
|
||||
else {
|
||||
panic!("expected WorkflowInstruction action");
|
||||
};
|
||||
app.api_messages.push(crate::models::Message {
|
||||
app.api_messages.push(codewhale_models::Message {
|
||||
role: Role::User,
|
||||
content: vec![ContentBlock::Text {
|
||||
text: format!("{instruction}\n\n---\n\nUser request: {display}"),
|
||||
@@ -722,7 +722,7 @@ mod tests {
|
||||
workflow(&mut app, Some("confirm")).is_error,
|
||||
"a failed or unfinished draft turn is not a reviewed plan"
|
||||
);
|
||||
app.api_messages.push(crate::models::Message {
|
||||
app.api_messages.push(codewhale_models::Message {
|
||||
role: Role::Assistant,
|
||||
content: vec![ContentBlock::Text {
|
||||
text: "Objective, phases, workers, and risks. Run /workflow confirm to start."
|
||||
@@ -748,7 +748,7 @@ mod tests {
|
||||
"only the later explicit confirmation restores the normal catalog"
|
||||
);
|
||||
|
||||
app.api_messages.push(crate::models::Message {
|
||||
app.api_messages.push(codewhale_models::Message {
|
||||
role: Role::User,
|
||||
content: vec![ContentBlock::Text {
|
||||
text: instruction,
|
||||
@@ -851,14 +851,14 @@ mod tests {
|
||||
Some(Vec::new())
|
||||
);
|
||||
|
||||
app.api_messages.push(crate::models::Message {
|
||||
app.api_messages.push(codewhale_models::Message {
|
||||
role: Role::User,
|
||||
content: vec![ContentBlock::Text {
|
||||
text: instruction,
|
||||
cache_control: None,
|
||||
}],
|
||||
});
|
||||
app.api_messages.push(crate::models::Message {
|
||||
app.api_messages.push(codewhale_models::Message {
|
||||
role: Role::Assistant,
|
||||
content: vec![ContentBlock::Text {
|
||||
text: "Saved Workflow path and risks reviewed.".to_string(),
|
||||
|
||||
@@ -4,9 +4,9 @@ use std::time::Instant;
|
||||
|
||||
use super::CommandResult;
|
||||
use crate::client::{CacheWarmupKey, PromptInspection, inspect_prompt_for_request};
|
||||
use crate::models::MessageRequest;
|
||||
use crate::tui::app::{App, AppAction, TurnCacheRecord};
|
||||
use codewhale_localization::{Locale, MessageId, tr};
|
||||
use codewhale_models::MessageRequest;
|
||||
|
||||
/// Show per-turn DeepSeek prefix-cache telemetry for the last N turns (#263).
|
||||
///
|
||||
@@ -675,7 +675,7 @@ fn format_cache_history(app: &App, count: usize, locale: Locale) -> String {
|
||||
let replay_cell = rec
|
||||
.reasoning_replay_tokens
|
||||
.map_or_else(|| "—".to_string(), |t| t.to_string());
|
||||
let classes = crate::pricing::token_usage_for_pricing(&crate::models::Usage {
|
||||
let classes = crate::pricing::token_usage_for_pricing(&codewhale_models::Usage {
|
||||
input_tokens: rec.input_tokens,
|
||||
output_tokens: rec.output_tokens,
|
||||
prompt_cache_hit_tokens: rec.cache_hit_tokens,
|
||||
|
||||
@@ -187,7 +187,7 @@ fn parse_args(raw: &str) -> Result<PreviewArgs, String> {
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::config::Config;
|
||||
use crate::models::Role;
|
||||
use codewhale_models::Role;
|
||||
|
||||
fn args(raw: &str) -> Result<PreviewArgs, String> {
|
||||
parse_args(raw)
|
||||
@@ -366,9 +366,9 @@ mod tests {
|
||||
"/tmp/test-workspace-preview-request-pure",
|
||||
));
|
||||
let mut app = App::new(options, &Config::default());
|
||||
app.api_messages.push(crate::models::Message {
|
||||
app.api_messages.push(codewhale_models::Message {
|
||||
role: Role::User,
|
||||
content: vec![crate::models::ContentBlock::Text {
|
||||
content: vec![codewhale_models::ContentBlock::Text {
|
||||
text: "hello".to_string(),
|
||||
cache_control: None,
|
||||
}],
|
||||
|
||||
@@ -3,10 +3,10 @@ use super::tokens::{context, cost, system_prompt, tokens};
|
||||
use super::undo::{patch_undo, prune_undone_tool_context, retry, undo_conversation};
|
||||
use crate::client::CacheWarmupKey;
|
||||
use crate::config::Config;
|
||||
use crate::models::Role;
|
||||
use crate::models::{ContentBlock, Message, SystemBlock, SystemPrompt, Tool};
|
||||
use crate::tui::app::{App, AppAction, TuiOptions, TurnCacheRecord};
|
||||
use crate::tui::history::{GenericToolCell, HistoryCell, ToolCell, ToolStatus};
|
||||
use codewhale_models::Role;
|
||||
use codewhale_models::{ContentBlock, Message, SystemBlock, SystemPrompt, Tool};
|
||||
use std::path::PathBuf;
|
||||
use std::time::Instant;
|
||||
|
||||
@@ -139,7 +139,7 @@ fn cost_report_states_its_coverage_and_names_what_it_excludes() {
|
||||
use crate::pricing::audit_turn_cost_for_provider_at;
|
||||
|
||||
let mut app = create_test_app();
|
||||
let write_heavy = crate::models::Usage {
|
||||
let write_heavy = codewhale_models::Usage {
|
||||
input_tokens: 1_000_000,
|
||||
output_tokens: 100_000,
|
||||
prompt_cache_hit_tokens: Some(200_000),
|
||||
@@ -207,7 +207,7 @@ fn cost_report_states_its_coverage_and_names_what_it_excludes() {
|
||||
#[test]
|
||||
fn cost_coverage_is_currency_specific_for_mixed_deepseek_openai() {
|
||||
let mut app = create_test_app();
|
||||
let usage = crate::models::Usage {
|
||||
let usage = codewhale_models::Usage {
|
||||
input_tokens: 10_000,
|
||||
output_tokens: 1_000,
|
||||
..Default::default()
|
||||
@@ -333,7 +333,7 @@ fn reset_cost_coverage_clears_every_counter() {
|
||||
use crate::pricing::audit_turn_cost_for_provider_at;
|
||||
|
||||
let mut app = create_test_app();
|
||||
let usage = crate::models::Usage {
|
||||
let usage = codewhale_models::Usage {
|
||||
input_tokens: 1_000_000,
|
||||
output_tokens: 100_000,
|
||||
prompt_cache_write_tokens: Some(100_000),
|
||||
@@ -390,7 +390,7 @@ fn tokens_report_says_estimate_and_exposes_coverage_and_cache_write() {
|
||||
app.record_turn_cost_audit(&crate::pricing::audit_turn_cost_for_provider_at(
|
||||
crate::config::ApiProvider::Moonshot,
|
||||
"kimi-k2.7-code",
|
||||
&crate::models::Usage {
|
||||
&codewhale_models::Usage {
|
||||
input_tokens: 1_000_000,
|
||||
output_tokens: 100_000,
|
||||
prompt_cache_write_tokens: Some(100_000),
|
||||
@@ -691,14 +691,14 @@ fn cache_inspect_reports_divergence_from_previous_request() {
|
||||
));
|
||||
app.api_messages.push(Message {
|
||||
role: Role::Assistant,
|
||||
content: vec![crate::models::ContentBlock::Text {
|
||||
content: vec![codewhale_models::ContentBlock::Text {
|
||||
text: "Prior answer".to_string(),
|
||||
cache_control: None,
|
||||
}],
|
||||
});
|
||||
app.api_messages.push(Message {
|
||||
role: Role::User,
|
||||
content: vec![crate::models::ContentBlock::Text {
|
||||
content: vec![codewhale_models::ContentBlock::Text {
|
||||
text: "First task".to_string(),
|
||||
cache_control: None,
|
||||
}],
|
||||
@@ -710,7 +710,7 @@ fn cache_inspect_reports_divergence_from_previous_request() {
|
||||
assert!(first.contains("Static base prefix stability: no previous request"));
|
||||
|
||||
if let Some(last) = app.api_messages.last_mut()
|
||||
&& let Some(crate::models::ContentBlock::Text { text, .. }) = last.content.first_mut()
|
||||
&& let Some(codewhale_models::ContentBlock::Text { text, .. }) = last.content.first_mut()
|
||||
{
|
||||
*text = "Second task".to_string();
|
||||
}
|
||||
@@ -919,7 +919,7 @@ fn cache_history_shows_cache_write_tokens_and_explains_unpriced_turns() {
|
||||
use crate::pricing::audit_turn_cost_for_provider_at;
|
||||
|
||||
let mut app = create_test_app();
|
||||
let write_heavy = crate::models::Usage {
|
||||
let write_heavy = codewhale_models::Usage {
|
||||
input_tokens: 1_000_000,
|
||||
output_tokens: 100_000,
|
||||
prompt_cache_hit_tokens: Some(200_000),
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
//! Token/cost introspection and context commands.
|
||||
|
||||
use crate::compaction::estimate_input_tokens_conservative;
|
||||
use crate::models::SystemPrompt;
|
||||
use crate::tui::app::{App, AppAction};
|
||||
use codewhale_localization::{Locale, MessageId, tr};
|
||||
use codewhale_models::SystemPrompt;
|
||||
|
||||
use super::CommandResult;
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
//! Undo, retry, edit, and diff commands.
|
||||
|
||||
use crate::dependencies::{ExternalTool, Git};
|
||||
use crate::models::ContentBlock;
|
||||
use crate::tui::app::{App, AppAction};
|
||||
use crate::tui::history::HistoryCell;
|
||||
use codewhale_models::ContentBlock;
|
||||
|
||||
use super::CommandResult;
|
||||
|
||||
|
||||
@@ -15,10 +15,10 @@ use regex::Regex;
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::commands::traits::{CommandInfo, RegisterCommand};
|
||||
use crate::models::{ContentBlock, Message, Role};
|
||||
use crate::tui::app::App;
|
||||
use crate::tui::history::HistoryCell;
|
||||
use codewhale_localization::MessageId;
|
||||
use codewhale_models::{ContentBlock, Message, Role};
|
||||
|
||||
use super::CommandResult;
|
||||
|
||||
@@ -950,9 +950,9 @@ fn set_owner_only(_path: &Path) -> std::io::Result<()> {
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::config::Config;
|
||||
use crate::models::{ImageUrlContent, ToolCaller};
|
||||
use crate::tui::app::{App, TuiOptions};
|
||||
use crate::tui::clipboard::ClipboardHandler;
|
||||
use codewhale_models::{ImageUrlContent, ToolCaller};
|
||||
use tempfile::TempDir;
|
||||
|
||||
fn test_app(tmpdir: &TempDir) -> App {
|
||||
|
||||
@@ -44,9 +44,9 @@ use serde_json::{Value, json};
|
||||
use unicode_segmentation::UnicodeSegmentation;
|
||||
|
||||
use crate::commands::traits::{CommandInfo, RegisterCommand};
|
||||
use crate::models::{ContentBlock, Message};
|
||||
use crate::tui::app::App;
|
||||
use codewhale_localization::{Locale, MessageId, tr};
|
||||
use codewhale_models::{ContentBlock, Message};
|
||||
|
||||
use super::CommandResult;
|
||||
use super::export::{is_internal_role, is_sensitive_key, redact_json, sanitize_text};
|
||||
@@ -1238,11 +1238,11 @@ fn caps_value(caps: &Caps) -> Value {
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::config::Config;
|
||||
use crate::models::Role;
|
||||
use crate::models::{ImageUrlContent, ToolCaller};
|
||||
use crate::tools::plan::{PlanItemArg, StepStatus, UpdatePlanArgs};
|
||||
use crate::tui::app::TuiOptions;
|
||||
use crate::tui::clipboard::ClipboardHandler;
|
||||
use codewhale_models::Role;
|
||||
use codewhale_models::{ImageUrlContent, ToolCaller};
|
||||
use tempfile::TempDir;
|
||||
|
||||
fn test_app(tmpdir: &TempDir) -> App {
|
||||
|
||||
@@ -8,12 +8,12 @@ use tempfile::TempDir;
|
||||
|
||||
use crate::commands::{self, CommandResult};
|
||||
use crate::config::Config;
|
||||
use crate::models::{ContentBlock, Message, Role};
|
||||
use crate::session_manager::{SavedSession, SessionManager, create_saved_session_with_id_and_mode};
|
||||
use crate::test_support::{EnvVarGuard, lock_test_env};
|
||||
use crate::tui::app::{App, AppAction, TuiOptions};
|
||||
use crate::tui::history::HistoryCell;
|
||||
use crate::tui::views::ModalKind;
|
||||
use codewhale_models::{ContentBlock, Message, Role};
|
||||
|
||||
const FEATURE_NAME: &str = "Session command workflows";
|
||||
const FEATURE_PATH: &str = concat!(
|
||||
|
||||
@@ -13,12 +13,12 @@ use tempfile::TempDir;
|
||||
use crate::commands::groups::session::MAX_TITLE_LEN;
|
||||
use crate::commands::{CommandResult, execute};
|
||||
use crate::config::{ApiProvider, Config};
|
||||
use crate::models::{ContentBlock, Message, Role, SystemPrompt};
|
||||
use crate::session_manager::{SessionManager, create_saved_session_with_mode};
|
||||
use crate::test_support::{EnvVarGuard, TestEnvLock};
|
||||
use crate::tui::app::{App, AppAction, TuiOptions};
|
||||
use codewhale_config::AppMode;
|
||||
use codewhale_localization::{Locale, MessageId, tr};
|
||||
use codewhale_models::{ContentBlock, Message, Role, SystemPrompt};
|
||||
|
||||
/// Owns the global environment lock for as long as its CODEWHALE_HOME guard.
|
||||
/// Fields are ordered so the guard restores the environment before the lock
|
||||
|
||||
@@ -10,13 +10,13 @@ use tempfile::TempDir;
|
||||
|
||||
use crate::commands::CommandResult;
|
||||
use crate::config::Config;
|
||||
use crate::models::Role;
|
||||
use crate::reasoning_preference::ReasoningEffort;
|
||||
use crate::session_manager::create_saved_session_with_id_and_mode;
|
||||
use crate::test_support::EnvVarGuard;
|
||||
use crate::tui::app::{App, AppAction, TuiOptions, TurnCacheRecord};
|
||||
use crate::tui::history::HistoryCell;
|
||||
use codewhale_config::AppMode;
|
||||
use codewhale_models::Role;
|
||||
|
||||
fn dispatch_lifecycle(app: &mut App, name: &str, arg: Option<&str>) -> CommandResult {
|
||||
let command = match arg {
|
||||
@@ -170,9 +170,9 @@ fn fork_saves_parent_and_switches_to_child_session() {
|
||||
.expect("fixed parent timestamp");
|
||||
app.current_session_metadata = Some(cached_parent.clone());
|
||||
app.session_title = Some(cached_parent.title.clone());
|
||||
app.api_messages.push(crate::models::Message {
|
||||
app.api_messages.push(codewhale_models::Message {
|
||||
role: Role::User,
|
||||
content: vec![crate::models::ContentBlock::Text {
|
||||
content: vec![codewhale_models::ContentBlock::Text {
|
||||
text: "try another path".to_string(),
|
||||
cache_control: None,
|
||||
}],
|
||||
@@ -258,9 +258,9 @@ fn fork_rejects_active_runtime_without_switching_sessions() {
|
||||
let tmpdir = TempDir::new().unwrap();
|
||||
let mut app = create_test_app_with_tmpdir(&tmpdir);
|
||||
app.current_session_id = Some("parent-session".to_string());
|
||||
app.api_messages.push(crate::models::Message {
|
||||
app.api_messages.push(codewhale_models::Message {
|
||||
role: Role::User,
|
||||
content: vec![crate::models::ContentBlock::Text {
|
||||
content: vec![codewhale_models::ContentBlock::Text {
|
||||
text: "still running".to_string(),
|
||||
cache_control: None,
|
||||
}],
|
||||
@@ -281,9 +281,9 @@ fn new_session_from_resumed_state_creates_distinct_empty_session() {
|
||||
let mut app = create_test_app_with_tmpdir(&tmpdir);
|
||||
app.current_session_id = Some("old-session".to_string());
|
||||
app.session_title = Some("Old Session".to_string());
|
||||
app.api_messages.push(crate::models::Message {
|
||||
app.api_messages.push(codewhale_models::Message {
|
||||
role: Role::User,
|
||||
content: vec![crate::models::ContentBlock::Text {
|
||||
content: vec![codewhale_models::ContentBlock::Text {
|
||||
text: "continue this thread".to_string(),
|
||||
cache_control: None,
|
||||
}],
|
||||
@@ -291,7 +291,9 @@ fn new_session_from_resumed_state_creates_distinct_empty_session() {
|
||||
app.add_message(HistoryCell::System {
|
||||
content: "old transcript".to_string(),
|
||||
});
|
||||
app.system_prompt = Some(crate::models::SystemPrompt::Text("old prompt".to_string()));
|
||||
app.system_prompt = Some(codewhale_models::SystemPrompt::Text(
|
||||
"old prompt".to_string(),
|
||||
));
|
||||
app.session.total_tokens = 123;
|
||||
app.session.session_cost = 1.25;
|
||||
|
||||
@@ -384,7 +386,7 @@ fn new_session_force_cannot_detach_an_in_flight_turn() {
|
||||
let tmpdir = TempDir::new().unwrap();
|
||||
let mut app = create_test_app_with_tmpdir(&tmpdir);
|
||||
app.current_session_id = Some("old-session".to_string());
|
||||
app.api_messages.push(crate::models::Message {
|
||||
app.api_messages.push(codewhale_models::Message {
|
||||
role: Role::User,
|
||||
content: vec![],
|
||||
});
|
||||
@@ -410,7 +412,7 @@ fn load_rejects_an_active_runtime_before_reading_or_mutating() {
|
||||
let tmpdir = TempDir::new().unwrap();
|
||||
let mut app = create_test_app_with_tmpdir(&tmpdir);
|
||||
app.current_session_id = Some("old-session".to_string());
|
||||
app.api_messages.push(crate::models::Message {
|
||||
app.api_messages.push(codewhale_models::Message {
|
||||
role: Role::User,
|
||||
content: vec![],
|
||||
});
|
||||
@@ -529,9 +531,9 @@ fn test_load_valid_session_defers_state_restore_to_event_loop() {
|
||||
let tmpdir = TempDir::new().unwrap();
|
||||
let mut app1 = create_test_app_with_tmpdir(&tmpdir);
|
||||
// Set up some state to save
|
||||
app1.api_messages.push(crate::models::Message {
|
||||
app1.api_messages.push(codewhale_models::Message {
|
||||
role: Role::User,
|
||||
content: vec![crate::models::ContentBlock::Text {
|
||||
content: vec![codewhale_models::ContentBlock::Text {
|
||||
text: "Hello".to_string(),
|
||||
cache_control: None,
|
||||
}],
|
||||
@@ -543,7 +545,7 @@ fn test_load_valid_session_defers_state_restore_to_event_loop() {
|
||||
|
||||
// Create new app and load
|
||||
let mut app2 = create_test_app_with_tmpdir(&tmpdir);
|
||||
app2.system_prompt = Some(crate::models::SystemPrompt::Text(
|
||||
app2.system_prompt = Some(codewhale_models::SystemPrompt::Text(
|
||||
"stale prompt from prior session".to_string(),
|
||||
));
|
||||
app2.session_context_references
|
||||
@@ -614,7 +616,7 @@ fn explicit_save_persists_work_state_and_load_defers_application() {
|
||||
fn new_session_is_all_or_nothing_when_work_state_is_busy() {
|
||||
let tmpdir = TempDir::new().unwrap();
|
||||
let mut app = create_test_app_with_tmpdir(&tmpdir);
|
||||
app.api_messages.push(crate::models::Message {
|
||||
app.api_messages.push(codewhale_models::Message {
|
||||
role: Role::User,
|
||||
content: vec![],
|
||||
});
|
||||
@@ -706,9 +708,9 @@ fn load_defers_artifact_registry_restore_to_event_loop() {
|
||||
fn load_defers_telemetry_reset_to_event_loop() {
|
||||
let tmpdir = TempDir::new().unwrap();
|
||||
let mut saved_app = create_test_app_with_tmpdir(&tmpdir);
|
||||
saved_app.api_messages.push(crate::models::Message {
|
||||
saved_app.api_messages.push(codewhale_models::Message {
|
||||
role: Role::User,
|
||||
content: vec![crate::models::ContentBlock::Text {
|
||||
content: vec![codewhale_models::ContentBlock::Text {
|
||||
text: "checkpoint".to_string(),
|
||||
cache_control: None,
|
||||
}],
|
||||
|
||||
@@ -8,8 +8,8 @@ use std::time::Duration;
|
||||
use crate::config::DEFAULT_TEXT_MODEL;
|
||||
use crate::core::model_client::ModelClient;
|
||||
use crate::logging;
|
||||
use crate::models::Role;
|
||||
use crate::models::{
|
||||
use codewhale_models::Role;
|
||||
use codewhale_models::{
|
||||
CacheControl, ContentBlock, Message, MessageRequest, SystemBlock, SystemPrompt, Usage,
|
||||
};
|
||||
|
||||
@@ -1536,10 +1536,10 @@ async fn create_summary(
|
||||
// Usage above is already billed; a provider-declared incomplete
|
||||
// summary must still fail rather than replace the session history
|
||||
// with a fragment.
|
||||
if crate::models::is_incomplete_stop_reason(response.stop_reason.as_deref()) {
|
||||
if codewhale_models::is_incomplete_stop_reason(response.stop_reason.as_deref()) {
|
||||
anyhow::bail!(
|
||||
"Compaction summary response incomplete: provider stop reason `{}`; the partial summary was not accepted.",
|
||||
crate::models::stop_reason_detail(response.stop_reason.as_deref())
|
||||
codewhale_models::stop_reason_detail(response.stop_reason.as_deref())
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1633,7 +1633,7 @@ mod quota_tests;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::models::{ImageUrlContent, Message};
|
||||
use codewhale_models::{ImageUrlContent, Message};
|
||||
|
||||
#[test]
|
||||
fn inline_image_estimates_nonzero_tokens() {
|
||||
@@ -1970,7 +1970,7 @@ mod tests {
|
||||
async fn create_message(
|
||||
&self,
|
||||
request: MessageRequest,
|
||||
) -> anyhow::Result<crate::models::MessageResponse> {
|
||||
) -> anyhow::Result<codewhale_models::MessageResponse> {
|
||||
self.requests
|
||||
.lock()
|
||||
.expect("capture scripted summary request")
|
||||
@@ -1988,7 +1988,7 @@ mod tests {
|
||||
}
|
||||
let content = outcome
|
||||
.ok_or_else(|| anyhow::anyhow!("scripted summary responses exhausted"))??;
|
||||
Ok(crate::models::MessageResponse {
|
||||
Ok(codewhale_models::MessageResponse {
|
||||
id: "summary-scripted".to_string(),
|
||||
r#type: "message".to_string(),
|
||||
role: "assistant".to_string(),
|
||||
@@ -2032,9 +2032,9 @@ mod tests {
|
||||
async fn create_message(
|
||||
&self,
|
||||
request: MessageRequest,
|
||||
) -> anyhow::Result<crate::models::MessageResponse> {
|
||||
) -> anyhow::Result<codewhale_models::MessageResponse> {
|
||||
*self.request.lock().expect("capture summary request") = Some(request);
|
||||
Ok(crate::models::MessageResponse {
|
||||
Ok(codewhale_models::MessageResponse {
|
||||
id: "summary-fixture".to_string(),
|
||||
r#type: "message".to_string(),
|
||||
role: "assistant".to_string(),
|
||||
@@ -2046,7 +2046,7 @@ mod tests {
|
||||
stop_reason: None,
|
||||
stop_sequence: None,
|
||||
container: None,
|
||||
usage: crate::models::Usage::default(),
|
||||
usage: codewhale_models::Usage::default(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -2572,8 +2572,8 @@ mod tests {
|
||||
async fn create_message(
|
||||
&self,
|
||||
_request: MessageRequest,
|
||||
) -> anyhow::Result<crate::models::MessageResponse> {
|
||||
Ok(crate::models::MessageResponse {
|
||||
) -> anyhow::Result<codewhale_models::MessageResponse> {
|
||||
Ok(codewhale_models::MessageResponse {
|
||||
id: "summary-truncated".to_string(),
|
||||
r#type: "message".to_string(),
|
||||
role: "assistant".to_string(),
|
||||
@@ -2585,7 +2585,7 @@ mod tests {
|
||||
stop_reason: Some("max_tokens".to_string()),
|
||||
stop_sequence: None,
|
||||
container: None,
|
||||
usage: crate::models::Usage::default(),
|
||||
usage: codewhale_models::Usage::default(),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
use crate::models::{ContentBlock, Message, SystemPrompt};
|
||||
use codewhale_models::{ContentBlock, Message, SystemPrompt};
|
||||
|
||||
use super::{
|
||||
compaction_checkpoint_message, is_compaction_checkpoint_message, retained_user_messages,
|
||||
@@ -455,7 +455,7 @@ pub(super) fn build_replacement_history(
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::compaction::{COMPACTION_SUMMARY_MARKER, compaction_checkpoint_message};
|
||||
use crate::models::{ContentBlock, Role};
|
||||
use codewhale_models::{ContentBlock, Role};
|
||||
use serde_json::json;
|
||||
|
||||
fn msg(role: &str, text: &str) -> Message {
|
||||
|
||||
+26
-26
@@ -688,10 +688,10 @@ pub fn provider_capability_with_wire(
|
||||
return ProviderCapability {
|
||||
provider,
|
||||
resolved_model: resolved_model.to_string(),
|
||||
context_window: crate::models::context_window_for_model(resolved_model)
|
||||
.unwrap_or(crate::models::LEGACY_DEEPSEEK_CONTEXT_WINDOW_TOKENS),
|
||||
max_output: crate::models::max_output_tokens_for_model(resolved_model),
|
||||
thinking_supported: crate::models::model_supports_reasoning(resolved_model),
|
||||
context_window: codewhale_models::context_window_for_model(resolved_model)
|
||||
.unwrap_or(codewhale_models::LEGACY_DEEPSEEK_CONTEXT_WINDOW_TOKENS),
|
||||
max_output: codewhale_models::max_output_tokens_for_model(resolved_model),
|
||||
thinking_supported: codewhale_models::model_supports_reasoning(resolved_model),
|
||||
cache_telemetry_supported: false,
|
||||
request_payload_mode: RequestPayloadMode::AnthropicMessages,
|
||||
alias_deprecation: None,
|
||||
@@ -701,10 +701,10 @@ pub fn provider_capability_with_wire(
|
||||
return ProviderCapability {
|
||||
provider,
|
||||
resolved_model: resolved_model.to_string(),
|
||||
context_window: crate::models::context_window_for_model(resolved_model)
|
||||
.unwrap_or(crate::models::LEGACY_DEEPSEEK_CONTEXT_WINDOW_TOKENS),
|
||||
max_output: crate::models::max_output_tokens_for_model(resolved_model),
|
||||
thinking_supported: crate::models::model_supports_reasoning(resolved_model),
|
||||
context_window: codewhale_models::context_window_for_model(resolved_model)
|
||||
.unwrap_or(codewhale_models::LEGACY_DEEPSEEK_CONTEXT_WINDOW_TOKENS),
|
||||
max_output: codewhale_models::max_output_tokens_for_model(resolved_model),
|
||||
thinking_supported: codewhale_models::model_supports_reasoning(resolved_model),
|
||||
cache_telemetry_supported: false,
|
||||
request_payload_mode: RequestPayloadMode::Responses,
|
||||
alias_deprecation: None,
|
||||
@@ -721,7 +721,7 @@ pub fn provider_capability_with_wire(
|
||||
resolved_model: resolved_model.to_string(),
|
||||
// 200K is the conservative Anthropic floor; 4.6+ models resolve
|
||||
// their 1M windows from models.rs rows (#3014).
|
||||
context_window: crate::models::context_window_for_model(resolved_model)
|
||||
context_window: codewhale_models::context_window_for_model(resolved_model)
|
||||
.unwrap_or(200_000),
|
||||
// 64K is the documented Anthropic Messages floor. For a model
|
||||
// the catalogue describes this carries its documented ceiling;
|
||||
@@ -729,9 +729,9 @@ pub fn provider_capability_with_wire(
|
||||
// `route_budget::output_ceiling_source` labels it unverified so
|
||||
// no receipt renders it as "documented" (#5440).
|
||||
max_output: Some(
|
||||
crate::models::max_output_tokens_for_model(resolved_model).unwrap_or(64_000),
|
||||
codewhale_models::max_output_tokens_for_model(resolved_model).unwrap_or(64_000),
|
||||
),
|
||||
thinking_supported: crate::models::model_supports_reasoning(resolved_model),
|
||||
thinking_supported: codewhale_models::model_supports_reasoning(resolved_model),
|
||||
cache_telemetry_supported: matches!(provider, ApiProvider::Anthropic),
|
||||
request_payload_mode: RequestPayloadMode::AnthropicMessages,
|
||||
alias_deprecation: None,
|
||||
@@ -766,12 +766,12 @@ pub fn provider_capability_with_wire(
|
||||
return ProviderCapability {
|
||||
provider,
|
||||
resolved_model: resolved_model.to_string(),
|
||||
context_window: crate::models::context_window_for_model(resolved_model)
|
||||
.unwrap_or(crate::models::LEGACY_DEEPSEEK_CONTEXT_WINDOW_TOKENS),
|
||||
context_window: codewhale_models::context_window_for_model(resolved_model)
|
||||
.unwrap_or(codewhale_models::LEGACY_DEEPSEEK_CONTEXT_WINDOW_TOKENS),
|
||||
// No documented output maximum for these routes: stay unknown so
|
||||
// no compatibility clamp is applied downstream.
|
||||
max_output: crate::models::max_output_tokens_for_model(resolved_model),
|
||||
thinking_supported: crate::models::model_supports_reasoning(resolved_model),
|
||||
max_output: codewhale_models::max_output_tokens_for_model(resolved_model),
|
||||
thinking_supported: codewhale_models::model_supports_reasoning(resolved_model),
|
||||
cache_telemetry_supported: false,
|
||||
request_payload_mode: RequestPayloadMode::ChatCompletions,
|
||||
alias_deprecation: None,
|
||||
@@ -782,12 +782,12 @@ pub fn provider_capability_with_wire(
|
||||
return ProviderCapability {
|
||||
provider,
|
||||
resolved_model: resolved_model.to_string(),
|
||||
context_window: crate::models::context_window_for_model(resolved_model)
|
||||
.unwrap_or(crate::models::LEGACY_DEEPSEEK_CONTEXT_WINDOW_TOKENS),
|
||||
context_window: codewhale_models::context_window_for_model(resolved_model)
|
||||
.unwrap_or(codewhale_models::LEGACY_DEEPSEEK_CONTEXT_WINDOW_TOKENS),
|
||||
// No documented output maximum for these routes: stay unknown so
|
||||
// no compatibility clamp is applied downstream.
|
||||
max_output: crate::models::max_output_tokens_for_model(resolved_model),
|
||||
thinking_supported: crate::models::model_supports_reasoning(resolved_model),
|
||||
max_output: codewhale_models::max_output_tokens_for_model(resolved_model),
|
||||
thinking_supported: codewhale_models::model_supports_reasoning(resolved_model),
|
||||
cache_telemetry_supported: false,
|
||||
request_payload_mode: RequestPayloadMode::ChatCompletions,
|
||||
alias_deprecation: None,
|
||||
@@ -815,8 +815,8 @@ pub fn provider_capability_with_wire(
|
||||
let offering =
|
||||
crate::provider_lake::bundled_catalog_offering_for_model(provider, resolved_model);
|
||||
let context_window = if is_v4_pro || is_v4_flash {
|
||||
crate::models::DEEPSEEK_V4_CONTEXT_WINDOW_TOKENS
|
||||
} else if let Some(window) = crate::models::context_window_for_model(resolved_model) {
|
||||
codewhale_models::DEEPSEEK_V4_CONTEXT_WINDOW_TOKENS
|
||||
} else if let Some(window) = codewhale_models::context_window_for_model(resolved_model) {
|
||||
window
|
||||
} else if let Some(window) = offering
|
||||
.as_ref()
|
||||
@@ -828,7 +828,7 @@ pub fn provider_capability_with_wire(
|
||||
} else if matches!(provider, ApiProvider::Ollama) {
|
||||
8192
|
||||
} else {
|
||||
crate::models::LEGACY_DEEPSEEK_CONTEXT_WINDOW_TOKENS
|
||||
codewhale_models::LEGACY_DEEPSEEK_CONTEXT_WINDOW_TOKENS
|
||||
};
|
||||
|
||||
// Output limits require an exact catalog row or an explicitly recognized
|
||||
@@ -839,7 +839,7 @@ pub fn provider_capability_with_wire(
|
||||
// are owned by the membership catalog. It must not become a placeholder
|
||||
// number: a fabricated 4K here silently clamped offline membership routes
|
||||
// to 4K output via `route_budget`.
|
||||
let max_output = crate::models::max_output_tokens_for_model(resolved_model)
|
||||
let max_output = codewhale_models::max_output_tokens_for_model(resolved_model)
|
||||
.or_else(|| {
|
||||
// Provider-owned wire IDs need not exist in the legacy model-only
|
||||
// catalog (for example Fireworks' accounts/... slug). Reuse the
|
||||
@@ -857,7 +857,7 @@ pub fn provider_capability_with_wire(
|
||||
.as_ref()
|
||||
.map(|_| DEEPSEEK_ALIAS_REPLACEMENT)
|
||||
})
|
||||
.and_then(crate::models::max_output_tokens_for_model)
|
||||
.and_then(codewhale_models::max_output_tokens_for_model)
|
||||
});
|
||||
|
||||
// Exact catalog reasoning facts and recognized compatibility aliases only.
|
||||
@@ -867,7 +867,7 @@ pub fn provider_capability_with_wire(
|
||||
|| offering
|
||||
.as_ref()
|
||||
.is_some_and(|row| row.reasoning == Some(true))
|
||||
|| crate::models::model_supports_reasoning(resolved_model);
|
||||
|| codewhale_models::model_supports_reasoning(resolved_model);
|
||||
|
||||
// Cache telemetry: returned only by DeepSeek-native and NVIDIA NIM endpoints.
|
||||
let cache_telemetry_supported = matches!(
|
||||
@@ -1067,7 +1067,7 @@ pub fn validate_route(provider: ApiProvider, model: &str) -> Result<(), String>
|
||||
Ok(())
|
||||
}
|
||||
|
||||
use crate::models::canonical_official_deepseek_model_id;
|
||||
use codewhale_models::canonical_official_deepseek_model_id;
|
||||
|
||||
/// Resolve model names accepted by DeepSeek's first-party endpoints.
|
||||
///
|
||||
|
||||
@@ -126,11 +126,11 @@ pub const KIMI_CODE_K3_256K_MODEL: &str = "k3-256k";
|
||||
pub const KIMI_CODE_HIGHSPEED_MODEL: &str = "kimi-for-coding-highspeed";
|
||||
// The K3 contract constants (`KIMI_CODE_K3_CONTEXT_WINDOW_TOKENS`,
|
||||
// `KIMI_K3_CONTEXT_WINDOW_TOKENS`, and the distinct default/direct output
|
||||
// limits) live in `crate::models` — the model-facts table, which also compiles
|
||||
// limits) live in `codewhale_models` — the model-facts table, which also compiles
|
||||
// standalone in integration tests — so the facts have exactly one home.
|
||||
// Re-export only the route-owned floor, which existing `crate::config` call
|
||||
// sites import.
|
||||
pub use crate::models::KIMI_CODE_K3_CONTEXT_WINDOW_TOKENS;
|
||||
pub use codewhale_models::KIMI_CODE_K3_CONTEXT_WINDOW_TOKENS;
|
||||
pub const DEFAULT_SGLANG_MODEL: &str = "deepseek-ai/DeepSeek-V4-Pro";
|
||||
pub const DEFAULT_SGLANG_FLASH_MODEL: &str = "deepseek-ai/DeepSeek-V4-Flash";
|
||||
pub const DEFAULT_SGLANG_BASE_URL: &str = "http://localhost:30000/v1";
|
||||
|
||||
@@ -11426,7 +11426,7 @@ fn provider_capability_scenario() {
|
||||
let cap = provider_capability(ApiProvider::Deepseek, "deepseek-v4-pro");
|
||||
assert_eq!(
|
||||
cap.context_window,
|
||||
crate::models::DEEPSEEK_V4_CONTEXT_WINDOW_TOKENS
|
||||
codewhale_models::DEEPSEEK_V4_CONTEXT_WINDOW_TOKENS
|
||||
);
|
||||
assert_eq!(cap.max_output, Some(384_000));
|
||||
assert!(cap.thinking_supported);
|
||||
@@ -11444,7 +11444,7 @@ fn provider_capability_scenario() {
|
||||
);
|
||||
assert_eq!(
|
||||
cap.context_window,
|
||||
crate::models::DEEPSEEK_V4_CONTEXT_WINDOW_TOKENS
|
||||
codewhale_models::DEEPSEEK_V4_CONTEXT_WINDOW_TOKENS
|
||||
);
|
||||
assert_eq!(cap.max_output, Some(384_000));
|
||||
assert!(cap.thinking_supported);
|
||||
@@ -11461,12 +11461,12 @@ fn provider_capability_scenario() {
|
||||
assert_eq!(cap.resolved_model, DEFAULT_OPENMODEL_MODEL);
|
||||
assert_eq!(
|
||||
cap.context_window,
|
||||
crate::models::context_window_for_model(DEFAULT_OPENMODEL_MODEL).unwrap_or(200_000)
|
||||
codewhale_models::context_window_for_model(DEFAULT_OPENMODEL_MODEL).unwrap_or(200_000)
|
||||
);
|
||||
assert_eq!(
|
||||
cap.max_output,
|
||||
Some(
|
||||
crate::models::max_output_tokens_for_model(DEFAULT_OPENMODEL_MODEL)
|
||||
codewhale_models::max_output_tokens_for_model(DEFAULT_OPENMODEL_MODEL)
|
||||
.unwrap_or(64_000)
|
||||
)
|
||||
);
|
||||
@@ -11482,7 +11482,7 @@ fn provider_capability_scenario() {
|
||||
let cap = provider_capability(ApiProvider::Deepseek, "deepseek-v4-flash");
|
||||
assert_eq!(
|
||||
cap.context_window,
|
||||
crate::models::DEEPSEEK_V4_CONTEXT_WINDOW_TOKENS
|
||||
codewhale_models::DEEPSEEK_V4_CONTEXT_WINDOW_TOKENS
|
||||
);
|
||||
assert_eq!(cap.max_output, Some(384_000));
|
||||
assert!(cap.thinking_supported);
|
||||
@@ -11493,7 +11493,7 @@ fn provider_capability_scenario() {
|
||||
let cap = provider_capability(ApiProvider::Deepseek, "deepseek-chat");
|
||||
assert_eq!(
|
||||
cap.context_window,
|
||||
crate::models::DEEPSEEK_V4_CONTEXT_WINDOW_TOKENS
|
||||
codewhale_models::DEEPSEEK_V4_CONTEXT_WINDOW_TOKENS
|
||||
);
|
||||
assert_eq!(cap.max_output, Some(384_000));
|
||||
assert!(cap.thinking_supported);
|
||||
@@ -11513,7 +11513,7 @@ fn provider_capability_scenario() {
|
||||
let cap = provider_capability(ApiProvider::Deepseek, "deepseek-reasoner");
|
||||
assert_eq!(
|
||||
cap.context_window,
|
||||
crate::models::DEEPSEEK_V4_CONTEXT_WINDOW_TOKENS
|
||||
codewhale_models::DEEPSEEK_V4_CONTEXT_WINDOW_TOKENS
|
||||
);
|
||||
assert_eq!(cap.max_output, Some(384_000));
|
||||
assert!(cap.thinking_supported);
|
||||
@@ -11536,7 +11536,7 @@ fn provider_capability_scenario() {
|
||||
let cap = provider_capability(ApiProvider::NvidiaNim, DEFAULT_NVIDIA_NIM_MODEL);
|
||||
assert_eq!(
|
||||
cap.context_window,
|
||||
crate::models::DEEPSEEK_V4_CONTEXT_WINDOW_TOKENS
|
||||
codewhale_models::DEEPSEEK_V4_CONTEXT_WINDOW_TOKENS
|
||||
);
|
||||
assert_eq!(cap.max_output, Some(384_000));
|
||||
assert!(cap.thinking_supported);
|
||||
@@ -11556,7 +11556,7 @@ fn provider_capability_scenario_2() {
|
||||
let cap = provider_capability(ApiProvider::NvidiaNim, DEFAULT_NVIDIA_NIM_FLASH_MODEL);
|
||||
assert_eq!(
|
||||
cap.context_window,
|
||||
crate::models::DEEPSEEK_V4_CONTEXT_WINDOW_TOKENS
|
||||
codewhale_models::DEEPSEEK_V4_CONTEXT_WINDOW_TOKENS
|
||||
);
|
||||
assert_eq!(cap.max_output, Some(384_000));
|
||||
assert!(cap.thinking_supported);
|
||||
@@ -11581,11 +11581,11 @@ fn provider_capability_scenario_2() {
|
||||
let cap = provider_capability(ApiProvider::Together, TOGETHER_INKLING_MODEL);
|
||||
assert!(cap.thinking_supported);
|
||||
assert_eq!(
|
||||
crate::models::context_window_for_model(TOGETHER_INKLING_MODEL),
|
||||
codewhale_models::context_window_for_model(TOGETHER_INKLING_MODEL),
|
||||
None
|
||||
);
|
||||
assert_eq!(
|
||||
crate::models::max_output_tokens_for_model(TOGETHER_INKLING_MODEL),
|
||||
codewhale_models::max_output_tokens_for_model(TOGETHER_INKLING_MODEL),
|
||||
None
|
||||
);
|
||||
}
|
||||
@@ -11612,7 +11612,7 @@ fn provider_capability_scenario_2() {
|
||||
let cap = provider_capability(ApiProvider::Novita, DEFAULT_NOVITA_MODEL);
|
||||
assert_eq!(
|
||||
cap.context_window,
|
||||
crate::models::DEEPSEEK_V4_CONTEXT_WINDOW_TOKENS
|
||||
codewhale_models::DEEPSEEK_V4_CONTEXT_WINDOW_TOKENS
|
||||
);
|
||||
assert_eq!(cap.max_output, Some(384_000));
|
||||
assert!(cap.thinking_supported);
|
||||
@@ -11623,7 +11623,7 @@ fn provider_capability_scenario_2() {
|
||||
let cap = provider_capability(ApiProvider::Fireworks, DEFAULT_FIREWORKS_MODEL);
|
||||
assert_eq!(
|
||||
cap.context_window,
|
||||
crate::models::DEEPSEEK_V4_CONTEXT_WINDOW_TOKENS
|
||||
codewhale_models::DEEPSEEK_V4_CONTEXT_WINDOW_TOKENS
|
||||
);
|
||||
assert_eq!(cap.max_output, Some(384_000));
|
||||
assert!(cap.thinking_supported);
|
||||
@@ -11654,7 +11654,7 @@ fn provider_capability_scenario_2() {
|
||||
let cap = provider_capability(ApiProvider::Siliconflow, DEFAULT_SILICONFLOW_MODEL);
|
||||
assert_eq!(
|
||||
cap.context_window,
|
||||
crate::models::DEEPSEEK_V4_CONTEXT_WINDOW_TOKENS
|
||||
codewhale_models::DEEPSEEK_V4_CONTEXT_WINDOW_TOKENS
|
||||
);
|
||||
assert_eq!(cap.max_output, Some(384_000));
|
||||
assert!(cap.thinking_supported);
|
||||
@@ -11669,7 +11669,7 @@ fn provider_capability_scenario_2() {
|
||||
let cap = provider_capability(ApiProvider::Sglang, DEFAULT_SGLANG_MODEL);
|
||||
assert_eq!(
|
||||
cap.context_window,
|
||||
crate::models::DEEPSEEK_V4_CONTEXT_WINDOW_TOKENS
|
||||
codewhale_models::DEEPSEEK_V4_CONTEXT_WINDOW_TOKENS
|
||||
);
|
||||
assert_eq!(cap.max_output, Some(384_000));
|
||||
assert!(cap.thinking_supported);
|
||||
@@ -11682,7 +11682,7 @@ fn provider_capability_openrouter_v4_pro_has_thinking_no_cache() {
|
||||
let cap = provider_capability(ApiProvider::Openrouter, DEFAULT_OPENROUTER_MODEL);
|
||||
assert_eq!(
|
||||
cap.context_window,
|
||||
crate::models::DEEPSEEK_V4_CONTEXT_WINDOW_TOKENS
|
||||
codewhale_models::DEEPSEEK_V4_CONTEXT_WINDOW_TOKENS
|
||||
);
|
||||
assert_eq!(cap.max_output, Some(384_000));
|
||||
assert!(cap.thinking_supported);
|
||||
@@ -11801,7 +11801,7 @@ fn provider_capability_arcee_direct_models_use_api_docs_shape() {
|
||||
// now says so instead of fabricating a 4K request fallback.
|
||||
assert_eq!(mini.max_output, None);
|
||||
assert_eq!(
|
||||
crate::models::max_output_tokens_for_model(ARCEE_TRINITY_MINI_MODEL),
|
||||
codewhale_models::max_output_tokens_for_model(ARCEE_TRINITY_MINI_MODEL),
|
||||
None
|
||||
);
|
||||
assert!(mini.thinking_supported);
|
||||
@@ -11820,7 +11820,7 @@ fn provider_capability_scenario_3() {
|
||||
let cap = provider_capability(ApiProvider::Openai, "glm-5");
|
||||
assert_eq!(
|
||||
cap.context_window,
|
||||
crate::models::LEGACY_DEEPSEEK_CONTEXT_WINDOW_TOKENS
|
||||
codewhale_models::LEGACY_DEEPSEEK_CONTEXT_WINDOW_TOKENS
|
||||
);
|
||||
assert_eq!(cap.max_output, None);
|
||||
assert!(!cap.thinking_supported);
|
||||
@@ -11838,7 +11838,7 @@ fn provider_capability_scenario_3() {
|
||||
let cap = provider_capability(ApiProvider::Atlascloud, "deepseek-ai/deepseek-v4-flash");
|
||||
assert_eq!(
|
||||
cap.context_window,
|
||||
crate::models::DEEPSEEK_V4_CONTEXT_WINDOW_TOKENS
|
||||
codewhale_models::DEEPSEEK_V4_CONTEXT_WINDOW_TOKENS
|
||||
);
|
||||
assert_eq!(cap.max_output, Some(384_000));
|
||||
assert!(cap.thinking_supported);
|
||||
@@ -11877,7 +11877,7 @@ fn provider_capability_scenario_3() {
|
||||
let cap = provider_capability(ApiProvider::WanjieArk, DEFAULT_WANJIE_ARK_MODEL);
|
||||
assert_eq!(
|
||||
cap.context_window,
|
||||
crate::models::LEGACY_DEEPSEEK_CONTEXT_WINDOW_TOKENS
|
||||
codewhale_models::LEGACY_DEEPSEEK_CONTEXT_WINDOW_TOKENS
|
||||
);
|
||||
assert_eq!(cap.max_output, None);
|
||||
assert!(cap.thinking_supported);
|
||||
@@ -11909,7 +11909,7 @@ fn provider_capability_scenario_3() {
|
||||
let cap = provider_capability(ApiProvider::Ollama, "deepseek-v3.1:671b");
|
||||
assert_eq!(cap.context_window, 8192);
|
||||
assert_eq!(
|
||||
crate::models::context_window_for_model("deepseek-v3.1:671b"),
|
||||
codewhale_models::context_window_for_model("deepseek-v3.1:671b"),
|
||||
None
|
||||
);
|
||||
assert_eq!(cap.max_output, None);
|
||||
@@ -12039,7 +12039,7 @@ fn provider_capability_scenario_4() {
|
||||
let cap = provider_capability(ApiProvider::Deepseek, "deepseek-coder");
|
||||
assert_eq!(
|
||||
cap.context_window,
|
||||
crate::models::LEGACY_DEEPSEEK_CONTEXT_WINDOW_TOKENS
|
||||
codewhale_models::LEGACY_DEEPSEEK_CONTEXT_WINDOW_TOKENS
|
||||
);
|
||||
assert_eq!(cap.max_output, None);
|
||||
assert!(!cap.thinking_supported);
|
||||
|
||||
@@ -13,11 +13,11 @@ use serde::Serialize;
|
||||
use crate::compaction::{estimate_input_tokens_conservative, estimate_text_tokens_conservative};
|
||||
use crate::config::Config;
|
||||
use crate::context_budget::PressureLevel;
|
||||
use crate::models::{CacheControl, ContentBlock, Message, SystemPrompt, Tool};
|
||||
use crate::prompts::{CORE_EXECUTION_PROFILE_PROMPT, Personality};
|
||||
use crate::route_budget::route_context_window_tokens;
|
||||
use crate::tui::app::App;
|
||||
use codewhale_config::AppMode;
|
||||
use codewhale_models::{CacheControl, ContentBlock, Message, SystemPrompt, Tool};
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct PromptSourceMap {
|
||||
@@ -955,10 +955,10 @@ pub fn prompt_context_json(context: &PromptContext) -> String {
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::config::{ApiProvider, Config};
|
||||
use crate::models::Role;
|
||||
use crate::models::Tool;
|
||||
use crate::route_runtime::{ContextWindowResolution, ContextWindowSource};
|
||||
use codewhale_config::route::RouteLimits;
|
||||
use codewhale_models::Role;
|
||||
use codewhale_models::Tool;
|
||||
use std::fs;
|
||||
use tempfile::tempdir;
|
||||
|
||||
@@ -1377,7 +1377,7 @@ mod tests {
|
||||
// deepseek-v4-pro defaults to a 1M window; a resolved route advertising a
|
||||
// smaller window must win in the report's context_window_tokens.
|
||||
let route_window = 128_000u64;
|
||||
let model_default = crate::models::context_window_for_model("deepseek-v4-pro")
|
||||
let model_default = codewhale_models::context_window_for_model("deepseek-v4-pro")
|
||||
.expect("model has a default window");
|
||||
assert_ne!(
|
||||
u64::from(model_default),
|
||||
|
||||
@@ -32,12 +32,6 @@ use crate::core::model_client::SharedModelClient;
|
||||
use crate::error_taxonomy::{ErrorCategory, ErrorEnvelope, ErrorSeverity, StreamError};
|
||||
use crate::features::{Feature, Features};
|
||||
use crate::mcp::{McpConfig, McpPool};
|
||||
#[cfg(test)]
|
||||
use crate::models::ToolCaller;
|
||||
use crate::models::{
|
||||
ContentBlock, ContentBlockStart, Delta, Message, StreamEvent, SystemPrompt, Tool, Usage,
|
||||
is_incomplete_stop_reason, is_output_limit_stop_reason, stop_reason_detail,
|
||||
};
|
||||
use crate::prompts;
|
||||
use crate::purge::{emit_purge_completed, emit_purge_failed, emit_purge_started, run_purge};
|
||||
#[cfg(test)]
|
||||
@@ -71,6 +65,12 @@ use crate::worker_profile::WorkerRuntimeProfile;
|
||||
use crate::working_set::WorkingSet;
|
||||
use codewhale_config::AppMode;
|
||||
use codewhale_execpolicy::ApprovalMode;
|
||||
#[cfg(test)]
|
||||
use codewhale_models::ToolCaller;
|
||||
use codewhale_models::{
|
||||
ContentBlock, ContentBlockStart, Delta, Message, StreamEvent, SystemPrompt, Tool, Usage,
|
||||
is_incomplete_stop_reason, is_output_limit_stop_reason, stop_reason_detail,
|
||||
};
|
||||
|
||||
#[cfg(test)]
|
||||
use super::authority::agent_approval_mode_for_turn;
|
||||
@@ -85,7 +85,7 @@ use super::ops::{
|
||||
use super::session::Session;
|
||||
use super::tool_parser;
|
||||
use super::turn::{TurnContext, post_turn_snapshot, pre_turn_snapshot};
|
||||
use crate::models::Role;
|
||||
use codewhale_models::Role;
|
||||
|
||||
const ENGINE_OP_CHANNEL_CAPACITY: usize = 32;
|
||||
const GOAL_CONTINUATION_FAILURE_DETAIL_MAX_BYTES: usize = 512;
|
||||
@@ -3539,7 +3539,7 @@ impl Engine {
|
||||
let already_committed = self.session.messages.last().is_some_and(|last| {
|
||||
matches!(
|
||||
last.role.as_str(),
|
||||
"assistant" | crate::models::INTERRUPTED_ASSISTANT_ROLE
|
||||
"assistant" | codewhale_models::INTERRUPTED_ASSISTANT_ROLE
|
||||
) && last.content == message.content
|
||||
});
|
||||
if already_committed {
|
||||
@@ -5518,7 +5518,7 @@ impl Engine {
|
||||
})
|
||||
.clone();
|
||||
|
||||
let advisor_messages: Vec<crate::models::Message> = self.session.messages.to_vec();
|
||||
let advisor_messages: Vec<codewhale_models::Message> = self.session.messages.to_vec();
|
||||
let advisor_config = self.config.advisor_config.clone();
|
||||
// This clone is frozen before the detached task starts and keeps
|
||||
// every configured provider route available for an explicit
|
||||
|
||||
@@ -288,13 +288,13 @@ mod tests {
|
||||
use crate::core::engine::tool_catalog::ToolSurfacePolicy;
|
||||
use crate::core::turn::TurnContext;
|
||||
use crate::llm_client::mock::{MockLlmClient, canned};
|
||||
use crate::models::{ContentBlock, Message, Role, StreamEvent, Usage};
|
||||
use crate::sandbox::SandboxPolicy;
|
||||
use crate::tools::spec::{
|
||||
ApprovalRequirement, ToolCapability, ToolContext, ToolResult, ToolSpec,
|
||||
};
|
||||
use codewhale_config::AppMode;
|
||||
use codewhale_execpolicy::ApprovalMode;
|
||||
use codewhale_models::{ContentBlock, Message, Role, StreamEvent, Usage};
|
||||
use serde_json::{Value, json};
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
|
||||
@@ -6,12 +6,12 @@
|
||||
|
||||
use crate::config::ApiProvider;
|
||||
use crate::context_budget::ContextBudget;
|
||||
use crate::models::SystemPrompt;
|
||||
#[cfg(test)]
|
||||
pub(super) use crate::route_budget::effective_max_output_tokens;
|
||||
pub(super) use crate::route_budget::effective_max_output_tokens_for_route;
|
||||
use crate::tools::spec::ToolResult;
|
||||
use codewhale_config::route::RouteLimits;
|
||||
use codewhale_models::SystemPrompt;
|
||||
use serde_json::Value;
|
||||
/// Keep this many most recent messages when emergency trimming is required.
|
||||
pub(super) const MIN_RECENT_MESSAGES_TO_KEEP: usize = 4;
|
||||
|
||||
@@ -16,11 +16,11 @@
|
||||
|
||||
use serde_json::json;
|
||||
|
||||
use crate::models::{Tool, ToolCaller};
|
||||
use crate::tools::spec::{
|
||||
ResourceClaim, ToolError, ToolExecutionOutcome, ToolResult, ToolResultContentBlock,
|
||||
schedule_non_conflicting,
|
||||
};
|
||||
use codewhale_models::{Tool, ToolCaller};
|
||||
|
||||
use super::ToolUseState;
|
||||
|
||||
|
||||
@@ -13,16 +13,16 @@
|
||||
use std::time::Duration;
|
||||
|
||||
use crate::core::model_client::ModelClient;
|
||||
use crate::models::Role;
|
||||
use crate::models::{
|
||||
ContentBlock, Message, MessageRequest, MessageResponse, SystemPrompt, Usage,
|
||||
is_incomplete_stop_reason,
|
||||
};
|
||||
use crate::tools::spec::ToolError;
|
||||
use crate::tui::auto_review::{
|
||||
AutoReviewAction, DEFAULT_GUARDIAN_POLICY, ReviewerRiskLevel, ReviewerVerdict,
|
||||
parse_reviewer_verdict,
|
||||
};
|
||||
use codewhale_models::Role;
|
||||
use codewhale_models::{
|
||||
ContentBlock, Message, MessageRequest, MessageResponse, SystemPrompt, Usage,
|
||||
is_incomplete_stop_reason,
|
||||
};
|
||||
use tokio_util::sync::CancellationToken;
|
||||
|
||||
/// One-shot reviewer deadline. Slow reviewers are denials, surfaced
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
//! content block kind tracking, streamed tool-use buffers, transparent retry
|
||||
//! policy, and scrubbers for text that looks like a forged tool-call wrapper.
|
||||
|
||||
use crate::models::ToolCaller;
|
||||
use codewhale_models::ToolCaller;
|
||||
use std::time::Duration;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
|
||||
@@ -9,12 +9,12 @@ use super::turn_loop::{
|
||||
requested_sandbox_escalation, sandbox_escalation_denial, workspace_write_carve_out_applies,
|
||||
};
|
||||
use crate::config::ApiProvider;
|
||||
use crate::models::{SystemBlock, Usage};
|
||||
use crate::prompts::{
|
||||
InstructionSource, PromptSessionContext, system_prompt_flat_text,
|
||||
system_prompt_for_mode_with_context_skills_and_session,
|
||||
};
|
||||
use crate::test_support::{EnvVarGuard, lock_test_env};
|
||||
use codewhale_models::{SystemBlock, Usage};
|
||||
use serde_json::{Value, json};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::ffi::OsString;
|
||||
@@ -497,8 +497,8 @@ impl crate::core::model_client::ModelClient for BlockingEmergencyCompactionModel
|
||||
|
||||
async fn create_message(
|
||||
&self,
|
||||
_request: crate::models::MessageRequest,
|
||||
) -> anyhow::Result<crate::models::MessageResponse> {
|
||||
_request: codewhale_models::MessageRequest,
|
||||
) -> anyhow::Result<codewhale_models::MessageResponse> {
|
||||
let _drop_signal = DropSignal(std::sync::Arc::clone(&self.request_dropped));
|
||||
self.entered.notify_one();
|
||||
std::future::pending().await
|
||||
@@ -506,7 +506,7 @@ impl crate::core::model_client::ModelClient for BlockingEmergencyCompactionModel
|
||||
|
||||
async fn create_message_stream(
|
||||
&self,
|
||||
_request: crate::models::MessageRequest,
|
||||
_request: codewhale_models::MessageRequest,
|
||||
) -> anyhow::Result<crate::llm_client::StreamEventBox> {
|
||||
anyhow::bail!("emergency compaction uses the non-streaming model boundary")
|
||||
}
|
||||
@@ -1046,7 +1046,7 @@ async fn exact_turn_snapshot_restores_custom_endpoint_and_turn_receipt_after_bui
|
||||
|
||||
struct GatedGoalModelClient {
|
||||
calls: std::sync::atomic::AtomicUsize,
|
||||
requests: std::sync::Mutex<Vec<crate::models::MessageRequest>>,
|
||||
requests: std::sync::Mutex<Vec<codewhale_models::MessageRequest>>,
|
||||
second_request_entered: std::sync::Arc<tokio::sync::Notify>,
|
||||
release_second_request: std::sync::Arc<tokio::sync::Notify>,
|
||||
first_usage: Option<Usage>,
|
||||
@@ -1082,14 +1082,14 @@ impl crate::core::model_client::ModelClient for IndexedGatedGoalModelClient {
|
||||
|
||||
async fn create_message(
|
||||
&self,
|
||||
_request: crate::models::MessageRequest,
|
||||
) -> anyhow::Result<crate::models::MessageResponse> {
|
||||
_request: codewhale_models::MessageRequest,
|
||||
) -> anyhow::Result<codewhale_models::MessageResponse> {
|
||||
anyhow::bail!("indexed gate regression uses the streaming model boundary")
|
||||
}
|
||||
|
||||
async fn create_message_stream(
|
||||
&self,
|
||||
_request: crate::models::MessageRequest,
|
||||
_request: codewhale_models::MessageRequest,
|
||||
) -> anyhow::Result<crate::llm_client::StreamEventBox> {
|
||||
let call = self
|
||||
.calls
|
||||
@@ -1126,14 +1126,14 @@ impl crate::core::model_client::ModelClient for FirstRequestGatedGoalModelClient
|
||||
|
||||
async fn create_message(
|
||||
&self,
|
||||
_request: crate::models::MessageRequest,
|
||||
) -> anyhow::Result<crate::models::MessageResponse> {
|
||||
_request: codewhale_models::MessageRequest,
|
||||
) -> anyhow::Result<codewhale_models::MessageResponse> {
|
||||
anyhow::bail!("mailbox regression uses the streaming model boundary")
|
||||
}
|
||||
|
||||
async fn create_message_stream(
|
||||
&self,
|
||||
_request: crate::models::MessageRequest,
|
||||
_request: codewhale_models::MessageRequest,
|
||||
) -> anyhow::Result<crate::llm_client::StreamEventBox> {
|
||||
let call = self
|
||||
.calls
|
||||
@@ -1173,14 +1173,14 @@ impl crate::core::model_client::ModelClient for FailingGoalModelClient {
|
||||
|
||||
async fn create_message(
|
||||
&self,
|
||||
_request: crate::models::MessageRequest,
|
||||
) -> anyhow::Result<crate::models::MessageResponse> {
|
||||
_request: codewhale_models::MessageRequest,
|
||||
) -> anyhow::Result<codewhale_models::MessageResponse> {
|
||||
anyhow::bail!("failure regression uses the streaming model boundary")
|
||||
}
|
||||
|
||||
async fn create_message_stream(
|
||||
&self,
|
||||
_request: crate::models::MessageRequest,
|
||||
_request: codewhale_models::MessageRequest,
|
||||
) -> anyhow::Result<crate::llm_client::StreamEventBox> {
|
||||
self.calls.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
|
||||
anyhow::bail!(self.message.clone())
|
||||
@@ -1192,7 +1192,7 @@ impl crate::core::model_client::ModelClient for FailingGoalModelClient {
|
||||
}
|
||||
|
||||
impl GatedGoalModelClient {
|
||||
fn captured_requests(&self) -> Vec<crate::models::MessageRequest> {
|
||||
fn captured_requests(&self) -> Vec<codewhale_models::MessageRequest> {
|
||||
self.requests
|
||||
.lock()
|
||||
.expect("goal model request lock")
|
||||
@@ -1212,14 +1212,14 @@ impl crate::core::model_client::ModelClient for GatedGoalModelClient {
|
||||
|
||||
async fn create_message(
|
||||
&self,
|
||||
_request: crate::models::MessageRequest,
|
||||
) -> anyhow::Result<crate::models::MessageResponse> {
|
||||
_request: codewhale_models::MessageRequest,
|
||||
) -> anyhow::Result<codewhale_models::MessageResponse> {
|
||||
anyhow::bail!("goal regression uses the streaming model boundary")
|
||||
}
|
||||
|
||||
async fn create_message_stream(
|
||||
&self,
|
||||
request: crate::models::MessageRequest,
|
||||
request: codewhale_models::MessageRequest,
|
||||
) -> anyhow::Result<crate::llm_client::StreamEventBox> {
|
||||
let call = self
|
||||
.calls
|
||||
@@ -1239,9 +1239,9 @@ impl crate::core::model_client::ModelClient for GatedGoalModelClient {
|
||||
let mut events = crate::llm_client::mock::canned::simple_text_turn("still working");
|
||||
if call == 1
|
||||
&& let Some(usage) = self.first_usage.clone()
|
||||
&& let Some(crate::models::StreamEvent::MessageDelta { usage: slot, .. }) = events
|
||||
&& let Some(codewhale_models::StreamEvent::MessageDelta { usage: slot, .. }) = events
|
||||
.iter_mut()
|
||||
.find(|event| matches!(event, crate::models::StreamEvent::MessageDelta { .. }))
|
||||
.find(|event| matches!(event, codewhale_models::StreamEvent::MessageDelta { .. }))
|
||||
{
|
||||
*slot = Some(usage);
|
||||
}
|
||||
@@ -4654,8 +4654,8 @@ async fn idle_subagent_delivery_releases_claim_when_route_fails_before_recording
|
||||
|
||||
#[test]
|
||||
fn subagent_mailbox_keeps_lifecycle_events_reliable() {
|
||||
use crate::models::Usage;
|
||||
use crate::tools::subagent::MailboxMessage;
|
||||
use codewhale_models::Usage;
|
||||
|
||||
assert!(subagent_mailbox_message_is_best_effort(
|
||||
&MailboxMessage::progress("agent_a", "step 1")
|
||||
@@ -4765,8 +4765,8 @@ fn subagent_mailbox_samples_best_effort_events_per_agent() {
|
||||
|
||||
#[test]
|
||||
fn subagent_mailbox_never_samples_lifecycle_or_usage_events() {
|
||||
use crate::models::Usage;
|
||||
use crate::tools::subagent::{FleetRole, MailboxMessage};
|
||||
use codewhale_models::Usage;
|
||||
|
||||
let mut last_sent_at = HashMap::new();
|
||||
let start = Instant::now();
|
||||
@@ -5506,7 +5506,7 @@ async fn steer_during_final_coordination_response_gets_its_own_provider_reply()
|
||||
|
||||
/// Compose one assistant turn that proposes `calls` as a single parallel
|
||||
/// tool-call batch: `(call_id, tool_name, args_json)` per block, in order.
|
||||
fn tool_batch_turn(calls: &[(&str, &str, &str)]) -> Vec<crate::models::StreamEvent> {
|
||||
fn tool_batch_turn(calls: &[(&str, &str, &str)]) -> Vec<codewhale_models::StreamEvent> {
|
||||
use crate::llm_client::mock::canned;
|
||||
|
||||
let mut events = vec![canned::message_start("mock_tool_batch")];
|
||||
@@ -6265,14 +6265,14 @@ impl crate::core::model_client::ModelClient for FailingGuardianModelClient {
|
||||
|
||||
async fn create_message(
|
||||
&self,
|
||||
_request: crate::models::MessageRequest,
|
||||
) -> anyhow::Result<crate::models::MessageResponse> {
|
||||
_request: codewhale_models::MessageRequest,
|
||||
) -> anyhow::Result<codewhale_models::MessageResponse> {
|
||||
anyhow::bail!("fixture guardian transport failure")
|
||||
}
|
||||
|
||||
async fn create_message_stream(
|
||||
&self,
|
||||
request: crate::models::MessageRequest,
|
||||
request: codewhale_models::MessageRequest,
|
||||
) -> anyhow::Result<crate::llm_client::StreamEventBox> {
|
||||
crate::core::model_client::ModelClient::create_message_stream(&self.inner, request).await
|
||||
}
|
||||
@@ -6294,8 +6294,8 @@ impl crate::core::model_client::ModelClient for BlockingGuardianModelClient {
|
||||
|
||||
async fn create_message(
|
||||
&self,
|
||||
_request: crate::models::MessageRequest,
|
||||
) -> anyhow::Result<crate::models::MessageResponse> {
|
||||
_request: codewhale_models::MessageRequest,
|
||||
) -> anyhow::Result<codewhale_models::MessageResponse> {
|
||||
let _drop_signal = DropSignal(std::sync::Arc::clone(&self.guardian_dropped));
|
||||
self.guardian_entered.notify_one();
|
||||
std::future::pending().await
|
||||
@@ -6303,7 +6303,7 @@ impl crate::core::model_client::ModelClient for BlockingGuardianModelClient {
|
||||
|
||||
async fn create_message_stream(
|
||||
&self,
|
||||
_request: crate::models::MessageRequest,
|
||||
_request: codewhale_models::MessageRequest,
|
||||
) -> anyhow::Result<crate::llm_client::StreamEventBox> {
|
||||
use crate::llm_client::mock::canned;
|
||||
|
||||
@@ -6340,14 +6340,14 @@ impl crate::core::model_client::ModelClient for BlockingModelClient {
|
||||
|
||||
async fn create_message(
|
||||
&self,
|
||||
_request: crate::models::MessageRequest,
|
||||
) -> anyhow::Result<crate::models::MessageResponse> {
|
||||
_request: codewhale_models::MessageRequest,
|
||||
) -> anyhow::Result<codewhale_models::MessageResponse> {
|
||||
std::future::pending().await
|
||||
}
|
||||
|
||||
async fn create_message_stream(
|
||||
&self,
|
||||
_request: crate::models::MessageRequest,
|
||||
_request: codewhale_models::MessageRequest,
|
||||
) -> anyhow::Result<crate::llm_client::StreamEventBox> {
|
||||
let _drop_signal = DropSignal(std::sync::Arc::clone(&self.request_dropped));
|
||||
self.entered.notify_one();
|
||||
@@ -6362,7 +6362,7 @@ impl crate::core::model_client::ModelClient for BlockingModelClient {
|
||||
fn test_tool_surface(
|
||||
engine: &Engine,
|
||||
registry: crate::tools::ToolRegistry,
|
||||
tools: Option<Vec<crate::models::Tool>>,
|
||||
tools: Option<Vec<codewhale_models::Tool>>,
|
||||
mode: AppMode,
|
||||
) -> ToolSurfacePolicy {
|
||||
ToolSurfacePolicy::new(
|
||||
@@ -6429,7 +6429,7 @@ async fn tool_request_snapshot_matches_the_exact_mock_request_payload() {
|
||||
#[tokio::test]
|
||||
async fn normal_repl_kernel_persists_across_user_turns() {
|
||||
use crate::llm_client::mock::{MockLlmClient, canned};
|
||||
use crate::models::{ContentBlock, Message, MessageResponse, Usage};
|
||||
use codewhale_models::{ContentBlock, Message, MessageResponse, Usage};
|
||||
|
||||
let workspace = tempdir().expect("tempdir");
|
||||
let mock = std::sync::Arc::new(MockLlmClient::new(vec![
|
||||
@@ -6555,7 +6555,7 @@ async fn normal_repl_kernel_persists_across_user_turns() {
|
||||
|
||||
async fn snapshot_for_catalog(
|
||||
workspace: &Path,
|
||||
catalog: Option<Vec<crate::models::Tool>>,
|
||||
catalog: Option<Vec<codewhale_models::Tool>>,
|
||||
) -> crate::tool_inspection::ToolInspectionSnapshot {
|
||||
use crate::llm_client::mock::{MockLlmClient, canned};
|
||||
|
||||
@@ -6585,7 +6585,7 @@ async fn snapshot_for_catalog(
|
||||
async fn request_selector_distinguishes_absent_tools_from_present_empty_tools() {
|
||||
let workspace = tempdir().expect("tempdir");
|
||||
let absent = snapshot_for_catalog(workspace.path(), None).await;
|
||||
let deferred_only = crate::models::Tool {
|
||||
let deferred_only = codewhale_models::Tool {
|
||||
tool_type: Some("function".to_string()),
|
||||
name: "deferred_fixture".to_string(),
|
||||
description: "Deferred fixture".to_string(),
|
||||
@@ -6874,7 +6874,7 @@ async fn request_snapshot_reports_registry_provenance_for_the_transmitted_catalo
|
||||
// the turn an empty catalog and nothing would be transmitted. Hand the
|
||||
// engine an explicit catalog instead: the registry is still the source of
|
||||
// the *facts*, including the fact that this tool is not model-visible.
|
||||
let tools = Some(vec![crate::models::Tool {
|
||||
let tools = Some(vec![codewhale_models::Tool {
|
||||
tool_type: None,
|
||||
name: "read_file".to_string(),
|
||||
description: "Read a file".to_string(),
|
||||
@@ -8425,8 +8425,8 @@ async fn engine_cancellation_drops_active_injected_model_request() {
|
||||
task.await.expect("engine task");
|
||||
}
|
||||
|
||||
fn guardian_fixture_response(text: &str) -> crate::models::MessageResponse {
|
||||
crate::models::MessageResponse {
|
||||
fn guardian_fixture_response(text: &str) -> codewhale_models::MessageResponse {
|
||||
codewhale_models::MessageResponse {
|
||||
id: "guardian-fixture".to_string(),
|
||||
r#type: "message".to_string(),
|
||||
role: "assistant".to_string(),
|
||||
@@ -8447,7 +8447,7 @@ fn guardian_fixture_response(text: &str) -> crate::models::MessageResponse {
|
||||
}
|
||||
|
||||
fn guardian_tool_results<'a>(
|
||||
request: &'a crate::models::MessageRequest,
|
||||
request: &'a codewhale_models::MessageRequest,
|
||||
call_id: &str,
|
||||
) -> Vec<(&'a str, Option<bool>)> {
|
||||
request
|
||||
@@ -8699,7 +8699,7 @@ async fn auto_review_guardian_parse_and_transport_failures_deny_closed() {
|
||||
r#"{"action":"write","path":".env","content":"must-not-run\n"}"#,
|
||||
);
|
||||
let follow_up_id = call_id.clone();
|
||||
let follow_up = move |request: &crate::models::MessageRequest| {
|
||||
let follow_up = move |request: &codewhale_models::MessageRequest| {
|
||||
let results = guardian_tool_results(request, &follow_up_id);
|
||||
assert_eq!(results.len(), 1, "reviewer failure must pair one result");
|
||||
let result = results[0];
|
||||
@@ -11251,7 +11251,7 @@ fn print_mode_runtime_contract_metrics() {
|
||||
);
|
||||
let prompt_bytes = system_prompt_flat_text(&prompt).len();
|
||||
let prompt_blocks = match &prompt {
|
||||
crate::models::SystemPrompt::Blocks(blocks) => blocks.len(),
|
||||
codewhale_models::SystemPrompt::Blocks(blocks) => blocks.len(),
|
||||
_ => 1,
|
||||
};
|
||||
mode_metrics.insert(
|
||||
@@ -11280,7 +11280,7 @@ fn representative_prompt(
|
||||
instructions: Option<&[InstructionSource]>,
|
||||
user_memory_block: Option<&str>,
|
||||
goal_objective: Option<&str>,
|
||||
) -> crate::models::SystemPrompt {
|
||||
) -> codewhale_models::SystemPrompt {
|
||||
system_prompt_for_mode_with_context_skills_and_session(
|
||||
workspace,
|
||||
None,
|
||||
@@ -11296,10 +11296,10 @@ fn representative_prompt(
|
||||
)
|
||||
}
|
||||
|
||||
fn prompt_block_count(prompt: &crate::models::SystemPrompt) -> usize {
|
||||
fn prompt_block_count(prompt: &codewhale_models::SystemPrompt) -> usize {
|
||||
match prompt {
|
||||
crate::models::SystemPrompt::Blocks(blocks) => blocks.len(),
|
||||
crate::models::SystemPrompt::Text(_) => 1,
|
||||
codewhale_models::SystemPrompt::Blocks(blocks) => blocks.len(),
|
||||
codewhale_models::SystemPrompt::Text(_) => 1,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11343,7 +11343,7 @@ fn normalize_representative_prompt(text: &str, workspace: &Path, home: &Path) ->
|
||||
|
||||
fn representative_stage(
|
||||
name: &'static str,
|
||||
prompt: crate::models::SystemPrompt,
|
||||
prompt: codewhale_models::SystemPrompt,
|
||||
workspace: &Path,
|
||||
home: &Path,
|
||||
) -> RepresentativePromptStage {
|
||||
@@ -16600,7 +16600,7 @@ async fn edit_last_turn_without_user_prompt_errors_and_sends_nothing() {
|
||||
Message {
|
||||
role: Role::User,
|
||||
content: vec![ContentBlock::ImageUrl {
|
||||
image_url: crate::models::ImageUrlContent {
|
||||
image_url: codewhale_models::ImageUrlContent {
|
||||
url: "data:image/png;base64,AAAA".to_string(),
|
||||
},
|
||||
}],
|
||||
@@ -20228,14 +20228,14 @@ impl crate::core::model_client::ModelClient for FlakyNetworkDropModelClient {
|
||||
|
||||
async fn create_message(
|
||||
&self,
|
||||
_request: crate::models::MessageRequest,
|
||||
) -> anyhow::Result<crate::models::MessageResponse> {
|
||||
_request: codewhale_models::MessageRequest,
|
||||
) -> anyhow::Result<codewhale_models::MessageResponse> {
|
||||
anyhow::bail!("flaky-network regression uses the streaming model boundary")
|
||||
}
|
||||
|
||||
async fn create_message_stream(
|
||||
&self,
|
||||
_request: crate::models::MessageRequest,
|
||||
_request: codewhale_models::MessageRequest,
|
||||
) -> anyhow::Result<crate::llm_client::StreamEventBox> {
|
||||
use crate::llm_client::mock::canned;
|
||||
let call = self
|
||||
@@ -20256,7 +20256,7 @@ impl crate::core::model_client::ModelClient for FlakyNetworkDropModelClient {
|
||||
if let StreamEvent::MessageStart { message } = &mut message_start {
|
||||
message.usage = start_usage;
|
||||
}
|
||||
let events: Vec<anyhow::Result<crate::models::StreamEvent>> = vec![
|
||||
let events: Vec<anyhow::Result<codewhale_models::StreamEvent>> = vec![
|
||||
Ok(message_start),
|
||||
Ok(canned::text_block_start(0)),
|
||||
Ok(canned::text_delta(0, "billed truncated fragment")),
|
||||
@@ -20279,7 +20279,7 @@ impl crate::core::model_client::ModelClient for FlakyNetworkDropModelClient {
|
||||
// Partial content first — this flips `any_content_received` so
|
||||
// the #103 transparent retry cannot fire — then the transport
|
||||
// dies the way the 0.9.4 Terminal-Bench crashes did.
|
||||
let events: Vec<anyhow::Result<crate::models::StreamEvent>> = vec![
|
||||
let events: Vec<anyhow::Result<codewhale_models::StreamEvent>> = vec![
|
||||
Ok(canned::message_start("flaky_msg")),
|
||||
Ok(canned::text_block_start(0)),
|
||||
Ok(canned::text_delta(
|
||||
@@ -20720,14 +20720,14 @@ impl crate::core::model_client::ModelClient for CancelAfterTerminalUsageModelCli
|
||||
|
||||
async fn create_message(
|
||||
&self,
|
||||
_request: crate::models::MessageRequest,
|
||||
) -> anyhow::Result<crate::models::MessageResponse> {
|
||||
_request: codewhale_models::MessageRequest,
|
||||
) -> anyhow::Result<codewhale_models::MessageResponse> {
|
||||
anyhow::bail!("unused")
|
||||
}
|
||||
|
||||
async fn create_message_stream(
|
||||
&self,
|
||||
_request: crate::models::MessageRequest,
|
||||
_request: codewhale_models::MessageRequest,
|
||||
) -> anyhow::Result<crate::llm_client::StreamEventBox> {
|
||||
use crate::llm_client::mock::canned;
|
||||
|
||||
@@ -21028,14 +21028,14 @@ impl crate::core::model_client::ModelClient for ThinkingOnlyDropModelClient {
|
||||
|
||||
async fn create_message(
|
||||
&self,
|
||||
_request: crate::models::MessageRequest,
|
||||
) -> anyhow::Result<crate::models::MessageResponse> {
|
||||
_request: codewhale_models::MessageRequest,
|
||||
) -> anyhow::Result<codewhale_models::MessageResponse> {
|
||||
anyhow::bail!("thinking-only drop regression uses the streaming model boundary")
|
||||
}
|
||||
|
||||
async fn create_message_stream(
|
||||
&self,
|
||||
_request: crate::models::MessageRequest,
|
||||
_request: codewhale_models::MessageRequest,
|
||||
) -> anyhow::Result<crate::llm_client::StreamEventBox> {
|
||||
use crate::llm_client::mock::canned;
|
||||
let call = self
|
||||
@@ -21047,11 +21047,11 @@ impl crate::core::model_client::ModelClient for ThinkingOnlyDropModelClient {
|
||||
// visible streams before the transport dies. This still flips
|
||||
// `any_content_received`, which is what routes the drop to the
|
||||
// interactive resume path instead of the transparent retry.
|
||||
let events: Vec<anyhow::Result<crate::models::StreamEvent>> = vec![
|
||||
let events: Vec<anyhow::Result<codewhale_models::StreamEvent>> = vec![
|
||||
Ok(canned::message_start("thinking_only_msg")),
|
||||
Ok(StreamEvent::ContentBlockStart {
|
||||
index: 0,
|
||||
content_block: crate::models::ContentBlockStart::Thinking {
|
||||
content_block: codewhale_models::ContentBlockStart::Thinking {
|
||||
thinking: String::new(),
|
||||
},
|
||||
}),
|
||||
@@ -21245,7 +21245,7 @@ struct ReasoningOnlyCleanFinishModelClient {
|
||||
stop_reason: &'static str,
|
||||
/// Every outbound request's messages, in order, so a test can tell a
|
||||
/// request-scoped nudge from one written into the session.
|
||||
requests: std::sync::Mutex<Vec<Vec<crate::models::Message>>>,
|
||||
requests: std::sync::Mutex<Vec<Vec<codewhale_models::Message>>>,
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
@@ -21260,14 +21260,14 @@ impl crate::core::model_client::ModelClient for ReasoningOnlyCleanFinishModelCli
|
||||
|
||||
async fn create_message(
|
||||
&self,
|
||||
_request: crate::models::MessageRequest,
|
||||
) -> anyhow::Result<crate::models::MessageResponse> {
|
||||
_request: codewhale_models::MessageRequest,
|
||||
) -> anyhow::Result<codewhale_models::MessageResponse> {
|
||||
anyhow::bail!("reasoning-only recovery uses the streaming model boundary")
|
||||
}
|
||||
|
||||
async fn create_message_stream(
|
||||
&self,
|
||||
_request: crate::models::MessageRequest,
|
||||
_request: codewhale_models::MessageRequest,
|
||||
) -> anyhow::Result<crate::llm_client::StreamEventBox> {
|
||||
use crate::llm_client::mock::canned;
|
||||
if let Ok(mut requests) = self.requests.lock() {
|
||||
@@ -21280,11 +21280,11 @@ impl crate::core::model_client::ModelClient for ReasoningOnlyCleanFinishModelCli
|
||||
if call <= self.reasoning_only {
|
||||
// A protocol-complete response that opened and closed only a
|
||||
// thinking block: no text, no tool call, and a clean stop reason.
|
||||
let events: Vec<anyhow::Result<crate::models::StreamEvent>> = vec![
|
||||
let events: Vec<anyhow::Result<codewhale_models::StreamEvent>> = vec![
|
||||
Ok(canned::message_start("reasoning_only_msg")),
|
||||
Ok(StreamEvent::ContentBlockStart {
|
||||
index: 0,
|
||||
content_block: crate::models::ContentBlockStart::Thinking {
|
||||
content_block: codewhale_models::ContentBlockStart::Thinking {
|
||||
thinking: String::new(),
|
||||
},
|
||||
}),
|
||||
@@ -21540,7 +21540,7 @@ async fn the_reasoning_only_nudge_rides_one_request_and_never_joins_the_session(
|
||||
);
|
||||
|
||||
let nudge = crate::config::DEFAULT_REASONING_ONLY_REPROMPT_MESSAGE;
|
||||
let carries_nudge = |messages: &Vec<crate::models::Message>| {
|
||||
let carries_nudge = |messages: &Vec<codewhale_models::Message>| {
|
||||
serde_json::to_string(messages)
|
||||
.expect("messages serialize")
|
||||
.contains(nudge)
|
||||
@@ -21765,7 +21765,7 @@ async fn post_edit_hook_injects_diagnostics_message_before_next_request() {
|
||||
assert_eq!(last.role, "user");
|
||||
// turn_meta is now at the tail of the content array (PR #2517).
|
||||
let meta = match last.content.last() {
|
||||
Some(crate::models::ContentBlock::Text { text, .. }) => text.clone(),
|
||||
Some(codewhale_models::ContentBlock::Text { text, .. }) => text.clone(),
|
||||
other => panic!("expected text block at tail, got {other:?}"),
|
||||
};
|
||||
assert!(meta.starts_with("<turn_meta>\n"));
|
||||
@@ -21773,7 +21773,7 @@ async fn post_edit_hook_injects_diagnostics_message_before_next_request() {
|
||||
.content
|
||||
.iter()
|
||||
.find_map(|block| match block {
|
||||
crate::models::ContentBlock::Text { text, .. }
|
||||
codewhale_models::ContentBlock::Text { text, .. }
|
||||
if text.contains("<diagnostics file=\"") =>
|
||||
{
|
||||
Some(text)
|
||||
@@ -22980,7 +22980,7 @@ async fn background_completion_after_a_turn_is_delivered_once_on_the_next_turn()
|
||||
|
||||
// ...and it is model-visible, marked as untrusted tool data.
|
||||
let message = crate::runtime_handoff::shell_completion_runtime_message(&first);
|
||||
let crate::models::ContentBlock::Text { text, .. } = &message.content[0] else {
|
||||
let codewhale_models::ContentBlock::Text { text, .. } = &message.content[0] else {
|
||||
panic!("expected runtime event text");
|
||||
};
|
||||
assert!(text.contains("background_shell_completion"), "{text}");
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//! Process-local memoization for [`crate::compaction::estimate_input_tokens_conservative`].
|
||||
//!
|
||||
//! The token estimator walks the full [`crate::models::Message`] history and the
|
||||
//! The token estimator walks the full [`codewhale_models::Message`] history and the
|
||||
//! active system prompt, which is by far the most expensive per-turn CPU cost
|
||||
//! in the engine hot path. The same input data is queried from at least five
|
||||
//! sites per turn: capacity pre/post tool checkpoints, error escalation,
|
||||
@@ -21,7 +21,7 @@ use std::collections::hash_map::DefaultHasher;
|
||||
use std::hash::{Hash, Hasher};
|
||||
|
||||
use crate::compaction::estimate_input_tokens_conservative;
|
||||
use crate::models::{Message, SystemPrompt};
|
||||
use codewhale_models::{Message, SystemPrompt};
|
||||
|
||||
/// Default capacity for the rolling audit ring. Sized so a 64-entry window
|
||||
/// covers a full capacity controller observation cycle without unbounded
|
||||
@@ -166,8 +166,8 @@ fn fingerprint_system_prompt(system: Option<&SystemPrompt>) -> u64 {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::models::Role;
|
||||
use crate::models::{ContentBlock, SystemBlock};
|
||||
use codewhale_models::Role;
|
||||
use codewhale_models::{ContentBlock, SystemBlock};
|
||||
|
||||
fn user_text(s: &str) -> Message {
|
||||
Message {
|
||||
|
||||
@@ -14,10 +14,10 @@ use serde_json::{Value, json};
|
||||
#[cfg(test)]
|
||||
use crate::mcp::McpPool;
|
||||
use crate::model_profile::ToolSurfaceBudget;
|
||||
use crate::models::Tool;
|
||||
use crate::tools::spec::{ToolError, ToolResult, optional_str, optional_u64, required_str};
|
||||
use codewhale_config::AppMode;
|
||||
use codewhale_execpolicy::ApprovalMode;
|
||||
use codewhale_models::Tool;
|
||||
|
||||
use crate::core::session::ToolActivationCache;
|
||||
use crate::dependencies::ExternalTool;
|
||||
|
||||
@@ -7,8 +7,8 @@ use super::{
|
||||
touch_cached_tool_after_execution,
|
||||
};
|
||||
use crate::core::session::ToolActivationCache;
|
||||
use crate::models::Tool;
|
||||
use codewhale_config::AppMode;
|
||||
use codewhale_models::Tool;
|
||||
use serde_json::json;
|
||||
use std::collections::{BTreeSet, HashSet};
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@ use super::dispatch::{
|
||||
use super::*;
|
||||
use crate::core::authority::{ToolPermission, resolve_tool_permission};
|
||||
use crate::core::ops::UserInputProvenance;
|
||||
use crate::models::Role;
|
||||
use crate::prompt_zones::PinnedPrefix;
|
||||
use crate::runtime_handoff::{
|
||||
shell_completion_runtime_message, subagent_completion_runtime_message,
|
||||
@@ -22,6 +21,7 @@ use crate::tools::canonical_action::canonical_action_alias;
|
||||
use crate::tools::spec::ToolTerminalStatus;
|
||||
use crate::tools::tool_call_budget::ToolCallBudget;
|
||||
use codewhale_core::request::{PrimaryTurnRequest, prepare_primary_turn_request};
|
||||
use codewhale_models::Role;
|
||||
|
||||
const MAX_APPROVAL_INTENT_SUMMARY_CHARS: usize = 2_000;
|
||||
|
||||
@@ -36,7 +36,7 @@ struct StreamOutcome {
|
||||
current_text_visible: String,
|
||||
current_thinking: String,
|
||||
current_thinking_signature: Option<String>,
|
||||
current_thinking_state: Option<crate::models::OpaqueReasoningState>,
|
||||
current_thinking_state: Option<codewhale_models::OpaqueReasoningState>,
|
||||
tool_uses: Vec<ToolUseState>,
|
||||
usage: Usage,
|
||||
usage_reported: bool,
|
||||
@@ -1287,7 +1287,7 @@ impl Engine {
|
||||
if let Some(pm) = self.session.prefix_stability.as_mut() {
|
||||
let system_text =
|
||||
crate::prefix_cache::system_prompt_text(self.session.system_prompt.as_ref());
|
||||
let tools_ref: Option<&[crate::models::Tool]> = active_tools.as_deref();
|
||||
let tools_ref: Option<&[codewhale_models::Tool]> = active_tools.as_deref();
|
||||
let outcome = pm.check(&system_text, tools_ref, declared_change.as_deref());
|
||||
// C5: request N's prefix may only diverge from N-1 across a
|
||||
// DECLARED change. An undeclared drift means the pinned header
|
||||
@@ -1382,7 +1382,8 @@ impl Engine {
|
||||
// PrefixStabilityManager already reports the change above.
|
||||
let system_text =
|
||||
crate::prefix_cache::system_prompt_text(self.session.system_prompt.as_ref());
|
||||
let current_tools: &[crate::models::Tool] = active_tools.as_deref().unwrap_or_default();
|
||||
let current_tools: &[codewhale_models::Tool] =
|
||||
active_tools.as_deref().unwrap_or_default();
|
||||
|
||||
match &self.session.frozen_prefix {
|
||||
Some(frozen) => {
|
||||
@@ -2645,7 +2646,7 @@ impl Engine {
|
||||
stream_request.max_tokens
|
||||
)
|
||||
} else if has_provider_reasoning {
|
||||
let reason = crate::models::stop_reason_detail(stop_reason.as_deref());
|
||||
let reason = codewhale_models::stop_reason_detail(stop_reason.as_deref());
|
||||
format!(
|
||||
"Model returned reasoning but no answer or tool call; the provider response was incomplete (stop reason: {}).",
|
||||
reason
|
||||
@@ -2943,7 +2944,7 @@ impl Engine {
|
||||
turn: &mut TurnContext,
|
||||
tool_policy: &ToolSurfacePolicy,
|
||||
tool_uses: &mut [ToolUseState],
|
||||
tool_catalog: &[crate::models::Tool],
|
||||
tool_catalog: &[codewhale_models::Tool],
|
||||
tool_registry: Option<&crate::tools::ToolRegistry>,
|
||||
active_tool_names: &mut std::collections::HashSet<String>,
|
||||
tool_call_budget: &mut ToolCallBudget,
|
||||
@@ -3581,7 +3582,7 @@ impl Engine {
|
||||
plans: Vec<ToolExecutionPlan>,
|
||||
origin_turn_id: &str,
|
||||
current_text_visible: &str,
|
||||
tool_catalog: &[crate::models::Tool],
|
||||
tool_catalog: &[codewhale_models::Tool],
|
||||
active_tool_names: &mut std::collections::HashSet<String>,
|
||||
tool_registry: Option<&crate::tools::ToolRegistry>,
|
||||
tool_exec_lock: Arc<RwLock<()>>,
|
||||
@@ -4478,7 +4479,7 @@ impl Engine {
|
||||
&mut self,
|
||||
outcomes: Vec<Option<ToolExecOutcome>>,
|
||||
turn: &mut TurnContext,
|
||||
tool_catalog: &mut Vec<crate::models::Tool>,
|
||||
tool_catalog: &mut Vec<codewhale_models::Tool>,
|
||||
active_tool_names: &mut std::collections::HashSet<String>,
|
||||
hook_contexts: &std::collections::HashMap<String, String>,
|
||||
mut fleet_denial_guard: Option<&mut FleetDenialGuard>,
|
||||
@@ -4729,7 +4730,7 @@ impl Engine {
|
||||
&mut self,
|
||||
client: &dyn crate::core::model_client::ModelClient,
|
||||
stream: crate::llm_client::StreamEventBox,
|
||||
stream_request: &crate::models::MessageRequest,
|
||||
stream_request: &codewhale_models::MessageRequest,
|
||||
mut request_dispatched_at: Instant,
|
||||
drop_resumes_spent: u32,
|
||||
diagnostics: &mut crate::tool_inspection::TurnStopDiagnostics,
|
||||
@@ -4746,7 +4747,7 @@ impl Engine {
|
||||
// #3014: Anthropic signed-thinking signature for the current
|
||||
// thinking block; must be replayed verbatim in tool loops.
|
||||
let mut current_thinking_signature: Option<String> = None;
|
||||
let mut current_thinking_state: Option<crate::models::OpaqueReasoningState> = None;
|
||||
let mut current_thinking_state: Option<codewhale_models::OpaqueReasoningState> = None;
|
||||
let mut tool_uses: Vec<ToolUseState> = Vec::new();
|
||||
let mut usage = Usage {
|
||||
input_tokens: 0,
|
||||
@@ -6735,7 +6736,7 @@ mod tests {
|
||||
},
|
||||
]);
|
||||
let text = match &message.content[0] {
|
||||
crate::models::ContentBlock::Text { text, .. } => text,
|
||||
codewhale_models::ContentBlock::Text { text, .. } => text,
|
||||
other => panic!("expected runtime event text, got {other:?}"),
|
||||
};
|
||||
assert!(text.contains("background_shell_completion"));
|
||||
|
||||
@@ -10,11 +10,11 @@ use serde_json::Value;
|
||||
|
||||
use crate::config::ApiProvider;
|
||||
use crate::error_taxonomy::ErrorEnvelope;
|
||||
use crate::models::{Message, SystemPrompt, Tool, Usage};
|
||||
use crate::tools::goal::GoalSnapshot;
|
||||
use crate::tools::spec::{ToolError, ToolResult};
|
||||
use crate::tools::subagent::{AgentWorkerStatus, CoordinationDetailProjection, SubAgentResult};
|
||||
use crate::tools::user_input::UserInputRequest;
|
||||
use codewhale_models::{Message, SystemPrompt, Tool, Usage};
|
||||
|
||||
/// Final status for a turn.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize)]
|
||||
|
||||
@@ -5,11 +5,11 @@
|
||||
|
||||
use crate::compaction::CompactionConfig;
|
||||
use crate::config::ApiProvider;
|
||||
use crate::models::{Message, SystemPrompt};
|
||||
use crate::route_runtime::ResolvedRuntimeRoute;
|
||||
use crate::tools::goal::GoalStatus;
|
||||
use codewhale_config::AppMode;
|
||||
use codewhale_execpolicy::ApprovalMode;
|
||||
use codewhale_models::{Message, SystemPrompt};
|
||||
use codewhale_protocol::runtime::DynamicToolSpec;
|
||||
use std::path::PathBuf;
|
||||
|
||||
|
||||
@@ -39,13 +39,13 @@ use crate::core::ops::Op;
|
||||
use crate::cost_status::RouteBillingMode;
|
||||
use crate::mcp::{McpManagerSnapshot, McpServerCapabilityMetadata};
|
||||
use crate::model_profile::SupportState;
|
||||
use crate::models::Usage;
|
||||
use crate::route_billing::RouteProduct;
|
||||
use crate::tools::spec::ToolError;
|
||||
use crate::tools::subagent::AgentWorkerStatus;
|
||||
use crate::tools::user_input::UserInputRequest;
|
||||
use codewhale_config::AppMode;
|
||||
use codewhale_execpolicy::ApprovalMode;
|
||||
use codewhale_models::Usage;
|
||||
use codewhale_protocol::ResponseChannel;
|
||||
|
||||
/// Routing ids the engine does not carry on each event; the emitter supplies
|
||||
|
||||
@@ -5,7 +5,7 @@ use async_trait::async_trait;
|
||||
|
||||
use crate::llm_client::LlmClient;
|
||||
use crate::llm_client::StreamEventBox;
|
||||
use crate::models::{MessageRequest, MessageResponse};
|
||||
use codewhale_models::{MessageRequest, MessageResponse};
|
||||
|
||||
/// Object-safe model boundary for Engine dependency injection.
|
||||
///
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
//!
|
||||
//! Tracks conversation history, token usage, and session metadata.
|
||||
|
||||
use crate::models::{Message, SystemPrompt, Usage};
|
||||
use crate::prefix_cache::PrefixStabilityManager;
|
||||
use crate::project_context::{ProjectContext, load_project_context_with_parents};
|
||||
use crate::prompt_zones::{AppendLog, FrozenPrefix};
|
||||
use crate::working_set::WorkingSet;
|
||||
use codewhale_execpolicy::ApprovalMode;
|
||||
use codewhale_models::{Message, SystemPrompt, Usage};
|
||||
use std::collections::{HashSet, VecDeque};
|
||||
use std::path::PathBuf;
|
||||
|
||||
@@ -48,19 +48,19 @@ impl ToolActivationCache {
|
||||
}
|
||||
|
||||
fn catalog_tool<'a>(
|
||||
catalog: &'a [crate::models::Tool],
|
||||
catalog: &'a [codewhale_models::Tool],
|
||||
name: &str,
|
||||
) -> Option<&'a crate::models::Tool> {
|
||||
) -> Option<&'a codewhale_models::Tool> {
|
||||
catalog
|
||||
.iter()
|
||||
.find(|tool| tool.name == name && tool.defer_loading.unwrap_or(false))
|
||||
}
|
||||
|
||||
fn serialized_bytes(tool: &crate::models::Tool) -> usize {
|
||||
fn serialized_bytes(tool: &codewhale_models::Tool) -> usize {
|
||||
serde_json::to_vec(tool).map_or(usize::MAX, |bytes| bytes.len())
|
||||
}
|
||||
|
||||
fn total_serialized_bytes(&self, catalog: &[crate::models::Tool]) -> usize {
|
||||
fn total_serialized_bytes(&self, catalog: &[codewhale_models::Tool]) -> usize {
|
||||
self.names
|
||||
.iter()
|
||||
.filter_map(|name| Self::catalog_tool(catalog, name))
|
||||
@@ -70,7 +70,7 @@ impl ToolActivationCache {
|
||||
|
||||
/// Drop entries that are no longer deferred members of this turn's
|
||||
/// filtered catalog and enforce both cache bounds.
|
||||
pub(crate) fn revalidate(&mut self, catalog: &[crate::models::Tool]) -> Vec<String> {
|
||||
pub(crate) fn revalidate(&mut self, catalog: &[codewhale_models::Tool]) -> Vec<String> {
|
||||
let mut evicted = Vec::new();
|
||||
self.names.retain(|name| {
|
||||
let keep = Self::catalog_tool(catalog, name).is_some_and(|tool| {
|
||||
@@ -98,7 +98,7 @@ impl ToolActivationCache {
|
||||
/// until both bounds hold.
|
||||
pub(crate) fn activate(
|
||||
&mut self,
|
||||
catalog: &[crate::models::Tool],
|
||||
catalog: &[codewhale_models::Tool],
|
||||
requested: &[String],
|
||||
) -> ToolActivationDelta {
|
||||
let mut delta = ToolActivationDelta {
|
||||
@@ -378,8 +378,8 @@ mod tests {
|
||||
use super::*;
|
||||
use serde_json::json;
|
||||
|
||||
fn deferred_tool(name: &str, description_bytes: usize) -> crate::models::Tool {
|
||||
crate::models::Tool {
|
||||
fn deferred_tool(name: &str, description_bytes: usize) -> codewhale_models::Tool {
|
||||
codewhale_models::Tool {
|
||||
tool_type: None,
|
||||
name: name.to_string(),
|
||||
description: "x".repeat(description_bytes),
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
//! snapshots.
|
||||
|
||||
use crate::core::events::TurnRoute;
|
||||
use crate::models::Usage;
|
||||
use crate::snapshot::SnapshotRepo;
|
||||
use codewhale_models::Usage;
|
||||
use std::path::Path;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
@@ -295,7 +295,7 @@ fn add_optional_usage(total: Option<u32>, delta: Option<u32>) -> Option<u32> {
|
||||
#[cfg(test)]
|
||||
mod usage_tests {
|
||||
use super::*;
|
||||
use crate::models::ServerToolUsage;
|
||||
use codewhale_models::ServerToolUsage;
|
||||
|
||||
#[test]
|
||||
fn add_usage_preserves_replay_and_saturates_server_tool_counters() {
|
||||
@@ -323,7 +323,7 @@ mod usage_tests {
|
||||
assert_eq!(server.tool_search_requests, Some(5));
|
||||
}
|
||||
|
||||
fn below_threshold(messages: &[crate::models::Message], turn: &TurnContext) -> bool {
|
||||
fn below_threshold(messages: &[codewhale_models::Message], turn: &TurnContext) -> bool {
|
||||
let config = crate::compaction::CompactionConfig {
|
||||
enabled: true,
|
||||
token_threshold: 100_000,
|
||||
|
||||
@@ -38,9 +38,9 @@ use std::sync::{Arc, Mutex, OnceLock};
|
||||
use chrono::{DateTime, Utc};
|
||||
|
||||
use crate::config::ApiProvider;
|
||||
use crate::models::Usage;
|
||||
use crate::pricing::{CostEstimate, TurnCostAudit};
|
||||
use crate::route_billing::BillingPresentation;
|
||||
use codewhale_models::Usage;
|
||||
|
||||
/// Everything a drained background accrual needs to be explained.
|
||||
///
|
||||
|
||||
@@ -54,8 +54,8 @@ use super::role::{
|
||||
};
|
||||
use crate::config::{ApiProvider, Config};
|
||||
use crate::llm_client::LlmClient;
|
||||
use crate::models::Role;
|
||||
use crate::reasoning_preference::ReasoningEffort;
|
||||
use codewhale_models::Role;
|
||||
|
||||
/// Where exact Fleet definitions and Reasoning Router profiles are looked up,
|
||||
/// labelled so an identity can be qualified (`workspace/glm-pair`) instead of
|
||||
@@ -452,7 +452,7 @@ impl FleetRouterCaller for LiveFleetRouter {
|
||||
}
|
||||
|
||||
async fn decide(&self, input: &RouterCallInput) -> Result<String, String> {
|
||||
use crate::models::{ContentBlock, Message, MessageRequest, SystemPrompt};
|
||||
use codewhale_models::{ContentBlock, Message, MessageRequest, SystemPrompt};
|
||||
|
||||
// The bounded, redacted summary is transmitted exactly once, in the
|
||||
// user turn. The system prompt carries the contract and the frozen
|
||||
@@ -495,10 +495,10 @@ impl FleetRouterCaller for LiveFleetRouter {
|
||||
.create_message(request)
|
||||
.await
|
||||
.map_err(|error| error.to_string())?;
|
||||
if crate::models::is_incomplete_stop_reason(response.stop_reason.as_deref()) {
|
||||
if codewhale_models::is_incomplete_stop_reason(response.stop_reason.as_deref()) {
|
||||
return Err(format!(
|
||||
"reasoning router response incomplete: provider stop reason `{}`",
|
||||
crate::models::stop_reason_detail(response.stop_reason.as_deref())
|
||||
codewhale_models::stop_reason_detail(response.stop_reason.as_deref())
|
||||
));
|
||||
}
|
||||
let text = response
|
||||
|
||||
@@ -905,7 +905,7 @@ pub struct TurnEndPayloadInput<'a> {
|
||||
pub status: &'a str,
|
||||
pub error: Option<&'a str>,
|
||||
pub duration: Duration,
|
||||
pub usage: &'a crate::models::Usage,
|
||||
pub usage: &'a codewhale_models::Usage,
|
||||
pub totals: TurnEndTotals,
|
||||
pub tool_count: usize,
|
||||
pub queued_message_count: usize,
|
||||
@@ -3326,7 +3326,7 @@ NOEQUAL line dropped
|
||||
.with_mode("agent")
|
||||
.with_model("deepseek-v4")
|
||||
.with_tokens(125);
|
||||
let usage = crate::models::Usage {
|
||||
let usage = codewhale_models::Usage {
|
||||
input_tokens: 40,
|
||||
output_tokens: 9,
|
||||
prompt_cache_hit_tokens: Some(10),
|
||||
@@ -3779,7 +3779,7 @@ printf '%s\n' '{{"text":"stdout is not a mutation contract"}}'
|
||||
},
|
||||
dir.path().to_path_buf(),
|
||||
);
|
||||
let usage = crate::models::Usage {
|
||||
let usage = codewhale_models::Usage {
|
||||
input_tokens: 12,
|
||||
output_tokens: 3,
|
||||
prompt_cache_hit_tokens: None,
|
||||
@@ -5334,7 +5334,7 @@ command = "echo project"
|
||||
#[test]
|
||||
fn turn_end_error_is_sanitized_and_bounded() {
|
||||
let context = HookContext::new();
|
||||
let usage = crate::models::Usage::default();
|
||||
let usage = codewhale_models::Usage::default();
|
||||
let error = format!(
|
||||
"boom\u{1b}[2J{}",
|
||||
"x".repeat(super::HOOK_TURN_ERROR_MAX_CHARS * 2)
|
||||
|
||||
@@ -53,7 +53,7 @@ use std::path::Path;
|
||||
use base64::{Engine as _, engine::general_purpose::STANDARD};
|
||||
|
||||
use crate::model_profile::SupportState;
|
||||
use crate::models::{ContentBlock, ImageUrlContent};
|
||||
use codewhale_models::{ContentBlock, ImageUrlContent};
|
||||
|
||||
/// Largest source image accepted, in bytes, before base64 expansion.
|
||||
///
|
||||
@@ -401,8 +401,8 @@ pub(crate) fn safe_tool_result_content_blocks(
|
||||
|
||||
#[must_use]
|
||||
pub(crate) fn safe_tool_result_message_projection(
|
||||
messages: &[crate::models::Message],
|
||||
) -> Vec<crate::models::Message> {
|
||||
messages: &[codewhale_models::Message],
|
||||
) -> Vec<codewhale_models::Message> {
|
||||
let mut projected = messages.to_vec();
|
||||
for message in &mut projected {
|
||||
for block in &mut message.content {
|
||||
@@ -641,7 +641,7 @@ fn tag_block(text: &str) -> ContentBlock {
|
||||
/// The image is replaced in place rather than removed, so the model is told
|
||||
/// why it is looking at a gap instead of being left to invent one.
|
||||
pub fn strip_images_when_unsupported(
|
||||
messages: &mut [crate::models::Message],
|
||||
messages: &mut [codewhale_models::Message],
|
||||
vision: SupportState,
|
||||
model: &str,
|
||||
) -> usize {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use super::*;
|
||||
use crate::models::Role;
|
||||
use codewhale_models::Role;
|
||||
|
||||
/// A 1x1 PNG, as bytes rather than a fixture file so the encoding tests
|
||||
/// have no filesystem dependency.
|
||||
@@ -52,7 +52,7 @@ fn lowercase_read_image_preparation_is_typed_and_bounded() {
|
||||
|
||||
#[test]
|
||||
fn blind_route_removes_nested_tool_result_image() {
|
||||
let mut messages = vec![crate::models::Message {
|
||||
let mut messages = vec![codewhale_models::Message {
|
||||
role: Role::User,
|
||||
content: vec![ContentBlock::ToolResult {
|
||||
tool_use_id: "call-image".to_string(),
|
||||
@@ -200,8 +200,8 @@ fn classifies_remote_urls() {
|
||||
assert!(!is_remote_image_url("file:///tmp/a.png"));
|
||||
}
|
||||
|
||||
fn message_with_image(url: &str) -> crate::models::Message {
|
||||
crate::models::Message {
|
||||
fn message_with_image(url: &str) -> codewhale_models::Message {
|
||||
codewhale_models::Message {
|
||||
role: Role::User,
|
||||
content: vec![
|
||||
ContentBlock::ImageUrl {
|
||||
@@ -321,7 +321,7 @@ fn ingest_does_not_consult_model_capability() {
|
||||
fn a_blind_route_gets_text_in_place_of_every_image() {
|
||||
let mut messages = vec![
|
||||
message_with_image("data:image/png;base64,QUJD"),
|
||||
crate::models::Message {
|
||||
codewhale_models::Message {
|
||||
role: Role::Assistant,
|
||||
content: vec![ContentBlock::Text {
|
||||
text: "sure".to_string(),
|
||||
|
||||
+32
-33
@@ -68,13 +68,11 @@ mod lsp;
|
||||
mod mcp;
|
||||
mod mcp_server;
|
||||
mod media_originals;
|
||||
mod model_catalog;
|
||||
mod model_context;
|
||||
mod model_inventory;
|
||||
mod model_profile;
|
||||
mod model_registry;
|
||||
mod model_routing;
|
||||
mod models;
|
||||
mod models_dev_live;
|
||||
mod native_memory;
|
||||
mod network_policy;
|
||||
@@ -168,11 +166,11 @@ use crate::mcp::{
|
||||
McpCommandAvailability, McpConfig, McpPool, McpServerConfig, McpServerOAuthConfig,
|
||||
is_relative_stdio_path_arg,
|
||||
};
|
||||
use crate::models::Role;
|
||||
use crate::models::{ContentBlock, Message, MessageRequest, SystemPrompt};
|
||||
use crate::session_manager::{SessionManager, create_saved_session, truncate_id};
|
||||
use crate::tui::app::ScreenMode;
|
||||
use crate::tui::history::{summarize_tool_args, summarize_tool_output};
|
||||
use codewhale_models::Role;
|
||||
use codewhale_models::{ContentBlock, Message, MessageRequest, SystemPrompt};
|
||||
|
||||
#[cfg(windows)]
|
||||
fn configure_windows_console_utf8() {
|
||||
@@ -7779,7 +7777,7 @@ mod speech_cli_tests {
|
||||
/// Test API connectivity by making a minimal request
|
||||
async fn test_api_connectivity(config: &Config) -> Result<()> {
|
||||
use crate::client::DeepSeekClient;
|
||||
use crate::models::{ContentBlock, Message, MessageRequest};
|
||||
use codewhale_models::{ContentBlock, Message, MessageRequest};
|
||||
|
||||
let client = DeepSeekClient::new(config)?;
|
||||
let model = client.model().to_string();
|
||||
@@ -8386,24 +8384,25 @@ Provide findings ordered by severity with file references, then open questions,
|
||||
let client = DeepSeekClient::new(&execution_config)?;
|
||||
let request_route = client.effective_route_envelope(&model, chrono::Utc::now());
|
||||
let planned_passes = prompts.len();
|
||||
let mut usage = crate::models::Usage::default();
|
||||
let mut usage = codewhale_models::Usage::default();
|
||||
let mut publication = if args.post {
|
||||
ReviewPublication::NotAttempted
|
||||
} else {
|
||||
ReviewPublication::NotRequested
|
||||
};
|
||||
let report_failure = |usage: &crate::models::Usage, completed_passes, publication, message| {
|
||||
report_review_failure(
|
||||
&args,
|
||||
&route_provider,
|
||||
&model,
|
||||
usage,
|
||||
completed_passes,
|
||||
planned_passes,
|
||||
publication,
|
||||
message,
|
||||
)
|
||||
};
|
||||
let report_failure =
|
||||
|usage: &codewhale_models::Usage, completed_passes, publication, message| {
|
||||
report_review_failure(
|
||||
&args,
|
||||
&route_provider,
|
||||
&model,
|
||||
usage,
|
||||
completed_passes,
|
||||
planned_passes,
|
||||
publication,
|
||||
message,
|
||||
)
|
||||
};
|
||||
let mut accumulator = pr_plan
|
||||
.as_ref()
|
||||
.map(crate::tools::review::PrReviewAccumulator::new);
|
||||
@@ -8450,7 +8449,7 @@ Provide findings ordered by severity with file references, then open questions,
|
||||
};
|
||||
crate::tools::review::add_review_usage(&mut usage, &response.usage);
|
||||
review_stop_reason = response.stop_reason.clone();
|
||||
if crate::models::is_incomplete_stop_reason(review_stop_reason.as_deref()) {
|
||||
if codewhale_models::is_incomplete_stop_reason(review_stop_reason.as_deref()) {
|
||||
return report_failure(
|
||||
&usage,
|
||||
index,
|
||||
@@ -8459,7 +8458,7 @@ Provide findings ordered by severity with file references, then open questions,
|
||||
"Review pass {}/{} incomplete: provider stop reason `{}`; the partial review was not accepted or posted.",
|
||||
index + 1,
|
||||
planned_passes,
|
||||
crate::models::stop_reason_detail(review_stop_reason.as_deref())
|
||||
codewhale_models::stop_reason_detail(review_stop_reason.as_deref())
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -8622,7 +8621,7 @@ impl ReviewPublication {
|
||||
fn review_failure_payload(
|
||||
provider: &str,
|
||||
model: &str,
|
||||
usage: &crate::models::Usage,
|
||||
usage: &codewhale_models::Usage,
|
||||
completed_passes: usize,
|
||||
planned_passes: usize,
|
||||
publication: ReviewPublication,
|
||||
@@ -8646,7 +8645,7 @@ fn report_review_failure(
|
||||
args: &ReviewArgs,
|
||||
provider: &str,
|
||||
model: &str,
|
||||
usage: &crate::models::Usage,
|
||||
usage: &codewhale_models::Usage,
|
||||
completed_passes: usize,
|
||||
planned_passes: usize,
|
||||
publication: ReviewPublication,
|
||||
@@ -11372,7 +11371,7 @@ async fn run_one_shot(
|
||||
force_configured_route: bool,
|
||||
) -> Result<()> {
|
||||
use crate::client::DeepSeekClient;
|
||||
use crate::models::{
|
||||
use codewhale_models::{
|
||||
ContentBlock, Message, MessageRequest, is_incomplete_stop_reason, stop_reason_detail,
|
||||
};
|
||||
|
||||
@@ -11432,7 +11431,7 @@ async fn run_one_shot_json(
|
||||
force_configured_route: bool,
|
||||
) -> Result<()> {
|
||||
use crate::client::DeepSeekClient;
|
||||
use crate::models::{
|
||||
use codewhale_models::{
|
||||
ContentBlock, Message, MessageRequest, SystemPrompt, is_incomplete_stop_reason,
|
||||
stop_reason_detail,
|
||||
};
|
||||
@@ -11502,13 +11501,13 @@ fn one_shot_exec_json_receipt(
|
||||
model: String,
|
||||
output: String,
|
||||
stop_reason: Option<String>,
|
||||
usage: crate::models::Usage,
|
||||
usage: codewhale_models::Usage,
|
||||
) -> serde_json::Value {
|
||||
let incomplete = crate::models::is_incomplete_stop_reason(stop_reason.as_deref());
|
||||
let incomplete = codewhale_models::is_incomplete_stop_reason(stop_reason.as_deref());
|
||||
let error = incomplete.then(|| {
|
||||
format!(
|
||||
"Model response incomplete: provider stop reason `{}`.",
|
||||
crate::models::stop_reason_detail(stop_reason.as_deref())
|
||||
codewhale_models::stop_reason_detail(stop_reason.as_deref())
|
||||
)
|
||||
});
|
||||
serde_json::json!({
|
||||
@@ -15707,7 +15706,7 @@ api_key = "test-only-key"
|
||||
|
||||
#[test]
|
||||
fn review_failure_payload_preserves_usage_without_complete_claim() {
|
||||
let usage = crate::models::Usage {
|
||||
let usage = codewhale_models::Usage {
|
||||
input_tokens: 24,
|
||||
output_tokens: 4,
|
||||
reasoning_tokens: Some(3),
|
||||
@@ -15735,15 +15734,15 @@ api_key = "test-only-key"
|
||||
|
||||
#[test]
|
||||
fn review_failure_after_publication_preserves_all_usage_and_post_state() {
|
||||
let mut usage = crate::models::Usage::default();
|
||||
let mut usage = codewhale_models::Usage::default();
|
||||
for response_usage in [
|
||||
crate::models::Usage {
|
||||
codewhale_models::Usage {
|
||||
input_tokens: 21,
|
||||
output_tokens: 5,
|
||||
reasoning_tokens: Some(2),
|
||||
..Default::default()
|
||||
},
|
||||
crate::models::Usage {
|
||||
codewhale_models::Usage {
|
||||
input_tokens: 34,
|
||||
output_tokens: 8,
|
||||
reasoning_tokens: Some(3),
|
||||
@@ -16570,7 +16569,7 @@ api_key = "test-only-key"
|
||||
"model-a".to_string(),
|
||||
"done".to_string(),
|
||||
Some("end_turn".to_string()),
|
||||
crate::models::Usage {
|
||||
codewhale_models::Usage {
|
||||
input_tokens: 12,
|
||||
output_tokens: 3,
|
||||
..Default::default()
|
||||
@@ -16584,7 +16583,7 @@ api_key = "test-only-key"
|
||||
"model-a".to_string(),
|
||||
"partial".to_string(),
|
||||
Some("max_output_tokens".to_string()),
|
||||
crate::models::Usage {
|
||||
codewhale_models::Usage {
|
||||
input_tokens: 20,
|
||||
output_tokens: 9,
|
||||
..Default::default()
|
||||
|
||||
@@ -50,12 +50,12 @@ use anyhow::{Result, anyhow};
|
||||
use async_stream::try_stream;
|
||||
use futures_util::Stream;
|
||||
|
||||
use crate::models::{
|
||||
use codewhale_models::{
|
||||
ContentBlock, MessageDelta, MessageRequest, MessageResponse, StreamEvent, Usage,
|
||||
};
|
||||
|
||||
use super::{LlmClient, StreamEventBox};
|
||||
use crate::models::Role;
|
||||
use codewhale_models::Role;
|
||||
|
||||
/// A pre-recorded "turn" the mock will replay on the next streaming call.
|
||||
///
|
||||
@@ -294,7 +294,7 @@ fn stream_from_canned(turn: CannedTurn) -> StreamEventBox {
|
||||
/// `MessageResponse` by concatenating text deltas. Used only as a fallback
|
||||
/// when callers `create_message` without a queued `MessageResponse`.
|
||||
fn synthesize_message_response(turn: CannedTurn, model: &str) -> MessageResponse {
|
||||
use crate::models::Delta;
|
||||
use codewhale_models::Delta;
|
||||
|
||||
let mut text = String::new();
|
||||
let mut stop_reason: Option<String> = None;
|
||||
@@ -336,7 +336,7 @@ fn synthesize_message_response(turn: CannedTurn, model: &str) -> MessageResponse
|
||||
pub mod canned {
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::models::{
|
||||
use codewhale_models::{
|
||||
ContentBlockStart, Delta, MessageDelta, MessageResponse, StreamEvent, Usage,
|
||||
};
|
||||
|
||||
@@ -477,7 +477,7 @@ mod tests {
|
||||
|
||||
use super::*;
|
||||
use crate::llm_client::LlmClient;
|
||||
use crate::models::{Delta, Message, MessageRequest, StreamEvent};
|
||||
use codewhale_models::{Delta, Message, MessageRequest, StreamEvent};
|
||||
|
||||
fn empty_request() -> MessageRequest {
|
||||
MessageRequest {
|
||||
@@ -641,7 +641,7 @@ mod tests {
|
||||
while let Some(ev) = stream.next().await {
|
||||
match ev.unwrap() {
|
||||
StreamEvent::ContentBlockStart { content_block, .. } => {
|
||||
use crate::models::ContentBlockStart;
|
||||
use codewhale_models::ContentBlockStart;
|
||||
if let ContentBlockStart::ToolUse { name, .. } = content_block {
|
||||
assert_eq!(name, "list_dir");
|
||||
saw_tool_use = true;
|
||||
|
||||
@@ -23,8 +23,8 @@
|
||||
//! ```
|
||||
|
||||
use crate::config::RetryPolicy;
|
||||
use crate::models::{MessageRequest, MessageResponse, StreamEvent};
|
||||
use anyhow::Result;
|
||||
use codewhale_models::{MessageRequest, MessageResponse, StreamEvent};
|
||||
use serde_json::Value;
|
||||
use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
|
||||
@@ -6,7 +6,7 @@ use std::sync::{Mutex, OnceLock};
|
||||
use lru::LruCache;
|
||||
use sha2::{Digest, Sha256};
|
||||
|
||||
use crate::models::{MessageRequest, MessageResponse, Usage};
|
||||
use codewhale_models::{MessageRequest, MessageResponse, Usage};
|
||||
|
||||
const DEFAULT_CAPACITY: usize = 256;
|
||||
|
||||
|
||||
@@ -4049,11 +4049,11 @@ impl McpPool {
|
||||
}
|
||||
|
||||
/// Convert discovered tools to API Tool format
|
||||
pub fn to_api_tools(&self) -> Vec<crate::models::Tool> {
|
||||
pub fn to_api_tools(&self) -> Vec<codewhale_models::Tool> {
|
||||
let mut api_tools = Vec::new();
|
||||
// Add regular tools
|
||||
for (name, tool) in self.all_tools() {
|
||||
api_tools.push(crate::models::Tool {
|
||||
api_tools.push(codewhale_models::Tool {
|
||||
tool_type: None,
|
||||
name,
|
||||
description: tool.description.clone().unwrap_or_default(),
|
||||
@@ -4095,7 +4095,7 @@ impl McpPool {
|
||||
if api_tools.iter().any(|tool| tool.name == name) {
|
||||
continue;
|
||||
}
|
||||
api_tools.push(crate::models::Tool {
|
||||
api_tools.push(codewhale_models::Tool {
|
||||
tool_type: None,
|
||||
name,
|
||||
description: oauth::authenticate_tool_description(server),
|
||||
@@ -4119,7 +4119,7 @@ impl McpPool {
|
||||
// and prompt tokens. Gate each on its own non-empty collection, mirroring
|
||||
// the `mcp_read_resource` guard below (`!resources.is_empty()`).
|
||||
if !self.all_resources().is_empty() {
|
||||
api_tools.push(crate::models::Tool {
|
||||
api_tools.push(codewhale_models::Tool {
|
||||
tool_type: None,
|
||||
name: "list_mcp_resources".to_string(),
|
||||
description: "List available MCP resources across servers (optionally filtered by server).".to_string(),
|
||||
@@ -4137,7 +4137,7 @@ impl McpPool {
|
||||
});
|
||||
}
|
||||
if !self.all_resource_templates().is_empty() {
|
||||
api_tools.push(crate::models::Tool {
|
||||
api_tools.push(codewhale_models::Tool {
|
||||
tool_type: None,
|
||||
name: "list_mcp_resource_templates".to_string(),
|
||||
description: "List available MCP resource templates across servers (optionally filtered by server).".to_string(),
|
||||
@@ -4158,7 +4158,7 @@ impl McpPool {
|
||||
// Add resource reading tools if resources exist
|
||||
let resources = self.all_resources();
|
||||
if !resources.is_empty() {
|
||||
api_tools.push(crate::models::Tool {
|
||||
api_tools.push(codewhale_models::Tool {
|
||||
tool_type: None,
|
||||
name: "mcp_read_resource".to_string(),
|
||||
description: "Read a resource from an MCP server using its URI".to_string(),
|
||||
@@ -4176,7 +4176,7 @@ impl McpPool {
|
||||
strict: None,
|
||||
cache_control: None,
|
||||
});
|
||||
api_tools.push(crate::models::Tool {
|
||||
api_tools.push(codewhale_models::Tool {
|
||||
tool_type: None,
|
||||
name: "read_mcp_resource".to_string(),
|
||||
description: "Alias for mcp_read_resource.".to_string(),
|
||||
@@ -4199,7 +4199,7 @@ impl McpPool {
|
||||
// Add prompt getting tools if prompts exist
|
||||
let prompts = self.all_prompts();
|
||||
if !prompts.is_empty() {
|
||||
api_tools.push(crate::models::Tool {
|
||||
api_tools.push(codewhale_models::Tool {
|
||||
tool_type: None,
|
||||
name: "mcp_get_prompt".to_string(),
|
||||
description: "Get a prompt from an MCP server".to_string(),
|
||||
|
||||
@@ -14,11 +14,11 @@ use uuid::Uuid;
|
||||
use crate::client::DeepSeekClient;
|
||||
use crate::config::Config;
|
||||
use crate::llm_client::LlmClient;
|
||||
use crate::models::Role;
|
||||
use crate::models::{ContentBlock, Message, MessageRequest};
|
||||
use crate::session_manager::SessionManager;
|
||||
use crate::tools::spec::{ToolError, ToolResult};
|
||||
use crate::tools::{ToolContext, ToolRegistryBuilder};
|
||||
use codewhale_models::Role;
|
||||
use codewhale_models::{ContentBlock, Message, MessageRequest};
|
||||
|
||||
#[derive(Debug, Default, Deserialize)]
|
||||
struct McpServerConfigFile {
|
||||
@@ -427,10 +427,10 @@ impl McpServer {
|
||||
// A provider-declared incomplete reply must not enter the stored
|
||||
// thread or be returned as a successful answer. The billed usage is
|
||||
// still reported in the error payload.
|
||||
if crate::models::is_incomplete_stop_reason(response.stop_reason.as_deref()) {
|
||||
if codewhale_models::is_incomplete_stop_reason(response.stop_reason.as_deref()) {
|
||||
let error = format!(
|
||||
"Model response incomplete: provider stop reason `{}`; the partial reply was not accepted.",
|
||||
crate::models::stop_reason_detail(response.stop_reason.as_deref())
|
||||
codewhale_models::stop_reason_detail(response.stop_reason.as_deref())
|
||||
);
|
||||
return Ok(json!({
|
||||
"content": [{ "type": "text", "text": &error }],
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use crate::models::SystemBlock;
|
||||
use codewhale_models::SystemBlock;
|
||||
|
||||
use super::fragment::{FragmentId, FragmentRender, FragmentRole, ModelContextFragment};
|
||||
|
||||
|
||||
@@ -135,7 +135,7 @@ impl ModelInventory {
|
||||
// that nobody verified it — the auto-router must not read a
|
||||
// guessed window as a route capability.
|
||||
let mut context_window_unverified =
|
||||
crate::model_catalog::resolved_context_window(&model).is_none();
|
||||
codewhale_models::model_catalog::resolved_context_window(&model).is_none();
|
||||
if let Ok(route) =
|
||||
crate::route_runtime::resolve_runtime_route(config, provider, Some(&model))
|
||||
{
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
//! Historically, "what is this model's context window / max output / does it
|
||||
//! reason?" was answered by several hard-coded sites:
|
||||
//!
|
||||
//! * [`crate::models::context_window_for_model`] /
|
||||
//! * [`codewhale_models::context_window_for_model`] /
|
||||
//! the models module's context-window lookup for context windows,
|
||||
//! * [`crate::models::max_output_tokens_for_model`] for output caps,
|
||||
//! * [`crate::models::model_supports_reasoning`] for the reasoning flag,
|
||||
//! * [`codewhale_models::max_output_tokens_for_model`] for output caps,
|
||||
//! * [`codewhale_models::model_supports_reasoning`] for the reasoning flag,
|
||||
//! * the `DEFAULT_*` model-id constants in `crates/config/src/lib.rs` for the
|
||||
//! canonical model each provider ships by default.
|
||||
//!
|
||||
@@ -20,7 +20,7 @@
|
||||
//!
|
||||
//! The registry does not re-declare context-window / max-output / reasoning
|
||||
//! numbers. Instead it **seeds** each entry by calling the existing
|
||||
//! `crate::models` functions, so the registry can never silently disagree with
|
||||
//! `codewhale_models` functions, so the registry can never silently disagree with
|
||||
//! `models.rs`. The canonical model ids come from the same provider defaults
|
||||
//! the config crate ships (see [`SEED_MODEL_IDS`]). The
|
||||
//! The `registry_context_window_matches_models_rs` drift guard then
|
||||
@@ -34,7 +34,7 @@
|
||||
use std::collections::BTreeMap;
|
||||
use std::sync::OnceLock;
|
||||
|
||||
use crate::models::{
|
||||
use codewhale_models::{
|
||||
context_window_for_model, max_output_tokens_for_model, model_supports_reasoning,
|
||||
};
|
||||
|
||||
@@ -84,7 +84,7 @@ pub enum ModelProvider {
|
||||
|
||||
/// One row of model facts, looked up in [`lookup`].
|
||||
///
|
||||
/// All numeric fields are seeded from `crate::models` so they stay in lockstep
|
||||
/// All numeric fields are seeded from `codewhale_models` so they stay in lockstep
|
||||
/// with the legacy lookups (see module docs).
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct ModelMetadata {
|
||||
@@ -103,7 +103,7 @@ pub struct ModelMetadata {
|
||||
|
||||
impl ModelMetadata {
|
||||
/// Build a metadata row for `id` by seeding every fact from the existing
|
||||
/// `crate::models` lookups. This is the only constructor, which is what
|
||||
/// `codewhale_models` lookups. This is the only constructor, which is what
|
||||
/// keeps the registry from drifting away from `models.rs`.
|
||||
fn seed(id: &'static str, provider: ModelProvider) -> Self {
|
||||
Self {
|
||||
@@ -238,7 +238,7 @@ fn registry() -> &'static BTreeMap<&'static str, ModelMetadata> {
|
||||
///
|
||||
/// Returns a pre-seeded [`ModelMetadata`] when `model` is one of the canonical
|
||||
/// [`SEED_MODEL_IDS`] (case-insensitive). For any other id, this falls back to
|
||||
/// the same `crate::models` heuristics (explicit `_Nk` suffix, DeepSeek/Claude
|
||||
/// the same `codewhale_models` heuristics (explicit `_Nk` suffix, DeepSeek/Claude
|
||||
/// family rules, etc.) and reports the provider as [`ModelProvider::Other`], so
|
||||
/// callers always get a usable answer rather than `None` for a real model.
|
||||
///
|
||||
@@ -285,7 +285,7 @@ mod tests {
|
||||
|
||||
/// DRIFT GUARD (#3071, #3073).
|
||||
///
|
||||
/// The registry must agree with `crate::models` for the context window of
|
||||
/// The registry must agree with `codewhale_models` for the context window of
|
||||
/// every model it claims to know. Today they agree because the registry is
|
||||
/// *seeded* from `models.rs`; this test exists so that if a future change
|
||||
/// replaces a seed with a hard-coded literal that drifts from `models.rs`,
|
||||
|
||||
@@ -15,9 +15,9 @@ use crate::cost_status::{
|
||||
};
|
||||
use crate::llm_client::LlmClient;
|
||||
use crate::model_inventory::ModelInventory;
|
||||
use crate::models::Role;
|
||||
use crate::models::{ContentBlock, Message, MessageRequest, MessageResponse, SystemPrompt};
|
||||
use crate::reasoning_preference::ReasoningEffort;
|
||||
use codewhale_models::Role;
|
||||
use codewhale_models::{ContentBlock, Message, MessageRequest, MessageResponse, SystemPrompt};
|
||||
|
||||
/// Big/cheap model pair the auto-router may choose between for the active
|
||||
/// provider (#3018).
|
||||
@@ -1038,7 +1038,7 @@ fn auto_route_pair(
|
||||
AutoRoutePair { strong, fast }
|
||||
}
|
||||
|
||||
fn auto_route_usage_has_reported_data(usage: &crate::models::Usage) -> bool {
|
||||
fn auto_route_usage_has_reported_data(usage: &codewhale_models::Usage) -> bool {
|
||||
usage.input_tokens > 0
|
||||
|| usage.output_tokens > 0
|
||||
|| usage.prompt_cache_hit_tokens.is_some()
|
||||
@@ -1098,7 +1098,7 @@ fn auto_route_attempt_from_response(
|
||||
.into_iter()
|
||||
.collect();
|
||||
let recommendation =
|
||||
(!crate::models::is_incomplete_stop_reason(response.stop_reason.as_deref()))
|
||||
(!codewhale_models::is_incomplete_stop_reason(response.stop_reason.as_deref()))
|
||||
.then(|| {
|
||||
parse_inventory_auto_route_recommendation(
|
||||
&message_response_text(response),
|
||||
@@ -1474,7 +1474,7 @@ mod tests {
|
||||
id: &str,
|
||||
text: &str,
|
||||
stop_reason: &str,
|
||||
usage: crate::models::Usage,
|
||||
usage: codewhale_models::Usage,
|
||||
) -> MessageResponse {
|
||||
MessageResponse {
|
||||
id: id.to_string(),
|
||||
@@ -1553,7 +1553,7 @@ mod tests {
|
||||
"same-provider-response-id",
|
||||
&format!(r#"{{"provider":"openrouter","model":"{model}","thinking":"off"}}"#),
|
||||
"stop",
|
||||
crate::models::Usage {
|
||||
codewhale_models::Usage {
|
||||
input_tokens: 10,
|
||||
output_tokens: 2,
|
||||
prompt_cache_hit_tokens: Some(3),
|
||||
@@ -1580,7 +1580,7 @@ mod tests {
|
||||
"same-provider-response-id",
|
||||
"not valid route json",
|
||||
"stop",
|
||||
crate::models::Usage {
|
||||
codewhale_models::Usage {
|
||||
input_tokens: 11,
|
||||
output_tokens: 3,
|
||||
..Default::default()
|
||||
@@ -1594,7 +1594,7 @@ mod tests {
|
||||
"same-provider-response-id",
|
||||
&format!(r#"{{"provider":"openrouter","model":"{model}"}}"#),
|
||||
"length",
|
||||
crate::models::Usage {
|
||||
codewhale_models::Usage {
|
||||
input_tokens: 12,
|
||||
output_tokens: 4,
|
||||
..Default::default()
|
||||
@@ -1610,7 +1610,7 @@ mod tests {
|
||||
"missing-usage-response-id",
|
||||
"not valid route json",
|
||||
"stop",
|
||||
crate::models::Usage::default(),
|
||||
codewhale_models::Usage::default(),
|
||||
),
|
||||
&inventory,
|
||||
);
|
||||
|
||||
@@ -165,7 +165,10 @@ pub fn cache_path() -> Option<PathBuf> {
|
||||
#[must_use]
|
||||
pub fn status() -> ModelsDevStatus {
|
||||
let current = STATUS.read().map(|guard| guard.clone()).unwrap_or_default();
|
||||
honor_bundled_staleness(current, crate::model_catalog::bundled_catalog_is_stale())
|
||||
honor_bundled_staleness(
|
||||
current,
|
||||
codewhale_models::model_catalog::bundled_catalog_is_stale(),
|
||||
)
|
||||
}
|
||||
|
||||
/// A Bundled-only report whose snapshot is itself past TTL reports `Stale`:
|
||||
|
||||
@@ -41,7 +41,7 @@ use std::hash::{Hash, Hasher};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::models::{SystemPrompt, Tool};
|
||||
use codewhale_models::{SystemPrompt, Tool};
|
||||
|
||||
/// A snapshot of the immutable prefix's fingerprint.
|
||||
///
|
||||
|
||||
+12
-12
@@ -16,7 +16,7 @@ use crate::config::{
|
||||
DEFAULT_STEPFUN_BASE_URL, DEFAULT_STEPFUN_MODEL, DEFAULT_STEPFUN_PLAN_BASE_URL,
|
||||
canonical_model_id_for_provider,
|
||||
};
|
||||
use crate::models::{Usage, has_date_snapshot_suffix};
|
||||
use codewhale_models::{Usage, has_date_snapshot_suffix};
|
||||
|
||||
/// Cost display currency.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
@@ -747,7 +747,7 @@ fn known_pricing_for_model(model_lower: &str) -> Option<ModelPricing> {
|
||||
return explicit;
|
||||
}
|
||||
if let Some((input_usd_per_million, output_usd_per_million)) =
|
||||
crate::model_catalog::resolved_usd_pricing(model_lower)
|
||||
codewhale_models::model_catalog::resolved_usd_pricing(model_lower)
|
||||
{
|
||||
return Some(usd_only_pricing(
|
||||
input_usd_per_million,
|
||||
@@ -4253,15 +4253,15 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn deepseek_pricing_requires_exact_ids_or_explicit_route_aliases() {
|
||||
let _lock = crate::model_catalog::test_catalog_lock();
|
||||
let _lock = codewhale_models::model_catalog::test_catalog_lock();
|
||||
let at = utc_hm(2, 0);
|
||||
let catalog = crate::model_catalog::MergedCatalog::from_sources(
|
||||
let catalog = codewhale_models::model_catalog::MergedCatalog::from_sources(
|
||||
BTreeMap::new(),
|
||||
None,
|
||||
crate::model_catalog::bundled_catalog(),
|
||||
codewhale_models::model_catalog::bundled_catalog(),
|
||||
at,
|
||||
);
|
||||
let _guard = crate::model_catalog::replace_active_catalog_for_test(catalog);
|
||||
let _guard = codewhale_models::model_catalog::replace_active_catalog_for_test(catalog);
|
||||
let usage = Usage {
|
||||
input_tokens: 1_000,
|
||||
output_tokens: 100,
|
||||
@@ -4478,7 +4478,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn catalog_pricing_overrides_known_row_when_present() {
|
||||
let _lock = crate::model_catalog::test_catalog_lock();
|
||||
let _lock = codewhale_models::model_catalog::test_catalog_lock();
|
||||
let mut overrides = BTreeMap::new();
|
||||
let models = [
|
||||
"catalog-priced-model",
|
||||
@@ -4487,7 +4487,7 @@ mod tests {
|
||||
for model in models {
|
||||
overrides.insert(
|
||||
model.to_string(),
|
||||
crate::model_catalog::CatalogEntry {
|
||||
codewhale_models::model_catalog::CatalogEntry {
|
||||
id: model.to_string(),
|
||||
context_window: None,
|
||||
max_output: None,
|
||||
@@ -4497,17 +4497,17 @@ mod tests {
|
||||
modalities: Vec::new(),
|
||||
supported_parameters: Vec::new(),
|
||||
provider_model_id: None,
|
||||
provenance: crate::model_catalog::MetadataProvenance::UserOverride,
|
||||
provenance: codewhale_models::model_catalog::MetadataProvenance::UserOverride,
|
||||
},
|
||||
);
|
||||
}
|
||||
let catalog = crate::model_catalog::MergedCatalog::from_sources(
|
||||
let catalog = codewhale_models::model_catalog::MergedCatalog::from_sources(
|
||||
overrides,
|
||||
None,
|
||||
crate::model_catalog::bundled_catalog(),
|
||||
codewhale_models::model_catalog::bundled_catalog(),
|
||||
Utc::now(),
|
||||
);
|
||||
let _guard = crate::model_catalog::replace_active_catalog_for_test(catalog);
|
||||
let _guard = codewhale_models::model_catalog::replace_active_catalog_for_test(catalog);
|
||||
|
||||
for model in models {
|
||||
let pricing = pricing_for_model_at(model, Utc::now()).expect(model);
|
||||
|
||||
@@ -21,8 +21,8 @@
|
||||
//! `AppendLog` / `TurnScratch` / `ThreeZoneRequest` are type scaffolding
|
||||
//! for future phases — not yet wired into the request path.
|
||||
|
||||
use crate::models::Role;
|
||||
use crate::models::{Message, SystemPrompt, Tool};
|
||||
use codewhale_models::Role;
|
||||
use codewhale_models::{Message, SystemPrompt, Tool};
|
||||
// ── helpers ────────────────────────────────────────────────────────────
|
||||
|
||||
fn sha256_hex(bytes: &[u8]) -> String {
|
||||
@@ -348,16 +348,16 @@ impl<'a> ThreeZoneRequest<'a> {
|
||||
Some(SystemPrompt::Text(text)) => {
|
||||
messages.push(Message {
|
||||
role: Role::System,
|
||||
content: vec![crate::models::ContentBlock::Text {
|
||||
content: vec![codewhale_models::ContentBlock::Text {
|
||||
text: text.clone(),
|
||||
cache_control: None,
|
||||
}],
|
||||
});
|
||||
}
|
||||
Some(SystemPrompt::Blocks(blocks)) => {
|
||||
let content: Vec<crate::models::ContentBlock> = blocks
|
||||
let content: Vec<codewhale_models::ContentBlock> = blocks
|
||||
.iter()
|
||||
.map(|block| crate::models::ContentBlock::Text {
|
||||
.map(|block| codewhale_models::ContentBlock::Text {
|
||||
text: block.text.clone(),
|
||||
cache_control: block.cache_control.clone(),
|
||||
})
|
||||
@@ -398,7 +398,7 @@ impl<'a> ThreeZoneRequest<'a> {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::models::ContentBlock;
|
||||
use codewhale_models::ContentBlock;
|
||||
|
||||
fn make_tool(name: &str) -> Tool {
|
||||
Tool {
|
||||
@@ -652,7 +652,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn blocks_system_prompt_preserves_cache_control() {
|
||||
use crate::models::{CacheControl, SystemBlock};
|
||||
use codewhale_models::{CacheControl, SystemBlock};
|
||||
let cc = Some(CacheControl {
|
||||
cache_type: "ephemeral".to_string(),
|
||||
});
|
||||
|
||||
@@ -10,9 +10,9 @@
|
||||
//! Keeping every layer's text in one module makes prompt tuning a
|
||||
//! single-file operation.
|
||||
|
||||
use crate::models::{SystemBlock, SystemPrompt};
|
||||
use crate::project_context::load_project_context_with_parents;
|
||||
use codewhale_config::AppMode;
|
||||
use codewhale_models::{SystemBlock, SystemPrompt};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::{LazyLock, Mutex};
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
use std::path::Path;
|
||||
|
||||
use crate::models::{SystemBlock, SystemPrompt};
|
||||
use codewhale_models::{SystemBlock, SystemPrompt};
|
||||
|
||||
/// Pager title for the preview surface.
|
||||
pub const PREVIEW_TITLE: &str = "Effective Base Prompt";
|
||||
|
||||
@@ -14,9 +14,9 @@ use crate::config::ApiProvider;
|
||||
use crate::core::events::Event;
|
||||
use crate::fast_hash::{FastHashMap, FastHashSet};
|
||||
use crate::llm_client::LlmClient;
|
||||
use crate::models::Role;
|
||||
use crate::models::{ContentBlock, Message, MessageRequest, Tool};
|
||||
use crate::regex_cache::compile_user_regex;
|
||||
use codewhale_models::Role;
|
||||
use codewhale_models::{ContentBlock, Message, MessageRequest, Tool};
|
||||
|
||||
// ── Prompt‑building constants ──────────────────────────────────────────────
|
||||
|
||||
@@ -705,10 +705,10 @@ pub async fn run_purge(
|
||||
|
||||
// A truncated response can still carry a complete-looking `purge_context`
|
||||
// call; executing it would mutate the session from incomplete output.
|
||||
if crate::models::is_incomplete_stop_reason(response.stop_reason.as_deref()) {
|
||||
if codewhale_models::is_incomplete_stop_reason(response.stop_reason.as_deref()) {
|
||||
return Err(format!(
|
||||
"Purge model response incomplete: provider stop reason `{}`; no purge was applied.",
|
||||
crate::models::stop_reason_detail(response.stop_reason.as_deref())
|
||||
codewhale_models::stop_reason_detail(response.stop_reason.as_deref())
|
||||
));
|
||||
}
|
||||
|
||||
@@ -1093,7 +1093,7 @@ mod tests {
|
||||
}
|
||||
|
||||
use crate::llm_client::mock::MockLlmClient;
|
||||
use crate::models::{MessageResponse, Usage};
|
||||
use codewhale_models::{MessageResponse, Usage};
|
||||
|
||||
fn msg_response_with_tool_call(operations: serde_json::Value) -> MessageResponse {
|
||||
MessageResponse {
|
||||
|
||||
@@ -19,9 +19,10 @@ use serde_json::{Value, json};
|
||||
use sha2::{Digest, Sha256};
|
||||
use tokio::sync::mpsc;
|
||||
|
||||
use codewhale_models::{ContentBlock, Message};
|
||||
|
||||
use crate::{
|
||||
core::events::{Event as EngineEvent, TurnOutcomeStatus},
|
||||
models::{ContentBlock, Message},
|
||||
runtime_chat_relay::{
|
||||
RuntimeChatControlScope, RuntimeChatProjection, RuntimeChatPrompt, RuntimeChatRelayHost,
|
||||
},
|
||||
@@ -5004,7 +5005,7 @@ fn epoch_seconds() -> u64 {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::models::Role;
|
||||
use codewhale_models::Role;
|
||||
use std::sync::{
|
||||
Arc, Mutex,
|
||||
atomic::{AtomicUsize, Ordering},
|
||||
@@ -7697,8 +7698,8 @@ mod tests {
|
||||
|
||||
fn turn_complete_event() -> EngineEvent {
|
||||
EngineEvent::TurnComplete {
|
||||
usage: crate::models::Usage::default(),
|
||||
parent_route_usage: crate::models::Usage::default(),
|
||||
usage: codewhale_models::Usage::default(),
|
||||
parent_route_usage: codewhale_models::Usage::default(),
|
||||
routed_usage_dropped_records: 0,
|
||||
status: TurnOutcomeStatus::Completed,
|
||||
error: None,
|
||||
@@ -8179,10 +8180,10 @@ mod tests {
|
||||
assert!(controller.has_active_run());
|
||||
assert!(controller.start(fixture_start()).is_err());
|
||||
|
||||
let usage = crate::models::Usage {
|
||||
let usage = codewhale_models::Usage {
|
||||
input_tokens: 17,
|
||||
output_tokens: 5,
|
||||
..crate::models::Usage::default()
|
||||
..codewhale_models::Usage::default()
|
||||
};
|
||||
controller.observe_engine_event(&EngineEvent::TurnComplete {
|
||||
usage: usage.clone(),
|
||||
|
||||
@@ -21,13 +21,13 @@ use tokio::sync::Mutex;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::llm_client::LlmClient;
|
||||
use crate::models::Role;
|
||||
use crate::models::{
|
||||
use crate::repl::runtime::{BatchResp, RpcDispatcher, RpcRequest, RpcResponse, SingleResp};
|
||||
use crate::utils::spawn_supervised;
|
||||
use codewhale_models::Role;
|
||||
use codewhale_models::{
|
||||
ContentBlock, Message, MessageRequest, MessageResponse, SystemPrompt, Usage,
|
||||
is_incomplete_stop_reason, stop_reason_detail,
|
||||
};
|
||||
use crate::repl::runtime::{BatchResp, RpcDispatcher, RpcRequest, RpcResponse, SingleResp};
|
||||
use crate::utils::spawn_supervised;
|
||||
|
||||
/// One pre-dispatch reservation in the shared routed-usage ledger.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
//! - Code rounds and sub-LLM calls travel over a single stdin/stdout
|
||||
//! pipe to a long-lived Python subprocess. No HTTP sidecar.
|
||||
|
||||
use crate::models::Usage;
|
||||
use codewhale_models::Usage;
|
||||
|
||||
pub mod bridge;
|
||||
pub mod prompt;
|
||||
@@ -92,7 +92,7 @@ mod tests {
|
||||
prompt_cache_miss_tokens: Some(20),
|
||||
reasoning_tokens: Some(4),
|
||||
reasoning_replay_tokens: Some(3),
|
||||
server_tool_use: Some(crate::models::ServerToolUsage {
|
||||
server_tool_use: Some(codewhale_models::ServerToolUsage {
|
||||
code_execution_requests: Some(2),
|
||||
tool_search_requests: Some(1),
|
||||
}),
|
||||
@@ -109,7 +109,7 @@ mod tests {
|
||||
assert_eq!(total.reasoning_replay_tokens, Some(3));
|
||||
assert_eq!(
|
||||
total.server_tool_use,
|
||||
Some(crate::models::ServerToolUsage {
|
||||
Some(codewhale_models::ServerToolUsage {
|
||||
code_execution_requests: Some(2),
|
||||
tool_search_requests: Some(1),
|
||||
})
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
//! The prompt is deliberately strict: the only way to make progress is
|
||||
//! through a `repl` block. There is no fall-through prose path.
|
||||
|
||||
use crate::models::SystemPrompt;
|
||||
use codewhale_models::SystemPrompt;
|
||||
|
||||
/// Build the system prompt for a Recursive Language Model (RLM) root call.
|
||||
pub fn rlm_system_prompt() -> SystemPrompt {
|
||||
|
||||
@@ -10,8 +10,8 @@ use serde_json::{Value, json};
|
||||
use tokio::sync::Mutex;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::models::{ContentBlock, Message, SystemPrompt};
|
||||
use crate::repl::PythonRuntime;
|
||||
use codewhale_models::{ContentBlock, Message, SystemPrompt};
|
||||
|
||||
pub type SharedRlmSessionStore = Arc<Mutex<HashMap<String, Arc<Mutex<RlmSession>>>>>;
|
||||
|
||||
@@ -459,7 +459,7 @@ fn sha256_hex(bytes: &[u8]) -> String {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::models::Role;
|
||||
use codewhale_models::Role;
|
||||
|
||||
#[test]
|
||||
fn derive_session_name_slugifies_path() {
|
||||
|
||||
@@ -10,15 +10,15 @@ use uuid::Uuid;
|
||||
|
||||
use crate::client::DeepSeekClient;
|
||||
use crate::core::events::Event;
|
||||
use crate::models::{
|
||||
use crate::repl::PythonRuntime;
|
||||
use codewhale_models::{
|
||||
ContentBlock, Message, MessageRequest, SystemPrompt, Usage, is_incomplete_stop_reason,
|
||||
stop_reason_detail,
|
||||
};
|
||||
use crate::repl::PythonRuntime;
|
||||
|
||||
use super::bridge::{RlmBridge, RlmLlmClient, RlmUsageAccumulator};
|
||||
use super::prompt::rlm_system_prompt;
|
||||
use crate::models::Role;
|
||||
use codewhale_models::Role;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Constants
|
||||
@@ -998,7 +998,7 @@ fn truncate_text(text: &str, max_chars: usize) -> String {
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::llm_client::mock::MockLlmClient;
|
||||
use crate::models::MessageResponse;
|
||||
use codewhale_models::MessageResponse;
|
||||
|
||||
#[tokio::test]
|
||||
async fn max_tokens_complete_repl_is_not_executed_or_accepted() {
|
||||
|
||||
@@ -811,14 +811,14 @@ pub fn usage_chip(
|
||||
provider,
|
||||
model,
|
||||
surface,
|
||||
&crate::models::Usage::default(),
|
||||
&codewhale_models::Usage::default(),
|
||||
chrono::Utc::now(),
|
||||
)
|
||||
} else {
|
||||
crate::pricing::audit_turn_cost_for_provider_at(
|
||||
provider,
|
||||
model,
|
||||
&crate::models::Usage::default(),
|
||||
&codewhale_models::Usage::default(),
|
||||
chrono::Utc::now(),
|
||||
)
|
||||
};
|
||||
@@ -1102,8 +1102,8 @@ fn xiaomi_is_explicit_pay_as_you_go(config: Option<&ProviderConfig>) -> bool {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::models::Usage;
|
||||
use crate::pricing::CostCurrency;
|
||||
use codewhale_models::Usage;
|
||||
|
||||
fn config_with(provider: ApiProvider, provider_config: ProviderConfig) -> Config {
|
||||
let mut config = Config::default();
|
||||
@@ -1754,7 +1754,7 @@ mod tests {
|
||||
fn child_route_billing_fails_closed_for_every_ambiguous_provider() {
|
||||
use crate::pricing::UnpricedReason;
|
||||
|
||||
let usage = crate::models::Usage {
|
||||
let usage = codewhale_models::Usage {
|
||||
input_tokens: 10_000,
|
||||
output_tokens: 1_000,
|
||||
..Default::default()
|
||||
|
||||
@@ -2,7 +2,7 @@ use codewhale_config::route::RouteLimits;
|
||||
|
||||
use crate::config::{ApiProvider, provider_capability};
|
||||
use crate::context_budget::ContextBudget;
|
||||
use crate::models::{DEFAULT_COMPACTION_TOKEN_THRESHOLD, context_window_for_model};
|
||||
use codewhale_models::{DEFAULT_COMPACTION_TOKEN_THRESHOLD, context_window_for_model};
|
||||
|
||||
/// Safe ordinary API request cap across provider routes.
|
||||
const API_MAX_OUTPUT_TOKENS: u32 = 65_536;
|
||||
@@ -118,7 +118,7 @@ pub(crate) fn effective_max_output_tokens(model: &str) -> u32 {
|
||||
// output ceiling in a machine-readable form; that number remains a
|
||||
// catalogue-sourced value to re-verify against official docs when they
|
||||
// publish one (#5373).
|
||||
if let Some(documented) = crate::models::max_output_tokens_for_model(model) {
|
||||
if let Some(documented) = codewhale_models::max_output_tokens_for_model(model) {
|
||||
return documented.min(API_MAX_OUTPUT_TOKENS);
|
||||
}
|
||||
|
||||
@@ -224,7 +224,7 @@ pub(crate) fn output_ceiling_source(provider: ApiProvider, model: &str) -> Outpu
|
||||
if matches!(
|
||||
provider,
|
||||
ApiProvider::Anthropic | ApiProvider::MinimaxAnthropic | ApiProvider::Openmodel
|
||||
) && crate::models::max_output_tokens_for_model(model).is_none()
|
||||
) && codewhale_models::max_output_tokens_for_model(model).is_none()
|
||||
{
|
||||
return OutputCeilingSource::Unverified(ANTHROPIC_UNKNOWN_MAX_OUTPUT_TOKENS);
|
||||
}
|
||||
@@ -256,7 +256,7 @@ pub(crate) fn effective_max_output_tokens_for_route(
|
||||
// for a configured 32K Ollama route, leaving just 1K for input (#5820).
|
||||
// Explicit requests and documented ceilings retain their existing rules.
|
||||
let requested_cap = if explicit_max_output_tokens_override().is_none()
|
||||
&& crate::models::max_output_tokens_for_model(model).is_none()
|
||||
&& codewhale_models::max_output_tokens_for_model(model).is_none()
|
||||
&& route_cap.is_none()
|
||||
&& matches!(
|
||||
compatibility_source,
|
||||
@@ -374,7 +374,7 @@ mod tests {
|
||||
let _canonical = crate::test_support::EnvVarGuard::remove("CODEWHALE_MAX_OUTPUT_TOKENS");
|
||||
let _legacy = crate::test_support::EnvVarGuard::remove("DEEPSEEK_MAX_OUTPUT_TOKENS");
|
||||
let model = "qwen2.5:7b";
|
||||
assert!(crate::models::max_output_tokens_for_model(model).is_none());
|
||||
assert!(codewhale_models::max_output_tokens_for_model(model).is_none());
|
||||
for provider in [
|
||||
ApiProvider::Ollama,
|
||||
ApiProvider::Sglang,
|
||||
@@ -846,14 +846,14 @@ mod tests {
|
||||
let _env_lock = crate::test_support::lock_test_env();
|
||||
let _codewhale = crate::test_support::EnvVarGuard::remove("CODEWHALE_MAX_OUTPUT_TOKENS");
|
||||
let _deepseek = crate::test_support::EnvVarGuard::remove("DEEPSEEK_MAX_OUTPUT_TOKENS");
|
||||
let _catalog_lock = crate::model_catalog::test_catalog_lock();
|
||||
let catalog = crate::model_catalog::MergedCatalog::from_sources(
|
||||
let _catalog_lock = codewhale_models::model_catalog::test_catalog_lock();
|
||||
let catalog = codewhale_models::model_catalog::MergedCatalog::from_sources(
|
||||
std::collections::BTreeMap::new(),
|
||||
None,
|
||||
crate::model_catalog::bundled_catalog(),
|
||||
codewhale_models::model_catalog::bundled_catalog(),
|
||||
chrono::Utc::now(),
|
||||
);
|
||||
let _catalog = crate::model_catalog::replace_active_catalog_for_test(catalog);
|
||||
let _catalog = codewhale_models::model_catalog::replace_active_catalog_for_test(catalog);
|
||||
|
||||
for provider in [
|
||||
ApiProvider::Deepseek,
|
||||
@@ -887,7 +887,7 @@ mod tests {
|
||||
.map(|(id, max_output)| {
|
||||
(
|
||||
id.to_string(),
|
||||
crate::model_catalog::CatalogEntry {
|
||||
codewhale_models::model_catalog::CatalogEntry {
|
||||
id: id.to_string(),
|
||||
context_window: Some(128_000),
|
||||
max_output: Some(max_output),
|
||||
@@ -897,19 +897,19 @@ mod tests {
|
||||
modalities: Vec::new(),
|
||||
supported_parameters: Vec::new(),
|
||||
provider_model_id: None,
|
||||
provenance: crate::model_catalog::MetadataProvenance::UserOverride,
|
||||
provenance: codewhale_models::model_catalog::MetadataProvenance::UserOverride,
|
||||
},
|
||||
)
|
||||
})
|
||||
.into_iter()
|
||||
.collect();
|
||||
let catalog = crate::model_catalog::MergedCatalog::from_sources(
|
||||
let catalog = codewhale_models::model_catalog::MergedCatalog::from_sources(
|
||||
overrides,
|
||||
None,
|
||||
crate::model_catalog::bundled_catalog(),
|
||||
codewhale_models::model_catalog::bundled_catalog(),
|
||||
chrono::Utc::now(),
|
||||
);
|
||||
let _override = crate::model_catalog::replace_active_catalog_for_test(catalog);
|
||||
let _override = codewhale_models::model_catalog::replace_active_catalog_for_test(catalog);
|
||||
for (model, expected) in [
|
||||
("deepseek-v4.1-flash-expires-on-0910", 24_576),
|
||||
("deepseek-v4-flash", 32_768),
|
||||
|
||||
@@ -12,7 +12,7 @@ use crate::config::{
|
||||
ProviderIdentity, is_exact_direct_moonshot_k3_route, is_exact_kimi_code_bare_k3_route,
|
||||
validate_kimi_code_api_model_id,
|
||||
};
|
||||
use crate::models::DIRECT_KIMI_K3_MAX_OUTPUT_TOKENS;
|
||||
use codewhale_models::DIRECT_KIMI_K3_MAX_OUTPUT_TOKENS;
|
||||
|
||||
/// Why a route is using its effective context-window value. Keep this
|
||||
/// receipt separate from the numeric route limits so every consumer can state
|
||||
@@ -162,7 +162,7 @@ pub(crate) fn resolve_context_window(
|
||||
/// (a hint that overstates the window delays compaction past the provider's
|
||||
/// real limit).
|
||||
fn classify_capability_fallback_window(model: &str, tokens: u32) -> ContextWindowSource {
|
||||
if crate::models::name_suffix_context_window_hint(model) == Some(tokens) {
|
||||
if codewhale_models::name_suffix_context_window_hint(model) == Some(tokens) {
|
||||
ContextWindowSource::NameSuffixHint
|
||||
} else {
|
||||
ContextWindowSource::Fallback
|
||||
|
||||
@@ -65,8 +65,6 @@ use crate::fleet::profile::canonical_public_role_name;
|
||||
use crate::fleet::task_spec::FleetTaskSpecDocument;
|
||||
use crate::fleet::worker_runtime::fleet_write_roots;
|
||||
use crate::mcp::McpPool;
|
||||
#[cfg(test)]
|
||||
pub(super) use crate::models::{ContentBlock, Message};
|
||||
use crate::runtime_threads::{
|
||||
CompactThreadRequest, CreateThreadRequest, ExternalApprovalDecision,
|
||||
MAX_RUNTIME_EVENT_REPLAY_TAIL, RuntimeThreadManager, RuntimeThreadManagerConfig,
|
||||
@@ -86,6 +84,8 @@ use crate::tools::subagent::{
|
||||
AgentWorkerRecord, SharedSubAgentManager, load_persisted_agent_worker_records,
|
||||
new_shared_subagent_manager_with_timeout,
|
||||
};
|
||||
#[cfg(test)]
|
||||
pub(super) use codewhale_models::{ContentBlock, Message};
|
||||
use codewhale_protocol::fleet::{
|
||||
FleetArtifactKind, FleetEventReplay, FleetRun, FleetRunId, FleetRuntimeEvent,
|
||||
FleetRuntimeTarget, FleetSecurityPolicy, FleetTaskSpec, FleetWorkerEventPayload,
|
||||
|
||||
@@ -7,7 +7,6 @@ use axum::http::StatusCode;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::{Value, json};
|
||||
|
||||
use crate::models::{ContentBlock, Message};
|
||||
use crate::runtime_threads::{
|
||||
CreateThreadRequest, RuntimeTurnStatus, ThreadDetail, ThreadListFilter, TurnItemKind,
|
||||
TurnItemLifecycleStatus,
|
||||
@@ -18,9 +17,10 @@ use crate::session_manager::{
|
||||
};
|
||||
use crate::session_peek::{MAX_PEEK_ENTRIES, SessionPeek, build_peek};
|
||||
use crate::session_projection::{SessionQuery, SessionSortMode, SessionSummary, project_sessions};
|
||||
use codewhale_models::{ContentBlock, Message};
|
||||
|
||||
use super::{ApiError, RuntimeApiState, map_thread_err, truncate_text};
|
||||
use crate::models::Role;
|
||||
use codewhale_models::Role;
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub(super) struct SessionsResponse {
|
||||
@@ -895,13 +895,13 @@ pub(super) fn session_to_detail(session: SavedSession) -> SessionDetailResponse
|
||||
.content
|
||||
.iter()
|
||||
.map(|block| match block {
|
||||
crate::models::ContentBlock::Text { text, .. } => {
|
||||
codewhale_models::ContentBlock::Text { text, .. } => {
|
||||
json!({ "type": "text", "text": text })
|
||||
}
|
||||
crate::models::ContentBlock::Thinking { thinking, .. } => {
|
||||
codewhale_models::ContentBlock::Thinking { thinking, .. } => {
|
||||
json!({ "type": "thinking", "text": thinking })
|
||||
}
|
||||
crate::models::ContentBlock::ToolUse {
|
||||
codewhale_models::ContentBlock::ToolUse {
|
||||
id,
|
||||
name,
|
||||
input,
|
||||
@@ -913,7 +913,7 @@ pub(super) fn session_to_detail(session: SavedSession) -> SessionDetailResponse
|
||||
}
|
||||
obj
|
||||
}
|
||||
crate::models::ContentBlock::ToolResult {
|
||||
codewhale_models::ContentBlock::ToolResult {
|
||||
tool_use_id,
|
||||
content,
|
||||
is_error,
|
||||
@@ -934,22 +934,22 @@ pub(super) fn session_to_detail(session: SavedSession) -> SessionDetailResponse
|
||||
}
|
||||
obj
|
||||
}
|
||||
crate::models::ContentBlock::ServerToolUse { id, name, input } => {
|
||||
codewhale_models::ContentBlock::ServerToolUse { id, name, input } => {
|
||||
json!({ "type": "tool_use", "id": id, "name": name, "input": input })
|
||||
}
|
||||
crate::models::ContentBlock::ToolSearchToolResult {
|
||||
codewhale_models::ContentBlock::ToolSearchToolResult {
|
||||
tool_use_id,
|
||||
content,
|
||||
} => {
|
||||
json!({ "type": "tool_result", "tool_use_id": tool_use_id, "content": content })
|
||||
}
|
||||
crate::models::ContentBlock::CodeExecutionToolResult {
|
||||
codewhale_models::ContentBlock::CodeExecutionToolResult {
|
||||
tool_use_id,
|
||||
content,
|
||||
} => {
|
||||
json!({ "type": "tool_result", "tool_use_id": tool_use_id, "content": content })
|
||||
}
|
||||
crate::models::ContentBlock::ImageUrl { .. } => Value::Null,
|
||||
codewhale_models::ContentBlock::ImageUrl { .. } => Value::Null,
|
||||
})
|
||||
.collect();
|
||||
json!({
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
use super::*;
|
||||
use crate::core::events::{Event as EngineEvent, TurnOutcomeStatus};
|
||||
use crate::core::ops::Op;
|
||||
use crate::models::Role;
|
||||
use crate::models::Usage;
|
||||
use crate::runtime_threads::RuntimeEventRecord;
|
||||
use crate::test_support::{EnvVarGuard, lock_test_env};
|
||||
use anyhow::{Context, bail};
|
||||
use codewhale_models::Role;
|
||||
use codewhale_models::Usage;
|
||||
use futures_util::StreamExt;
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
@@ -271,7 +271,7 @@ impl crate::task_manager::TaskExecutor for MockExecutor {
|
||||
}
|
||||
}
|
||||
|
||||
fn saved_session_with_blocks(blocks: Vec<crate::models::ContentBlock>) -> SavedSession {
|
||||
fn saved_session_with_blocks(blocks: Vec<codewhale_models::ContentBlock>) -> SavedSession {
|
||||
SavedSession {
|
||||
schema_version: 1,
|
||||
metadata: SessionMetadata {
|
||||
@@ -296,7 +296,7 @@ fn saved_session_with_blocks(blocks: Vec<crate::models::ContentBlock>) -> SavedS
|
||||
},
|
||||
journal: None,
|
||||
leaf_id: None,
|
||||
messages: vec![crate::models::Message {
|
||||
messages: vec![codewhale_models::Message {
|
||||
role: Role::Assistant,
|
||||
content: blocks,
|
||||
}],
|
||||
@@ -366,11 +366,11 @@ fn session_detail_scenario() {
|
||||
// from session_detail_tool_use_preserves_caller_metadata
|
||||
{
|
||||
let detail = session_to_detail(saved_session_with_blocks(vec![
|
||||
crate::models::ContentBlock::ToolUse {
|
||||
codewhale_models::ContentBlock::ToolUse {
|
||||
id: "tool-1".to_string(),
|
||||
name: "task_shell_start".to_string(),
|
||||
input: json!({ "cmd": "cargo test" }),
|
||||
caller: Some(crate::models::ToolCaller {
|
||||
caller: Some(codewhale_models::ToolCaller {
|
||||
caller_type: "subagent".to_string(),
|
||||
tool_id: Some("parent-tool".to_string()),
|
||||
}),
|
||||
@@ -386,7 +386,7 @@ fn session_detail_scenario() {
|
||||
// from session_detail_tool_result_keeps_fallback_content_with_blocks
|
||||
{
|
||||
let detail = session_to_detail(saved_session_with_blocks(vec![
|
||||
crate::models::ContentBlock::ToolResult {
|
||||
codewhale_models::ContentBlock::ToolResult {
|
||||
tool_use_id: "tool-1".to_string(),
|
||||
content: "fallback text".to_string(),
|
||||
is_error: Some(false),
|
||||
@@ -5367,16 +5367,16 @@ async fn spawn_server_with_saved_sessions(
|
||||
let mut saved = crate::session_manager::create_saved_session_with_id_and_mode(
|
||||
(*id).to_string(),
|
||||
&[
|
||||
crate::models::Message {
|
||||
codewhale_models::Message {
|
||||
role: Role::User,
|
||||
content: vec![crate::models::ContentBlock::Text {
|
||||
content: vec![codewhale_models::ContentBlock::Text {
|
||||
text: format!("prompt for {title} with token=hunter2"),
|
||||
cache_control: None,
|
||||
}],
|
||||
},
|
||||
crate::models::Message {
|
||||
codewhale_models::Message {
|
||||
role: Role::Assistant,
|
||||
content: vec![crate::models::ContentBlock::Text {
|
||||
content: vec![codewhale_models::ContentBlock::Text {
|
||||
text: "acknowledged".to_string(),
|
||||
cache_control: None,
|
||||
}],
|
||||
@@ -13734,7 +13734,7 @@ fn runtime_image_named_catalog_cursor_binds_identity_endpoint_and_catalog() -> R
|
||||
|
||||
#[tokio::test]
|
||||
async fn runtime_image_saved_session_import_validates_before_creating_a_thread() -> Result<()> {
|
||||
use crate::models::{ContentBlock, ImageUrlContent};
|
||||
use codewhale_models::{ContentBlock, ImageUrlContent};
|
||||
let _env = crate::test_support::lock_test_env();
|
||||
let dir = tempfile::tempdir()?;
|
||||
let _home = crate::test_support::EnvVarGuard::set("CODEWHALE_HOME", dir.path());
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
//! restart. This module owns both the exact live envelope and the narrow,
|
||||
//! idempotent restore projection so creation and recognition cannot drift.
|
||||
|
||||
use crate::models::Role;
|
||||
use crate::models::{ContentBlock, Message};
|
||||
use crate::safe_label::SafeLabel;
|
||||
use crate::tools::subagent::{AgentWorkerStatus, SubAgentResult, SubAgentStatus};
|
||||
use codewhale_models::Role;
|
||||
use codewhale_models::{ContentBlock, Message};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
const COMPLETION_EVENT_PREFIX: &str = concat!(
|
||||
@@ -1448,7 +1448,7 @@ mod tests {
|
||||
let image_only = Message {
|
||||
role: Role::User,
|
||||
content: vec![ContentBlock::ImageUrl {
|
||||
image_url: crate::models::ImageUrlContent {
|
||||
image_url: codewhale_models::ImageUrlContent {
|
||||
url: "data:image/png;base64,AAAA".to_string(),
|
||||
},
|
||||
}],
|
||||
|
||||
@@ -40,8 +40,6 @@ use crate::cost_status::{
|
||||
EffectiveRouteEnvelope, EffectiveRouteUsage, RouteBillingMode, RuntimeUsageDropRecord,
|
||||
RuntimeUsageRecord,
|
||||
};
|
||||
use crate::models::Role;
|
||||
use crate::models::{ContentBlock, Message, SystemPrompt, Usage};
|
||||
use crate::provider_catalog_live::ProviderLivePricingQuote;
|
||||
use crate::route_budget::{
|
||||
auto_compact_default_for_route, compaction_threshold_for_route_at_percent, known_route_limits,
|
||||
@@ -57,6 +55,8 @@ use crate::tools::todo::new_shared_todo_list;
|
||||
#[cfg(test)]
|
||||
use codewhale_config::AppMode;
|
||||
use codewhale_execpolicy::ApprovalMode;
|
||||
use codewhale_models::Role;
|
||||
use codewhale_models::{ContentBlock, Message, SystemPrompt, Usage};
|
||||
use codewhale_protocol::agent_mail::{
|
||||
AGENT_MAIL_EVENT_DELIVERED, AGENT_MAIL_EVENT_DELIVERING, AGENT_MAIL_EVENT_DELIVERY_FAILED,
|
||||
AGENT_MAIL_EVENT_QUEUED, AGENT_MAIL_EVENT_READ, AGENT_MAIL_SCHEMA_VERSION, AgentMailAddress,
|
||||
|
||||
@@ -426,7 +426,7 @@ mod recovery {
|
||||
let response = |text: &str, stop: &str| {
|
||||
let mut events = canned::simple_text_turn(text);
|
||||
for event in &mut events {
|
||||
if let crate::models::StreamEvent::MessageDelta { delta, usage } = event {
|
||||
if let codewhale_models::StreamEvent::MessageDelta { delta, usage } = event {
|
||||
delta.stop_reason = Some(stop.into());
|
||||
*usage = Some(Usage {
|
||||
input_tokens: 11,
|
||||
@@ -7584,7 +7584,7 @@ async fn monitor_separates_lifecycle_start_from_billing_dispatch_and_child_usage
|
||||
input_tokens: 10,
|
||||
output_tokens: 4,
|
||||
reasoning_replay_tokens: Some(6),
|
||||
server_tool_use: Some(crate::models::ServerToolUsage {
|
||||
server_tool_use: Some(codewhale_models::ServerToolUsage {
|
||||
code_execution_requests: Some(2),
|
||||
tool_search_requests: Some(3),
|
||||
}),
|
||||
@@ -7594,7 +7594,7 @@ async fn monitor_separates_lifecycle_start_from_billing_dispatch_and_child_usage
|
||||
input_tokens: 10,
|
||||
output_tokens: 4,
|
||||
reasoning_replay_tokens: Some(6),
|
||||
server_tool_use: Some(crate::models::ServerToolUsage {
|
||||
server_tool_use: Some(codewhale_models::ServerToolUsage {
|
||||
code_execution_requests: Some(2),
|
||||
tool_search_requests: Some(3),
|
||||
}),
|
||||
@@ -7640,7 +7640,7 @@ async fn monitor_separates_lifecycle_start_from_billing_dispatch_and_child_usage
|
||||
assert_eq!(persisted_usage.reasoning_replay_tokens, Some(6));
|
||||
assert_eq!(
|
||||
persisted_usage.server_tool_use,
|
||||
Some(crate::models::ServerToolUsage {
|
||||
Some(codewhale_models::ServerToolUsage {
|
||||
code_execution_requests: Some(2),
|
||||
tool_search_requests: Some(3),
|
||||
})
|
||||
|
||||
@@ -161,7 +161,7 @@ fn catalog_model_identifier_is_allowlisted(value: &str) -> bool {
|
||||
{
|
||||
return false;
|
||||
}
|
||||
crate::model_catalog::resolved_entry(value)
|
||||
codewhale_models::model_catalog::resolved_entry(value)
|
||||
.is_some_and(|entry| entry.id == value || entry.provider_model_id.as_deref() == Some(value))
|
||||
}
|
||||
|
||||
@@ -442,7 +442,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn generic_identifiers_reject_all_slashes_and_catalog_models_require_exact_ids() {
|
||||
let _catalog_guard = crate::model_catalog::test_catalog_lock();
|
||||
let _catalog_guard = codewhale_models::model_catalog::test_catalog_lock();
|
||||
for path in [
|
||||
"src/lib.rs",
|
||||
"docs/PREVIEW_REQUEST.md",
|
||||
|
||||
@@ -17,10 +17,10 @@ use serde::{Deserialize, Serialize};
|
||||
use crate::config::ApiProvider;
|
||||
#[cfg(test)]
|
||||
use crate::config::{DEEPSEEK_ALIAS_REPLACEMENT, DEEPSEEK_ALIAS_RETIREMENT_UTC};
|
||||
use crate::models::Usage;
|
||||
use crate::pricing::{
|
||||
CostEstimate, TurnCostAudit, audit_turn_cost_for_route_at, token_usage_for_pricing,
|
||||
};
|
||||
use codewhale_models::Usage;
|
||||
|
||||
/// One turn's normalized token economics.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
|
||||
@@ -15,14 +15,14 @@
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use crate::models::Role;
|
||||
use crate::models::{ContentBlock, Message};
|
||||
use crate::session_manager::{
|
||||
SavedSession, SessionListFilter, SessionManager, SessionMutator,
|
||||
create_saved_session_with_id_and_mode,
|
||||
};
|
||||
use crate::session_projection::{SessionQuery, SessionSortMode, project_sessions};
|
||||
use crate::session_resume::{AutoResumeDecision, ResumeRequest, decide_auto_resume};
|
||||
use codewhale_models::Role;
|
||||
use codewhale_models::{ContentBlock, Message};
|
||||
|
||||
/// Which issue's acceptance list a row comes from.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
|
||||
@@ -10,7 +10,6 @@ use crate::approval_log::{ApprovalReceipt, ApprovalReceiptStore, ApprovalReplay}
|
||||
use crate::artifacts::ArtifactRecord;
|
||||
use crate::config::ApiProvider;
|
||||
use crate::model_routing::AutoRouteReceipt;
|
||||
use crate::models::{ContentBlock, Message, SystemPrompt};
|
||||
use crate::project_context::find_git_root;
|
||||
use crate::session_tree::{SessionEntry, SessionImportContainer, SessionJournal};
|
||||
use crate::tools::goal::{GoalPauseReason, GoalSnapshot};
|
||||
@@ -22,6 +21,7 @@ use chrono::{DateTime, Utc};
|
||||
use codewhale_core::ContextReference;
|
||||
#[cfg(test)]
|
||||
use codewhale_core::{ContextReferenceKind, ContextReferenceSource};
|
||||
use codewhale_models::{ContentBlock, Message, SystemPrompt};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
use std::fs::{self, OpenOptions};
|
||||
@@ -60,7 +60,7 @@ struct LateUsageRecord {
|
||||
turn_fingerprint: String,
|
||||
route: crate::cost_status::EffectiveRouteEnvelope,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
usage: Option<crate::models::Usage>,
|
||||
usage: Option<codewhale_models::Usage>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
@@ -1451,7 +1451,7 @@ impl SessionManager {
|
||||
turn_id: &str,
|
||||
source_id: &str,
|
||||
route: &crate::cost_status::EffectiveRouteEnvelope,
|
||||
usage: Option<&crate::models::Usage>,
|
||||
usage: Option<&codewhale_models::Usage>,
|
||||
) -> io::Result<bool> {
|
||||
let (path, lock_path) = self.ensure_late_usage_paths(session_id)?;
|
||||
let lock_file = open_private_lock_file(&lock_path)?;
|
||||
@@ -3359,10 +3359,10 @@ fn format_age(dt: &DateTime<Utc>) -> String {
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::approval_log::ApprovalOutcome;
|
||||
use crate::models::ContentBlock;
|
||||
use crate::models::Role;
|
||||
use crate::tools::plan::StepStatus;
|
||||
use crate::tui::history::{HistoryCell, ToolCell, history_cells_from_message};
|
||||
use codewhale_models::ContentBlock;
|
||||
use codewhale_models::Role;
|
||||
use std::fs;
|
||||
use tempfile::tempdir;
|
||||
|
||||
@@ -3402,7 +3402,7 @@ mod tests {
|
||||
Some(crate::config::DEFAULT_DEEPSEEK_BASE_URL),
|
||||
Utc::now(),
|
||||
),
|
||||
usage: crate::models::Usage {
|
||||
usage: codewhale_models::Usage {
|
||||
input_tokens: 1,
|
||||
..Default::default()
|
||||
},
|
||||
@@ -4028,10 +4028,10 @@ mod tests {
|
||||
Some(crate::config::DEFAULT_DEEPSEEK_BASE_URL),
|
||||
Utc::now(),
|
||||
);
|
||||
let usage = crate::models::Usage {
|
||||
let usage = codewhale_models::Usage {
|
||||
input_tokens: 17,
|
||||
output_tokens: 5,
|
||||
..crate::models::Usage::default()
|
||||
..codewhale_models::Usage::default()
|
||||
};
|
||||
let usage_record = crate::cost_status::RuntimeUsageRecord {
|
||||
source_id: "translation:old-turn:assistant:1".to_string(),
|
||||
@@ -4165,9 +4165,9 @@ mod tests {
|
||||
source_id: format!("late-bounded:{index}"),
|
||||
usage: crate::cost_status::EffectiveRouteUsage {
|
||||
route: route.clone(),
|
||||
usage: crate::models::Usage {
|
||||
usage: codewhale_models::Usage {
|
||||
input_tokens: 1,
|
||||
..crate::models::Usage::default()
|
||||
..codewhale_models::Usage::default()
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -4218,9 +4218,9 @@ mod tests {
|
||||
source_id: "linked-sidecar-response".to_string(),
|
||||
usage: crate::cost_status::EffectiveRouteUsage {
|
||||
route,
|
||||
usage: crate::models::Usage {
|
||||
usage: codewhale_models::Usage {
|
||||
input_tokens: 1,
|
||||
..crate::models::Usage::default()
|
||||
..codewhale_models::Usage::default()
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -5135,7 +5135,7 @@ mod tests {
|
||||
);
|
||||
assert!(loaded.messages.iter().any(|message| {
|
||||
(message.role == "assistant"
|
||||
|| message.role == crate::models::INTERRUPTED_ASSISTANT_ROLE)
|
||||
|| message.role == codewhale_models::INTERRUPTED_ASSISTANT_ROLE)
|
||||
&& message.content.iter().any(|block| {
|
||||
matches!(
|
||||
block,
|
||||
@@ -5983,7 +5983,7 @@ mod tests {
|
||||
let mut first = Message {
|
||||
role: Role::User,
|
||||
content: vec![ContentBlock::ImageUrl {
|
||||
image_url: crate::models::ImageUrlContent {
|
||||
image_url: codewhale_models::ImageUrlContent {
|
||||
url: "data:image/png;base64,AAAA".to_string(),
|
||||
},
|
||||
}],
|
||||
|
||||
@@ -22,8 +22,8 @@
|
||||
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::models::ContentBlock;
|
||||
use crate::session_manager::SavedSession;
|
||||
use codewhale_models::ContentBlock;
|
||||
|
||||
/// Most entries a peek carries. The dashboard shows a tail, so this is "the
|
||||
/// last N exchanges", which is what a peek is for.
|
||||
@@ -299,9 +299,9 @@ fn mask_assignment(token: &str) -> Option<String> {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::models::Message;
|
||||
use crate::models::Role;
|
||||
use crate::session_manager::create_saved_session_with_id_and_mode;
|
||||
use codewhale_models::Message;
|
||||
use codewhale_models::Role;
|
||||
|
||||
fn text_block(text: &str) -> ContentBlock {
|
||||
ContentBlock::Text {
|
||||
@@ -571,7 +571,7 @@ mod tests {
|
||||
text_block(envelope),
|
||||
text_block("<image path=\"/tmp/shot.png\">"),
|
||||
ContentBlock::ImageUrl {
|
||||
image_url: crate::models::ImageUrlContent {
|
||||
image_url: codewhale_models::ImageUrlContent {
|
||||
url: "data:image/png;base64,iVBORw0KGgo=".to_string(),
|
||||
},
|
||||
},
|
||||
|
||||
Loaded 100 of 151 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user