Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion docs/plans/core-decomposition-completed.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
- execution 下 tool 相关目录已按职责命名:`tool-contracts`、`tool-provider-groups`、`tool-execution`。Cargo package / lib 名保持兼容。
- `agent-stream` 已成为统一 stream DTO、tool-call 累积和 replay 契约 owner;provider stream 解析测试归属 `ai-adapters`。
- AGENTS、README、DeepReview path classifier、core boundary rules 和 Cargo workspace path 已同步到当前分层。
- `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。

## 2. 已建立的保护

Expand All @@ -67,4 +68,4 @@
- 产品入口仍主要通过 `bitfun-core/product-full` 获取完整能力;Product Assembly 已可表达当前完整能力集合,但尚未真正按交付形态裁剪 default feature / dependency。
- concrete session manager、scheduler lifecycle、event delivery、permission UI/channel wait、prompt assembly、session persistence IO、AI client factory / provider acquisition 仍在 core。
- 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 迁移。
- no-default 与 product-full 的依赖边界已有数据基线, no-default 仍包含较大 concrete 依赖;不能声称各交付形态已达到最小依赖。
- no-default 与 product-full 的依赖边界已有数据基线, no-default 已不再携带 workspace-search owner、debug ingest HTTP server、AI provider adapter runtime 或 `reqwest` direct dependency;remote-ssh 基础 workspace identity 仍是兼容期依赖,不能声称各交付形态已达到最小依赖。
1 change: 1 addition & 0 deletions docs/plans/core-decomposition-plan.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
- 物理目录已按六层展开,旧 `surfaces` 和 `providers` 层级不再作为目标层级存在。
- Cargo package / lib 名保持兼容;例如 `tool-contracts` 仍发布为 `bitfun-agent-tools`,`tool-provider-groups` 仍发布为 `bitfun-tool-packs`,`tool-execution` 仍发布为 `tool-runtime`。
- Desktop / CLI / ACP 仍通过 `bitfun-core/product-full` 获取完整能力;Server / Web / Mobile Web 不直接依赖 core,但尚未完成按交付形态裁剪最小 feature / dependency。
- `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 接口迁移。
- `runtime-services` 已有 typed builder、capability availability 和 core product runtime provider adapter,但不少 concrete provider 仍在 core 创建或持有。
- remote-connect command routing、wire response assembly、workspace/session/poll/file/dialog/cancel/interaction helper 和 state tracker contract 已归入 `services-integrations`;core 保留 host adapter、加密入口和全局 tracker 接线。
- `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 仍未完全迁移。
Expand Down
4 changes: 4 additions & 0 deletions scripts/core-boundaries/rules/feature-rules.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ export const optionalDependencyFeatureOwnerRules = [
dependencies: [
{ depName: 'aes', ownerFeatures: ['service-integrations'] },
{ depName: 'aes-gcm', ownerFeatures: ['service-integrations'] },
{ depName: 'axum', ownerFeatures: ['service-integrations'] },
{ depName: 'bitfun-ai-adapters', ownerFeatures: ['ai-adapter-runtime'] },
{ depName: 'bitfun-product-capabilities', ownerFeatures: ['product-capabilities'] },
{ depName: 'bitfun-product-domains', ownerFeatures: ['product-domains'] },
{ depName: 'bitfun-relay-server', ownerFeatures: ['service-integrations'] },
Expand All @@ -31,11 +33,13 @@ export const optionalDependencyFeatureOwnerRules = [
{ depName: 'md5', ownerFeatures: ['product-full', 'service-integrations'] },
{ depName: 'qrcode', ownerFeatures: ['service-integrations'] },
{ depName: 'rand', ownerFeatures: ['service-integrations'] },
{ depName: 'reqwest', ownerFeatures: ['ai-adapter-runtime', 'service-integrations'] },
{ depName: 'rmcp', ownerFeatures: ['service-integrations'] },
{ depName: 'russh', ownerFeatures: ['ssh-remote'] },
{ depName: 'similar', ownerFeatures: ['product-full'] },
{ depName: 'sse-stream', ownerFeatures: ['service-integrations'] },
{ depName: 'tokio-tungstenite', ownerFeatures: ['service-integrations'] },
{ depName: 'tower-http', ownerFeatures: ['service-integrations'] },
{ depName: 'tool-runtime', ownerFeatures: ['product-full'] },
{ depName: 'x25519-dalek', ownerFeatures: ['service-integrations'] },
],
Expand Down
15 changes: 15 additions & 0 deletions scripts/core-boundaries/rules/source/forbidden-rules.mjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,21 @@
// Boundary rules for source ownership, facades, and required owner content.

export const forbiddenContentRules = [
{
path: 'src/crates/contracts/core-types/src/ai.rs',
patterns: [
{
regex: /\bresolve_request_url\b/,
message:
'core-types may own AI DTOs, but provider URL resolution belongs in adapter or assembly compatibility owners',
},
{
regex: /\b(?:chat\/completions|v1\/messages|streamGenerateContent)\b/,
message:
'core-types must not encode provider endpoint paths; keep protocol URL behavior above contracts',
},
],
},
{
path: 'src/crates/assembly/core/src/product_assembly.rs',
patterns: [
Expand Down
69 changes: 67 additions & 2 deletions scripts/core-boundaries/rules/source/required-rules.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -1630,9 +1630,34 @@ export const requiredContentRules = [
},
{
regex:
/bitfun-services-integrations = \{ path = "\.\.\/\.\.\/services\/services-integrations", default-features = false, features = \["remote-ssh", "workspace-search"\] \}/,
/bitfun-services-integrations = \{ path = "\.\.\/\.\.\/services\/services-integrations", default-features = false, features = \["remote-ssh"\] \}/,
message:
'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',
'bitfun-services-integrations dependency may keep remote workspace identity but must not force workspace-search or product-full outside the core feature graph',
},
{
regex:
/bitfun-ai-adapters = \{ path = "\.\.\/\.\.\/adapters\/ai-adapters", optional = true \}/,
message: 'bitfun-ai-adapters dependency must stay optional for no-default core builds',
},
{
regex: /"dep:bitfun-ai-adapters"/,
message: 'core ai-adapter-runtime feature must explicitly enable the optional dependency',
},
{
regex: /product-full = \[[^\]]*"ai-adapter-runtime"[^\]]*\]/,
message: 'core product-full assembly must explicitly opt into AI adapter runtime',
},
{
regex: /product-domains = \[[^\]]*"ai-adapter-runtime"[^\]]*\]/,
message: 'core product-domain facade must explicitly opt into AI adapter runtime while concrete AI adapters remain optional',
},
{
regex: /product-domains = \[[^\]]*"bitfun-services-integrations\/function-agents"[^\]]*\]/,
message: 'core product-domain facade must enable the function-agent service owner feature it imports',
},
{
regex: /product-domains = \[[^\]]*"bitfun-services-integrations\/miniapp-runtime"[^\]]*\]/,
message: 'core product-domain facade must enable the MiniApp service owner feature it imports',
},
{
regex:
Expand Down Expand Up @@ -1696,6 +1721,38 @@ export const requiredContentRules = [
},
],
},
{
path: 'src/crates/assembly/core/src/infrastructure/mod.rs',
reason: 'concrete AI adapter runtime and debug ingest HTTP server must stay out of no-default core builds',
patterns: [
{
regex: /#\[cfg\(feature = "ai-adapter-runtime"\)\]\s*pub mod ai\b/s,
message: 'AI client runtime must stay behind ai-adapter-runtime',
},
{
regex: /#\[cfg\(feature = "ai-adapter-runtime"\)\]\s*pub mod cli_credentials\b/s,
message: 'AI CLI credential runtime must stay behind ai-adapter-runtime',
},
{
regex: /#\[cfg\(feature = "product-full"\)\]\s*pub mod debug_log\b/s,
message: 'debug ingest HTTP server must stay behind product-full',
},
],
},
{
path: 'src/crates/assembly/core/src/util/types/ai.rs',
reason: 'legacy AI implementation DTO re-exports must not force AI adapters into no-default core builds',
patterns: [
{
regex: /pub use bitfun_core_types::\{ConnectionTestMessageCode, ConnectionTestResult, RemoteModelInfo\};/s,
message: 'stable AI DTOs must be re-exported from core-types',
},
{
regex: /#\[cfg\(feature = "ai-adapter-runtime"\)\]\s*pub use bitfun_ai_adapters::types::\{GeminiResponse, GeminiUsage\};/s,
message: 'legacy Gemini implementation DTOs must stay behind ai-adapter-runtime',
},
],
},
{
path: 'src/crates/assembly/core/src/service/mod.rs',
reason:
Expand All @@ -1717,6 +1774,14 @@ export const requiredContentRules = [
regex: /#\[cfg\(feature = "service-integrations"\)\]\s*pub mod review_platform\b/s,
message: 'review platform facade must stay behind service-integrations',
},
{
regex: /#\[cfg\(feature = "product-full"\)\]\s*pub mod search\b/s,
message: 'workspace search facade must stay behind product-full',
},
{
regex: /#\[cfg\(feature = "product-full"\)\]\s*pub use search::/s,
message: 'workspace search exports must stay behind product-full',
},
{
regex: /#\[cfg\(feature = "product-full"\)\]\s*pub mod snapshot\b/s,
message: 'snapshot service must stay behind product-full until tool-runtime ownership is split',
Expand Down
35 changes: 34 additions & 1 deletion scripts/core-boundaries/self-test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -549,6 +549,14 @@ export function runManifestParserSelfTest({
if (!coreTypesProfile?.forbiddenNonOptionalDeps.includes('bitfun-ai-adapters')) {
throw new Error('core-types dependency profile must forbid ai-adapter dependencies');
}
const coreTypesAiRuleText = forbiddenRuleTextForPath(
'src/crates/contracts/core-types/src/ai.rs',
);
for (const contract of ['resolve_request_url', 'chat\\/completions', 'v1\\/messages']) {
if (!coreTypesAiRuleText.includes(contract)) {
throw new Error(`core-types AI DTO boundary rule must forbid: ${contract}`);
}
}
const runtimePortsProfile = dependencyProfileRules.find(
(rule) => rule.crateName === 'runtime-ports',
);
Expand Down Expand Up @@ -1800,9 +1808,14 @@ export function runManifestParserSelfTest({
path: 'src/crates/assembly/core/Cargo.toml',
contracts: [
'bitfun-product-capabilities = \\{ path = "\\.\\.\\/product-capabilities", default-features = false, optional = true \\}',
'bitfun-ai-adapters = \\{ path = "\\.\\.\\/\\.\\.\\/adapters\\/ai-adapters", optional = true \\}',
'bitfun-tool-packs = \\{ path = "\\.\\.\\/\\.\\.\\/execution\\/tool-provider-groups", default-features = false, optional = true \\}',
'bitfun-services-integrations = \\{ path = "\\.\\.\\/\\.\\.\\/services\\/services-integrations", default-features = false, features = \\["remote-ssh", "workspace-search"\\] \\}',
'bitfun-services-integrations = \\{ path = "\\.\\.\\/\\.\\.\\/services\\/services-integrations", default-features = false, features = \\["remote-ssh"\\] \\}',
'bitfun-product-domains = \\{ path = "\\.\\.\\/\\.\\.\\/contracts\\/product-domains", default-features = false, optional = true \\}',
'dep:bitfun-ai-adapters',
'ai-adapter-runtime',
'bitfun-services-integrations\\/function-agents',
'bitfun-services-integrations\\/miniapp-runtime',
'dep:bitfun-product-capabilities',
'dep:bitfun-tool-packs',
'bitfun-tool-packs\\/product-full',
Expand All @@ -1823,6 +1836,25 @@ export function runManifestParserSelfTest({
'service_agent_runtime',
],
},
{
path: 'src/crates/assembly/core/src/infrastructure/mod.rs',
contracts: [
'feature = "ai-adapter-runtime"',
'pub mod ai',
'pub mod cli_credentials',
'feature = "product-full"',
'pub mod debug_log',
],
},
{
path: 'src/crates/assembly/core/src/util/types/ai.rs',
contracts: [
'bitfun_core_types',
'feature = "ai-adapter-runtime"',
'GeminiResponse',
'GeminiUsage',
],
},
{
path: 'src/crates/assembly/core/src/service/mod.rs',
contracts: [
Expand All @@ -1832,6 +1864,7 @@ export function runManifestParserSelfTest({
'pub mod remote_connect',
'pub mod review_platform',
'feature = "product-full"',
'pub mod search',
'pub mod snapshot',
],
},
Expand Down
38 changes: 2 additions & 36 deletions src/crates/adapters/ai-adapters/src/types/ai.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use serde::{Deserialize, Serialize};
use serde_json::Value;

pub use bitfun_core_types::{ConnectionTestMessageCode, ConnectionTestResult, RemoteModelInfo};

/// Gemini API response
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GeminiResponse {
Expand Down Expand Up @@ -63,42 +65,6 @@ impl From<GeminiUsage> for bitfun_agent_stream::UnifiedTokenUsage {
}
}

/// Structured message codes for localized connection test messaging.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ConnectionTestMessageCode {
ToolCallsNotDetected,
ImageInputCheckFailed,
}

/// AI connection test result
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ConnectionTestResult {
/// Whether the test succeeded
pub success: bool,
/// Response time (ms)
pub response_time_ms: u64,
/// Model response content (if successful)
#[serde(skip_serializing_if = "Option::is_none")]
pub model_response: Option<String>,
/// Structured message code for localized frontend messaging
#[serde(skip_serializing_if = "Option::is_none")]
pub message_code: Option<ConnectionTestMessageCode>,
/// Raw error or diagnostic details
#[serde(skip_serializing_if = "Option::is_none")]
pub error_details: Option<String>,
}

/// Remote model info discovered from a provider API.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RemoteModelInfo {
/// Provider model identifier (used as the actual model_name).
pub id: String,
/// Optional human-readable display name returned by the provider.
#[serde(skip_serializing_if = "Option::is_none")]
pub display_name: Option<String>,
}

#[cfg(test)]
mod tests {
use super::GeminiUsage;
Expand Down
45 changes: 1 addition & 44 deletions src/crates/adapters/ai-adapters/src/types/config.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use serde::{Deserialize, Serialize};
pub use bitfun_core_types::{AIConfig, ProxyConfig, ReasoningMode};

fn append_endpoint(base_url: &str, endpoint: &str) -> String {
let base = base_url.trim();
Expand Down Expand Up @@ -63,49 +63,6 @@ pub fn resolve_request_url(base_url: &str, provider: &str, model_name: &str) ->
}
}

#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Default)]
#[serde(rename_all = "snake_case")]
pub enum ReasoningMode {
#[default]
Default,
Enabled,
Disabled,
Adaptive,
}

#[derive(Debug, Clone, Serialize, Deserialize, Default)]
#[serde(default)]
pub struct ProxyConfig {
pub enabled: bool,
pub url: String,
pub username: Option<String>,
pub password: Option<String>,
}

/// AI client configuration shared across runtime contexts.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AIConfig {
pub name: String,
pub base_url: String,
pub request_url: String,
pub api_key: String,
pub model: String,
pub format: String,
pub context_window: u32,
pub max_tokens: Option<u32>,
pub temperature: Option<f64>,
pub top_p: Option<f64>,
pub reasoning_mode: ReasoningMode,
pub inline_think_in_text: bool,
pub custom_headers: Option<std::collections::HashMap<String, String>>,
pub custom_headers_mode: Option<String>,
pub skip_ssl_verify: bool,
pub reasoning_effort: Option<String>,
pub thinking_budget_tokens: Option<u32>,
pub custom_request_body: Option<serde_json::Value>,
pub custom_request_body_mode: Option<String>,
}

#[cfg(test)]
mod tests {
use super::resolve_request_url;
Expand Down
Loading
Loading