@cartanova/qgrid-cli 2.5.2 → 2.5.3
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/bundle/dist/application/qgrid/qgrid.dispatcher.js +6 -2
- package/bundle/dist/application/qgrid/qgrid.frame.js +56 -24
- package/bundle/dist/application/qgrid/qgrid.types.js +5 -3
- package/bundle/dist/utils/providers/anthropic/anthropic-dispatcher.js +2 -2
- package/bundle/dist/utils/providers/anthropic/stream-json-adapter.js +6 -4
- package/bundle/src/application/qgrid/qgrid.dispatcher.test.ts +21 -1
- package/bundle/src/application/qgrid/qgrid.dispatcher.ts +5 -3
- package/bundle/src/application/qgrid/qgrid.frame.test.ts +49 -0
- package/bundle/src/application/qgrid/qgrid.frame.ts +79 -26
- package/bundle/src/application/qgrid/qgrid.types.ts +4 -1
- package/bundle/src/utils/providers/anthropic/anthropic-dispatcher.test.ts +12 -0
- package/bundle/src/utils/providers/anthropic/anthropic-dispatcher.ts +1 -1
- package/bundle/src/utils/providers/anthropic/stream-json-adapter.test.ts +66 -0
- package/bundle/src/utils/providers/anthropic/stream-json-adapter.ts +12 -3
- package/bundle/src/utils/providers/common/provider-dispatcher.ts +2 -0
- package/bundle/web-dist/client/assets/{index-BQuKeBC5.js → index-DXdGBfB8.js} +3 -3
- package/bundle/web-dist/client/assets/{logs-BSsHMIKT.js → logs-D_j1yxC4.js} +1 -1
- package/bundle/web-dist/client/assets/{monit-D5ypGmGi.js → monit-CIToyoxW.js} +1 -1
- package/bundle/web-dist/client/assets/{routes-BsCbz225.js → routes-Dd21A-wi.js} +1 -1
- package/bundle/web-dist/client/assets/{show-CXPhLZCl.js → show-DfePWRbc.js} +1 -1
- package/bundle/web-dist/client/assets/{tokens-gEGH52O8.js → tokens-B4MV2fdk.js} +1 -1
- package/bundle/web-dist/client/index.html +1 -1
- package/bundle/web-dist/server/entry-server.generated.js +1 -1
- package/package.json +1 -1
- package/skills/qgrid/references/ai-sdk-provider-contract.md +8 -0
- package/skills/qgrid/references/anthropic-claude-code-runtime.md +28 -1
- package/skills/qgrid/references/decision-rationale.md +1 -0
|
@@ -175,6 +175,18 @@ describe("AnthropicDispatcher", () => {
|
|
|
175
175
|
expect(call.jsonSchema).toBe(JSON.stringify({ type: "object", properties: {} }));
|
|
176
176
|
});
|
|
177
177
|
|
|
178
|
+
it("요청 timeoutMs를 Claude session에 전달하고 미지정 시 240초 기본값을 쓴다", async () => {
|
|
179
|
+
const d = new AnthropicDispatcher();
|
|
180
|
+
d.onTokenAdded(1, "tok-A", creds(), null, 1);
|
|
181
|
+
|
|
182
|
+
await d.generate(baseReq({ timeoutMs: 360_000 }));
|
|
183
|
+
expect(firstRunRequest().timeoutMs).toBe(360_000);
|
|
184
|
+
|
|
185
|
+
runClaudeSessionMock.mockClear();
|
|
186
|
+
await d.generate(baseReq());
|
|
187
|
+
expect(firstRunRequest().timeoutMs).toBe(240_000);
|
|
188
|
+
});
|
|
189
|
+
|
|
178
190
|
it("quota 소진 → 에러", async () => {
|
|
179
191
|
const d = new AnthropicDispatcher();
|
|
180
192
|
d.onTokenAdded(1, "tok-A", creds(), null, 1);
|
|
@@ -326,7 +326,7 @@ export class AnthropicDispatcher implements ProviderDispatcher {
|
|
|
326
326
|
system: req.systemPrompt,
|
|
327
327
|
jsonSchema,
|
|
328
328
|
effort: req.effort,
|
|
329
|
-
timeoutMs: DEFAULT_TIMEOUT_MS,
|
|
329
|
+
timeoutMs: req.timeoutMs ?? DEFAULT_TIMEOUT_MS,
|
|
330
330
|
coldHistory: req.coldHistory,
|
|
331
331
|
input: req.coldInput,
|
|
332
332
|
abortSignal: req.abortSignal,
|
|
@@ -265,6 +265,72 @@ describe("handleStreamJsonLine (출력 어댑터)", () => {
|
|
|
265
265
|
expect(result!.costUsd).toBe(0.0042);
|
|
266
266
|
});
|
|
267
267
|
|
|
268
|
+
it("structured retry 성공: 첫 거절 입력이 아니라 최종 structured_output을 반환", () => {
|
|
269
|
+
const rejected = {
|
|
270
|
+
l2: "en",
|
|
271
|
+
line_id: "s1_l1",
|
|
272
|
+
speaker: "Minjae",
|
|
273
|
+
title: "첫 시도",
|
|
274
|
+
scenes: [],
|
|
275
|
+
};
|
|
276
|
+
const accepted = {
|
|
277
|
+
title: "두 번째 시도",
|
|
278
|
+
opening_line: "스키마를 만족한 최종 응답",
|
|
279
|
+
scenes: [],
|
|
280
|
+
};
|
|
281
|
+
const { result } = runLines(
|
|
282
|
+
[
|
|
283
|
+
JSON.stringify({
|
|
284
|
+
type: "assistant",
|
|
285
|
+
message: {
|
|
286
|
+
content: [{ type: "tool_use", name: "StructuredOutput", input: rejected }],
|
|
287
|
+
},
|
|
288
|
+
}),
|
|
289
|
+
JSON.stringify({
|
|
290
|
+
type: "user",
|
|
291
|
+
message: {
|
|
292
|
+
content: [
|
|
293
|
+
{
|
|
294
|
+
type: "tool_result",
|
|
295
|
+
is_error: true,
|
|
296
|
+
content: "Output does not match required schema",
|
|
297
|
+
},
|
|
298
|
+
],
|
|
299
|
+
},
|
|
300
|
+
}),
|
|
301
|
+
JSON.stringify({
|
|
302
|
+
type: "assistant",
|
|
303
|
+
message: {
|
|
304
|
+
content: [{ type: "tool_use", name: "StructuredOutput", input: accepted }],
|
|
305
|
+
},
|
|
306
|
+
}),
|
|
307
|
+
JSON.stringify({
|
|
308
|
+
type: "user",
|
|
309
|
+
message: {
|
|
310
|
+
content: [
|
|
311
|
+
{
|
|
312
|
+
type: "tool_result",
|
|
313
|
+
content: "Structured output provided successfully",
|
|
314
|
+
},
|
|
315
|
+
],
|
|
316
|
+
},
|
|
317
|
+
}),
|
|
318
|
+
JSON.stringify({
|
|
319
|
+
type: "result",
|
|
320
|
+
subtype: "success",
|
|
321
|
+
is_error: false,
|
|
322
|
+
structured_output: accepted,
|
|
323
|
+
usage: { input_tokens: 10, output_tokens: 20 },
|
|
324
|
+
}),
|
|
325
|
+
],
|
|
326
|
+
{ structuredOutput: true },
|
|
327
|
+
);
|
|
328
|
+
|
|
329
|
+
expect(JSON.parse(result!.text)).toEqual(accepted);
|
|
330
|
+
expect(result!.isError).toBe(false);
|
|
331
|
+
expect(result!.subtype).toBe("success");
|
|
332
|
+
});
|
|
333
|
+
|
|
268
334
|
// SON-495: error_max_structured_output_retries 는 모델이 schema 를 못 맞춘 비정상 종료다.
|
|
269
335
|
// CC structured output 은 constrained decoding 이 아니라 사후 AJV 검증이라, 모델이 가끔
|
|
270
336
|
// placeholder($PARAMETER_NAME)·거부("just kidding")·필드 누락 같은 발작/불완전 출력을 낸다.
|
|
@@ -406,9 +406,20 @@ export function handleStreamJsonLine(
|
|
|
406
406
|
}
|
|
407
407
|
|
|
408
408
|
if (j.type === "result") {
|
|
409
|
+
const subtype = typeof j.subtype === "string" ? j.subtype : undefined;
|
|
410
|
+
const terminalReason = typeof j.terminal_reason === "string" ? j.terminal_reason : undefined;
|
|
411
|
+
const resultSucceeded =
|
|
412
|
+
j.is_error !== true &&
|
|
413
|
+
terminalReason !== "model_error" &&
|
|
414
|
+
(subtype === undefined || subtype === "success");
|
|
409
415
|
let text: string;
|
|
410
416
|
const preservedStructuredOutput = structuredOutput ? state?.structuredOutputText : undefined;
|
|
411
|
-
|
|
417
|
+
// Claude Code는 StructuredOutput 스키마 검증 실패 후 내부 재시도를 할 수 있다. assistant
|
|
418
|
+
// 이벤트의 첫 tool input은 거절된 시도일 수 있으므로, 성공 result가 제공한 최종 검증값을
|
|
419
|
+
// 우선한다. 첫 입력 보존값은 max_turns/retry 초과처럼 성공 result가 없는 진단 경로용이다.
|
|
420
|
+
if (structuredOutput && resultSucceeded && j.structured_output !== undefined) {
|
|
421
|
+
text = JSON.stringify(j.structured_output);
|
|
422
|
+
} else if (preservedStructuredOutput !== undefined) {
|
|
412
423
|
text = preservedStructuredOutput;
|
|
413
424
|
} else if (j.structured_output !== undefined) {
|
|
414
425
|
text = JSON.stringify(j.structured_output);
|
|
@@ -429,8 +440,6 @@ export function handleStreamJsonLine(
|
|
|
429
440
|
}
|
|
430
441
|
const usage = toUsageBreakdown(rawUsage as ClaudeUsage);
|
|
431
442
|
const quotaExhausted = text.startsWith("You've hit");
|
|
432
|
-
const subtype = typeof j.subtype === "string" ? j.subtype : undefined;
|
|
433
|
-
const terminalReason = typeof j.terminal_reason === "string" ? j.terminal_reason : undefined;
|
|
434
443
|
|
|
435
444
|
// SON-495: 비정상 종료(error_max_structured_output_retries 등)는 정직하게 에러로 처리한다.
|
|
436
445
|
// CC structured output 은 constrained decoding 이 아니라 "tool input 생성 후 사후 AJV 검증"이라
|
|
@@ -55,6 +55,8 @@ export interface GenerateRequest {
|
|
|
55
55
|
verbosity?: string;
|
|
56
56
|
reasoningSummary?: string;
|
|
57
57
|
serviceTier?: string;
|
|
58
|
+
// provider 실행 제한(ms). 현재 Anthropic Claude session 타이머가 사용한다.
|
|
59
|
+
timeoutMs?: number;
|
|
58
60
|
abortSignal?: AbortSignal;
|
|
59
61
|
// 첫 turn / 재사용 폴백 시 보낼 input — 전체 prompt. 항상 설정.
|
|
60
62
|
coldInput: Array<UserInput>;
|