# Anda Brain API 文档(含 TypeScript 类型)
Rust 现要求 Cognitive Nexus 0.13.1:Watch 触发会原子记录状态变化、`watch_fire`
活动及受保护 wake,并提供可重放回执和原生租约。服务现会独立于 Full Maintenance
调度结构化 Watch,从持久化目录发现已驱逐的注册 Space,并在重启后恢复有界扫描。
受信任 Rust 宿主现可在加载 Space 前安装 `ActionBindings`:四分支决策、澄清、固定
Attempt 和原生租约分派接入同一调度器。默认不安装生产执行器;运行时 API 已提供认证后的
待办/回答/后果接口,`BRAIN_RUNTIME_CONFIG` 可装配持久化 inbox 和明确的身份映射,
详见[运行时接入与恢复](RUNTIME_cn.md)。Space fork 不能复制原生运行身份。内部 `memory_runtime/status` 只读当前
配置,不领取任务或授予权限;现有 HTTP payload 和 token scopes 保持兼容。
批量记忆强度代谢跳过 SleepTask/Watch 运行记录;宿主结算错误通过
assessment.settlement_errors 提供给维护模型。
## 1) 通用约定
- Base URL: `http://{host}:{port}`
- 认证头:`Authorization: Bearer <token>`
- 分片部署:发送与服务端 `SHARDING_IDX` 相同的 `Shard-Id: <index>`(或 `X-Shard`);默认值为 `0`。
- 若 `ED25519_PUBKEYS` 为空或未提供,旧接口鉴权会关闭;新运行时接口仍要求真实凭据及映射,没有 CWT 验签器时独立后果 HTTP 写入不启用。
- 支持的序列化格式:
- 请求:`Content-Type: application/json | application/cbor | text/markdown`
- 响应:`Accept: application/json | application/cbor | text/markdown`
- 内容协商仅作用于成功响应体。处理器错误使用 JSON,与 `Accept` 无关;中间件限流(`429`/`503`)和未匹配路由可能返回纯文本或空响应体。
- 大多数业务接口都会返回 RPC 包装后的结构体:`RpcResponse<T>`
- MCP 客户端可使用内置的支持流式传输的 HTTP MCP 端点:`/mcp/<space_id>`,也可以使用本地 stdio server:`anda_brain mcp --space-id <space_id> [local|aws]`
CognitiveMemory 2.1 对齐说明:现有 JSON/CBOR/Markdown 请求和鉴权保持兼容;没有新增
五意图 Memory Interface 或标准 after barrier。conversation id 不是处理回执。
维护报告 `skills` 新增可选 `unsupported_reason`,说明没有配置可信学习管线,旧计数
保持零。Watch 的 `disarmed` 兼容字段也统计 Nexus 的 expired;文本 Watch 无已配置的语义求值器时保持 deferred。
模型生成的 Formation 请求不得覆盖宿主捕获的 ingest 或 msgN 绑定;学习/runtime Facet
写入返回 UnsupportedCapability。原始管理 KIP 仍接受符合 Nexus 契约的受权写入。
使用精确 `@2.0.0` schema_ref 的旧 Watch/SleepTask 不能原地改成 2.1,需要显式创建、
重连并核验替代记录后再归档旧记录。
---
## 2) TypeScript 类型定义
```ts
export type TokenScope = 'read' | 'write' | '*';
export interface RpcError {
message: string;
data?: unknown;
}
export interface RpcResponse<T> {
result?: T;
error?: RpcError;
next_cursor?: string;
}
export interface InputContext {
counterparty?: string;
agent?: string;
source?: string; // 来源线程/渠道;不是提交或消息的去重键
topic?: string;
}
export type MessageRole = 'system' | 'user' | 'assistant' | 'tool';
export type MessageContentPart =
| string
| {
type: string;
text?: string;
[k: string]: unknown;
};
export interface Message {
role: MessageRole;
content: string | MessageContentPart[];
name?: string; // user 或 tool 的名称
user?: string; // user ID
timestamp?: number; // Unix timestamp in milliseconds
}
export interface FormationInput {
messages: Message[]; // 至少包含一条非空消息(否则 400)
context?: InputContext;
timestamp?: string; // RFC 3339;统一为 UTC 毫秒格式,无效或缺省时使用接收时间
}
export interface RecallInput {
query: string; // 不能为空/纯空白(否则 400)
context?: InputContext;
budget?: RecallBudget | null;
}
export interface RecallBudget {
tokenizer?: 'o200k_base@tiktoken-rs-0.12.0';
max_tokens?: number; // 1–65536;显式启用后的默认值为 4096
context_tokens?: number; // 1–131072;默认 32768;整次规划输入规范序列化的累计上限
}
export interface MemoryPolicy {
version?: number;
memory_strength_decay_factor?: number;
recall_reinforcement?: number; // retained for stored-policy compatibility; inert
correction_penalty?: number; // retained for stored-policy compatibility; inert
decay_floor?: number;
stale_event_threshold_days?: number;
unconsolidated_max_backlog?: number;
orphan_max_count?: number;
self_test_queries_per_cycle?: number;
self_test_token_budget?: number;
recall_search_threshold?: number; // declared but not consumed yet
recall_max_rounds?: number;
recall_budget?: RecallBudget | null;
shadow_replay_sample?: number;
}
export interface MemoryCitation {
entity: string;
type?: string;
name?: string;
confidence?: number;
source?: string;
created_at?: string;
}
export interface RecallBudgetReceipt {
tokenizer: string;
token_limit: number;
tokens: number;
context_token_limit: number;
}
export interface RecallOutput {
answer: string;
found: boolean;
uncertainty?: number;
memories?: MemoryCitation[];
conversation?: number;
usage: Usage;
failed_reason?: string;
memory_budget?: RecallBudgetReceipt;
}
export interface ProbeInput {
query: string;
limit?: number;
}
export interface ProbeOutput {
found: boolean;
negative_cached: boolean;
search_exhaustive?: boolean;
hits?: MemoryCitation[];
}
export interface MemoryPinInput {
entity: string; // 图谱实体 ID,例如 C-7、P-3、A-2
pinned?: boolean; // default true
}
export interface MemoryPinOutput {
entity: string;
pinned: boolean;
updated: number; // 更改的 retention 记录数
}
export interface MemoryForgetInput {
entities: string[];
dry_run?: boolean; // default false; inspect a dry run before deletion
}
export interface MemoryForgetEntity {
entity: string;
existed: boolean;
error?: string;
}
export interface MemoryForgetReport {
dry_run: boolean;
deleted_concepts: number;
deleted_propositions: number;
deleted_assertions: number;
deleted_evidence: number;
deleted_activities: number;
entities?: MemoryForgetEntity[];
}
export interface MemoryMetrics {
recalls_completed: number;
entities_recalled: number;
probe_hits: number;
probe_misses: number;
negative_cache_hits: number;
self_test_tested: number;
self_test_grounded: number;
reencode_tasks: number;
corrections: number;
decayed: number;
uncertainty_reports: number;
uncertainty_sum: number;
forgotten_entities: number;
updated_at: number;
}
export interface MemoryGraphCounters {
concepts: number;
propositions: number;
unconsolidated?: number;
orphans?: number;
predicate_types?: number;
as_of?: number;
}
export interface WatchSettlement {
fired: number;
conflicted: number;
disarmed: number;
deferred: number;
error?: string;
}
export interface SkillSettlement {
unsupported_reason?: string;
graded: number;
transitions: number;
conflicted: number;
error?: string;
}
export interface MemorySettlementReport {
settled_at: number;
revised_roots?: unknown[];
decayed: number;
decay_ran: boolean;
new_corrections: number;
watches: WatchSettlement;
skills: SkillSettlement;
decay_error?: string;
correction_scan_error?: string;
correction_scan_incomplete: boolean;
correction_scan_through_seq: number;
retention: {
expired_assertions: number;
archived: number;
held: number;
refused: number;
remaining: number;
error?: string;
};
}
export interface SelfTestReport {
tested_at: number;
tested: number;
grounded: number;
reencode_tasks: number;
usage: Usage;
}
export interface ShadowEvalInput {
policy: MemoryPolicy;
replay_sample?: number; // default from policy, at most 16
}
export interface ShadowReport {
compared_at: number;
replayed: number;
baseline_wins: number;
candidate_wins: number;
ties: number;
judge_errors: number;
candidate_policy: MemoryPolicy;
usage: Usage;
samples?: { query: string; winner: 'baseline' | 'candidate' | 'tie' | 'error'; reason?: string }[];
}
export interface MemoryStatus {
metrics: MemoryMetrics;
groundability?: number;
probe_hit_rate?: number;
correction_rate?: number;
avg_uncertainty?: number;
maintenance_tokens_per_recall?: number;
graph: MemoryGraphCounters;
last_settlement?: MemorySettlementReport;
last_self_test?: SelfTestReport;
last_shadow?: ShadowReport;
last_schema_audit?: { audited_at: number; predicates?: Record<string, number> };
}
export interface MaintenanceParameters {
stale_event_threshold_days?: number; // [1, 365]
memory_strength_decay_factor?: number; // (0, 1];旧名 confidence_decay_factor 仍被接受
unconsolidated_max_backlog?: number; // [1, 10000];旧名 unsorted_max_backlog 仍被接受
orphan_max_count?: number; // [1, 10000]
}
export interface MaintenanceInput {
trigger?: 'scheduled' | 'threshold' | 'on_demand';
scope?: 'full' | 'quick' | 'daydream'; // 默认 'daydream'
timestamp?: string; // 规范 UTC:YYYY-MM-DDTHH:mm:ss.SSSZ
parameters?: MaintenanceParameters;
}
export interface AddSpaceTokenInput {
scope: TokenScope; // 铸造 "*" 需要 "*" scope 的 CWT
name: string; // 必填,空间内唯一
expires_at?: number; // Unix timestamp in milliseconds
labels?: string[]; // wiki ACL 标签;缺省 = 不受限,[] = 仅无标签内容
}
export interface RevokeSpaceTokenInput {
token?: string; // 完整 token 值……
name?: string; // ……或唯一 token 名称(两者必填其一)
}
export interface UpdateSpaceInput {
name?: string;
description?: string;
public?: boolean;
wiki_digest?: boolean; // 开启 WikiDigest 图谱蒸馏(默认关闭)
wiki_audit_reads?: boolean; // 外部 wiki 读操作写审计事件(默认关闭)
wiki_acl_defaults?: Record<string, string>; // namespace -> 默认 ACL 标签
memory_policy?: MemoryPolicy; // 替换空间策略;省略的成员使用服务端默认值
}
export interface FormationRestartInput {
conversation: number;
}
export interface CreateOrUpdateSpaceInput {
user: string;
space_id: string;
tier: number;
}
export interface GetOrInitUserInput {
user: string;
name?: string;
}
// ── Wiki:版本化参考文档与可校验引用 ──────────────────────────────
export type WikiDocStatus = 'active' | 'archived';
export type WikiSearchMode = 'chunks' | 'docs';
export interface WikiCommitInput {
doc_id?: number; // 缺省 = 创建新文档
parent_version?: number; // 更新必填(CAS);过期返回 409
namespace?: string; // 默认 "default"
slug?: string; // 展示用;缺省从标题派生
title: string;
content: string; // 全量 Markdown(非 diff);规范化后 ≤ 1 MiB
tags?: string[]; // 缺省 = 更新时保持原值
acl_label?: string; // 缺省 = 保持/继承 namespace 默认;"" 清除
source_uri?: string; // 缺省 = 保持原值
message?: string; // 提交说明
metadata?: Record<string, unknown>; // 缺省 = 保持原值
}
export interface WikiDocInfo {
id: number;
namespace: string;
slug: string;
title: string;
status: WikiDocStatus;
current_version: number;
current_checksum: string; // "sha3-256:..."
tags: string[];
acl_label?: string;
source_uri?: string;
metadata?: Record<string, unknown>;
created_by: string;
updated_by: string;
created_at: number;
updated_at: number;
}
export interface WikiVersionInfo {
id: number;
doc_id: number;
parent_version?: number;
checksum: string;
size: number;
author: string;
message?: string;
created_at: number;
}
export interface WikiCommitOutput {
doc: WikiDocInfo;
version: WikiVersionInfo;
chunks: number;
created: boolean;
idempotent: boolean; // true = 内容未变,零写入
}
export interface WikiSearchInput {
query: string; // BM25 关键词:术语、产品名、错误码优于整句
namespaces?: string[];
doc_ids?: number[];
tags?: string[];
top_k?: number; // 1-50,默认 8
mode?: WikiSearchMode; // 'docs' = 每篇文档只返回最佳命中
expand?: number; // 0-2 邻域扩展;引用范围相应扩大
}
export interface WikiCitation {
uri: string; // wiki://{space}/{doc_id}@{version_id}#{start}-{end}
doc_id: number;
version_id: number;
chunk_id: number;
heading_path: string[];
anchor: string; // 稳定章节锚点,可用于按节读取
byte_range: [number, number];
checksum: string; // 可经 /wiki/verify 校验
quote: string;
}
export interface WikiHit {
text: string;
doc_title: string;
heading_path: string[];
citation: WikiCitation;
}
export interface WikiSearchOutput {
hits: WikiHit[];
total_docs_matched: number;
}
export type WikiSelector =
| { type: 'toc' }
| { type: 'section'; anchor: string }
| { type: 'range'; start: number; end: number }
| { type: 'full' };
export interface WikiReadInput {
doc_id: number;
version?: number; // 读取历史版本(time-travel)
selector?: WikiSelector; // 默认 { type: 'full' }
}
export interface WikiTocEntry {
anchor: string;
heading_path: string[];
byte_start: number;
byte_end: number;
}
export interface WikiReadOutput {
doc_id: number;
version_id: number;
is_current: boolean;
title: string;
status: WikiDocStatus;
checksum: string;
size: number;
toc?: WikiTocEntry[]; // selector 为 'toc' 时返回
content?: string; // section/range/full 时返回
byte_range?: [number, number];
truncated: boolean; // 全文读取有上限(256 KiB)
}
export interface WikiVerifyInput {
uri?: string; // wiki:// 引用 URI;或使用下方显式字段
doc_id?: number;
version_id?: number;
byte_range?: [number, number];
checksum?: string; // 提供时与重算校验和比对
}
export type WikiVerifyStatus = 'valid' | 'superseded' | 'invalid' | 'not_found';
export interface WikiVerifyOutput {
status: WikiVerifyStatus; // 'superseded' = 内容完好但已有新版本
current_version?: number;
checksum?: string; // 从不可变内容重算
quote?: string;
}
export interface WikiBundleEntry {
path: string; // bundle 相对路径,如 "guides/setup.md"
content: string;
}
export interface WikiImportInput {
entries: WikiBundleEntry[]; // OKF v0.1 bundle 文件(Markdown + YAML frontmatter)
namespace?: string; // 默认 "default";bundle 以 namespace 为单位往返
}
export type WikiImportStatus = 'created' | 'updated' | 'unchanged';
export interface WikiImportOutput {
created: number;
updated: number;
unchanged: number; // checksum 幂等:重复导入零版本膨胀
docs: { path: string; doc_id: number; version_id: number; status: WikiImportStatus }[];
skipped?: { path: string; reason: string }[];
}
export interface WikiExportOutput {
namespace: string;
entries: WikiBundleEntry[]; // concept .md 文件 + index.md + manifest.json
docs: number;
}
export interface WikiEventInfo {
id: number;
// DocCreated | VersionCommitted | DocArchived | DocRestored | OrphanSwept
// | CitationVerifyFailed | ImportCompleted | ExportCompleted
// | DigestExtracted | DigestFailed | WikiQueried | WikiRead | StaleReport | EventsPruned
kind: string;
doc_id?: number;
version_id?: number;
actor: string;
detail?: Record<string, unknown>;
created_at: number;
}
export interface WikiDigestReport {
digested: number; // 已提取或复用已有结果的文档代数
facts: number; // 本轮处理的文档账本中保留的断言数,不表示事实完整性
superseded: number; // 经明确核验或来源撤回而 retract 的本来源断言数
skipped: number; // 无需提取的已归档、带标签或评测文档
failed: number; // 失败且仍在待处理队列中的文档;再次调用可重试
citations_checked: number;
citations_invalid: number;
usage: Usage;
}
export interface McpServerConfig {
space_id: string;
auth_token?: string;
auto_create_space?: boolean;
auto_create_tier?: number;
}
export interface McpHttpServerConfig {
path_prefix?: string; // 默认 "/mcp"; client 连接 {path_prefix}/{space_id}
allowed_hosts?: string[]; // rmcp 默认只允许 loopback;公司域名需要显式配置
allowed_origins?: string[]; // 浏览器型 MCP client 使用
auto_create_space?: boolean;
auto_create_tier?: number;
}
export interface Concept {
id: string;
kind: 'concept';
space_id?: string;
schema_ref?: string;
key?: string;
name?: string;
canonical_id?: string;
aliases?: string[];
attributes?: Record<string, unknown>;
facets?: Record<string, Record<string, unknown>>;
retention?: { retention_class?: string; expires_at?: string; legal_hold?: boolean };
_system?: Record<string, unknown>;
}
export interface ModelConfig {
family: string; // "gemini", "anthropic", "openai", "deepseek", "mimo" etc.
model: string;
api_base: string;
api_key: string;
disabled?: boolean;
label?: string;
effort?: 'minimal' | 'low' | 'medium' | 'high' | 'max';
bearer_auth?: boolean;
stream?: boolean;
context_window?: number;
max_output?: number;
}
export interface SpaceTier {
tier: number;
updated_at: number; // Unix timestamp in milliseconds
}
export interface SpaceToken {
token: string;
name: string;
scope: TokenScope;
usage: number;
created_at: number; // Unix timestamp in milliseconds
updated_at: number; // Unix timestamp in milliseconds
expires_at?: number; // Unix timestamp in milliseconds
labels?: string[]; // wiki ACL 标签:[] 仅可见无标签内容;缺省不受限
}
export interface StorageStats {
[k: string]: number | string | boolean | null;
}
export interface SpaceInfo {
id: string;
name?: string;
description?: string;
owner: string;
db_stats: StorageStats;
concepts: number;
propositions: number;
conversations: number;
public: boolean;
tier: SpaceTier;
formation_usage: Usage;
recall_usage: Usage;
maintenance_usage: Usage;
formation_processed_id: number;
maintenance_processed_id: number;
maintenance_at: MaintenanceAt;
wiki_docs: number;
wiki_chunks: number;
wiki_versions: number;
wiki_queries: number;
wiki_digested: number; // 观测用的版本高水位,不代表所有文档都已处理
wiki_stale_docs: number; // 最近一次 housekeeping 陈旧扫描结果
}
export interface FormationStatus {
id: string;
concepts: number;
propositions: number;
conversations: number;
formation_processing: boolean;
maintenance_processing: boolean;
formation_processed_id: number;
maintenance_processed_id: number;
maintenance_at: MaintenanceAt;
}
export interface MaintenanceAt {
daydream: number;
full: number;
quick: number;
/** 最近一次 maintenance 任务的启动时间(unix 毫秒),0 表示尚未启动过。 */
start_at: number;
}
export interface Usage {
/** 发送给 LLM 的输入 token 数。 */
input_tokens: number;
/** 从 LLM 接收的输出 token 数。 */
output_tokens: number;
/** 执行过程中命中缓存的 token 数。 */
cached_tokens: number;
/** 对模型、agent 或工具发起的请求次数。 */
requests: number;
}
export interface AgentOutput {
content: string;
conversation?: number;
failed_reason?: string;
usage?: Usage;
model?: string;
[k: string]: unknown;
}
export type ConversationStatus =
| 'submitted'
| 'working'
| 'idle'
| 'completed'
| 'failed'
| 'cancelled';
export interface Conversation {
_id: number;
user: string;
thread?: string;
label?: string;
messages: Message[];
resources: unknown[];
artifacts: unknown[];
status: ConversationStatus;
failed_reason?: string | null;
period: number;
created_at: number;
updated_at: number;
usage: Usage;
steering_messages?: string[];
follow_up_messages?: string[];
ancestors?: number[];
}
export interface ConversationDelta {
_id: number;
messages: unknown[];
artifacts: unknown[];
status: ConversationStatus;
usage: Usage;
failed_reason?: string | null;
updated_at: number;
child?: number | null;
}
export interface ServiceInfo {
name: string;
version: string;
sharding: number;
description: string;
}
export type KipOperation = string | {
op_id?: string;
language?: 'KQL' | 'KML' | 'META'; // 声明仅供参考;只读限制以解析后的命令为准
command?: string;
ast?: unknown;
parameters?: Record<string, unknown>;
idempotency_key?: string;
options?: { extensions?: Record<string, unknown> };
extensions?: Record<string, unknown>;
};
export interface KipRequest {
command?: string; // 单条命令;与 `operations` 互斥
operations?: KipOperation[]; // 一次往返执行多条命令
execution?: { mode: 'independent' | 'sequence' | 'atomic'; on_error?: 'stop' | 'continue'; isolation?: string; idempotency_key?: string; extensions?: Record<string, unknown> }; // 多于一条操作时必填
read?: { snapshot_token?: string; extensions?: Record<string, unknown> }; // 把所有操作绑定到同一读取坐标
parameters?: Record<string, unknown>; // 绑定到命令中 `:placeholder` 的值
dry_run?: boolean; // 仅校验与规划,不提交
}
export interface KipError {
code: string; // 注册表名称,如 "NotFoundOrNotVisible",不再是数字码
message: string;
category?: string;
hint?: string;
retry?: { class: string; after_ms?: number };
details?: unknown;
}
export interface KipOperationResult<T> {
op_id?: string;
status: 'succeeded' | 'failed' | 'skipped' | 'rolled_back' | 'no_effect';
result?: T;
context?: unknown;
error?: KipError;
warnings?: unknown[];
next_cursor?: string;
receipt?: unknown;
extensions?: Record<string, unknown>;
}
export interface KipResponse<T> {
kip: '2.0';
request_id?: string;
status: 'succeeded' | 'failed' | 'partial' | 'outcome_unknown';
results: KipOperationResult<T>[];
execution?: unknown;
context?: unknown;
snapshot?: { space_id?: string; snapshot_seq: number; schema_environment_version?: number; snapshot_token?: string; extensions?: Record<string, unknown> };
receipt?: unknown;
warnings?: unknown[];
next_cursor?: string;
error?: KipError; // 仅当请求在进入 operations 之前就失败时才设置
extensions?: Record<string, unknown>;
}
```
> **KIP 2.0。** 普通错误在 operation 层,信封错误才在请求层,客户端两处都要读。
> `outcome_unknown` 既不是成功也不是失败:写入可能已经提交,正确做法是按幂等键
> 查事务,而不是当作没发生过重发一次。
---
## 3) MCP Server
默认情况下,HTTP 服务会暴露支持流式传输的 HTTP MCP 端点;`MCP_HTTP_ENABLED=false` 可关闭它:
```text
https://your-brain-host/mcp/my_space_001
```
Client 通过 URL path 选择目标记忆空间,并使用与 REST 相同的 CWT 或 space token:`Authorization: Bearer <token>`。这适合公司内部多用户智能体平台:为每位员工分配一个 Brain space,员工的智能体通过 MCP 连接自己的空间。
Anda Brain 也可作为本地 MCP stdio server 运行:
```bash
MCP_AUTH_TOKEN="$SPACE_TOKEN" \
anda_brain mcp --space-id my_space_001 local --db ./data
```
两种 MCP 模式都复用 HTTP 服务的模型、认证和存储配置。stdio 模式的嵌套 storage 子命令可省略(内存开发模式),也可以使用 `local --db ./data` 持久化到本地,或使用 `aws --bucket ... --region ...` 连接 S3。
| Tool | Input | Output | Scope |
| ---- | ----- | ------ | ----- |
| `anda_brain_remember_conversation` | `FormationInput` 形状(`messages`, `context`, `timestamp`) | `AgentOutput` | `write` |
| `anda_brain_recall_memory` | `RecallInput` 形状(`query`, `context`,可选 `budget`) | `AgentOutput` | `read` |
| `anda_brain_run_maintenance` | `MaintenanceInput` 形状 | `AgentOutput` | `write` |
| `anda_brain_get_space_info` | 无 | `SpaceInfo` | `read` |
| `anda_brain_get_formation_status` | 无 | `FormationStatus` | `read` |
| `anda_brain_execute_kip_readonly` | `{ command?, commands?, parameters?, dry_run? }` | `KipResponse` | `read` |
| `anda_brain_get_or_init_user` | `{ user, name? }` | `Concept` | `write` |
| `anda_brain_list_conversations` | `{ collection?, cursor?, limit? }` | `{ conversations, next_cursor }` | `read` |
| `anda_brain_get_conversation` | `{ conversation_id, collection?, delta?, messages_offset?, artifacts_offset? }` | `Conversation` 或 `ConversationDelta` | `read` |
| `anda_brain_wiki_search` | wiki 查询、过滤条件和结果上限 | `WikiSearchOutput` | `read` |
| `anda_brain_wiki_read` | 文档 ID 和读取选择器 | `WikiReadOutput` | `read` |
| `anda_brain_wiki_commit` | 文档字段和完整 Markdown 内容 | `WikiCommitOutput` | `write` |
| `anda_brain_wiki_verify` | citation URI 或显式引用字段 | `WikiVerifyOutput` | `read` |
MCP 只读 KIP 工具使用 `commands`,并为批量读取补上 independent 执行模式。HTTP `/execute_kip_readonly` 使用 `operations`,批量请求须显式提供 `execution.mode`。Wiki MCP 工具在启用 `wiki` feature 时提供;服务二进制始终启用该 feature。
当设置了 `ED25519_PUBKEYS` 时,远程 MCP 客户端需要携带 `Authorization` bearer token;stdio 模式请通过 `MCP_AUTH_TOKEN` 或 `--mcp-auth-token` 配置 CWT 或 space token。`read` 工具也可无 token 访问 public space。远程 MCP 经过公司域名或反向代理暴露时,请设置 `MCP_HTTP_ALLOWED_HOSTS`。本地 stdio 开发可用 `--mcp-auto-create-space` 自动创建目标 space;远程开发可用 `MCP_HTTP_AUTO_CREATE_SPACE=true`,但在远程自动创建不存在的 space 前,必须配置好 `ED25519_PUBKEYS`,且客户端需提供该 space 拥有 `write` 范围的 CWT。
---
## 4) 接口列表
## 4.1 公共接口
### GET `/favicon.ico` 和 GET `/apple-touch-icon.webp`
- 说明:产品图标静态资源
- 鉴权:无
- 响应:`image/x-icon` 或 `image/webp`
### GET `/info`
- 说明:服务信息
- 鉴权:无
- 响应(JSON):`ServiceInfo`
### GET `/SKILL.md`
- 说明:返回技能描述 Markdown
- 鉴权:无
- 响应:`text/markdown`
---
## 4.2 空间业务接口(`/v1/{space_id}`)
### POST `/v1/{space_id}/formation`
- 作用:提交记忆写入任务
- 鉴权:SpaceToken/CWT `write`
- 请求体:`FormationInput`(Markdown 模式下也允许原始字符串)
- 观察时间接受带时区偏移和不同小数精度的 RFC 3339,统一为 `YYYY-MM-DDTHH:mm:ss.SSSZ`。无效或缺省的时间戳使用已保存的会话创建时间,重试沿用同一回退时间,并保留原始输入。Markdown 原文按一条 user 消息原样捕获,同样提供 `:msg1` Evidence 绑定。
- 响应(JSON/CBOR):`RpcResponse<AgentOutput>`
- 响应(Markdown):`string`(仅返回 `AgentOutput.content`)
### POST `/v1/{space_id}/recall`
- 作用:按自然语言召回记忆
- 鉴权:SpaceToken/CWT `read`(公开空间免鉴权,私有空间需有效 token)。带标签限制的 space token 会收到 `403`,因为 agentic Recall 可跨所有 wiki 标签读取。
- 请求体:`RecallInput`(Markdown 模式下也允许原始字符串)
- 响应(JSON/CBOR):`RpcResponse<AgentOutput>`
- 响应(Markdown):纯文本 `AgentOutput.content`
### POST `/v1/{space_id}/recall_structured`
- 作用:返回合成答案、从检索轨迹提取的记忆引用、`found` 和可选不确定性。
- 鉴权和请求体:同 `/recall`;带标签限制的 token 返回 `403`。
- 响应(JSON/CBOR):`RpcResponse<RecallOutput>`
- 响应(Markdown):纯文本 `RecallOutput.answer`
<a id="recall-budget-contract"></a>
### Recall 预算合同
可选 `budget` 启用宿主选择的 JSON 记忆包,放在 `content` 中,替代自由生成的答案。
`memory_policy.recall_budget` 可对所有 Recall 强制同一上限;请求只能收紧,不能提高或
关闭策略。策略和请求均省略/null 时保持旧行为。
每次请求先按当前问题执行有界、参数化的概念搜索。只有未完成的承诺(`pending`/`blocked`)
作为必需项;已结束承诺作为可选历史候选。返回的紧凑记录保留 ID、版本和来源,省略重复的
LegacyRecord 原文,并在 `recall_detail` 中列出省略字段。必需属性和原生程序检查不会被
摘要掉。完整 Primer 仍进入规划上下文,交付包仅带紧凑的执行依据;需要详情时可用 KQL
字段投影读取。
可选候选逐条装包;`coverage.partial`、`coverage.omitted` 明示不完整交付。累计模型输入
预算耗尽时,宿主仍可返回已授权读取的候选,同时附上必需警告 `recall_context_budget_exhausted`。
这类响应是局部 `bounded` 包,不是模型合成答案或相关性证明。必需读取不完整,或输出预算
连完整约束和警告都容纳不了时,仍返回 `budget_insufficient`;提供方调用失败也仍按失败处理。
固定 codec 对 compact JSON 记忆包全文计数,含转义和 coverage;`context_tokens`
另行限制本次 Recall 所有规划输入规范序列化的累计 token。提供商消息模板、计费和
RPC/MCP 传输副本不属于这些范围。不根据模型名猜编码,也不回退字符数估算。
预算响应不会附带历史、thoughts、artifacts 或工具调用作为记忆旁路。
`recall_structured` 将同一包放在 `answer`,不从完整 trace 另外复制 citations,并增加
`memory_budget`:`tokenizer`、`token_limit`、`tokens`、`context_token_limit`;此模式的
`found` 仅表示交付了非 Primer 候选,不表示已证明语义相关或完整。Markdown 返回同一
包文本。`budget_insufficient` 或带静态 `failed_reason` 的字面量 `null` 表示不可用/
不充分,不能当成成功的空答案。预算允许时,包内可选的 `failed_reason` 字段携带同一
固定错误代码,用于区分模型调用失败和 token 预算耗尽;该字段计入包的 token 总数,
不会交付提供方的原始错误内容。预算失败使用固定代码:`recall_output_budget_exhausted`、
`recall_required_read_incomplete`、`recall_context_budget_exhausted`、
`recall_deadline_reached`、`recall_model_unavailable`、
`recall_planner_incomplete` 或 `recall_procedure_window_incomplete`。
记忆包始终是候选读取(`semantic_complete=false`、`action_ready=false`)。
必要约束和警告作为整体保留;无法容纳时不交付普通记忆,不用估算或自由答案绕过预算。
### POST `/v1/{space_id}/maintenance`
- 作用:触发维护(睡眠/整理)
- 鉴权:SpaceToken/CWT `write`
- 请求体:`MaintenanceInput`
- 响应:`RpcResponse<AgentOutput>`
`parameters` 中明确提供的值覆盖空间策略;省略项使用空间策略的默认值。同一份有效参数同时用于确定性 settlement 和维护模型,不修改持久化的空间策略。
### POST `/v1/{space_id}/memory/pin`
- 作用:固定或取消固定一个图谱实体;固定后其记忆强度不参与闲置衰减。
- 鉴权:SpaceToken/CWT `write`
- 请求体:`MemoryPinInput`;`pinned` 默认 `true`。
- 响应:`RpcResponse<MemoryPinOutput>`
### POST `/v1/{space_id}/memory/forget`
- 作用:物理删除图谱实体;删除前可用 `dry_run: true` 检查影响。
- 鉴权:SpaceToken/CWT `write`
- 请求体:`MemoryForgetInput`;`dry_run` 默认 `false`。
- 响应:`RpcResponse<MemoryForgetReport>`;单个实体的错误位于 `result.entities`。
接受显式的 Concept(`C-*`)、Proposition(`P-*`)、Assertion(`A-*`)、Evidence(`E-*`)和 Activity(`X-*`)ID,包括保存消息原文的 Evidence。原生 legal hold 和引用检查仍然生效,成功清除后保留已擦除身份桩。计数分别报告各类被清除记录,包含级联删除。此操作清除所选图谱记录;已保存的会话、wiki 文档及外部副本各有独立生命周期。
### GET `/v1/{space_id}/memory_status`
- 用途:读取记忆统计和最近一次维护报告。
- 鉴权:SpaceToken/CWT `read`;公开空间允许匿名读取。
- 响应:`RpcResponse<MemoryStatus>`,保持 JSON/CBOR/Markdown 协商。
- `result.last_settlement.correction_scan_incomplete`:本次有界扫描尚未证明 backlog 已耗尽,后续维护会从事务内部继续。
- `result.last_settlement.correction_scan_through_seq`:已完整读取的最大事务序号。
- `result.last_settlement.correction_scan_error`:扫描失败原因;失败不会推进游标。
- 这些字段表示更正发现进度,不表示模型完成审查或 Watch 获得完整授权覆盖。
### POST `/v1/{space_id}/execute_kip_readonly`
- 作用:执行 KIP 请求(只读模式,适用于查询)
- 鉴权:SpaceToken/CWT `read`(公开空间免鉴权,私有空间需有效 token)
- 请求体:`KipRequest`,或直接一个 JSON 字符串(按单条命令解析)
- 若 `operations` 超过一项,必须提供 `execution.mode`;即使 HTTP 返回 `200`,也要检查顶层 `status` 和每个 `results[].status`。
- 响应:`KipResponse<T>`(结果类型随命令而定)
- 只读由命令**解析出的语义**决定:无论请求怎么标注,KML 变更都会在这里被拒绝
### POST `/v1/{space_id}/get_or_init_user`
- 作用:按给定 principal 获取或初始化用户 Concept 节点
- 鉴权:SpaceToken/CWT `write`
- 请求体:`GetOrInitUserInput`
- 省略 `name` 时保留已有显示名;显式提供 `name` 时更新显示名。首次创建且未提供姓名时,使用 key 作为初始显示名。
- 响应:`RpcResponse<Concept>`
### GET `/v1/{space_id}/info`
- 作用:获取空间状态和统计
- 鉴权:SpaceToken/CWT `read`(公开空间免鉴权,私有空间需有效 token)
- 响应:`RpcResponse<SpaceInfo>`
### GET `/v1/{space_id}/status`
- `/v1/{space_id}/info` 的别名,鉴权和响应相同。
### POST `/v1/{space_id}/probe`
- 作用:无需模型的检索可达性检查;`found:false` 不代表信念被否定。
- 鉴权:沿用 Space 的 `read` 权限和公开空间读取规则。
- 请求:`{"query":"...", "limit":8}`。
- 响应:`RpcResponse<ProbeOutput>`,含 `found`、`negative_cached`、可选 `hits` 和可选 `search_exhaustive`。后者来自 SEARCH result 顶层覆盖字段;缺省表示未知,有剩余分页时为 false。负缓存仅保存明确穷尽的检索 miss,不能作为不存在或信念被否定的证明。
### GET `/v1/{space_id}/formation_status`
- 作用:获取记忆写入状态(更轻量级的接口,专门用于监控记忆写入进度)
- 鉴权:SpaceToken/CWT `read`(公开空间免鉴权,私有空间需有效 token)
- 响应:`RpcResponse<FormationStatus>`
- 此接口是轻量监控,游标不是逐任务成功证明。Rust 宿主可用 `Space::processing_report` / `wait_for_processing` 区分排队、运行、失败、取消、中断和超时;超时后继续核对同一 conversation ID,不重新提交。
### GET `/v1/{space_id}/conversations/{conversation_id}?collection=<collection>`
- 作用:获取单条会话详情
- 鉴权:SpaceToken/CWT `read`(公开空间免鉴权,私有空间需有效 token);带 ACL 标签限制的 token 返回 `403`——会话持久化了完整的 agent 运行历史,不受标签过滤;`collection=recall` 对公开空间的匿名访问也返回 `403`(私有期的 recall 运行可能内嵌 labeled wiki 内容)
- Query:
- `collection?: string` // "formation"(默认)、"recall" 或 "maintenance";未知值返回 `400`
- 响应:`RpcResponse<Conversation>`
### GET `/v1/{space_id}/conversations/{conversation_id}/delta?collection=<collection>&messages_offset=<n>&artifacts_offset=<n>`
- 作用:按客户端已消费的 offset 获取会话增量更新
- 鉴权:SpaceToken/CWT `read`(公开空间免鉴权,私有空间需有效 token);带 ACL 标签限制的 token 返回 `403`(`collection=recall`:公开空间匿名访问同样拒绝)
- Query:
- `collection?: string` // "formation"(默认)、"recall" 或 "maintenance";未知值返回 `400`
- `messages_offset?: number` // 仅返回该偏移量之后的新消息,默认 `0`
- `artifacts_offset?: number` // 仅返回该偏移量之后的新 artifacts,默认 `0`
- 响应:`RpcResponse<ConversationDelta>`
### GET `/v1/{space_id}/conversations?collection=<collection>&cursor=<cursor>&limit=<n>`
- 作用:分页列出会话
- 鉴权:SpaceToken/CWT `read`(公开空间免鉴权,私有空间需有效 token);带 ACL 标签限制的 token 返回 `403`(`collection=recall`:公开空间匿名访问同样拒绝)
- Query:
- `collection?: string` // "formation"(默认)、"recall" 或 "maintenance";未知值返回 `400`
- `cursor?: string`
- `limit?: number`
- 响应:`RpcResponse<Conversation[]>`(并通过 `next_cursor` 给出下一页游标)
---
## 4.3 Wiki 接口(`/v1/{space_id}/wiki`)
Wiki 是空间的版本化参考记忆(政策、手册、SOP、API 文档)。写入是 Git 式不可变提交(CAS 并发控制);检索返回可校验的 `wiki://` 引用。ACL:文档可携带 `acl_label`;带 `labels` 的 space token 仅可见无标签内容 + 所授标签——查询预过滤后仍核对文档当前版本、状态和权限。权限检查与版本选择共享同一文档快照。公开空间的匿名读者仅可见无标签内容;越权一律表现为 404。
Wiki 专属错误语义:`409` 提交冲突(`RpcError.data.current_version` 为应 rebase 的版本)、`413` 内容超 1 MiB、`404` 不存在或 ACL 拒绝。
目录由 Markdown 的 ATX 标题(`#`–`######`)生成,独立于检索分块;读取 section 包含该标题的子章节。锚点按标题派生,同名标题加序号。`full`、`range` 和 `section` 均最多返回 256 KiB;`truncated` 为 true 时,使用返回的 `byte_range` 继续读取。历史和引用校验只接受已发布 parent 链中的版本,失败提交的残留不是历史。
OKF 导入按完整文件替换 title、tags、resource、type 和未知 frontmatter 键值,删除字段会清空对应导入状态;已有 ACL 与其他宿主 metadata 保留。标题或标签经 commit 修改后,导出仍保留未知键值。YAML 使用标准解析和序列化,不承诺注释或原始排版保真。
WikiDigest 默认关闭。开启后,commit、archive、restore 和 ACL 变化持久化文档待处理标记;每轮最多处理 20 个文档,启动、维护后或显式调用时推进,失败文档保留待重试。正文校验和未变时复用已有账本,不再调用模型。提取漏项不是撤回依据:对旧断言必须在每个正文批次中明确核验为 `absent`,缺失、重复或 `unknown` 判断均保留原断言。归档或加标签由后续 digest 撤回本来源断言;该图谱同步是异步的。模型处理中发生文档变更时,不发布旧结果,保留新一代待处理标记。观测高水位 `wiki_digested` 不表示队列已经清空。
### POST `/v1/{space_id}/wiki/docs`
- 作用:提交文档(创建;或携带 `doc_id` + `parent_version` 做 CAS 更新);同内容提交为零写入
- 鉴权:SpaceToken/CWT `write`
- 请求体:`WikiCommitInput`(也接受原始 Markdown 字符串,标题取首个标题行)
- 响应:`RpcResponse<WikiCommitOutput>`
### GET `/v1/{space_id}/wiki/docs?namespace=<ns>&status=<status>&tag=<tag>&cursor=<cursor>&limit=<n>`
- 作用:分页列出文档
- 鉴权:SpaceToken/CWT `read`(公开空间免鉴权;ACL 标签生效)
- 响应:`RpcResponse<WikiDocInfo[]>`(下一页游标经 `next_cursor` 返回)
### GET `/v1/{space_id}/wiki/docs/{doc_id}`
- 作用:文档元信息 + 目录(TOC)
- 鉴权:SpaceToken/CWT `read`(公开空间免鉴权;ACL 标签生效)
- 响应:`RpcResponse<{ doc: WikiDocInfo; toc: WikiTocEntry[] }>`
### GET `/v1/{space_id}/wiki/docs/{doc_id}/content?version=<id>&anchor=<anchor>&start=<n>&end=<n>`
- 作用:渐进读取——`anchor` 读单节、`start`+`end` 读字节区间、均不传读受限全文;`version` 读历史版本
- 鉴权:SpaceToken/CWT `read`(公开空间免鉴权;ACL 标签生效)
- 响应:`RpcResponse<WikiReadOutput>`
### GET `/v1/{space_id}/wiki/docs/{doc_id}/versions?cursor=<cursor>&limit=<n>`
- 作用:版本历史(不可变提交链)
- 鉴权:SpaceToken/CWT `read`(公开空间免鉴权;ACL 标签生效)
- 响应:`RpcResponse<WikiVersionInfo[]>`(下一页游标经 `next_cursor` 返回)
### POST `/v1/{space_id}/wiki/docs/{doc_id}/archive`
- 作用:归档文档(退出检索,仍可按 id 读取,可恢复)
- 鉴权:SpaceToken/CWT `write`
- 响应:`RpcResponse<WikiDocInfo>`
### POST `/v1/{space_id}/wiki/docs/{doc_id}/restore`
- 作用:恢复归档文档进入检索
- 鉴权:SpaceToken/CWT `write`
- 响应:`RpcResponse<WikiDocInfo>`
### POST `/v1/{space_id}/wiki/search`
- 作用:BM25 关键词检索,返回片段与可校验引用
- 鉴权:SpaceToken/CWT `read`(公开空间免鉴权;ACL 标签生效)
- 请求体:`WikiSearchInput`(也接受原始查询字符串)
- 响应:`RpcResponse<WikiSearchOutput>`
### POST `/v1/{space_id}/wiki/verify`
- 作用:对照不可变存储校验引用
- 鉴权:SpaceToken/CWT `read`(公开空间免鉴权;ACL 标签生效)
- 请求体:`WikiVerifyInput`(也接受原始 `wiki://` URI 字符串)
- 响应:`RpcResponse<WikiVerifyOutput>`
### GET `/v1/{space_id}/wiki/events?kind=<kind>&doc_id=<id>&cursor=<cursor>&limit=<n>`
- 作用:查询 append-only 审计日志(写入、导入、蒸馏;开启 `wiki_audit_reads` 后含读操作)
- 鉴权:SpaceToken/CWT `read`;受 ACL 标签限制的 token 返回 `403`
- 响应:`RpcResponse<WikiEventInfo[]>`(下一页游标经 `next_cursor` 返回)
### POST `/v1/{space_id}/wiki/import`
- 作用:导入 OKF v0.1 bundle;checksum 幂等(重复导入零版本膨胀);未知 frontmatter 键值按结构保留;YAML 注释、字段顺序及标量排版不保留
- 鉴权:SpaceToken/CWT `*`(全量 scope)
- 请求体:`WikiImportInput`
- 响应:`RpcResponse<WikiImportOutput>`
### GET `/v1/{space_id}/wiki/export?namespace=<ns>`
- 作用:按 namespace 导出 OKF bundle(concept `.md` + `index.md` + 含校验和的 `manifest.json`);可在空库完整重放
- 鉴权:SpaceToken/CWT `*`(全量 scope)
- 响应:`RpcResponse<WikiExportOutput>`
### POST `/v1/{space_id}/wiki/digest`
- 作用:把待处理 wiki 版本蒸馏进 Cognitive Nexus(每条事实写成 Proposition + 归属于 Brain 的 Assertion,并引用对应段落作为 Evidence);经完整正文批次明确核验不再支持的旧断言,digest 撤回自己的 Assertion;漏提取或未知判断不会触发撤回,Proposition 与他人的 Assertion 不受影响(需先 `update_space {"wiki_digest": true}` 开启)
- 鉴权:SpaceToken/CWT `write`
- 响应:`RpcResponse<WikiDigestReport>`
---
## 4.4 空间管理接口(`/v1/{space_id}/management`)
### GET `/v1/{space_id}/management/space_tokens`
- 作用:列出 Space Token
- 鉴权:必须通过 CWT `write`(用户管理级鉴权)
- 响应:`RpcResponse<SpaceToken[]>` —— `token` 字段仅显示前缀(如 `STabc123…`);完整 token 值只在 `add_space_token` 响应中出现一次,铸造时务必保存,或后续凭 `name` 吊销
### POST `/v1/{space_id}/management/add_space_token`
- 作用:新增 Space Token
- 鉴权:必须通过 CWT `write`(用户管理级鉴权)。铸造 `*`(全 scope)token 需要 `*` scope 的 CWT——`write` CWT 不能铸造高于自身 scope 的 token
- 请求体:`AddSpaceTokenInput` —— `name` 必填且空间内唯一。仅 `read` token 可设置 `labels`;`[]` 表示仅可读无标签 wiki 内容,省略表示不受标签限制。
- 响应:`RpcResponse<SpaceToken>`(新 token,前缀总是 `ST`;这是唯一携带完整 token 值的响应)
### POST `/v1/{space_id}/management/revoke_space_token`
- 作用:吊销 Space Token
- 鉴权:必须通过 CWT `write`(用户管理级鉴权)
- 请求体:`RevokeSpaceTokenInput` —— 传 `token`(完整 token 值)或 `name`(唯一 token 名称,供未保存 token 值的管理者使用)
- 响应:`RpcResponse<boolean>`(是否成功吊销)
### PATCH `/v1/{space_id}/management/update_space`
- 作用:更新空间信息、wiki 设置及可选的 `memory_policy`(校验后作为新策略持久化)。
- 鉴权:必须通过 CWT `write`(用户管理级鉴权)
- 请求体:`UpdateSpaceInput`
- 响应:`RpcResponse<true>`
### POST `/v1/{space_id}/management/shadow_eval`
- 作用:在空间副本上重放近期 Recall,对比候选记忆策略和当前策略;可能产生多次模型调用。
- 鉴权:CWT `write`(不接受 space token)。
- 请求体:`ShadowEvalInput`;`replay_sample` 默认采用空间策略,上限为 `16`。
- 响应:`RpcResponse<ShadowReport>`
### PATCH `/v1/{space_id}/management/restart_formation`
- 作用:通过会话 ID 重启记忆写入任务(用于失败/过期的写入任务)
- 鉴权:必须通过 CWT `write`(用户管理级鉴权)
- 请求体:`FormationRestartInput`
- 响应:`RpcResponse<true>`
### GET `/v1/{space_id}/management/space_byok`
- 作用:获取 BYOK(Bring Your Own Key)配置,即使用自定义模型配置
- 鉴权:必须通过 CWT `write`(用户管理级鉴权;响应包含模型供应商凭据)
- 响应:`RpcResponse<ModelConfig>`
### PATCH `/v1/{space_id}/management/space_byok`
- 作用:更新 BYOK(Bring Your Own Key)配置,即使用自定义模型配置
- 鉴权:必须通过 CWT `write`(用户管理级鉴权)
- 请求体:`ModelConfig`
- 响应:`RpcResponse<true>`
---
## 4.5 管理员接口(`/admin`)
### POST `/admin/create_space`
- 作用:创建空间
- 鉴权:平台管理员 + CWT `write`
- 请求体:`CreateOrUpdateSpaceInput`
- 响应:`RpcResponse<SpaceInfo>`
### POST `/admin/{space_id}/update_space_tier`
- 作用:更新空间 tier
- 鉴权:平台管理员 + CWT `write`
- 请求体:`CreateOrUpdateSpaceInput`
- 响应:`RpcResponse<SpaceTier>`
---
## 5) 前端调用示例(TS)
```ts
async function rpcPost<TReq, TRes>(
url: string,
body: TReq,
token?: string
): Promise<RpcResponse<TRes>> {
const res = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
...(token ? { Authorization: `Bearer ${token}` } : {}),
},
body: JSON.stringify(body),
});
const responseText = await res.text();
if (!res.ok) {
let message = responseText || `HTTP ${res.status}`;
try {
const error = JSON.parse(responseText) as RpcError;
if (error.message) message = error.message;
} catch { /* 中间件错误可能是纯文本 */ }
throw new Error(`HTTP ${res.status}: ${message}`);
}
return JSON.parse(responseText) as RpcResponse<TRes>;
}
// Recall
const recall = await rpcPost<RecallInput, AgentOutput>(
'/v1/my_space_001/recall',
{ query: '这个用户的偏好是什么?', context: { counterparty: 'user_1' } },
'YOUR_TOKEN'
);
if (recall.error) {
console.error(recall.error.message);
} else {
console.log(recall.result?.content);
}
```
---
## 6) 错误语义
- 认证失败:HTTP `401`,响应体为 `RpcError`
- 参数错误:HTTP `400`,响应体为 `RpcError`
- 无权访问:HTTP `403`;空间或 wiki 文档不存在:HTTP `404`
- Wiki 提交冲突:HTTP `409`,当前版本位于 `RpcError.data.current_version`;wiki 内容超限:HTTP `413`
- 模型请求限流:HTTP `429`;全局 HTTP 限流:HTTP `503`。这些中间件响应是纯文本。
- 成功时:HTTP `200`,响应体通常为 `RpcResponse<T>`
- 处理器错误即使在 `Accept` 请求 CBOR 或 Markdown 时也返回 JSON;未匹配路由和中间件错误可能是纯文本或空响应体。只有成功响应体遵循 `Accept`。
- KIP 请求可能返回 HTTP `200`,但 `KipResponse.status` 或某项操作的 `status` 为 `failed`;必须检查两层 KIP 状态。
- MCP 工具沿用同一分类:调用方可修复的失败以 JSON-RPC `invalid_params`/`invalid_request` 返回(wiki 提交冲突携带与 HTTP `409` 相同的 `data.current_version` 重试载荷),只有真正的内部错误才用 `internal_error`
### 隔离的 MIB 宿主
相邻 Anda Bot 的 `mib` feature 在本机提供独立的 `/mib-agent/v0.1` 和
`/mib-memory/v0.1` 协议;它们不属于本生产 Brain API 的路由。宿主使用
`experiments` 实现隔离状态、完成屏障、单调业务时间和清理,详见
[接入](README.md#mib-integration)。适配器不声明在线学习能力;
缺少 provider 或 observer 遥测的成本仍明确标为不完整。
Rust 工厂 `Experiment::create_with_recall_budget` 在运行对外可用前持久化强制
Recall 预算。`audit_procedures()` 返回有界、只读的原生程序清单;截断计数不能证明
不存在。仅 Bot MIB 的 `learning_audit` 扩展将该清单交给评测侧,不进入业务模型。
它不启用学习,也不赋予执行权限。详见 [验证](README.md#mib-integration)。
已退役 Rust `anda_brain::eval` API 与 `eval` CLI(含 optimizer/miner 参数)。
MIB 提供公开产品回归 profile;自测、shadow 诊断、probe、引用与账本继续作为线上
工具。运行策略使用各 Space 持久化的 `MemoryPolicy`。可信 Rust 宿主可以在共享或
打开 Space 前调用 `AppState::with_agent_prompts(AgentPrompts)` 提供不可变的部署
段:每段以 `# A.` 开头、最多 128 KiB,编译参考前缀保持原样。这不是 HTTP/MCP
提示操作。详见 [迁移](README.md#offline-regression-and-instance-configuration)。
### 可信学习运行时(仅 Rust)
启用 `learning` feature 后,`Space::learning()` 提供显式注册、冻结 cohort、
有界 `drive` 步骤、重启后发现工作及独立认证的 Outcome 接收。原生 lease、当前
可执行权限、依赖有效性和 policy pin 共同约束派发。这些宿主 API 不增加 HTTP/MCP
路由或模型写权限;收齐 cohort 不会采纳 Skill。`settle(job_id)` 在固定 cutoff 后
重算原生账本,原子提交裁决与 standing。`reviews()` 和 `enroll_review()` 提供保留
原始采纳依据的持久复核;`submit_safety_signal()` 接受独立认证的安全撤销信号。
`bind_application_context()` 接受短时有效的可信宿主环境观测,`procedure_status()`
及 Recall 内部的 `check_procedure_status` 工具只读检查当前推荐条件,不授予执行权限。
条件无法验证或复核到期时停止推荐。已配置 learning 的 Space 不允许通过 fork/snapshot
复制操作 journal。详见 [运行时](README.md#native-learning-contracts) 和
[生命周期与恢复](README.md#native-learning-contracts)。
## 有身份的运行时待办与后果
启动前配置 `BRAIN_RUNTIME_CONFIG`。完整合同、恢复及示例见 [RUNTIME_cn.md](RUNTIME_cn.md)
和 [runtime.example.json](runtime.example.json)。公共/本地 Space 也必须提供真实凭据。
| 接口 | 授权 | 返回 |
| --- | --- | --- |
| `GET /v1/{space_id}/attention?limit=20&cursor=...` | 真实 read/* 凭据、原生主体映射和 audience | `AttentionPage`,读取不领取 |
| `POST /v1/{space_id}/attention/{id}/responses` | 真实 write/*、当前可见性及正确接收者 | `ResponseReceipt`,body 为 `AttentionResponse` |
| `POST /v1/{space_id}/outcomes` | 验签的观察者 CWT、当前 record_outcome 及登记合同 | `ObservationReceipt`,body 为 `OutcomeInput` |
| `GET /v1/{space_id}/runtime/status` | 真实 read/*,配置启用时需映射 | `RuntimeStatus`,计数仅覆盖可见的有限页面 |
URL 中的 id 是返回的 wake 摘要,不是带斜杠的 wake_ref。五分钟有效的游标经加密认证,
绑定调用者/instance/配置;跨调用者或过期游标被拒绝。公共 Space 和普通 write token
不能认证独立观察者。MCP 暴露 get_attention、respond_attention、get_runtime_status
(均带 anda_brain_ 前缀),观察者写入不属于模型工具。
POST 使用结构化 JSON/CBOR,响应保留 JSON/CBOR/Markdown 协商。同事件同文幂等,
异文 409 并留存审计;未来时间或错误 instance 被拒绝。迟到/更正/安全状态、原生提交
和 learning 入样分别报告。learning 变体必须符合原有 OutcomeMeasurements 合同,
包括 baseline 在内均只路由到既有控制器。
```ts
type RuntimeScope = { space_id: string; space_instance: string };
type AttentionQuery = { cursor?: string | null; limit?: number | null };
type AttentionResponse =
| { kind: "clarification"; event_key: string; answer: string }
| { kind: "agent_statement"; event_key: string; statement: string };
type ResponseReceipt = {
receipt_id: string; status: string; evidence_ref: string | null;
};
type AttentionPage = {
scope: RuntimeScope; items: AttentionItem[];
next_cursor: string | null; complete: boolean;
};
type AttentionItem = {
id: string; wake_ref: string; parent_id: string | null;
watch_ref: string; fire_activity_ref: string; summary: string;
state: "pending" | "running" | "blocked" | "completed" | "cancelled";
reason: string | null; decision: Record<string, unknown> | null;
decision_ref: string | null; attempt_ref: string | null;
dispatch_ref: string | null; clarification: Record<string, unknown> | null;
delivery: Record<string, unknown> | null;
};
type OutcomeStatus = "success" | "partial" | "failure" | "aborted" | "unknown";
type OutcomeInput = {
space_instance: string; attempt_ref: string;
observer_configuration_digest: string; event_key: string;
observed_at: string; metric: string; window: string;
observation:
| { kind: "measurement"; terminal: boolean; outcome_status: OutcomeStatus;
magnitude?: number | null; payload: unknown }
| { kind: "learning"; measurements: Record<string, unknown> };
correction_of?: string | null; safety_signal?: string | null;
utility?: { witness_ref?: string; witness?: ContributionWitness } | null;
};
type ObservationReceipt = {
format: "anda-brain:observation-receipt-v1";
receipt_id: string; scope: RuntimeScope; event_key: string;
body_digest: string; observer: string; received_at_ms: number;
observed_at: string; status: string;
native_committed: boolean; learning_eligible: boolean;
outcome_status: OutcomeStatus | null; outcome_ref: string | null;
observation_ref: string | null; reason: string | null; safety_pending: boolean;
safety_evaluation_ref?: string; // 解决或覆盖本安全信号的原生撤销记录。
};
type RuntimeStatus = {
supported: boolean; configured: boolean; scope: RuntimeScope | null;
attention_enabled: boolean; actions_enabled: boolean;
observation_enabled: boolean; observer_authenticated: boolean;
blocked_reasons: string[]; visible_items: number; inventory_complete: boolean;
utility?: UtilityStatus;
learning?: LearningRuntimeStatus;
semantic_attention?: SemanticAttentionStatus;
trust?: TrustRuntimeStatus;
};
```
### 后果与回答语义
待办页包含 1–50 项、最多 256 KiB 可见输出。`complete` 仅表示本次快照遍历结束,
不表示任务完成或语义完整;每页重验可见性,包括 gate 记忆包背后的原生证据。
MCP 回答参数为 `{id, response}`,列表参数为 `{cursor, limit}`。读取和回答均不领取
任务;澄清回答须对应已提交 ask、正确接收者和有效期限,回答进入新 gate,不授予权限。
`agent_statement` 只生成带归属 Evidence 和 Activity,不生成独立 OutcomeRecord。例如:
```json
{"kind":"clarification","event_key":"answer-42","answer":"明天"}
```
测量请求使用实际保留的身份与摘要:
```json
{
"space_instance":"sha256:INSTANCE_DIGEST",
"attempt_ref":"X-42",
"observer_configuration_digest":"sha256:REGISTERED_METHOD_DIGEST",
"event_key":"instrument-event-42",
"observed_at":"2026-09-17T10:00:00.000Z",
"metric":"delivery",
"window":"durable_inbox_v1",
"observation":{
"kind":"measurement",
"terminal":true,
"outcome_status":"success",
"magnitude":null,
"payload":{"delivery_digest":"sha256:ACTUAL_DELIVERY_REQUEST_DIGEST"}
},
"correction_of":null,
"safety_signal":null
}
```
观察合同固定主体、方法/配置摘要、控制域、任务族、指标、窗口及允许延迟。接收层验证
真实 act/Attempt、原生事务作者、已存在分派和观测时间,拒绝控制器自评。inbox 成功还
须验证实际持久化投递及匹配的摘要/时间,仅证明 inbox 写入,不代表人已阅读或业务成功。
其他回调须提供自己的独立测量合同。
普通合格测量原子生成 Outcome Evidence 与 `outcome_observation` Activity;原始材料
保留在 Evidence payload,不扩展封闭的 OutcomeRecord Facet。非终结/unknown 不完成
分派,缺失 magnitude/cost 不填零。终结证据对账同一 Attempt,取消后也可保留真实后果。
原生留证与分派对账是两个可恢复步骤;未确认写入须用相同事件/内容和新鲜认证重试。
调用方取消不截断已接收写入。
认证后的迟到、冲突及学习非终结材料可审计,不改变旧试验入样资格。更正指向同一
观察者/Attempt 的较早事件,追加证据,不改写旧 Outcome/Evaluation。迟到或排除的
安全信号仍可发现;显式启用的学习消费者使用当前观察者权限,在原生撤销完成后才确认
`safety_pending` 并记录 `safety_evaluation_ref`。
已登记学习 Attempt 使用 `observation:{"kind":"learning", "measurements":{...}}`。
归属来自保留的 ticket,`trial_ref:null` 的 baseline 也不会落入普通写入器;只有
`LearningRuntime::submit_outcome` 写原生结果,保持冻结 cutoff、可比性和 ACK 恢复。
控制器不可用时拒绝,不转普通路径。`learning_eligible:true` 只表示合同接纳,不等于
正向裁决。输入上限 16 KiB,事件键 256 字节;身份装配和存储上限见[运行时指南](RUNTIME_cn.md)。
### 学习运行状态
既有 status 路由和 MCP 工具新增 learning;模型工具不提供 cohort 报名或观察者
凭据管理。只有明确映射的 auditor 能看到 capacity / last_pass,其他调用方为 null。
Maintenance 的可选 skills.runtime 显示独立调度状态,旧 Skill 计数不会重复计入
此前调度工作。详见[学习指南](LEARNING_RUNTIME_cn.md)。
```typescript
type LearningRuntimeStatus = {
compiled: boolean; registered: boolean; registration_enabled?: boolean;
bindings_ready: boolean; automatic_allowed: boolean; running?: boolean;
automation?: { trials: boolean; reviews: boolean; archive: boolean; safety: boolean };
blocked_reasons?: string[];
capacity?: { hot_jobs: number; maximum_hot_jobs: number; archived_jobs: number;
retained_identities: number; reserved_bytes: number;
storage: { maximum_records: number; maximum_reserved_bytes: number } } | null;
last_pass?: { started_at_ms: number; finished_at_ms: number; enrolled: number;
driven: number; observed: number; settled: number; archived: number;
reviews_checked: number; reviews_enrolled: number; safety_resolved: number;
blocked: string[] } | null;
};
```
### 交付与效用元数据
结构化 Recall 新增可选 recall_receipt 元数据,answer/语义 packet 保持不变。普通或
直接 agent 调用可通过 conversation ID 在可信 Rust API 查询收据。观察者在 outcomes
的 utility 中可选择内联见证或既有原生见证引用,不放宽验签与独立权限检查。
运行状态新增 utility 的开关、校准状态及恢复原因;模型没有设置分数或新增 MCP
变更工具。详见 [UTILITY_RUNTIME_cn.md](UTILITY_RUNTIME_cn.md)。
```typescript
type RecallReceiptRef = {
id: string; digest: string; scope: RuntimeScope;
};
// RecallOutput.recall_receipt?: RecallReceiptRef
// OutcomeInput.utility?: { witness_ref?: string; witness?: ContributionWitness }
// RuntimeStatus.utility?: UtilityStatus
type UtilityStatus = {
configured: boolean; automatic: boolean; apply: boolean;
calibrated: boolean; ranking: boolean; running: boolean;
reason: string | null;
};
```
### 文本注意力状态
Runtime status 新增可选 `semantic_attention`:`configured`、`automatic`、`running`、
`pin`、`reason` 及可空的 `last_pass`。后者包含单轮有界统计 `scanned`、`calls`、
`input_tokens`、`advanced`、`fired`、`expired`、`deferred`、`reason`,仅配置为 auditor
的调用者可读取,其他调用者得到 null。它不是完整清单,也不证明所有文本 Watch
均已求值。既有 JSON/CBOR/Markdown 和 HTTP/MCP 请求形状保持兼容;不新增模型配置
或求值写接口。操作员通过每 Space 的 `semantic` 启动绑定安装。预算、pin 迁移、
unknown/deferred、原生 Artifact 擦除及幂等恢复见
[SEMANTIC_WATCH_RUNTIME_cn.md](SEMANTIC_WATCH_RUNTIME_cn.md)。
```typescript
type SemanticAttentionStatus = {
configured: boolean; automatic: boolean; running: boolean;
pin: { id: string; digest: string } | null; reason: string | null;
last_pass: {
scanned: number; calls: number; input_tokens: number; advanced: number;
fired: number; expired: number; deferred: number; reason: string | null;
} | null;
};
```
### 上下文 trust 状态与发现提示
既有 HTTP 状态路由和 MCP 状态工具新增可选 `trust` 元数据。`governor_authorized`
表示配置的治理主体当前是否具有原生权限,不是授予调用者的权限。不新增 HTTP/MCP
trust 管理或独立事实写工具,既有 JSON/CBOR/Markdown 请求保持兼容。正常认证的
独立 measurement payload 可选携带 `trust_verification_ref: "E-…"`,用于公告既有原生
事实核验记录并有界发现,不能把行动成功/失败转成信任得分。可信 Rust 事实接收、
审查、应用、版本冲突恢复和限定域回退见 [TRUST_RUNTIME_cn.md](TRUST_RUNTIME_cn.md)。
```typescript
type TrustRuntimeStatus = {
configured: boolean; automatic: boolean; apply: boolean; automatic_apply: boolean;
calibrated: boolean; governor_authorized: boolean; running: boolean;
reason: string | null;
};
```