JSON value transport: validate structured results directly
Generate JSON collection and parsing from an output Schema without adding a tool-selection envelope, and return a unified model result.
The json mode is enabled by default; CompatibleModelProvider uses json_object. When array or scalar output requires turning that provider mode off, set options.json=false explicitly, and the same JSON decoding and Schema validation still run.
createJsonTransport({id,outputSchema,options?}) returns an implementation that satisfies the Core ModelTransportDefinition<T> contract and preserves the id literal. outputSchema is a SchemaAdapter<T> containing the JSON Schema and a synchronous parser; it can be a plain object, a Support Schema implementation, or a custom class. The parser is also called after JSON decoding, so neither the Schema declaration nor the model output can replace runtime validation.
Each model call creates a new collector and does not share fragment caches. The collector accepts text fragments; function-call fragments, invalid JSON, Schema validation failures, and asynchronous parsers are all rejected. The Runner continues to own input, Schema, output budget, cancellation, and call quota; this helper does not create extra runners or widen permissions.
The model output is directly the JSON value of that Schema, and the call result is still {value,invocation}. It has no tool/input envelope and does not require a tool catalog. Use createModelTransport/createStageModelTransport when the model must select tools. The Provider decides the JSON wire format and which value types are actually supported; nothing is inferred from the model name.
Progressive examples for the same business case
Minimal JSON summary: bind Schema and parser in one step
Beginner · Node.js
import { ModelRunner, Support } from '@jangts/agent-core';
const summary = Support.createJsonTransport({ id: 'summary', outputSchema: {
jsonSchema: { type: 'object', properties: { text: { type: 'string' } }, required: ['text'], additionalProperties: false },
parse(value: unknown) {
if (!value || typeof value !== 'object' || !('text' in value) || typeof value.text !== 'string') throw new TypeError('需要摘要正文');
return { text: value.text };
},
} });
const provider = { async *stream() { yield '{"text":"服务运行正常。"}'; } };
const model = new ModelRunner({ provider, transports: [summary] });
const result = await model.invoke({ input: '概括服务状态', transport: summary });
console.log(result.value.text, result.invocation);import { ModelRunner, Support } from '@jangts/agent-core';
const summary = Support.createJsonTransport({ id: 'summary', outputSchema: {
jsonSchema: { type: 'object', properties: { text: { type: 'string' } }, required: ['text'], additionalProperties: false },
parse(value) {
if (!value || typeof value !== 'object' || !('text' in value) || typeof value.text !== 'string')
throw new TypeError('需要摘要正文');
return { text: value.text };
},
} });
const provider = { async *stream() { yield '{"text":"服务运行正常。"}'; } };
const model = new ModelRunner({ provider, transports: [summary] });
const result = await model.invoke({ input: '概括服务状态', transport: summary });
console.log(result.value.text, result.invocation);Add temperature, budget, and a custom parser to the same summary contract
Extension · Node.js
Both examples use offline Providers. When switching providers, the same transport and call contract continue to apply.
import { ModelRunner, Support } from '@jangts/agent-core';
class SummarySchema {
readonly jsonSchema = { type: 'object', properties: { text: { type: 'string' } }, required: ['text'], additionalProperties: false };
#maxChars = 100;
parse(value: unknown) {
if (!value || typeof value !== 'object' || !('text' in value) || typeof value.text !== 'string'
|| !value.text.trim() || value.text.length > this.#maxChars) throw new TypeError('需要简短摘要');
return { text: value.text };
}
}
const summary = Support.createJsonTransport({ id: 'summary', outputSchema: new SummarySchema(), options: { temperature: 0.2 } });
const model = new ModelRunner({ provider: { async *stream() { yield '{"text":"服务运行正常。"}'; } },
transports: [summary], maxCalls: 2, maxOutputTokens: 256,
});
console.log((await model.invoke({ input: '概括服务状态', transport: 'summary' })).value.text);import { ModelRunner, Support } from '@jangts/agent-core';
class SummarySchema {
jsonSchema = { type: 'object', properties: { text: { type: 'string' } }, required: ['text'], additionalProperties: false };
#maxChars = 100;
parse(value) {
if (!value || typeof value !== 'object' || !('text' in value) || typeof value.text !== 'string'
|| !value.text.trim() || value.text.length > this.#maxChars)
throw new TypeError('需要简短摘要');
return { text: value.text };
}
}
const summary = Support.createJsonTransport({ id: 'summary', outputSchema: new SummarySchema(), options: { temperature: 0.2 } });
const model = new ModelRunner({ provider: { async *stream() { yield '{"text":"服务运行正常。"}'; } },
transports: [summary], maxCalls: 2, maxOutputTokens: 256,
});
console.log((await model.invoke({ input: '概括服务状态', transport: 'summary' })).value.text);