• 简体中文
  • v6.6.0
  • 会话

    Agent 持有配置和服务提供商状态。Session 把这个智能体绑定到一个工作区和一次 对话生命周期。

    界面通常从这里开始接入:订阅 Session 产生的 AgentEvent,再把事件映射为进度、 工具调用、权限确认和结果。

    session.tsTypeScript
    import { Agent } from '@a3s-lab/code';
    const agent = await Agent.create('agent.acl');
    const session = agent.session('/repo', {
    model: 'provider/model-id',
    planningMode: 'enabled',
    goalTracking: true,
    autoDelegation: { enabled: true, maxTasks: 4 },
    autoParallel: false,
    });

    Rust 构建路径

    Rust 会话构建以异步为先,因为默认内存存储、文件型存储、队列、轨迹记录与 MCP 发现都可能需要 I/O:

    Rust
    let session = agent
    .session_builder("/repo")
    .options(options)
    .build()
    .await?;

    session_asyncresume_session_asyncsession_for_agent_asyncsession_for_worker_async 是直接的异步入口。Node 和 Python 保留现有工厂 命名,由原生绑定在内部委托给同一个异步构建内核。

    同步 Rust Agent::session 是严格兼容路径:只接受已经显式初始化好的资源,绝不 启动或阻塞异步运行时。仍需初始化的默认或文件型内存存储、文件会话存储、队列、 轨迹记录器,以及 SessionOptions 中的任何宿主 MCP 管理器都会返回 CodeError::AsyncSessionBuildRequired;会话选项中的 MCP 能力发现始终是异步的。 应改用构建器,不要捕获错误后悄悄更换后端。 同步路径只能继承智能体初始化时已经缓存的全局 MCP 工具。

    planningMode 是显式三态:'auto' 使用默认结构化预分析,'enabled' 强制规划,'disabled' 在低延迟调用中关闭规划。旧的布尔 planning 选项仍保留兼容。

    规划会写入运行级状态。宿主应用可以把这些状态渲染成任务列表,并随着运行事件更新 每一项,而不是从文本令牌中猜测进度。

    单任务操作约束

    同一个会话同时只准入一个会影响对话记录的操作。sendstream、它们的附件变体、 斜杠命令与 resumeRun 共用快速失败准入门。重叠调用会在读取历史或派发命令前返回 CodeError::SessionBusy,不会排队 等待当前操作。

    开始下一次对话操作前,应等待活动结果、把事件流消费到结束,或先取消它。 即使公开的事件流句柄被丢弃或中止,运行时也会在生产者真正停止前继续 持有租约。直接调用宿主工具的辅助方法不改变对话记录,因此不占用这把租约。

    Node 与 Python 的事件流迭代器会在终止边界等待这段生命周期清理。迭代器完整消费 并报告结束后,立即开始下一次对话操作不会继承上一个事件流留下的过期忙碌状态。

    发送消息

    Rust
    Node.js
    Python
    Go
    Rust
    let result = session
    .send("审查这个仓库并列出发布阻塞项", None)
    .await?;
    println!("{}", result.text);
    println!("{}", result.usage.total_tokens);
    println!("{:?}", result.verification_summary().status);

    流式输出

    Rust
    Node.js
    Python
    Go
    Rust
    use a3s_code_core::{AgentEvent, CodeError};
    let (mut events, lifecycle) = session
    .stream("运行相关测试并解释失败原因", None)
    .await?;
    while let Some(event) = events.recv().await {
    match event {
    AgentEvent::TextDelta { text } => print!("{text}"),
    AgentEvent::ToolStart { name, .. } => println!("\n工具:{name}"),
    AgentEvent::End { .. } => break,
    AgentEvent::Error { message } => return Err(CodeError::Llm(message)),
    _ => {}
    }
    }
    lifecycle
    .await
    .map_err(|error| CodeError::Internal(error.into()))??;

    每个 SDK 事件都是 EventEnvelopeV1 投影,包含 version === 1、开放的 type 字符串、完整 payload 与可选 metadatatexttoolName 等便捷字段 由信封统一派生。消费端应保留默认分支,并为未来的事件类型保存原始载荷。

    临时提问

    SDK 没有专用的临时提问辅助方法。要提出临时问题,可以先快照当前历史,再把它 显式传给 sendstream。显式历史只服务这一次调用,不会把答案写回 会话历史。

    TypeScript
    const snapshot = session.history();
    const answer = await session.send('这个 session 已经看过哪些文件?', snapshot);
    console.log(answer.text);
    console.log(session.history().length === snapshot.length);

    恢复会话

    Rust
    Node.js
    Python
    Go
    Rust
    use a3s_code_core::{Agent, SessionOptions};
    let session = agent
    .resume_session_async(
    "release-review",
    SessionOptions::new().with_file_session_store("./.a3s/sessions"),
    )
    .await?;

    使用会话存储时设置 autoSave: true,或显式调用 await session.save()。 这里恢复的是已保存的会话快照;中断运行的检查点通过 session.resumeRun(runId) 恢复。Go 使用 SaveResumeSessionResumeRun(ctx, runID) 对应同样的两层持久化。参见 持久化

    生命周期与关闭

    session.close() 是一次完整的优雅停止。首次调用会把会话切换到 已关闭状态——之后的 send/stream 调用会以 CodeError::SessionClosed 快速失败,而不会启动新运行——然后取消正在执行的运行、所有正在进行的委派子 智能体任务,以及所有挂起的人工确认。后续调用不会重复操作,且保证 不会触发 panic。用 session.isClosed()(Node)、session.is_closed()(Python) 或 session.IsClosed(ctx)(Go)查询关闭状态。

    TypeScript
    session.close();
    if (session.isClosed()) {
    // send/stream 现在会以 CodeError::SessionClosed 拒绝
    }
    Python
    session.close()
    if session.is_closed():
    # send/stream 现在会以 CodeError::SessionClosed 拒绝
    pass
    Go
    if err := session.Close(ctx); err != nil {
    return err
    }
    closed, err := session.IsClosed(ctx)

    取消令牌

    每个运行都通过 child_token() 从同一个会话级父令牌派生出自己的 逐操作取消令牌,因此 close() 会一次性级联到所有正在进行的工作。需要原始 令牌的嵌入方——例如把它接入宿主侧的 select!,或者绕过 close() 的 运行存储和钩子副作用直接中止会话——可以通过 AgentSession::session_cancel_token() 克隆它。

    智能体侧会话注册表

    所属的 Agent 通过 Weak 引用跟踪它的存活会话(惰性回收),这样控制面 就能在不持有会话句柄的情况下驱动生命周期:

    • Agent::list_sessions() 返回存活的会话 ID(已排序,稳定)。
    • Agent::close_session(id) 按 ID 关闭单个会话——与 AgentSession::close() 相同的清理流程,从带外调用。
    • Agent::close() 关闭每个存活会话并拆除智能体持有的后台资源(同时 断开全局 MCP 连接)。返回后,新的 session / resumeSession 调用会以 CodeError::SessionClosed 快速失败。
    • Agent::is_closed() 报告智能体自身是否已被关闭。
    TypeScript
    const ids = await agent.listSessions();
    await agent.closeSession(ids[0]);
    await agent.close(); // 关闭所有剩余会话和全局 MCP
    console.log(agent.isClosed());
    Python
    ids = agent.list_sessions()
    agent.close_session(ids[0])
    agent.close() # 关闭所有剩余会话和全局 MCP
    print(agent.is_closed())
    Go
    ids, err := agent.ListSessions(ctx)
    if err == nil && len(ids) > 0 {
    _, err = agent.CloseSession(ctx, ids[0])
    }
    err = agent.Close(ctx)

    参见更新日志 [3.3.0] 中的“会话与智能体生命周期控制”。

    宿主身份标签

    SessionOptions 携带四个不透明的身份字段,宿主可以在创建会话时附加。 框架只负责传递它们——从不解释或强制执行。它们会被传播进 SessionData、 钩子和追踪,并在恢复时还原,因此宿主可以据此驱动多租户聚合、计费 和分布式追踪:

    Node(驼峰命名)Python(蛇形命名)Go含义
    tenantIdtenant_idTenantID多租户标签
    principalprincipalPrincipal触发会话的用户或服务
    agentTemplateIdagent_template_idAgentTemplateID会话实例化所基于的智能体模板或定义
    correlationIdcorrelation_idCorrelationID分布式追踪关联标识
    TypeScript
    const session = agent.session('/repo', {
    tenantId: 'tenant-example',
    principal: 'principal-example',
    agentTemplateId: 'agent-template-example',
    correlationId: 'trace-example',
    });
    Python
    opts = SessionOptions()
    opts.tenant_id = 'tenant-example'
    opts.principal = 'principal-example'
    opts.agent_template_id = 'agent-template-example'
    opts.correlation_id = 'trace-example'
    session = agent.session('/repo', opts)
    print(session.tenant_id, session.principal)
    Go
    session, err := agent.Session(ctx, "/repo", &code.SessionOptions{
    TenantID: "tenant-example",
    Principal: "principal-example",
    AgentTemplateID: "agent-template-example",
    CorrelationID: "trace-example",
    })

    参见更新日志 [3.3.0] 中的“宿主提供的身份标签”。

    运行记录与回放

    每次 send()stream() 都会创建运行记录。应用可以用这些记录实现界面状态、 审计、回放、取消和测试断言:

    TypeScript
    const runs = await session.runs();
    const latest = runs.at(-1);
    if (latest) {
    console.log(await session.runSnapshot(latest.id));
    console.log(await session.runEvents(latest.id));
    }
    Go
    runs, err := session.Runs(ctx)
    if err == nil && len(runs) > 0 {
    latest := runs[len(runs)-1]
    snapshot, snapshotErr := session.RunSnapshot(ctx, latest.ID)
    events, eventsErr := session.RunEvents(ctx, latest.ID)
    _, _, _ = snapshot, snapshotErr, eventsErr
    _ = events
    }

    currentRun() 用来读取调用当下的当前运行。send()stream() 仍在 执行时,可以把它的 id 传给 cancelRun(id) 请求取消。空闲时,currentRun() 可能返回 null,也可能保留一个运行快照;已完成历史应使用 runs(), 取消前必须检查 status

    TypeScript
    const current = await session.currentRun();
    if (current?.id && current.status === 'running') {
    await session.cancelRun(current.id);
    }

    智能体定义

    sessionForAgent() 应用一个命名的智能体定义,来源是内置智能体、 .a3s/agents 或配置的 agentDirs

    TypeScript
    const session = agent.sessionForAgent('/repo', 'explore', ['./agents'], {
    planningMode: 'auto',
    });
    Go
    session, err := agent.SessionForAgent(
    ctx,
    "/repo",
    "explore",
    []string{"./agents"},
    &code.SessionOptions{PlanningMode: code.PlanningAuto},
    )

    对于通过值定义的一次性 worker,可使用 SessionForWorker;两种方法都返回通用的 Go Session API。