← Về thư mục
📄 / / profiles / r-and-d / raw_evidence / OpenAI4S / docs / backend-refactor-architecture.md

Backend refactor architecture

Status: implemented. The migration completed through small, tested commits. Legacy import paths remain as compatibility/composition facades; capability behaviour now lives in focused classes and repositories.

This document records the agreed target architecture for the OpenAI4S backend refactor. It is a compatibility-preserving reorganization, not a reduction of the product to CoreCoder's function-calling loop.

Confirmed decisions

  1. OpenAI4S remains a hybrid agent with two deliberately separate action planes:

  2. Native JSON tool calling is the control plane. It is limited to orchestration, permission checks, external services, and operations that require human approval. Providers must expose these calls through their native structured tool-call protocol; fenced ```tool JSON is not the target representation.

  3. Python/R Code-as-Action is the scientific execution plane. Data loading, transformation, numerical analysis, simulation, plotting, model execution, and other scientific computation continue to run as real code in persistent Python or R kernels.

  4. The Python kernel retains synchronous mid-cell host.* RPC. A cell may use host services while its scientific program is running; native JSON tool calls do not replace this inner loop.

  5. host.submit_output(...), called from a Python cell, is the only task completion signal. Plain assistant text, an R cell, a native tool result, an empty action, or exhaustion of work does not mean success. Maximum turns, cancellation, refusal, timeout, and failure are non-success stop reasons.

  6. All current capabilities are retained, including persistent Python/R kernels, delegation, skills, MCP, web access, compute/folding, environment management, artifacts and lineage, replay/review, security controls, permissions, the CLI, the HTTP/WebSocket server, and session persistence.

  7. Public contracts remain compatible. This includes documented Python APIs, host.*, CLI behavior and environment variables, REST and WebSocket payloads, persisted sessions and database data, and user-visible behavior. Internal module paths and private implementation details may change. Public imports that move must keep compatibility re-exports for the supported deprecation period.

  8. The refactor is delivered as a sequence of reviewable commits. Each phase must preserve a runnable system and pass the relevant offline and end-to-end checks before the next phase starts.

Action model

The outer loop consumes one normalized assistant reply and chooses one action kind:

assistant reply
    |
    +-- native JSON tool call(s) --> control-plane executor
    |                                orchestration / permission / external
    |                                service / human approval
    |
    +-- one Python or R cell ------> scientific executor
    |                                persistent language kernel
    |
    +-- no valid action -----------> corrective observation

Provider-specific streaming formats are normalized before they reach the agent loop. Native tool-call IDs and their results remain paired as one indivisible protocol group. Likewise, a code action and its observation remain an indivisible turn group for interruption handling and context compaction.

The control plane and scientific plane share policy and observability, but not responsibility:

Human approval is represented as a durable control-plane state. An operation may pause with a pending approval and later resume the same session; approval must not be inferred from model text. A live approval wakes the exact blocked call. A daemon restart destroys that call stack, so a later approval never replays persisted arguments: it records the interrupted action as unexecuted and requires a fresh, explicit continuation/replan turn.

One authoritative agent engine

There will be one reusable AgentEngine for in-process, CLI, WebSocket, root, and delegated runs. Server and CLI layers adapt events and persistence; they do not implement their own model/action/execution loop.

The engine depends on small internal protocols:

ModelClient       messages -> normalized reply + native tool calls + usage
ActionRouter      normalized reply -> CodeAction | NativeToolBatch | NoAction
ContextPolicy     complete turn groups -> retained/compacted context
ActionExecutor    action -> observation + optional submitted completion
EventSink         typed run events -> CLI / WebSocket / persistence adapters
Cancellation      reports whether the current run should stop

AgentEngine must not construct or import a concrete store, gateway, kernel, dispatcher, skill loader, replay recorder, or WebSocket hub. Those dependencies are assembled at the application boundary. The loop remains small enough that its state transitions and terminal conditions can be reviewed in one place.

Implemented package layout

The finished layout is intentionally compact. A directory exists only when it owns a real dependency boundary. Large public modules remain as compatible composition facades, while the behaviour they used to contain is grouped by domain below.

openai4s/
  agent/
    engine.py                  sole outer-loop state machine
    actions.py                 native-tool / one-cell / no-action routing
    runtime.py                 local and CLI adapter
    control.py                 protected native-tool execution
    models.py · ports.py       provider-neutral values and dependency ports

  llm/
    client.py                  provider-neutral chat orchestration
    messages.py · models.py    normalized messages, replies, calls, usage
    tooling.py · transport.py  wire assembly and stdlib transport
  llm/__init__.py              compatible public facade

  execution/
    models.py                  cell/capture value types
    watchdog.py                timeout and exact-kernel recovery policy

  tools/
    base.py                    executable Tool interface and safe defaults
    contexts.py                narrow workspace/environment ports
    <capability>.py            one named class with schema, policy, behaviour
    registry.py                ordered class catalogue and runtime instances
    native.py                  provider-neutral JSON declarations

  host_dispatch.py             permission/audit/replay/injection routing facade
  host/
    files.py                   workspace boundary service
    llm.py · completion.py     model fanout and sole completion state
    data.py · delegation.py    query/artifact/lineage and child orchestration
    remote_capabilities.py     verified service registration
    remote_science.py          real fold/mutation remote execution
    progress.py · skills.py    plan/todo and skill services
    endpoints.py · mcp.py      managed endpoints and MCP services
    credentials.py             in-memory credential service

  sdk/
    host.py                    compatible in-kernel host facade
    compute.py                 host.compute namespace and job handles

  kernel/
    manager.py                 worker lifecycle and synchronous host RPC
    supervisor.py              per-session Python/R slot ownership
    worker.py                  persistent Python worker
    r_kernel.py · r_worker.R   persistent analysis-only R channel
    background.py · environments.py · guards.py · provenance.py

  store.py                     schema/migration/connection + compatible facade
  storage/
    frames.py                  projects, frames, messages, steps, cell log
    artifacts.py               versions, snapshots, lineage
    metadata.py                notes, folders, endpoints, compaction, audit
    agents.py · connectors.py · memories.py
    annotations.py · plans.py · permissions.py · settings.py

  server/
    gateway.py                 stdlib HTTP/WS composition and route adapter
    agent_run.py               AgentEngine-to-Web event/action adapter
    cell_run.py                one scientific cell transaction
    artifacts.py               capture, versions, restore, mutations
    plans.py · reviews.py      plan and evidence-review orchestration
    skills.py · titles.py      customization and background titles
    execution_views.py         execution-log/lineage presentation
    daemon.py · webui/

  cli/main.py                  CLI adapter
  security/ · compute/         policy and remote-compute subsystems

These ownership and dependency boundaries are architectural constraints.

Dependency rules

  1. agent.engine imports only agent action/context/event abstractions and the injected protocols. It never imports server, storage, or concrete kernel and host implementations.
  2. llm owns provider wire differences. No provider-specific response object crosses into the agent engine.
  3. agent.runtime and server.agent_run adapt engine actions to the local or Web runtime; shared execution values/watchdog policy live in execution.
  4. host_dispatch.HostDispatcher is the policy-aware router. Capability business logic lives in classes under host/ or the corresponding Tool class; native tools and kernel RPC cross the same envelope.
  5. Services under server/ own durable run operations. gateway.py and the CLI are adapters/composition roots and cannot contain another agent loop.
  6. Store owns the connection, schema, and migrations. Domain repositories share its connection and lock; they do not open competing write connections.
  7. Kernel workers import the kernel-side sdk and security guards, never server or storage code. The host process continues to execute no shell on behalf of the model.
  8. Capability restriction is structural. Leaf agents, reviewers, plan runs, and approval-pending runs receive restricted registries/executors instead of relying on prompt instructions alone.
  9. Core runtime code remains Python standard-library only. The refactor does not introduce mandatory framework or SDK dependencies.

Compatibility gates

Before moving behavior, the current contracts must be inventoried and protected with characterization tests. At minimum the gates cover:

Compatibility shims may forward old public imports or call signatures to new implementations. They must not duplicate business logic.

Migration phases

Each phase is a separate commit or short commit series with an explicit test gate. Later phases do not begin while the preceding compatibility gate is red.

Current implementation status:

Phase 1 — Architecture and contract baseline

Phase 2 — Normalize replies and actions

Phase 3 — Introduce the single AgentEngine

Phase 4 — Establish the native JSON control plane

Phase 5 — Extract host, SDK, session, and storage boundaries

Phase 6 — Thin transports and remove legacy internals

Phases 1–6 are complete. The remaining large facade files are deliberate: gateway.py contains the framework-free route table/composition plus demo payloads, store.py contains the SQLite schema/migrations and forwarding API, and host_dispatch.py contains the shared policy envelope and compatibility adapters. Domain algorithms no longer need to be added directly to those facades.

Non-goals