tagent

package module
v0.0.0-...-88bd7a9 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 27, 2026 License: Apache-2.0 Imports: 28 Imported by: 0

README

tagent

记忆驱动的长期运行 Agent 框架 —— 基于 trpc-agent-go,用事件驱动引擎替代同步 ReAct 循环:事件永久入库、上下文按需压缩、历史随时召回,让 Agent 可以连续运行数天而不失忆、不失控

English | 中文


✨ 特性一览

特性 一句话说明
🔄 持久事件循环 StartLoop 后常驻运行;消息、工具结果、定时事件统一经 EventBus 驱动 turn
🧠 记忆三原语 store(事件不可变入库)/ compress(总结+自然遗忘)/ recall(票据或语义召回)
🗂 卡片序列 压缩后的历史浓缩为索引卡片行——模型始终"看得见做过什么",每张卡自带召回票据
异步任务层 长命令/服务经 tmux 后台运行:快命令内联返回,慢任务 ACK + task_settled 通知回写
🔁 任务重入 resume_task 对存活服务续输入(REPL 式)、对完成的子 Agent 续指令(自动还原上下文)
🤖 子 Agent 编排 本地 AgentToolWrapper / 远程 A2A 协议统一封装;事件跨 Agent 按 key 精确传递
🧘 冥想心跳 空闲期自动回顾与沉淀,产出 ★ 高亮卡片进入长期记忆
🎓 RL 集成 HTTPAPI + SwappableModel + TrajectoryRecorder,与 AReaL 对接采集训练轨迹

🎬 一个长期运行的日常

sequenceDiagram
    participant U as 用户
    participant T as tagent
    participant X as tmux 任务层
    participant M as MemoryStore

    U->>T: "部署服务并盯着"
    T->>X: spawn(deploy.sh)
    Note over X: dense 窗口密集探测(~10s)
    X-->>T: 未结算 → ACK「后台运行 task-42」
    T-->>U: 已开始部署,完成后通知你
    Note over T: 期间正常处理其他消息
    X->>T: task_settled(task-42, 部署成功)
    T-->>U: 🔔 部署完成(通知回写,非阻塞)
    Note over T,M: 上下文超预算 → 压缩:旧事件归档,<br/>历史浓缩为卡片行 [evt_1a2b] 部署成功…
    U->>T: (次日)"昨天部署时的报错细节是什么?"
    T->>M: recall(items=[{key: 1a2b}])
    M-->>T: 精确回补原文(零幻觉)
    T-->>U: 完整细节

🚀 快速开始

1. 声明式配置(YAML)

entry: tagent
prompt_dir: resources/prompts
model: glm-4-flash
providers:
  openai:
    api_endpoint: "https://open.bigmodel.cn/api/paas/v4"
    api_key_env: "ZAI_API_KEY"

agents:
  tagent:
    system_prompt:
      files: [AGENTS.md, SOUL.md, TOOLS.md]
    memory:
      type: localfile
      path: /data/tagent/events
    tools:
      - kind: tool
        id: recall               # 统一召回入口:票据/因果链/关键词检索(参数即路由)
      - kind: tool
        id: exec                 # tmux 命令执行(异步任务层)
        description_file: action_tool_desc.md

  recall:
    system_prompt:
      files: [recall_agent.md]
    memory:
      type: memory
    max_tool_iterations: 10

2. 三行进入持久循环(Go)

ta, _ := tagent.New(cfg, tagent.WithModel(model))
defer ta.Close()

outputCh, _ := ta.StartLoop("userID", "sessionID")
ta.InjectMessage(model.Message{Role: model.RoleUser, Content: "帮我执行一个命令"})

for evt := range outputCh {
    if evt.IsFinalResponse() {
        println("Final:", evt.Message.Content)
    }
}

3. 跑通完整示例

cd examples/wechat-bot && go run .    # 微信机器人:持久循环+全部机制实战

其他运行模式:A2A 服务端(agent.NewA2AServer)、RL rollout worker(agent.NewHTTPAPI 对接 AReaL)——见 examples/docs/wiki/

🧠 心智模型

三层数据表示
位置 职责 生命周期
EventBus AgentEvent Agent 内存 事件触发队列 Publish → Pull 后丢弃
SessionProjection EventReference[] Agent 内存 投影(有界工作内存) 可被 Compactor 清理
MemoryStore FullEvent 内存/文件/DB 永久存储(不可变) 永久
graph TB
    EB["EventBus: AgentEvent"]
    SP["SessionProjection: EventReference[]"]
    MS["MemoryStore: FullEvent"]
    LLM["[]model.Message<br/>发给 LLM 的上下文"]
    TOOL["Tool"]

    EB -->|驱动 turn: Pull → RunFlow| SP
    EB -->|插件管线: 事件入库| MS
    MS -.同步追加轻量引用.-> SP
    SP -->|assembleRequest 原生渲染| LLM
    MS -->|recall 工具| TOOL

关键约束:投影只存轻量引用(key+type+summary);MemoryStore 是唯一完整事件链;压缩只改 LLM 视图与投影,永不动存储。

记忆三原语与压缩级联
graph LR
    A["事件原文<br/>(唯一全文接触点)"] -->|"L3 整段折叠:票据层(工程) + 综述层(LLM,可选)"| C["卡片行<br/>[evt_key] 任务骨架"]
    C -->|超限,卡片浓缩 condenseCardLines| D["浓缩卡片<br/>(保骨架+key引用)"]
  • 双层折叠:L3 整段离场时,工程票据层(卡片行 + [evt_key] 召回票据)恒在;配置 summary_model 时叠加单行 〔历史综述〕 LLM 滚动综述(增量合成、编译期常量限长,失败降级纯工程)
  • 成本可控:骨架定级与票据层纯工程零 LLM,开销只与新增段有关;LLM 仅两处低频叠加——L3 滚动综述(每轮折叠 1 次)与卡片超限浓缩(condenseCardLines),无模型时均降级为工程形态
  • 卡片序列:压缩后的历史保持为可读的卡片行([Compacted N] + 〔历史综述〕 + 卡片行 + recent keys),冥想沉淀带 ★ 高亮
  • 原文可忘,票据长存:卡片里的 [hex] key 就是召回票据——随时用 recall 取回原文(旧 legacy 管线的 L3 LLM 段摘要/固化物已移除,存量固化物保留 TTL 豁免、自然清退)
