@cartanova/qgrid-cli 2.9.1 → 2.9.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.
Files changed (49) hide show
  1. package/bundle/dist/application/qgrid/qgrid.frame.js +4 -3
  2. package/bundle/dist/application/qgrid/token-death.js +6 -22
  3. package/bundle/dist/application/qgrid/token-subscriber.js +2 -1
  4. package/bundle/dist/application/token/token.model.js +22 -17
  5. package/bundle/dist/startup-migrations.js +8 -5
  6. package/bundle/dist/utils/providers/anthropic/claude-session.js +3 -2
  7. package/bundle/dist/utils/providers/common/effort.js +51 -0
  8. package/bundle/dist/utils/providers/common/model-cost.js +29 -14
  9. package/bundle/dist/utils/providers/openai/openai-backend-protocol.js +1 -1
  10. package/bundle/dist/utils/providers/openai/openai-dispatcher.js +5 -3
  11. package/bundle/src/application/qgrid/qgrid.frame.test.ts +20 -0
  12. package/bundle/src/application/qgrid/qgrid.frame.ts +3 -2
  13. package/bundle/src/application/qgrid/token-death.test.ts +11 -10
  14. package/bundle/src/application/qgrid/token-death.ts +9 -21
  15. package/bundle/src/application/qgrid/token-subscriber.test.ts +5 -1
  16. package/bundle/src/application/qgrid/token-subscriber.ts +1 -0
  17. package/bundle/src/application/token/token.model.test.ts +24 -5
  18. package/bundle/src/application/token/token.model.ts +30 -23
  19. package/bundle/src/startup-migrations.test.ts +19 -15
  20. package/bundle/src/startup-migrations.ts +11 -3
  21. package/bundle/src/utils/providers/anthropic/anthropic-dispatcher.test.ts +1 -1
  22. package/bundle/src/utils/providers/anthropic/claude-session.test.ts +13 -0
  23. package/bundle/src/utils/providers/anthropic/claude-session.ts +3 -1
  24. package/bundle/src/utils/providers/common/effort.test.ts +61 -0
  25. package/bundle/src/utils/providers/common/effort.ts +53 -0
  26. package/bundle/src/utils/providers/common/model-cost.test.ts +25 -12
  27. package/bundle/src/utils/providers/common/model-cost.ts +43 -14
  28. package/bundle/src/utils/providers/openai/openai-backend-protocol.ts +3 -1
  29. package/bundle/src/utils/providers/openai/openai-dispatcher.test.ts +21 -0
  30. package/bundle/src/utils/providers/openai/openai-dispatcher.ts +5 -4
  31. package/bundle/web-dist/client/assets/{index-DiioTXCk.js → index-fogJvajr.js} +3 -3
  32. package/bundle/web-dist/client/assets/{logs-Cmh7iNUl.js → logs-CsY2cqvt.js} +1 -1
  33. package/bundle/web-dist/client/assets/{monit-BxqRbzYv.js → monit-ChgaLEcD.js} +1 -1
  34. package/bundle/web-dist/client/assets/{routes-DrNdqoD1.js → routes-BvyiTnOZ.js} +2 -2
  35. package/bundle/web-dist/client/assets/{settings-ROuRMHwU.js → settings-ZR2J9rWb.js} +1 -1
  36. package/bundle/web-dist/client/assets/{show-Ct97ts6E.js → show-CjwO4-So.js} +1 -1
  37. package/bundle/web-dist/client/assets/{tokens-Cw2eWi9I.js → tokens-Bx-hG1gm.js} +1 -1
  38. package/bundle/web-dist/client/assets/{use-oauth-login-flow-D4-P9yOJ.js → use-oauth-login-flow-Bqax_icS.js} +1 -1
  39. package/bundle/web-dist/client/index.html +1 -1
  40. package/bundle/web-dist/server/assets/{routes-CxMHXfdH.js → routes-B408iqh1.js} +29 -14
  41. package/bundle/web-dist/server/entry-server.generated.js +3 -2
  42. package/package.json +1 -1
  43. package/skills/qgrid/SKILL.md +1 -0
  44. package/skills/qgrid/references/ai-sdk-provider-contract.md +2 -2
  45. package/skills/qgrid/references/cli-env-and-server-boot.md +1 -0
  46. package/skills/qgrid/references/openai-codex-runtime.md +71 -0
  47. package/skills/qgrid/references/provider-runtime-differences.md +2 -0
  48. package/skills/qgrid/references/sonamu-api-web-flow.md +1 -1
  49. package/skills/qgrid/references/token-auth-quota-lifecycle.md +3 -2
@@ -10,6 +10,8 @@
10
10
  * @see https://platform.claude.com/docs/en/about-claude/pricing
11
11
  */
12
12
 
13
+ import { type OpenAIEffort } from "./effort";
14
+
13
15
  export interface ModelCosts {
14
16
  inputTokens: number;
15
17
  outputTokens: number;
@@ -32,7 +34,7 @@ export interface ModelCosts {
32
34
 
33
35
  // ── OpenAI ─────────────────────────────────────────────────────────
34
36
  //
35
- // 가격 출처: https://developers.openai.com/api/docs/models (2026-07-18 확인)
37
+ // Standard pricing verified 2026-09-07: https://developers.openai.com/api/docs/pricing
36
38
  // 신모델 출시마다 단가가 바뀌므로(5.2→5.4→5.5) 모델 추가 시 반드시 공식 페이지 재확인해야함
37
39
 
38
40
  // GPT-5.4에서 처음 도입된 long-context 할증 (5.2/5.3-codex는 해당 없음, 5.4-mini/nano는 공식 표에서 long-context 단가 없음)
@@ -45,31 +47,53 @@ const LONG_CONTEXT_272K: NonNullable<ModelCosts["longContext"]> = {
45
47
  outputMultiplier: 1.5,
46
48
  };
47
49
 
48
- const OPENAI_COSTS: Record<string, ModelCosts> = {
50
+ // OpenAI 모델 카탈로그. 단가와 함께 Codex 백엔드가 모델별로 받는 최대 reasoning effort 를 한 곳에 둔다.
51
+ // maxEffort 출처: ~/.codex/models_cache.json 의 supported_reasoning_levels (2026-09-07 확인).
52
+ // 미기재 모델은 xhigh 까지만 받는다.
53
+ type OpenAIModelSpec = ModelCosts & { maxEffort?: OpenAIEffort };
54
+
55
+ const OPENAI_COSTS: Record<string, OpenAIModelSpec> = {
56
+ // GPT-6 Astra: Standard API-equivalent pricing, verified 2026-09-07.
57
+ // Codex subscription catalog supports ultra; the public API lists only through max.
58
+ // @see https://developers.openai.com/api/docs/models/gpt-6-astra
59
+ // @see https://developers.openai.com/api/docs/pricing
60
+ "gpt-6-astra": {
61
+ maxEffort: "ultra",
62
+ inputTokens: 10,
63
+ outputTokens: 50,
64
+ cachedInputTokens: 1,
65
+ cacheCreationInputTokens: 12.5,
66
+ longContext: LONG_CONTEXT_272K,
67
+ },
49
68
  // GPT-5.6 Sol, Terra, Luna. cache write 단가는 외부 logger/manual usage 입력을 위해
50
69
  // 유지한다. 현재 OpenAI 응답 usage 에 cache write 토큰 필드가 없으면 비용은 0으로 계산된다.
51
70
  // @see https://developers.openai.com/api/docs/models/gpt-5.6-sol
52
71
  // @see https://developers.openai.com/api/docs/models/gpt-5.6-terra
53
72
  // @see https://developers.openai.com/api/docs/models/gpt-5.6-luna
73
+ // Sol promotional rates are available at least through 2026-11-21.
74
+ // No confirmed end date/replacement rate: recheck official pricing instead of auto-reverting.
54
75
  "gpt-5.6-sol": {
55
- inputTokens: 5,
56
- outputTokens: 30,
57
- cachedInputTokens: 0.5,
58
- cacheCreationInputTokens: 6.25,
76
+ maxEffort: "ultra",
77
+ inputTokens: 4,
78
+ outputTokens: 20,
79
+ cachedInputTokens: 0.4,
80
+ cacheCreationInputTokens: 5,
59
81
  longContext: LONG_CONTEXT_272K,
60
82
  },
61
83
  "gpt-5.6-terra": {
62
- inputTokens: 2.5,
63
- outputTokens: 15,
64
- cachedInputTokens: 0.25,
65
- cacheCreationInputTokens: 3.125,
84
+ maxEffort: "ultra",
85
+ inputTokens: 2,
86
+ outputTokens: 12,
87
+ cachedInputTokens: 0.2,
88
+ cacheCreationInputTokens: 2.5,
66
89
  longContext: LONG_CONTEXT_272K,
67
90
  },
68
91
  "gpt-5.6-luna": {
69
- inputTokens: 1,
70
- outputTokens: 6,
71
- cachedInputTokens: 0.1,
72
- cacheCreationInputTokens: 1.25,
92
+ maxEffort: "max",
93
+ inputTokens: 0.2,
94
+ outputTokens: 1.2,
95
+ cachedInputTokens: 0.02,
96
+ cacheCreationInputTokens: 0.25,
73
97
  longContext: LONG_CONTEXT_272K,
74
98
  },
75
99
  // https://openai.com/index/introducing-gpt-5-5/ (2026-04 출시)
@@ -148,6 +172,11 @@ const ANTHROPIC_COSTS: Record<string, ModelCosts> = {
148
172
  // @see https://help.openai.com/en/articles/20001106-codex-rate-card
149
173
  const DEFAULT_COSTS: ModelCosts = { inputTokens: 3, outputTokens: 15, cachedInputTokens: 0.3 };
150
174
 
175
+ /** Codex 백엔드가 이 모델에 허용하는 최대 effort. 카탈로그에 없는 모델은 xhigh 까지다. */
176
+ export function openaiModelMaxEffort(model: string): OpenAIEffort {
177
+ return OPENAI_COSTS[model]?.maxEffort ?? "xhigh";
178
+ }
179
+
151
180
  export function getModelCosts(model: string): ModelCosts {
152
181
  const normalizedModel = (model.split("/").pop() ?? model).replace(/\[1m\]$/i, "");
153
182
  return OPENAI_COSTS[normalizedModel] ?? ANTHROPIC_COSTS[normalizedModel] ?? DEFAULT_COSTS;
@@ -1,5 +1,7 @@
1
1
  import os from "node:os";
2
2
 
3
+ import { type OpenAIEffort } from "../common/effort";
4
+
3
5
  export const CHATGPT_CODEX_RESPONSES_URL =
4
6
  "https://chatgpt.com/backend-api/codex/responses" as const;
5
7
 
@@ -58,7 +60,7 @@ export interface OpenAIResponsesOptions {
58
60
  toolChoice?: string | OpenAIResponseItem;
59
61
  parallelToolCalls?: boolean;
60
62
  reasoning?: {
61
- effort?: "none" | "minimal" | "low" | "medium" | "high" | "xhigh";
63
+ effort?: OpenAIEffort;
62
64
  summary?: "auto" | "concise" | "detailed";
63
65
  };
64
66
  verbosity?: "low" | "medium" | "high";
@@ -416,3 +416,24 @@ describe("OpenAIDispatcher direct runtime", () => {
416
416
  await expect(blocked.generate(request())).rejects.toThrow("NO_OPENAI_WORKERS");
417
417
  });
418
418
  });
419
+
420
+ describe("effort 어휘 해석 (Codex 카탈로그 기준)", () => {
421
+ async function mappedEffortFor(model: string, effort: string): Promise<unknown> {
422
+ let mapped: OpenAIResponsesOptions | undefined;
423
+ const d = dispatcher((options) => {
424
+ mapped = options;
425
+ return events({ type: "completed", responseId: "r1" });
426
+ });
427
+ await d.onTokenAdded(7, "primary", credentials, null, 1);
428
+ await d.generate(request({ model, effort }));
429
+ return mapped?.reasoning?.effort;
430
+ }
431
+
432
+ it("모델이 지원하는 값은 그대로 보내고, 상한 초과·공개 API 어휘는 reasoning 에서 빼 백엔드 기본값을 쓴다", async () => {
433
+ await expect(mappedEffortFor("gpt-6-astra", "ultra")).resolves.toBe("ultra");
434
+ await expect(mappedEffortFor("gpt-5.6-terra", "ultra")).resolves.toBe("ultra");
435
+ await expect(mappedEffortFor("gpt-5.5", "xhigh")).resolves.toBe("xhigh");
436
+ await expect(mappedEffortFor("gpt-5.5", "max")).resolves.toBeUndefined();
437
+ await expect(mappedEffortFor("gpt-5.6-terra", "minimal")).resolves.toBeUndefined();
438
+ });
439
+ });
@@ -3,6 +3,7 @@ import { getLogger } from "@logtape/logtape";
3
3
  import { QuotaThresholdExceededError } from "../../../application/qgrid/qgrid.types";
4
4
  import { TokenModel } from "../../../application/token/token.model";
5
5
  import { type OpenAICredentials } from "../../../application/token/token.types";
6
+ import { resolveOpenAIEffort } from "../common/effort";
6
7
  import {
7
8
  type GenerateRequest,
8
9
  type GenerateResult,
@@ -97,11 +98,11 @@ function inputItems(req: GenerateRequest): OpenAIResponseItem[] {
97
98
  function asReasoning(req: GenerateRequest): OpenAIResponsesOptions["reasoning"] | undefined {
98
99
  const summary =
99
100
  req.reasoningSummary && req.reasoningSummary !== "none" ? req.reasoningSummary : undefined;
100
- if (!req.effort && !summary) return undefined;
101
+ // Codex 어휘·모델 상한 밖의 effort 는 여기서 조용히 버린다(백엔드 기본값 적용).
102
+ const effort = resolveOpenAIEffort(req.model ?? "", req.effort);
103
+ if (!effort && !summary) return undefined;
101
104
  return {
102
- ...(req.effort
103
- ? { effort: req.effort as NonNullable<OpenAIResponsesOptions["reasoning"]>["effort"] }
104
- : {}),
105
+ ...(effort ? { effort } : {}),
105
106
  ...(summary
106
107
  ? {
107
108
  summary: summary as NonNullable<OpenAIResponsesOptions["reasoning"]>["summary"],