Repository navigation
fix: Expose image_edit_oai to Agents That Select It Directly - #16974
RutgerLubbers wants to merge 2 commits into
Conversation
There was a problem hiding this comment.
🟡 Changes recommended
The fallback bypasses active-branch scoping and the established inspected file-resource pipeline.
1 open finding
What changed in this PR
Enables agents to select and use image_edit_oai independently.
Changes:
- Recognizes toolkit child tools directly.
- Filters toolkit output to selected tools.
- Adds conversation-image fallback and regression tests.
| File | Description |
|---|---|
packages/api/src/tools/definitions.ts |
Recognizes toolkit children. |
packages/api/src/tools/definitions.spec.ts |
Tests child recognition. |
api/app/clients/tools/util/handleTools.js |
Filters tools and loads image references. |
api/app/clients/tools/util/handleTools.test.js |
Tests toolkit filtering. |
🧠 Review effort: Balanced
💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
60537e6 to
dcde508
Compare
|
Moved the fallback out of the legacy |
dcde508 to
92f3956
Compare
A toolkit child such as image_edit_oai is not a manifest plugin/toolkit key, so the runtime isBuiltInTool predicate reports it as not built-in and its definition is dropped. The model then writes the call as plain text instead of invoking the tool. Treat the children listed in the toolkit parent mapping as built-in so their definitions and registry entries are emitted.
…nly Selected Tools An image-edit tool references its input by file_id, but an image uploaded on an earlier turn is neither a request attachment nor a persisted agent file, so the model receives no id to edit. primeResources now primes the conversation's images for image tools: the file ids the conversation references are hydrated under the requesting owner and passed through the same access filtering and policy screening as any other historical file before landing in tool_resources[image_edit]. The loader stays a pure adapter that reads the primed resources. The image toolkit constructor always builds both image_gen_oai and image_edit_oai; the loader now exposes only the tools the agent requested, expanding toolkit keys (image_gen_oai -> image_edit_oai) so selecting the toolkit still exposes its child while an edit-only agent can no longer fall back to text-to-image.
92f3956 to
9814a3c
Compare

Pull Request
Summary
An agent that enables only
image_edit_oaicannot edit images.image_edit_oaiis a child of theimage_gen_oaitoolkit: it is not a manifest plugin/toolkit key, so the definition loader drops it, and the shared toolkit constructor still exposes both image tools with no reference image. Selecting the toolkit (image_gen_oai) works because that key is treated as built-in.This PR makes the directly selected toolkit child work end to end: the definition is emitted, the conversation's images are primed for it, and only the tools the agent selected are loaded.
How it works
Recognition comes from the toolkit parent mapping rather than the manifest, so a child selected on its own is no longer skipped:
An image-edit tool references its input by
file_id, and the edit usually targets an image uploaded on an earlier turn. That image is neither a request attachment nor a persisted agent file, so it is absent from every sourceprimeResourcesalready walks.primeResourcesnow primes it through an injected loader, keeping the DB read and file selection inpackages/apiand applying the same access filtering (filterFiles) and policy screening (screenPersistentFiles) as any other historical file:+ await applyConversationImageEditFallback(); const provisionState = await computeProvisionState({ ... });initialize.tssupplies that loader: it reads the conversation's referenced file ids, hydrates them under the requesting owner, and passes the result intoprimeResources. The legacy/apiloader (handleTools.js) stays a pure adapter — it only readstool_resources[image_edit].filesand exposes the tools the agent selected, expanding toolkit keys so selecting the toolkit still yields its child:Type of change
Testing
Automated tests:
packages/api/src/tools/definitions.spec.ts: a toolkit child selected on its own is included (fails without the definition-loader change).packages/api/src/agents/resources.test.ts:primeResourcesprimes a conversation's images for an image-edit agent, passes them throughfilterFiles, skips when the agent cannot edit images or an image is already primed, and ignores records without dimensions.api/app/clients/tools/util/handleTools.test.js: an edit-only agent receives onlyimage_edit_oai, and the toolkit still exposes both tools (the second fails without the expansion-aware filter).All suites pass locally (
jest), along withtscandeslinton the changed files.Tested environments/configuration:
image_edit_oai.Manual verification: upload an image in a conversation, then ask the edit-only agent to modify it, and confirm the model calls
image_edit_oaiwith the realfile_idand returns an edited image.Screenshots / recordings
No user-facing change.
Risk / compatibility
None notable. The definition gate only widens recognition to names already present in the toolkit parent mapping. The conversation-image fallback runs only for agents whose tools include an image tool and only when no image is primed yet; it reuses the existing owner-scoped hydration and access/policy checks, so it adds no new file-loading path.
Checklist