Skip to content

[Design]: generic client preferences propagation (locale, timezone, etc.) — beyond _meta #131

Description

@Million-mo

背景

PR #128 通过 ACP initialize_meta 字段传入 locale,实现了 i18n。功能方向正确,但字段设计需要讨论。

需要讨论的几个问题

1. 约定合适的字段

ACP 协议(v1)的 initialize 请求结构中没有任何多语言/locale 相关字段。协议层面的字段只有:protocolVersionclientCapabilities(fs/terminal/elicitation/configOptions)、clientInfo(name/title/version)、_meta(扩展点)。

_meta 是 ACP 协议中 AnnotatedObject 的扩展点(field_meta),设计用途就是传递实现特定的附加信息。ACP 官方文档也确认,自定义能力可以通过 _meta 字段广告扩展支持。协议层面没有其他字段可以用来传 locale。

建议:继续用 _meta,但约定一个明确的 key 和文档:

"_meta": { "locale": "zh-CN" }
  • key 就叫 locale,值为 BCP 47 语言标签(enzh-CNja-JP
  • 在 ACP initialize response 中可以回传支持的 locale 列表,让客户端知道服务端支持哪些语言
  • 在代码中用结构化的方式提取(一个 _extract_locale() 函数),而不是散落在各处

2. 配置如何通过 initialize 生效

PR #128 的链路是对的:

client initialize (_meta.locale)
  → AgentPoolACPAgent.initialize() 提取 locale
  → 透传到 ACPSessionManager.create_session() / resume_session()
  → ACPSession.client_locale
  → 注入 callable system prompt

这个链路保持不变。唯一要确认的是:locale 应该是 per-connection(initialize 时设定,整个连接生效)还是 per-session(new_session 时可以覆盖)?

建议:per-connection 为主(简单),后续如果需要 per-session 覆盖再加。

3. 环境变量控制的必要性

结论:不需要环境变量。

理由:

  • locale 是客户端偏好,客户端切换语言后通过 initialize 通知即可,不需要服务端环境变量
  • 环境变量适合"服务端默认值"场景(见下),但不应作为客户端偏好的传递通道
  • 如果客户端没传 locale,应该走服务端默认配置(YAML),而不是环境变量

4. agentpool ACP 服务如何配置默认语言

当客户端没有在 initialize 中传 locale 时,agentpool 应该有一个默认值。这个默认值应该在 YAML 配置中设定。

建议:在 ACP server 配置或 agent 配置中加 default_locale 字段:

# 方案 A:server 级别默认
servers:
  acp:
    default_locale: zh-CN

# 方案 B:agent 级别默认
agents:
  assistant:
    default_locale: zh-CN
    system_prompt: "You are a helpful assistant."

优先级_meta.locale(客户端传入)> default_locale(YAML 配置)> 无(agent 自行决定语言)

方案 A 更简单(一个服务一个默认语言),方案 B 更灵活(不同 agent 可以有不同默认语言)。倾向方案 A,除非有明确的 per-agent 语言差异需求。

5. 是否需要注入到 Jinja2 模板

结论:不需要。维持 PR #128 的 callable prompt 方式。

当前 system prompt 有两种渲染机制:

  • Jinja2 模板渲染format_system_prompt()):在 sys_prompts.py 中,渲染时传入 agentpromptsdynamic 等框架内部变量,面向的是 YAML 配置层面的静态模板渲染。
  • Callable prompt:pydantic-ai 在每次 model call 时调用 callable 函数,返回动态字符串拼到 system prompt 中。get_cwd_context 就是这个模式。

不注入 Jinja2 的理由:

  1. locale 是 per-connection 的运行时值,不是 YAML 配置时已知的静态值。把 client_locale 塞进 Jinja2 渲染上下文会让模板变量承担不属于它的职责。
  2. callable prompt 已经够用。PR feat(acp): support locale injection via ACP initialize for i18n #128get_locale_prompt() 返回 "Language: You MUST respond in {locale}.",每次 model call 时执行,简单直接,与 get_cwd_context 同构。
  3. 不是所有 agent 都需要 locale 注入。用 callable prompt 时,只有客户端传了 locale 才追加这段 prompt;如果注入 Jinja2 变量,所有 agent 的模板都要改才能生效,反而增加了耦合。

总结

问题 建议
字段 _meta.locale,BCP 47 格式,文档化
生效机制 PR #128 现有链路不变
环境变量 不需要
默认语言 YAML default_locale,server 级别
Jinja2 注入 不需要,维持 callable prompt

Related

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions