# https://github.com/agentscope-ai/agentscope Project Manual

Generated at: 2026-06-21 13:47:39 UTC

## Table of Contents

- [Framework Overview & Architecture](#page-1)
- [Agent Loop, Events & Tool System](#page-2)
- [Permissions, MCP & Workspace Manager](#page-3)
- [Model & Embedding Integrations](#page-4)
- [Skills, Long-Term Memory, Middleware & Tracing](#page-5)
- [Workspaces, TTS & Audio](#page-6)
- [Agent Service: FastAPI Backend, Multi-Tenancy & Agent Teams](#page-7)
- [Web UI: Frontend, Pages & Hooks](#page-8)

<a id='page-1'></a>

## Framework Overview & Architecture

### Related Pages

Related topics: [Agent Loop, Events & Tool System](#page-2), [Agent Service: FastAPI Backend, Multi-Tenancy & Agent Teams](#page-7)

<details>
<summary>Related Source Files</summary>

The following source files were used to generate this page:

- [README.md](https://github.com/agentscope-ai/agentscope/blob/main/README.md)
- [src/agentscope/agent/_agent.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/agent/_agent.py)
- [src/agentscope/agent/_config.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/agent/_config.py)
- [src/agentscope/app/_app.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/app/_app.py)
- [src/agentscope/app/_service/_toolkit.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/app/_service/_toolkit.py)
- [src/agentscope/app/_tools/__init__.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/app/_tools/__init__.py)
- [src/agentscope/app/_tools/_team_create.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/app/_tools/_team_create.py)
- [src/agentscope/app/middleware/_tool_offload_middleware.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/app/middleware/_tool_offload_middleware.py)
- [src/agentscope/app/_router/_agent.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/app/_router/_agent.py)
- [src/agentscope/middleware/_budget.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/middleware/_budget.py)
- [src/agentscope/middleware/_longterm_memory/_mem0/_middleware.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/middleware/_longterm_memory/_mem0/_middleware.py)
- [src/agentscope/middleware/_longterm_memory/_mem0/_tools.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/middleware/_longterm_memory/_mem0/_tools.py)
- [src/agentscope/middleware/_tracing/_extractor.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/middleware/_tracing/_extractor.py)
- [scripts/model_examples/README.md](https://github.com/agentscope-ai/agentscope/blob/main/scripts/model_examples/README.md)
</details>

# Framework Overview & Architecture

## 1. Purpose and Positioning

AgentScope is a developer-centric multi-agent framework that combines an embeddable Python SDK with a ready-to-deploy FastAPI service. The README positions it as a "Flexible yet Robust Multi-Agent Platform" backed by two arXiv papers (`2402.14034` and `2508.16279`) and maintained by a team that emphasises careful ergonomics — a sentiment echoed in community issue [#842](https://github.com/agentscope-ai/agentscope/issues/842), where developers highlight how granular framework details save integration time.

Two design choices recur across the codebase:

- **Composition over inheritance.** Behaviour is layered through middleware hooks and tool groups rather than subclassing.
- **Decoupled transports.** The application layer separates `StorageBase` (persistence) from `MessageBus` (transport), so production deployments can mix backends such as SQL for state and Redis for live messaging ([src/agentscope/app/_app.py:1-50]()).

## 2. Core Agent Architecture

The `Agent` class is the central abstraction. On construction it wires together a model, a toolkit, an offloader, and several middleware lists that are pre-filtered by the hook they implement ([src/agentscope/agent/_agent.py:1-80]()):

```python
self._reply_middlewares = [_ for _ in middlewares if _.is_implemented("on_reply")]
self._reasoning_middlewares = [_ for _ in middlewares if _.is_implemented("on_reasoning")]
self._acting_middlewares = [_ for _ in middlewares if _.is_implemented("on_acting")]
self._model_call_middlewares = [_ for _ in middlewares if _.is_implemented("on_model_call")]
self._system_prompt_middlewares = [_ for _ in middlewares if _.is_implemented("on_system_prompt")]
self._compress_context_middlewares = [_ for _ in middlewares if _.is_implemented("on_compress_context")]
```

Configuration is fully declarative and Pydantic-based. The key config classes are `ReActConfig` (loop control), `ModelConfig` (retries and limits), and `ContextConfig` (compression thresholds, summary schema) ([src/agentscope/agent/_config.py:1-80]()). `ContextConfig.trigger_ratio` defaults to `0.8` and `reserve_ratio` to `0.1`, meaning that once a session fills 80% of the context window, compression runs and preserves at least 10% of the original tokens.

```mermaid
flowchart TB
    subgraph Core["Agent Core"]
        SP[System Prompt]
        ST[AgentState]
        TOOL[Toolkit]
        PERM[PermissionEngine]
    end
    subgraph Middlewares["Middleware Pipeline"]
        REPLY[on_reply]
        REAS[on_reasoning]
        ACT[on_acting]
        MODEL[on_model_call]
        COMP[on_compress_context]
        SYSP[on_system_prompt]
    end
    MODEL --> REAS --> ACT --> MODEL
    REPLY --> MODEL
    SP --> SYSP
    Core --> Middlewares
```

The middleware pipeline is also where long-term memory hooks live. `Mem0Middleware` accepts three modes (`static_control`, `agent_control`, `both`) and validates the `user_id` early to prevent silent misconfiguration ([src/agentscope/middleware/_longterm_memory/_mem0/_middleware.py:1-60]()). Community RFC [#1474](https://github.com/agentscope-ai/agentscope/issues/1474) proposes a competing "VantaGrid" deterministic memory middleware, which underscores that the framework deliberately leaves the memory slot open.

## 3. Application & Service Layer

The FastAPI app is built by `create_app(...)`, which takes a `StorageBase`, a `MessageBus`, and a `WorkspaceManagerBase` and registers every built-in router automatically ([src/agentscope/app/_app.py:1-60]()). Lifespans for storage and bus are managed by the app, so callers only own the wiring.

Per-turn tool assembly is centralised in `get_toolkit(...)`, which gathers workspace builtins, planning tools, background-task control, scheduler tools, and team tools into one `Toolkit` ([src/agentscope/app/_service/_toolkit.py:1-60]()):

> 1. Workspace builtins (Bash / Read / Write / Grep / …)
> 2. Planning tools (`TaskCreate` / `TaskList` / `TaskGet` / `TaskUpdate`)
> 3. Background-task control (`ToolStop`)
> 4. Schedule control (only when the session has a model)
> 5. Team tools — selected inline by `agent_record.source`
> 6. Caller-supplied extras (`extra_factory`)

Team-tool visibility is decided inline by `agent.source`: a `source='team'` worker only sees `TeamSay`, while a leader-side agent gets the full `TeamCreate / AgentCreate / TeamSay / TeamDelete` set ([src/agentscope/app/_tools/__init__.py:1-40]()). Each tool checks storage state at `__call__` time, so a single chat run can `TeamCreate` and then `AgentCreate` without any toolkit refresh ([src/agentscope/app/_tools/_team_create.py:1-60]()).

Background tool results are not lost when they finish after the agent has stopped reasoning. The tool-offload middleware pushes a `HintBlock` to the session inbox and enqueues a wakeup, so an idle session resumes naturally ([src/agentscope/app/middleware/_tool_offload_middleware.py:1-60]()). This design also addresses a community concern raised in issue [#1453](https://github.com/agentscope-ai/agentscope/issues/1453) about whether the framework supports intent-driven skill execution; the toolkit can attach skills via the workspace and let the model select them.

## 4. Cross-Cutting Middleware Ecosystem

Several middleware families layer on top of the core agent:

| Middleware | Hook | Primary Role |
|---|---|---|
| `ReplyBudgetControlMiddleware` | `on_reply` | Enforces a weighted token budget (`input_token_weight * input_tokens + output_token_weight * output_tokens`) and injects a `<system-reminder>` plus `tool_choice="none"` once exhausted ([src/agentscope/middleware/_budget.py:1-50]()) |
| `Mem0Middleware` | `on_reply` | Long-term memory with `static_control` / `agent_control` / `both` modes and configurable `top_k` and `threshold` |
| Tool-offload middleware | Reply pipeline | Forwards background tool completions via inbox + wakeup |
| Tracing extractor | Observability | Converts AgentScope `Msg` content blocks into OpenTelemetry parts ([src/agentscope/middleware/_tracing/_extractor.py:1-60]()) |

The budget middleware deliberately stores its state in `AgentState.middle_context` rather than on `self`, so the budget survives HITL interruptions and is cleared automatically on `ReplyEndEvent`.

The tracing extractor centralises message serialisation; when role/name lookup fails it falls back to a safe empty list rather than raising a secondary exception ([src/agentscope/middleware/_tracing/_extractor.py:1-60]()). This pattern — fail soft, never break a reply — is consistent across the framework.

## 5. Configuration, Models, and Operational Concerns

`scripts/model_examples/README.md` documents the supported providers (OpenAI, Anthropic, DashScope, DeepSeek, Gemini, Moonshot, xAI, and local Ollama) along with their environment variables. Each provider has its own reasoning controls (`thinking_enable`, `thinking_budget`, `reasoning_effort`), which are surfaced through `ModelConfig`.

Operational footguns flagged by the community include issue [#1660](https://github.com/agentscope-ai/agentscope/issues/1660), where ripgrep is compiled from source on Alibaba Cloud Linux. Ripgrep is only needed for the code-search and RAG workspace tools, so isolating it as an optional dependency keeps the core install lean. Issue [#1296](https://github.com/agentscope-ai/agentscope/issues/1296) likewise reflects a community concern that the public roadmap (CoPaw) can crowd out AgentScope maintenance visibility — a reminder to align releases with the published roadmap.

For agent authoring, the REST surface in `app/_router/_agent.py` slices `AgentData.model_json_schema()` into identity, `ContextConfig`, and `ReActConfig` sections so a schema-driven UI can render the configuration form without hand-maintained JSON ([src/agentscope/app/_router/_agent.py:1-60]()). Hiding `summary_schema` from that slice avoids exposing internal compression hints to end users.

## See Also

- [Toolkit & Tool Assembly](toolkit.md)
- [Middleware Pipeline](middleware.md)
- [Application Service (FastAPI)](app-service.md)
- [Context Compression & Memory](context-compression.md)

---

<a id='page-2'></a>

## Agent Loop, Events & Tool System

### Related Pages

Related topics: [Permissions, MCP & Workspace Manager](#page-3), [Skills, Long-Term Memory, Middleware & Tracing](#page-5)

<details>
<summary>Related Source Files</summary>

The following source files were used to generate this page:

- [src/agentscope/agent/_agent.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/agent/_agent.py)
- [src/agentscope/agent/_config.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/agent/_config.py)
- [src/agentscope/middleware/_base.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/middleware/_base.py)
- [src/agentscope/middleware/_budget.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/middleware/_budget.py)
- [src/agentscope/middleware/__init__.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/middleware/__init__.py)
- [src/agentscope/middleware/_longterm_memory/_mem0/_middleware.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/middleware/_longterm_memory/_mem0/_middleware.py)
- [src/agentscope/middleware/_tracing/_extractor.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/middleware/_tracing/_extractor.py)
- [src/agentscope/app/_service/_toolkit.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/app/_service/_toolkit.py)
- [src/agentscope/app/_tools/__init__.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/app/_tools/__init__.py)
- [src/agentscope/app/_tools/_team_create.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/app/_tools/_team_create.py)
- [src/agentscope/app/_service/_chat.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/app/_service/_chat.py)
- [src/agentscope/app/middleware/_state_change_middleware.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/app/middleware/_state_change_middleware.py)
- [README.md](https://github.com/agentscope-ai/agentscope/blob/main/README.md)
</details>

# Agent Loop, Events & Tool System

AgentScope 2.0 is a production-grade agent framework whose core abstractions are an explicit **reasoning–acting loop**, a unified **event stream**, and a composable **toolkit**. This page explains how these three systems are wired together inside `Agent` and how the app-level services extend them for multi-session, multi-tenant deployment.

Source: [README.md](https://github.com/agentscope-ai/agentscope/blob/main/README.md)

## 1. Reasoning–Acting Loop

The agent's runtime is a bounded loop that alternates between a *reasoning* step (calling the chat model) and an *acting* step (executing tools returned by the model). The reasoning side and the acting side are independently extensible through middleware chains.

```mermaid
flowchart TD
    A[ReplyStartEvent] --> B[Reasoning Middleware Chain]
    B --> C[Chat Model Call]
    C --> D{Tool Calls?}
    D -- Yes --> E[Acting Middleware Chain]
    E --> F[Toolkit.call_tool]
    F --> G[ToolResponse / ToolChunk]
    G --> H{iter < max_iters?}
    H -- Yes --> B
    H -- No --> I[ReplyEndEvent]
    D -- No --> I
```

The loop's bound is configured by `ReActConfig`:

| Field | Default | Purpose |
| --- | --- | --- |
| `max_iters` | `20` | Maximum reasoning-acting iterations in one reply. |
| `stop_on_reject` | `False` | If `True`, stop the loop when tool calls are rejected, awaiting external interaction. |

Source: [src/agentscope/agent/_config.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/agent/_config.py)

Inside the agent, the acting step recursively chains every registered `_acting_middlewares` via an `execute_chain(index, ...)` helper, then delegates to the inner `_acting_impl`, which wraps `Toolkit.call_tool`. State-injected tools receive the live agent context without an intermediate service layer. Source: [src/agentscope/agent/_agent.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/agent/_agent.py)

A wake-up driven chat run (where `input_msg is None`) is skipped when the last assistant message is parked on an `ASKING` or `SUBMITTED` tool call, so the resuming run drains the inbox naturally. Source: [src/agentscope/app/_service/_chat.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/app/_service/_chat.py)

## 2. Middleware System

Middleware hooks customize both halves of the loop and the surrounding lifecycle. `MiddlewareBase` exposes async generator hooks `on_reply`, `on_reasoning`, and `on_acting`. Five built-in middlewares are exported from the public API:

- `ReplyBudgetControlMiddleware` — enforces a weighted token budget per reply. It tracks `input_token_weight * input_tokens + output_token_weight * output_tokens`, injects a `<system-reminder>` hint, and forces `tool_choice="none"` once the budget is exceeded. State persists in `AgentState.middle_context` and is cleaned up on `ReplyEndEvent`, surviving HITL interruptions. Source: [src/agentscope/middleware/_budget.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/middleware/_budget.py)
- `Mem0Middleware` — long-term memory with three modes (`static_control`, `agent_control`, `both`). It validates `user_id`, resolves the Mem0 client (custom or auto-built from `chat_model` + `embedding_model`), and advertises `search_memory` / `add_memory` to the LLM in agent-facing modes. Source: [src/agentscope/middleware/_longterm_memory/_mem0/_middleware.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/middleware/_longterm_memory/_mem0/_middleware.py)
- `TracingMiddleware` — converts `Msg` objects (including content blocks) into OpenTelemetry-friendly parts via `_format_msg_to_parts`, with a fallback that avoids raising secondary exceptions if extraction fails. Source: [src/agentscope/middleware/_tracing/_extractor.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/middleware/_tracing/_extractor.py)
- `TTSMiddleware` — text-to-speech integration.
- Custom middlewares (e.g. `StateChangeMiddleware`) detect state mutations after each tool call by comparing hashes of `tasks_context` and `permission_context`, and publish `CustomEvent(name="state_updated", value={...})` directly to the message bus. The team tools (`TeamCreate`, `AgentCreate`, `TeamDelete`) short-circuit this check and always publish `team_updated`. Source: [src/agentscope/app/middleware/_state_change_middleware.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/app/middleware/_state_change_middleware.py)

Source: [src/agentscope/middleware/__init__.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/middleware/__init__.py)

## 3. Tool System and Toolkit Assembly

A `Toolkit` is the single container exposed to one chat turn. The app-level `get_toolkit` assembles it in attachment order:

1. **Workspace builtins** — `Bash`, `Read`, `Write`, `Grep`, etc.
2. **Planning tools** — `TaskCreate`, `TaskList`, `TaskGet`, `TaskUpdate`.
3. **Background-task control** — `ToolStop`, from `BackgroundTaskManager.list_tools()`.
4. **Schedule control** — `ScheduleCreate`, `ScheduleView`, `ScheduleDelete`, `ScheduleList`, attached only when the session has a configured model.
5. **Team tools** — selected inline by `agent_record.source`: workers (`source='team'`) see only `TeamSay`; everyone else sees the full leader-side set (`TeamCreate`, `AgentCreate`, `TeamSay`, `TeamDelete`).
6. **Caller-supplied extras** — via `extra_factory`.

The workspace's skills and MCPs become the toolkit's `skills_or_loaders` and `mcps` parameters. The benefit of source-based visibility is that a single chat run can call `TeamCreate` then `AgentCreate` without a toolkit refresh, because the toolkit never changed — only the storage state did, which the next tool reads fresh.

Source: [src/agentscope/app/_service/_toolkit.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/app/_service/_toolkit.py)
Source: [src/agentscope/app/_tools/__init__.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/app/_tools/__init__.py)

Team tools bind to app-level resources at construction: a `StorageBase`, a `MessageBus`, and request-scoped `user_id` / `session_id` / `agent_id`. For example, `TeamCreate` first fetches the session via `storage.get_session` and rejects creation if `session.team_id` is already set, returning a `ToolChunk` with `state=ToolResultState.ERROR`. On success it upserts a `TeamRecord` and writes the team's id back onto the session via `storage.set_session_team_id`. Source: [src/agentscope/app/_tools/_team_create.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/app/_tools/_team_create.py)

## 4. Event System and Service Integration

The event stream is the unified backbone for both the frontend and human-in-the-loop control. Built-in events include `ReplyStartEvent`, `ReplyEndEvent`, `ModelCallEndEvent`, and `CustomEvent`. Middlewares use these to register cleanup hooks (the budget middleware cleans up on `ReplyEndEvent`), while the state-change middleware publishes `CustomEvent`s directly to the message bus because `on_acting` yields `ToolChunk | ToolResponse` — not `AgentEvent`. The SSE `/stream` endpoint picks them up like any other session event. Source: [src/agentscope/app/middleware/_state_change_middleware.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/app/middleware/_state_change_middleware.py)

`create_app` is the primary entry point for embedding AgentScope into an existing service or running it standalone. It requires `StorageBase`, `MessageBus`, and `WorkspaceManagerBase`; both the storage and bus lifecycles are managed by the FastAPI lifespan, and the bus is intentionally decoupled from storage so the persistence backend (e.g. SQL) can differ from the transport backend (Redis). Source: [src/agentscope/app/_app.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/app/_app.py)

### Community-Relevant Notes

- **Skill loading (issue #1453):** Users have reported cases where the agent skips a `SKILL.md` and calls a generic tool such as `execute_shell_command` instead. The toolkit wiring in `get_toolkit` makes skills part of `skills_or_loaders`, but the framework relies on the LLM to *select* a skill through normal tool calling; explicit intent-recognition steps must be encoded as prompts or middleware hooks, not assumed by default.
- **Optional dependencies (issue #1660):** Heavy native dependencies (e.g. ripgrep, required only by code-search / RAG tools) trigger source compilation on non-standard glibc/musl environments. Treat such tools as optional extensions of the toolkit rather than core requirements.

## See Also

- Memory compression and `ReActConfig` reference: [src/agentscope/agent/_config.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/agent/_config.py)
- Long-term memory with Mem0: [src/agentscope/middleware/_longterm_memory/_mem0/_middleware.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/middleware/_longterm_memory/_mem0/_middleware.py)
- Agent Service deployment: [src/agentscope/app/_app.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/app/_app.py)

---

<a id='page-3'></a>

## Permissions, MCP & Workspace Manager

### Related Pages

Related topics: [Agent Loop, Events & Tool System](#page-2), [Workspaces, TTS & Audio](#page-6)

<details>
<summary>Related Source Files</summary>

The following source files were used to generate this page:

- [src/agentscope/app/_app.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/app/_app.py)
- [src/agentscope/app/_service/_toolkit.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/app/_service/_toolkit.py)
- [src/agentscope/app/_tools/_team_tool_base.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/app/_tools/_team_tool_base.py)
- [src/agentscope/app/_tools/_team_create.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/app/_tools/_team_create.py)
- [src/agentscope/app/_tools/_team_say.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/app/_tools/_team_say.py)
- [src/agentscope/app/_tools/__init__.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/app/_tools/__init__.py)
- [src/agentscope/app/_manager/_scheduler/_tools/_schedule_create.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/app/_manager/_scheduler/_tools/_schedule_create.py)
- [src/agentscope/app/middleware/_tool_offload_middleware.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/app/middleware/_tool_offload_middleware.py)
- [src/agentscope/middleware/_longterm_memory/_mem0/_middleware.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/middleware/_longterm_memory/_mem0/_middleware.py)
- [src/agentscope/middleware/_longterm_memory/_mem0/_tools.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/middleware/_longterm_memory/_mem0/_tools.py)
- [src/agentscope/agent/_config.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/agent/_config.py)
- [README.md](https://github.com/agentscope-ai/agentscope/blob/main/README.md)
</details>

# Permissions, MCP & Workspace Manager

## 1. Overview

AgentScope's `app` layer is a FastAPI service that wires three cross-cutting subsystems around every chat turn: a **Permissions engine** that gates tool invocations, an **MCP** (Model Context Protocol) surface that lets agents call external tool servers, and a **Workspace Manager** that resolves per-session working directories and exposes the workspace's built-in skills and tool groups. Together they form the safety and capability boundary between a reasoning agent and the outside world.

The principal entry point is `create_app(...)`, which accepts a `StorageBase`, a `MessageBus`, a `WorkspaceManagerBase`, and a `SchedulerManager`, and registers all built-in routers automatically. Source: [src/agentscope/app/_app.py:1-80](). Inside each chat turn, `get_toolkit(...)` reassembles a per-request `Toolkit` that consumes the workspace, the scheduler, the background-task manager, and the message bus. Source: [src/agentscope/app/_service/_toolkit.py:1-90]().

## 2. Permissions

### 2.1 Decision primitives

The permission module exposes four cooperating types referenced across the codebase:

- `PermissionBehavior` — the per-tool return value: `ALLOW`, `DENY`, or `ASK`.
- `PermissionContext` — the call-site state (agent, user, tool, arguments).
- `PermissionDecision` — the resolved verdict plus any user-facing reason.
- `PermissionMode` — the policy mode that decides how a `PermissionBehavior` is interpreted.

These are imported in both the team-tool base class and the scheduler's `ScheduleCreate` tool. Source: [src/agentscope/app/_tools/_team_tool_base.py:1-40](), Source: [src/agentscope/app/_manager/_scheduler/_tools/_schedule_create.py:1-50]().

### 2.2 Per-tool policy pattern

Every tool is responsible for declaring its own permission policy in its `__call__` (or override hooks). For example, `_TeamToolBase` documents that "all team tools allow themselves unconditionally — the agent's authority to call them is already gated by the role/source-aware logic inside `get_toolkit` that decides which team tools to attach in the first place." Source: [src/agentscope/app/_tools/_team_tool_base.py:1-40](). This is a deliberate design choice: the toolkit-level selection (which tools the agent sees) is the coarse-grained gate, while the per-tool permission primitive is a fine-grained override hook.

### 2.3 Toolkit-level gating

`get_toolkit` selects which tools are attached to an agent in a strict order: workspace builtins, planning tools (`TaskCreate`/`TaskList`/`TaskGet`/`TaskUpdate`), background-task control (`ToolStop`), schedule control (only when a model is configured), team tools (selected by `agent_record.source` — workers get `TeamSay` only, leaders get the full set), and caller-supplied extras. Source: [src/agentscope/app/_service/_toolkit.py:1-90](). The "leader vs. worker" split is the first permission boundary; a worker can never obtain `TeamCreate` or `AgentCreate` regardless of what it asks for.

```mermaid
flowchart TD
    A[get_toolkit called] --> B[Attach workspace builtins]
    B --> C[Attach planning tools Task*]
    C --> D[Attach ToolStop from BackgroundTaskManager]
    D --> E{Model configured?}
    E -- yes --> F[Attach Schedule* tools]
    E -- no --> G[Skip schedule tools]
    F --> H{agent.source == team?}
    G --> H
    H -- yes --> I[Attach TeamSay only]
    H -- no --> J[Attach TeamCreate, AgentCreate, TeamSay, TeamDelete]
    I --> K[Attach extra_factory tools]
    J --> K
```

## 3. MCP Integration

MCP support is wired into `Toolkit` as a first-class parameter. The toolkit assembly docstring states: "Plus the workspace's skills and MCPs, which become the toolkit's `skills_or_loaders` and `mcps` parameters." Source: [src/agentscope/app/_service/_toolkit.py:1-90](). In practice this means a workspace discovered by the `WorkspaceManagerBase` can contribute both (a) on-disk `SKILL.md` packages and (b) live MCP server connections to the per-turn toolkit.

The community issue #1453 reports that users sometimes observe agents calling a generic shell tool instead of a skill-bound tool. This is consistent with the design: skill *selection* is an LLM choice driven by tool descriptions and the system prompt, not a hard-coded mapping. Operators who want stricter intent → skill routing must rely on the workspace's `SKILL.md` frontmatter being unambiguous and the model's tool-selection instruction being explicit. Source: [src/agentscope/app/_service/_toolkit.py:1-90]().

`ToolBase` carries explicit `is_mcp: bool = False` and `mcp_name: str | None = None` flags so the runtime can distinguish external MCP tools from local ones for telemetry and for prompt-rendering decisions. Source: [src/agentscope/app/_tools/_team_tool_base.py:1-40]().

## 4. Workspace Manager

### 4.1 Role

`WorkspaceManagerBase` is responsible for resolving a per-session `WorkspaceBase` instance, which then provides:

- **Built-in tool groups** (Bash, Read, Write, Grep, …) attached first by `get_toolkit`.
- **Skill loaders** (`SKILL.md` packages) exposed as `skills_or_loaders` on the toolkit.
- **MCP server registrations** exposed as `mcps` on the toolkit.

The caller passes the resolved `workspace` into `get_toolkit`, so the workspace manager is invoked once upstream (typically in the chat router) and reused for the duration of the turn. Source: [src/agentscope/app/_service/_toolkit.py:1-90]().

### 4.2 Lifecycle

`create_app` takes `workspace_manager` as a required argument because "every chat run" needs to resolve a workspace. The FastAPI lifespan manages the storage and bus lifecycles, but the workspace manager is treated as a long-lived collaborator owned by the embedding service. Source: [src/agentscope/app/_app.py:1-80](). This decoupling matters for production: the workspace manager can be swapped for a multi-tenant implementation without touching storage or transport.

### 4.3 Tool-result and context budgets

Workspace-supplied tools (e.g., Bash, file readers) can produce very long outputs, so the agent's `ContextConfig` caps tool results at `tool_result_limit` tokens (default 50 000). When exceeded, the result is truncated before it enters the agent's memory. Source: [src/agentscope/agent/_config.py:1-200]().

## 5. Failure Modes and Operational Notes

- **Optional ripgrep dependency.** Issue #1660 notes that ripgrep is source-compiled on non-standard glibc environments even though it is only needed for code-search/RAG tools shipped through the workspace. Operators on Alibaba Cloud Linux should pre-install `ripgrep` from their package manager or pin to a precompiled wheel. Source: [src/agentscope/app/_service/_toolkit.py:1-90]().
- **Background tool completion.** When a workspace tool is offloaded, completion is delivered through the message bus inbox + wakeup path; the agent sees a `<system-notification>` block on its next reasoning step. Source: [src/agentscope/app/middleware/_tool_offload_middleware.py:1-80]().
- **Memory middleware writes.** Long-term memory writes (e.g., Mem0) can be awaited inline or scheduled as background tasks via the `await_write` flag; failures are logged, not raised, so a memory-store outage will not break a turn. Source: [src/agentscope/middleware/_longterm_memory/_mem0/_middleware.py:1-120]().
- **Tool self-allowance is intentional.** A `TeamSay` invocation on a worker is allowed by the tool itself because the worker-vs-leader split was already enforced at toolkit assembly. Operators should not duplicate the check downstream. Source: [src/agentscope/app/_tools/_team_say.py:1-60]().

## See Also

- [Toolkit assembly and team tools](https://docs.agentscope.io/) — covers `get_toolkit` and the team tool contract.
- [FastAPI app entry point](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/app/_app.py) — `create_app` configuration.
- [Context and ReAct configuration](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/agent/_config.py) — `ContextConfig` and `ReActConfig`.

---

<a id='page-4'></a>

## Model & Embedding Integrations

### Related Pages

Related topics: [Agent Loop, Events & Tool System](#page-2), [Agent Service: FastAPI Backend, Multi-Tenancy & Agent Teams](#page-7)

<details>
<summary>Related Source Files</summary>

The following source files were used to generate this page:

- [src/agentscope/embedding/_embedding_model_card.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/embedding/_embedding_model_card.py)
- [src/agentscope/embedding/_ollama/_model.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/embedding/_ollama/_model.py)
- [src/agentscope/embedding/_dashscope/_model.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/embedding/_dashscope/_model.py)
- [scripts/model_examples/README.md](https://github.com/agentscope-ai/agentscope/blob/main/scripts/model_examples/README.md)
- [README.md](https://github.com/agentscope-ai/agentscope/blob/main/README.md)
- [src/agentscope/agent/_config.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/agent/_config.py)
- [src/agentscope/app/__init__.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/app/__init__.py)
</details>

# Model & Embedding Integrations

## Overview

AgentScope exposes a pluggable model layer that abstracts over chat-completion providers and embedding backends. The integrations are designed around two ideas: (1) every provider shares a uniform request/response surface so agents and tools stay provider-agnostic, and (2) each integration can advertise its capabilities to the Web UI through a typed *card* schema. Source: [src/agentscope/embedding/_embedding_model_card.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/embedding/_embedding_model_card.py).

For chat, the provider catalog is exercised by a runnable test harness under `scripts/model_examples/`, which exposes a `--list` mode and uses environment-variable credentials per provider. Source: [scripts/model_examples/README.md](https://github.com/agentscope-ai/agentscope/blob/main/scripts/model_examples/README.md). For embeddings, AgentScope ships first-class integrations for Ollama (local) and DashScope (text + multimodal) plus a `ModelCard`-style declarative descriptor.

## Chat Model Providers

The provider catalog in `scripts/model_examples/README.md` lists the supported chat integrations, the credential each one expects, and any non-standard knobs it exposes.

| Provider | Env Var | Notes |
|---|---|---|
| `openai_chat` | `OPENAI_API_KEY` | OpenAI Chat Completions |
| `anthropic` | `ANTHROPIC_API_KEY` | Anthropic Claude |
| `dashscope` | `DASHSCOPE_API_KEY` | Qwen series, supports `thinking_enable` |
| `deepseek` | `DEEPSEEK_API_KEY` | Supports `call` / `multiagent` only (no multimodal) |
| `gemini` | `GEMINI_API_KEY` | Supports `thinking_budget` |
| `moonshot` | `MOONSHOT_API_KEY` | Moonshot AI kimi-k2.6, etc. |
| `xai` | `XAI_API_KEY` | Grok, supports `reasoning_effort` |
| `ollama` | *(auto-detect)* | Local server, default `http://localhost:11434` |

Source: [scripts/model_examples/README.md](https://github.com/agentscope-ai/agentscope/blob/main/scripts/model_examples/README.md).

Ollama is the only provider that does not require an API key; the harness verifies the local server is reachable before running. Each provider implements the same agent contract, but model-specific reasoning controls (`thinking_enable`, `thinking_budget`, `reasoning_effort`) are surfaced where the upstream API supports them.

## Embedding Model Card Schema

The `EmbeddingModelCard` class is the schema used by the frontend and orchestration layers to discover embedding capabilities without importing provider-specific code. Source: [src/agentscope/embedding/_embedding_model_card.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/embedding/_embedding_model_card.py).

| Field | Type | Purpose |
|---|---|---|
| `type` | `Literal["embedding_model"]` | Discriminator, always `"embedding_model"` |
| `name` | `str` | Model name used in API calls (e.g. `text-embedding-3-small`) |
| `label` | `str` | Human-readable label for the frontend |
| `status` | `Literal["active","deprecated","sunset"]` | Lifecycle marker |
| `input_types` | `list[str]` | Supported MIME types (e.g. `text/plain`, `image/*`) |
| `output_types` | `list[str]` | `application/x-embedding` indicates dense vectors |
| `parameter_schema` | `dict` | Knobs the frontend can edit; built from the model class's `Parameters` + YAML `parameter_overrides` |

```mermaid
classDiagram
    class EmbeddingModelCard {
      +Literal type = "embedding_model"
      +str name
      +str label
      +Literal status
      +list input_types
      +list output_types
      +dict parameter_schema
    }
    class OllamaEmbeddingModel {
      +int _TEXT_BATCH_SIZE = 512
      +str host
      +EmbeddingCacheBase embedding_cache
    }
    class DashScopeEmbeddingModel {
      +bool _is_multimodal
      +_split_multimodal_batches()
      +_merge_responses()
    }
    EmbeddingModelCard <.. OllamaEmbeddingModel : describes
    EmbeddingModelCard <.. DashScopeEmbeddingModel : describes
```

The card mirrors `ModelCard` (used for chat) but is specialised for embeddings; the `application/x-embedding` output type is the canonical signal that a model produces dense vectors.

## Ollama Embedding Integration

`OllamaEmbeddingModel` wraps locally-hosted Ollama servers and inherits batching/retry behaviour from `EmbeddingModelBase`. Source: [src/agentscope/embedding/_ollama/_model.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/embedding/_ollama/_model.py).

Key configuration:

- `_TEXT_BATCH_SIZE = 512` — text is sent in batches of 512 strings
- `context_size = 8192` — maximum input tokens per text
- `max_retries = 3`, `retry_delay = 1.0` — transient-failure handling
- `credential` — an `OllamaCredential` providing the host URL
- `embedding_cache` — optional `EmbeddingCacheBase` for memoisation

Common target models include `nomic-embed-text` and `mxbai-embed-large`. The integration deliberately keeps the surface narrow (text only, single vector per input) so that the batching contract from the base class is sufficient.

## DashScope Embedding Integration

`DashScopeEmbeddingModel` supports both text and multimodal inputs. When multimodal is active, the integration switches from the base-class batch splitter to a content-aware splitter. Source: [src/agentscope/embedding/_dashscope/_model.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/embedding/_dashscope/_model.py).

The multimodal path:

1. Calls `_split_multimodal_batches(inputs)` which uses a greedy algorithm to pack inputs so each batch respects the model's per-request limits on `max_elements`, `max_images`, and `max_videos`.
2. Dispatches batches in parallel via `asyncio.gather`.
3. Merges per-batch responses into a single `EmbeddingResponse` via `_merge_responses`.

Text inputs fall through to the base-class implementation. This design keeps the same `__call__(inputs)` interface for both modes — callers do not branch on model type.

## Configuration & Common Failure Modes

- **Credentials** — every provider reads its credential from a typed `CredentialBase` subclass. Ollama uses `OllamaCredential` for the host URL, others read API keys from environment variables per the provider table.
- **Batching** — Ollama uses fixed 512-element text batches; DashScope uses content-aware multimodal splitting.
- **Retries** — default `max_retries=3` with `retry_delay=1.0` seconds covers transient HTTP failures.
- **Caching** — `EmbeddingCacheBase` can be injected to memoise vectors across calls.
- **Installation** — note the community-reported case (issue #1660) where installing on Alibaba Cloud Linux forces a source build of ripgrep because it is not optional; ripgrep is only required for code-search / RAG tooling, not the core model or embedding paths.

## See Also

- Agent Service (`app/_app.py`) for how providers plug into the FastAPI app factory. Source: [src/agentscope/app/__init__.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/app/__init__.py).
- `ModelConfig` and `ReActConfig` for the higher-level agent configuration that consumes these models. Source: [src/agentscope/agent/_config.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/agent/_config.py).
- Project overview and academic references. Source: [README.md](https://github.com/agentscope-ai/agentscope/blob/main/README.md).

---

<a id='page-5'></a>

## Skills, Long-Term Memory, Middleware & Tracing

### Related Pages

Related topics: [Agent Loop, Events & Tool System](#page-2), [Agent Service: FastAPI Backend, Multi-Tenancy & Agent Teams](#page-7)

<details>
<summary>Related Source Files</summary>

The following source files were used to generate this page:

- [src/agentscope/middleware/__init__.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/middleware/__init__.py)
- [src/agentscope/middleware/_base.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/middleware/_base.py)
- [src/agentscope/middleware/_budget.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/middleware/_budget.py)
- [src/agentscope/middleware/_tracing/_extractor.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/middleware/_tracing/_extractor.py)
- [src/agentscope/middleware/_longterm_memory/__init__.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/middleware/_longterm_memory/__init__.py)
- [src/agentscope/middleware/_longterm_memory/_mem0/__init__.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/middleware/_longterm_memory/_mem0/__init__.py)
- [src/agentscope/middleware/_longterm_memory/_mem0/_middleware.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/middleware/_longterm_memory/_mem0/_middleware.py)
- [src/agentscope/middleware/_longterm_memory/_mem0/_tools.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/middleware/_longterm_memory/_mem0/_tools.py)
- [src/agentscope/app/_service/_toolkit.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/app/_service/_toolkit.py)
- [src/agentscope/app/_tools/__init__.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/app/_tools/__init__.py)
- [src/agentscope/agent/_config.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/agent/_config.py)
- [examples/long_term_memory/mem0/README.md](https://github.com/agentscope-ai/agentscope/blob/main/examples/long_term_memory/mem0/README.md)
</details>

# Skills, Long-Term Memory, Middleware & Tracing

AgentScope 2.x builds its extensibility story around four composable primitives: a **middleware pipeline** that hooks the agent reply loop, a **mem0-backed long-term memory** middleware for cross-session recall, a **toolkit assembly** that wires skills, MCPs, and built-ins into the agent, and a **tracing extractor** that turns AgentScope messages into OpenTelemetry-compatible spans. This page documents how those pieces fit together and how to use them.

## Middleware System

The middleware package exposes a small, explicit surface. From [src/agentscope/middleware/__init__.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/middleware/__init__.py):

| Export | Purpose |
|---|---|
| `MiddlewareBase` | Abstract base for custom hooks (`on_reply`, etc.) |
| `ReplyBudgetControlMiddleware` | Enforces a weighted token budget per reply |
| `Mem0Middleware` | Long-term memory via mem0 |
| `TracingMiddleware` | OpenTelemetry tracing of replies and tool calls |
| `TTSMiddleware` | Streaming text-to-speech integration |

All built-in middlewares subclass `MiddlewareBase` and are async-generator compatible, so they can `yield` items into the reply stream. For example, `ReplyBudgetControlMiddleware` ([src/agentscope/middleware/_budget.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/middleware/_budget.py)) accumulates `input_token_weight * input_tokens + output_token_weight * output_tokens`, and once the per-reply budget is hit it injects a `<system-reminder>` hint and forces `tool_choice="none"`. State persists across human-in-the-loop interruptions because it lives in `AgentState.middle_context` and is cleared on `ReplyEndEvent`.

The agent config object wires these middlewares via fields on `ReActConfig` and `ContextConfig` in [src/agentscope/agent/_config.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/agent/_config.py), where you also find `trigger_ratio` (default `0.8`) and `reserve_ratio` (default `0.1`) for context compression — the maximum allowed `trigger_ratio` is capped at `0.9` to reserve headroom for the compression call itself.

## Long-Term Memory via mem0

The `agentscope.middleware` long-term memory layer is mem0-only today ([src/agentscope/middleware/_longterm_memory/__init__.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/middleware/_longterm_memory/__init__.py)). `Mem0Middleware` supports three modes — `static_control`, `agent_control`, and `both` — chosen at construction:

- **`agent_control`**: middleware is a no-op on the reply path; the LLM calls `search_memory` / `add_memory` itself.
- **`static_control` / `both`**: middleware pre-fetches memories from mem0 on the user's query, then appends a `HintBlock` right after the user message in `state.context` (mirroring AgentScope 1.x's `_retrieve_from_long_term_memory` slot), and finally writes the new exchange back via `_dispatch_write`. Writes are awaited inline when `await_write=True`; otherwise they are scheduled as background tasks. Source: [src/agentscope/middleware/_longterm_memory/_mem0/_middleware.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/middleware/_longterm_memory/_mem0/_middleware.py).

The agent-side tools live in [src/agentscope/middleware/_longterm_memory/_mem0/_tools.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/middleware/_longterm_memory/_mem0/_tools.py). `add_memory` requires both `thinking` (audit-only, not persisted) and `content` (a list of standalone sentences); `is_concurrency_safe=False` because mem0's underlying vector store can hold exclusive locks (see also community discussion [#1660](https://github.com/agentscope-ai/agentscope/issues/1660) on lock contention in containerized deployments).

For production, the FastAPI service layer (`agentscope.app`) injects `user_id` from the `X-User-ID` header and exposes an `extra_agent_middlewares` factory so a shared `AsyncMemory` client (with Qdrant) is built once at module scope, not per request. Source: [examples/long_term_memory/mem0/README.md](https://github.com/agentscope-ai/agentscope/blob/main/examples/long_term_memory/mem0/README.md).

## Toolkit Assembly: Skills, MCPs, and Built-Ins

The toolkit for a single chat turn is composed in `get_toolkit` ([src/agentscope/app/_service/_toolkit.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/app/_service/_toolkit.py)). Sources are attached in a deterministic order:

1. Workspace builtins (`Bash`, `Read`, `Write`, `Grep`, …).
2. Planning tools (`TaskCreate`, `TaskList`, `TaskGet`, `TaskUpdate`).
3. Background-task control (`ToolStop`).
4. Schedule control (`ScheduleCreate`/`View`/`Delete`/`List`) — only when the session has a model configured.
5. Team tools — selected inline by `agent_record.source`: workers (`source='team'`) get only `TeamSay`; leaders (`source='user'`) get `TeamCreate`, `AgentCreate`, `TeamSay`, `TeamDelete`.
6. Caller-supplied extras (`extra_factory`).

Workspace **skills** and **MCPs** are passed as the toolkit's `skills_or_loaders` and `mcps` parameters, not merged into the builtin list. Skills are loaded per-workspace, so each session sees the skill catalog resolved by its `WorkspaceBase`. The framework-builtin team tools are documented in [src/agentscope/app/_tools/__init__.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/app/_tools/__init__.py), and an example precondition check (session must exist, must not already belong to a team) is implemented in [src/agentscope/app/_tools/_team_create.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/app/_tools/_team_create.py).

> **Community note.** Issue [#1453](https://github.com/agentscope-ai/agentscope/issues/1453) reports that an agent sometimes skips its `SKILL.md` and falls back to `execute_shell_command`. In AgentScope's design the skill catalog is exposed to the model via the toolkit — the model is expected to consult the skill loader before falling back to a generic tool. If you observe this behavior, verify that the skill directory is registered on the active `WorkspaceBase` and that the model prompt advertises the skill catalog (skills are loaded, not auto-invoked).

## Tracing & Observability

Tracing is implemented as another middleware ([src/agentscope/middleware/_tracing/_extractor.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/middleware/_tracing/_extractor.py)). `_format_msgs_for_tracing` walks `Msg` content blocks, converts each block into a part (`text`, `tool_use`, `tool_result`, etc.), and emits `{role, parts, name, finish_reason: "stop"}` dictionaries — the shape expected by OpenInference/OpenTelemetry GenAI semantic conventions. A defensive fallback path returns an empty list rather than raising if message objects lack expected attributes, so a single malformed span never aborts a reply.

Combined with `TracingMiddleware`, the agent reply, model call, and tool execution all become spans. The extractor accepts either a single `Msg` or a list, so middleware authors can pass either shape through `_format_msgs_for_tracing(msgs)` and trust the result.

## Data Flow Summary

```mermaid
flowchart LR
    User[User Input] --> Reply[Agent Reply]
    Reply --> Mem0[Mem0Middleware\nstatic_control / agent_control]
    Mem0 --> Hint[HintBlock injected\nin state.context]
    Reply --> Budget[ReplyBudgetControlMiddleware]
    Budget --> Toolkit[Toolkit: skills + MCPs + builtins]
    Toolkit --> Tools[Tool Execution]
    Reply --> Trace[TracingMiddleware\nOTel spans]
    Reply --> Out[Reply Output]
    Mem0 -. async write .-> Mem0Store[(mem0 / Qdrant)]
```

## See Also

- Agent configuration reference (`ReActConfig`, `ContextConfig`, `ModelConfig`): [src/agentscope/agent/_config.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/agent/_config.py)
- FastAPI service entry point and `extra_agent_middlewares` factory: [examples/long_term_memory/mem0/README.md](https://github.com/agentscope-ai/agentscope/blob/main/examples/long_term_memory/mem0/README.md)
- Web UI build configuration: [examples/web_ui/package.json](https://github.com/agentscope-ai/agentscope/blob/main/examples/web_ui/package.json)
- RFC tracking deterministic memory middleware ("VantaGrid"): [Issue #1474](https://github.com/agentscope-ai/agentscope/issues/1474)

---

<a id='page-6'></a>

## Workspaces, TTS & Audio

### Related Pages

Related topics: [Permissions, MCP & Workspace Manager](#page-3), [Agent Service: FastAPI Backend, Multi-Tenancy & Agent Teams](#page-7)

<details>
<summary>Related Source Files</summary>

The following source files were used to generate this page:

- [src/agentscope/app/_app.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/app/_app.py)
- [src/agentscope/app/_service/_toolkit.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/app/_service/_toolkit.py)
- [src/agentscope/app/_tools/__init__.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/app/_tools/__init__.py)
- [src/agentscope/app/_tools/_team_create.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/app/_tools/_team_create.py)
- [src/agentscope/app/middleware/_tool_offload_middleware.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/app/middleware/_tool_offload_middleware.py)
- [src/agentscope/agent/_config.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/agent/_config.py)
- [README.md](https://github.com/agentscope-ai/agentscope/blob/main/README.md)
</details>

# Workspaces, TTS & Audio

AgentScope is a multi-agent platform whose agent runtime is built around three coordinated layers: a **workspace** that gives the agent a sandboxed operating environment (shell, file system, skills, MCPs), a **toolkit** that exposes the workspace as callable tools, and a set of **model integrations** (text and increasingly multimodal — text-to-speech and streaming audio) that drive the reasoning loop. This page summarizes how workspaces are assembled inside the FastAPI service and how audio / TTS capabilities are referenced from the runtime, including community context that affects installation and usage.

## Workspace Concept and Resolution

Every chat turn in the AgentScope service runs inside a `WorkspaceBase` instance resolved by a `WorkspaceManagerBase`. The app factory in `src/agentscope/app/_app.py` requires a `workspace_manager` argument and threads it into the request lifecycle, so each `(user_id, session_id)` pair gets a consistent workspace across turns. The `create_app` docstring makes the workspace manager a required dependency rather than an optional one, because every chat run is expected to read, write, or execute against a sandboxed environment. Source: [src/agentscope/app/_app.py:create_app](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/app/_app.py).

The `get_toolkit` function in `src/agentscope/app/_service/_toolkit.py` is the single assembly point that converts a resolved `WorkspaceBase` into a `Toolkit` the agent can call. Its docstring enumerates the tool sources in attachment order: workspace builtins (Bash, Read, Write, Grep, …) come first, followed by planning tools, background-task control, schedule control, team tools, and any caller-supplied extras. The workspace's skills and MCPs are passed in as the toolkit's `skills_or_loaders` and `mcps` parameters. Source: [src/agentscope/app/_service/_toolkit.py:get_toolkit](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/app/_service/_toolkit.py).

```mermaid
flowchart LR
    A[WorkspaceManagerBase] -->|resolves per session| B(WorkspaceBase)
    B -->|builtins| C[Toolkit]
    B -->|skills| C
    B -->|MCPs| C
    C --> D[ReAct Agent]
    D -->|tool calls| B
```

The design intent — that one toolkit is built per chat turn from a stable workspace — is what allows the agent to perform file I/O and shell execution through uniform tool calls without each tool having to know about the broader session state.

## Workspace Tools and the Skill Pipeline

Workspace builtins are the agent's primary interface to the sandbox. They are attached first to the toolkit so that file and shell operations are always available, even when the user has not registered any MCP or skill. The `app/_tools/__init__.py` module is the home of the *framework* tools (as opposed to workspace builtins) — things like `TeamCreate`, `AgentCreate`, `TeamSay`, and `TeamDelete` — and the docstring is explicit that these bind to `StorageBase` + `MessageBus` plus the request-scoped `user_id` / `session_id` / `agent_id` at assembly time, then call storage directly inside `__call__`. Source: [src/agentscope/app/_tools/__init__.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/app/_tools/__init__.py).

A representative example is `TeamCreate` in `src/agentscope/app/_tools/_team_create.py`, which reads the current session record, refuses to create a second team if one is already attached, persists a `TeamRecord`, and updates the session's `team_id`. This pattern — read fresh state, mutate, write back — is the standard contract for workspace-adjacent tools in the service layer. Source: [src/agentscope/app/_tools/_team_create.py:TeamCreate.__call__](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/app/_tools/_team_create.py).

The skills pipeline is the more recent extension. Community issue #1453 reports that an agent triggered a `unit-converter` skill but bypassed its `SKILL.md` and fell back to a generic shell tool. This is a real failure mode of skill-driven workflows: intent recognition must hand off to skill document loading before the generic toolset takes over, and the toolkit's `skills_or_loaders` parameter is the extension point. Workspace skills (Markdown files under the workspace) and MCP loaders both flow through that parameter, so any fix to skill-vs-generic dispatch lives in the toolkit assembly logic, not in the workspace itself. Source: [src/agentscope/app/_service/_toolkit.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/app/_service/_toolkit.py).

## Audio, TTS, and the Omni Runtime

The README documents AgentScope v2.0.2 with the change `feat(omni): streaming audio + live captions for DashScope/OpenAI omni` (PR #1701), and `feat(agent-team): support custom subagent templates in agent service` (PR mentioned in the release notes). These land in the **omni** runtime path, which is the multimodal side of the platform. The runtime no longer treats the model as text-only; it streams audio chunks and renders live captions into the same event stream that downstream middleware consumes. Source: [README.md](https://github.com/agentscope-ai/agentscope/blob/main/README.md) (Release v2.0.2 section).

For agent authors, the practical consequence is that the `Agent` configuration in `src/agentscope/agent/_config.py` accommodates the new modalities. `ReActConfig` still governs the reasoning loop (`max_iters`, `stop_on_reject`), while memory and tool-result limits (e.g. `tool_result_limit: int = 50000`) cap how much audio transcript or tool output a single step can carry. The memory compression block exposes a `summary_template` and a structured `SummarySchema`, which become the schema the compression model fills when long audio or tool histories are summarized. Source: [src/agentscope/agent/_config.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/agent/_config.py).

Background tool results in the audio/omni path are also surfaced as system notifications. The `_tool_offload_middleware.py` snippet shows a background tool completion that wraps the response content with `<system-notification>` tags and pushes the hint through `message_bus.inbox_push` plus `enqueue_wakeup` — the same delivery path a team message uses, which keeps audio and tool events on one inbox. Source: [src/agentscope/app/middleware/_tool_offload_middleware.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/app/middleware/_tool_offload_middleware.py).

## Community Context and Known Issues

Two community threads are directly relevant to workspaces and the audio stack:

- **#1660 — Ripgrep as an optional dependency.** The default workspace toolset includes `Grep`, which under the hood uses `ripgrep`. On Alibaba Cloud Linux (and other non-standard glibc/musl environments) pip falls back to a source build of ripgrep, which is slow and fragile even though ripgrep is only needed for the code-search builtin. The thread argues for making it an optional extra so that installs without `code_search` skip the compilation. Source: [README.md](https://github.com/agentscope-ai/agentscope/blob/main/README.md) (Installation section).
- **#1453 — Skill execution bypass.** As described above, the skill loader path is sometimes skipped in favor of generic tools. Until a deterministic intent→skill loader is wired into the toolkit assembly, users who depend on `SKILL.md` workflows should verify that the workspace's skills directory is mounted and that `skills_or_loaders` actually resolves to the expected loaders. Source: [src/agentscope/app/_service/_toolkit.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/app/_service/_toolkit.py).

## See Also

- Agent configuration reference (in this wiki)
- Toolkit assembly and middleware pipeline (in this wiki)
- Memory middleware (mem0) (in this wiki)
- Tracer and observability (in this wiki)

---

<a id='page-7'></a>

## Agent Service: FastAPI Backend, Multi-Tenancy & Agent Teams

### Related Pages

Related topics: [Framework Overview & Architecture](#page-1), [Web UI: Frontend, Pages & Hooks](#page-8)

<details>
<summary>Related Source Files</summary>

The following source files were used to generate this page:

- [src/agentscope/app/_app.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/app/_app.py)
- [src/agentscope/app/__init__.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/app/__init__.py)
- [src/agentscope/app/_service/_toolkit.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/app/_service/_toolkit.py)
- [src/agentscope/app/_tools/__init__.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/app/_tools/__init__.py)
- [src/agentscope/app/_tools/_team_create.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/app/_tools/_team_create.py)
- [src/agentscope/middleware/__init__.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/middleware/__init__.py)
- [src/agentscope/middleware/_longterm_memory/__init__.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/middleware/_longterm_memory/__init__.py)
- [src/agentscope/middleware/_longterm_memory/_mem0/_middleware.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/middleware/_longterm_memory/_mem0/_middleware.py)
- [src/agentscope/middleware/_budget.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/middleware/_budget.py)
- [README.md](https://github.com/agentscope-ai/agentscope/blob/main/README.md)
- [examples/agent_service/README.md](https://github.com/agentscope-ai/agentscope/tree/main/examples/agent_service)
- [examples/long_term_memory/mem0/README.md](https://github.com/agentscope-ai/agentscope/tree/main/examples/long_term_memory/mem0)
</details>

# Agent Service: FastAPI Backend, Multi-Tenancy & Agent Teams

The **Agent Service** is AgentScope 2.0's production-grade serving layer, exposed as a configurable [FastAPI](https://fastapi.tiangolo.com/) application via the public entry point `agentscope.app.create_app` ([src/agentscope/app/_app.py:1](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/app/_app.py)). It is documented in the README as "an extensible FastAPI based multi-tenancy, multi-session agent service with pre-built Web UI" ([README.md:1](https://github.com/agentscope-ai/agentscope/blob/main/README.md)) and powers the chat-style deployment shown in `examples/agent_service`. The service is intentionally decoupled into three pluggable backends — `StorageBase`, `MessageBus`, and `WorkspaceManagerBase` — so persistence, transport, and tool execution can each be scaled independently.

## 1. Architecture & App Factory

The `create_app(...)` factory is the single construction point. It wires up routers, manages lifecycles, and accepts custom middlewares and sub-agent templates ([src/agentscope/app/_app.py:1-60](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/app/_app.py)). Three required backends are documented in the docstring:

| Backend | Purpose | Lifecycle |
|---|---|---|
| `StorageBase` | Persistence (sessions, agents, messages, teams) | Managed via `__aenter__` / `__aexit__` |
| `MessageBus` | Cross-session inbox delivery, idle-session triggers | Same lifespan handling |
| `WorkspaceManagerBase` | Per-session tool sandbox (local, Docker, E2B) | Required for every chat run |

```mermaid
flowchart LR
    Client[Web UI / HTTP Client] -->|HTTP + SSE| FastAPI[create_app FastAPI]
    FastAPI --> Router[Chat / Agent Routers]
    Router --> Toolkit[get_toolkit per session]
    Toolkit --> Storage[(StorageBase)]
    Toolkit --> Bus[MessageBus]
    Toolkit --> WS[WorkspaceManager]
    Toolkit --> MW[Middleware Chain]
    MW --> Agent[Agent + Tools]
    Storage -.tenancy.-> User[user_id isolation]
    Bus -.delivery.-> Inbox[Cross-session inbox]
```

The factory can be run standalone (e.g. `uvicorn.run(app, ...)`) or mounted under a prefix on an existing app via `root.mount("/agentscope", agentscope_app)` ([src/agentscope/app/_app.py:1-60](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/app/_app.py)). All built-in routers register automatically; `extra_middlewares` lets the host add framework-level hooks, while `extra_agent_middlewares` injects request-scoped middleware such as Mem0.

## 2. Multi-Tenancy & Multi-Session Model

Tenants are identified by the `X-User-ID` HTTP header, which is propagated through the service and surfaces inside request-scoped factories. The library example for Mem0 shows the canonical pattern: a single `AsyncMemory` client is built at module scope (because "local OSS Qdrant takes an exclusive lock on its storage folder; per-request construction would deadlock under concurrent traffic") and reused across all requests via `long_term_memory_factory(user_id, agent_id, session_id)` ([examples/long_term_memory/mem0/README.md:1-60](https://github.com/agentscope-ai/agentscope/blob/main/examples/long_term_memory/mem0/README.md)).

Sessions are first-class records: `Mem0Middleware.__init__` validates `user_id` (rejecting empty strings) and stores the per-tenant identifier used to scope every memory read/write ([src/agentscope/middleware/_longterm_memory/_mem0/_middleware.py:1-60](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/middleware/_longterm_memory/_mem0/_middleware.py)). Quickstart guidance in `examples/agent_service/README.md` recommends Redis for storage and bus in development: `docker run --rm -p 6379:6379 redis:7` ([examples/agent_service/README.md:1-40](https://github.com/agentscope-ai/agentscope/blob/main/examples/agent_service/README.md)).

## 3. Agent Teams & Toolkit Assembly

The agent-team feature is the headline 2.0 capability, introduced in the June 2026 news entry "Agent Team supported" ([README.md:1-40](https://github.com/agentscope-ai/agentscope/blob/main/README.md)) and exposed in v2.0.2 with "support custom subagent templates in agent service". Teams are *not* a separate process — they are persisted as `TeamRecord` rows in `StorageBase` and orchestrated through four framework-builtin tools.

`get_toolkit(...)` in [src/agentscope/app/_service/_toolkit.py:1-40](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/app/_service/_toolkit.py) is the single assembly point. It composes, in order:

1. Workspace builtins (Bash, Read, Write, Grep, …)
2. Planning tools (`TaskCreate`, `TaskList`, `TaskGet`, `TaskUpdate`)
3. Background-task control (`ToolStop`) and schedule control (`Schedule*`)
4. Skills and MCP integrations
5. Team participation tools (`AgentCreate`, `TeamCreate`, `TeamSay`, `TeamDelete`)
6. Caller-supplied extras via `extra_factory`
7. `sub_agent_templates` for custom worker shapes

Tool visibility is governed by `agent.source` rather than by a per-call refresh: `source='user'` agents always see the full leader-side toolset, while `source='team'` workers see only `TeamSay` ([src/agentscope/app/_tools/__init__.py:1-25](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/app/_tools/__init__.py)). Each tool checks storage state at `__call__` time, so a single chat run can `TeamCreate` and then `AgentCreate` immediately afterwards without any toolkit refresh.

The `TeamCreate` tool enforces a single-team-per-session invariant: if `session.team_id` is already set, it returns a `ToolResultState.ERROR` chunk advising the user to "dissolve the current one with TeamDelete first" ([src/agentscope/app/_tools/_team_create.py:1-60](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/app/_tools/_team_create.py)). It then writes a `TeamRecord` and binds it to the session via `set_session_team_id`.

## 4. Middleware Integration & Community Notes

The middleware package re-exports `MiddlewareBase`, `Mem0Middleware`, `TracingMiddleware`, `ReplyBudgetControlMiddleware`, and `TTSMiddleware` ([src/agentscope/middleware/__init__.py:1-15](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/middleware/__init__.py)). The long-term memory sub-package currently exposes only the mem0 backend, with the docstring noting "Future backends (e.g. dedicated vector stores, custom user-profile services) can sit alongside `_mem0/` under this package" ([src/agentscope/middleware/_longterm_memory/__init__.py:1-15](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/middleware/_longterm_memory/__init__.py)).

`ReplyBudgetControlMiddleware` demonstrates how per-reply state survives human-in-the-loop (HITL) interruptions: it persists counters in `agent.state.middle_context` keyed by middleware key, and cleans up on `ReplyEndEvent` ([src/agentscope/middleware/_budget.py:1-50](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/middleware/_budget.py)). The same pattern lets `Mem0Middleware` track its write state across the long-running `on_reply` generator.

Two recurring community concerns map directly to this surface:

- **SKILL.md loading (issue #1453)**: Users have reported agents that should consult a `SKILL.md` instead invoking generic shell tools. Skills are integrated as one of the toolkit sources assembled in `_service/_toolkit.py`, but there is no separate "intent → load SKILL.md" router — routing happens through the model's own tool selection. If a skill is intended to be mandatory, it must be the only tool matching the request or be pinned via the permission system.
- **Optional ripgrep (issue #1660)**: The README's headline feature is "Workspace / Sandbox Support ... with built-in backends for local, Docker, and E2B" ([README.md:1-40](https://github.com/agentscope-ai/agentscope/blob/main/README.md)). The grep-style workspace tools compile ripgrep from source on non-glibc platforms; deployments on Alibaba Cloud Linux should consider pre-installing a binary or omitting those tools, since ripgrep is only required for code-search/RAG features and is not needed for the core agent service.
- **Memory RFCs (issue #1474)**: External proposals like VantaGrid have been raised for deterministic memory middleware. These would slot into the `agentscope.middleware._longterm_memory` package alongside `_mem0/`, following the pattern flagged in its `__init__.py`.

## See Also

- [AgentScope 2.0 README](https://github.com/agentscope-ai/agentscope/blob/main/README.md)
- [examples/agent_service quickstart](https://github.com/agentscope-ai/agentscope/tree/main/examples/agent_service)
- [examples/long_term_memory/mem0 service-mode integration](https://github.com/agentscope-ai/agentscope/tree/main/examples/long_term_memory/mem0)
- [src/agentscope/app module index](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/app/__init__.py)
- [src/agentscope/middleware package](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/middleware/__init__.py)

---

<a id='page-8'></a>

## Web UI: Frontend, Pages & Hooks

### Related Pages

Related topics: [Agent Service: FastAPI Backend, Multi-Tenancy & Agent Teams](#page-7), [Skills, Long-Term Memory, Middleware & Tracing](#page-5)

<details>
<summary>Related Source Files</summary>

The following source files were used to generate this page:

- [examples/web_ui/package.json](https://github.com/agentscope-ai/agentscope/blob/main/examples/web_ui/package.json)
- [README.md](https://github.com/agentscope-ai/agentscope/blob/main/README.md)
- [src/agentscope/app/_app.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/app/_app.py)
- [src/agentscope/app/_tools/__init__.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/app/_tools/__init__.py)
- [src/agentscope/agent/_agent.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/agent/_agent.py)
</details>

# Web UI: Frontend, Pages & Hooks

## Overview and Scope

AgentScope ships a pre-built Web UI together with its FastAPI service to give users a ready-to-run graphical surface over the multi-tenant, multi-session agent runtime. As stated in the project README, the framework offers an "extensible FastAPI based **multi-tenancy**, **multi-session** agent service with pre-built Web UI in `examples/web_ui`." The Web UI is therefore not a separate product but a frontend reference implementation that lives next to the Python backend under [`examples/web_ui/`](https://github.com/agentscope-ai/agentscope/tree/main/examples/web_ui).

Source: [README.md](https://github.com/agentscope-ai/agentscope/blob/main/README.md)

The frontend is responsible for:

- Presenting chat sessions to end users and rendering streamed model output.
- Surfacing agentic artefacts produced by the backend (background-tool completion hints, team messages, task-plan updates).
- Acting as the human-in-the-loop surface where the **Permission System** can approve, reject, or bypass tool calls before they execute.
- Talking to the FastAPI app created by [`create_app()`](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/app/_app.py) for session lifecycle, message streaming, and event delivery.

The backend exposes a unified **Event System** to the frontend; the same event bus is what the Web UI subscribes to in order to render assistant text, tool calls, and human-in-the-loop prompts. Source: [README.md](https://github.com/agentscope-ai/agentscope/blob/main/README.md)

## Package Configuration and Tooling

The Web UI workspace is managed with **pnpm**, and its frontend package is described in [`examples/web_ui/package.json`](https://github.com/agentscope-ai/agentscope/blob/main/examples/web_ui/package.json). The package file reveals a focused dev-tooling setup that the team enforces via CI.

```json
"devDependencies": {
  "concurrently": "^8.2.2",
  "eslint-config-prettier": "^10.1.8",
  "eslint-plugin-prettier": "^5.5.5",
  "husky": "^9.1.7",
  "lint-staged": "^17.0.5",
  "prettier": "^3.8.3"
}
```

Source: [examples/web_ui/package.json](https://github.com/agentscope-ai/agentscope/blob/main/examples/web_ui/package.json)

| Tool | Role in the Web UI |
| --- | --- |
| `concurrently` | Run the frontend dev server, backend, and any auxiliary watchers in parallel from a single `pnpm dev` command. |
| `eslint-config-prettier` + `eslint-plugin-prettier` | Lint TypeScript / TSX while deferring all formatting decisions to Prettier, eliminating rule conflicts. |
| `husky` + `lint-staged` | Run ESLint and Prettier only against staged files before each commit, keeping the Web UI diffable and CI-green. |
| `prettier` | Single source of truth for formatting HTML, TSX, JSON, and Markdown files (the `format:html` script uses it directly). |

The `format:html` script (`prettier --write`) is a deliberate hint that the Web UI contains hand-authored HTML entry points or static templates alongside the React tree, not only generated JSX. Source: [examples/web_ui/package.json](https://github.com/agentscope-ai/agentscope/blob/main/examples/web_ui/package.json)

This devDependency set was the motivation for the **v2.0.2** release change *"ci(webui): add format and build checks"* (PR [#1821](https://github.com/agentscope-ai/agentscope/pull/1821)), which makes the Web UI's lint/format pipeline a first-class CI step rather than a developer-only convention. Source: [README.md (v2.0.2 changelog)](https://github.com/agentscope-ai/agentscope/blob/main/README.md)

## Pages, Hooks, and Runtime Wiring

The Web UI is organized around a small set of pages that map directly onto backend concepts:

```mermaid
flowchart LR
    UI[Web UI Frontend] -->|HTTP / SSE| FastAPI[create_app FastAPI]
    FastAPI --> Bus[MessageBus]
    FastAPI --> Store[StorageBase]
    FastAPI --> WS[WorkspaceBase]
    UI -. HITL .-> Perm[Permission Engine]
    Perm -. approve/reject .-> FastAPI
```

The chat page consumes streamed events from the FastAPI app assembled by `create_app()`, which mandates three collaborators — a `StorageBase`, a `MessageBus`, and a `WorkspaceManagerBase` — before it will start. Source: [src/agentscope/app/_app.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/app/_app.py)

The same app-level resources drive the **team** and **agent** pages through framework-supplied tools (`TeamCreate`, `AgentCreate`, `TeamSay`, `TeamDelete`). These tools are constructed at agent-assembly time and read live `StorageBase` state on every invocation, so the Web UI never has to refresh its toolkit — only the underlying storage row changes. Source: [src/agentscope/app/_tools/__init__.py](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/app/_tools/__init__.py)

Hooks inside the Web UI are therefore best thought of as **event-typed subscribers**: each page registers interest in a slice of the unified event stream (model deltas, tool-call chunks, completion hints from background tasks, permission requests) and the FastAPI app pushes events through the `MessageBus`. Source: [README.md](https://github.com/agentscope-ai/agentscope/blob/main/README.md)

## Common Failure Modes and Community Notes

Two recurring concerns from the community surface relevant failure modes for the Web UI's frontend:

- **SKILL execution gaps (issue #1453).** When a user's question triggers a named skill such as `unit-converter`, the agent must dynamically read `SKILL.md` before falling back to a generic tool like `execute_shell_command`. The Web UI's chat page surfaces this distinction because it renders both skill activations and raw tool calls; an operator watching the stream can see the agent skip the skill flow and intervene. Source: [issue #1453 context](https://github.com/agentscope-ai/agentscope/issues/1453)

- **Optional native dependencies on non-standard Linux distros (issue #1660).** `ripgrep` is currently a hard install dependency even though only the code-search/RAG surface of the Web UI requires it. The frontend's search panel does not need rg to render, but the install step blocks otherwise working environments (e.g. Alibaba Cloud Linux). Marking rg optional is an open feature request that would let the Web UI ship on these platforms without source compilation. Source: [issue #1660 context](https://github.com/agentscope-ai/agentscope/issues/1660)

- **Slowed release cadence (issue #1296).** Users have publicly asked whether focus on CoPaw has slowed Web UI fixes; the v2.0.2 release — which bundles `ci(webui)` hardening — is the maintainers' direct response, and the Web UI now has its own format/build CI gate. Source: [issue #1296 context](https://github.com/agentscope-ai/agentscope/issues/1296) and [README.md (v2.0.2 changelog)](https://github.com/agentscope-ai/agentscope/blob/main/README.md)

## See Also

- [Agent Service & Multi-Tenancy](./Agent-Service-and-Multi-Tenancy.md) — the FastAPI app behind the Web UI
- [Event System & Human-in-the-Loop](./Event-System-and-HITL.md) — the unified event bus the UI subscribes to
- [Toolkit & Tool Assembly](./Toolkit-and-Tool-Assembly.md) — how `get_toolkit()` decides which tools the UI can invoke
- [Permission System](./Permission-System.md) — the engine the UI uses for tool-call approvals

---

<!-- evidence_pipeline_checked: true -->
<!-- evidence_injected: true -->

---

## Pitfall Log

Project: agentscope-ai/agentscope

Summary: Found 6 structured pitfall item(s), including 0 high/blocking item(s). Top priority: Capability evidence risk - Capability evidence risk requires verification.

## 1. Capability evidence risk - Capability evidence risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: README/documentation is current enough for a first validation pass.
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: capability.assumptions | https://github.com/agentscope-ai/agentscope

## 2. Maintenance risk - Maintenance risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: Project evidence flags a maintenance risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: evidence.maintainer_signals | https://github.com/agentscope-ai/agentscope

## 3. Security or permission risk - Security or permission risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: no_demo
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: downstream_validation.risk_items | https://github.com/agentscope-ai/agentscope

## 4. Security or permission risk - Security or permission risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: no_demo
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: risks.scoring_risks | https://github.com/agentscope-ai/agentscope

## 5. Maintenance risk - Maintenance risk requires verification

- Severity: low
- Evidence strength: source_linked
- Finding: issue_or_pr_quality=unknown。
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: evidence.maintainer_signals | https://github.com/agentscope-ai/agentscope

## 6. Maintenance risk - Maintenance risk requires verification

- Severity: low
- Evidence strength: source_linked
- Finding: release_recency=unknown。
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: evidence.maintainer_signals | https://github.com/agentscope-ai/agentscope

<!-- canonical_name: agentscope-ai/agentscope; human_manual_source: deepwiki_human_wiki -->
