Skip to content

Commit ea9b024

Browse files
committed
openapi: keep the file-emit hint on the fast serve path
The content-addressed serve path rebuilds a tool def from the persisted binding instead of re-parsing the spec. The re-parse path (kept as the fallback) appends the ToolFile emit contract to a file-returning tool's description at the projection step; the fast path bypassed that step and served the bare description, so a file-returning operation lost the contract whenever it was served from the binding (the common case once a spec is persisted). Apply the hint at the same projection step in the fast path, sourced from the binding's response fileHint (already inspected for the output schema), so a file tool carries the contract identically whether served fast or via the fallback. No persist-path or schema change: existing rows pick it up on the next list. Covered by the tool-descriptions e2e scenario.
1 parent 408e9da commit ea9b024

1 file changed

Lines changed: 19 additions & 9 deletions

File tree

packages/plugins/openapi/src/sdk/backing.ts

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -290,26 +290,36 @@ const decodeDefsJson = Schema.decodeUnknownOption(Schema.fromJsonString(DefsJson
290290

291291
/** Rebuild a tool def from a stored operation binding, no spec parse. Mirrors
292292
* `openApiToolDefsFromCompiled` but sources its schemas from the persisted
293-
* binding (params/body/response carry `$ref`s into the shared defs blob). */
293+
* binding (params/body/response carry `$ref`s into the shared defs blob). The
294+
* file-emit hint is applied here, at the same ToolDef projection step the
295+
* re-parse path applies it, so a file-returning op carries the contract
296+
* whether it is served fast (from the binding) or via the spec fallback. */
294297
const toolDefFromStoredOperation = (op: StoredOperation): ToolDef => {
295298
const binding = op.binding;
299+
const returnsFile = Option.match(binding.responseBody, {
300+
onNone: () => false,
301+
onSome: (responseBody) => Option.isSome(responseBody.fileHint),
302+
});
296303
return {
297304
name: ToolName.make(op.toolName),
298-
description: op.description ?? `${binding.method.toUpperCase()} ${binding.pathTemplate}`,
305+
description: withFileEmitHint(
306+
op.description ?? `${binding.method.toUpperCase()} ${binding.pathTemplate}`,
307+
returnsFile,
308+
),
299309
inputSchema: normalizeOpenApiRefs(
300310
buildInputSchema(
301311
binding.parameters,
302312
Option.getOrUndefined(binding.requestBody),
303313
binding.servers ?? [],
304314
),
305315
),
306-
outputSchema: Option.match(binding.responseBody, {
307-
onNone: () => undefined,
308-
onSome: (responseBody) =>
309-
Option.isSome(responseBody.fileHint)
310-
? ToolFileJsonSchema
311-
: normalizeOpenApiRefs(Option.getOrUndefined(responseBody.schema)),
312-
}),
316+
outputSchema: returnsFile
317+
? ToolFileJsonSchema
318+
: Option.match(binding.responseBody, {
319+
onNone: () => undefined,
320+
onSome: (responseBody) =>
321+
normalizeOpenApiRefs(Option.getOrUndefined(responseBody.schema)),
322+
}),
313323
annotations: annotationsForOperation(binding.method, binding.pathTemplate),
314324
};
315325
};

0 commit comments

Comments
 (0)