Skip to content

🚥 feat: Gate Synchronous Tool Results Before Release - #597

Open
lia-by-librechat[bot] wants to merge 14 commits into
mainfrom
lia/pii-tool-results
Open

lia-by-librechat[bot] wants to merge 14 commits into
mainfrom
lia/pii-tool-results

Conversation

@lia-by-librechat

@lia-by-librechat lia-by-librechat Bot commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Adds default-off RunConfig.toolResultProtection for trusted synchronous text tools. Required inspection is separate from optional hooks and precedes native tool callbacks, host-result tracing, completion events, output references and ToolMessage/model reuse.

  • Reuses B1's versioned result vocabulary and bounded attempt leases. Required failures are terminal and raw-free.
  • Covers direct tools, host success/error batches, eager adoption, hook/error-handler replacements and local/Code API nested dispatch. Child graphs inherit the same policy/budget.
  • Re-inspects checkpoint-owned replay and earlier-turn references without repeating settled side effects. Legacy reference snapshots without SDK source/protection provenance fail closed. Restored entries require current-policy inspection; live entries retain nonserialized policy bindings. Full approved references remain separate from model previews.
  • Freezes dispatched identity across host awaits. Required failures outrank approval interrupts. Missing/throwing required SDK host handlers, including foreground child forwarding, fail raw-free.
  • Snapshots validated producer envelopes before inspection awaits. Canonical identity/status/metadata provenance is rechecked before reuse.
  • Configured local bridge cancellation is raw-free and terminal before text/JSON responses; SDK safety abort identity is retained.
  • Rejects controlled reference collections and all symbol-keyed envelope aliases before copying; reference inspection uses detached indexed data.
  • Revalidates nested results after callbacks, normalizes external policy exceptions and authenticates post-hook source envelopes before cloning.
  • Preserves IDs/status, approvals, execution authority and batch accounting. No argument or arbitrary structured-payload rewriting.

Selected artifacts, files/media, background results, opaque/executable aliases, custom tool shells and Cloudflare-native programmatic outputs are unsupported and gated. Unselected/absent-policy behavior remains default-off. No activation, package publication or documentation changes.

Verification

Head: b2319ce8ef5f30e1e1260813fa92def0a7eca30d

Check Result
Focused tool/reference/eager/local/backend suites 588 passed
Approval/resume and tracing regressions 353 passed
Child/authority and adjacent dispatch suites 289 passed, including rerank; 1 existing benchmark skipped
Cooperative restart/sealing 30 passed
tsc --noEmit Passed
CJS/ESM/declaration builds, real dispatch/replay and declared exports Passed
Touched ESLint/import order and dependency cycles Passed

Real SDK dispatch exercises A1 result/error/alias canaries and allowed controls, required handler failures, deadlines, Stop/late completion, retries, concurrent attempts, approval replay, full references, local/HTTP nested execution, standalone version checks and disconnected bridge drain. Cloudflare gating tests confirm no sandbox work for selected native outputs.

All 13 CI checks passed for this head. Independent review is incomplete: its continuation could not create the isolated lane (already exists), and Git registration cleanup returned Device or resource busy. No clean review is claimed and no review is running. All focused SDK checks, including the unchanged rerank suite, passed locally. Built CJS/ESM checks exercise canonical dispatch, reference replay/restoration, hostile collections, hidden symbols, nested callback mutation, typed-error normalization, post-hook provenance and real local HTTP cancellation. Full SDK suites were not run locally. Live provider/Cloudflare certification and D1 serialized exporter certification were not performed.

Review ledger

21 P1 and 14 P2 findings fixed. No rejected or open ledger entries. All four Codex threads are resolved. This ledger is not a completed independent review of the current head.

C2 prerequisite

C2 must wait for an approved SDK release containing C1, pin that exact version, require capability/policy version 1, and certify trusted text adapters plus real app/SSE/replay sinks. Merge alone does not authorize release or activation. Unsupported paths remain gated across rollback/mixed versions.

