Skip to content

Ask a Bot for evidence before it closes a responsibility, and keep it on the trail - #959

Open
seagullinfight2077 wants to merge 1 commit into
CopilotKit:mainfrom
seagullinfight2077:feat/responsibility-completion-evidence
Open

seagullinfight2077 wants to merge 1 commit into
CopilotKit:mainfrom
seagullinfight2077:feat/responsibility-completion-evidence

Conversation

@seagullinfight2077

Copy link
Copy Markdown

English · 繁體中文 · 简体中文

English

What this changes

A responsibility's success criteria are free text that no code can check, and completion was a
boolean the model set. complete_responsibility closed a goal with no reason at all, and nothing on
the trail said why a goal ended. A person reading a closed goal had no way to check that it was done.

Now a Bot closes a goal only with evidence: what it checked the criteria against (a link, a file, a
test, a number).

  • report_responsibility_progress with complete: true refuses without evidence.
    complete_responsibility now takes a required evidence and goes through the same run-bound
    recordProgress path as progress does. A Bot can therefore no longer close a goal its person paused.
  • The evidence is kept on the goal's progress, whole. A long summary gives way to it, so the two
    always fit the store's 6000 characters.
  • A new responsibility.completed audit row carries the Bot, the criteria, the evidence and the run.
    A failure to write it is logged and does not tell the Bot its completion failed, because the goal
    did close. This matches responsibility.triggered.
  • Unchanged: a person closing a goal from its page (store.transition), pausing and resuming, and
    progress that does not close the goal.

This changes a Bot-facing tool contract. A Bot that called complete_responsibility with only an
id is now refused. The refusal says what to pass, so it corrects itself on the next call.

Files: server/src/responsibilities/tools.ts, server/src/audit.ts, server/src/index.ts and
server/src/responsibilities/wiring.ts (both now pass the audit store), CHANGELOG.md. Tests:
server/tests/responsibility-completion-evidence.integration.test.ts (new), and
server/tests/approvals-question-resume.integration.test.ts (its Bot now passes evidence).

Where it runs

  • New state that outlives a request? No new table or column. The evidence is part of the
    existing responsibilities.progress text and of an audit row.
  • What happens on the second replica? Nothing different. Completion goes through the existing
    recordProgress transaction, which checks the goal is active and the run is current.
  • Anything serialised? The existing conditional update in recordProgress.
  • Anything fanned out to a browser? No. New listener, port, or schedule? No.

Boundary and audit

  • Every acting call still goes through the gateway: this adds no action.
  • A Bot closing a goal now writes a row (responsibility.completed). A completion refused for
    missing evidence is a tool-argument validation error and is not written, like other schema
    refusals. A completion the store refuses (paused goal, stale run) is not written either.
  • Nothing new is trusted from the client: the Bot, owner and run come from the signed run.

Changelog

  • "A Bot closes a responsibility only with evidence" under Unreleased.

Proof

What Result
New tests on main 3 fail for the right reason (expect assertions: a goal closes without evidence; no evidence is kept; complete_responsibility asks for none). The 3 controls pass
New tests with the change 9 pass / 0 fail, including the longest summary with the longest evidence, an audit store that throws, and a paused goal
Responsibility, approval-resume, audit and turn-prompt suites 102 pass / 0 fail
Static format:check, lint, typecheck, typecheck:tests, supervisor/ and agent-computer/ typecheck all exit 0
Whole suite (bun run test:ci, Postgres 17.11 + pgvector 0.8.7, on 947955a5) 11661 ran / 11442 pass / 218 skip / 1 fail: tests/compose.test.ts, which needs docker and fails the same way on main
In practice: the real server process, hosted CopilotKit Intelligence, a conversation and a responsibility created through POST /api/channels and POST /api/responsibilities, run through POST /api/responsibilities/:id/run by the server's own dispatch loop. A mock OpenAI server (@copilotkit/aimock) has the Bot call complete_responsibility main, no evidence: the goal closes, with empty progress and no row. This branch, no evidence: refused, the goal stays active. This branch, with evidence: closed, the evidence kept on its progress, one responsibility.completed row

