# How the v3 `/v3/scenario/*` Endpoints Manage L2 Scenarios in TencentDB Agent Memory

> Discover how v3 scenario endpoints manage L2 scenarios via CRUD operations. Learn about listing, reading, writing, deleting, and counting files with enhanced security.

- Repository: [Tencent Cloud/TencentDB-Agent-Memory](https://github.com/TencentCloud/TencentDB-Agent-Memory)
- Tags: internals
- Published: 2026-08-31

---

**The v3 `/v3/scenario/*` endpoints provide five CRUD operations for managing L2 scenarios: `ls` to list files, `read` to retrieve markdown content, `write` to create or update with versioning, `rm` to delete, and `count` to tally files—all enforcing team-agent-user isolation and path-traversal protection.**

The L2 scenario layer in TencentDB Agent Memory stores complete markdown files representing structured scenarios or "scenes." These files power contextual memory for AI agents, with the v3 data-plane API exposing granular control over this content. All five scenario endpoints share a unified architecture for isolation, validation, and storage abstraction, implemented centrally in [`MemoryCore/src/gateway/v2-router.ts`](https://github.com/TencentCloud/TencentDB-Agent-Memory/blob/main/MemoryCore/src/gateway/v2-router.ts).

---

## The Five v3 `/v3/scenario/*` Endpoints

Each endpoint follows a consistent POST-over-HTTP pattern with JSON bodies, returning standardized envelopes containing `code`, `message`, `request_id`, and `data`.

### POST `/v3/scenario/ls` — List Scenario Files

**`handleScenarioLs`** retrieves the **scene index**: an array of scenario file paths with their metadata.

The handler accepts an optional `path_prefix` to scope the listing, then calls `storage.listObjects` filtered by L2 isolation fields (`team_id`, `agent_id`, `user_id`). Each returned entry contains `path`, `summary`, `updated_at`, and related fields.

Router registration appears at **line 424** of [`v2-router.ts`](https://github.com/TencentCloud/TencentDB-Agent-Memory/blob/main/v2-router.ts):

```typescript
// Request shape validated by scenarioLsRequestSchema
{
  path_prefix?: string  // "" or omitted for root listing
}

// Response data
{
  scenes: [
    { path: "scenarios/onboarding.md", summary: "User onboarding flow", updated_at: "2024-01-15T09:23:00Z", version: 3 },
    ...
  ]
}

```

### POST `/v3/scenario/read` — Retrieve Full Content

**`handleScenarioRead`** fetches the complete markdown of a single scenario, **internal meta block intact**.

The `path` parameter undergoes **safePath** validation via Zod schema to prevent directory traversal. The handler injects isolation fields into the request context before reading from storage. The raw response includes the `-----META-START----- … -----META-END-----` wrapper that front-end code later strips.

See **line 425** for implementation.

```typescript
// Request
{ path: "scenarios/known_issue_resolution.md" }

// Response data includes raw markdown:
{
  content: "-----META-START-----\nversion: 2\nupdated_at: ...\n-----META-END-----\n# Known Issue Resolution\n\nWhen users report..."

}

```

### POST `/v3/scenario/write` — Create or Update with Versioning

**`handleScenarioWrite`** implements **upsert semantics** with automatic version incrementing.

The request body validates against **`scenarioWriteRequestSchema`** (defined in [`v2-schemas.ts`](https://github.com/TencentCloud/TencentDB-Agent-Memory/blob/main/v2-schemas.ts) around line 269). New files start at `v1`; each subsequent write increments the version. The handler persists content, updates metadata (summary, timestamps), and returns the new version.

See **line 426** for handler registration.

```typescript
// Request
{
  path: "scenarios/escalation_playbook.md",
  content: "# Escalation Playbook\n\n1. Verify customer tier...",

  summary: "Tiered escalation procedures"
}

// Response data
{
  version: 4,
  updated_at: "2024-01-16T14:32:00Z"
}

```

### POST `/v3/scenario/rm` — Delete Scenario Files

**`handleScenarioRm`** performs **atomic deletion** of a scenario by path.

Validated by **`scenarioRmRequestSchema`** using the same `safePath` protection, the handler invokes `storage.deleteObject` and returns a simple success indicator. The file and its index entry disappear together.

See **line 427** for implementation.

```typescript
// Request
{ path: "scenarios/deprecated_workflow.md" }

// Response
{ success: true }

```

### POST `/v3/scenario/count` — Count Matching Scenarios

**`handleScenarioCount`** returns the **total number of scenario files** matching an optional prefix.

This endpoint reuses the listing logic but returns only the aggregate count—useful for pagination UIs or quota enforcement. Validation uses `scenarioCountRequestSchema` (line 141 in [`v2-schemas.ts`](https://github.com/TencentCloud/TencentDB-Agent-Memory/blob/main/v2-schemas.ts)).

See **line 428** for handler registration.

```typescript
// Request
{ path_prefix: "scenarios/2024-q1/" }

// Response data
{ count: 47 }

```

---

## Core Architecture Mechanisms

### Isolation Enforcement via `resolveIsolation`

All five endpoints require four identifiers: `team_id`, `agent_id`, `user_id`, and `task_id`. These may appear in request bodies or `x-tdai-*` headers. The `resolveIsolation` function (lines **990–1000** in [`v2-router.ts`](https://github.com/TencentCloud/TencentDB-Agent-Memory/blob/main/v2-router.ts)) normalizes and validates these fields, rejecting incomplete requests with **HTTP 422**.

This ensures **strict data separation** between organizational boundaries—no scenario file is accessible without complete isolation context.

### Path-Traversal Protection

Every endpoint accepting a `path` parameter uses the **`safePath`** Zod validator. This strips `../` components and anchors paths within the service's storage namespace, preventing escape to parent directories or system files.

### Storage Abstraction

Handlers call **`resolveStoreForRequest`** and **`resolveStorageForRequest`** to obtain storage instances. The generic `Storage` interface allows the same endpoint code to operate over ClickHouse, local filesystem, or cloud object stores without modification.

### Versioning and Meta Block Handling

Scenario files maintain internal versioning front-end components consume. The `write` endpoint auto-increments versions; `read` returns raw content including meta wrappers. Client-side code in [`MemoryPanel/web/src/pages/ChatMemoryPage/utils/memory-utils.ts`](https://github.com/TencentCloud/TencentDB-Agent-Memory/blob/main/MemoryPanel/web/src/pages/ChatMemoryPage/utils/memory-utils.ts) handles meta block stripping for display purposes.

---

## Complete API Usage Examples

### Listing Scenarios

```typescript
const response = await fetch("http://localhost:8420/v3/scenario/ls", {
  method: "POST",
  headers: {
    "Authorization": "Bearer <KERNEL_AUTH_TOKEN>",
    "Content-Type": "application/json",
    "x-tdai-team-id": "team_prod",
    "x-tdai-agent-id": "agent_support_bot",
    "x-tdai-user-id": "user_ops_001"
  },
  body: JSON.stringify({ path_prefix: "playbooks/" })
});
const { scenes } = (await response.json()).data;

```

### Reading Scenario Content

```typescript
const response = await fetch("http://localhost:8420/v3/scenario/read", {
  method: "POST",
  headers: { /* auth and isolation headers */ },
  body: JSON.stringify({ path: "playbooks/security_incident.md" })
});
const { content } = (await response.json()).data;
// content includes -----META-START----- block

```

### Writing a New Scenario

```typescript
const response = await fetch("http://localhost:8420/v3/scenario/write", {
  method: "POST",
  headers: { /* auth and isolation headers */ },
  body: JSON.stringify({
    path: "playbooks/new_feature_announcement.md",
    content: "# New Feature: Vector Search\n\nOur latest release adds...",

    summary: "Customer-facing announcement for vector search capability"
  })
});
const { version, updated_at } = (await response.json()).data;

```

### Deleting a Scenario

```typescript
await fetch("http://localhost:8420/v3/scenario/rm", {
  method: "POST",
  headers: { /* auth and isolation headers */ },
  body: JSON.stringify({ path: "playbooks/superseded_policy.md" })
});

```

### Counting Scenarios

```typescript
const response = await fetch("http://localhost:8420/v3/scenario/count", {
  method: "POST",
  headers: { /* auth and isolation headers */ },
  body: JSON.stringify({ path_prefix: "archived/" })
});
const { count } = (await response.json()).data;

```

---

## Key Source Files

| File | Purpose | Location |
|------|---------|----------|
| [`MemoryCore/src/gateway/v2-router.ts`](https://github.com/TencentCloud/TencentDB-Agent-Memory/blob/main/MemoryCore/src/gateway/v2-router.ts) | Handler registration and core logic for all `/v3/scenario/*` endpoints | [`MemoryCore/src/gateway/v2-router.ts`](https://github.com/TencentCloud/TencentDB-Agent-Memory/blob/main/MemoryCore/src/gateway/v2-router.ts) |
| [`MemoryCore/src/gateway/v2-schemas.ts`](https://github.com/TencentCloud/TencentDB-Agent-Memory/blob/main/MemoryCore/src/gateway/v2-schemas.ts) | Zod schemas: `scenarioWriteRequestSchema`, `scenarioReadRequestSchema`, `safePath` validator | [`MemoryCore/src/gateway/v2-schemas.ts`](https://github.com/TencentCloud/TencentDB-Agent-Memory/blob/main/MemoryCore/src/gateway/v2-schemas.ts) |
| [`MemoryPanel/web/src/pages/ChatMemoryPage/utils/memory-utils.ts`](https://github.com/TencentCloud/TencentDB-Agent-Memory/blob/main/MemoryPanel/web/src/pages/ChatMemoryPage/utils/memory-utils.ts) | Client-side meta block stripping from `read` responses | [`MemoryPanel/web/src/pages/ChatMemoryPage/utils/memory-utils.ts`](https://github.com/TencentCloud/TencentDB-Agent-Memory/blob/main/MemoryPanel/web/src/pages/ChatMemoryPage/utils/memory-utils.ts) |
| [`MemoryCore/v3-api-memorycore-doc.md`](https://github.com/TencentCloud/TencentDB-Agent-Memory/blob/main/MemoryCore/v3-api-memorycore-doc.md) | Official API documentation for v3 endpoints | [`MemoryCore/v3-api-memorycore-doc.md`](https://github.com/TencentCloud/TencentDB-Agent-Memory/blob/main/MemoryCore/v3-api-memorycore-doc.md) |

---

## Summary

- **Five endpoints** provide complete L2 scenario lifecycle management: `ls`, `read`, `write`, `rm`, and `count`.

- **Mandatory isolation** via `team_id`, `agent_id`, `user_id`, and `task_id` prevents cross-tenant data access, enforced by `resolveIsolation` in [`v2-router.ts`](https://github.com/TencentCloud/TencentDB-Agent-Memory/blob/main/v2-router.ts).

- **Automatic versioning** on write operations tracks scenario evolution without manual version management.

- **Path-traversal protection** through `safePath` Zod schemas ensures storage security.

- **Storage-agnostic design** via the `Storage` interface abstraction supports multiple backends from identical endpoint code.

---

## Frequently Asked Questions

### What is an L2 scenario in TencentDB Agent Memory?

An **L2 scenario** is a complete markdown file representing a structured scene or procedural context for AI agent memory. Unlike L1 (key-value pairs) or L3 (semantic vectors), L2 stores human-readable, versioned documents that agents can reference during conversations.

### How does scenario versioning work?

Each `write` operation automatically increments an internal version counter starting from `v1`. The version and timestamps are stored in the meta block (between `-----META-START-----` and `-----META-END-----`) and returned in the API response. No manual version specification is required.

### Why do all scenario endpoints use POST instead of RESTful HTTP methods?

The v3 API design prioritizes **consistent request envelopes** and **complex filtering parameters** (like `path_prefix`) that exceed URL length limits for GET requests. POST with JSON bodies also simplifies header-based isolation and batch operations across the entire v3 surface.

### How do I strip the meta block from scenario content for display?

The reference implementation in [`MemoryPanel/web/src/pages/ChatMemoryPage/utils/memory-utils.ts`](https://github.com/TencentCloud/TencentDB-Agent-Memory/blob/main/MemoryPanel/web/src/pages/ChatMemoryPage/utils/memory-utils.ts) parses the raw markdown and removes everything between `-----META-START-----` and `-----META-END-----`. Your client code should implement similar logic, or you can use a regex like `/-----META-START-----[\s\S]*?-----META-END-----/` to isolate the content portion.