Files
composiohq__composio/.changeset/file-modifier-dereference-ref.md
T
Serhii Zghama 6a4cb542ae fix(core): resolve $ref/$defs so file flags behind a reference aren't dropped (#3566)
## Problem

Tools whose parameter schemas express their file fields through a
`$ref`/`$defs` indirection lose auto file handling: with
`dangerouslyAllowAutoUploadDownloadFiles` enabled, a `file_uploadable`
input behind a `$ref` is never staged (the local path is forwarded as-is
and the backend rejects it), and the `format: "path"` hint never reaches
the model.

`GMAIL_GET_ATTACHMENT` is the canonical shape — its parameters nest the
file flag two `$ref` hops deep:

```
data → $ref → #/$defs/GetAttachmentResponse → file → $ref → #/$defs/FileDownloadable   (file_downloadable: true)
```

This is the TypeScript-SDK counterpart of #3506 (the Python side is
handled separately in #3545).

Two coupled causes defeat reference resolution:

1. **`$defs` is dropped on parse.** `ParametersSchema`
(`src/types/tool.types.ts`) is a strict `z.object` that never declared
`$defs`/`definitions`, so `ToolSchema.parse` stripped the root
definition block off every tool. Each nested `$ref` was then dangling
and unresolvable for *all* downstream consumers — providers that pass
`inputParameters` straight to the model (e.g. `OpenAIProvider`) and the
file modifier alike. (`JSONSchemaPropertySchema` already accepts both
keywords; the root did not.)
2. **The file modifier never dereferences.** `transformProperties`,
`schemaHasFileProperty`, and the upload/download hydration recurse
`properties`/`anyOf`/`oneOf`/`allOf`/`items` but skip `$ref`, so a flag
reachable only through a reference is invisible to the walk.

## Solution

- Add `$defs`/`definitions` to `ParametersSchema` so the root definition
block survives parsing and `$ref` pointers stay resolvable.
- Dereference `inputParameters`/`outputParameters` in `FileToolModifier`
(node runtime) before walking, via the existing `dereferenceJsonSchema`
helper in `'sentinel'` mode — the same mode `MastraProvider` already
uses. Tools that ship a `$ref` without a matching `$defs` target (#3307)
degrade to a permissive object instead of throwing, exactly as today.

No new dependencies; `dereferenceJsonSchema` already exists and is
exercised by the Mastra provider. The edge (`workerd`) modifier is
unchanged — its upload/download paths already throw as unsupported.

## Testing

- `pnpm typecheck` — clean.
- `pnpm test` (core) — 926 passing, including new cases:
- `$ref`-indirected `file_uploadable` is marked `format: "path"` by
`modifyToolSchema`.
- `fileUploadModifier` stages a file whose flag is reachable only via
`$ref`/`$defs`.
- a `$ref` with no matching `$defs` target degrades gracefully (no
throw).
- root `$defs` survives `ToolSchema.parse` and nested `$ref` pointers
remain intact.
- Provider suites unaffected: `mastra` (51), `openai` (29), `vercel`
(10), `anthropic` (19) all green.

---------

Co-authored-by: jkomyno <alberto@composio.dev>
2026-06-22 19:32:07 +04:00

280 B

@composio/core
@composio/core
patch

Preserve root $defs / definitions blocks on tool parameter schemas and dereference them in the Node file modifier, so auto file upload/download detection works when file_uploadable or file_downloadable is hidden behind an internal $ref.