记忆数据模型(LSM)

存储按 LSM 树组织:事件从两条现役管线(EventBus 注入 / 框架 LLM 事件)汇入唯一写入路径(旧 legacy 压缩固化物管线已移除,存量固化物只读不清),顺序追加进按写入时间分段的存储;层级表示写入新近度与压实代数,封口/压实写入真实时间边界供查询剪枝;遗忘由压实、TTL、容量三层各自负责。

graph LR
    P["事件管线<br/>注入/LLM事件"] --> W["StoreEvent<br/>碰撞守卫+seq恢复"]
    W --> S["分段存储<br/>evt/idx/meta/tomb"]
    S --> L["L0活跃→L1封口→L2→L3<br/>压实写真实边界"]
    L --> R["召回:票据/语义/卡片"]
    F["遗忘:压实·TTL·容量"] -.墓碑.-> L
  • 召回与压缩同向:压缩丢旧留新,召回新先于旧——timestamp_desc 下截断只牺牲最旧,永不丢最新记忆
  • 两条时间轴Timestamp(事件时刻)是唯一语义时间轴;EventKey 内嵌时间(写入时刻)仅用于段放置与同毫秒决胜
  • 事件不可变:EventKey 是事件身份,重复写入被拒绝;重启后 seq 从已有最大值恢复,不覆写旧事件
  • 遗忘可配置:TTL 按事件类型衰减(固化物豁免),经 memory.lifecycle 声明;负全局 TTL = 总开关关闭遗忘

完整数据流、隐式连接与硬契约见 wiki/memory §16

⚙️ 六大机制速览

机制 亮点 详解
持久事件循环 Pull 批处理;async 结果排队不打断进行中 turn wiki/agent
上下文压缩 双层设计:发给 LLM 的视图分级压缩 + 工作内存滚动成卡片;容量单维触发(token 超阈才整理)+ 整理间渲染冻结(前缀字节稳定,缓存友好);进行中段工具调用历史折叠为工具链行(有界化,无零信息占位符);超大 settle 结果转储文件(事件本体有界,防召回复发);被丢弃的执行过程经 recall(turn_key=...) 因果链召回;永不修改已存储的事件 wiki/memory
事件驱动记忆 每个事件有全局唯一 key(时间有序);Agent 间存储隔离,跨 Agent 读需显式授权 wiki/memory
子 Agent 调用 event_params: [event_keys] 按 key 传事件(数据隔离);A2A 远程透明 wiki/tool
异步任务层 快命令秒回、慢任务后台通知;实时任务看板;resume_task 随时续跑;退出不留孤儿进程 wiki/tool
冥想心跳 空闲期自动回顾近期工作,总结沉淀为 ★ 卡片进入长期记忆 wiki/agent

🏗 架构

graph TB
    ROOT["tagent.New() 组合根"]
    TA["TagentAgent"]
    EB["EventBus"]
    CM["ContextManager"]
    SC["SmartCompressor"]
    CP["Compactor"]
    MM["MeditationManager"]
    MP["MemoryPlugin"]
    MS["MemoryStore"]
    RS["RelationStore"]
    ATW["AgentToolWrapper"]

    ROOT --> TA
    TA --> EB
    EB -->|Pull| TA
    TA -->|BuildInvocation + RunFlow| CM
    CM --> SC
    CM --> CP
    CM -->|runner.Run| LLMAGENT["框架 LLMAgent/Runner"]
    LLMAGENT -->|OnEvent| MP
    MP --> MS
    MS --> RS
    ATW -->|调用| TA
    TA --> MM