AI-2213

@lia-by-librechat

Copy link
Copy Markdown
Contributor Author

Head: 68df78e

C1 mandatory synchronous tool-result gate. Direct/native callbacks, host success/error, eager completion, post-hook replacement, references, nested local/programmatic execution and child inheritance use canonical releases. Required failures are terminal; unsupported artifacts/files/media/background paths stay gated.

Focused baseline: 355 tests plus 3 added child/approval cases passed. Workspace types, CJS/ESM/declarations, touched lint/import order and dependency cycles passed. Tracing/approval/resume regressions and independent review are running against this head. No docs, activation or package publication. C2 requires an approved SDK release/pin and adapter/sink certification.

@lia-by-librechat

Copy link
Copy Markdown
Contributor Author

Head: c0e10d2

Fixed independent R1-R5 in 3f3c3a8: raw-free eager rejections/cardinality, nested pre-call errors and local denial text, terminal remote protection failures. Also covered remote bash dispatch, SDK safety interruptions, native callback/error-handler ownership and opaque/accessor message aliases. Integrated current main at 265d97f without rewriting history.

Current-head checks: 375 focused tests, 353 approval/tracing tests and 232 child/host-argument tests passed. Workspace types, CJS/ESM/declarations, touched lint/imports, dependency cycles and built C1 exports passed. Fresh independent review follows for this exact head. No docs, activation or package publication; C2 still requires an approved SDK release containing C1 plus exact pin/capability and adapter/sink certification.

@danny-avila

Copy link
Copy Markdown
Collaborator

@codex review the latest head, final review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 5, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-05T22:05:52.568584Z b2319ce Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c0e10d264c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/protection/toolResult.ts Outdated
Comment thread src/tools/ToolNode.ts
@lia-by-librechat

Copy link
Copy Markdown
Contributor Author

Head: 3d39e2f

Fixed R6-R8 in 3d39e2f after a producer/reuse/projection invariant sweep. Checkpoint-owner-validated replay re-inspects canonical content without repeating settled side effects. Full approved references remain separate from model previews. Text-only tuple-format exceptions retain native error status and callbacks.

378 focused SDK tests and 353 approval/tracing tests passed. Separate types, CJS/ESM/declarations, declared exports, touched lint/import checks and dependency cycles passed. No docs, activation or publication. Fresh independent review is running for this exact head; C2 still needs an approved SDK release/pin, capability checks and adapter/app sink certification.

@lia-by-librechat

Copy link
Copy Markdown
Contributor Author

Head: 0333d5f

Fixed Codex CX1/CX2 and independent R9/R10 in 0333d5f. Host envelopes are validated before accessor reads, timestamping and host-result tracing. Cloudflare native outputs remain unsupported and gate before sandbox work. Direct approval responses are inspected in full before truncation. Local runners drain accepted bridge requests before checking required failures. Error-handler replacements are re-inspected before reuse.

432 focused/backend tests and 353 approval/tracing tests passed. Separate types, CJS/ESM/declarations, declared exports, touched lint/import checks and dependency cycles passed. Fresh independent review follows for this exact head. No docs, activation or package publication. C2 requires an approved SDK release containing C1, exact pin, capability/policy checks and adapter/app sink certification.

@lia-by-librechat

Copy link
Copy Markdown
Contributor Author

Head: 61dad14

Fixed independent R11-R13. Uncertified executable/request aliases reject before execution; standalone native boundaries validate supplied policy versions; accepted local bridge handlers drain even after client disconnect.

75 C1 dispatch regressions and separate types passed. Broader focused/backend, approval/tracing, child/authority and static/build checks are running against this head alongside CI and fresh independent review. No docs, activation or publication. C2 still requires an approved SDK release containing C1, an exact pin, version-1 capability/policy checks and trusted adapter/app sink certification.

@lia-by-librechat

Copy link
Copy Markdown
Contributor Author

Head: d1ec9ff

