@cartanova/qgrid-cli 2.4.7 → 2.4.8
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-run-lifecycle.js +15 -1
- package/bundle/dist/application/qgrid/qgrid.dispatcher.js +12 -4
- package/bundle/dist/application/qgrid/qgrid.frame.js +20 -1
- package/bundle/dist/application/qgrid/qgrid.types.js +38 -2
- package/bundle/dist/application/request-log/request-log.model.js +49 -22
- package/bundle/dist/application/request-log-step/request-log-step.types.js +8 -1
- package/bundle/dist/application/sonamu.generated.js +37 -1
- package/bundle/dist/application/sonamu.generated.sso.js +25 -1
- package/bundle/dist/i18n/sd.generated.js +13 -1
- package/bundle/dist/migrations/20260718180824_alter_request_logs_add5_alter1.js +20 -0
- package/bundle/dist/migrations/20260718180825_alter_request_log_steps_add7_alter1.js +22 -0
- package/bundle/dist/utils/providers/anthropic/anthropic-constants.js +8 -2
- package/bundle/dist/utils/providers/anthropic/anthropic-dispatcher.js +6 -3
- package/bundle/dist/utils/providers/anthropic/claude-session.js +11 -7
- package/bundle/dist/utils/providers/anthropic/stream-json-adapter.js +117 -7
- package/bundle/dist/utils/providers/common/model-cost.js +45 -98
- package/bundle/src/application/qgrid/qgrid-run-lifecycle.test.ts +68 -0
- package/bundle/src/application/qgrid/qgrid-run-lifecycle.ts +14 -0
- package/bundle/src/application/qgrid/qgrid.dispatcher.test.ts +81 -0
- package/bundle/src/application/qgrid/qgrid.dispatcher.ts +16 -9
- package/bundle/src/application/qgrid/qgrid.frame.ts +19 -0
- package/bundle/src/application/qgrid/qgrid.types.ts +36 -0
- package/bundle/src/application/qgrid/tool-emulation.test.ts +1 -0
- package/bundle/src/application/request-log/request-log.entity.json +42 -0
- package/bundle/src/application/request-log/request-log.model.test.ts +58 -0
- package/bundle/src/application/request-log/request-log.model.ts +107 -18
- package/bundle/src/application/request-log-step/request-log-step.entity.json +54 -0
- package/bundle/src/application/request-log-step/request-log-step.types.ts +7 -0
- package/bundle/src/application/sonamu.generated.http +26 -0
- package/bundle/src/application/sonamu.generated.sso.ts +24 -0
- package/bundle/src/application/sonamu.generated.ts +48 -0
- package/bundle/src/i18n/sd.generated.ts +12 -0
- package/bundle/src/migrations/20260718180824_alter_request_logs_add5_alter1.ts +25 -0
- package/bundle/src/migrations/20260718180825_alter_request_log_steps_add7_alter1.ts +29 -0
- package/bundle/src/utils/providers/anthropic/anthropic-constants.test.ts +15 -0
- package/bundle/src/utils/providers/anthropic/anthropic-constants.ts +11 -2
- package/bundle/src/utils/providers/anthropic/anthropic-dispatcher.ts +7 -2
- package/bundle/src/utils/providers/anthropic/claude-session.test.ts +26 -0
- package/bundle/src/utils/providers/anthropic/claude-session.ts +16 -4
- package/bundle/src/utils/providers/anthropic/stream-json-adapter.test.ts +131 -0
- package/bundle/src/utils/providers/anthropic/stream-json-adapter.ts +194 -11
- package/bundle/src/utils/providers/common/model-cost.test.ts +136 -2
- package/bundle/src/utils/providers/common/model-cost.ts +76 -99
- package/bundle/src/utils/providers/common/provider-dispatcher.ts +18 -0
- package/bundle/web-dist/client/assets/{index-CYnw2kNG.js → index-CmuPjbCl.js} +3 -3
- package/bundle/web-dist/client/assets/{logs-CnXIN-jp.js → logs-cXOsDli3.js} +1 -1
- package/bundle/web-dist/client/assets/{monit-DRuDGJj4.js → monit-B5Edhvy-.js} +1 -1
- package/bundle/web-dist/client/assets/{routes-CuyNd-ya.js → routes-UPWScORY.js} +1 -1
- package/bundle/web-dist/client/assets/{sd.generated-D2Y9QeiN.js → sd.generated-DYuKzBY6.js} +1 -1
- package/bundle/web-dist/client/assets/{services.generated-CmxXl220.js → services.generated-D_SkWOo-.js} +1 -1
- package/bundle/web-dist/client/assets/show-pRp-eZIK.js +30 -0
- package/bundle/web-dist/client/assets/{tokens-DxFeKC8Q.js → tokens-DJlttxCM.js} +1 -1
- package/bundle/web-dist/client/assets/{use-update-token-mutation-6J1T9U2-.js → use-update-token-mutation-CpFGLWUl.js} +1 -1
- package/bundle/web-dist/client/index.html +2 -2
- package/bundle/web-dist/server/assets/{lazyRouteComponent-BlfOh9S3.js → lazyRouteComponent-Cu6IkL8A.js} +1 -1
- package/bundle/web-dist/server/assets/{logs-DYly4ipQ.js → logs-Dx2knN2T.js} +10 -7
- package/bundle/web-dist/server/assets/{monit-CYyY2S2f.js → monit-DU6PLatf.js} +2 -2
- package/bundle/web-dist/server/assets/{routes-Dqu3osXt.js → routes-CTco1oJZ.js} +3 -3
- package/bundle/web-dist/server/assets/{sd.generated-CE6D5clm.js → sd.generated-qzuRe35X.js} +12 -0
- package/bundle/web-dist/server/assets/{services.generated-DyZUzXiq.js → services.generated-C8q1M41a.js} +1 -1
- package/bundle/web-dist/server/assets/{show-BDul8xLb.js → show-B3q8_GDh.js} +47 -4
- package/bundle/web-dist/server/assets/{tokens-fzMW4G74.js → tokens-Bvjn15h9.js} +3 -3
- package/bundle/web-dist/server/assets/{use-update-token-mutation-BejUW5sw.js → use-update-token-mutation-BlZo6swF.js} +1 -1
- package/bundle/web-dist/server/entry-server.generated.js +8 -8
- package/package.json +1 -1
- package/skills/qgrid/SKILL.md +4 -0
- package/skills/qgrid/references/ai-sdk-provider-contract.md +30 -2
- package/skills/qgrid/references/anthropic-claude-code-runtime.md +43 -5
- package/skills/qgrid/references/decision-rationale.md +2 -0
- package/skills/qgrid/references/prompt-cache-and-usage.md +4 -1
- package/skills/qgrid/references/request-log-run-lifecycle.md +6 -2
- package/skills/qgrid/references/sonamu-api-web-flow.md +13 -0
- package/bundle/web-dist/client/assets/show-EleAOzJv.js +0 -30
|
@@ -17,6 +17,26 @@
|
|
|
17
17
|
},
|
|
18
18
|
{ "name": "step_index", "type": "integer", "desc": "ai-sdk step number (0-based)" },
|
|
19
19
|
{ "name": "type", "type": "enum", "id": "RequestLogStepType", "desc": "step 타입" },
|
|
20
|
+
{
|
|
21
|
+
"name": "model_name",
|
|
22
|
+
"type": "string",
|
|
23
|
+
"length": 50,
|
|
24
|
+
"nullable": true,
|
|
25
|
+
"desc": "실제 serving 모델"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"name": "requested_model_name",
|
|
29
|
+
"type": "string",
|
|
30
|
+
"length": 50,
|
|
31
|
+
"nullable": true,
|
|
32
|
+
"desc": "요청 모델 (fallback 전)"
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"name": "fallback_count",
|
|
36
|
+
"type": "integer",
|
|
37
|
+
"nullable": true,
|
|
38
|
+
"desc": "모델 fallback 횟수"
|
|
39
|
+
},
|
|
20
40
|
{ "name": "input_tokens", "type": "integer", "nullable": true, "desc": "입력 토큰 (generate)" },
|
|
21
41
|
{
|
|
22
42
|
"name": "output_tokens",
|
|
@@ -31,6 +51,26 @@
|
|
|
31
51
|
"nullable": true,
|
|
32
52
|
"desc": "캐시 생성 토큰"
|
|
33
53
|
},
|
|
54
|
+
{
|
|
55
|
+
"name": "cache_creation_5m_tokens",
|
|
56
|
+
"type": "integer",
|
|
57
|
+
"nullable": true,
|
|
58
|
+
"desc": "5분 TTL 캐시 생성 토큰"
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"name": "cache_creation_1h_tokens",
|
|
62
|
+
"type": "integer",
|
|
63
|
+
"nullable": true,
|
|
64
|
+
"desc": "1시간 TTL 캐시 생성 토큰"
|
|
65
|
+
},
|
|
66
|
+
{ "name": "cost_usd", "type": "integer", "nullable": true, "desc": "step 비용 (micro-USD)" },
|
|
67
|
+
{
|
|
68
|
+
"name": "cost_source",
|
|
69
|
+
"type": "string",
|
|
70
|
+
"length": 20,
|
|
71
|
+
"nullable": true,
|
|
72
|
+
"desc": "비용 출처(provider/pricing_table)"
|
|
73
|
+
},
|
|
34
74
|
{ "name": "duration_ms", "type": "integer", "nullable": true, "desc": "소요시간(ms)" },
|
|
35
75
|
{ "name": "ttft_ms", "type": "integer", "nullable": true, "desc": "Gen TTFT(ms)" },
|
|
36
76
|
{
|
|
@@ -95,10 +135,17 @@
|
|
|
95
135
|
"created_at",
|
|
96
136
|
"step_index",
|
|
97
137
|
"type",
|
|
138
|
+
"model_name",
|
|
139
|
+
"requested_model_name",
|
|
140
|
+
"fallback_count",
|
|
98
141
|
"input_tokens",
|
|
99
142
|
"output_tokens",
|
|
100
143
|
"cache_read_tokens",
|
|
101
144
|
"cache_creation_tokens",
|
|
145
|
+
"cache_creation_5m_tokens",
|
|
146
|
+
"cache_creation_1h_tokens",
|
|
147
|
+
"cost_usd",
|
|
148
|
+
"cost_source",
|
|
102
149
|
"duration_ms",
|
|
103
150
|
"ttft_ms",
|
|
104
151
|
"finish_reason",
|
|
@@ -117,10 +164,17 @@
|
|
|
117
164
|
"created_at",
|
|
118
165
|
"step_index",
|
|
119
166
|
"type",
|
|
167
|
+
"model_name",
|
|
168
|
+
"requested_model_name",
|
|
169
|
+
"fallback_count",
|
|
120
170
|
"input_tokens",
|
|
121
171
|
"output_tokens",
|
|
122
172
|
"cache_read_tokens",
|
|
123
173
|
"cache_creation_tokens",
|
|
174
|
+
"cache_creation_5m_tokens",
|
|
175
|
+
"cache_creation_1h_tokens",
|
|
176
|
+
"cost_usd",
|
|
177
|
+
"cost_source",
|
|
124
178
|
"duration_ms",
|
|
125
179
|
"ttft_ms",
|
|
126
180
|
"finish_reason",
|
|
@@ -11,10 +11,17 @@ export const RequestLogStepSaveParams = RequestLogStepBaseSchema.partial({
|
|
|
11
11
|
id: true,
|
|
12
12
|
created_at: true,
|
|
13
13
|
request_log_id: true,
|
|
14
|
+
model_name: true,
|
|
15
|
+
requested_model_name: true,
|
|
16
|
+
fallback_count: true,
|
|
14
17
|
input_tokens: true,
|
|
15
18
|
output_tokens: true,
|
|
16
19
|
cache_read_tokens: true,
|
|
17
20
|
cache_creation_tokens: true,
|
|
21
|
+
cache_creation_5m_tokens: true,
|
|
22
|
+
cache_creation_1h_tokens: true,
|
|
23
|
+
cost_usd: true,
|
|
24
|
+
cost_source: true,
|
|
18
25
|
duration_ms: true,
|
|
19
26
|
finish_reason: true,
|
|
20
27
|
reasoning_text: true,
|
|
@@ -103,10 +103,17 @@ Content-Type: application/json
|
|
|
103
103
|
"request_log_id": 0,
|
|
104
104
|
"step_index": 0,
|
|
105
105
|
"type": "generate",
|
|
106
|
+
"model_name": null,
|
|
107
|
+
"requested_model_name": null,
|
|
108
|
+
"fallback_count": null,
|
|
106
109
|
"input_tokens": null,
|
|
107
110
|
"output_tokens": null,
|
|
108
111
|
"cache_read_tokens": null,
|
|
109
112
|
"cache_creation_tokens": null,
|
|
113
|
+
"cache_creation_5m_tokens": null,
|
|
114
|
+
"cache_creation_1h_tokens": null,
|
|
115
|
+
"cost_usd": null,
|
|
116
|
+
"cost_source": null,
|
|
110
117
|
"duration_ms": null,
|
|
111
118
|
"ttft_ms": null,
|
|
112
119
|
"finish_reason": null,
|
|
@@ -173,6 +180,8 @@ Content-Type: application/json
|
|
|
173
180
|
"token_name": null,
|
|
174
181
|
"project_name": null,
|
|
175
182
|
"model_name": null,
|
|
183
|
+
"requested_model_name": null,
|
|
184
|
+
"fallback_count": null,
|
|
176
185
|
"user_prompt": null,
|
|
177
186
|
"system_prompt": null,
|
|
178
187
|
"response": "RESPONSE",
|
|
@@ -180,9 +189,12 @@ Content-Type: application/json
|
|
|
180
189
|
"output_tokens": 0,
|
|
181
190
|
"cache_read_tokens": 0,
|
|
182
191
|
"cache_creation_tokens": 0,
|
|
192
|
+
"cache_creation_5m_tokens": null,
|
|
193
|
+
"cache_creation_1h_tokens": null,
|
|
183
194
|
"duration_ms": 0,
|
|
184
195
|
"ttft_ms": 0,
|
|
185
196
|
"cost_usd": null,
|
|
197
|
+
"cost_source": null,
|
|
186
198
|
"image_cost_usd": null,
|
|
187
199
|
"image_cost_method": null,
|
|
188
200
|
"effort": null,
|
|
@@ -360,10 +372,17 @@ Content-Type: application/json
|
|
|
360
372
|
"requestLogId": 0,
|
|
361
373
|
"stepIndex": 0,
|
|
362
374
|
"type": "generate",
|
|
375
|
+
"modelName": "MODELNAME",
|
|
376
|
+
"requestedModelName": "REQUESTEDMODELNAME",
|
|
377
|
+
"fallbackCount": 0,
|
|
363
378
|
"inputTokens": 0,
|
|
364
379
|
"outputTokens": 0,
|
|
365
380
|
"cacheReadTokens": 0,
|
|
366
381
|
"cacheCreationTokens": 0,
|
|
382
|
+
"cacheCreation5mTokens": 0,
|
|
383
|
+
"cacheCreation1hTokens": 0,
|
|
384
|
+
"costUsd": 0,
|
|
385
|
+
"costSource": "provider",
|
|
367
386
|
"durationMs": 0,
|
|
368
387
|
"ttftMs": null,
|
|
369
388
|
"finishReason": "FINISHREASON",
|
|
@@ -390,10 +409,17 @@ Content-Type: application/json
|
|
|
390
409
|
"status": "succeeded",
|
|
391
410
|
"response": "RESPONSE",
|
|
392
411
|
"tokenName": "TOKENNAME",
|
|
412
|
+
"modelName": "MODELNAME",
|
|
413
|
+
"requestedModelName": "REQUESTEDMODELNAME",
|
|
414
|
+
"fallbackCount": 0,
|
|
393
415
|
"totalInputTokens": 0,
|
|
394
416
|
"totalOutputTokens": 0,
|
|
395
417
|
"totalCacheReadTokens": 0,
|
|
396
418
|
"totalCacheCreationTokens": 0,
|
|
419
|
+
"totalCacheCreation5mTokens": 0,
|
|
420
|
+
"totalCacheCreation1hTokens": 0,
|
|
421
|
+
"costUsd": 0,
|
|
422
|
+
"costSource": "provider",
|
|
397
423
|
"totalDurationMs": 0,
|
|
398
424
|
"history": "HISTORY",
|
|
399
425
|
"errorMessage": "ERRORMESSAGE"
|
|
@@ -23,6 +23,8 @@ export const requestLogSubsetQueries = {
|
|
|
23
23
|
token_name: "request_logs.token_name",
|
|
24
24
|
project_name: "request_logs.project_name",
|
|
25
25
|
model_name: "request_logs.model_name",
|
|
26
|
+
requested_model_name: "request_logs.requested_model_name",
|
|
27
|
+
fallback_count: "request_logs.fallback_count",
|
|
26
28
|
user_prompt: "request_logs.user_prompt",
|
|
27
29
|
system_prompt: "request_logs.system_prompt",
|
|
28
30
|
response: "request_logs.response",
|
|
@@ -30,9 +32,12 @@ export const requestLogSubsetQueries = {
|
|
|
30
32
|
output_tokens: "request_logs.output_tokens",
|
|
31
33
|
cache_read_tokens: "request_logs.cache_read_tokens",
|
|
32
34
|
cache_creation_tokens: "request_logs.cache_creation_tokens",
|
|
35
|
+
cache_creation_5m_tokens: "request_logs.cache_creation_5m_tokens",
|
|
36
|
+
cache_creation_1h_tokens: "request_logs.cache_creation_1h_tokens",
|
|
33
37
|
duration_ms: "request_logs.duration_ms",
|
|
34
38
|
ttft_ms: "request_logs.ttft_ms",
|
|
35
39
|
cost_usd: "request_logs.cost_usd",
|
|
40
|
+
cost_source: "request_logs.cost_source",
|
|
36
41
|
image_cost_usd: "request_logs.image_cost_usd",
|
|
37
42
|
image_cost_method: "request_logs.image_cost_method",
|
|
38
43
|
effort: "request_logs.effort",
|
|
@@ -50,13 +55,18 @@ export const requestLogSubsetQueries = {
|
|
|
50
55
|
token_name: "request_logs.token_name",
|
|
51
56
|
project_name: "request_logs.project_name",
|
|
52
57
|
model_name: "request_logs.model_name",
|
|
58
|
+
requested_model_name: "request_logs.requested_model_name",
|
|
59
|
+
fallback_count: "request_logs.fallback_count",
|
|
53
60
|
input_tokens: "request_logs.input_tokens",
|
|
54
61
|
output_tokens: "request_logs.output_tokens",
|
|
55
62
|
cache_read_tokens: "request_logs.cache_read_tokens",
|
|
56
63
|
cache_creation_tokens: "request_logs.cache_creation_tokens",
|
|
64
|
+
cache_creation_5m_tokens: "request_logs.cache_creation_5m_tokens",
|
|
65
|
+
cache_creation_1h_tokens: "request_logs.cache_creation_1h_tokens",
|
|
57
66
|
duration_ms: "request_logs.duration_ms",
|
|
58
67
|
ttft_ms: "request_logs.ttft_ms",
|
|
59
68
|
cost_usd: "request_logs.cost_usd",
|
|
69
|
+
cost_source: "request_logs.cost_source",
|
|
60
70
|
image_cost_usd: "request_logs.image_cost_usd",
|
|
61
71
|
image_cost_method: "request_logs.image_cost_method",
|
|
62
72
|
effort: "request_logs.effort",
|
|
@@ -81,10 +91,17 @@ export const requestLogStepSubsetQueries = {
|
|
|
81
91
|
created_at: "request_log_steps.created_at",
|
|
82
92
|
step_index: "request_log_steps.step_index",
|
|
83
93
|
type: "request_log_steps.type",
|
|
94
|
+
model_name: "request_log_steps.model_name",
|
|
95
|
+
requested_model_name: "request_log_steps.requested_model_name",
|
|
96
|
+
fallback_count: "request_log_steps.fallback_count",
|
|
84
97
|
input_tokens: "request_log_steps.input_tokens",
|
|
85
98
|
output_tokens: "request_log_steps.output_tokens",
|
|
86
99
|
cache_read_tokens: "request_log_steps.cache_read_tokens",
|
|
87
100
|
cache_creation_tokens: "request_log_steps.cache_creation_tokens",
|
|
101
|
+
cache_creation_5m_tokens: "request_log_steps.cache_creation_5m_tokens",
|
|
102
|
+
cache_creation_1h_tokens: "request_log_steps.cache_creation_1h_tokens",
|
|
103
|
+
cost_usd: "request_log_steps.cost_usd",
|
|
104
|
+
cost_source: "request_log_steps.cost_source",
|
|
88
105
|
duration_ms: "request_log_steps.duration_ms",
|
|
89
106
|
ttft_ms: "request_log_steps.ttft_ms",
|
|
90
107
|
finish_reason: "request_log_steps.finish_reason",
|
|
@@ -105,10 +122,17 @@ export const requestLogStepSubsetQueries = {
|
|
|
105
122
|
created_at: "request_log_steps.created_at",
|
|
106
123
|
step_index: "request_log_steps.step_index",
|
|
107
124
|
type: "request_log_steps.type",
|
|
125
|
+
model_name: "request_log_steps.model_name",
|
|
126
|
+
requested_model_name: "request_log_steps.requested_model_name",
|
|
127
|
+
fallback_count: "request_log_steps.fallback_count",
|
|
108
128
|
input_tokens: "request_log_steps.input_tokens",
|
|
109
129
|
output_tokens: "request_log_steps.output_tokens",
|
|
110
130
|
cache_read_tokens: "request_log_steps.cache_read_tokens",
|
|
111
131
|
cache_creation_tokens: "request_log_steps.cache_creation_tokens",
|
|
132
|
+
cache_creation_5m_tokens: "request_log_steps.cache_creation_5m_tokens",
|
|
133
|
+
cache_creation_1h_tokens: "request_log_steps.cache_creation_1h_tokens",
|
|
134
|
+
cost_usd: "request_log_steps.cost_usd",
|
|
135
|
+
cost_source: "request_log_steps.cost_source",
|
|
112
136
|
duration_ms: "request_log_steps.duration_ms",
|
|
113
137
|
ttft_ms: "request_log_steps.ttft_ms",
|
|
114
138
|
finish_reason: "request_log_steps.finish_reason",
|
|
@@ -92,6 +92,8 @@ export const RequestLogBaseSchema = z.object({
|
|
|
92
92
|
token_name: z.string().max(100).nullable(),
|
|
93
93
|
project_name: z.string().max(50).nullable(),
|
|
94
94
|
model_name: z.string().max(50).nullable(),
|
|
95
|
+
requested_model_name: z.string().max(50).nullable(),
|
|
96
|
+
fallback_count: z.int().nullable(),
|
|
95
97
|
user_prompt: z.string().nullable(),
|
|
96
98
|
system_prompt: z.string().nullable(),
|
|
97
99
|
response: z.string(),
|
|
@@ -99,9 +101,12 @@ export const RequestLogBaseSchema = z.object({
|
|
|
99
101
|
output_tokens: z.int(),
|
|
100
102
|
cache_read_tokens: z.int(),
|
|
101
103
|
cache_creation_tokens: z.int(),
|
|
104
|
+
cache_creation_5m_tokens: z.int().nullable(),
|
|
105
|
+
cache_creation_1h_tokens: z.int().nullable(),
|
|
102
106
|
duration_ms: z.int(),
|
|
103
107
|
ttft_ms: z.int(),
|
|
104
108
|
cost_usd: z.int().nullable(),
|
|
109
|
+
cost_source: z.string().max(20).nullable(),
|
|
105
110
|
image_cost_usd: z.int().nullable(),
|
|
106
111
|
image_cost_method: z.string().max(100).nullable(),
|
|
107
112
|
effort: z.string().max(10).nullable(),
|
|
@@ -117,6 +122,8 @@ export type RequestLogBaseSchema = z.infer<typeof RequestLogBaseSchema> & {
|
|
|
117
122
|
"token_name",
|
|
118
123
|
"project_name",
|
|
119
124
|
"model_name",
|
|
125
|
+
"requested_model_name",
|
|
126
|
+
"fallback_count",
|
|
120
127
|
"user_prompt",
|
|
121
128
|
"system_prompt",
|
|
122
129
|
"response",
|
|
@@ -124,9 +131,12 @@ export type RequestLogBaseSchema = z.infer<typeof RequestLogBaseSchema> & {
|
|
|
124
131
|
"output_tokens",
|
|
125
132
|
"cache_read_tokens",
|
|
126
133
|
"cache_creation_tokens",
|
|
134
|
+
"cache_creation_5m_tokens",
|
|
135
|
+
"cache_creation_1h_tokens",
|
|
127
136
|
"duration_ms",
|
|
128
137
|
"ttft_ms",
|
|
129
138
|
"cost_usd",
|
|
139
|
+
"cost_source",
|
|
130
140
|
"image_cost_usd",
|
|
131
141
|
"image_cost_method",
|
|
132
142
|
"effort",
|
|
@@ -146,10 +156,17 @@ export const RequestLogStepBaseSchema = z.object({
|
|
|
146
156
|
request_log_id: z.int(),
|
|
147
157
|
step_index: z.int(),
|
|
148
158
|
type: RequestLogStepType,
|
|
159
|
+
model_name: z.string().max(50).nullable(),
|
|
160
|
+
requested_model_name: z.string().max(50).nullable(),
|
|
161
|
+
fallback_count: z.int().nullable(),
|
|
149
162
|
input_tokens: z.int().nullable(),
|
|
150
163
|
output_tokens: z.int().nullable(),
|
|
151
164
|
cache_read_tokens: z.int().nullable(),
|
|
152
165
|
cache_creation_tokens: z.int().nullable(),
|
|
166
|
+
cache_creation_5m_tokens: z.int().nullable(),
|
|
167
|
+
cache_creation_1h_tokens: z.int().nullable(),
|
|
168
|
+
cost_usd: z.int().nullable(),
|
|
169
|
+
cost_source: z.string().max(20).nullable(),
|
|
153
170
|
duration_ms: z.int().nullable(),
|
|
154
171
|
ttft_ms: z.int().nullable(),
|
|
155
172
|
finish_reason: z.string().max(20).nullable(),
|
|
@@ -166,10 +183,17 @@ export const RequestLogStepBaseSchema = z.object({
|
|
|
166
183
|
export type RequestLogStepBaseSchema = z.infer<typeof RequestLogStepBaseSchema> & {
|
|
167
184
|
readonly __hasDefault__: readonly [
|
|
168
185
|
"created_at",
|
|
186
|
+
"model_name",
|
|
187
|
+
"requested_model_name",
|
|
188
|
+
"fallback_count",
|
|
169
189
|
"input_tokens",
|
|
170
190
|
"output_tokens",
|
|
171
191
|
"cache_read_tokens",
|
|
172
192
|
"cache_creation_tokens",
|
|
193
|
+
"cache_creation_5m_tokens",
|
|
194
|
+
"cache_creation_1h_tokens",
|
|
195
|
+
"cost_usd",
|
|
196
|
+
"cost_source",
|
|
173
197
|
"duration_ms",
|
|
174
198
|
"ttft_ms",
|
|
175
199
|
"finish_reason",
|
|
@@ -265,6 +289,8 @@ export const RequestLogSubsetA = z.object({
|
|
|
265
289
|
token_name: z.string().max(100).nullable(),
|
|
266
290
|
project_name: z.string().max(50).nullable(),
|
|
267
291
|
model_name: z.string().max(50).nullable(),
|
|
292
|
+
requested_model_name: z.string().max(50).nullable(),
|
|
293
|
+
fallback_count: z.int().nullable(),
|
|
268
294
|
user_prompt: z.string().nullable(),
|
|
269
295
|
system_prompt: z.string().nullable(),
|
|
270
296
|
response: z.string(),
|
|
@@ -272,9 +298,12 @@ export const RequestLogSubsetA = z.object({
|
|
|
272
298
|
output_tokens: z.int(),
|
|
273
299
|
cache_read_tokens: z.int(),
|
|
274
300
|
cache_creation_tokens: z.int(),
|
|
301
|
+
cache_creation_5m_tokens: z.int().nullable(),
|
|
302
|
+
cache_creation_1h_tokens: z.int().nullable(),
|
|
275
303
|
duration_ms: z.int(),
|
|
276
304
|
ttft_ms: z.int(),
|
|
277
305
|
cost_usd: z.int().nullable(),
|
|
306
|
+
cost_source: z.string().max(20).nullable(),
|
|
278
307
|
image_cost_usd: z.int().nullable(),
|
|
279
308
|
image_cost_method: z.string().max(100).nullable(),
|
|
280
309
|
effort: z.string().max(10).nullable(),
|
|
@@ -291,13 +320,18 @@ export const RequestLogSubsetP = z.object({
|
|
|
291
320
|
token_name: z.string().max(100).nullable(),
|
|
292
321
|
project_name: z.string().max(50).nullable(),
|
|
293
322
|
model_name: z.string().max(50).nullable(),
|
|
323
|
+
requested_model_name: z.string().max(50).nullable(),
|
|
324
|
+
fallback_count: z.int().nullable(),
|
|
294
325
|
input_tokens: z.int(),
|
|
295
326
|
output_tokens: z.int(),
|
|
296
327
|
cache_read_tokens: z.int(),
|
|
297
328
|
cache_creation_tokens: z.int(),
|
|
329
|
+
cache_creation_5m_tokens: z.int().nullable(),
|
|
330
|
+
cache_creation_1h_tokens: z.int().nullable(),
|
|
298
331
|
duration_ms: z.int(),
|
|
299
332
|
ttft_ms: z.int(),
|
|
300
333
|
cost_usd: z.int().nullable(),
|
|
334
|
+
cost_source: z.string().max(20).nullable(),
|
|
301
335
|
image_cost_usd: z.int().nullable(),
|
|
302
336
|
image_cost_method: z.string().max(100).nullable(),
|
|
303
337
|
effort: z.string().max(10).nullable(),
|
|
@@ -319,10 +353,17 @@ export const RequestLogStepSubsetA = z.object({
|
|
|
319
353
|
created_at: z.date(),
|
|
320
354
|
step_index: z.int(),
|
|
321
355
|
type: RequestLogStepType,
|
|
356
|
+
model_name: z.string().max(50).nullable(),
|
|
357
|
+
requested_model_name: z.string().max(50).nullable(),
|
|
358
|
+
fallback_count: z.int().nullable(),
|
|
322
359
|
input_tokens: z.int().nullable(),
|
|
323
360
|
output_tokens: z.int().nullable(),
|
|
324
361
|
cache_read_tokens: z.int().nullable(),
|
|
325
362
|
cache_creation_tokens: z.int().nullable(),
|
|
363
|
+
cache_creation_5m_tokens: z.int().nullable(),
|
|
364
|
+
cache_creation_1h_tokens: z.int().nullable(),
|
|
365
|
+
cost_usd: z.int().nullable(),
|
|
366
|
+
cost_source: z.string().max(20).nullable(),
|
|
326
367
|
duration_ms: z.int().nullable(),
|
|
327
368
|
ttft_ms: z.int().nullable(),
|
|
328
369
|
finish_reason: z.string().max(20).nullable(),
|
|
@@ -342,10 +383,17 @@ export const RequestLogStepSubsetT = z.object({
|
|
|
342
383
|
created_at: z.date(),
|
|
343
384
|
step_index: z.int(),
|
|
344
385
|
type: RequestLogStepType,
|
|
386
|
+
model_name: z.string().max(50).nullable(),
|
|
387
|
+
requested_model_name: z.string().max(50).nullable(),
|
|
388
|
+
fallback_count: z.int().nullable(),
|
|
345
389
|
input_tokens: z.int().nullable(),
|
|
346
390
|
output_tokens: z.int().nullable(),
|
|
347
391
|
cache_read_tokens: z.int().nullable(),
|
|
348
392
|
cache_creation_tokens: z.int().nullable(),
|
|
393
|
+
cache_creation_5m_tokens: z.int().nullable(),
|
|
394
|
+
cache_creation_1h_tokens: z.int().nullable(),
|
|
395
|
+
cost_usd: z.int().nullable(),
|
|
396
|
+
cost_source: z.string().max(20).nullable(),
|
|
349
397
|
duration_ms: z.int().nullable(),
|
|
350
398
|
ttft_ms: z.int().nullable(),
|
|
351
399
|
finish_reason: z.string().max(20).nullable(),
|
|
@@ -215,6 +215,8 @@ const entityLabels = {
|
|
|
215
215
|
"entity.RequestLog.token_name": "토큰 이름",
|
|
216
216
|
"entity.RequestLog.project_name": "프로젝트 이름",
|
|
217
217
|
"entity.RequestLog.model_name": "모델 이름",
|
|
218
|
+
"entity.RequestLog.requested_model_name": "요청 모델 이름 (fallback 전)",
|
|
219
|
+
"entity.RequestLog.fallback_count": "모델 fallback 횟수",
|
|
218
220
|
"entity.RequestLog.user_prompt": "사용자 프롬프트",
|
|
219
221
|
"entity.RequestLog.system_prompt": "시스템 프롬프트",
|
|
220
222
|
"entity.RequestLog.response": "llm 응답 전문",
|
|
@@ -222,9 +224,12 @@ const entityLabels = {
|
|
|
222
224
|
"entity.RequestLog.output_tokens": "출력 토큰",
|
|
223
225
|
"entity.RequestLog.cache_read_tokens": "캐시 읽기 토큰",
|
|
224
226
|
"entity.RequestLog.cache_creation_tokens": "캐시 생성 토큰",
|
|
227
|
+
"entity.RequestLog.cache_creation_5m_tokens": "5분 TTL 캐시 생성 토큰",
|
|
228
|
+
"entity.RequestLog.cache_creation_1h_tokens": "1시간 TTL 캐시 생성 토큰",
|
|
225
229
|
"entity.RequestLog.duration_ms": "응답 소요시간(ms)",
|
|
226
230
|
"entity.RequestLog.ttft_ms": "first gen TTFT(ms)",
|
|
227
231
|
"entity.RequestLog.cost_usd": "API 비용",
|
|
232
|
+
"entity.RequestLog.cost_source": "비용 출처(provider/pricing_table/mixed)",
|
|
228
233
|
"entity.RequestLog.image_cost_usd": "이미지 생성 추정 비용",
|
|
229
234
|
"entity.RequestLog.image_cost_method": "이미지 비용 추정 방식",
|
|
230
235
|
"entity.RequestLog.effort": "effort level",
|
|
@@ -247,10 +252,17 @@ const entityLabels = {
|
|
|
247
252
|
"entity.RequestLogStep.request_log": "부모 request log ID",
|
|
248
253
|
"entity.RequestLogStep.step_index": "ai-sdk step number (0-based)",
|
|
249
254
|
"entity.RequestLogStep.type": "step 타입",
|
|
255
|
+
"entity.RequestLogStep.model_name": "실제 serving 모델",
|
|
256
|
+
"entity.RequestLogStep.requested_model_name": "요청 모델 (fallback 전)",
|
|
257
|
+
"entity.RequestLogStep.fallback_count": "모델 fallback 횟수",
|
|
250
258
|
"entity.RequestLogStep.input_tokens": "입력 토큰 (generate)",
|
|
251
259
|
"entity.RequestLogStep.output_tokens": "출력 토큰 (generate)",
|
|
252
260
|
"entity.RequestLogStep.cache_read_tokens": "캐시 읽기 토큰",
|
|
253
261
|
"entity.RequestLogStep.cache_creation_tokens": "캐시 생성 토큰",
|
|
262
|
+
"entity.RequestLogStep.cache_creation_5m_tokens": "5분 TTL 캐시 생성 토큰",
|
|
263
|
+
"entity.RequestLogStep.cache_creation_1h_tokens": "1시간 TTL 캐시 생성 토큰",
|
|
264
|
+
"entity.RequestLogStep.cost_usd": "step 비용 (micro-USD)",
|
|
265
|
+
"entity.RequestLogStep.cost_source": "비용 출처(provider/pricing_table)",
|
|
254
266
|
"entity.RequestLogStep.duration_ms": "소요시간(ms)",
|
|
255
267
|
"entity.RequestLogStep.ttft_ms": "Gen TTFT(ms)",
|
|
256
268
|
"entity.RequestLogStep.finish_reason": "완료 사유",
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type Knex } from "knex";
|
|
2
|
+
|
|
3
|
+
export async function up(knex: Knex): Promise<void> {
|
|
4
|
+
await knex.schema.alterTable("request_logs", (table) => {
|
|
5
|
+
// add
|
|
6
|
+
table.integer("cache_creation_1h_tokens").nullable();
|
|
7
|
+
table.integer("cache_creation_5m_tokens").nullable();
|
|
8
|
+
table.string("cost_source", 20).nullable();
|
|
9
|
+
table.integer("fallback_count").nullable();
|
|
10
|
+
table.string("requested_model_name", 50).nullable();
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export async function down(knex: Knex): Promise<void> {
|
|
15
|
+
await knex.schema.alterTable("request_logs", (table) => {
|
|
16
|
+
// rollback - add
|
|
17
|
+
table.dropColumns(
|
|
18
|
+
"cache_creation_1h_tokens",
|
|
19
|
+
"cache_creation_5m_tokens",
|
|
20
|
+
"cost_source",
|
|
21
|
+
"fallback_count",
|
|
22
|
+
"requested_model_name",
|
|
23
|
+
);
|
|
24
|
+
});
|
|
25
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { type Knex } from "knex";
|
|
2
|
+
|
|
3
|
+
export async function up(knex: Knex): Promise<void> {
|
|
4
|
+
await knex.schema.alterTable("request_log_steps", (table) => {
|
|
5
|
+
// add
|
|
6
|
+
table.integer("cache_creation_1h_tokens").nullable();
|
|
7
|
+
table.integer("cache_creation_5m_tokens").nullable();
|
|
8
|
+
table.string("cost_source", 20).nullable();
|
|
9
|
+
table.integer("cost_usd").nullable();
|
|
10
|
+
table.integer("fallback_count").nullable();
|
|
11
|
+
table.string("model_name", 50).nullable();
|
|
12
|
+
table.string("requested_model_name", 50).nullable();
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export async function down(knex: Knex): Promise<void> {
|
|
17
|
+
await knex.schema.alterTable("request_log_steps", (table) => {
|
|
18
|
+
// rollback - add
|
|
19
|
+
table.dropColumns(
|
|
20
|
+
"cache_creation_1h_tokens",
|
|
21
|
+
"cache_creation_5m_tokens",
|
|
22
|
+
"cost_source",
|
|
23
|
+
"cost_usd",
|
|
24
|
+
"fallback_count",
|
|
25
|
+
"model_name",
|
|
26
|
+
"requested_model_name",
|
|
27
|
+
);
|
|
28
|
+
});
|
|
29
|
+
}
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
canonicalAnthropicModel,
|
|
7
7
|
hasOneMillionSuffix,
|
|
8
8
|
needsCli1mSuffix,
|
|
9
|
+
requiresAdaptiveThinking,
|
|
9
10
|
supports1MContext,
|
|
10
11
|
} from "./anthropic-constants";
|
|
11
12
|
|
|
@@ -16,6 +17,7 @@ describe("canonicalAnthropicModel", () => {
|
|
|
16
17
|
|
|
17
18
|
it("provider prefix 를 제거한다", () => {
|
|
18
19
|
expect(canonicalAnthropicModel("anthropic/claude-opus-4-8")).toBe("claude-opus-4-8");
|
|
20
|
+
expect(canonicalAnthropicModel("anthropic/claude-fable-5")).toBe("claude-fable-5");
|
|
19
21
|
});
|
|
20
22
|
|
|
21
23
|
it("[1m] suffix 를 base canonical 에서 제거한다", () => {
|
|
@@ -26,6 +28,8 @@ describe("canonicalAnthropicModel", () => {
|
|
|
26
28
|
|
|
27
29
|
describe("Anthropic 1M context policy", () => {
|
|
28
30
|
it("지원 모델은 실측 확인된 exact set 만 true", () => {
|
|
31
|
+
expect(supports1MContext("claude-fable-5")).toBe(true);
|
|
32
|
+
expect(supports1MContext("claude-sonnet-5")).toBe(true);
|
|
29
33
|
expect(supports1MContext("claude-sonnet-4-6")).toBe(true);
|
|
30
34
|
expect(supports1MContext("claude-opus-4-6")).toBe(true);
|
|
31
35
|
expect(supports1MContext("claude-opus-4-8")).toBe(true);
|
|
@@ -37,6 +41,8 @@ describe("Anthropic 1M context policy", () => {
|
|
|
37
41
|
});
|
|
38
42
|
|
|
39
43
|
it("CLI suffix 필요 모델과 기본 1M 모델을 분리한다", () => {
|
|
44
|
+
expect(needsCli1mSuffix("claude-fable-5")).toBe(false);
|
|
45
|
+
expect(needsCli1mSuffix("claude-sonnet-5")).toBe(false);
|
|
40
46
|
expect(needsCli1mSuffix("claude-sonnet-4-6")).toBe(true);
|
|
41
47
|
expect(needsCli1mSuffix("claude-opus-4-6")).toBe(true);
|
|
42
48
|
expect(needsCli1mSuffix("claude-opus-4-8")).toBe(false);
|
|
@@ -58,3 +64,12 @@ describe("Anthropic 1M context policy", () => {
|
|
|
58
64
|
expect(() => assertSupportedOneMillionSuffix("anthropic/claude-sonnet-4-6[1m]")).not.toThrow();
|
|
59
65
|
});
|
|
60
66
|
});
|
|
67
|
+
|
|
68
|
+
describe("Anthropic thinking policy", () => {
|
|
69
|
+
it("Fable 5 만 always-on adaptive thinking 으로 실행한다", () => {
|
|
70
|
+
expect(requiresAdaptiveThinking("claude-fable-5")).toBe(true);
|
|
71
|
+
expect(requiresAdaptiveThinking("anthropic/claude-fable-5")).toBe(true);
|
|
72
|
+
expect(requiresAdaptiveThinking("claude-sonnet-5")).toBe(false);
|
|
73
|
+
expect(requiresAdaptiveThinking("claude-opus-4-8")).toBe(false);
|
|
74
|
+
});
|
|
75
|
+
});
|
|
@@ -42,15 +42,18 @@ export function hasOneMillionSuffix(model?: string): boolean {
|
|
|
42
42
|
return model !== undefined && ONE_MILLION_SUFFIX_RE.test(model);
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
// 1M 지원 여부는 Claude Code
|
|
46
|
-
// opus-4-7 은 실측 전까지 미포함. 새 모델 추가 시 실제
|
|
45
|
+
// 1M 지원 여부는 Claude Code 내부의 광범위한 prefix 판정이 아니라 qgrid에서 확인한 exact set 으로
|
|
46
|
+
// 고정한다. opus-4-7 은 실측 전까지 미포함. 새 모델 추가 시 공식 사양과 실제 CLI 동작을 확인한다.
|
|
47
47
|
const ONE_MILLION_CONTEXT_MODELS = new Set([
|
|
48
|
+
"claude-fable-5",
|
|
49
|
+
"claude-sonnet-5",
|
|
48
50
|
"claude-sonnet-4-6",
|
|
49
51
|
"claude-opus-4-6",
|
|
50
52
|
"claude-opus-4-8",
|
|
51
53
|
]);
|
|
52
54
|
|
|
53
55
|
const CLI_ONE_MILLION_SUFFIX_MODELS = new Set(["claude-sonnet-4-6", "claude-opus-4-6"]);
|
|
56
|
+
const ALWAYS_ADAPTIVE_THINKING_MODELS = new Set(["claude-fable-5"]);
|
|
54
57
|
|
|
55
58
|
// 불변 계약: suffix 가 필요한 모델은 반드시 1M 지원 모델의 부분집합이어야 한다. 역방향 불일치(suffix
|
|
56
59
|
// 대상인데 지원 집합엔 없음)면 needsCli1mSuffix=true·supports1MContext=false 가 동시에 나서
|
|
@@ -70,6 +73,12 @@ export function needsCli1mSuffix(model?: string): boolean {
|
|
|
70
73
|
return CLI_ONE_MILLION_SUFFIX_MODELS.has(canonicalAnthropicModel(model));
|
|
71
74
|
}
|
|
72
75
|
|
|
76
|
+
// Fable 5 는 adaptive thinking 이 유일한 thinking mode 이므로 disabled 로 실행할 수 없다.
|
|
77
|
+
// 나머지 모델은 qgrid 의 기존 저비용/비추론 경로를 그대로 유지한다.
|
|
78
|
+
export function requiresAdaptiveThinking(model?: string): boolean {
|
|
79
|
+
return ALWAYS_ADAPTIVE_THINKING_MODELS.has(canonicalAnthropicModel(model));
|
|
80
|
+
}
|
|
81
|
+
|
|
73
82
|
export function assertSupportedOneMillionSuffix(model?: string): void {
|
|
74
83
|
if (!hasOneMillionSuffix(model)) return;
|
|
75
84
|
const canonical = canonicalAnthropicModel(model);
|
|
@@ -347,7 +347,8 @@ export class AnthropicDispatcher implements ProviderDispatcher {
|
|
|
347
347
|
? `${session.text.slice(0, 500)}…(${session.text.length} chars)`
|
|
348
348
|
: session.text
|
|
349
349
|
: `empty text, outputTokens=${session.usage.outputTokens}`;
|
|
350
|
-
|
|
350
|
+
const refusal = session.refusal ? ` refusal=${JSON.stringify(session.refusal)}` : "";
|
|
351
|
+
throw new Error(`claude error (${token.name}) [${reason}]: ${body}${refusal}`);
|
|
351
352
|
}
|
|
352
353
|
|
|
353
354
|
return {
|
|
@@ -357,7 +358,11 @@ export class AnthropicDispatcher implements ProviderDispatcher {
|
|
|
357
358
|
durationMs: session.durationMs,
|
|
358
359
|
ttftMs: session.ttftMs,
|
|
359
360
|
costUsd: session.costUsd,
|
|
360
|
-
|
|
361
|
+
// Claude Code 는 Fable refusal 을 Opus 로 자동 fallback 할 수 있다. 요청 모델을
|
|
362
|
+
// 그대로 serving model 로 기록하면 비용/감사 로그가 모두 틀어지므로 둘을 구분한다.
|
|
363
|
+
model: session.servedModel ?? model,
|
|
364
|
+
requestedModel: model,
|
|
365
|
+
modelFallbacks: session.modelFallbacks,
|
|
361
366
|
// systemHash 는 상위 issueConvContext 가 채운다(여기선 비운다).
|
|
362
367
|
threadCoord: {
|
|
363
368
|
workerId: makeAnthropicWorkerId(token.id),
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
oneMillionEnv,
|
|
13
13
|
runClaudeSession,
|
|
14
14
|
structuredOutputRetriesEnv,
|
|
15
|
+
thinkingEnv,
|
|
15
16
|
SYSTEM_PROMPT_ARGV_MAX_BYTES,
|
|
16
17
|
withSessionLock,
|
|
17
18
|
} from "./claude-session";
|
|
@@ -132,6 +133,15 @@ describe("buildClaudeArgs (멀티턴/격리/structured)", () => {
|
|
|
132
133
|
expect(oneMillionEnv(false)).toEqual({ CLAUDE_CODE_DISABLE_1M_CONTEXT: "1" });
|
|
133
134
|
});
|
|
134
135
|
|
|
136
|
+
it("thinkingEnv: Fable 은 always-on adaptive thinking 을 보존하고 나머지는 비활성화", () => {
|
|
137
|
+
expect(thinkingEnv("claude-fable-5")).toEqual({});
|
|
138
|
+
expect(thinkingEnv("anthropic/claude-fable-5")).toEqual({});
|
|
139
|
+
expect(thinkingEnv("claude-opus-4-8")).toEqual({
|
|
140
|
+
CLAUDE_CODE_DISABLE_ADAPTIVE_THINKING: "1",
|
|
141
|
+
MAX_THINKING_TOKENS: "0",
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
|
|
135
145
|
// SON-495: structured output retry 를 1 로 고정한다.
|
|
136
146
|
it("structuredOutputRetriesEnv: 미설정/비정상 값은 1 로 기본 고정", () => {
|
|
137
147
|
expect(structuredOutputRetriesEnv(undefined)).toEqual({ MAX_STRUCTURED_OUTPUT_RETRIES: "1" });
|
|
@@ -221,6 +231,22 @@ describe("buildClaudeArgs (멀티턴/격리/structured)", () => {
|
|
|
221
231
|
expect(args[args.indexOf("--model") + 1]).toBe("claude-opus-4-8");
|
|
222
232
|
});
|
|
223
233
|
|
|
234
|
+
it("Fable 5 는 항상 켜진 adaptive thinking 을 끄지 않고 effort 만 전달한다", () => {
|
|
235
|
+
const args = buildClaudeArgs({
|
|
236
|
+
model: "claude-fable-5",
|
|
237
|
+
sessionId: "u",
|
|
238
|
+
effort: "low",
|
|
239
|
+
});
|
|
240
|
+
expect(args[args.indexOf("--model") + 1]).toBe("claude-fable-5");
|
|
241
|
+
expect(args).not.toContain("--thinking");
|
|
242
|
+
expect(args[args.indexOf("--effort") + 1]).toBe("low");
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
it("기존 Anthropic 모델은 thinking disabled 계약을 유지한다", () => {
|
|
246
|
+
const args = buildClaudeArgs({ model: "claude-opus-4-8", sessionId: "u" });
|
|
247
|
+
expect(args[args.indexOf("--thinking") + 1]).toBe("disabled");
|
|
248
|
+
});
|
|
249
|
+
|
|
224
250
|
it("non-structured(jsonSchema 없음): --allowed-tools 미부여 (P2-7)", () => {
|
|
225
251
|
const args = buildClaudeArgs({ model: "m", sessionId: "u" });
|
|
226
252
|
expect(args).not.toContain("--allowed-tools");
|