fix: harden select/cancel orchestration and swagger uploader#542
Merged
Conversation
`select.ts` and `cancel.ts` were left behind by the typia v12 migration (#534). `FUNCTION.parse()` now returns an `IJsonParseResult` wrapper, but the code passed the whole wrapper to `FUNCTION.validate()` instead of its `.data` - so validation always failed and every select/cancel call burned all retries feeding garbage back to the LLM. Bring both files to parity with `call.ts`: - validate the parsed `.data`, never the `IJsonParseResult` wrapper - distinguish JSON parse failures from type validation failures via a discriminated `IFailure` union - feed JSON parse failures back to the LLM (`JSON_PARSE_ERROR` prompt plus failure detail), which was previously absent entirely - enrich validation feedback with the `VALIDATE` prompt and annotated errors via `LlmJson.stringify` - use the lenient parser in PROCESS COMPLETION instead of the strict `typia.json.isParse`, so leniently-accepted arguments are not silently dropped Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The uploader ran its own strict `typia.validate()` against the union of all OpenAPI document types, rejecting real-world specs that the rest of the pipeline (`OpenApiConverter` / `HttpLlm`) accepts leniently. Valid documents triggered an "invalid json" error dialog. Parse the file, then hand it straight to `OpenApiConverter.upgradeDocument` - the same lenient converter `Agentica` relies on. Parse failures and conversion failures are now reported with distinct, accurate messages. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@agentica/benchmark
@agentica/chat
agentica
@agentica/core
create-agentica
@agentica/rpc
@agentica/vector-selector
commit: |
Contributor
There was a problem hiding this comment.
Pull request overview
This PR fixes lenient JSON handling regressions in the core select/cancel orchestration introduced during the typia v12 migration, and makes the chat Swagger/OpenAPI uploader accept real-world specs by removing redundant strict validation. It also bumps the openai dependency catalog.
Changes:
- Align
select.ts/cancel.tswithcall.tsby validatingFUNCTION.parse(...).data(not theIJsonParseResultwrapper) and feeding parse/validation failures back to the LLM with clearer prompts. - Remove strict
typia.validate()gating in the swagger uploader and rely onOpenApiConverter.upgradeDocument()for lenient conversion with better error messages. - Bump
openaicatalog to^6.38.0(and update lockfile).
Reviewed changes
Copilot reviewed 4 out of 5 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| pnpm-workspace.yaml | Bumps the workspace openai catalog version. |
| pnpm-lock.yaml | Updates locked openai resolution to match the catalog bump. |
| packages/core/src/orchestrate/select.ts | Fixes parse/validate flow for select orchestration and improves LLM-facing error feedback. |
| packages/core/src/orchestrate/cancel.ts | Fixes parse/validate flow for cancel orchestration and improves LLM-facing error feedback. |
| packages/chat/src/examples/uploader/AgenticaChatUploaderMovie.tsx | Removes redundant strict OpenAPI validation and improves parse vs conversion error handling. |
Files not reviewed (1)
- pnpm-lock.yaml: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // by the VALIDATION retry above are processed consistently here. | ||
| const parsed: IJsonParseResult<unknown> = FUNCTION.parse( | ||
| tc.function.arguments, | ||
| ); |
| // by the VALIDATION retry above are processed consistently here. | ||
| const parsed: IJsonParseResult<unknown> = FUNCTION.parse( | ||
| tc.function.arguments, | ||
| ); |
`__IChatFunctionReference.name` is typed as plain `string`, so typia validation cannot tell whether a referenced function actually exists. A hallucinated name was silently dropped by `selectFunctionFromContext` / `cancelFunctionFromContext` with no feedback and no retry. After type validation passes, check each referenced name - select against `ctx.operations.flat`, cancel against the current `ctx.stack`. Unresolved references become synthetic `IValidation.IError`s (`path` pointing at the offending `functions[i].name`, the valid function names listed in `expected`, a human-readable instruction in `description`) and are pushed as an `IValidation.IFailure`, so the existing validation-feedback path reports them to the LLM and retries within the same bounded retry budget. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…e "{}"
`reduceStreamingWithDispatch` bootstrapped its accumulator by calling
`ChatGptCompletionMessageUtil.merge([acc, chunk])` on the first reduction
step. `merge` runs an empty-arguments fixup (`arguments === "" -> "{}"`)
that is only valid on a final completion: applied mid-stream it seeded a
still-incomplete tool call with `"{}"`, and every subsequent streamed
argument chunk was appended onto it, yielding `{}{"functions":...}`.
The agent could then never select a function - the corrupted arguments
parsed to `{}`, validation failed on every retry, and `select` produced
an empty selection so the chat returned no response.
Split `merge` into `mergeChunks` (raw accumulation) + `fixEmptyToolArguments`
(the fixup). Streaming now accumulates with `mergeChunks` and applies the
fixup exactly once, to the final completion.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Hardens the select/cancel orchestration and the
packages/chatswagger uploader.fix(core)—select.ts/cancel.tsleft behind by the typia v12 migrationThe typia v12 migration (#534) updated
call.tsto the new lenientIJsonParseResultAPI but only mechanically renamedJsonUtil.parse→FUNCTION.parseinselect.ts/cancel.ts. SinceFUNCTION.parse()nowreturns an
IJsonParseResultwrapper ({ success, data, errors }), theas objectcast hid the fact that the whole wrapper was passed toFUNCTION.validate()instead of its.data.Result: validation failed on every select/cancel call, burning all
RETRYattempts and feeding garbage back to the LLM via
emendMessages.Brought both files to parity with
call.ts:.data, never theIJsonParseResultwrapperIFailureunion)JSON_PARSE_ERRORprompt + failure detail) — previously absent entirelyVALIDATEprompt +LlmJson.stringifyannotated errorstypia.json.isParse, so leniently-accepted arguments are not silently droppedfix(core)— feed back non-existent function references__IChatFunctionReference.nameis typed as plainstring, so typia validationcannot tell whether a referenced function actually exists. A hallucinated name
was silently dropped by
selectFunctionFromContext/cancelFunctionFromContextwith no feedback and no retry.
After type validation passes, each referenced name is checked — select against
ctx.operations.flat, cancel against the currentctx.stack. Unresolvedreferences become synthetic
IValidation.IErrors (path→ the offendingfunctions[i].name, valid names listed inexpected, instruction indescription) pushed as anIValidation.IFailure, so the existingvalidation-feedback path reports them to the LLM and retries within the same
bounded retry budget.
fix(chat)— redundant strict OpenAPI validation in the swagger uploaderAgenticaChatUploaderMovieran its own stricttypia.validate()against theunion of all OpenAPI document types, rejecting real-world specs that the rest
of the pipeline (
OpenApiConverter/HttpLlm) accepts leniently — surfacingas an "invalid json" error dialog. It now parses the file and hands it
straight to
OpenApiConverter.upgradeDocument, with distinct messages forparse vs. conversion failures.
chore(deps)Bump
openaicatalog to^6.38.0.Test plan
tscfull build ofpackages/core— passestsc -p tsconfig.app.jsonofpackages/chat— passeseslinton all changed files — passesKnown follow-ups (not in this PR)
IFailure,emendMessagesandvalidateFunctionExistenceare duplicated acrossselect.ts/cancel.ts— this duplication is what let the fix(core): newtypiafor lenient json parsing and coercing. #534 regression slip through; extracting a shared helper would prevent recurrence.call.tssurfaces asuccess: falseevent.🤖 Generated with Claude Code