模块 职责
agent/ 事件驱动引擎:EventBus、runEventLoop、ContextManager(粘合层)、冥想、子 Agent 封装
agent/task/ 任务生命周期:TaskManager、完成探测、任务看板、重入
agent/compress/ 压缩域:上下文压缩、卡片序列、投影、token 计量
memory/ 结构化事件存储:InMemoryStore、FileSegmentStore、RelationStore、生命周期
plugin/ 框架插件:MemoryPlugin(持久化+因果链)、SummaryPlugin(元数据标注)
tool/ 工具:ActionTool(tmux)、recall/knowledge 子工具、任务工具族、文件工具
event/ 事件类型系统与元数据契约(FormatEventKey/ParseEventMeta
rl/ RL 集成:TrajectoryRecorder、SwappableModel、HTTPAPI
tagent.go + config.go 组合根与声明式配置

依赖全部单向无循环:root → agent → plugin → memorytool/* → memory

📐 设计哲学

四条承诺,贯穿所有机制:

  1. 事件不可变:发生过的事永久入库、永不修改——压缩、遗忘都只作用于"视图",不作用于事实
  2. 上下文有界:发给 LLM 的工作内存永远有预算上限,超限自动压缩——不靠无限窗口,靠分层记忆
  3. 召回精确:压缩掉的内容都留有票据(事件 key),按票取回原文,零幻觉
  4. 异步不失联:长任务先应答、完成后通知;通知自带完整上下文,压缩或乱序都不会产生"断线"的任务

更完整的设计论证(不变量、时间线渲染规则、元数据契约)见 docs/wiki/openspec/specs/

🔧 配置参考

全局选项
选项 默认值 说明
entry tagent 入口 Agent 名称
prompt_dir resources/prompts 全局 prompt 目录
model (必填) 默认模型名称
provider openai 默认 provider
providers {} provider 连接信息
log_level info 日志级别
request_timeout_seconds 3600 请求超时
trajectory_dump false 启用轨迹记录
trajectory_dir data/trajectories 轨迹文件目录
Agent 级选项
选项 默认值 说明
model / provider (继承全局) LLM 模型与 provider
system_prompt.files [] 加载的 prompt 文件
memory.type memory memory/file/localfile
memory.path "" 存储路径/标识
memory.read_namespaces [] 可读取的其他 agent 分区
max_tool_iterations 入口 50 / 子 10 最大 ReAct 迭代次数
max_tokens 入口 8000 / 子 4096 上下文 token 预算
compress_threshold 0.8 压缩触发比例——整理(compaction)的唯一触发条件(容量超阈才整理);task_settled 通知全文内联,整理间上下文前缀稳定以利缓存复用
keep_recent_tasks 2 整理后保留的最近任务数(L0 保留区与全文窗口派生的状态参数,不参与触发)
task_terminal_ttl "2m" 终态任务回收前保留期(也是终态任务的 resume_task 重入窗口)
resume_context_rounds 3 子 Agent 重入还原的前序轮次数
temperature 入口 0.7 / 子 0.3 LLM 温度
meditation.enabled false 启用冥想(interval/min_gap/prompt_file
compress 块(压缩家族)
选项 默认值 说明
summary_model / summary_provider (继承 agent) 压缩摘要专用模型(可用廉价模型)
card_max_chars 6000 卡片序列长度上限;超限旧卡 LLM 整理或沉底
compact_keys_listed 32 滚动摘要列出的 recent keys 上限
recent_full_count keep_recent_tasks × 4 全文解析窗口大小(未配置时派生,显式配置优先);在整理轮锚定、整理间冻结——锚点后的既有引用保持摘要渲染,新追加事件全文(活跃前沿),前缀字节稳定
summary_max_tokens 8192 每次摘要 LLM 调用的输出 token 预算下限(防 reasoning 模型挤空 Content)
工具引用(ToolRef)
字段 说明
kind agent(默认)或 tool
agent / id 子 Agent 名称 / 工具 ID
description_file 工具描述 prompt 文件
event_params 事件参数,如 [event_keys]
extra_params 附加路由参数声明(如 plan 的 action enum + name);调用时随 request 打包为 JSON 消息体透传子 Agent,未声明则消息体保持纯文本
async 子 Agent 是否走异步任务层(默认 true)
remote.url 远程 A2A Agent URL
properties 工具专属配置(exec: workspace/run_as_user/run_as_group

agent 运行参数(max_tool_iterations/max_tokens/temperature只在被引用 agent 自身的 agents.<name> 定义处配置——ToolRef 只声明引用关系。

📚 深入阅读

主题 文档
记忆架构 / 策展 / recall 协议 docs/wiki/memory/memory-architecture.md
工具架构 / 任务重入 / 会话回收 docs/wiki/tool/tool-architecture.md
Agent 架构 / 事件流 docs/wiki/agent/
事件系统 / 插件 / Prompt docs/wiki/
设计规格(OpenSpec) openspec/specs/
完整示例(WeChat Bot + RL) examples/wechat-bot/

开发

go build ./...                        # 构建(Go 1.21+)
go test ./...                         # 测试
bash scripts/race_check.sh            # race 门禁
cd examples/wechat-bot && go run .    # 运行示例

License

Apache License 2.0

Documentation

Overview

Package tagent provides the top-level composition root for tagent applications.

The root package encapsulates the agent instantiation process, assembling a TagentAgent with configured tools and wiring cross-boundary dependencies.

Tool Registration:

Built-in tools are registered via RegisterBuiltinTools() (see registry.go). External tools can be registered via RegisterPlainTool() and RegisterToolAgent(). Only tools that are both registered AND configured for an agent can be used.

This file contains factory functions for built-in plain tools.

Package tagent — ToolRegistry wraps the global tool registration maps from agent/tool_agent.go and provides a unified interface for:

  • Registering built-in tools (exec + knowledge/recall sub-tools)
  • Querying factories by ID
  • Validating that config-referenced tools are registered

Package tagent provides the top-level composition root for tagent applications.

The root package encapsulates the agent instantiation process, assembling a TagentAgent with configured tools and wiring cross-boundary dependencies.

Dependency direction (all one-way, no cycles):

tagent (root) → agent → plugin → memory
tagent (root) → tool/action → memory
tagent (root) → tool/recall → memory
tagent (root) → tool/knowledge → memory
tagent (root) → prompt

Tool Registration:

tagent uses a ToolRegistry to manage available tools. Built-in tools are registered via RegisterBuiltinTools(). External tools can be registered via RegisterPlainTool() and RegisterToolAgent(). Only tools that are both registered and configured for an agent can be used by that agent.

Usage:

ta, err := tagent.New(tagent.DefaultConfig(),
    tagent.WithModel(modelInstance),
)

testing.go provides exported helpers for integration tests in tests/. These expose internal APIs for comprehensive testing. Do NOT rely on them in production code — they may change without notice.

Convention: all symbols use the "Testing" prefix.

Index

Constants

View Source
const (
	DefaultEntry          = "tagent"
	DefaultPromptDir      = "resources/prompts"
	DefaultMaxToolIter    = 50
	DefaultMaxTokens      = 8000
	DefaultTemperature    = 0.7
	DefaultCompressThresh = 0.8

	DefaultAgentMaxToolIter = 10
	DefaultAgentMaxTokens   = 4096
	DefaultAgentTemp        = 0.3
)

Default values

View Source
const DefaultPromptsPrefix = "resources/prompts"

DefaultPromptsPrefix is the path prefix under which the embedded defaults live.

Variables

This section is empty.

Functions

func DefaultPromptsFS

func DefaultPromptsFS() embed.FS

DefaultPromptsFS returns the embedded framework default prompts. The tree is rooted at "resources/prompts" (e.g. "resources/prompts/recall_tool_desc.md").

func New

func New(cfg Config, opts ...Option) (*agent.TagentAgent, error)

New creates a fully-wired TagentAgent from declarative Config + runtime Options.

Config is declarative and serializable (loadable from YAML/JSON via LoadConfig). Options inject runtime-only dependencies (model instances, etc.).

New handles all cross-boundary wiring internally:

  • Registers built-in tools (knowledge, recall, exec)
  • Validates that all configured tools are registered
  • Resolves the entry agent from Config.Agents map
  • Creates a MemoryStore per agent (isolated, from MemoryConfig)
  • Builds tools by resolving ToolRef entries (agent refs → sub-agents)
  • For agent-kind tools: creates the referenced agent and wraps it via AgentToolWrapper which handles event_key → external context resolution
  • For tool-kind tools: delegates to registered plain tool factories

func RegisterBuiltinTools

func RegisterBuiltinTools() error

func TestingBuildAgent

func TestingBuildAgent(
	name string,
	acfg AgentConfig,
	cfg Config,
	m model.Model,
	skillRepo tagenttool.SkillRepository,
	mcpToolSets []trpctool.ToolSet,
	loader *prompt.Loader,
	cache map[string]*agent.TagentAgent,
) (*agent.TagentAgent, error)

TestingBuildAgent creates a TagentAgent using the internal build pipeline. Test-only — do NOT use in production code.

Types

type AgentConfig

type AgentConfig struct {
	// Model is the LLM model name (resolved at runtime). Falls back to Config.Model.
	Model string `json:"model,omitempty" yaml:"model,omitempty"`

	// Provider overrides the global default provider for this agent.
	// References a key in Config.Providers. Falls back to Config.Provider if empty.
	Provider string `json:"provider,omitempty" yaml:"provider,omitempty"`

	// PromptDir is the base directory for this agent's prompt files.
	// Falls back to Config.PromptDir.
	PromptDir string `json:"prompt_dir,omitempty" yaml:"prompt_dir,omitempty"`

	// SystemPrompt configures how to load this agent's system prompt.
	SystemPrompt PromptConfig `json:"system_prompt,omitempty" yaml:"system_prompt,omitempty"`

	// Memory configures this agent's own memory store.
	// Each agent has its own isolated storage. Defaults to in-memory store.
	Memory MemoryConfig `json:"memory,omitempty" yaml:"memory,omitempty"`

	// Tools declares which tools this agent uses.
	// Tools can reference other agents (agent kind) or plain tools (tool kind).
	Tools []ToolRef `json:"tools" yaml:"tools"`

	// Agent parameters
	MaxToolIterations int     `json:"max_tool_iterations,omitempty" yaml:"max_tool_iterations,omitempty"`
	MaxTokens         int     `json:"max_tokens,omitempty"          yaml:"max_tokens,omitempty"`
	Temperature       float64 `json:"temperature,omitempty"         yaml:"temperature,omitempty"`
	CompressThreshold float64 `json:"compress_threshold,omitempty"  yaml:"compress_threshold,omitempty"`
	KeepRecentTasks   int     `json:"keep_recent_tasks,omitempty"   yaml:"keep_recent_tasks,omitempty"`

	// TaskTerminalTTL is the grace period an exited task (completed/failed/
	// cancelled/dead) is retained before pruning, as a duration string
	// (e.g. "2m", "30m"). It bounds the resume_task window for terminal
	// subagent tasks. Empty/invalid → default "2m".
	TaskTerminalTTL string `json:"task_terminal_ttl,omitempty" yaml:"task_terminal_ttl,omitempty"`
	// ResumeContextRounds caps how many prior rounds the subagent task-chain
	// restorer injects on resume (default 3).
	ResumeContextRounds int            `json:"resume_context_rounds,omitempty" yaml:"resume_context_rounds,omitempty"`
	Compress            CompressConfig `json:"compress,omitempty" yaml:"compress,omitempty"`

	// Generation controls thinking/reasoning mode for the LLM.
	// When set, these fields are merged into model.GenerationConfig.
	ThinkingEnabled *bool   `json:"thinking_enabled,omitempty"  yaml:"thinking_enabled,omitempty"`
	ThinkingTokens  *int    `json:"thinking_tokens,omitempty"   yaml:"thinking_tokens,omitempty"`
	ReasoningEffort *string `json:"reasoning_effort,omitempty"  yaml:"reasoning_effort,omitempty"`
	// ReasoningContentMode controls how reasoning_content from history is handled.
	// "keep_all" (keep everything), "discard_previous" (default, keep current turn only),
	// "discard_all" (strip all reasoning_content).
	ReasoningContentMode string `json:"reasoning_content_mode,omitempty" yaml:"reasoning_content_mode,omitempty"`

	// Meditation configures the periodic meditation/heartbeat mechanism.
	// Only effective when the agent is started via StartLoop.
	Meditation MeditationConfig `json:"meditation,omitempty" yaml:"meditation,omitempty"`

	// WorkspaceRoot is the unified on-disk scratch root for this agent
	// (default: .tagent-workspace). Oversized tool outputs go to <root>/tool-output;
	// the tmux command working directory is <root>/exec. A periodic cleaner bounds
	// the accumulated files.
	WorkspaceRoot string `json:"workspace_root,omitempty" yaml:"workspace_root,omitempty"`

	// Description for agent.Agent interface (used when this agent is a sub-agent)
	Description string `json:"description,omitempty" yaml:"description,omitempty"`
}

AgentConfig describes a single agent's configuration. Each agent only cares about itself and who it communicates with.

type CompressConfig

type CompressConfig struct {
	// CompactKeysListed caps the keys listed in the rolling compaction
	// summary (default 32); older events stay retrievable via recall.
	CompactKeysListed int `json:"compact_keys_listed,omitempty" yaml:"compact_keys_listed,omitempty"`
	// RecentFullCount is how many most-recent refs resolve with full content
	// from MemoryStore. Unset (0) derives keep_recent_tasks × 4 so the most
	// recent complete turns resolve full as a whole; explicit values win.
	RecentFullCount int `json:"recent_full_count,omitempty" yaml:"recent_full_count,omitempty"`
	// CardMaxChars caps the index-card section of the rolling compaction
	// summary (default 6000); beyond it old card lines are LLM-condensed
	// (with summary_model) or sink into an "earlier n items" counter.
	CardMaxChars int `json:"card_max_chars,omitempty" yaml:"card_max_chars,omitempty"`

	// SummaryMaxTokens is the floor for the output-token budget reserved on each
	// summary LLM call (0 = package default 8192). Reasoning models spend part
	// of max_tokens on their thinking chain; too small a budget returns empty
	// Content and degrades compression. The per-call budget scales up with the
	// summary size but never below this floor.
	SummaryMaxTokens int `json:"summary_max_tokens,omitempty" yaml:"summary_max_tokens,omitempty"`

	// SummaryModel is the model name for LLM summary compression.
	// Falls back to the agent's main model if empty.
	SummaryModel string `json:"summary_model,omitempty" yaml:"summary_model,omitempty"`
	// SummaryProvider is the provider name for the summary model.
	// Falls back to the agent's provider if empty.
	SummaryProvider string `json:"summary_provider,omitempty" yaml:"summary_provider,omitempty"`
}

CompressConfig configures SmartCompressor parameters.

type Config

type Config struct {
	// Entry specifies which agent in the Agents map is the top-level agent.
	// Defaults to "tagent" if empty.
	Entry string `json:"entry" yaml:"entry"`

	// Agents maps agent name → AgentConfig. Each agent is independently configured.
	Agents map[string]AgentConfig `json:"agents" yaml:"agents"`

	// PromptDir is the global base directory for prompt file resolution.
	// Individual agents can override this via their own PromptDir field.
	PromptDir string `json:"prompt_dir" yaml:"prompt_dir"`

	// Model is the global default model name (resolved at runtime).
	// Individual agents can override this via their own Model field.
	Model string `json:"model" yaml:"model"`

	// Provider is the global default model provider name (e.g., "openai", "anthropic").
	// Defaults to "openai" if empty. Agents can override via AgentConfig.Provider.
	Provider string `json:"provider,omitempty" yaml:"provider,omitempty"`

	// Providers maps provider name → connection info (endpoint, api_key_env).
	// Each agent references a provider by name to resolve its model instance.
	// Example:
	//   providers:
	//     openai:
	//       api_endpoint: "https://open.bigmodel.cn/api/paas/v4"
	//       api_key_env: "ZAI_API_KEY"
	//     anthropic:
	//       api_endpoint: "https://api.anthropic.com"
	//       api_key_env: "ANTHROPIC_API_KEY"
	Providers map[string]ProviderConfig `json:"providers,omitempty" yaml:"providers,omitempty"`

	// APIEndpoint is the LLM API base URL (e.g., "https://open.bigmodel.cn/api/paas/v4").
	APIEndpoint string `json:"api_endpoint,omitempty" yaml:"api_endpoint,omitempty"`

	// APIKeyEnv is the environment variable name holding the API key.
	// Defaults to "ZAI_API_KEY" if empty.
	APIKeyEnv string `json:"api_key_env,omitempty" yaml:"api_key_env,omitempty"`

	// LogLevel controls framework (trpc-agent-go/log) verbosity.
	// One of: "debug", "info", "warn", "error".
	// Can be overridden by the LOG_LEVEL environment variable.
	LogLevel string `json:"log_level,omitempty" yaml:"log_level,omitempty"`

	// RequestTimeoutSeconds is the per-request timeout in seconds (0 = default 3600).
	RequestTimeoutSeconds int `json:"request_timeout_seconds,omitempty" yaml:"request_timeout_seconds,omitempty"`

	// App holds application-specific configuration (e.g., wechat bot settings).
	// Each application deserializes this into its own typed struct.
	// This keeps Config generic — no app-specific fields pollute the shared structure.
	App map[string]any `json:"app,omitempty" yaml:"app,omitempty"`

	// TrajectoryDump enables recording every LLM call to JSONL files on disk.
	// Default: false. When true, a TrajectoryRecorder wraps the model.
	TrajectoryDump bool `json:"trajectory_dump,omitempty" yaml:"trajectory_dump,omitempty"`

	// TrajectoryDir is the directory for trajectory JSONL files.
	// Default: "data/trajectories". Each session gets its own file: {dir}/{session_id}.jsonl
	TrajectoryDir string `json:"trajectory_dir,omitempty" yaml:"trajectory_dir,omitempty"`
}

Config is the top-level tagent configuration. Declarative and serializable — loadable from YAML or JSON. Runtime-only dependencies (model instances, memory stores, etc.) are injected via Option functions.

The configuration follows an agent-centric design: each agent describes its own settings (model, memory, tools) and its communication intent (which agents it calls). The top-level Config holds a map of agent configs, keyed by agent name.

Example YAML:

agents:
  tagent:
    model: glm-4-flash
    prompt_dir: resources/prompts
    system_prompt:
      files: [AGENTS.md, SOUL.md, USER.md, TOOLS.md]
    memory:
      type: file
      path: /data/tagent/events
    tools:
      - agent: knowledge
        description_file: knowledge_tool_desc.md
        event_params: [event_key]
      - agent: recall
        description_file: recall_tool_desc.md
        event_params: [event_key]
      - kind: tool
        id: action
        description_file: action_tool_desc.md
  knowledge:
    model: glm-4-flash
    prompt:
      files: [knowledge_agent.md]
    memory:
      type: memory
    max_tool_iterations: 5
    max_tokens: 4096
  recall:
    model: glm-4-flash
    prompt:
      files: [recall_agent.md]
    memory:
      type: memory
    max_tool_iterations: 5

func DefaultConfig

func DefaultConfig() Config

DefaultConfig returns a Config with sensible defaults and the three core agents.

func LoadConfig

func LoadConfig(path string) (*Config, error)

LoadConfig loads configuration from a YAML or JSON file. Format is auto-detected from the file extension (.yaml/.yml → YAML, .json → JSON).

func (*Config) APIKey

func (c *Config) APIKey() string

APIKey returns the API key from the environment variable specified by APIKeyEnv.

func (*Config) ApplyDefaults

func (c *Config) ApplyDefaults()

ApplyDefaults fills in zero/empty values with defaults.

func (*Config) ResolveAgentProvider

func (c *Config) ResolveAgentProvider(agentName string) (endpoint, apiKeyEnv string, err error)

ResolveAgentProvider returns the resolved API endpoint and API key environment variable name for the given agent. It honors the agent's provider override (AgentConfig.Provider) and falls back to the global provider settings. Pass an empty agentName to resolve the global provider.

func (*Config) Validate

func (c *Config) Validate() error

Validate checks the config for errors after defaults are applied.

type ExtraParam

type ExtraParam = agent.ExtraParam

ExtraParam re-exports agent.ExtraParam for YAML/JSON config declaration (ToolRef.extra_params).

type LifecycleConfig

type LifecycleConfig struct {
	// GlobalTTLDays is the default time-to-live in days (default: 7).
	// Negative = disable TTL entirely (no event is ever tombstoned by age).
	GlobalTTLDays *int `json:"global_ttl_days,omitempty" yaml:"global_ttl_days,omitempty"`

	// TypeTTL overrides the global TTL per event type (days).
	// Negative value = exempt (curated artifacts never expire).
	TypeTTL map[string]int `json:"type_ttl,omitempty" yaml:"type_ttl,omitempty"`

	// CheckInterval is how often the lifecycle scanner runs (e.g., "1h"). Default: "1h".
	CheckInterval string `json:"check_interval,omitempty" yaml:"check_interval,omitempty"`

	// MaxEventsPerPartition caps events per partition (0 = unlimited, default).
	MaxEventsPerPartition *int `json:"max_events_per_partition,omitempty" yaml:"max_events_per_partition,omitempty"`
}

LifecycleConfig declares the forgetting policy over YAML/JSON. Unset fields fall back to memory.DefaultLifecycleConfig values.

type MeditationConfig

type MeditationConfig struct {
	// Enabled activates the meditation ticker.
	Enabled bool `json:"enabled" yaml:"enabled"`

	// Interval is the check interval (e.g., "30m"). Default: "30m".
	Interval string `json:"interval,omitempty" yaml:"interval,omitempty"`

	// MinGap is the minimum idle duration before meditation fires (e.g., "2h"). Default: "2h".
	MinGap string `json:"min_gap,omitempty" yaml:"min_gap,omitempty"`

	// PromptFile is the meditation prompt file (relative to prompt_dir). Default: "meditation.md".
	PromptFile string `json:"prompt_file,omitempty" yaml:"prompt_file,omitempty"`
}

MeditationConfig configures the periodic meditation/heartbeat mechanism. Uses string durations (e.g., "30m", "2h") for YAML/JSON serialization. tagent.go converts these to time.Duration for agent.MeditationConfig.

type MemoryConfig

type MemoryConfig struct {
	// Type selects the memory store implementation:
	//   "memory"    — in-memory store (default, lost on process exit)
	//   "file"      — file-backed persistent store (requires rustviking CLI)
	//   "localfile" — file-backed persistent store (JSON file KV, no external deps)
	Type string `json:"type" yaml:"type"`

	// Path is the storage location identifier:
	//   - For "file"/"localfile" type: filesystem directory path
	//   - For "memory" type: logical store identifier — agents with the same
	//     type: memory and same path share a single InMemoryStore instance
	//   Empty value means an isolated store (no sharing).
	Path string `json:"path,omitempty" yaml:"path,omitempty"`

	// ReadNamespaces lists agent names whose storage partitions this agent
	// is allowed to read. Each name is converted to a PartitionID at build time.
	// For example, recall can read tagent's events by declaring:
	//   read_namespaces: [tagent]
	// This enables cross-agent memory access across partitions.
	ReadNamespaces []string `json:"read_namespaces,omitempty" yaml:"read_namespaces,omitempty"`

	// RustVikingBinary sets the rustviking CLI binary path for "file" type stores.
	// Empty value uses "rustviking" (looked up via PATH).
	RustVikingBinary string `json:"rustviking_binary,omitempty" yaml:"rustviking_binary,omitempty"`

	// Lifecycle configures TTL / capacity-based forgetting for this store.
	// Nil keeps the built-in defaults (global TTL 7d, per-type table, 1h checks).
	Lifecycle *LifecycleConfig `json:"lifecycle,omitempty" yaml:"lifecycle,omitempty"`
}

MemoryConfig configures an agent's memory store. Each agent has its own isolated storage instance.

type Option

type Option func(*runtimeConfig)

Option injects runtime-only dependencies that cannot be serialized.

func WithMCPToolSets

func WithMCPToolSets(ts []trpctool.ToolSet) Option

WithMCPToolSets sets the MCP tool sources for knowledge agent.

func WithModel

func WithModel(m model.Model) Option

WithModel sets the resolved model instance (required). This is the default model; individual agents can override via AgentConfig.Model.

func WithModelOverrides

func WithModelOverrides(overrides map[string]model.Model) Option

WithModelOverrides injects pre-resolved model instances for specific agents. This supports scenarios like SwappableModel for entry agent (AReaL proxy). The map key is the agent name, the value is the model instance to use.

func WithSkillRepo

func WithSkillRepo(sr tool.SkillRepository) Option

WithSkillRepo sets the skill repository for knowledge agent.

func WithSummaryModel

func WithSummaryModel(m model.Model) Option

WithSummaryModel sets the model for Stage 2 LLM summary compression.

type PromptConfig

type PromptConfig = prompt.CompositeConfig

PromptConfig is an alias for prompt.CompositeConfig, providing bootstrap-style prompt loading aligned with nanobot's pattern (AGENTS.md, SOUL.md, USER.md, TOOLS.md).

Prompt composition order: inline → files (in order) → directory scan.

type ProviderConfig

type ProviderConfig struct {
	// Provider is the protocol implementation to use (e.g., "openai", "anthropic", "gemini").
	// Most domestic models (GLM, DeepSeek, Moonshot, etc.) use OpenAI-compatible protocol,
	// so this field should be "openai" with different api_endpoint to distinguish providers.
	// Defaults to the provider registry key name if not specified.
	// e.g., "openai" for OpenAI-compatible APIs (OpenAI/ZhiPu/DeepSeek/Moonshot/Baichuan/Qwen),
	//       "anthropic" for Anthropic Claude,
	//       "gemini" for Google Gemini.
	Provider string `json:"provider,omitempty" yaml:"provider,omitempty"`

	// APIEndpoint is the base URL for the provider's API.
	// e.g., "https://open.bigmodel.cn/api/paas/v4" for ZhiPu,
	//       "https://api.anthropic.com" for Anthropic.
	APIEndpoint string `json:"api_endpoint" yaml:"api_endpoint"`

	// APIKeyEnv is the environment variable name holding the API key for this provider.
	// e.g., "ZAI_API_KEY", "ANTHROPIC_API_KEY".
	APIKeyEnv string `json:"api_key_env,omitempty" yaml:"api_key_env,omitempty"`
}

ProviderConfig holds connection info for a model provider. Used in Config.Providers to declare provider endpoints and credentials.

type RemoteConfig

type RemoteConfig struct {
	// URL is the A2A agent card endpoint (e.g., "http://knowledge-service:8088").
	// The remote agent must expose an A2A server with agent card at /.well-known/agent.json.
	URL string `json:"url" yaml:"url"`
}

RemoteConfig declares A2A connection info for a remote sub-agent. tagent YAML only declares the URL; trpc communication options (TransferStateKey, streaming, etc.) are derived internally by tagent.go.

type ToolKind

type ToolKind string

ToolKind distinguishes tool agents from plain tools.

const (
	// ToolKindAgent: TagentAgent wrapped as CallableTool.
	// Has internal React loop, system prompt, and sub-tools.
	ToolKindAgent ToolKind = "agent"

	// ToolKindTool: directly implements CallableTool.
	// Pure execution tool with no internal React loop.
	ToolKindTool ToolKind = "tool"
)

type ToolRef

type ToolRef struct {
	// Kind distinguishes agent tools from plain tools. Defaults to "agent".
	Kind ToolKind `json:"kind" yaml:"kind"`

	// AgentID references another agent in the Agents map (kind=agent).
	// The referenced agent becomes a CallableTool for this agent.
	AgentID string `json:"agent,omitempty" yaml:"agent,omitempty"`

	// ID is the tool identifier for plain tools (kind=tool).
	ID string `json:"id,omitempty" yaml:"id,omitempty"`

	// Tool description: inline or from file (relative to prompt_dir)
	Description     string `json:"description,omitempty"      yaml:"description,omitempty"`
	DescriptionFile string `json:"description_file,omitempty" yaml:"description_file,omitempty"`

	// EventParams declares which event-derived parameters this tool requires.
	// When the parent agent's LLM outputs a tool call, it includes these parameter values
	// (e.g., "event_key"). The tool wrapper then resolves them: for event_key, it fetches
	// the complete event data from the parent agent's MemStore and passes it as external
	// context to the tool agent. This prevents the LLM from breaking context isolation —
	// the LLM only outputs a numeric key, but the actual event content is resolved server-side.
	EventParams []string `json:"event_params,omitempty" yaml:"event_params,omitempty"`

	// ExtraParams declares additional routing-level parameters for agent-kind
	// tools (plan-interaction-contract D2). Each declared parameter is added to
	// the tool's InputSchema and, when present in a call, packed together with
	// request into a JSON message body passed to the sub-agent (e.g. plan's
	// action/name). Tools without extra_params keep the plain-text request
	// message unchanged.
	ExtraParams []ExtraParam `json:"extra_params,omitempty" yaml:"extra_params,omitempty"`

	// Async controls whether an agent-kind tool may run through the async task
	// layer (sync-wait window → inline result or background ack + task_settled).
	// nil/true = async allowed (default); false = always run synchronously —
	// an operator knob to reduce cognitive load on weaker models that struggle
	// with ack/notification semantics.
	Async *bool `json:"async,omitempty" yaml:"async,omitempty"`

	// Properties holds tool-specific configuration that each tool factory
	// deserializes into its own typed struct. This keeps ToolRef generic
	// — no tool-specific fields pollute the shared structure.
	//
	// Example (action tool):
	//
	//	properties:
	//	  workspace: /tmp/tagent-workspace
	//	  run_as_user: tagent-runner
	//	  run_as_group: tagent-runner
	Properties map[string]any `json:"properties,omitempty" yaml:"properties,omitempty"`

	// Remote declares that this agent tool is a remote A2A agent.
	// When set, tagent creates an a2aagent.A2AAgent instead of a local TagentAgent.
	// The URL is the agent card endpoint (e.g., "http://knowledge-service:8088").
	// Context is passed via RuntimeState → A2A metadata (auto-mapped by trpc framework).
	//
	// This field embodies the configuration layer separation:
	//   - tagent YAML: agent definition (model, prompt, etc.) — here
	//   - ToolRef.Remote.URL: connection info ("where is this agent?") — here
	//   - trpc Go options: communication details (A2A protocol, TransferStateKey) — internal
	Remote *RemoteConfig `json:"remote,omitempty" yaml:"remote,omitempty"`

	// Extension: custom factory path (for non-builtin tools/agents)
	Factory string `json:"factory,omitempty" yaml:"factory,omitempty"`
}

ToolRef declares a tool that an agent uses. For agent-kind tools, the AgentID field references another AgentConfig in the Agents map. For tool-kind tools, the ID field identifies the plain tool factory.

type ToolRegistry

type ToolRegistry struct{}

ToolRegistry is a facade over the agent package's global tool registration maps. It provides a unified entry point for tool registration, lookup, and validation.

The actual factory maps live in agent/tool_agent.go as package-level variables. ToolRegistry delegates to those maps so callers can register tools via either the ToolRegistry API or agent.RegisterPlainTool / agent.RegisterToolAgent directly.

func GetRegistry

func GetRegistry() *ToolRegistry

GetRegistry returns the global ToolRegistry singleton.

func (*ToolRegistry) GetPlainToolFactory

func (r *ToolRegistry) GetPlainToolFactory(id string) (agent.PlainToolFactory, bool)

GetPlainToolFactory returns the factory for the given plain tool ID.

func (*ToolRegistry) GetToolAgentFactory

func (r *ToolRegistry) GetToolAgentFactory(id string) (agent.ToolAgentFactory, bool)

GetToolAgentFactory returns the factory for the given tool agent ID.

func (*ToolRegistry) RegisterPlainTool

func (r *ToolRegistry) RegisterPlainTool(id string, factory agent.PlainToolFactory)

RegisterPlainTool registers a plain tool factory. Delegates to agent.RegisterPlainTool.

func (*ToolRegistry) RegisterToolAgent

func (r *ToolRegistry) RegisterToolAgent(id string, factory agent.ToolAgentFactory)

RegisterToolAgent registers a tool agent factory. Delegates to agent.RegisterToolAgent.

func (*ToolRegistry) ValidateToolAccess

func (r *ToolRegistry) ValidateToolAccess(cfg *Config) error

ValidateToolAccess checks that all config-referenced plain tools (kind: tool) are registered in the ToolRegistry. Returns an error on the first unregistered tool.

Agent-kind tools (kind: agent) are not checked here — they reference other agents in the Config.Agents map, which is validated separately in Config.Validate().

Directories

Path Synopsis
Package agent provides tagent's core agent mechanism coordination.
Package agent provides tagent's core agent mechanism coordination.
Package-level event metadata contract (unified-event-projection D4).
Package-level event metadata contract (unified-event-projection D4).
Package prototype contains the original 126-line tagent skeleton.
Package prototype contains the original 126-line tagent skeleton.
Package rl provides reinforcement learning utilities for tagent agents.
Package rl provides reinforcement learning utilities for tagent agents.
file
Package file wraps trpc-agent-go's built-in file operation tools for tagent.
Package file wraps trpc-agent-go's built-in file operation tools for tagent.
knowledge
Package knowledge provides tools for the Knowledge Agent (skill search + web search + MCP discovery).
Package knowledge provides tools for the Knowledge Agent (skill search + web search + MCP discovery).
plan
Package plan implements the PlanAgent — a TagentAgent wrapper with custom Run that bypasses the LLM for progress queries.
Package plan implements the PlanAgent — a TagentAgent wrapper with custom Run that bypasses the LLM for progress queries.
recall
memory_recall: the recall PROTOCOL implementation (unified-memory-curation D6), now internal — the model-facing entry is the unified `recall` tool (recall.go, stable-context-compaction D7) which routes items/query through recallByItems/recallByQuery below.
memory_recall: the recall PROTOCOL implementation (unified-memory-curation D6), now internal — the model-facing entry is the unified `recall` tool (recall.go, stable-context-compaction D7) which routes items/query through recallByItems/recallByQuery below.
spec
Package spec provides an LLM-facing tool for managing specification-driven work plans (create / status / validate / archive / …) without handing the agent a general shell.
Package spec provides an LLM-facing tool for managing specification-driven work plans (create / status / validate / archive / …) without handing the agent a general shell.
task
Package task provides LLM-facing tools for managing async background tasks tracked by the agent's TaskManager: listing, cancelling, and relaunching.
Package task provides LLM-facing tools for managing async background tasks tracked by the agent's TaskManager: listing, cancelling, and relaunching.
Package workspace centralizes tagent's on-disk scratch space (oversized tool outputs) under one root, and provides a periodic cleaner that bounds the accumulated files (by age and count).
Package workspace centralizes tagent's on-disk scratch space (oversized tool outputs) under one root, and provides a periodic cleaner that bounds the accumulated files (by age and count).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL