Agent Development Kit (ADK) · 09 - Context

Posted on Sep 23, 2026

ADK-Go 源码阅读笔记 · Context:上下文能力、状态变化与恢复边界

源码基准:ADK-Go v2.4.0,commit 4e57df40cbd35f055ba654b03ffb0e509fdd754a。本文的“当前实现”均指这个版本。

范围:公开 Context 接口、commonContext、callback/tool wrapper、状态与 artifact 追踪、派生和恢复信息;workflow 调度算法见配套文章。

返回 ADK 源码阅读合集 · 配套阅读:Agent、Runner、Flow、Tool、Workflow、Session Event。

工具函数收到一个 agent.Context,里面既能读用户输入,也能写状态、搜索 Memory、请求用户确认。它究竟是一份数据、一组服务,还是一个可以随时结束 Agent 的控制器?

答案需要分两层:Context 接口列出运行能力,具体构造器和 wrapper 决定当前调用点真正可用的能力。 同样写着 agent.Context,Agent 回调、工具、workflow 节点收到的对象并不完全相同。

本文用“杭州天气怎么样”贯穿:weather_agent 调用 get_weather,工具写入 last_city=Hangzhou,然后返回天气。第四节再把工具改成需要确认的“购买天气报告”,观察正常读写与暂停恢复的区别。

本文回答三个问题:

  1. Go context、InvocationContext、ReadonlyContext、Context 各自提供什么?
  2. 工具写入的状态怎样进入 Event,何时才涉及持久化?
  3. Context 派生、取消、分支和确认能保证什么,又不能保证什么?

阅读前先分清这些词

术语含义不应混成
Go ContextDeadline、Done、Err、Value 的请求链Session 状态容器
InvocationContext当前 Agent、Session、服务和 invocation 环境单次模型请求
EventActions.StateDelta本事件声明的状态变化Context 派生用的 Delta
FunctionCallID模型要求的一次函数调用 IDEvent.ID 或 InterruptID
InterruptIDworkflow 等待外部响应的中断键当前节点 RunID
Branch / IsolationScope历史选择条件用户权限或数据库隔离

一、源码入口与阅读地图

阅读顺序文件 / 符号要回答的问题
1agent/context.go三个公开接口之间到底怎样组合?
2internal/context/invocation_context.goRunner 创建的基础环境在哪里?
3agent/common_context.gocallbacks、tools、nodes 怎样共享实现?
4callback_context_wrapper.go、tool_context_wrapper.go同一接口在不同调用点有哪些护栏?
5agent/common_context_delta.go浅拷贝派生保留和替换哪些字段?
6internal/llminternal/request_confirmation_processor.go确认对象怎样在下一次输入后重建?
7runner/run_node.go、runner/runner.go谁把 Context 里的 actions 接到 Event 和存储?
应用的 context.Context
          │ Runner 注入父子树、Plugin、运行配置等 Value
          ▼
internal/context.InvocationContext
  ├─ Session、Agent、InvocationID、UserContent
  ├─ Artifacts、Memory、RunConfig
  └─ Branch、IsolationScope、Ended
          │
          ▼
agent.commonContext
  ├─ Go Context 链 + invocation 环境
  ├─ actions / artifacts
  ├─ functionCallID / confirmation
  └─ resumeInputs / Path / RunID / SubScheduler
          │
      按场景构造
  ┌───────┼─────────────────┐
  ▼       ▼                 ▼
普通节点  callback wrapper  tool wrapper

public API 位于 agent;internal/context 是 Runner 等框架代码使用的适配层,应用不能从模块外直接导入 internal。业务扩展通常由框架把 Context 传进 callback、工具或节点函数。

二、核心接口与数据结构

1. 三个接口是组合关系

以下为 context.go#L63-L159 的删节摘录;省略服务和派生方法,只保留足以看清关系的字段:

type InvocationContext interface {
    context.Context
    Agent() Agent
    Session() session.Session
    InvocationID() string
    Branch() string
    IsolationScope() string
    UserContent() *genai.Content
    RunConfig() *RunConfig
    EndInvocation()
    Ended() bool
    ResumedInput(interruptID string) (any, bool)
    // 省略 Artifacts、Memory、WithContext、WithICDelta。
}

type ReadonlyContext interface {
    context.Context
    UserContent() *genai.Content
    InvocationID() string
    AgentName() string
    ReadonlyState() session.ReadonlyState
    UserID() string
    AppName() string
    SessionID() string
    Branch() string
}

type Context interface {
    ReadonlyContext
    InvocationContext
    State() session.State
    FunctionCallID() string
    Actions() *session.EventActions
    // 省略 artifact、memory、confirmation、node 和派生方法。
}

Context 同时包含 InvocationContext 和 ReadonlyContext,而后两者不互相包含。静态类型为 InvocationContext 的变量没有 AgentName、ReadonlyState、UserID 等方法,不能直接赋给 ReadonlyContext;能从 Session 间接推导这些值,不改变 Go 的接口方法集合。

三个接口都嵌入 Go context,因此 Context 自身可以直接传给支持 context.Context 的 HTTP、模型或存储 API。

2. Invocation、Agent call、step 的区别

context.go 的原始注释用下面的结构解释调用层次(L28-L62):

invocation e-1
  ├─ weather_agent.Run
  │    ├─ step 1: LLM → get_weather
  │    └─ step 2: LLM → 最终答案
  └─ 也可能继续 transfer 到另一个 Agent

工具结果回来后再交给模型总结,需要新的一次模型调用,所以是新的 step。HITL 恢复可能在下一次 Runner 调用时沿用 invocation ID;一次 HTTP 请求也不一定等于一次完整 invocation。

3. commonContext 有两条上下文链

结构定义 的删节摘录:

type commonContext struct {
    context.Context
    invocationContext InvocationContext
    artifacts         Artifacts
    actions           *session.EventActions

    functionCallID   string
    toolConfirmation *toolconfirmation.ToolConfirmation

    resumeInputs       map[string]any
    path, runID        string
    subScheduler       DynamicSubScheduler
    outputForAncestors []string
}

内嵌的 Go Context 决定 Done / Err / Value;invocationContext 决定 Agent、Session、InvocationID、服务等 ADK 环境。它们经常来自同一个父对象,但派生 API 不一定同时改两者,第四节会解释差别。

4. 谁创建、修改和消费

对象 / 字段创建者修改者消费者天气例子
基础 InvocationContextRunner派生方法按字段替换Agent、Flowe-1 / weather_agent
callback actionscallback 构造器或调用方当前 callback 的 State 写入callback Event 构造者last_city
tool ContextFlow / tool node工具写 Actions、State、确认Flow / node 创建工具 Eventcall-1
StateDeltaactions 初始化或事件创建State.Set / 工具代码Session Servicelast_city=Hangzhou
confirmation恢复处理器或首次请求RequestConfirmation 初始化工具判断 Confirmed未确认 / 批准 / 拒绝
resumeInputsworkflow 激活时注入调度器当前节点 ResumedInputinterrupt-1 的 payload

ReadonlyContext 只是收窄写方法。UserContent() 返回指针,ReadonlyState() 仍委托当前 Session State,没有深拷贝或冻结;见 readonly_context.go#L26-L72。

三、主执行路径:从天气工具到事件状态

1. Runner 创建,Agent 派生,Flow 再创建工具 Context

普通 Runner 先用内部构造器绑定 Session、服务、Agent、UserContent、RunConfig、InvocationID;基础构造器在未传 ID 时生成 e- 前缀的 UUID。见 invocation_context.go#L27-L54。

Agent.Run 派生当前 Agent Context,Flow 收到函数调用后,再调用 NewToolContext(ic, "call-1", actions, confirmation)。该构造器:

  1. 若输入是原生 commonContext,浅拷贝其字段;否则以 InvocationContext 为底层包装。
  2. 空 FunctionCallID 才生成 UUID。
  3. 准备 StateDelta、ArtifactDelta map。
  4. 设置本次函数 ID、确认对象、tracked artifacts。
  5. 返回 toolContextWrapper。

见 common_context.go#L106-L155。

2. 工具 State.Set 同时触及两处

假设 Session 当前 last_city=Beijing,工具执行:

// 工具处理函数中的示意片段,不是完整工具定义。
if err := ctx.State().Set("last_city", "Hangzhou"); err != nil {
    return nil, err
}

变化为:

之前
  Session.State["last_city"] = Beijing
  actions.StateDelta        = {}

State.Set("last_city", "Hangzhou")
  ① actions.StateDelta["last_city"] = Hangzhou
  ② Session.State().Set("last_city", "Hangzhou")

之后
  工具再调用 State.Get → 优先读 delta → Hangzhou
  工具 Event.Actions.StateDelta → {last_city: Hangzhou}
  Runner.AppendEvent → Session Service 的持久化 / 应用规则

源码 callbackContextState 的关键摘录如下,省略了 nil 检查:

func (c *callbackContextState) Set(key string, val any) error {
    if c.ctx.actions != nil && c.ctx.actions.StateDelta != nil {
        c.ctx.actions.StateDelta[key] = val
    }
    return c.ctx.invocationContext.Session().State().Set(key, val)
}

Set 既不只是写一个待提交 map,也不等于数据库提交成功。它写当前 Session State,事件 delta 还要由创建者放入 Event,再进入 Session Service 的 AppendEvent 路径。服务后端具体怎样保存,由其实现决定。

3. 读、写、遍历的语义不完全对称

方法实际顺序影响
State.Get先查 actions.StateDelta,再查 Session.State同一个工具能读到刚写的 delta
State.Set先写 delta,再调用底层 State.Set底层报错前 delta 可能已修改
State.All直接返回底层 State.All不是“底层 + delta”独立合并视图
ReadonlyState直接返回 Session.State 的只读接口不经过 callback delta 的优先读逻辑

若底层 State.Set 失败,框架这里没有撤回先写入的 delta。业务应处理错误,不能把“没有返回成功”推断为“所有内存变化都没发生”。

如果取出 map 或 slice 后原地修改,也未必会产生 StateDelta;需要显式 Set,并自行管理共享引用。Context 不知道任意对象内部发生了什么。

4. 事件把状态变化交给下一步

图中表示非 partial 工具事件成功追加的正常路径:AppendEvent 属于 SessionService,Session 是本次运行持有的历史与状态视图。下一 step 的 ContentsRequestProcessor 直接遍历 ctx.Session().Events(),并不是每一步重新调用 SessionService.Get 查询数据库;见 contents_processor.go#L88-L102。

Context 不自行 yield。它收集变化并暴露服务;Flow、Agent 或 workflow node 才构建事件,Runner 才消费普通事件。仅手动创建 Context 并写 actions,而不把 actions 接进 Event,Runner 不会扫描内存自动发现它。

5. Artifact 是已执行保存 + 版本记录

工具的 trackedArtifacts.Save 先调用底层保存,成功后才把版本写入 ArtifactDelta[name]。版本记录不是文件字节,也不是延期保存请求。

ctx.Artifacts().Save("weather.txt", data)
    → Artifact Service 保存内容
    → 返回 version=2
    → actions.ArtifactDelta["weather.txt"] = 2
    → 工具 Event 携带版本变更

若后面的 Event 持久化失败,已经保存的 artifact 不会由 Context 自动删除。这里没有跨 Artifact Service 和 Session Service 的事务。见 common_context.go#L464-L495。

四、关键细节与分支

4.1 同样的 Context 接口,不同 wrapper 能力

callback/tool wrapper 不是透明代理。以下是 v2.4.0 的具体行为:

方法callback wrappertool wrapper
AgentName / 用户会话身份、Branch转发转发
State / ReadonlyState / Artifacts转发转发
Deadline / Done / Err / Value转发转发
Actions / FunctionCallID日志 + nil / 空串转发
SearchMemory / RequestConfirmation日志 + error转发
ToolConfirmation日志 + nil转发
Agent / Session / Memory / RunConfig日志 + nil日志 + nil
EndInvocation / Endedno-op / false,并记日志no-op / false,并记日志
WithAgentTimeout日志 + (nil, nil)日志 + (nil, nil)
WithAgentCancel日志 + (nil, nil)转发
Path / SubScheduler / OutputForAncestors空值并记日志转发
ResumedInput / RunID空值并记日志空值并记日志

源码:callback_context_wrapper.go#L36-L258、tool_context_wrapper.go#L35-L244。

例如工具搜索 Memory 应调用 ctx.SearchMemory(ctx, query);ctx.Memory() 在工具 wrapper 中返回 nil。普通 Agent callback 不支持这两个入口。

接口声明存在,不等于当前调用点获得有效实现。Runner 的 run 级 Plugin 可以直接收到普通 Context,因此不能把这张 callback-wrapper 表扩大为“所有名字包含 callback 的函数都一样”。

这也解释 Agent before 返回 Content 为何能结束 Agent:结束动作由框架拿着外层 InvocationContext 执行;它不是让用户 callback 调用 wrapper.EndInvocation。