On main, a call that does pass evidence is rejected before the tool runs. z.toJSONSchema emits
additionalProperties: false, and the runtime's @cfworker/json-schema validator in
convertToolsToVercelAITools refuses the extra key. That is why the evidence has to be a declared
parameter.

Unverified

  • Not run on Linux CI. The local run is macOS arm64 with Bun 1.4.4 (the repo pins 1.4.3).
  • The Audit screen shows the new row, but decisionDetails does not yet print its evidence.
  • The turn prompt (shared/responsibility-turn.ts) is unchanged. The tool descriptions say when
    evidence is needed. Changing the prompt would also change the parser that reads old turns back.

繁體中文

這個改動做什麼

responsibility 的成功標準是自由文字,程式沒辦法檢查;「完成」只是 model 自己設定的一個布林值。complete_responsibility 不需要任何理由就能關閉目標,審計紀錄裡也沒有任何關於「為什麼結束」的資訊。看到一個已關閉的目標,使用者無從確認它是不是真的做完了。

現在 Bot 必須附上證據才能關閉目標,也就是說明它用什麼來確認成功標準已經達成(一個連結、一個檔案、一個測試、一個數字)。

  • report_responsibility_progress 帶 complete: true 時,沒有 evidence 就會被拒絕。complete_responsibility 改成必須帶 evidence,並和回報進度走同一條綁定 run 的 recordProgress 路徑,所以 Bot 不能再關閉使用者已暫停的目標。
  • 證據會完整保存在目標的進度裡。摘要太長時由摘要讓位,確保兩者合計不超過資料層的 6000 字。
  • 新增審計事件 responsibility.completed,記錄 Bot、成功標準、證據和 run。這筆紀錄寫入失敗時只記錯誤日誌,不會讓 Bot 以為完成失敗(目標確實已經關閉),做法和 responsibility.triggered 一致。
  • 不變的部分:使用者在頁面上關閉目標(store.transition)、暫停與恢復,以及不關閉目標的進度回報。

這改變了 Bot 使用的工具規格。 只帶 id 呼叫 complete_responsibility 的 Bot 現在會被拒絕;拒絕訊息會說明要補什麼,Bot 下一次呼叫就能自行修正。

改動檔案:server/src/responsibilities/tools.ts、server/src/audit.ts、server/src/index.ts 和 server/src/responsibilities/wiring.ts(兩處都改成傳入審計儲存)、CHANGELOG.md。測試:server/tests/responsibility-completion-evidence.integration.test.ts(新檔),以及 server/tests/approvals-question-resume.integration.test.ts(測試裡的 Bot 改成附上證據)。

在哪裡執行(多副本部署)

  • 有新增會活過單次請求的狀態嗎? 沒有新的資料表或欄位。證據寫在既有的 responsibilities.progress 文字和一筆審計紀錄裡。
  • 第二個副本上會怎樣? 沒有差別。完成會走既有的 recordProgress 交易,它會確認目標仍在進行中、run 是目前這一個。
  • 有需要序列化的操作嗎? 沿用 recordProgress 既有的條件式更新。
  • 要推送到瀏覽器嗎? 不用。有新的 listener、port 或排程嗎? 沒有。

邊界與審計

  • 每個會產生動作的呼叫仍經過 gateway:這次沒有新增任何動作。
  • Bot 關閉目標現在會寫一筆紀錄(responsibility.completed)。因為缺少證據而被拒絕的完成屬於工具參數驗證錯誤,和其他 schema 拒絕一樣不寫紀錄。被資料層拒絕的完成(目標已暫停、run 已過期)也不寫。
  • 沒有新增信任前端資料的地方:Bot、擁有者和 run 都來自簽章過的 run。

變更紀錄

Unreleased 下新增「A Bot closes a responsibility only with evidence」。

證明

項目 結果
新測試在 main 上 3 個失敗,原因正確(都是 expect 斷言:沒有證據也能關閉、證據沒有被保存、complete_responsibility 不要求證據);3 個對照組通過
加上改動後的新測試 9 通過 / 0 失敗,包含最長摘要加最長證據、會拋錯的審計儲存、已暫停的目標
responsibility、核准後恢復、審計、turn 提示詞的測試套件 102 通過 / 0 失敗
靜態檢查 format:check、lint、typecheck、typecheck:tests,以及 supervisor/ 和 agent-computer/ 的 typecheck,全部 exit 0
全量測試(bun run test:ci,Postgres 17.11 + pgvector 0.8.7,基底 947955a5) 共 11661 個、11442 通過、218 略過、1 失敗:tests/compose.test.ts,需要 docker,在 main 上也同樣失敗
實測:真的 server 行程接託管的 CopilotKit Intelligence。透過 POST /api/channels 和 POST /api/responsibilities 建立對話和 responsibility,再透過 POST /api/responsibilities/:id/run 交給 server 自己的排程迴圈執行。由 mock OpenAI server(@copilotkit/aimock)讓 Bot 呼叫 complete_responsibility main、不附證據:目標被關閉,進度空白,沒有審計紀錄。本分支、不附證據:被拒絕,目標維持進行中。本分支、附證據:關閉,進度裡保存了證據,寫入一筆 responsibility.completed

在 main 上,附了 evidence 的呼叫會在工具執行之前就被擋下。原因是 z.toJSONSchema 產生的 schema 帶有 additionalProperties: false,runtime 在 convertToolsToVercelAITools 裡用 @cfworker/json-schema 驗證時,會拒絕這個多出來的參數。所以證據必須是正式宣告的參數。

未驗證

  • 沒有在 Linux CI 上跑過。本機是 macOS arm64、Bun 1.4.4(repo 指定 1.4.3)。
  • 審計頁面會顯示新的紀錄,但 decisionDetails 還不會把證據內容印出來。
  • turn 的提示詞(shared/responsibility-turn.ts)沒有修改。工具說明已經寫明何時需要證據;如果改提示詞,解析舊 turn 的程式也得跟著改。

简体中文

这个改动做什么

responsibility 的成功标准是自由文字,程序没办法检查;「完成」只是 model 自己设置的一个布尔值。complete_responsibility 不需要任何理由就能关闭目标,审计纪录里也没有任何关于「为什么结束」的信息。看到一个已关闭的目标,用户无从确认它是不是真的做完了。

现在 Bot 必须附上证据才能关闭目标,也就是说明它用什么来确认成功标准已经达成(一个链接、一个文件、一个测试、一个数字)。

  • report_responsibility_progress 带 complete: true 时,没有 evidence 就会被拒绝。complete_responsibility 改成必须带 evidence,并和回报进度走同一条绑定 run 的 recordProgress 路径,所以 Bot 不能再关闭用户已暂停的目标。
  • 证据会完整保存在目标的进度里。摘要太长时由摘要让位,确保两者合计不超过数据层的 6000 字。
  • 添加审计事件 responsibility.completed,记录 Bot、成功标准、证据和 run。这笔纪录写入失败时只记错误日志,不会让 Bot 以为完成失败(目标确实已经关闭),做法和 responsibility.triggered 一致。
  • 不变的部分:用户在页面上关闭目标(store.transition)、暂停与恢复,以及不关闭目标的进度回报。

这改变了 Bot 使用的工具规格。 只带 id 调用 complete_responsibility 的 Bot 现在会被拒绝;拒绝消息会说明要补什么,Bot 下一次调用就能自行修正。

改动文件:server/src/responsibilities/tools.ts、server/src/audit.ts、server/src/index.ts 和 server/src/responsibilities/wiring.ts(两处都改成传入审计保存)、CHANGELOG.md。测试:server/tests/responsibility-completion-evidence.integration.test.ts(新档),以及 server/tests/approvals-question-resume.integration.test.ts(测试里的 Bot 改成附上证据)。

