Skip to content

Commit e2a3310

Browse files
committed
refactor(core): move stable AI DTOs into core types
1 parent a8758bc commit e2a3310

24 files changed

Lines changed: 443 additions & 254 deletions

File tree

docs/plans/core-decomposition-completed.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
- execution 下 tool 相关目录已按职责命名:`tool-contracts``tool-provider-groups``tool-execution`。Cargo package / lib 名保持兼容。
4949
- `agent-stream` 已成为统一 stream DTO、tool-call 累积和 replay 契约 owner;provider stream 解析测试归属 `ai-adapters`
5050
- AGENTS、README、DeepReview path classifier、core boundary rules 和 Cargo workspace path 已同步到当前分层。
51+
- `bitfun-core --no-default-features` 已裁掉 workspace-search owner、debug ingest HTTP server、AI provider adapter runtime 和 `reqwest` direct dependency;workspace search 旧路径、debug ingest、CLI credential acquisition 和 AI client runtime 只在显式 product feature 下组装,边界脚本覆盖关键 feature gate。
5152

5253
## 2. 已建立的保护
5354

@@ -67,4 +68,4 @@
6768
- 产品入口仍主要通过 `bitfun-core/product-full` 获取完整能力;Product Assembly 已可表达当前完整能力集合,但尚未真正按交付形态裁剪 default feature / dependency。
6869
- concrete session manager、scheduler lifecycle、event delivery、permission UI/channel wait、prompt assembly、session persistence IO、AI client factory / provider acquisition 仍在 core。
6970
- Bash tool orchestration 的可复用 shell helper、本地 indexed workspace search owner、remote workspace search concrete owner、remote SSH/SFTP/PTY concrete owner、tool confirmation/checkpoint 纯策略、tool pipeline batching/retry policy、DeepReview provider-neutral policy/report/cache/task-execution shaping、DeepResearch citation renumber 纯重排 / report IO、MiniApp host dispatch、MiniApp built-in seed/marker IO、MiniApp JS worker process/pool lifecycle、MiniApp storage filesystem IO、MiniApp import bundle IO 和 prompt environment facts 已迁出;permission UI/channel side effect、tool pipeline concrete state/cancellation/scheduler glue、DeepReview concrete launch/provider wait/report persistence、MiniApp manager concrete workflow execution 仍未完成 owner 迁移。
70-
- no-default 与 product-full 的依赖边界已有数据基线, no-default 仍包含较大 concrete 依赖;不能声称各交付形态已达到最小依赖。
71+
- no-default 与 product-full 的依赖边界已有数据基线, no-default 已不再携带 workspace-search owner、debug ingest HTTP server、AI provider adapter runtime 或 `reqwest` direct dependency;remote-ssh 基础 workspace identity 仍是兼容期依赖,不能声称各交付形态已达到最小依赖。

docs/plans/core-decomposition-plan.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
- 物理目录已按六层展开,旧 `surfaces``providers` 层级不再作为目标层级存在。
2222
- Cargo package / lib 名保持兼容;例如 `tool-contracts` 仍发布为 `bitfun-agent-tools``tool-provider-groups` 仍发布为 `bitfun-tool-packs``tool-execution` 仍发布为 `tool-runtime`
2323
- Desktop / CLI / ACP 仍通过 `bitfun-core/product-full` 获取完整能力;Server / Web / Mobile Web 不直接依赖 core,但尚未完成按交付形态裁剪最小 feature / dependency。
24+
- `bitfun-core --no-default-features` 已不再携带 workspace-search owner、debug ingest HTTP server、AI provider adapter runtime 或 `reqwest` direct dependency;workspace search 旧路径、debug ingest、CLI credential acquisition 和 AI client runtime 只在显式 product feature 下组装。remote-ssh 基础 workspace identity 仍作为兼容期依赖保留,后续若要继续裁剪必须先完成 session / workspace identity 接口迁移。
2425
- `runtime-services` 已有 typed builder、capability availability 和 core product runtime provider adapter,但不少 concrete provider 仍在 core 创建或持有。
2526
- remote-connect command routing、wire response assembly、workspace/session/poll/file/dialog/cancel/interaction helper 和 state tracker contract 已归入 `services-integrations`;core 保留 host adapter、加密入口和全局 tracker 接线。
2627
- `tool-contracts` 已承接 provider-neutral tool manifest、admission、catalog、result policy、tool execution presentation 和截断恢复提示等纯策略;`tool-execution` 已承接低层 IO/search helper、Bash shell 可复用策略、结果渲染、tool pipeline batching plan 与 retry policy;`services-integrations` 已承接本地 indexed workspace search service owner、crate-private flashgrep protocol internals、remote SSH search 纯策略、remote workspace search concrete owner、remote SSH/SFTP/PTY concrete owner、DeepResearch report IO、MiniApp host dispatch、built-in seed/marker IO、MiniApp JS worker process/pool owner、MiniApp storage filesystem IO 和 MiniApp import bundle IO;`agent-runtime` 已承接 tool confirmation plan/failure/wait-result、light checkpoint summary policy、prompt environment facts、DeepReview task-execution provider-neutral shaping 和 DeepResearch citation renumber 纯重排。permission UI channel side effect、tool pipeline concrete state/cancellation/scheduler glue、DeepReview concrete launch/provider wait/report persistence 和完整 execution pipeline owner 仍未完全迁移。

