IronClaw Google Docs 扩展 format_text 操作全解析:从能力契约到 Google Docs API 的区间文本样式协议
【免费下载链接】ironclawIronClaw is an Agent OS focused on privacy, security and extensibility项目地址: https://gitcode.com/gh_mirrors/iro/ironclaw
导读
format_text是 IronClaw 开源仓库中 Google Docs 扩展(extension id:google-docs)提供的一项文本格式化能力,用于对文档中指定索引区间的文本批量应用加粗、斜体、下划线、删除线、字号、字体与前后景色等样式。本文以该操作的提示词文档(format_text.md)为核心骨架,结合其输入 Schema、WASM 工具实现与扩展清单(manifest),完整还原“能力调用 → 参数校验 → 样式构造 → Google Docs API 请求”的整条链路。读完本文,你将掌握该操作的完整参数语义、索引边界约定、底层updateTextStyle映射规则、宿主侧的安全边界,以及如何在自己的文档工作流中正确编排这一低层级操作。
一、操作契约:format_text 提示词文档说了什么
该扩展包的每个工具都配有一份极简的提示词文档(prompt doc),供模型在调用工具时理解操作语义。format_text.md全文只有两条核心约束:
- 操作语义:
Format text in a range.——在某个区间内格式化文本。 - 调用约束:宿主(host)通过能力 ID(capability id)选择该操作;调用方只需提供输入 Schema 描述的参数,不得包含 action 字段。
这两条约定在源码中都有强约束对应(详见下文第四节)。简言之,format_text是一个“区间定位 + 样式集合”的低层级文本样式工具:它不负责查找文本(那属于replace_text/apply_text_edits),只负责对给定的字符偏移区间施加样式。与之互补的是段落级样式操作format_paragraph(标题级别、对齐、行距),两者合起来构成 Docs 扩展的“文本样式 + 段落样式”能力面。
二、输入参数契约:从输入 Schema 看完整参数表
format_text的输入参数由 format_text.input.v1.json 精确定义,采用 JSON Schema draft-07。参数表如下:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
document_id | string | ✅ | 文档 ID(与 Google Drive 文件 ID 相同) |
start_index | integer | ✅ | 区间起始索引,含(inclusive) |
end_index | integer | ✅ | 区间结束索引,不含(exclusive) |
bold | boolean | null | ❌ | 是否加粗 |
italic | boolean | null | ❌ | 是否斜体 |
underline | boolean | null | ❌ | 是否下划线 |
strikethrough | boolean | null | ❌ | 是否删除线 |
font_size | number | null | ❌ | 字号,单位是磅(points,PT) |
font_family | string | null | ❌ | 字体族名称 |
foreground_color | string | null | ❌ | 文字颜色,十六进制字符串(hex) |
background_color | string | null | ❌ | 背景色,十六进制字符串(hex) |
值得注意的 Schema 语义细节:
- 必填仅三项:
document_id、start_index、end_index。也就是说,一次调用可以只给区间而完全不指定任何样式属性。 - 所有样式属性都允许
null(type: ["boolean", "null"]等),用于表达“本次不修改该属性”;但结合实现看,若所有样式属性都为null/缺失,调用会直接失败(见第三节的错误码no_formatting_options)。 additionalProperties: false:不接受 Schema 之外的多余字段,配合宿主侧参数注入,天然拒绝“野参数”。- 索引语义为左闭右开:
[start_index, end_index),这是 Google Docs API 一贯的索引约定,与 Pythonslice一致。
三、源码实现:format_text 如何映射为 Google Docs API 请求
该扩展是纯数据包(data-only package),不包含 crate,工具半身以 WASM guest 形式随 wasm/google_docs_tool.wasm 发布,guest 源码位于 wasm-src。核心实现在 api.rs 的FormatTextOptions与format_text函数中。
3.1 参数结构:FormatTextOptions
// crates/extensions/packages/google-docs/wasm-src/src/api.rs pub struct FormatTextOptions<'a> { pub document_id: &'a str, pub start_index: i64, pub end_index: i64, pub bold: Option<bool>, pub italic: Option<bool>, pub underline: Option<bool>, pub strikethrough: Option<bool>, pub font_size: Option<f64>, pub font_family: Option<&'a str>, pub foreground_color: Option<&'a str>, pub background_color: Option<&'a str>, }所有样式属性都是Option,与 Schema 中允许null的设计一一对应。
3.2 样式构造与字段掩码(field mask)
format_text的核心逻辑是:只把显式提供的属性写进textStyle,并用字段掩码(fields)告诉 Docs API 本次要更新哪些字段。这是 Google DocsbatchUpdate的标准模式——未列入掩码的样式字段保持原样:
let mut style = serde_json::json!({}); let mut fields = Vec::new(); if let Some(b) = opts.bold { style["bold"] = serde_json::Value::Bool(b); fields.push("bold"); } // ... italic / underline / strikethrough 同理 ... if let Some(size) = opts.font_size { style["fontSize"] = serde_json::json!({ "magnitude": size, "unit": "PT" }); fields.push("fontSize"); } if let Some(family) = opts.font_family { style["weightedFontFamily"] = serde_json::json!({ "fontFamily": family }); fields.push("weightedFontFamily"); } // foregroundColor / backgroundColor 由 parse_hex_color 转换后加入几个关键的底层映射规则(源码可查证):
font_size→fontSize:包装为{ "magnitude": <点数>, "unit": "PT" },即字号的单位固定为磅。font_family→weightedFontFamily:包装为{ "fontFamily": <名称> }。- 颜色 → RGB 浮点:
parse_hex_color先把字符串的#前缀剥掉,要求恰好 6 位十六进制字符,再按r/255、g/255、b/255转换为 Docs API 的rgbColor浮点结构;不符合格式(如#GG0000)时直接返回输入错误。 - 最终请求:组装为
updateTextStyle,携带range: { startIndex, endIndex }、textStyle和逗号拼接的fields掩码,通过batch_update_raw提交给docs.googleapis.com。
3.3 校验与错误码
实现中有两道显式校验,均返回input类失败并带稳定错误码:
| 场景 | 错误码 | 触发条件 |
|---|---|---|
| 颜色非法 | invalid_color | foreground_color/background_color不是合法 6 位 hex(如#GG0000) |
| 未指定任何样式 | no_formatting_options | 所有样式属性均为None/null |
成功时返回UpdateResult,包含document_id与最新的revision_id,便于调用方感知文档版本变化。
四、宿主调度与安全边界:能力 ID、参数注入与凭证
4.1 能力 ID 驱动分发
format_text的能力 ID 是google-docs.format_text。在 lib.rs 中,action_from_context从调用上下文的capability_id解析出动作名:
match context.capability_id.as_str() { "google-docs.format_text" => Ok("format_text"), // ... 其余 14 个动作 ... _ => Err(input_failure("unsupported_google_docs_capability")), }这正是提示词文档中“宿主从能力 ID 选择本操作”的代码落点:模型永远不需要、也不应该自己指定 action。
4.2 拒绝调用方自带的 action 字段
params_with_action会先检查参数中是否包含action键,若包含则直接拒绝:
if obj.contains_key("action") { return Err(input_failure("invalid_parameters")); } obj.insert("action".to_string(), serde_json::Value::String(action.to_string()));随后由宿主从能力 ID 推导出的动作名注入到参数里,交给GoogleDocsAction反序列化。这一设计(对应提示词文档中的“不要包含 action 字段”)从根源上防止模型伪造或覆盖动作,对应的单元测试params_with_action_rejects_caller_supplied_action也验证了这一行为。
4.3 清单中的权限、效应与凭证
manifest.toml 对format_text工具的声明如下:
[[tools]] origin_gate_matrix = { loop_run = "gated_unless_granted", product = "forbidden", automation = "forbidden" } id = "google-docs.format_text" description = "Format text in a range." effects = ["network", "use_secret", "external_write"] default_permission = "ask" visibility = "model" input_schema_ref = "schemas/google-docs/format_text.input.v1.json" prompt_doc_ref = "prompts/google-docs/format_text.md" [[tools.credentials]] handle = "google_runtime_token" vendor = "google" scopes = ["https://www.googleapis.com/auth/documents"] audience = { scheme = "https", host = "docs.googleapis.com" } injection = { type = "header", name = "authorization", prefix = "Bearer " }从中可以提炼出完整的安全与运行时信息:
- 效应声明(effects):
network(发起网络请求)、use_secret(使用凭证)、external_write(对外部系统产生写入)——external_write是写操作的重要标志。 - 默认权限:
ask,即默认需要用户授权确认;visibility = "model"表示该工具对模型可见。 - 来源门控(origin_gate_matrix):在
loop_run场景默认gated_unless_granted(除非被授予否则门控),在product与automation场景直接forbidden,把高风险写入操作限制在受控的 agent loop 内。 - 凭证注入:运行时由宿主把
google_runtime_token(Google 产品认证账号令牌,scope 为documents写入权限)以Authorization: Bearer <token>请求头的形式注入到docs.googleapis.com域名的请求中,工具本身不接触明文凭证。 - 认证链路:扩展级
[auth.google]使用 OAuth 2.0 authorization code + PKCE(S256),scope 为documents与documents.readonly,客户端凭据由部署级管理配置(google_oauth_client_id/google_oauth_client_secret)统一提供。
4.4 Schema 与代码零漂移
lib.rs中的schema()由schemars::schema_for!(types::GoogleDocsAction)自动生成,并在注释中明确说明“advertised schema can never drift from the serde contract”——对外公布的 Schema 与反序列化契约永远一致,避免了文档与实现脱节。这也是为什么本文第二节可以直接以format_text.input.v1.json为准展开。
五、索引约定与实战调用示例
5.1 索引语义(来自 lib.rs 文档注释与源码)
- 索引是从 0 开始的字符偏移(0-based character offsets)。
- 空文档的 body 在索引 0 处有一个换行符,因此在索引 1 处插入文本可以在文档开头前置内容。
- 使用
-1表示在文档末尾追加。 - 多次编辑时,从最高索引向最低索引处理,以避免索引漂移。
- 正式工作中优先使用
inspect_document获取段落/表格的真实索引,再调用format_text,避免手工猜测偏移。
5.2 可运行的调用示例
以下 JSON 是调用format_text的合法形态(动作名由宿主从能力 ID 注入,调用方只写 Schema 参数):
{ "document_id": "abc123", "start_index": 1, "end_index": 12, "bold": true, "font_size": 18 }等价于对文档abc123的[1, 12)区间文本设置加粗、18 磅字号;由于只传了这两个样式属性,其余样式字段通过 field mask 保持不变。组合其他属性:
{ "document_id": "abc123", "start_index": 5, "end_index": 20, "italic": true, "underline": true, "strikethrough": false, "font_family": "Arial", "foreground_color": "#FF0000", "background_color": "#FFFF00" }反例(会被拒绝):
{ "action": "delete_all", "document_id": "doc-1" }→ 因包含action字段返回invalid_parameters;若document_id/start_index/end_index缺失,则因不满足 Schema 的 required 约束而反序列化失败。
5.3 在文档工作流中的定位
扩展 README 建议:结构化编辑优先使用inspect_document→apply_text_edits/create_table_with_data→verify_document的语义化链路(通常只需 3~4 次模型可见调用,索引发现、批量写入、并发检查与回读都由扩展内部完成);而format_text这类低层级操作保留为兼容与逃生舱(escape-hatch)用途,适合对精确索引区间做样式微调。典型组合:inspect_document拿到段落索引 →format_text对标题区间加粗/改色 →get_document或verify_document确认结果。
六、测试与质量保障
该扩展的 WASM guest 内置单元测试,直接覆盖format_text的关键行为:
format_text_rejects_invalid_hex_colors(api.rs):对foreground_color: "#GG0000"返回invalid_color错误,message 为invalid foreground_color hex: #GG0000,验证了颜色校验路径。params_with_action_rejects_caller_supplied_action:验证调用方传入action字段会被拒绝并返回invalid_parameters。
此外,仓库还提供针对扩展包的回归检查:manifest 投影测试通过cargo test -p ironclaw_extension_registry执行;WASM 产物新鲜度由python3 scripts/ci/check-wasm-artifact-freshness.py校验,确保wasm/google_docs_tool.wasm与wasm-src源码同步(详见 README.md)。
七、参考文件索引
- 提示词文档:format_text.md
- 输入 Schema:format_text.input.v1.json
- 实现源码:api.rs 中 FormatTextOptions 与 format_text
- 调度与 Schema 生成:lib.rs
- 工具清单与凭证/权限声明:manifest.toml
- 扩展包总览:google-docs/README.md
结语
format_text看似只是“格式化一段文字”,实则浓缩了 IronClaw 扩展体系的三层设计:契约层(提示词 + JSON Schema 定义参数与调用边界)、实现层(WASM guest 把参数翻译为带 field mask 的 Docs APIupdateTextStyle请求)、治理层(能力 ID 分发、action 注入防伪造、ask权限与external_write效应声明、OAuth 凭证头注入)。理解这一操作,也就理解了该仓库中其他 14 个 google-docs 操作(乃至整个google-*扩展家族)的通用工作方式:以最小化参数契约暴露能力,把鉴权、作用域与 API 细节封存在沙箱化的 WASM 工具内部。
【免费下载链接】ironclawIronClaw is an Agent OS focused on privacy, security and extensibility项目地址: https://gitcode.com/gh_mirrors/iro/ironclaw
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考