Fixed independent R14/R15. Checkpoint references now retain SDK source/version/protection provenance. Selected earlier-turn values are re-inspected before restoration or substitution; legacy or newly selected uncertified reference snapshots fail closed. Unselected host outcome/outcome_patch controls survive routing validation; selected aliases stay gated.

145 result/reference regressions passed, including direct/host source replay, allowed controls, reblocking, legacy/mixed-version gating and real eager outcome controls. Types, builds, touched lint/imports, cycles and built CJS/ESM dispatch passed. Broader exact-head checks, CI and fresh independent review follow. No docs, activation or publication. C2 still requires an approved SDK release containing C1, exact pin, capability/policy version checks and trusted adapters plus app sinks.

@lia-by-librechat

Copy link
Copy Markdown
Contributor Author

Head: 99da8a3

Fixed independent R16/R17. Required host releases use frozen dispatched identities and reject changes before inspection, during inspection and after host cleanup. Required failures take precedence over approval interrupts. SDK-owned required host handler absence/throws fail raw-free before native callback logging. Native producer identity/format mutation is gated before callbacks.

100 C1 dispatch regressions and separate types passed. Focused/reference/backend, approval/tracing, child/authority and static/build checks follow for this exact head alongside CI and fresh independent review. No docs, activation or publication. C2 still requires an approved SDK release containing C1, exact pin, capability/policy checks and trusted adapter/app sink certification.

@lia-by-librechat

Copy link
Copy Markdown
Contributor Author

Head: ae4213e

Fixed independent R18/R19. Required child-host exceptions are rejected raw-free before native callback logging. Restored registry values are inspected under the current policy before reference resolution; serialized protection flags cannot recreate live policy bindings. Unchanged live values keep their policy-bound admission, avoiding redundant inspection. Batch turns remain reserved before awaits.

163 result/reference regressions, separate types and touched lint/import checks passed. Exact-head broader checks, builds, CI and fresh independent review follow. No docs, activation or publication. C2 requires an approved SDK release containing C1, exact pin, capability/policy checks and trusted adapters plus app sinks.

@lia-by-librechat

Copy link
Copy Markdown
Contributor Author

Head: 386dd9b

Fixed independent R20. Validated producer messages are snapshotted before awaited inspection. Changes to identity, status, content, artifacts or metadata reject before native callbacks. Canonical provenance includes the immutable envelope, and metadata is copied rather than shared with the producer.

179 result/reference regressions, types and touched lint/import checks passed. Broader exact-head checks, module builds, CI and fresh independent review follow. No docs, activation or publication. C2 requires an approved SDK release containing C1, exact pin, capability/policy checks and trusted adapters plus app sinks.

@lia-by-librechat

Copy link
Copy Markdown
Contributor Author

Head: 0781d19

Fixed independent R21. Configured local bridge cancellation becomes a raw-free terminal error before text or JSON responses. The failure latch survives ignored HTTP failures and bridge drain; SDK safety reasons retain identity.

189 result/reference regressions, types and touched lint/import checks passed. Real localhost HTTP tests cover ordinary/string canaries, typed policy errors and SDK safety controls in both response modes. Broader exact-head checks, builds, CI and fresh independent review follow. No docs, activation or publication. C2 requires an approved SDK release containing C1, exact pin, capability/policy checks and trusted adapters plus app sinks.

@danny-avila

Copy link
Copy Markdown
Collaborator

@codex review the latest head, final review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0781d1938c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/protection/toolResult.ts Outdated
Comment thread src/protection/toolResult.ts
@lia-by-librechat

Copy link
Copy Markdown
Contributor Author

Head: 8112d9a

Fixed Codex CX3/CX4 in 8112d9a. Reference collections are copied from validated indexed data before selection or inspection; proxy/subclass/iterable collections, overridden methods, accessors and symbol aliases reject before use. Detached reference fields stay stable across awaits. Envelope validation examines every own key, including non-enumerable symbols, before native callbacks or metadata copying.

208 result/reference regressions, types and touched lint/import checks passed. Broader exact-head checks and fresh independent review are running alongside CI. No docs, activation or publication. C2 still requires an approved SDK release containing C1, exact pin, capability/policy checks and trusted adapter/app sink certification.

@lia-by-librechat

lia-by-librechat Bot commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor Author

Head: b2319ce

Fixed R22-R24 in b2319ce: post-callback nested revalidation, raw-free external protection errors and authenticated post-hook source envelopes. Both new Codex findings are fixed in 8112d9a; all four Codex threads are resolved.

Exact-head verification Result
Focused result/reference/backend tests 588 passed
Approval/resume and tracing 353 passed
Child/authority, dispatch and rerank 289 passed; 1 existing benchmark skipped
Cooperative restart/sealing 30 passed
Types, CJS/ESM/declarations, touched lint/imports, dependency cycles Passed
Built real dispatch/replay, cancellation and callback-boundary regressions Passed
CI 13 passed

Ledger: 21 P1 and 14 P2 fixed; none rejected or open. Independent review is incomplete. The continuation could not create .worktrees/review-597-b2319ce (already exists); cleanup returned Device or resource busy. The directory is now absent, but its Git registration remains busy. No clean current-head review is claimed and no review is running.

Full SDK suites were not run locally. Live provider/Cloudflare and D1 serialized-exporter certification were not performed. No docs, activation, merge or package publication.

C2 requires an approved SDK release containing C1, an exact pin, version-1 capability/policy checks, and trusted adapter plus app/SSE/replay certification. Unsupported paths remain gated.

@danny-avila

Copy link
Copy Markdown
Collaborator

@codex review the latest head, final review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b2319ce8ef

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/tools/ToolNode.ts
Comment on lines +2244 to +2245
if (requiresToolResultProtection(this.toolResultProtection, call.name) && e.message !== admittedErrorText) {
e = new Error(await protectToolText(this.toolResultProtection, call.name, call.id ?? '', e.message, 'error', config.signal) as string);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Revalidate handler-mutated errors before logging

When a selected tool fails and errorHandler mutates the passed Error.message and then throws, the catch block logs e.message, e.stack, and the thrown handler error before this reinspection runs. A replacement containing the raw tool result therefore reaches server logs even though it is subsequently inspected for the returned ToolMessage; revalidate or normalize the error before the catch block records it.

AGENTS.md reference: AGENTS.md:L147-L147

Useful? React with 👍 / 👎.

Comment thread src/graphs/Graph.ts
Comment on lines +1607 to +1608
if (toolResultProtection != null) validateToolResultProtection(toolResultProtection);
this.toolResultProtection = toolResultProtection;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Reject protected tools delegated to the client

When a tool name appears in both toolResultProtection.toolNames and clientDelegatedToolNames, this accepts the protection policy even though the delegated-call route ends the graph without passing the call through ToolNode. The client-supplied ToolMessage on the subsequent turn is then treated as conversation history and projected into the next provider request without inspect, so a result explicitly selected for mandatory protection can reach the model and generation tracing raw; reject this overlap or protect delegated-result ingestion.

AGENTS.md reference: AGENTS.md:L147-L147

Useful? React with 👍 / 👎.

Comment on lines +567 to +574
if (
existing?.policy === policy &&
existing.name === name &&
existing.id === id &&
existing.text === message.content &&
existing.status === (message.status ?? 'success')
)
return message;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Detach released messages from callback-held aliases

For a selected direct tool, the wrapper marks the canonical ToolMessage and passes that same object to native handleToolEnd callbacks; when runTool subsequently calls this function, the approved fast path returns the identical object. A callback can retain that reference and mutate its content or metadata after its awaited handler has returned, thereby changing the ToolMessage already placed in graph state before the next model request or trace consumes it, with no further provenance check. Return a detached canonical copy at this callback boundary instead of reusing the callback-visible object.

AGENTS.md reference: AGENTS.md:L147-L147

Useful? React with 👍 / 👎.

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.

2 participants