在哪里运行(多副本部署)

  • 有添加会活过单次请求的状态吗? 没有新的数据表或字段。证据写在既有的 responsibilities.progress 文字和一笔审计纪录里。
  • 第二个副本上会怎样? 没有差别。完成会走既有的 recordProgress 交易,它会确认目标仍在进行中、run 是目前这一个。
  • 有需要串行化的操作吗? 沿用 recordProgress 既有的条件式更新。
  • 要推送到浏览器吗? 不用。有新的 listener、port 或调度吗? 没有。

边界与审计

  • 每个会产生动作的调用仍经过 gateway:这次没有添加任何动作。
  • Bot 关闭目标现在会写一笔纪录(responsibility.completed)。因为缺少证据而被拒绝的完成属于工具参数验证错误,和其他 schema 拒绝一样不写纪录。被数据层拒绝的完成(目标已暂停、run 已过期)也不写。
  • 没有添加信任前端数据的地方:Bot、拥有者和 run 都来自签章过的 run。

变更纪录

Unreleased 下添加「A Bot closes a responsibility only with evidence」。

证明

项目 结果
新测试在 main 上 3 个失败,原因正确(都是 expect 断言:没有证据也能关闭、证据没有被保存、complete_responsibility 不要求证据);3 个对照组通过
加上改动后的新测试 9 通过 / 0 失败,包含最长摘要加最长证据、会抛错的审计保存、已暂停的目标
responsibility、核准后恢复、审计、turn 提示词的测试套件 102 通过 / 0 失败
静态检查 format:check、lint、typecheck、typecheck:tests,以及 supervisor/ 和 agent-computer/ 的 typecheck,全部 exit 0
全量测试(bun run test:ci,Postgres 17.11 + pgvector 0.8.7,基底 947955a5) 共 11661 个、11442 通过、218 略过、1 失败:tests/compose.test.ts,需要 docker,在 main 上也同样失败
实测:真的 server 进程接托管的 CopilotKit Intelligence。透过 POST /api/channels 和 POST /api/responsibilities 创建对话和 responsibility,再透过 POST /api/responsibilities/:id/run 交给 server 自己的调度循环运行。由 mock OpenAI server(@copilotkit/aimock)让 Bot 调用 complete_responsibility main、不附证据:目标被关闭,进度空白,没有审计纪录。本分支、不附证据:被拒绝,目标维持进行中。本分支、附证据:关闭,进度里保存了证据,写入一笔 responsibility.completed

在 main 上,附了 evidence 的调用会在工具运行之前就被挡下。原因是 z.toJSONSchema 产生的 schema 带有 additionalProperties: false,runtime 在 convertToolsToVercelAITools 里用 @cfworker/json-schema 验证时,会拒绝这个多出来的参数。所以证据必须是正式声明的参数。

未验证

  • 没有在 Linux CI 上跑过。本机是 macOS arm64、Bun 1.4.4(repo 指定 1.4.3)。
  • 审计页面会显示新的纪录,但 decisionDetails 还不会把证据内容印出来。
  • turn 的提示词(shared/responsibility-turn.ts)没有修改。工具说明已经写明何时需要证据;如果改提示词,解析旧 turn 的程序也得跟着改。

🤖 Generated with Claude Code

… on the trail

A responsibility's success criteria are free text no code can check, and completion was a boolean
the model set: complete_responsibility closed the goal with no reason at all, and nothing on the
trail said why a goal ended.

- A Bot closes a goal only with evidence: what it checked the criteria against (a link, a file, a
  test, a number). report_responsibility_progress with complete: true refuses without it, and
  complete_responsibility now takes it and goes through the same run-bound path as progress, so a
  Bot can no longer close a goal its person paused.
- The evidence is kept on the goal's progress, whole (a long summary gives way to it), and a new
  responsibility.completed audit row carries the Bot, the criteria, the evidence and the run.
- A person closing a goal from its page is unchanged, and so is progress that does not close it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant