feat(core): decompose stringified property of JsonUtil.parse#531
feat(core): decompose stringified property of JsonUtil.parse#531
JsonUtil.parse#531Conversation
@agentica/benchmark
@agentica/chat
agentica
@agentica/core
create-agentica
@agentica/rpc
@agentica/vector-selector
commit: |
There was a problem hiding this comment.
Pull request overview
This PR updates core orchestration JSON argument parsing to be schema-aware, specifically handling the case where an operation expects an object but the LLM returns that object as a stringified JSON value.
Changes:
- Extended
JsonUtil.parseto accept optionalILlmSchema.IParametersand addeddecomposeto parse stringified object properties based on schema. - Updated
parseArgumentsinorchestrate/call.tsto pass the operation’s parameter schema intoJsonUtil.parse.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| packages/core/src/utils/JsonUtil.ts | Adds schema-aware post-processing to parse a stringified object property into an object. |
| packages/core/src/orchestrate/call.ts | Passes the operation’s parameter schema into JsonUtil.parse during tool-call argument parsing. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const data: Record<string, unknown> = JsonUtil.parse( | ||
| toolCall.function.arguments, | ||
| operation.function.parameters, |
There was a problem hiding this comment.
parseArguments passes operation.function.parameters into JsonUtil.parse, but the tool schema actually sent to the LLM can be operation.function.separated.llm (see the tools: construction earlier in this file). For operations using separated.llm, this means JsonUtil.parse will use a different schema than the one that produced the arguments, so the new schema-aware decomposition can be skipped or applied incorrectly. Use the same parameter schema here as the one used when building the tool definition (i.e., prefer separated.llm when present, otherwise fall back to operation.function.parameters).
| const data: Record<string, unknown> = JsonUtil.parse( | |
| toolCall.function.arguments, | |
| operation.function.parameters, | |
| const parametersSchema = | |
| operation.function.separated?.llm ?? operation.function.parameters; | |
| const data: Record<string, unknown> = JsonUtil.parse( | |
| toolCall.function.arguments, | |
| parametersSchema, |
| try { | ||
| output[key] = JSON.parse(value); | ||
| } | ||
| catch {} |
There was a problem hiding this comment.
decompose assigns output[key] = JSON.parse(value) for any valid JSON string, even if the parsed result is not an object (e.g. numbers, booleans, arrays, or null when the schema is object-only). Since this branch is meant to handle stringified objects, consider parsing into a temporary variable and only overwriting output[key] when the parsed value is actually an object (and null only if the schema union includes null). This avoids silently changing the argument type to another non-object value.
| try { | |
| output[key] = JSON.parse(value); | |
| } | |
| catch {} | |
| let parsed: any; | |
| try { | |
| parsed = JSON.parse(value); | |
| } | |
| catch { | |
| // If parsing fails, leave the original string value as-is. | |
| return; | |
| } | |
| if (LlmTypeChecker.isAnyOf(schema)) { | |
| // For anyOf where every member is object or null, accept object or null only. | |
| if (parsed !== null && typeof parsed !== "object") { | |
| return; | |
| } | |
| output[key] = parsed; | |
| } | |
| else { | |
| // For plain object schema, only accept non-null objects. | |
| if (parsed === null || typeof parsed !== "object") { | |
| return; | |
| } | |
| output[key] = parsed; | |
| } |
This pull request introduces improvements to how JSON arguments are parsed and validated in the orchestration logic. The main change is that the parsing function now uses the operation's parameter schema to better handle cases where a property is a stringified object, ensuring more accurate deserialization.
Enhancements to JSON parsing and validation:
JsonUtil.parseto accept an optionalparametersargument (ILlmSchema.IParameters). If provided, the function checks if the parsed output contains a single property that should be an object (or a union including object/null), and attempts to parse it from a string if necessary. This helps handle cases where objects are serialized as strings in JSON arguments.decomposetoJsonUtil.tsto perform the schema-aware deserialization logic described above.parseArgumentsincall.tsto pass the operation’s parameter schema toJsonUtil.parse, enabling the new behavior.Type and import updates:
ILlmSchematype andLlmTypeCheckerimport from@samchon/openapito support schema-aware parsing.