scripts/core-boundaries/rules/feature-rules.mjs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ export const optionalDependencyFeatureOwnerRules = [
88
dependencies: [
99
{ depName: 'aes', ownerFeatures: ['service-integrations'] },
1010
{ depName: 'aes-gcm', ownerFeatures: ['service-integrations'] },
11+
{ depName: 'axum', ownerFeatures: ['service-integrations'] },
12+
{ depName: 'bitfun-ai-adapters', ownerFeatures: ['ai-adapter-runtime'] },
1113
{ depName: 'bitfun-product-capabilities', ownerFeatures: ['product-capabilities'] },
1214
{ depName: 'bitfun-product-domains', ownerFeatures: ['product-domains'] },
1315
{ depName: 'bitfun-relay-server', ownerFeatures: ['service-integrations'] },
@@ -31,11 +33,13 @@ export const optionalDependencyFeatureOwnerRules = [
3133
{ depName: 'md5', ownerFeatures: ['product-full', 'service-integrations'] },
3234
{ depName: 'qrcode', ownerFeatures: ['service-integrations'] },
3335
{ depName: 'rand', ownerFeatures: ['service-integrations'] },
36+
{ depName: 'reqwest', ownerFeatures: ['ai-adapter-runtime', 'service-integrations'] },
3437
{ depName: 'rmcp', ownerFeatures: ['service-integrations'] },
3538
{ depName: 'russh', ownerFeatures: ['ssh-remote'] },
3639
{ depName: 'similar', ownerFeatures: ['product-full'] },
3740
{ depName: 'sse-stream', ownerFeatures: ['service-integrations'] },
3841
{ depName: 'tokio-tungstenite', ownerFeatures: ['service-integrations'] },
42+
{ depName: 'tower-http', ownerFeatures: ['service-integrations'] },
3943
{ depName: 'tool-runtime', ownerFeatures: ['product-full'] },
4044
{ depName: 'x25519-dalek', ownerFeatures: ['service-integrations'] },
4145
],

scripts/core-boundaries/rules/source/forbidden-rules.mjs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,21 @@
11
// Boundary rules for source ownership, facades, and required owner content.
22

33
export const forbiddenContentRules = [
4+
{
5+
path: 'src/crates/contracts/core-types/src/ai.rs',
6+
patterns: [
7+
{
8+
regex: /\bresolve_request_url\b/,
9+
message:
10+
'core-types may own AI DTOs, but provider URL resolution belongs in adapter or assembly compatibility owners',
11+
},
12+
{
13+
regex: /\b(?:chat\/completions|v1\/messages|streamGenerateContent)\b/,
14+
message:
15+
'core-types must not encode provider endpoint paths; keep protocol URL behavior above contracts',
16+
},
17+
],
18+
},
419
{
520
path: 'src/crates/assembly/core/src/product_assembly.rs',
621
patterns: [

scripts/core-boundaries/rules/source/required-rules.mjs

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1630,9 +1630,26 @@ export const requiredContentRules = [
16301630
},
16311631
{
16321632
regex:
1633-
/bitfun-services-integrations = \{ path = "\.\.\/\.\.\/services\/services-integrations", default-features = false, features = \["remote-ssh", "workspace-search"\] \}/,
1633+
/bitfun-services-integrations = \{ path = "\.\.\/\.\.\/services\/services-integrations", default-features = false, features = \["remote-ssh"\] \}/,
16341634
message:
1635-
'bitfun-services-integrations dependency may keep remote workspace identity and workspace-search owner helpers but must not force product-full outside the core feature graph',
1635+
'bitfun-services-integrations dependency may keep remote workspace identity but must not force workspace-search or product-full outside the core feature graph',
1636+
},
1637+
{
1638+
regex:
1639+
/bitfun-ai-adapters = \{ path = "\.\.\/\.\.\/adapters\/ai-adapters", optional = true \}/,
1640+
message: 'bitfun-ai-adapters dependency must stay optional for no-default core builds',
1641+
},
1642+
{
1643+
regex: /"dep:bitfun-ai-adapters"/,
1644+
message: 'core ai-adapter-runtime feature must explicitly enable the optional dependency',
1645+
},
1646+
{
1647+
regex: /product-full = \[[^\]]*"ai-adapter-runtime"[^\]]*\]/,
1648+
message: 'core product-full assembly must explicitly opt into AI adapter runtime',
1649+
},
1650+
{
1651+
regex: /product-domains = \[[^\]]*"ai-adapter-runtime"[^\]]*\]/,
1652+
message: 'core product-domain facade must explicitly opt into AI adapter runtime while concrete AI adapters remain optional',
16361653
},
16371654
{
16381655
regex:
@@ -1696,6 +1713,38 @@ export const requiredContentRules = [
16961713
},
16971714
],
16981715
},
1716+
{
1717+
path: 'src/crates/assembly/core/src/infrastructure/mod.rs',
1718+
reason: 'concrete AI adapter runtime and debug ingest HTTP server must stay out of no-default core builds',
1719+
patterns: [
1720+
{
1721+
regex: /#\[cfg\(feature = "ai-adapter-runtime"\)\]\s*pub mod ai\b/s,
1722+
message: 'AI client runtime must stay behind ai-adapter-runtime',
1723+
},
1724+
{
1725+
regex: /#\[cfg\(feature = "ai-adapter-runtime"\)\]\s*pub mod cli_credentials\b/s,
1726+
message: 'AI CLI credential runtime must stay behind ai-adapter-runtime',
1727+
},
1728+
{
1729+
regex: /#\[cfg\(feature = "product-full"\)\]\s*pub mod debug_log\b/s,
1730+
message: 'debug ingest HTTP server must stay behind product-full',
1731+
},
1732+
],
1733+
},
1734+
{
1735+
path: 'src/crates/assembly/core/src/util/types/ai.rs',
1736+
reason: 'legacy AI implementation DTO re-exports must not force AI adapters into no-default core builds',
1737+
patterns: [
1738+
{
1739+
regex: /pub use bitfun_core_types::\{ConnectionTestMessageCode, ConnectionTestResult, RemoteModelInfo\};/s,
1740+
message: 'stable AI DTOs must be re-exported from core-types',
1741+
},
1742+
{
1743+
regex: /#\[cfg\(feature = "ai-adapter-runtime"\)\]\s*pub use bitfun_ai_adapters::types::\{GeminiResponse, GeminiUsage\};/s,
1744+
message: 'legacy Gemini implementation DTOs must stay behind ai-adapter-runtime',
1745+
},
1746+
],
1747+
},
16991748
{
17001749
path: 'src/crates/assembly/core/src/service/mod.rs',
17011750
reason:
@@ -1717,6 +1766,14 @@ export const requiredContentRules = [
17171766
regex: /#\[cfg\(feature = "service-integrations"\)\]\s*pub mod review_platform\b/s,
17181767
message: 'review platform facade must stay behind service-integrations',
17191768
},
1769+
{
1770+
regex: /#\[cfg\(feature = "product-full"\)\]\s*pub mod search\b/s,
1771+
message: 'workspace search facade must stay behind product-full',
1772+
},
1773+
{
1774+
regex: /#\[cfg\(feature = "product-full"\)\]\s*pub use search::/s,
1775+
message: 'workspace search exports must stay behind product-full',
1776+
},
17201777
{
17211778
regex: /#\[cfg\(feature = "product-full"\)\]\s*pub mod snapshot\b/s,
17221779
message: 'snapshot service must stay behind product-full until tool-runtime ownership is split',

scripts/core-boundaries/self-test.mjs

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,14 @@ export function runManifestParserSelfTest({
549549
if (!coreTypesProfile?.forbiddenNonOptionalDeps.includes('bitfun-ai-adapters')) {
550550
throw new Error('core-types dependency profile must forbid ai-adapter dependencies');
551551
}
552+
const coreTypesAiRuleText = forbiddenRuleTextForPath(
553+
'src/crates/contracts/core-types/src/ai.rs',
554+
);
555+
for (const contract of ['resolve_request_url', 'chat\\/completions', 'v1\\/messages']) {
556+
if (!coreTypesAiRuleText.includes(contract)) {
557+
throw new Error(`core-types AI DTO boundary rule must forbid: ${contract}`);
558+
}
559+
}
552560
const runtimePortsProfile = dependencyProfileRules.find(
553561
(rule) => rule.crateName === 'runtime-ports',
554562
);
@@ -1800,9 +1808,12 @@ export function runManifestParserSelfTest({
18001808
path: 'src/crates/assembly/core/Cargo.toml',
18011809
contracts: [
18021810
'bitfun-product-capabilities = \\{ path = "\\.\\.\\/product-capabilities", default-features = false, optional = true \\}',
1811+
'bitfun-ai-adapters = \\{ path = "\\.\\.\\/\\.\\.\\/adapters\\/ai-adapters", optional = true \\}',
18031812
'bitfun-tool-packs = \\{ path = "\\.\\.\\/\\.\\.\\/execution\\/tool-provider-groups", default-features = false, optional = true \\}',
1804-
'bitfun-services-integrations = \\{ path = "\\.\\.\\/\\.\\.\\/services\\/services-integrations", default-features = false, features = \\["remote-ssh", "workspace-search"\\] \\}',
1813+
'bitfun-services-integrations = \\{ path = "\\.\\.\\/\\.\\.\\/services\\/services-integrations", default-features = false, features = \\["remote-ssh"\\] \\}',
18051814
'bitfun-product-domains = \\{ path = "\\.\\.\\/\\.\\.\\/contracts\\/product-domains", default-features = false, optional = true \\}',
1815+
'dep:bitfun-ai-adapters',
1816+
'ai-adapter-runtime',
18061817
'dep:bitfun-product-capabilities',
18071818
'dep:bitfun-tool-packs',
18081819
'bitfun-tool-packs\\/product-full',
@@ -1823,6 +1834,25 @@ export function runManifestParserSelfTest({
18231834
'service_agent_runtime',
18241835
],
18251836
},
1837+
{
1838+
path: 'src/crates/assembly/core/src/infrastructure/mod.rs',
1839+
contracts: [
1840+
'feature = "ai-adapter-runtime"',
1841+
'pub mod ai',
1842+
'pub mod cli_credentials',
1843+
'feature = "product-full"',
1844+
'pub mod debug_log',
1845+
],
1846+
},
1847+
{
1848+
path: 'src/crates/assembly/core/src/util/types/ai.rs',
1849+
contracts: [
1850+
'bitfun_core_types',
1851+
'feature = "ai-adapter-runtime"',
1852+
'GeminiResponse',
1853+
'GeminiUsage',
1854+
],
1855+
},
18261856
{
18271857
path: 'src/crates/assembly/core/src/service/mod.rs',
18281858
contracts: [
@@ -1832,6 +1862,7 @@ export function runManifestParserSelfTest({
18321862
'pub mod remote_connect',
18331863
'pub mod review_platform',
18341864
'feature = "product-full"',
1865+
'pub mod search',
18351866
'pub mod snapshot',
18361867
],
18371868
},

src/crates/adapters/ai-adapters/src/types/ai.rs

Lines changed: 2 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use serde::{Deserialize, Serialize};
22
use serde_json::Value;
33

4+
pub use bitfun_core_types::{ConnectionTestMessageCode, ConnectionTestResult, RemoteModelInfo};
5+
46
/// Gemini API response
57
#[derive(Debug, Clone, Serialize, Deserialize)]
68
pub struct GeminiResponse {
@@ -63,42 +65,6 @@ impl From<GeminiUsage> for bitfun_agent_stream::UnifiedTokenUsage {
6365
}
6466
}
6567

66-
/// Structured message codes for localized connection test messaging.
67-
#[derive(Debug, Clone, Serialize, Deserialize)]
68-
#[serde(rename_all = "snake_case")]
69-
pub enum ConnectionTestMessageCode {
70-
ToolCallsNotDetected,
71-
ImageInputCheckFailed,
72-
}
73-
74-
/// AI connection test result
75-
#[derive(Debug, Clone, Serialize, Deserialize)]
76-
pub struct ConnectionTestResult {
77-
/// Whether the test succeeded
78-
pub success: bool,
79-
/// Response time (ms)
80-
pub response_time_ms: u64,
81-
/// Model response content (if successful)
82-
#[serde(skip_serializing_if = "Option::is_none")]
83-
pub model_response: Option<String>,
84-
/// Structured message code for localized frontend messaging
85-
#[serde(skip_serializing_if = "Option::is_none")]
86-
pub message_code: Option<ConnectionTestMessageCode>,
87-
/// Raw error or diagnostic details
88-
#[serde(skip_serializing_if = "Option::is_none")]
89-
pub error_details: Option<String>,
90-
}
91-
92-
/// Remote model info discovered from a provider API.
93-
#[derive(Debug, Clone, Serialize, Deserialize)]
94-
pub struct RemoteModelInfo {
95-
/// Provider model identifier (used as the actual model_name).
96-
pub id: String,
97-
/// Optional human-readable display name returned by the provider.
98-
#[serde(skip_serializing_if = "Option::is_none")]
99-
pub display_name: Option<String>,
100-
}
101-
10268
#[cfg(test)]
10369
mod tests {
10470
use super::GeminiUsage;

src/crates/adapters/ai-adapters/src/types/config.rs

Lines changed: 1 addition & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use serde::{Deserialize, Serialize};
1+
pub use bitfun_core_types::{AIConfig, ProxyConfig, ReasoningMode};
22

33
fn append_endpoint(base_url: &str, endpoint: &str) -> String {
44
let base = base_url.trim();
@@ -63,49 +63,6 @@ pub fn resolve_request_url(base_url: &str, provider: &str, model_name: &str) ->
6363
}
6464
}
6565

66-
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Default)]
67-
#[serde(rename_all = "snake_case")]
68-
pub enum ReasoningMode {
69-
#[default]
70-
Default,
71-
Enabled,
72-
Disabled,
73-
Adaptive,
74-
}
75-
76-
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
77-
#[serde(default)]
78-
pub struct ProxyConfig {
79-
pub enabled: bool,
80-
pub url: String,
81-
pub username: Option<String>,
82-
pub password: Option<String>,
83-
}
84-
85-
/// AI client configuration shared across runtime contexts.
86-
#[derive(Debug, Clone, Serialize, Deserialize)]
87-
pub struct AIConfig {
88-
pub name: String,
89-
pub base_url: String,
90-
pub request_url: String,
91-
pub api_key: String,
92-
pub model: String,
93-
pub format: String,
94-
pub context_window: u32,
95-
pub max_tokens: Option<u32>,
96-
pub temperature: Option<f64>,
97-
pub top_p: Option<f64>,
98-
pub reasoning_mode: ReasoningMode,
99-
pub inline_think_in_text: bool,
100-
pub custom_headers: Option<std::collections::HashMap<String, String>>,
101-
pub custom_headers_mode: Option<String>,
102-
pub skip_ssl_verify: bool,
103-
pub reasoning_effort: Option<String>,
104-
pub thinking_budget_tokens: Option<u32>,
105-
pub custom_request_body: Option<serde_json::Value>,
106-
pub custom_request_body_mode: Option<String>,
107-
}
108-
10966
#[cfg(test)]
11067
mod tests {
11168
use super::resolve_request_url;

0 commit comments

Comments
 (0)