@cartanova/qgrid-cli 2.3.9 → 2.4.1
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 +2 -2
- package/README.md +2 -2
- package/bundle/dist/application/qgrid/conv-routing.js +21 -1
- package/bundle/dist/application/qgrid/qgrid-response-format.js +50 -3
- package/bundle/dist/application/qgrid/qgrid-run-lifecycle.js +3 -14
- package/bundle/dist/application/qgrid/qgrid.frame.js +3 -14
- package/bundle/dist/application/qgrid/qgrid.types.js +11 -2
- package/bundle/dist/application/sonamu.generated.js +11 -3
- package/bundle/dist/application/sonamu.generated.sso.js +9 -2
- package/bundle/src/application/qgrid/conv-routing.test.ts +31 -0
- package/bundle/src/application/qgrid/conv-routing.ts +13 -0
- package/bundle/src/application/qgrid/qgrid-response-format.test.ts +77 -0
- package/bundle/src/application/qgrid/qgrid-response-format.ts +79 -6
- package/bundle/src/application/qgrid/qgrid-run-lifecycle.ts +11 -21
- package/bundle/src/application/qgrid/qgrid.frame.test.ts +36 -0
- package/bundle/src/application/qgrid/qgrid.frame.ts +14 -22
- package/bundle/src/application/qgrid/qgrid.types.ts +14 -0
- package/bundle/src/application/request-log-step/request-log-step.entity.json +2 -1
- package/bundle/src/application/sonamu.generated.http +18 -0
- package/bundle/src/application/sonamu.generated.sso.ts +7 -0
- package/bundle/src/application/sonamu.generated.ts +7 -1
- package/bundle/web-dist/client/assets/{index-Cj1iWi5i.js → index-CHRDevod.js} +3 -3
- package/bundle/web-dist/client/assets/index-Dc-qeEPm.css +1 -0
- package/bundle/web-dist/client/assets/logs-CFw7oJgw.js +1 -0
- package/bundle/web-dist/client/assets/{routes-B_xvkM-J.js → routes-vhw9Wsg6.js} +1 -1
- package/bundle/web-dist/client/assets/{show-C6W3ywZz.js → show-CKIx8CD_.js} +3 -3
- package/bundle/web-dist/client/assets/{tokens-CxjeN72g.js → tokens-Di4RowSm.js} +1 -1
- package/bundle/web-dist/client/index.html +2 -2
- package/bundle/web-dist/server/assets/{logs-B_ZLzpwY.js → logs-Bk9C0ELo.js} +1 -0
- package/bundle/web-dist/server/assets/{show-CGlX9OYt.js → show-3GokIDEJ.js} +94 -12
- package/bundle/web-dist/server/entry-server.generated.js +3 -3
- package/dist/cli.js +86 -5
- package/package.json +1 -1
- package/postinstall.mjs +14 -2
- package/skills/qgrid/references/ai-sdk-provider-contract.md +4 -0
- package/skills/qgrid/references/cli-env-and-server-boot.md +2 -0
- package/skills/qgrid/references/decision-rationale.md +2 -2
- package/skills/qgrid/references/openai-codex-runtime.md +2 -0
- package/skills/qgrid/references/request-log-run-lifecycle.md +2 -0
- package/skills/qgrid/references/sonamu-api-web-flow.md +2 -0
- package/skills/qgrid/references/verification-and-debugging.md +4 -0
- package/bundle/web-dist/client/assets/index-VE_24EJf.css +0 -1
- package/bundle/web-dist/client/assets/logs-DvGWhZTu.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
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
type QueryOutput,
|
|
9
|
-
} from "./qgrid.types";
|
|
5
|
+
estimateImageGenerationCostMicroUsd,
|
|
6
|
+
imageGenerationCostMethod,
|
|
7
|
+
} from "./qgrid-image-generation";
|
|
10
8
|
import {
|
|
11
|
-
|
|
9
|
+
buildImageGenerationToolSteps,
|
|
12
10
|
formatResponseForLog,
|
|
13
11
|
getImageParts,
|
|
14
|
-
imageGenerationToolArgs,
|
|
15
12
|
} from "./qgrid-response-format";
|
|
16
13
|
import {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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 (
|
|
109
|
-
|
|
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
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
finishRunWithError,
|
|
35
|
-
} from "./qgrid-run-lifecycle";
|
|
31
|
+
estimateImageGenerationCostMicroUsd,
|
|
32
|
+
imageGenerationCostMethod,
|
|
33
|
+
} from "./qgrid-image-generation";
|
|
36
34
|
import {
|
|
37
|
-
|
|
35
|
+
buildImageGenerationToolSteps,
|
|
38
36
|
formatResponseForLog,
|
|
39
37
|
getImageParts,
|
|
40
|
-
imageGenerationToolArgs,
|
|
41
38
|
} from "./qgrid-response-format";
|
|
42
39
|
import {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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
|
|
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 (
|
|
197
|
-
|
|
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(),
|
|
@@ -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
|