@cartanova/qgrid-ai-sdk 2.5.2 → 2.5.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ko.md +70 -4
- package/README.md +75 -4
- package/dist/index.d.ts +6 -0
- package/dist/index.js +17 -7
- package/package.json +4 -2
package/README.ko.md
CHANGED
|
@@ -93,7 +93,7 @@ console.log(output.title, output.authors);
|
|
|
93
93
|
top-level이 `object`인 schema는 서버 structured output으로 전달되어 강제됩니다.
|
|
94
94
|
top-level이 `object`가 아니면 (예: array) AI SDK 클라이언트 파싱으로 fallback되며 경고 로그가 출력됩니다.
|
|
95
95
|
|
|
96
|
-
> **Anthropic 모델 주의:** OpenAI/codex structured output은 디코딩 단계에서 schema를 강제(constrained decoding)하므로 이 부류 실패가 거의 없지만, Claude Code의 `--json-schema`는 StructuredOutput tool + 사후 검증 방식이라 복잡한 schema는 모델이 준수하지 못할 수 있습니다. qgrid는
|
|
96
|
+
> **Anthropic 모델 주의:** OpenAI/codex structured output은 디코딩 단계에서 schema를 강제(constrained decoding)하므로 이 부류 실패가 거의 없지만, Claude Code의 `--json-schema`는 `StructuredOutput` tool + 사후 검증 방식이라 복잡한 schema는 모델이 준수하지 못할 수 있습니다. qgrid는 structured streaming에만 `MAX_STRUCTURED_OUTPUT_RETRIES=1`을 주입해 1회 시도로 제한합니다(1 미만 값은 1로 클램프). non-stream `generate`에는 이 override를 주입하지 않고 Claude Code의 기본 retry 예산을 사용합니다. 각 경로의 시도 이후 검증이 실패하면 깨진 JSON 대신 명시적 에러를 반환합니다.
|
|
97
97
|
|
|
98
98
|
### 스트리밍
|
|
99
99
|
|
|
@@ -114,7 +114,7 @@ for await (const chunk of textStream) {
|
|
|
114
114
|
### Tool Calling
|
|
115
115
|
|
|
116
116
|
```typescript
|
|
117
|
-
import { generateText, tool } from "ai";
|
|
117
|
+
import { generateText, stepCountIs, tool } from "ai";
|
|
118
118
|
import { qgrid } from "@cartanova/qgrid-ai-sdk";
|
|
119
119
|
import { z } from "zod";
|
|
120
120
|
|
|
@@ -124,17 +124,54 @@ const { text } = await generateText({
|
|
|
124
124
|
tools: {
|
|
125
125
|
getWeather: tool({
|
|
126
126
|
description: "도시의 현재 날씨 조회",
|
|
127
|
-
|
|
127
|
+
inputSchema: z.object({ city: z.string() }),
|
|
128
128
|
execute: async ({ city }) => {
|
|
129
129
|
return { temperature: 22, condition: "맑음" };
|
|
130
130
|
},
|
|
131
131
|
}),
|
|
132
132
|
},
|
|
133
|
+
stopWhen: stepCountIs(3),
|
|
133
134
|
});
|
|
134
135
|
```
|
|
135
136
|
|
|
136
137
|
tool-call은 qgrid 서버의 structured output emulation으로 동작합니다.
|
|
137
138
|
AI SDK가 tool 실행을 관리하고, qgrid는 각 턴의 LLM 호출만 담당합니다.
|
|
139
|
+
실행 가능한 tool을 쓸 때는 제한이 있는 `stopWhen`을 지정해야 AI SDK가
|
|
140
|
+
tool-call 턴 뒤에도 계속 진행해 모델의 최종 응답을 받습니다.
|
|
141
|
+
|
|
142
|
+
`tools`와 `Output.object`를 함께 사용할 수도 있습니다.
|
|
143
|
+
|
|
144
|
+
```typescript
|
|
145
|
+
import { generateText, Output, stepCountIs, tool } from "ai";
|
|
146
|
+
import { qgrid } from "@cartanova/qgrid-ai-sdk";
|
|
147
|
+
import { z } from "zod";
|
|
148
|
+
|
|
149
|
+
const { output } = await generateText({
|
|
150
|
+
model: qgrid("openai/gpt-5.4"),
|
|
151
|
+
prompt: "서울 날씨를 조회해서 예보를 반환해줘.",
|
|
152
|
+
tools: {
|
|
153
|
+
getWeather: tool({
|
|
154
|
+
description: "도시의 현재 날씨 조회",
|
|
155
|
+
inputSchema: z.object({ city: z.string() }),
|
|
156
|
+
execute: async ({ city }) => ({ city, temperature: 22 }),
|
|
157
|
+
}),
|
|
158
|
+
},
|
|
159
|
+
stopWhen: stepCountIs(3),
|
|
160
|
+
output: Output.object({
|
|
161
|
+
schema: z.object({
|
|
162
|
+
city: z.string(),
|
|
163
|
+
summary: z.string(),
|
|
164
|
+
}),
|
|
165
|
+
}),
|
|
166
|
+
});
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
qgrid 2.5.4는 모든 모델 턴에 합성된 action envelope를 강제합니다. tool-call
|
|
170
|
+
턴은 AI SDK tool call로 유지되고, 마지막 `answer`는 사용자 schema로 강제된 뒤
|
|
171
|
+
`output`으로 반환됩니다. 제한이 있는 `stopWhen`을 지정하지 않으면 AI SDK가
|
|
172
|
+
기본 첫 번째 step에서 멈춰 최종 structured output을 만들 수 없습니다. qgrid server
|
|
173
|
+
2.5.4와 `@cartanova/qgrid-ai-sdk` 2.5.4가 모두 필요합니다. AI SDK의
|
|
174
|
+
`toolChoice`는 현재 전송하거나 강제하지 않으며 tool 선택은 모델이 결정합니다.
|
|
138
175
|
|
|
139
176
|
### Provider Options
|
|
140
177
|
|
|
@@ -168,10 +205,16 @@ const { text } = await generateText({
|
|
|
168
205
|
| `verbosity` | `"low"` \| `"medium"` \| `"high"` | OpenAI 전용 | 응답 텍스트의 상세도 |
|
|
169
206
|
| `reasoningSummary` | `"auto"` \| `"concise"` \| `"detailed"` \| `"none"` | OpenAI 전용 | 추론 요약 출력 방식 |
|
|
170
207
|
| `serviceTier` | `string` | OpenAI 전용 | OpenAI/codex service tier |
|
|
208
|
+
| `timeoutMs` | 양의 정수, 최대 `1_800_000` | Anthropic 전용 | 서버의 Claude Code 프로세스 제한시간(ms). 기본값은 240초 |
|
|
171
209
|
| `imageGeneration` | `boolean` | OpenAI 전용, non-stream | codex 내장 `image_generation` tool 활성화 ([아래](#image-generation) 참조) |
|
|
172
210
|
| `imageGenerationOptions` | `{ quality?, size? }` | OpenAI 전용 | 이미지 품질/크기 힌트. `quality: "low" \| "medium" \| "high"`, `size: "1024x1024" \| "1024x1536" \| "1536x1024"` (기본: `medium` / `1536x1024`) |
|
|
173
211
|
| `fallbackModels` | `string[]` | 예약 | 향후 qgrid 서버 fallback routing용 예약 필드. 현재 동작하지 않으며 Claude Code의 Fable refusal fallback과 무관 |
|
|
174
212
|
|
|
213
|
+
AI SDK 최상위 `timeout`은 전체 클라이언트 제한시간이며 custom provider 실행 전에
|
|
214
|
+
`AbortSignal`로 변환됩니다. 따라서 그 숫자 자체는 qgrid에 전달되지 않습니다. qgrid 서버의
|
|
215
|
+
Claude Code 프로세스 제한시간을 바꾸려면 `providerOptions.qgrid.timeoutMs`를 사용하세요.
|
|
216
|
+
클라이언트 취소 또는 비스트리밍 HTTP 연결 종료도 서버의 provider 실행을 중단합니다.
|
|
217
|
+
|
|
175
218
|
### 멀티턴 prompt cache (sessionKey)
|
|
176
219
|
|
|
177
220
|
멀티턴 대화에서 `sessionKey`로 호출자의 도메인 ID(게임 세션 ID, 채팅방 ID 등) 하나만 넘기면, provider가 같은 대화를 같은 codex thread로 라우팅하여 prompt cache를 적중시킵니다. thread 좌표의 발급/보관/회송은 provider 내부에서 처리하므로 호출자는 key만 넘기면 됩니다.
|
|
@@ -363,7 +406,30 @@ qgrid(modelId, {
|
|
|
363
406
|
|
|
364
407
|
- `temperature`, `maxOutputTokens` 등 sampling 파라미터는 CLI 런타임(OpenAI: codex app-server, Anthropic: Claude Code)이 지원하지 않아 무시됩니다.
|
|
365
408
|
- Structured output은 top-level `object` schema만 서버에서 강제됩니다. top-level `array`는 클라이언트 파싱 fallback.
|
|
366
|
-
- `tools`와
|
|
409
|
+
- `tools`와 `Output.object`를 함께 사용하려면 qgrid server와 AI SDK가 모두 2.5.4 이상이어야 합니다.
|
|
410
|
+
- AI SDK/Zod가 Draft-7 `items: [...]`로 만드는 위치 기반 tuple은 지원되는
|
|
411
|
+
positive schema 위치에서 OpenAI 호출 전에 정규화되고 위치별 제약이
|
|
412
|
+
강제됩니다. tuple tail이 생략되면 고정 길이로 해석하며,
|
|
413
|
+
`additionalItems: true`로 명시한 무제한 tail은 HTTP 400으로 거부합니다.
|
|
414
|
+
negative, conditional 등 안전하게 정규화할 수 없는 위치의 tuple도 의미가
|
|
415
|
+
바뀌는 변환 대신 HTTP 400으로 거부합니다. definition은 전역 정규화되므로
|
|
416
|
+
해당 위치에서 참조하는 경우도 같은 이유로 거부합니다. Anthropic 위치 기반
|
|
417
|
+
tuple schema는 Claude Code가 위치 의미를 보존할 수 없어 HTTP 400으로
|
|
418
|
+
거부됩니다. tuple node는 `type: "array"`를 명시해야 하며 nullable tuple은
|
|
419
|
+
array/null `anyOf`로 표현합니다.
|
|
420
|
+
- structured schema에서는 문서 root 또는 `$defs`/`definitions` entry root만
|
|
421
|
+
연속으로 가리키는 로컬 root-relative JSON Pointer `$ref`를 허용합니다.
|
|
422
|
+
property, tuple 내부, conditional, literal 값을 가리키는 ref는 정규화 중
|
|
423
|
+
target이 이동하거나 다시 작성될 수 있어 HTTP 400으로 거부합니다. resource
|
|
424
|
+
ID, anchor, 외부 ref, dynamic ref, recursive ref도 허용하지 않습니다.
|
|
425
|
+
- output/tool schema serialization, tool 이름, 설명, JSON escaping,
|
|
426
|
+
composition framing은 합산 UTF-8 512 KiB 전처리 한도를 공유합니다.
|
|
427
|
+
schema 값에는 별도로 합산 20,000 node와 schema별 최대 깊이 128 한도가
|
|
428
|
+
적용됩니다. 잘못되거나 한도를 넘는 입력은 provider 실행 전에 HTTP 400으로
|
|
429
|
+
실패합니다.
|
|
430
|
+
- Anthropic 경로에서는 최종 합성 schema가 Claude Code 전송의 안전한 단일 argv
|
|
431
|
+
한도인 64 KiB도 넘지 않아야 합니다.
|
|
432
|
+
- AI SDK의 `toolChoice`는 현재 qgrid에서 지원하지 않습니다.
|
|
367
433
|
|
|
368
434
|
## 요구사항
|
|
369
435
|
|
package/README.md
CHANGED
|
@@ -93,7 +93,7 @@ console.log(output.title, output.authors);
|
|
|
93
93
|
Schemas with a top-level `object` are forwarded to server-side structured output and enforced.
|
|
94
94
|
If the top level is not an `object` (e.g. array), the AI SDK falls back to client-side parsing and a warning is logged.
|
|
95
95
|
|
|
96
|
-
> **Note for Anthropic models:** OpenAI/codex structured output constrains decoding to the schema, so this class of failure is rare there. Claude Code's `--json-schema`, however, works as a StructuredOutput tool
|
|
96
|
+
> **Note for Anthropic models:** OpenAI/codex structured output constrains decoding to the schema, so this class of failure is rare there. Claude Code's `--json-schema`, however, works as a `StructuredOutput` tool plus post-hoc validation, so the model may fail to honor a complex schema. For structured streaming only, qgrid sets `MAX_STRUCTURED_OUTPUT_RETRIES=1` (one attempt; values below 1 are clamped to 1) to bound stream latency. Non-streaming `generate` leaves that override unset and uses Claude Code's default retry budget. Validation failures after the applicable attempts return an explicit error instead of broken JSON.
|
|
97
97
|
|
|
98
98
|
### Streaming
|
|
99
99
|
|
|
@@ -114,7 +114,7 @@ for await (const chunk of textStream) {
|
|
|
114
114
|
### Tool Calling
|
|
115
115
|
|
|
116
116
|
```typescript
|
|
117
|
-
import { generateText, tool } from "ai";
|
|
117
|
+
import { generateText, stepCountIs, tool } from "ai";
|
|
118
118
|
import { qgrid } from "@cartanova/qgrid-ai-sdk";
|
|
119
119
|
import { z } from "zod";
|
|
120
120
|
|
|
@@ -124,17 +124,55 @@ const { text } = await generateText({
|
|
|
124
124
|
tools: {
|
|
125
125
|
getWeather: tool({
|
|
126
126
|
description: "Get the current weather for a city",
|
|
127
|
-
|
|
127
|
+
inputSchema: z.object({ city: z.string() }),
|
|
128
128
|
execute: async ({ city }) => {
|
|
129
129
|
return { temperature: 22, condition: "sunny" };
|
|
130
130
|
},
|
|
131
131
|
}),
|
|
132
132
|
},
|
|
133
|
+
stopWhen: stepCountIs(3),
|
|
133
134
|
});
|
|
134
135
|
```
|
|
135
136
|
|
|
136
137
|
Tool calls work through the qgrid server's structured output emulation.
|
|
137
138
|
The AI SDK manages tool execution; qgrid handles only each turn's LLM call.
|
|
139
|
+
Executable tools require a bounded `stopWhen` so the AI SDK continues after a
|
|
140
|
+
tool-call step and asks the model for the final response.
|
|
141
|
+
|
|
142
|
+
Tools can be combined with `Output.object`:
|
|
143
|
+
|
|
144
|
+
```typescript
|
|
145
|
+
import { generateText, Output, stepCountIs, tool } from "ai";
|
|
146
|
+
import { qgrid } from "@cartanova/qgrid-ai-sdk";
|
|
147
|
+
import { z } from "zod";
|
|
148
|
+
|
|
149
|
+
const { output } = await generateText({
|
|
150
|
+
model: qgrid("openai/gpt-5.4"),
|
|
151
|
+
prompt: "Look up Seoul's weather and return a forecast.",
|
|
152
|
+
tools: {
|
|
153
|
+
getWeather: tool({
|
|
154
|
+
description: "Get the current weather for a city",
|
|
155
|
+
inputSchema: z.object({ city: z.string() }),
|
|
156
|
+
execute: async ({ city }) => ({ city, temperature: 22 }),
|
|
157
|
+
}),
|
|
158
|
+
},
|
|
159
|
+
stopWhen: stepCountIs(3),
|
|
160
|
+
output: Output.object({
|
|
161
|
+
schema: z.object({
|
|
162
|
+
city: z.string(),
|
|
163
|
+
summary: z.string(),
|
|
164
|
+
}),
|
|
165
|
+
}),
|
|
166
|
+
});
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
qgrid 2.5.4 constrains every model turn with a composed action envelope. Tool-call
|
|
170
|
+
turns remain AI SDK tool calls, while the final `answer` is constrained by the
|
|
171
|
+
user schema and returned as `output`. Keep a bounded `stopWhen`; otherwise AI SDK
|
|
172
|
+
stops after its default first step and cannot produce the final structured output.
|
|
173
|
+
This requires both qgrid server 2.5.4 and `@cartanova/qgrid-ai-sdk` 2.5.4. AI SDK
|
|
174
|
+
`toolChoice` is not currently transported or enforced; tool selection remains
|
|
175
|
+
model-driven.
|
|
138
176
|
|
|
139
177
|
### Provider Options
|
|
140
178
|
|
|
@@ -168,10 +206,17 @@ const { text } = await generateText({
|
|
|
168
206
|
| `verbosity` | `"low"` \| `"medium"` \| `"high"` | OpenAI only | Response text verbosity |
|
|
169
207
|
| `reasoningSummary` | `"auto"` \| `"concise"` \| `"detailed"` \| `"none"` | OpenAI only | Reasoning summary output mode |
|
|
170
208
|
| `serviceTier` | `string` | OpenAI only | OpenAI/codex service tier |
|
|
209
|
+
| `timeoutMs` | positive integer, max `1_800_000` | Anthropic only | Server-side Claude Code process timeout in milliseconds. Defaults to 240 seconds |
|
|
171
210
|
| `imageGeneration` | `boolean` | OpenAI only, non-stream | Enables codex's built-in `image_generation` tool (see [below](#image-generation)) |
|
|
172
211
|
| `imageGenerationOptions` | `{ quality?, size? }` | OpenAI only | Image quality/size hints. `quality: "low" \| "medium" \| "high"`, `size: "1024x1024" \| "1024x1536" \| "1536x1024"` (defaults: `medium` / `1536x1024`) |
|
|
173
212
|
| `fallbackModels` | `string[]` | reserved | Reserved for future qgrid server-side fallback routing. Not functional yet and unrelated to Claude Code's Fable refusal fallback |
|
|
174
213
|
|
|
214
|
+
AI SDK's top-level `timeout` remains the overall client-side budget and is converted to an
|
|
215
|
+
`AbortSignal` before the custom provider runs. It does not expose the numeric timeout to qgrid.
|
|
216
|
+
Use `providerOptions.qgrid.timeoutMs` when the qgrid server's Claude Code process needs a different
|
|
217
|
+
limit. A client abort or disconnected non-streaming HTTP request also terminates the server-side
|
|
218
|
+
provider execution.
|
|
219
|
+
|
|
175
220
|
### Multi-turn prompt cache (sessionKey)
|
|
176
221
|
|
|
177
222
|
For multi-turn conversations, pass a single caller-side domain ID (game session ID, chat room ID, ...) as `sessionKey` and the provider routes the same conversation to the same codex thread, hitting the prompt cache. Thread coordinate issuance/storage/replay is handled inside the provider — the caller only passes the key.
|
|
@@ -363,7 +408,33 @@ If multiple projects/workflows share one qgrid server, set `QGRID_PROJECT_NAME`.
|
|
|
363
408
|
|
|
364
409
|
- Sampling parameters such as `temperature` and `maxOutputTokens` are ignored — the CLI runtimes (OpenAI: codex app-server, Anthropic: Claude Code) do not support them.
|
|
365
410
|
- Structured output is server-enforced only for top-level `object` schemas. Top-level `array` falls back to client-side parsing.
|
|
366
|
-
- `tools`
|
|
411
|
+
- Combining `tools` with `Output.object` requires qgrid server and AI SDK 2.5.4 or later.
|
|
412
|
+
- AI SDK/Zod positional tuples emitted as Draft-7 `items: [...]` are normalized
|
|
413
|
+
in supported positive schema positions before OpenAI dispatch and their
|
|
414
|
+
positional constraints are enforced. An omitted tuple tail is treated as
|
|
415
|
+
fixed-length; an explicitly unrestricted `additionalItems: true` tail is
|
|
416
|
+
rejected with HTTP 400. Tuples in negative, conditional, or otherwise
|
|
417
|
+
non-normalizable schema positions are also rejected instead of being
|
|
418
|
+
rewritten with changed semantics. References from those positions are
|
|
419
|
+
rejected for the same reason because definitions are normalized globally.
|
|
420
|
+
Anthropic positional tuple schemas are rejected with HTTP 400 because Claude
|
|
421
|
+
Code cannot preserve their positional semantics. Tuple nodes must explicitly
|
|
422
|
+
declare `type: "array"`; express nullable tuples with an `anyOf` array/null
|
|
423
|
+
branch.
|
|
424
|
+
- Structured schemas accept only local root-relative JSON Pointer `$ref` values
|
|
425
|
+
targeting the document root or a chain of `$defs`/`definitions` entry roots.
|
|
426
|
+
References into properties, tuple internals, conditionals, or literal values
|
|
427
|
+
fail with HTTP 400 because normalization can move or rewrite those targets.
|
|
428
|
+
Resource IDs, anchors, external refs, dynamic refs, and recursive refs are
|
|
429
|
+
also rejected.
|
|
430
|
+
- Output/tool schema serialization, tool names, descriptions, JSON escaping,
|
|
431
|
+
and composition framing share an aggregate 512 KiB UTF-8 preprocessing
|
|
432
|
+
budget. Schema values also share a 20,000-node budget and have a maximum
|
|
433
|
+
depth of 128 per schema. Invalid or over-budget inputs fail with HTTP 400
|
|
434
|
+
before provider execution.
|
|
435
|
+
- On Anthropic routes, the final composed schema must also fit the 64 KiB safe
|
|
436
|
+
single-argument budget used by the Claude Code transport.
|
|
437
|
+
- AI SDK `toolChoice` is not currently supported by qgrid.
|
|
367
438
|
|
|
368
439
|
## Requirements
|
|
369
440
|
|
package/dist/index.d.ts
CHANGED
|
@@ -31,6 +31,12 @@ type QgridProviderOptions = {
|
|
|
31
31
|
reasoningSummary?: "auto" | "concise" | "detailed" | "none";
|
|
32
32
|
/** OpenAI/codex service tier. OpenAI/codex route에서만 적용된다. */
|
|
33
33
|
serviceTier?: string;
|
|
34
|
+
/**
|
|
35
|
+
* qgrid 서버의 provider 실행 제한(ms). Anthropic 경로에서는 Claude Code 프로세스 타이머로
|
|
36
|
+
* 사용된다. AI SDK 표준 timeout은 provider에 숫자를 전달하지 않고 abortSignal로 변환되므로,
|
|
37
|
+
* 서버 측 제한을 바꾸려면 이 옵션을 사용한다. 양의 정수만 허용하며 최대 30분, 기본 240초다.
|
|
38
|
+
*/
|
|
39
|
+
timeoutMs?: number;
|
|
34
40
|
/**
|
|
35
41
|
* @todo 향후 qgrid 서버 fallback routing에 사용할 후보 모델 목록.
|
|
36
42
|
* Claude Code가 처리하는 Fable 5 safety-refusal fallback과는 무관하다.
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
const QGRID_PROVIDER_NAME = "qgrid";
|
|
3
3
|
const THREAD_COORD_TTL_MS = 10 * 6e4;
|
|
4
4
|
const TEXT_STREAM_ID_PREFIX = "text";
|
|
5
|
-
const TOP_LEVEL_SCHEMA_WARNING = "
|
|
5
|
+
const TOP_LEVEL_SCHEMA_WARNING = "qgrid server-enforced structured output requires \"object\". Falling back to client-side parsing.";
|
|
6
6
|
const PENDING_TOOL_RESULTS_WARNING = "[qgrid] tool results did not match any pending qgrid run; sending request without runContext";
|
|
7
7
|
//#endregion
|
|
8
8
|
//#region src/utils.ts
|
|
@@ -678,6 +678,16 @@ function warnDroppedImages(droppedImageCount) {
|
|
|
678
678
|
if (droppedImageCount <= 0) return;
|
|
679
679
|
console.warn(`[qgrid] ${droppedImageCount} image message part(s) were ignored because providerOptions.qgrid.imageGeneration is not enabled.`);
|
|
680
680
|
}
|
|
681
|
+
function serializeObjectResponseFormat(responseFormat) {
|
|
682
|
+
const rawSchema = responseFormat?.type === "json" ? responseFormat.schema : void 0;
|
|
683
|
+
if (rawSchema === void 0) return void 0;
|
|
684
|
+
const schemaType = rawSchema.type;
|
|
685
|
+
if (schemaType !== "object") {
|
|
686
|
+
console.warn(`[qgrid] responseFormat.schema top-level type is "${schemaType ?? "unknown"}". ${TOP_LEVEL_SCHEMA_WARNING}`);
|
|
687
|
+
return;
|
|
688
|
+
}
|
|
689
|
+
return JSON.stringify(rawSchema);
|
|
690
|
+
}
|
|
681
691
|
function getThreadCoord(sessionKey) {
|
|
682
692
|
const entry = threadCoordStore.get(sessionKey);
|
|
683
693
|
if (!entry) return void 0;
|
|
@@ -782,15 +792,13 @@ function qgrid(modelId, config) {
|
|
|
782
792
|
const verbosity = qgridOptions.verbosity;
|
|
783
793
|
const reasoningSummary = qgridOptions.reasoningSummary;
|
|
784
794
|
const serviceTier = qgridOptions.serviceTier;
|
|
795
|
+
const timeoutMs = qgridOptions.timeoutMs;
|
|
785
796
|
const logger = qgridOptions.logger;
|
|
786
797
|
const imageGenerationOptions = qgridOptions.imageGenerationOptions;
|
|
787
798
|
if (imageGeneration) assertImageInputFitsJsonTransport(imageUrls);
|
|
788
799
|
const sessionKey = qgridOptions.sessionKey;
|
|
789
800
|
const reuseSessionKey = reusableSessionKey(modelId, sessionKey);
|
|
790
|
-
const
|
|
791
|
-
const schemaType = rawSchema ? rawSchema.type : void 0;
|
|
792
|
-
if (rawSchema && !hasTools && schemaType !== "object") console.warn(`[qgrid] responseFormat.schema top-level type is "${schemaType ?? "unknown"}". ${TOP_LEVEL_SCHEMA_WARNING}`);
|
|
793
|
-
const jsonSchema = !hasTools && rawSchema && schemaType === "object" ? JSON.stringify(rawSchema) : void 0;
|
|
801
|
+
const jsonSchema = serializeObjectResponseFormat(options.responseFormat);
|
|
794
802
|
let runContext;
|
|
795
803
|
let toolResultsPayload;
|
|
796
804
|
const matchedClientRun = matchClientRun(options.prompt);
|
|
@@ -812,6 +820,7 @@ function qgrid(modelId, config) {
|
|
|
812
820
|
...verbosity ? { verbosity } : {},
|
|
813
821
|
...reasoningSummary ? { reasoningSummary } : {},
|
|
814
822
|
...serviceTier ? { serviceTier } : {},
|
|
823
|
+
...timeoutMs !== void 0 ? { timeout: timeoutMs } : {},
|
|
815
824
|
...hasTools ? { tools: tools.map(toQgridTool) } : {},
|
|
816
825
|
...jsonSchema ? { jsonSchema } : {},
|
|
817
826
|
...history.length > 0 ? { history: JSON.stringify(history) } : {},
|
|
@@ -880,14 +889,14 @@ function qgrid(modelId, config) {
|
|
|
880
889
|
const verbosity = qgridOptions.verbosity;
|
|
881
890
|
const reasoningSummary = qgridOptions.reasoningSummary;
|
|
882
891
|
const serviceTier = qgridOptions.serviceTier;
|
|
892
|
+
const timeoutMs = qgridOptions.timeoutMs;
|
|
883
893
|
const logger = qgridOptions.logger;
|
|
884
894
|
if (qgridOptions.imageGeneration) throw new Error("qgrid: imageGeneration is not supported with streamText — use generateText instead.");
|
|
885
895
|
const { prompt, system, history, droppedImageCount } = extractPromptAndHistory(options.prompt, { includeImages: false });
|
|
886
896
|
warnDroppedImages(droppedImageCount);
|
|
887
897
|
const sessionKey = qgridOptions.sessionKey;
|
|
888
898
|
const reuseSessionKey = reusableSessionKey(modelId, sessionKey);
|
|
889
|
-
const
|
|
890
|
-
const jsonSchema = !hasTools && rawSchema && rawSchema.type === "object" ? JSON.stringify(rawSchema) : void 0;
|
|
899
|
+
const jsonSchema = serializeObjectResponseFormat(options.responseFormat);
|
|
891
900
|
let runContext;
|
|
892
901
|
let toolResultsPayload;
|
|
893
902
|
const matchedClientRun = matchClientRun(options.prompt);
|
|
@@ -908,6 +917,7 @@ function qgrid(modelId, config) {
|
|
|
908
917
|
...verbosity ? { verbosity } : {},
|
|
909
918
|
...reasoningSummary ? { reasoningSummary } : {},
|
|
910
919
|
...serviceTier ? { serviceTier } : {},
|
|
920
|
+
...timeoutMs !== void 0 ? { timeout: timeoutMs } : {},
|
|
911
921
|
...hasTools ? { tools: tools.map(toQgridTool) } : {},
|
|
912
922
|
...jsonSchema ? { jsonSchema } : {},
|
|
913
923
|
...history.length > 0 ? { history: JSON.stringify(history) } : {},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cartanova/qgrid-ai-sdk",
|
|
3
|
-
"version": "2.5.
|
|
3
|
+
"version": "2.5.4",
|
|
4
4
|
"description": "AI SDK LanguageModelV3 provider for qgrid",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -24,7 +24,8 @@
|
|
|
24
24
|
"ai": "^6.0.190",
|
|
25
25
|
"tsdown": "^0.22.3",
|
|
26
26
|
"typescript": "^5.9.3",
|
|
27
|
-
"vitest": "^4.1.10"
|
|
27
|
+
"vitest": "^4.1.10",
|
|
28
|
+
"zod": "4.4.3"
|
|
28
29
|
},
|
|
29
30
|
"peerDependencies": {
|
|
30
31
|
"@ai-sdk/provider": "^3.0.0",
|
|
@@ -34,6 +35,7 @@
|
|
|
34
35
|
"build": "tsdown",
|
|
35
36
|
"test": "vitest run",
|
|
36
37
|
"e2e": "tsx e2e/e2e.ts",
|
|
38
|
+
"e2e:tools-output": "tsx e2e/tools-structured-output.ts",
|
|
37
39
|
"e2e:logger": "tsx e2e/e2e-logger.ts"
|
|
38
40
|
}
|
|
39
41
|
}
|