refactor: extract op-ai crate

Relocate the AI chat layer (chat_provider.rs, chat_models.rs,
agent_settings_state.rs) out of openpencil-shell-core into a dedicated
op-ai crate. These three modules are dependency-free transport-free
data shapes — the ChatProvider trait, the ModelEntry catalog type, and
the Cmd+, settings-modal state — so they form a clean wasm32-clean
leaf crate. A fresh lib.rs declares all three as modules; chat_models'
`crate::agent_settings_state::` path stays valid. openpencil-desktop's
chat_*.rs transports + model_discovery.rs now import `op_ai::*`. Pure
relocation, no behaviour change.
This commit is contained in:
Kayshen-X 2026-05-16 23:24:29 +08:00
parent e2e287c008
commit 0dc231a5e9
14 changed files with 49 additions and 14 deletions

13
crates/op-ai/Cargo.toml Normal file
View file

@ -0,0 +1,13 @@
[package]
name = "op-ai"
version.workspace = true
edition.workspace = true
rust-version.workspace = true
license.workspace = true
description = "OpenPencil AI chat layer — transport-free ChatProvider trait + model catalog + agent-settings state"
[lib]
name = "op_ai"
path = "src/lib.rs"
[dependencies]

20
crates/op-ai/src/lib.rs Normal file
View file

@ -0,0 +1,20 @@
//! OpenPencil AI chat layer.
//!
//! This crate carries the transport-free data shapes for the editor's
//! chat / agent integration — extracted out of `openpencil-shell-core`
//! in the Phase 7 strangler reorg:
//!
//! - [`chat_provider`] — the `ChatProvider` trait + provider-category
//! types (`CliName`, `Provider`, …) and the `EchoProvider` test
//! double. Real transports (tokio / reqwest / process-spawn) live
//! desktop-side in `openpencil-desktop`.
//! - [`chat_models`] — the `ModelEntry` model-catalog type.
//! - [`agent_settings_state`] — state types for the Cmd+, settings
//! modal (`AgentSettingsTab`, `AgentProvider`, …).
//!
//! The crate is dependency-free and wasm32-clean so both the native
//! and web shells can build against it.
pub mod agent_settings_state;
pub mod chat_models;
pub mod chat_provider;

View file

@ -25,6 +25,11 @@ op-editor-core = { path = "../op-editor-core" }
# (`mcp.rs` + `mcp/*`) was extracted out of openpencil-shell-core into the
# op-mcp crate; `mcp_serve.rs` registers tools through `op_mcp::*`.
op-mcp = { path = "../op-mcp" }
# Phase 7 strangler reorg: the transport-free AI chat data shapes
# (`ChatProvider` trait + model catalog + agent-settings state) were
# extracted into op-ai; the `src/chat_*.rs` real transports + the
# model-discovery path import them through `op_ai::*`.
op-ai = { path = "../op-ai" }
# Canonical `.op` (PenDocument) → shell `Document` loader / adapter.
# Extracted out of this binary into a shared library crate so library
# crates (openpencil-shell-native) can reuse the conversion;

View file

@ -21,7 +21,7 @@ use anthropic_agent_sdk::{
types::{ContentBlock, Message},
ClaudeAgentOptions, StreamExt,
};
use openpencil_shell_core::chat_provider::{
use op_ai::chat_provider::{
ChatDelta, ChatProvider, ChatRequest, StopReason,
};
use tokio::sync::mpsc;

View file

@ -27,7 +27,7 @@ use github_copilot_sdk::handler::{
};
use github_copilot_sdk::types::{MessageOptions, SessionConfig, SessionEvent};
use github_copilot_sdk::{Client, ClientOptions};
use openpencil_shell_core::chat_provider::{
use op_ai::chat_provider::{
ChatDelta, ChatProvider, ChatRequest, StopReason,
};
use tokio::sync::mpsc;

View file

@ -39,7 +39,7 @@
use std::sync::Arc;
use std::time::Duration;
use openpencil_shell_core::chat_provider::{
use op_ai::chat_provider::{
ChatDelta, ChatProvider, ChatRequest, CliName, StopReason,
};
use serde::Serialize;

View file

@ -1,5 +1,5 @@
//! Real `ChatProvider` impls — the desktop-side companion to the
//! abstraction in `openpencil_shell_core::chat_provider`. Shell-core
//! abstraction in `op_ai::chat_provider`. Shell-core
//! intentionally stays wasm32-clean (no tokio / reqwest / process), so
//! transports live here on the native binary.
//!
@ -27,7 +27,7 @@ use agent::provider::Provider;
use agent::query::QueryEngine;
use agent::stream::Event;
use futures::StreamExt;
use openpencil_shell_core::chat_provider::{
use op_ai::chat_provider::{
ChatDelta, ChatProvider, ChatRequest, StopReason,
};
use tokio::runtime::{Builder, Runtime};

View file

@ -10,7 +10,7 @@
use std::sync::mpsc::{self, Receiver, TryRecvError};
use std::thread;
use openpencil_shell_core::chat_provider::{
use op_ai::chat_provider::{
ChatDelta, ChatProvider, ChatRequest, CliName,
};
use openpencil_shell_native::WidgetHostNative;
@ -207,7 +207,7 @@ pub fn pump(
#[cfg(test)]
mod tests {
use super::*;
use openpencil_shell_core::chat_provider::{EchoProvider, StopReason};
use op_ai::chat_provider::{EchoProvider, StopReason};
#[test]
fn session_streams_echo_provider_deltas_to_completion() {

View file

@ -33,7 +33,7 @@
use std::path::PathBuf;
use std::sync::Arc;
use openpencil_shell_core::chat_provider::{
use op_ai::chat_provider::{
ChatDelta, ChatProvider, ChatRequest, CliName, StopReason,
};
use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader};

View file

@ -23,8 +23,8 @@ use std::process::{Command, Stdio};
use std::sync::mpsc::{self, Receiver, TryRecvError};
use std::time::{Duration, Instant};
use openpencil_shell_core::agent_settings_state::AgentProvider;
use openpencil_shell_core::chat_models::ModelEntry;
use op_ai::agent_settings_state::AgentProvider;
use op_ai::chat_models::ModelEntry;
/// Background model-discovery probe. [`discover_models`] reads a
/// cache file and spawns a subprocess (`opencode models`, ~1 s),
@ -79,7 +79,7 @@ impl ModelProbe {
/// Translate a shell-core `ModelEntry` into op-editor-core's.
fn model_entry_to_ec(m: ModelEntry) -> op_editor_core::ModelEntry {
use openpencil_shell_core::agent_settings_state::AgentProvider as ScP;
use op_ai::agent_settings_state::AgentProvider as ScP;
let provider = match m.provider {
ScP::ClaudeCode => op_editor_core::AgentProvider::ClaudeCode,
ScP::CodexCli => op_editor_core::AgentProvider::CodexCli,

View file

@ -16,9 +16,6 @@
//! differentiation lives at the canvas viewport / chrome layer
//! (single-page + infinite canvas recommended, multi-page also supported).
pub mod agent_settings_state;
pub mod chat_models;
pub mod chat_provider;
// Phase 3 strangler reorg: i18n extracted into the op-i18n crate. Re-exported
// as `i18n` so `crate::i18n::translate` / `crate::i18n::Locale` paths still resolve.
pub use op_i18n as i18n;