4.2 构造函数相近,保留的数据却不同

构造入口关键行为
NewContext创建普通 Context;传入原生 commonContext 时只保留两条基础 context 引用
Promote已是原生 commonContext 则原样返回,否则包装
PromoteWithDeltaPromote 后 WithDelta
NewCallbackContext准备 actions,直接用原始 Artifacts
NewCallbackContextWithArtifactTracking另外给 Artifacts.Save 加版本追踪
NewToolContext浅拷贝原生 commonContext 的专用字段,并重设工具信息和 actions

构造实现见 common_context.go#L35-L142。

internal/context.NewCallbackContext 调用的是带 ArtifactTracking 的公开构造器;agent.NewCallbackContext 本身并不额外追踪。因此要看完整包路径。见 internal/context/callback_context.go#L22-L36。

已有节点 Context 需要派生时,宜沿用 WithDelta;把它重新丢进 NewContext,可能失去 Path、RunID、resumeInputs 等专用信息。

4.3 Delta 派生:指针表达“不改”和“改成零值”

以下是 common_context_delta.go#L23-L40 的原字段:

type CommonContextDelta struct {
    ResumeInputs           *map[string]any
    InvocationContextDelta *InvocationContextDelta
    Path                   *string
    RunID                  *string
    SubScheduler           *DynamicSubScheduler
    OutputForAncestors     *[]string
}

type InvocationContextDelta struct {
    Context        *context.Context
    UserContent    **genai.Content
    Agent          *Agent
    Branch         *string
    IsolationScope *string
}

Branch == nil 表示保留原分支;Branch 指向空字符串表示清空。UserContent 使用双重指针,因此可以表达“把输入内容显式设为 nil”。

这是派生配置 delta,与 EventActions.StateDelta 没有相同的保存语义。前者替换 Context 字段,后者描述要随事件传递的会话状态变化。

parent commonContext ────────┐
  actions ──────────────────┼──► 同一个 EventActions
  Session ──────────────────┼──► 同一个 Session
                            │
child := parent.WithDelta   │
  Path = "root/tool@1"       │
  actions ──────────────────┘
  Session ─────────────────────► 同一个 Session

新 Context 不代表新 Session、新 actions map 或独立事务。构造器重新分配哪些字段,要逐项看实现。

4.4 WithDelta 与 WithICDelta 不完全等价

commonContext.WithDelta 浅拷贝自己,再把 InvocationContextDelta 交给底层;若 delta 包含 Go Context,还同步替换内嵌 Go Context。

commonContext.WithICDelta 则只替换持有的 invocationContext,不会同步改内嵌 Go Context。因此通过 commonContext 本身调用 Done / Value,可能仍走旧链;通过它的 ADK 环境委托又走新 invocation 链。见 common_context_delta.go#L44-L83。

wrapper 的 WithDelta / WithICDelta 直接返回底层派生结果,没有重新包回同类 wrapper。它们是当前 API 使用护栏,不是不可绕过的安全沙箱。应用不应依赖它们实施强权限隔离。

4.5 EndInvocation、取消、超时:三者不能互换

基础 invocation 的 EndInvocation 只是写 bool;WithICDelta 是结构体浅拷贝,因此派生标志不会自动向父对象广播。commonContext.EndInvocation 仅委托给它持有的 invocationContext。见 invocation_context.go#L98-L104、L131-L153。

操作直接效果不保证
EndInvocation当前 invocation 实现的 Ended 变 true关闭 Done、打断网络、父级同时结束
Go cancel关闭当前取消链 Done撤销已完成副作用、强制不配合的函数退出
WithAgentTimeout普通 commonContext 上给内嵌 Go Context 加超时wrapper 上可用、改变全部底层字段

ADK 停止标志影响后续调度,Go 取消链用于让正在进行的 I/O 感知停止。

工具里为一次请求加超时,直接使用标准库即可:

// 工具 handler 内的示意片段;endpoint 来自应用配置。
ioCtx, cancel := context.WithTimeout(ctx, 3*time.Second)
defer cancel()

req, err := http.NewRequestWithContext(ioCtx, http.MethodGet, endpoint, nil)
if err != nil {
    return nil, err
}
// 后续用 req 发请求,处理响应并关闭 Body。

ioCtx 给 I/O 使用;原始 ctx 继续提供 ADK 能力。不需要调用 tool wrapper 不支持的 WithAgentTimeout,也不要随手用 context.Background 替换原链而丢失取消和 Value。

4.6 RequestConfirmation:请求登记和批准执行分开

把天气工具改成“购买一份收费天气报告”。首次调用的 FunctionCallID=call-1,工具先检查:

ToolConfirmation() == nil
  → RequestConfirmation(hint, payload)
  → 返回“等待确认”
  → 不执行购买副作用

下一次恢复调用:
  confirmation.Confirmed == true  → 执行购买
  confirmation.Confirmed == false → 返回拒绝

RequestConfirmation 的真实动作只有:

  1. 空 FunctionCallID 返回 error。
  2. 初始化 RequestedToolConfirmations map。
  3. 用原始 FunctionCallID 写入 Hint、Payload、Confirmed:false。
  4. 设 SkipSummarization=true,阻止普通工具结果继续被模型总结。
  5. 返回 nil。

见 common_context.go#L388-L409。

该方法不阻塞等待,也不自动跳过工具后面的代码。发起后仍继续执行购买,就是工具业务逻辑自身越过了确认边界。

确认请求的 ID 和原始工具 call ID 是两层关联。恢复 processor 读取最近的 user Event,解析 adk_request_confirmation FunctionResponse,用响应 ID 匹配本 Agent 曾发出的确认请求,再从请求中取出原始 FunctionCall,以原始 call ID 重建工具 Context。它会检查同一确认 ID 是否指向冲突的原始调用,并跳过其他 Agent 作者的请求。见 request_confirmation_processor.go#L55-L209。

随后按原请求顺序重分派,并跳过当前历史快照中已有响应的调用。工具会重新进入 handler;这不是恢复 Go 栈。因此确认检查必须放在副作用之前,且跨调用去重仍属于业务和存储设计。见 L216-L257。

4.7 Workflow 恢复字段与 Memory 服务

字段 / 方法含义
ResumedInput(interruptID)当前激活的恢复 payload,按 InterruptID 查询
Path当前节点组合路径;动态子节点含父路径、名字与运行标识
RunID动态子节点运行标识,不是 InvocationID
SubScheduler当前动态激活调度子节点的入口
OutputForAncestors需要把当前输出交给哪些委托祖先

commonContext 先查自己的 resumeInputs map,没找到再委托底层;基础 InvocationContext 总返回 nil,false。返回 nil,true 代表 key 存在但 payload 为 nil,不能只判断 payload。见 common_context.go#L190-L241。

ToolConfirmation 和 ResumedInput 是不同恢复接口;工具 wrapper 的 ResumedInput 当前还会返回空值。不能把 FunctionCallID 与 InterruptID 混用。

Memory 的 SearchMemory 首先检查服务是否配置,再委托已绑定 App/User 的适配器;缺少服务返回 error。具体搜索算法由后端决定,Context 不把关键词检索自动升级成向量搜索。见 common_context.go#L373-L379 与 Memory。

4.8 Branch 与 IsolationScope:两道历史过滤

Branch 使用点分层级。当前 invocation 与 event 的 Branch 任一为空,这一层就放行;非空时,当前分支能看自己和祖先,不能看兄弟分支。祖先匹配带点边界,agent_0 不会误匹配 agent_00。见 utils.go#L186-L204。

当前 BranchEvent BranchBranch 检查
weather.source_a空可见
weather.source_aweather可见,祖先
weather.source_aweather.source_a可见,同分支
weather.source_aweather.source_b不可见,兄弟
weatherweather.source_a不可见,子分支

IsolationScope 则要求严格相等:有 scope 的 Agent 只看同 scope,空 scope 的 Agent 只看空 scope。即使 Branch 放行,也可能在 scope 检查被排除。见 contents_processor.go#L140-L151。

这两者作用于模型历史选择,不切分 Session.State,不是用户权限检查。节点派生通过 InvocationContextDelta 设置 scope;把同一个 Session 放进不同 Context,并不会自动得到独立状态存储。

4.9 错误与并发边界

发生位置直接结果已执行部分
State.Set 底层失败errordelta 可能已改,无自动回滚
Artifact.Save 失败error,通常不记版本是否有外部残留取决于服务
Artifact 保存成功、Event append 失败Event 持久化 errorartifact 不自动删除
SearchMemory 服务缺失error不发搜索请求
RequestConfirmation 缺 call IDerror不登记确认
wrapper 不支持的方法日志、空值、no-op 或 error不代表编译失败
Context 取消Done / Err 可观察不撤销工具已完成副作用

trackedArtifacts 中还保留“同名并发保存版本需要锁和较新版本比较”的 TODO。不同 Context 共享 actions 或 Session 引用时,要由具体调度和服务实现解决竞争;Context 类型本身不提供事务隔离。

五、重新梳理:运行时架构与边界

边界Context 提供什么真正执行者
请求取消Go Context 的 Done / Err / Deadline支持 Context 的模型、工具和服务
当前运行身份Agent、Session、InvocationIDRunner 创建,Agent/节点派生
状态变化State 视图、EventActions工具写入,事件生产者装载,Session Service 应用
文件保存绑定作用域的 ArtifactsArtifact Service
工具确认原调用 ID、确认对象、请求 actionsFlow / Runner / workflow / 客户端共同续接
节点恢复resumeInputs、Path、RunIDworkflow runtime
方法可用性普通 Context 与 wrapper构造路径决定实际实现

天气工具写 last_city 时,Context 负责记录变化和连接 Session;Flow 负责把变化放进工具 Event;Runner 负责消费并追加。Context 不替代其中任何一个模块,也没有独立的后台保存循环。

六、这个模块解决了什么问题

1. 显式传递一次运行需要的能力

如果工具只接收参数 map,它无法知道属于哪个用户、会话和函数调用,也不能把状态变化与当前 Event 对齐。Context 将这些请求级信息、绑定服务和控制信息放到显式接口中,减少在每个 handler 里重复组装。

2. 设计代价

当前选择得到什么代价
大 Context 接口复用callback、tool、node 共用基础设施方法存在不代表所有场景可用
wrapper 运行时护栏能记录误用并返回受限结果某些误用只在运行时表现为 nil 或 no-op
浅拷贝派生保留 Session / 服务,方便替换身份与路径共享引用需自行管理,不能当隔离副本
State 同时更新视图与 delta当前执行立即读到变化,事件可记录变化错误时没有跨两次写入的事务回滚
确认登记后重入 handler无需长期挂起函数栈副作用必须放在确认检查后,并考虑幂等
Go Context 与 invocation 环境分离可分别派生 I/O 链与 ADK 字段某些派生 API 只更新一条链

七、重点结论与常见误解

  • 接口关系是组合:Context 包含两个接口,InvocationContext 不包含 ReadonlyContext。
  • 能力看构造路径:普通 Context、callback wrapper、tool wrapper 有不同有效方法。
  • 状态有三个阶段:当前视图、事件 delta、服务持久化不能混为一谈。
  • 派生是浅拷贝:新对象可能仍共享 actions、Session、map 和 slice。
  • 停止与恢复各有协议:Ended、Go cancel、工具确认、节点 ResumedInput 不是同一种机制。
误解v2.4.0 的实际行为回看
ReadonlyContext 是冻结快照只收窄方法,仍返回底层引用第二节
State.Set 只是暂存变化还调用当前 Session.State.Set第三节
工具可随时 EndInvocationtool wrapper 的该方法是 no-op4.1
WithDelta 自动保留 wrapper返回底层派生 Context4.4
RequestConfirmation 返回 nil 就已批准只是登记请求,Confirmed 初始 false4.6
重新恢复工具就是继续原函数栈handler 会重新进入4.6

用贯穿示例检查自己

  1. last_city 写入后工具立即 Get 能读到什么?先读当前 delta,因此是 Hangzhou。
  2. 底层 State.Set 报错,delta 一定为空吗?不是;delta 在底层 Set 前已经写入。
  3. 购买报告首次 RequestConfirmation 后能继续购买吗?不能;必须返回等待,恢复时检查 Confirmed。
  4. 为工具 HTTP 请求加超时用什么?标准库 context.WithTimeout(ctx, …),保留原 ctx 访问 ADK 能力。

八、相关源码与进一步阅读

主题固定源码 / 文章
公开接口agent/context.go#L63-L240
基础 InvocationContextinternal/context/invocation_context.go#L27-L153
构造、工具、状态、Artifactscommon_context.go#L35-L495
派生 Deltacommon_context_delta.go#L23-L83
wrapper 行为测试callback_context_wrapper_test.go#L138-L258
确认重分派request_confirmation_processor.go#L37-L257
配套阅读Agent、Runner、Session Event、Tool、Workflow