@kentcdodds:我昨天向 @kodykoala 推送了一个新功能,这对将敏感操作交给 AI 代理至关重要。示例是 Gmail……
摘要
Kent C. Dodds 宣布了 Kody 的一项新功能,允许创建锁定的 Gmail 草稿以防止 AI 代理发送邮件,从而增强敏感操作的安全性。
查看缓存全文
缓存时间: 2026/08/29 21:58
我昨天向@kodykoala推送了一个功能,这对于将敏感数据托付给代理来说至关重要。示例使用了Gmail,但该功能适用于任何场景 https://kody.codes/guides/locked-gmail-drafts… 我将在下周制作一个关于此功能的视频。 — # 无需发送的Gmail草稿 — 锁定Google无法限制的权限 — Kody指南 来源:https://kody.codes/guides/locked-gmail-drafts Google的Gmail API具有仅发送范围,而没有仅草稿范围。创建草稿需要gmail.compose (https://developers.google.com/workspace/gmail/api/auth/scopes)(“管理草稿和发送电子邮件”)或更宽泛的写入授权。该令牌具有发送能力。而一个锁定的Kody包则是那个无法发送的授权。这是常见的抱怨:助手应该准备好回复发票或支持工单,然后将其保存在草稿中。人类用户打开Gmail,进行编辑,然后发送。OAuth无法做到这一点。而已发布的导出可以——发布锁可以防止后续的代理扩大其权限范围。 ## 锁的作用 一个包是声明的权限单元:其命名的导出、作业以及其他包拥有的接口都运行在已发布的版本上。一个集成仅处理授权。Google令牌的权限范围与Google签发时一样宽。 发布锁(保存在包上的locked_at字段)确保持续提供该已发布的版本。代理和五分钟的同步作业无法推进published_commit。package_update接受changes: { locked: true }参数。代理无法解锁;需将所有者引导至/@{username}/{kodyId}。锁不会吊销令牌的发送权限、不会对execute隐藏createAuthenticatedFetch,也不会阻止不同的未解锁包调用发送功能。它阻止的是此包的作业和导出默默地成为发送者。MCP服务器有所不同:将服务器锁定到一个包,这样execute和其他包就无法调用kody.mcp["name"]。该授权存在于服务器上,而非locked_at中。参见将MCP服务器锁定到一个包 (https://kody.codes/guides/locked-mcp-server)。使用详情:包 → 发布锁 (https://github.com/kentcdodds/kody/blob/main/docs/use/packages.md#publish-lock)。 ## 工作流程 1. 明确授权权限。“创建草稿回复。永不发送。“将此写入README的## Intent部分和导出的JSDoc的Purpose中。如果用户稍后要求发送,那就是新的授权——在网站上解锁,更改Intent,并在他们确认后,发布一个仅包含发送导出的版本。 2. **使用最窄的令牌连接Google以起草。**加载integration_bootstrap、oauth和provider_google。请求https://www.googleapis.com/auth/gmail.compose并添加gmail.googleapis.com到allowedHosts。仅当代理必须读取收件箱以建议回复时,才添加https://www.googleapis.com/auth/gmail.readonly。不要请求https://mail.google.com/或gmail.modify。 3. **对创建草稿进行冒烟测试,而非发送。**授权后,从execute中调用users.drafts.create(示例如下)。确认草稿出现在Gmail中。不要调用users.messages.send或users.drafts.send。 4. 保存一个精简的仅草稿包。遵循package_authoring和package_lifecycle。为其分配自己的kody.id(例如gmail-drafts)。如果完整的@kody/google分叉导出了发送功能,则不要锁定该分叉——保持发送功能远离此包的已发布接口。搜索Purpose必须说明该导出创建草稿且不发送。 5. 发布,然后锁定。检查通过且published_commit更新后,调用package_update并传入changes: { locked: true }(或在/@{username}/{kodyId}上点击锁图标)。在聊天中说明这一点,以便所有者知道后续发布需要他们点击“提升此提交”。 ## 草稿创建导出 这是包被允许执行的写操作。将RFC 2822消息编码为raw并将其POST到https://gmail.googleapis.com/gmail/v1/users/me/drafts。切勿添加/messages/send或/drafts/send。 import { createAuthenticatedFetch } from 'kody:runtime' function toBase64Url(text: string): string { const bytes = new TextEncoder().encode(text) let binary = '' for (const byte of bytes) { binary += String.fromCharCode(byte) } return btoa(binary) .replaceAll('+', '-') .replaceAll('/', '_') .replace(/=+$/g, '') } function rfc2822Raw(input: { to: string subject: string body: string }): string { const message = [ `To: ${input.to}`, `Subject: ${input.subject}`, 'MIME-Version: 1.0', 'Content-Type: text/plain; charset="UTF-8"', '', input.body, ].join('\r\n') return toBase64Url(message) } /** * 创建Gmail草稿。供人类在Gmail中审阅并发送时使用。 * 不会发送。 * * @param input - 收件人、主题和纯文本正文 * @returns Gmail草稿ID * * @example * import createDraft from 'kody:@scope/gmail-drafts/create-draft' * * const draft = await createDraft({ * to: '[email protected]', * subject: 'Re: Invoice 1842', * body: 'Thanks — I will review and reply today.', * }) */ export default async function createDraft(input: { to: string subject: string body: string }): Promise<{ draftId: string }> { const googleFetch = await createAuthenticatedFetch('google') const response = await googleFetch( 'https://gmail.googleapis.com/gmail/v1/users/me/drafts', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ message: { raw: rfc2822Raw(input) }, }), }, ) if (!response.ok) { throw new Error( `Gmail draft create failed: ${response.status} ${await response.text()}`, ) } const data = (await response.json()) as { id?: string } if (!data.id) { throw new Error('Gmail draft create returned no draft id.') } return { draftId: data.id } } 一个在夜间起草的作业遵循相同的规则:调度包装器仅调用此导出。它不会“为了方便”而扩展发送路径。 ## 后续发布 推送仍然会落到Artifacts HEAD上。发布工具返回locked和包含approval_url的/account/packages/:packageId/approve-publish?commit=。所有者打开该URL并点击提升此提交。提升一个提交不会解锁该包。如果代理需要解锁,它会将所有者引导至/@{username}/{kodyId}。它不会传递locked: false。 ## 在其他宽泛令牌上的相同模式 当提供者令牌可以执行的操作超出已发布接口应允许的范围时,请使用本指南。Slack工作区令牌、具有repo权限的GitHub PAT以及Drive范围的令牌都具有相同的形式:授予必要的令牌,只发布你期望的调用,进行锁定以防止其悄然扩大权限。 ## 何时加载此指南 当有人希望获得代理不应发送的Gmail草稿时,当他们询问为何Gmail没有仅草稿范围时,或者当任何OAuth令牌比预期的包权限更宽泛时,请加载locked_gmail_drafts。关于Google控制台和测试状态刷新令牌陷阱,请加载provider_google。关于将收件箱读取作为教学转录,请加载google_oauth。关于包的结构和锁字段,请加载package_authoring和发布锁 (https://github.com/kentcdodds/kody/blob/main/docs/use/packages.md#publish-lock)使用页面。
相似文章
@kentcdodds: 我昨晚又制作了一个Kody品牌的产品。它能让你的代理安全地与其他代理对话。用于合作…
Kent C. Dodds宣布了一款新的Kody品牌产品,该产品能实现AI代理之间的安全通信,促进与合作伙伴的协作。
@kentcdodds:我也将这个功能集成到了 @kodykoala 中。我对 Kody 的密钥管理相当满意,但如果你愿意,现在可以使用 …
Kent C. Dodds 宣布 Kody 现在支持自定义密钥提供商,使得能够集成像 1Password 这样的密码管理器,以实现 AI 代理中的安全密钥管理。
@kentcdodds:在这个视频中,我向大家展示代理在与@kodykoala交互时实际做了什么。我想你会觉得这很有意思…
Kent C. Dodds 分享了一个视频,展示了 AI 代理如何与 @kodykoala 交互,并强调给予代理安全访问所需服务的重要性。
@kentcdodds: 为Kody作为产品奠定基础。今天有一个新功能:当你注册Kody时,你会收到一封邮件,可以…
Kent C. Dodds宣布了Kody的一个新功能:用户将获得一个邮箱,可以接收和回复邮件,为Kody作为产品奠定基础。
@kentcdodds:这现已内置到 Kody 中,让你的 agents 设置新集成更加直接 https://gith…
Kody 是一个基于 Cloudflare Workers 和 MCP 构建的实验性个人助手平台;最近一次更新简化了 agents 的集成设置。