How the v3 `/v3/scenario/*` Endpoints Manage L2 Scenarios in TencentDB Agent Memory
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.
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:
// 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.
// 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 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.
// 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.
// 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).
See line 428 for handler registration.
// 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) 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 handles meta block stripping for display purposes.
Complete API Usage Examples
Listing Scenarios
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
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
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
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
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 |
Handler registration and core logic for all /v3/scenario/* endpoints |
MemoryCore/src/gateway/v2-router.ts |
MemoryCore/src/gateway/v2-schemas.ts |
Zod schemas: scenarioWriteRequestSchema, scenarioReadRequestSchema, safePath validator |
MemoryCore/src/gateway/v2-schemas.ts |
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 |
MemoryCore/v3-api-memorycore-doc.md |
Official API documentation for v3 endpoints | MemoryCore/v3-api-memorycore-doc.md |
Summary
-
Five endpoints provide complete L2 scenario lifecycle management:
ls,read,write,rm, andcount. -
Mandatory isolation via
team_id,agent_id,user_id, andtask_idprevents cross-tenant data access, enforced byresolveIsolationinv2-router.ts. -
Automatic versioning on write operations tracks scenario evolution without manual version management.
-
Path-traversal protection through
safePathZod schemas ensures storage security. -
Storage-agnostic design via the
Storageinterface 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 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.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →