@cartanova/qgrid-cli 2.4.0 → 2.4.2

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 (40) hide show
  1. package/bundle/dist/application/qgrid/conv-routing.js +21 -1
  2. package/bundle/dist/application/qgrid/qgrid-response-format.js +50 -3
  3. package/bundle/dist/application/qgrid/qgrid-run-lifecycle.js +3 -14
  4. package/bundle/dist/application/qgrid/qgrid.frame.js +3 -14
  5. package/bundle/dist/application/qgrid/qgrid.types.js +11 -2
  6. package/bundle/dist/application/sonamu.generated.js +11 -3
  7. package/bundle/dist/application/sonamu.generated.sso.js +9 -2
  8. package/bundle/src/application/qgrid/conv-routing.test.ts +31 -0
  9. package/bundle/src/application/qgrid/conv-routing.ts +13 -0
  10. package/bundle/src/application/qgrid/qgrid-response-format.test.ts +77 -0
  11. package/bundle/src/application/qgrid/qgrid-response-format.ts +79 -6
  12. package/bundle/src/application/qgrid/qgrid-run-lifecycle.ts +11 -21
  13. package/bundle/src/application/qgrid/qgrid.frame.test.ts +36 -0
  14. package/bundle/src/application/qgrid/qgrid.frame.ts +14 -22
  15. package/bundle/src/application/qgrid/qgrid.types.ts +14 -0
  16. package/bundle/src/application/request-log-step/request-log-step.entity.json +2 -1
  17. package/bundle/src/application/sonamu.generated.http +18 -0
  18. package/bundle/src/application/sonamu.generated.sso.ts +7 -0
  19. package/bundle/src/application/sonamu.generated.ts +7 -1
  20. package/bundle/web-dist/client/assets/{index-DVdnvcvo.js → index-CN7eSKO4.js} +3 -3
  21. package/bundle/web-dist/client/assets/index-Dc-qeEPm.css +1 -0
  22. package/bundle/web-dist/client/assets/logs-NubdF_C_.js +1 -0
  23. package/bundle/web-dist/client/assets/{routes-CvCEcpZ7.js → routes-NKxXqHvs.js} +1 -1
  24. package/bundle/web-dist/client/assets/{show-DWRh--ML.js → show-BvDjIZCX.js} +3 -3
  25. package/bundle/web-dist/client/assets/{tokens-DOu_ZFUL.js → tokens-XAhJyLqj.js} +1 -1
  26. package/bundle/web-dist/client/index.html +2 -2
  27. package/bundle/web-dist/server/assets/{logs-B_ZLzpwY.js → logs-Bk9C0ELo.js} +1 -0
  28. package/bundle/web-dist/server/assets/{show-CGlX9OYt.js → show-3GokIDEJ.js} +94 -12
  29. package/bundle/web-dist/server/entry-server.generated.js +3 -3
  30. package/package.json +1 -1
  31. package/postinstall.mjs +14 -2
  32. package/skills/qgrid/references/ai-sdk-provider-contract.md +4 -0
  33. package/skills/qgrid/references/decision-rationale.md +2 -2
  34. package/skills/qgrid/references/openai-codex-runtime.md +2 -0
  35. package/skills/qgrid/references/request-log-run-lifecycle.md +2 -0
  36. package/skills/qgrid/references/sonamu-api-web-flow.md +2 -0
  37. package/skills/qgrid/references/tool-calling-and-multiturn.md +7 -5
  38. package/skills/qgrid/references/verification-and-debugging.md +4 -0
  39. package/bundle/web-dist/client/assets/index-VE_24EJf.css +0 -1
  40. package/bundle/web-dist/client/assets/logs-B82PGnxD.js +0 -1
@@ -2,21 +2,20 @@ import { getLogger } from "@logtape/logtape";
2
2
 
3
3
  import { RequestLogModel } from "../request-log/request-log.model";
4
4
  import {
5
- type QgridRunContext,
6
- type QgridToolResultInput,
7
- type QueryInput,
8
- type QueryOutput,
9
- } from "./qgrid.types";
5
+ estimateImageGenerationCostMicroUsd,
6
+ imageGenerationCostMethod,
7
+ } from "./qgrid-image-generation";
10
8
  import {
11
- formatImagePartForLog,
9
+ buildImageGenerationToolSteps,
12
10
  formatResponseForLog,
13
11
  getImageParts,
14
- imageGenerationToolArgs,
15
12
  } from "./qgrid-response-format";
16
13
  import {
17
- estimateImageGenerationCostMicroUsd,
18
- imageGenerationCostMethod,
19
- } from "./qgrid-image-generation";
14
+ type QgridRunContext,
15
+ type QgridToolResultInput,
16
+ type QueryInput,
17
+ type QueryOutput,
18
+ } from "./qgrid.types";
20
19
 
21
20
  const logger = getLogger(["qgrid", "run-lifecycle"]);
22
21
  const STALE_RUN_THRESHOLD_MS = 30 * 60 * 1000;
@@ -105,17 +104,8 @@ export async function afterQuery(
105
104
  result,
106
105
  args.imageGenerationOptions,
107
106
  );
108
- for (let i = 0; i < imageParts.length; i++) {
109
- const image = imageParts[i]!;
110
- await RequestLogModel.appendStep(requestLogId, {
111
- step_index: stepIndex,
112
- type: "tool_call",
113
- tool_call_index: i,
114
- tool_call_id: `image_generation:${stepIndex}:${i}`,
115
- tool_name: "image_generation",
116
- tool_args: imageGenerationToolArgs(args),
117
- tool_result: formatImagePartForLog(image),
118
- });
107
+ for (const step of buildImageGenerationToolSteps(args, imageParts, stepIndex)) {
108
+ await RequestLogModel.appendStep(requestLogId, step);
119
109
  }
120
110
 
121
111
  if (result.finishReason === "tool-calls") {
@@ -102,6 +102,7 @@ describe("QgridFrame.query auto logging", () => {
102
102
  beforeEach(() => {
103
103
  requestLogSaveMock.mockReset();
104
104
  requestLogSaveMock.mockResolvedValue([1]);
105
+ appendStepMock.mockReset();
105
106
  dispatcherQueryMock.mockReset();
106
107
  });
107
108
 
@@ -156,6 +157,10 @@ describe("QgridFrame.query auto logging", () => {
156
157
 
157
158
  await QgridFrame.query({
158
159
  prompt: "draw",
160
+ input: [
161
+ { type: "text", text: "draw", text_elements: [] },
162
+ { type: "image", url: "data:image/webp;base64,UklGRg==" },
163
+ ],
159
164
  model: "openai/gpt-5-codex",
160
165
  logMode: "auto",
161
166
  imageGeneration: true,
@@ -181,6 +186,7 @@ describe("QgridFrame.query auto logging", () => {
181
186
  tool_name: "image_generation",
182
187
  tool_args: JSON.stringify({
183
188
  prompt: "draw",
189
+ inputImages: [{ mediaType: "image/webp", data: "UklGRg==", byteSize: 4 }],
184
190
  driverModel: "openai/gpt-5-codex",
185
191
  tool: {
186
192
  type: "image_generation",
@@ -196,6 +202,36 @@ describe("QgridFrame.query auto logging", () => {
196
202
  }),
197
203
  );
198
204
  });
205
+
206
+ it("stores input images only on the first image-generation tool step", async () => {
207
+ dispatcherQueryMock.mockResolvedValueOnce({
208
+ ...queryOutput(39),
209
+ text: "images ready",
210
+ content: [
211
+ { type: "image", data: "first", revisedPrompt: "first image" },
212
+ { type: "image", data: "second", revisedPrompt: "second image" },
213
+ ],
214
+ });
215
+
216
+ await QgridFrame.query({
217
+ prompt: "draw two",
218
+ input: [
219
+ { type: "text", text: "draw two", text_elements: [] },
220
+ { type: "image", url: "data:image/webp;base64,UklGRg==" },
221
+ ],
222
+ model: "openai/gpt-5-codex",
223
+ logMode: "auto",
224
+ imageGeneration: true,
225
+ });
226
+
227
+ const firstToolArgs = JSON.parse(appendStepMock.mock.calls[0]![1].tool_args);
228
+ const secondToolArgs = JSON.parse(appendStepMock.mock.calls[1]![1].tool_args);
229
+
230
+ expect(firstToolArgs.inputImages).toEqual([
231
+ { mediaType: "image/webp", data: "UklGRg==", byteSize: 4 },
232
+ ]);
233
+ expect(secondToolArgs.inputImages).toBeUndefined();
234
+ });
199
235
  });
200
236
 
201
237
  describe("QgridFrame.prepareStream", () => {
@@ -28,21 +28,20 @@ import {
28
28
  refreshAccessToken,
29
29
  } from "./oauth";
30
30
  import {
31
- afterQuery,
32
- beforeQuery,
33
- finishRunAborted,
34
- finishRunWithError,
35
- } from "./qgrid-run-lifecycle";
31
+ estimateImageGenerationCostMicroUsd,
32
+ imageGenerationCostMethod,
33
+ } from "./qgrid-image-generation";
36
34
  import {
37
- formatImagePartForLog,
35
+ buildImageGenerationToolSteps,
38
36
  formatResponseForLog,
39
37
  getImageParts,
40
- imageGenerationToolArgs,
41
38
  } from "./qgrid-response-format";
42
39
  import {
43
- estimateImageGenerationCostMicroUsd,
44
- imageGenerationCostMethod,
45
- } from "./qgrid-image-generation";
40
+ afterQuery,
41
+ beforeQuery,
42
+ finishRunAborted,
43
+ finishRunWithError,
44
+ } from "./qgrid-run-lifecycle";
46
45
  import { QgridDispatcher } from "./qgrid.dispatcher";
47
46
  import {
48
47
  type QueryInput,
@@ -174,7 +173,9 @@ class QgridFrameClass extends BaseFrameClass {
174
173
  cost_usd: result.costUsd !== null ? Math.round(result.costUsd * MICRO_USD) : null,
175
174
  image_cost_usd: imageCostMicroUsd,
176
175
  image_cost_method:
177
- imageCostMicroUsd !== null ? imageGenerationCostMethod(args.imageGenerationOptions) : null,
176
+ imageCostMicroUsd !== null
177
+ ? imageGenerationCostMethod(args.imageGenerationOptions)
178
+ : null,
178
179
  effort: args.effort ?? null,
179
180
  // malformed history가 와도 성공한 턴(특히 stream sse.end())을 깨지 않도록 방어.
180
181
  history: ((): { type: string }[] | null => {
@@ -193,17 +194,8 @@ class QgridFrameClass extends BaseFrameClass {
193
194
  .then(async (ids) => {
194
195
  const requestLogId = ids[0];
195
196
  if (!requestLogId || imageParts.length === 0) return;
196
- for (let i = 0; i < imageParts.length; i++) {
197
- const image = imageParts[i]!;
198
- await RequestLogModel.appendStep(requestLogId, {
199
- step_index: 0,
200
- type: "tool_call",
201
- tool_call_index: i,
202
- tool_call_id: `image_generation:0:${i}`,
203
- tool_name: "image_generation",
204
- tool_args: imageGenerationToolArgs(args),
205
- tool_result: formatImagePartForLog(image),
206
- });
197
+ for (const step of buildImageGenerationToolSteps(args, imageParts, 0)) {
198
+ await RequestLogModel.appendStep(requestLogId, step);
207
199
  }
208
200
  })
209
201
  .catch((e) => logger.error(`requestLog save failed: ${(e as Error).message}`));
@@ -56,6 +56,19 @@ export const ImageGenerationOptions = z.object({
56
56
  });
57
57
  export type ImageGenerationOptions = z.infer<typeof ImageGenerationOptions>;
58
58
 
59
+ export const QgridInputPart = z.discriminatedUnion("type", [
60
+ z.object({
61
+ type: z.literal("text"),
62
+ text: z.string(),
63
+ text_elements: z.array(z.never()).default([]),
64
+ }),
65
+ z.object({
66
+ type: z.literal("image"),
67
+ url: z.string(),
68
+ }),
69
+ ]);
70
+ export type QgridInputPart = z.infer<typeof QgridInputPart>;
71
+
59
72
  // ─── Run Lifecycle Context (SDK ↔ Server contract) ───
60
73
 
61
74
  export const QgridLogMode = z.enum(["auto", "run", "none"]);
@@ -90,6 +103,7 @@ export type QgridToolResultInput = z.infer<typeof QgridToolResultInput>;
90
103
  export const QueryInput = z.object({
91
104
  system: z.string().optional(),
92
105
  prompt: z.string(),
106
+ input: z.array(QgridInputPart).optional(),
93
107
  model: z.string().optional(),
94
108
  timeout: z.number().optional(),
95
109
  jsonSchema: z.string().optional(),
@@ -130,7 +130,8 @@
130
130
  "tool_name",
131
131
  "tool_duration_ms",
132
132
  "error"
133
- ]
133
+ ],
134
+ "I": ["id", "tool_args"]
134
135
  },
135
136
  "enums": {
136
137
  "RequestLogStepType": { "generate": "LLM 생성", "tool_call": "Tool 호출" },
@@ -214,6 +214,15 @@ Content-Type: application/json
214
214
  "args": {
215
215
  "system": "SYSTEM",
216
216
  "prompt": "PROMPT",
217
+ "input": [
218
+ {
219
+ "type": "text",
220
+ "text": "TEXT",
221
+ "text_elements": [
222
+ "unknown-never"
223
+ ]
224
+ }
225
+ ],
217
226
  "model": "MODEL",
218
227
  "timeout": 0,
219
228
  "jsonSchema": "JSONSCHEMA",
@@ -266,6 +275,15 @@ Content-Type: application/json
266
275
  "args": {
267
276
  "system": "SYSTEM",
268
277
  "prompt": "PROMPT",
278
+ "input": [
279
+ {
280
+ "type": "text",
281
+ "text": "TEXT",
282
+ "text_elements": [
283
+ "unknown-never"
284
+ ]
285
+ }
286
+ ],
269
287
  "model": "MODEL",
270
288
  "timeout": 0,
271
289
  "jsonSchema": "JSONSCHEMA",
@@ -120,12 +120,19 @@ export const requestLogStepSubsetQueries = {
120
120
  error: "request_log_steps.error",
121
121
  });
122
122
  },
123
+ I: (qbWrapper: PuriWrapper<DatabaseSchemaExtend>) => {
124
+ return qbWrapper.from("request_log_steps").select({
125
+ id: "request_log_steps.id",
126
+ tool_args: "request_log_steps.tool_args",
127
+ });
128
+ },
123
129
  };
124
130
 
125
131
  // LoaderQuery: RequestLogStep
126
132
  export const requestLogStepLoaderQueries = {
127
133
  A: [],
128
134
  T: [],
135
+ I: [],
129
136
  } as const satisfies PuriLoaderQueries<RequestLogStepSubsetKey>;
130
137
 
131
138
  // SubsetQuery: Token
@@ -349,11 +349,17 @@ export const RequestLogStepSubsetT = z.object({
349
349
  error: z.string().nullable(),
350
350
  });
351
351
  export type RequestLogStepSubsetT = z.infer<typeof RequestLogStepSubsetT>;
352
+ export const RequestLogStepSubsetI = z.object({
353
+ id: z.int(),
354
+ tool_args: z.string().nullable(),
355
+ });
356
+ export type RequestLogStepSubsetI = z.infer<typeof RequestLogStepSubsetI>;
352
357
  export type RequestLogStepSubsetMapping = {
353
358
  A: RequestLogStepSubsetA;
354
359
  T: RequestLogStepSubsetT;
360
+ I: RequestLogStepSubsetI;
355
361
  };
356
- export const RequestLogStepSubsetKey = z.enum(["A", "T"]);
362
+ export const RequestLogStepSubsetKey = z.enum(["A", "T", "I"]);
357
363
  export type RequestLogStepSubsetKey = z.infer<typeof RequestLogStepSubsetKey>;
358
364
 
359
365
  // Subsets: Token