@cartanova/qgrid-cli 2.10.10 → 2.11.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/bundle/dist/_virtual/_rolldown/runtime.js +1 -10
- package/bundle/dist/application/monit/log-buffer.js +12 -6
- package/bundle/dist/application/monit/monit.frame.js +11 -3
- package/bundle/dist/application/monit/monit.types.js +1 -1
- package/bundle/dist/application/qgrid/conv-routing.js +9 -6
- package/bundle/dist/application/qgrid/expired-token-reminder.js +2 -2
- package/bundle/dist/application/qgrid/oauth.js +31 -4
- package/bundle/dist/application/qgrid/qgrid-image-generation.js +1 -1
- package/bundle/dist/application/qgrid/qgrid-response-format.js +21 -19
- package/bundle/dist/application/qgrid/qgrid-run-lifecycle.js +40 -33
- package/bundle/dist/application/qgrid/qgrid.dispatcher.js +128 -93
- package/bundle/dist/application/qgrid/qgrid.frame.js +930 -49
- package/bundle/dist/application/qgrid/qgrid.types.js +212 -5
- package/bundle/dist/application/qgrid/schema-prompt.js +75 -48
- package/bundle/dist/application/qgrid/slack-user-map.js +1 -1
- package/bundle/dist/application/qgrid/token-death.js +1 -1
- package/bundle/dist/application/qgrid/token-subscriber.js +83 -30
- package/bundle/dist/application/qgrid/token-trigger-setup.js +1 -1
- package/bundle/dist/application/qgrid/token-window-keepalive.js +8 -6
- package/bundle/dist/application/qgrid/tool-emulation-schema.js +13 -13
- package/bundle/dist/application/qgrid/tool-emulation.js +19 -15
- package/bundle/dist/application/request-log/json-schema-type-text.js +29 -12
- package/bundle/dist/application/request-log/request-log.model.js +83 -70
- package/bundle/dist/application/request-log/request-log.types.js +1 -1
- package/bundle/dist/application/request-log/zod-code-format.js +1 -1
- package/bundle/dist/application/request-log-step/request-log-step.model.js +1 -1
- package/bundle/dist/application/request-log-step/request-log-step.types.js +1 -1
- package/bundle/dist/application/setting/setting.constant.js +1 -1
- package/bundle/dist/application/setting/setting.model.js +2 -2
- package/bundle/dist/application/setting/setting.store.js +2 -2
- package/bundle/dist/application/setting/setting.types.js +1 -1
- package/bundle/dist/application/sonamu.generated.js +32 -16
- package/bundle/dist/application/sonamu.generated.sso.js +1 -1
- package/bundle/dist/application/token/token.model.js +26 -9
- package/bundle/dist/application/token/token.types.js +20 -3
- package/bundle/dist/i18n/en.js +15 -1
- package/bundle/dist/i18n/ko.js +15 -1
- package/bundle/dist/i18n/sd.generated.js +1 -1
- package/bundle/dist/migrations/20260807133553_manual__backfill_request_log_cost.js +8 -6
- package/bundle/dist/server-bootstrap.js +4 -2
- package/bundle/dist/server-error-handler.js +1 -1
- package/bundle/dist/sonamu.config.js +37 -8
- package/bundle/dist/startup-migrations.js +17 -7
- package/bundle/dist/testing/global.js +1 -1
- package/bundle/dist/testing/schema-bench.js +0 -0
- package/bundle/dist/testing/test-database-name.js +1 -1
- package/bundle/dist/utils/providers/anthropic/anthropic-constants.js +1 -1
- package/bundle/dist/utils/providers/anthropic/anthropic-dispatcher.js +11 -5
- package/bundle/dist/utils/providers/anthropic/anthropic-quota.js +4 -4
- package/bundle/dist/utils/providers/anthropic/anthropic-thinking.js +1 -1
- package/bundle/dist/utils/providers/anthropic/claude-session.js +20 -19
- package/bundle/dist/utils/providers/anthropic/fence-strip.js +1 -1
- package/bundle/dist/utils/providers/anthropic/stream-json-adapter.js +49 -23
- package/bundle/dist/utils/providers/common/credentials.js +5 -1
- package/bundle/dist/utils/providers/common/effort.js +3 -3
- package/bundle/dist/utils/providers/common/model-cost.js +69 -14
- package/bundle/dist/utils/providers/common/provider-types.js +29 -1
- package/bundle/dist/utils/providers/common/schema-validation.js +78 -40
- package/bundle/dist/utils/providers/common/smooth-weighted-round-robin.js +1 -1
- package/bundle/dist/utils/providers/common/strictifier.js +62 -43
- package/bundle/dist/utils/providers/common/thinking.js +3 -2
- package/bundle/dist/utils/providers/common/ttft.js +1 -1
- package/bundle/dist/utils/providers/grok/grok-backend-protocol.js +427 -0
- package/bundle/dist/utils/providers/grok/grok-constants.js +55 -0
- package/bundle/dist/utils/providers/grok/grok-direct-client.js +196 -0
- package/bundle/dist/utils/providers/grok/grok-dispatcher.js +1313 -0
- package/bundle/dist/utils/providers/grok/grok-headers.js +118 -0
- package/bundle/dist/utils/providers/grok/grok-media-client.js +420 -0
- package/bundle/dist/utils/providers/grok/grok-models.js +114 -0
- package/bundle/dist/utils/providers/grok/grok-oauth.js +455 -0
- package/bundle/dist/utils/providers/grok/grok-quota.js +119 -0
- package/bundle/dist/utils/providers/grok/grok-refresh.js +192 -0
- package/bundle/dist/utils/providers/grok/grok-types.js +186 -0
- package/bundle/dist/utils/providers/grok/grok-voice-client.js +199 -0
- package/bundle/dist/utils/providers/grok/index.js +11 -0
- package/bundle/dist/utils/providers/openai/openai-backend-protocol.js +111 -83
- package/bundle/dist/utils/providers/openai/openai-callback-relay.js +3 -2
- package/bundle/dist/utils/providers/openai/openai-constants.js +1 -1
- package/bundle/dist/utils/providers/openai/openai-direct-client.js +23 -7
- package/bundle/dist/utils/providers/openai/openai-dispatcher.js +143 -106
- package/bundle/dist/utils/providers/openai/openai-image-generation.js +48 -33
- package/bundle/dist/utils/providers/openai/openai-oauth.js +28 -13
- package/bundle/dist/utils/providers/openai/openai-quota.js +38 -27
- package/bundle/dist/utils/providers/openai/openai-refresh.js +17 -9
- package/bundle/dist/utils/providers/openai/openai-sse.js +1 -1
- package/bundle/dist/utils/providers/openai/openai-transport-config.js +1 -1
- package/bundle/dist/utils/quiet-hours.js +1 -1
- package/bundle/dist/utils/slack-notify.js +14 -8
- package/bundle/dist/utils/subset-loaders.js +4 -5
- package/bundle/src/application/monit/log-buffer.ts +23 -9
- package/bundle/src/application/monit/monit.frame.ts +22 -5
- package/bundle/src/application/monit/monit.types.ts +6 -0
- package/bundle/src/application/qgrid/conv-routing.test.ts +76 -4
- package/bundle/src/application/qgrid/conv-routing.ts +35 -9
- package/bundle/src/application/qgrid/expired-token-reminder.ts +9 -1
- package/bundle/src/application/qgrid/oauth.ts +51 -15
- package/bundle/src/application/qgrid/qgrid-image-generation.ts +9 -0
- package/bundle/src/application/qgrid/qgrid-response-format.ts +50 -25
- package/bundle/src/application/qgrid/qgrid-run-lifecycle.test.ts +19 -0
- package/bundle/src/application/qgrid/qgrid-run-lifecycle.ts +84 -40
- package/bundle/src/application/qgrid/qgrid.dispatcher.test.ts +97 -0
- package/bundle/src/application/qgrid/qgrid.dispatcher.ts +274 -126
- package/bundle/src/application/qgrid/qgrid.frame.test.ts +1013 -3
- package/bundle/src/application/qgrid/qgrid.frame.ts +1415 -60
- package/bundle/src/application/qgrid/qgrid.types.ts +335 -0
- package/bundle/src/application/qgrid/schema-prompt.ts +105 -41
- package/bundle/src/application/qgrid/slack-user-map.ts +5 -0
- package/bundle/src/application/qgrid/token-death.ts +4 -0
- package/bundle/src/application/qgrid/token-subscriber.test.ts +21 -19
- package/bundle/src/application/qgrid/token-subscriber.ts +186 -53
- package/bundle/src/application/qgrid/token-trigger-setup.ts +2 -0
- package/bundle/src/application/qgrid/token-window-keepalive.ts +49 -6
- package/bundle/src/application/qgrid/tool-emulation-schema.ts +33 -29
- package/bundle/src/application/qgrid/tool-emulation.ts +52 -27
- package/bundle/src/application/request-log/json-schema-type-text.test.ts +5 -5
- package/bundle/src/application/request-log/json-schema-type-text.ts +81 -26
- package/bundle/src/application/request-log/request-log.model.test.ts +111 -4
- package/bundle/src/application/request-log/request-log.model.ts +277 -146
- package/bundle/src/application/request-log/request-log.types.ts +6 -0
- package/bundle/src/application/request-log/zod-code-format.ts +11 -0
- package/bundle/src/application/request-log-step/request-log-step.model.ts +1 -0
- package/bundle/src/application/request-log-step/request-log-step.types.ts +2 -0
- package/bundle/src/application/setting/setting.constant.ts +9 -0
- package/bundle/src/application/setting/setting.model.ts +12 -2
- package/bundle/src/application/setting/setting.store.ts +5 -1
- package/bundle/src/application/setting/setting.types.ts +8 -0
- package/bundle/src/application/sonamu.generated.http +133 -0
- package/bundle/src/application/sonamu.generated.sso.ts +2 -0
- package/bundle/src/application/sonamu.generated.ts +15 -0
- package/bundle/src/application/token/token.identity.test.ts +20 -0
- package/bundle/src/application/token/token.model.ts +66 -7
- package/bundle/src/application/token/token.types.ts +24 -1
- package/bundle/src/i18n/en.ts +19 -0
- package/bundle/src/i18n/ko.ts +21 -0
- package/bundle/src/i18n/sd.generated.ts +23 -2
- package/bundle/src/migrations/20260807133553_manual__backfill_request_log_cost.ts +16 -8
- package/bundle/src/server-bootstrap.ts +4 -2
- package/bundle/src/server-error-handler.ts +1 -0
- package/bundle/src/sonamu.config.ts +69 -7
- package/bundle/src/startup-migrations.ts +27 -9
- package/bundle/src/testing/global.ts +20 -0
- package/bundle/src/testing/schema-bench.ts +105 -30
- package/bundle/src/testing/test-database-name.ts +2 -0
- package/bundle/src/utils/providers/anthropic/anthropic-constants.ts +8 -0
- package/bundle/src/utils/providers/anthropic/anthropic-dispatcher.ts +41 -6
- package/bundle/src/utils/providers/anthropic/anthropic-quota.ts +7 -3
- package/bundle/src/utils/providers/anthropic/anthropic-thinking.ts +6 -0
- package/bundle/src/utils/providers/anthropic/claude-session.ts +58 -24
- package/bundle/src/utils/providers/anthropic/fence-strip.ts +11 -0
- package/bundle/src/utils/providers/anthropic/stream-json-adapter.ts +110 -45
- package/bundle/src/utils/providers/common/credentials.ts +8 -0
- package/bundle/src/utils/providers/common/effort.ts +9 -2
- package/bundle/src/utils/providers/common/model-cost.test.ts +48 -1
- package/bundle/src/utils/providers/common/model-cost.ts +259 -158
- package/bundle/src/utils/providers/common/provider-dispatcher.ts +98 -2
- package/bundle/src/utils/providers/common/provider-types.ts +46 -3
- package/bundle/src/utils/providers/common/schema-validation.test.ts +5 -1
- package/bundle/src/utils/providers/common/schema-validation.ts +124 -56
- package/bundle/src/utils/providers/common/smooth-weighted-round-robin.ts +4 -0
- package/bundle/src/utils/providers/common/strictifier.ts +185 -59
- package/bundle/src/utils/providers/common/thinking.ts +2 -2
- package/bundle/src/utils/providers/common/ttft.ts +4 -2
- package/bundle/src/utils/providers/grok/__fixtures__/golden-responses-1.0.60.json +164 -0
- package/bundle/src/utils/providers/grok/grok-backend-protocol.test.ts +325 -0
- package/bundle/src/utils/providers/grok/grok-backend-protocol.ts +721 -0
- package/bundle/src/utils/providers/grok/grok-constants.ts +105 -0
- package/bundle/src/utils/providers/grok/grok-direct-client.test.ts +179 -0
- package/bundle/src/utils/providers/grok/grok-direct-client.ts +313 -0
- package/bundle/src/utils/providers/grok/grok-dispatcher.test.ts +1395 -0
- package/bundle/src/utils/providers/grok/grok-dispatcher.ts +2105 -0
- package/bundle/src/utils/providers/grok/grok-headers.test.ts +149 -0
- package/bundle/src/utils/providers/grok/grok-headers.ts +199 -0
- package/bundle/src/utils/providers/grok/grok-media-client.test.ts +446 -0
- package/bundle/src/utils/providers/grok/grok-media-client.ts +703 -0
- package/bundle/src/utils/providers/grok/grok-models.test.ts +96 -0
- package/bundle/src/utils/providers/grok/grok-models.ts +161 -0
- package/bundle/src/utils/providers/grok/grok-oauth.test.ts +406 -0
- package/bundle/src/utils/providers/grok/grok-oauth.ts +771 -0
- package/bundle/src/utils/providers/grok/grok-quota.test.ts +142 -0
- package/bundle/src/utils/providers/grok/grok-quota.ts +198 -0
- package/bundle/src/utils/providers/grok/grok-refresh.test.ts +239 -0
- package/bundle/src/utils/providers/grok/grok-refresh.ts +325 -0
- package/bundle/src/utils/providers/grok/grok-types.test.ts +252 -0
- package/bundle/src/utils/providers/grok/grok-types.ts +374 -0
- package/bundle/src/utils/providers/grok/grok-voice-client.test.ts +321 -0
- package/bundle/src/utils/providers/grok/grok-voice-client.ts +284 -0
- package/bundle/src/utils/providers/grok/index.ts +20 -0
- package/bundle/src/utils/providers/openai/openai-backend-protocol.ts +221 -137
- package/bundle/src/utils/providers/openai/openai-callback-relay.ts +12 -1
- package/bundle/src/utils/providers/openai/openai-constants.ts +2 -0
- package/bundle/src/utils/providers/openai/openai-direct-client.ts +111 -21
- package/bundle/src/utils/providers/openai/openai-dispatcher.ts +322 -169
- package/bundle/src/utils/providers/openai/openai-image-generation.ts +116 -36
- package/bundle/src/utils/providers/openai/openai-oauth.ts +48 -20
- package/bundle/src/utils/providers/openai/openai-quota.ts +77 -46
- package/bundle/src/utils/providers/openai/openai-refresh.ts +42 -18
- package/bundle/src/utils/providers/openai/openai-sse.ts +27 -3
- package/bundle/src/utils/providers/openai/openai-transport-config.ts +2 -0
- package/bundle/src/utils/quiet-hours.ts +12 -1
- package/bundle/src/utils/slack-notify.ts +44 -13
- package/bundle/src/utils/subset-loaders.ts +7 -7
- package/bundle/web-dist/client/assets/clsx-5XM_pHvN.js +1 -0
- package/bundle/web-dist/client/assets/index-Be2qCZmI.css +1 -0
- package/bundle/web-dist/client/assets/index-C96h3feE.js +32 -0
- package/bundle/web-dist/client/assets/logs-DBM6U0QD.js +1 -0
- package/bundle/web-dist/client/assets/monit-BBjXa7vB.js +1 -0
- package/bundle/web-dist/client/assets/routes-Crz_PQzi.js +5 -0
- package/bundle/web-dist/client/assets/{services.generated-NP-ValHd.js → services.generated-B5lc3aIC.js} +5 -5
- package/bundle/web-dist/client/assets/settings-Cdwm3OBB.js +1 -0
- package/bundle/web-dist/client/assets/show-DBUhALT1.js +2 -0
- package/bundle/web-dist/client/assets/tokens-CVQAVJTo.js +1 -0
- package/bundle/web-dist/client/assets/total-cost-MnfKU8IN.js +1 -0
- package/bundle/web-dist/client/assets/use-oauth-login-flow-BfxYI4Oh.js +1 -0
- package/bundle/web-dist/client/assets/use-update-token-mutation-qKBC2sn7.js +1 -0
- package/bundle/web-dist/client/assets/{vendor-tanstack-DJRQAbrY.js → vendor-tanstack-DRPs09ai.js} +1 -1
- package/bundle/web-dist/client/index.html +5 -5
- package/bundle/web-dist/server/assets/clsx-D_N5PN_2.js +16 -0
- package/bundle/web-dist/server/assets/{lazyRouteComponent-CgBdabgd.js → lazyRouteComponent-AKiHfZWp.js} +129 -2
- package/bundle/web-dist/server/assets/{logs-BMyR98rU.js → logs-B7QmGJq3.js} +18 -14
- package/bundle/web-dist/server/assets/{monit-ZPt66W5M.js → monit-DFt7x3bh.js} +13 -12
- package/bundle/web-dist/server/assets/{plus-BZ9I0VgC.js → plus-DaYQRpBt.js} +1 -1
- package/bundle/web-dist/server/assets/{react-dom-Ds75e4Jl.js → react-dom-Cv23mm1K.js} +2 -129
- package/bundle/web-dist/server/assets/{refresh-cw-CztCFis-.js → refresh-cw-BpXNsAy-.js} +1 -1
- package/bundle/web-dist/server/assets/{request-model-DjGldb-h.js → request-model-eHE6YbaF.js} +1 -1
- package/bundle/web-dist/server/assets/{routes-Ct-k7nBA.js → routes-_Y-PJfgO.js} +110 -39
- package/bundle/web-dist/server/assets/{services.generated-BA4AcAf5.js → services.generated-CMJ8AHbO.js} +582 -172
- package/bundle/web-dist/server/assets/{settings-CBUZ47Xx.js → settings-JwJKxn2e.js} +14 -14
- package/bundle/web-dist/server/assets/{show-LSFIzvO2.js → show-BEv6z1v_.js} +90 -60
- package/bundle/web-dist/server/assets/{tokens-DxrBW512.js → tokens-CNT4mI-f.js} +162 -50
- package/bundle/web-dist/server/assets/total-cost-fTE9Xy82.js +18 -0
- package/bundle/web-dist/server/assets/use-oauth-login-flow-jkAkT3X6.js +2345 -0
- package/bundle/web-dist/server/assets/{use-update-token-mutation-pkArIzCP.js → use-update-token-mutation-Sm6kh02m.js} +1 -1
- package/bundle/web-dist/server/entry-server.generated.js +1644 -21655
- package/dist/cli.js +9 -9
- package/package.json +4 -11
- package/postinstall.mjs +12 -0
- package/skills/qgrid/SKILL.md +1 -0
- package/skills/qgrid/references/cli-env-and-server-boot.md +4 -1
- package/skills/qgrid/references/decision-rationale.md +23 -0
- package/skills/qgrid/references/grok-runtime.md +89 -0
- package/skills/qgrid/references/provider-runtime-differences.md +30 -29
- package/skills/qgrid/references/repo-map.md +10 -0
- package/skills/qgrid/references/token-auth-quota-lifecycle.md +56 -3
- package/bundle/dist/node_modules/.pnpm/@jridgewell_sourcemap-codec@1.5.5/node_modules/@jridgewell/sourcemap-codec/dist/sourcemap-codec.js +0 -406
- package/bundle/dist/node_modules/.pnpm/@vitest_expect@4.1.10/node_modules/@vitest/expect/dist/index.js +0 -1507
- package/bundle/dist/node_modules/.pnpm/@vitest_pretty-format@4.1.10/node_modules/@vitest/pretty-format/dist/index.js +0 -887
- package/bundle/dist/node_modules/.pnpm/@vitest_runner@4.1.10/node_modules/@vitest/runner/dist/chunk-artifact.js +0 -2756
- package/bundle/dist/node_modules/.pnpm/@vitest_runner@4.1.10/node_modules/@vitest/runner/dist/index.js +0 -8
- package/bundle/dist/node_modules/.pnpm/@vitest_runner@4.1.10/node_modules/@vitest/runner/dist/utils.js +0 -8
- package/bundle/dist/node_modules/.pnpm/@vitest_snapshot@4.1.10/node_modules/@vitest/snapshot/dist/index.js +0 -922
- package/bundle/dist/node_modules/.pnpm/@vitest_spy@4.1.10/node_modules/@vitest/spy/dist/index.js +0 -386
- package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/chunk-pathe.M-eThtNZ.js +0 -121
- package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/constants.js +0 -51
- package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/diff.js +0 -1317
- package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/display.js +0 -561
- package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/error.js +0 -40
- package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/helpers.js +0 -272
- package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/offset.js +0 -27
- package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/serialize.js +0 -77
- package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/source-map.js +0 -381
- package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/timers.js +0 -51
- package/bundle/dist/node_modules/.pnpm/chai@6.2.2/node_modules/chai/index.js +0 -2986
- package/bundle/dist/node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/branding.js +0 -10
- package/bundle/dist/node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/index.js +0 -109
- package/bundle/dist/node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/messages.js +0 -10
- package/bundle/dist/node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/overloads.js +0 -10
- package/bundle/dist/node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/utils.js +0 -10
- package/bundle/dist/node_modules/.pnpm/magic-string@0.30.21/node_modules/magic-string/dist/magic-string.es.js +0 -1126
- package/bundle/dist/node_modules/.pnpm/pathe@2.0.3/node_modules/pathe/dist/index.js +0 -21
- package/bundle/dist/node_modules/.pnpm/pathe@2.0.3/node_modules/pathe/dist/shared/pathe.M-eThtNZ.js +0 -432
- package/bundle/dist/node_modules/.pnpm/tinybench@2.9.0/node_modules/tinybench/dist/index.js +0 -517
- package/bundle/dist/node_modules/.pnpm/tinyrainbow@3.1.0/node_modules/tinyrainbow/dist/index.js +0 -101
- package/bundle/dist/node_modules/.pnpm/vite@8.0.3_@emnapi_core@1.11.2_@emnapi_runtime@1.11.2_@types_node@25.0.7_esbuild@0.27.4_5b35fc1fb85d2af4d105e0d74f940f50/node_modules/vite/dist/node/module-runner.js +0 -1265
- package/bundle/dist/node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/chunks/_commonjsHelpers.D26ty3Ew.js +0 -9
- package/bundle/dist/node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/chunks/benchmark.CX_oY03V.js +0 -41
- package/bundle/dist/node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/chunks/evaluatedModules.Dg1zASAC.js +0 -19
- package/bundle/dist/node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/chunks/index.Chj8NDwU.js +0 -202
- package/bundle/dist/node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/chunks/index.DdgEv5B1.js +0 -46
- package/bundle/dist/node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/chunks/rpc.MzXet3jl.js +0 -119
- package/bundle/dist/node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/chunks/test.DNmyFkvJ.js +0 -3044
- package/bundle/dist/node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/chunks/utils.BX5Fg8C4.js +0 -59
- package/bundle/dist/node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/index.js +0 -28
- package/bundle/dist/testing/setup-mocks.js +0 -16
- package/bundle/src/testing/setup-mocks.ts +0 -44
- package/bundle/web-dist/client/assets/index-Bw2s88Ot.css +0 -1
- package/bundle/web-dist/client/assets/index-DZwzUfI-.js +0 -106
- package/bundle/web-dist/client/assets/logs-Cog79DU5.js +0 -1
- package/bundle/web-dist/client/assets/monit-2auznBys.js +0 -1
- package/bundle/web-dist/client/assets/routes-B0lTeLK-.js +0 -5
- package/bundle/web-dist/client/assets/settings-D8ZxZGSJ.js +0 -1
- package/bundle/web-dist/client/assets/show-CFSERlnM.js +0 -2
- package/bundle/web-dist/client/assets/tokens-CZXUyI7O.js +0 -1
- package/bundle/web-dist/client/assets/use-oauth-login-flow-hboOs3wG.js +0 -1
- package/bundle/web-dist/client/assets/use-update-token-mutation-BQHS0byG.js +0 -1
- package/bundle/web-dist/server/assets/use-oauth-login-flow-Gn8flMK5.js +0 -178
- package/dist/cli.d.ts +0 -10
- /package/bundle/web-dist/client/assets/{cost-DH2jZbrw.js → cost-DB3HbU7T.js} +0 -0
- /package/bundle/web-dist/client/assets/{plus-B62CuqT8.js → plus-BsQdY7PS.js} +0 -0
- /package/bundle/web-dist/client/assets/{preload-helper-ca-nBW7U.js → preload-helper-DWTEM3RW.js} +0 -0
- /package/bundle/web-dist/client/assets/{refresh-cw-NNcU0Cmq.js → refresh-cw-D9IUmT23.js} +0 -0
- /package/bundle/web-dist/client/assets/{request-model-CojtinqK.js → request-model-Bpp_rkK8.js} +0 -0
- /package/bundle/web-dist/server/assets/{cost-eEHeTRT5.js → cost-BC9yzyA9.js} +0 -0
|
@@ -11,6 +11,8 @@
|
|
|
11
11
|
* → "Composing Tools With A User Output Schema"
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
+
import { z } from "zod";
|
|
15
|
+
|
|
14
16
|
import {
|
|
15
17
|
SCHEMA_ARRAY_KEYWORDS,
|
|
16
18
|
SCHEMA_DEPENDENCIES_KEYWORD,
|
|
@@ -18,7 +20,11 @@ import {
|
|
|
18
20
|
SCHEMA_SINGLE_KEYWORDS,
|
|
19
21
|
UNSUPPORTED_REFERENCE_KEYWORDS,
|
|
20
22
|
} from "../../utils/providers/common/json-schema-keywords";
|
|
21
|
-
import {
|
|
23
|
+
import {
|
|
24
|
+
isJsonObject,
|
|
25
|
+
type JsonObject,
|
|
26
|
+
type JsonValue,
|
|
27
|
+
} from "../../utils/providers/common/provider-types";
|
|
22
28
|
import { type QgridTool } from "./qgrid.types";
|
|
23
29
|
|
|
24
30
|
const USER_OUTPUT_DEFINITION = "__qgrid_user_output";
|
|
@@ -44,6 +50,7 @@ export function buildToolCallSchema(tools: QgridTool[], answerSchema?: JsonValue
|
|
|
44
50
|
const toolDescriptions = tools
|
|
45
51
|
.map((tool) => {
|
|
46
52
|
const schema = JSON.stringify(tool.inputSchema);
|
|
53
|
+
|
|
47
54
|
return `- ${tool.name}: ${tool.description ?? ""}\n inputSchema: ${schema}`;
|
|
48
55
|
})
|
|
49
56
|
.join("\n");
|
|
@@ -51,7 +58,7 @@ export function buildToolCallSchema(tools: QgridTool[], answerSchema?: JsonValue
|
|
|
51
58
|
const normalizedAnswerSchema =
|
|
52
59
|
answerSchema === undefined ? undefined : rebaseUserOutputSchema(answerSchema);
|
|
53
60
|
|
|
54
|
-
|
|
61
|
+
const envelope: JsonObject = {
|
|
55
62
|
type: "object",
|
|
56
63
|
description:
|
|
57
64
|
"Return exactly one JSON object matching this schema as your final response, including when requesting a tool. This object is the response body, not a call to a built-in tool. To request client-side tools, set result.action to tool_call and include result.toolCalls, then end your turn. The client executes those tools and supplies their results in a later request. Do not invent tool results or emit an answer before receiving the required results.",
|
|
@@ -108,29 +115,28 @@ export function buildToolCallSchema(tools: QgridTool[], answerSchema?: JsonValue
|
|
|
108
115
|
},
|
|
109
116
|
required: ["result"],
|
|
110
117
|
additionalProperties: false,
|
|
111
|
-
...(normalizedAnswerSchema === undefined
|
|
112
|
-
? {}
|
|
113
|
-
: {
|
|
114
|
-
$defs: {
|
|
115
|
-
[USER_OUTPUT_DEFINITION]: normalizedAnswerSchema,
|
|
116
|
-
},
|
|
117
|
-
}),
|
|
118
118
|
};
|
|
119
|
+
|
|
120
|
+
if (normalizedAnswerSchema !== undefined) {
|
|
121
|
+
envelope.$defs = { [USER_OUTPUT_DEFINITION]: normalizedAnswerSchema };
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return envelope;
|
|
119
125
|
}
|
|
120
126
|
|
|
121
127
|
function rebaseUserOutputSchema(schema: JsonValue): JsonValue {
|
|
122
|
-
return rewriteSchemaNode(schema, "$");
|
|
128
|
+
return rewriteSchemaNode(schema, "$") ?? schema;
|
|
123
129
|
}
|
|
124
130
|
|
|
125
131
|
const MAP_KEYWORDS = new Set<string>(SCHEMA_MAP_KEYWORDS);
|
|
126
132
|
const ARRAY_KEYWORDS = new Set<string>(SCHEMA_ARRAY_KEYWORDS);
|
|
127
133
|
const SINGLE_KEYWORDS = new Set<string>(SCHEMA_SINGLE_KEYWORDS);
|
|
128
134
|
|
|
129
|
-
function rewriteSchemaNode(value: JsonValue, path: string): JsonValue {
|
|
130
|
-
if (
|
|
135
|
+
function rewriteSchemaNode(value: JsonValue | undefined, path: string): JsonValue | undefined {
|
|
136
|
+
if (!isJsonObject(value)) return value;
|
|
131
137
|
|
|
132
|
-
const source = value
|
|
133
|
-
const result:
|
|
138
|
+
const source = value;
|
|
139
|
+
const result: JsonObject = { ...source };
|
|
134
140
|
|
|
135
141
|
for (const unsupportedKeyword of UNSUPPORTED_REFERENCE_KEYWORDS) {
|
|
136
142
|
if (Object.hasOwn(source, unsupportedKeyword)) {
|
|
@@ -142,13 +148,15 @@ function rewriteSchemaNode(value: JsonValue, path: string): JsonValue {
|
|
|
142
148
|
}
|
|
143
149
|
|
|
144
150
|
if ("$ref" in source) {
|
|
145
|
-
const ref = source.$ref;
|
|
146
|
-
|
|
151
|
+
const ref = z.string().safeParse(source.$ref).data;
|
|
152
|
+
|
|
153
|
+
if (ref === undefined || (ref !== "#" && !ref.startsWith("#/"))) {
|
|
147
154
|
throw new ToolSchemaCompositionError(
|
|
148
155
|
"only root-relative JSON Pointer $ref values are supported",
|
|
149
156
|
`${path}.$ref`,
|
|
150
157
|
);
|
|
151
158
|
}
|
|
159
|
+
|
|
152
160
|
result.$ref = `${USER_OUTPUT_REF}${ref.slice(1)}`;
|
|
153
161
|
}
|
|
154
162
|
|
|
@@ -161,7 +169,7 @@ function rewriteSchemaNode(value: JsonValue, path: string): JsonValue {
|
|
|
161
169
|
name,
|
|
162
170
|
rewriteSchemaNode(schema, `${keywordPath}.${name}`),
|
|
163
171
|
]),
|
|
164
|
-
)
|
|
172
|
+
);
|
|
165
173
|
} else if (keyword === SCHEMA_DEPENDENCIES_KEYWORD && isJsonObject(child)) {
|
|
166
174
|
result[keyword] = Object.fromEntries(
|
|
167
175
|
Object.entries(child).map(([name, dependency]) => [
|
|
@@ -170,25 +178,21 @@ function rewriteSchemaNode(value: JsonValue, path: string): JsonValue {
|
|
|
170
178
|
? dependency
|
|
171
179
|
: rewriteSchemaNode(dependency, `${keywordPath}.${name}`),
|
|
172
180
|
]),
|
|
173
|
-
)
|
|
181
|
+
);
|
|
174
182
|
} else if (ARRAY_KEYWORDS.has(keyword) && Array.isArray(child)) {
|
|
175
|
-
result[keyword] = child.map(
|
|
176
|
-
rewriteSchemaNode(schema, `${keywordPath}[${index}]`),
|
|
177
|
-
)
|
|
183
|
+
result[keyword] = child.map(
|
|
184
|
+
(schema, index) => rewriteSchemaNode(schema, `${keywordPath}[${index}]`) ?? schema,
|
|
185
|
+
);
|
|
178
186
|
} else if (SINGLE_KEYWORDS.has(keyword)) {
|
|
179
187
|
if (keyword === "items" && Array.isArray(child)) {
|
|
180
|
-
result[keyword] = child.map(
|
|
181
|
-
rewriteSchemaNode(schema, `${keywordPath}[${index}]`),
|
|
182
|
-
)
|
|
188
|
+
result[keyword] = child.map(
|
|
189
|
+
(schema, index) => rewriteSchemaNode(schema, `${keywordPath}[${index}]`) ?? schema,
|
|
190
|
+
);
|
|
183
191
|
} else {
|
|
184
192
|
result[keyword] = rewriteSchemaNode(child, keywordPath);
|
|
185
193
|
}
|
|
186
194
|
}
|
|
187
195
|
}
|
|
188
196
|
|
|
189
|
-
return result
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
function isJsonObject(value: JsonValue): value is Record<string, JsonValue> {
|
|
193
|
-
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
197
|
+
return result;
|
|
194
198
|
}
|
|
@@ -3,6 +3,8 @@ import { Buffer } from "node:buffer";
|
|
|
3
3
|
import { getLogger } from "@logtape/logtape";
|
|
4
4
|
import { z } from "zod";
|
|
5
5
|
|
|
6
|
+
import { type JsonValue } from "../../utils/providers/common/provider-types";
|
|
7
|
+
|
|
6
8
|
// 응답(모델 출력) envelope 의 자원 한도. caller 스키마 전처리 한도(CALLER_SCHEMA_LIMITS)와 값이
|
|
7
9
|
// 같아 보여도 서로 다른 자원을 지키는 독립 상수다 — 스키마 깊이는 인스턴스 깊이를 bound 하지
|
|
8
10
|
// 않으므로(재귀 $ref 허용) 캘러 한도를 조정해도 응답 수용 기준이 따라 움직여선 안 된다.
|
|
@@ -11,6 +13,7 @@ const STRUCTURED_ENVELOPE_LIMITS = {
|
|
|
11
13
|
maxNodes: 20_000,
|
|
12
14
|
maxDepth: 132,
|
|
13
15
|
} as const;
|
|
16
|
+
|
|
14
17
|
import {
|
|
15
18
|
type ImageGenerationMetadata,
|
|
16
19
|
type QgridContent,
|
|
@@ -22,6 +25,7 @@ import {
|
|
|
22
25
|
const logger = getLogger(["qgrid", "tool-emulation"]);
|
|
23
26
|
|
|
24
27
|
type EmulationResult = Omit<QueryOutput, "content" | "finishReason" | "runContext">;
|
|
28
|
+
|
|
25
29
|
type ToolCall = { toolName: string; args: string };
|
|
26
30
|
|
|
27
31
|
// envelope 는 {result: <union>} 한 겹 구조 — 스키마 근거는 tool-emulation-schema.ts 참조.
|
|
@@ -58,6 +62,7 @@ function buildEnvelopeSchema(answerKind: AnswerKind) {
|
|
|
58
62
|
|
|
59
63
|
const TEXT_ENVELOPE = buildEnvelopeSchema("text");
|
|
60
64
|
const JSON_ENVELOPE = buildEnvelopeSchema("json");
|
|
65
|
+
|
|
61
66
|
type EnvelopeResponse = z.infer<typeof JSON_ENVELOPE>["result"];
|
|
62
67
|
|
|
63
68
|
export class ToolCallEmulationError extends Error {
|
|
@@ -99,18 +104,23 @@ export function applyToolCallEmulation(
|
|
|
99
104
|
}
|
|
100
105
|
|
|
101
106
|
const parsed = parseEnvelope(result.text, tools, answerKind);
|
|
107
|
+
|
|
102
108
|
if (parsed.action === "tool_call") {
|
|
103
109
|
return toolCallOutput(result, parsed.toolCalls, images, runContext);
|
|
104
110
|
}
|
|
105
111
|
|
|
106
112
|
return answerOutput(
|
|
107
113
|
result,
|
|
108
|
-
answerKind === "text" ? (parsed.answer
|
|
114
|
+
answerKind === "text" ? z.string().parse(parsed.answer) : JSON.stringify(parsed.answer),
|
|
109
115
|
images,
|
|
110
116
|
runContext,
|
|
111
117
|
);
|
|
112
118
|
}
|
|
113
119
|
|
|
120
|
+
const commentaryToolCallControl = z.looseObject({
|
|
121
|
+
result: z.looseObject({ action: z.literal("tool_call") }),
|
|
122
|
+
});
|
|
123
|
+
|
|
114
124
|
export function isToolCallEnvelope(
|
|
115
125
|
text: string,
|
|
116
126
|
tools: QgridTool[],
|
|
@@ -120,23 +130,17 @@ export function isToolCallEnvelope(
|
|
|
120
130
|
if (phase === "commentary") {
|
|
121
131
|
// Commentary is not the structured answer. Only an explicit tool control
|
|
122
132
|
// object is eligible, and that object must still pass the strict parser.
|
|
123
|
-
let value:
|
|
133
|
+
let value: JsonValue;
|
|
134
|
+
|
|
124
135
|
try {
|
|
125
136
|
value = JSON.parse(text);
|
|
126
137
|
} catch {
|
|
127
138
|
return false;
|
|
128
139
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
typeof value !== "object" ||
|
|
132
|
-
!("result" in value) ||
|
|
133
|
-
!value.result ||
|
|
134
|
-
typeof value.result !== "object" ||
|
|
135
|
-
!("action" in value.result) ||
|
|
136
|
-
value.result.action !== "tool_call"
|
|
137
|
-
)
|
|
138
|
-
return false;
|
|
140
|
+
|
|
141
|
+
if (!commentaryToolCallControl.safeParse(value).success) return false;
|
|
139
142
|
}
|
|
143
|
+
|
|
140
144
|
return parseEnvelope(text, tools, answerKind).action === "tool_call";
|
|
141
145
|
}
|
|
142
146
|
|
|
@@ -147,7 +151,9 @@ function parseEnvelope(text: string, tools: QgridTool[], answerKind: AnswerKind)
|
|
|
147
151
|
);
|
|
148
152
|
}
|
|
149
153
|
|
|
150
|
-
|
|
154
|
+
// JSON.parse without a reviver yields only JSON values.
|
|
155
|
+
let value: JsonValue;
|
|
156
|
+
|
|
151
157
|
try {
|
|
152
158
|
value = JSON.parse(text);
|
|
153
159
|
} catch (error) {
|
|
@@ -159,15 +165,18 @@ function parseEnvelope(text: string, tools: QgridTool[], answerKind: AnswerKind)
|
|
|
159
165
|
// 진단에는 위반 원문의 머리가 필요하다(SON-495 전례) — parse 에러 위치만으로는
|
|
160
166
|
// "프로즈로 답했는지 / 펜스가 남았는지 / JSON 이 잘렸는지"를 구분할 수 없다.
|
|
161
167
|
const head = JSON.stringify(text.slice(0, 200));
|
|
162
|
-
logger.warn(
|
|
168
|
+
logger.warn(
|
|
169
|
+
`tool envelope parse failed: ${error instanceof Error ? error.message : String(error)}; head=${head}`,
|
|
170
|
+
);
|
|
163
171
|
throw new ToolCallEmulationError(
|
|
164
|
-
`invalid tool envelope (response is not JSON — the model ignored the envelope contract; retry is the caller's decision): ${
|
|
172
|
+
`invalid tool envelope (response is not JSON — the model ignored the envelope contract; retry is the caller's decision): ${error instanceof Error ? error.message : String(error)}; response head: ${head}`,
|
|
165
173
|
);
|
|
166
174
|
}
|
|
167
175
|
|
|
168
176
|
assertStructuredEnvelopeComplexity(value);
|
|
169
177
|
const schema = answerKind === "text" ? TEXT_ENVELOPE : JSON_ENVELOPE;
|
|
170
178
|
const validation = schema.safeParse(value);
|
|
179
|
+
|
|
171
180
|
if (!validation.success) {
|
|
172
181
|
const issue = validation.error.issues[0];
|
|
173
182
|
const path = issue && issue.path.length > 0 ? ` at ${issue.path.join(".")}` : "";
|
|
@@ -181,15 +190,19 @@ function parseEnvelope(text: string, tools: QgridTool[], answerKind: AnswerKind)
|
|
|
181
190
|
);
|
|
182
191
|
}
|
|
183
192
|
|
|
184
|
-
//
|
|
185
|
-
//
|
|
193
|
+
// SAFETY: schema.safeParse(value) succeeded above, so value matches { result: EnvelopeResponse }.
|
|
194
|
+
// Zod clones JSON objects and drops own "__proto__" keys, so the validated raw value is returned
|
|
195
|
+
// to preserve the caller's exact structured answer.
|
|
186
196
|
const response = (value as { result: EnvelopeResponse }).result;
|
|
197
|
+
|
|
187
198
|
if (response.action === "tool_call") {
|
|
188
199
|
const unknownTool = findUnknownTool(response.toolCalls, tools);
|
|
200
|
+
|
|
189
201
|
if (unknownTool !== undefined) {
|
|
190
202
|
throw new ToolCallEmulationError(`unknown emulated tool: ${unknownTool}`);
|
|
191
203
|
}
|
|
192
204
|
}
|
|
205
|
+
|
|
193
206
|
return response;
|
|
194
207
|
}
|
|
195
208
|
|
|
@@ -232,47 +245,59 @@ function answerOutput(
|
|
|
232
245
|
|
|
233
246
|
function findUnknownTool(toolCalls: ToolCall[], tools: QgridTool[]): string | undefined {
|
|
234
247
|
const knownToolNames = new Set(tools.map((tool) => tool.name));
|
|
248
|
+
|
|
235
249
|
return toolCalls.find((toolCall) => !knownToolNames.has(toolCall.toolName))?.toolName;
|
|
236
250
|
}
|
|
237
251
|
|
|
238
252
|
function appendImages(content: QgridContent[], images?: EmulationImage[]): QgridContent[] {
|
|
239
253
|
if (!images?.length) return content;
|
|
254
|
+
|
|
240
255
|
return [
|
|
241
256
|
...content,
|
|
242
|
-
...images.map(
|
|
243
|
-
|
|
257
|
+
...images.map((image): QgridContent => {
|
|
258
|
+
const part: Extract<QgridContent, { type: "image" }> = {
|
|
244
259
|
type: "image",
|
|
245
260
|
data: image.data,
|
|
246
|
-
...(image.mediaType ? { mediaType: image.mediaType } : {}),
|
|
247
261
|
revisedPrompt: image.revisedPrompt ?? null,
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
if (image.mediaType) part.mediaType = image.mediaType;
|
|
265
|
+
|
|
266
|
+
if (image.generation) part.generation = image.generation;
|
|
267
|
+
|
|
268
|
+
return part;
|
|
269
|
+
}),
|
|
251
270
|
];
|
|
252
271
|
}
|
|
253
272
|
|
|
254
|
-
function assertStructuredEnvelopeComplexity(root:
|
|
273
|
+
function assertStructuredEnvelopeComplexity(root: JsonValue): void {
|
|
255
274
|
const maxDepth = STRUCTURED_ENVELOPE_LIMITS.maxDepth;
|
|
256
|
-
const stack = [{ value: root, depth: 0 }];
|
|
275
|
+
const stack: Array<{ value: JsonValue | undefined; depth: number }> = [{ value: root, depth: 0 }];
|
|
257
276
|
let nodes = 0;
|
|
258
277
|
|
|
259
278
|
while (stack.length > 0) {
|
|
260
279
|
const current = stack.pop()!;
|
|
261
280
|
nodes += 1;
|
|
281
|
+
|
|
262
282
|
if (nodes > STRUCTURED_ENVELOPE_LIMITS.maxNodes) {
|
|
263
283
|
throw new ToolCallEmulationError(
|
|
264
284
|
`structured-output envelope exceeds node limit of ${STRUCTURED_ENVELOPE_LIMITS.maxNodes}`,
|
|
265
285
|
);
|
|
266
286
|
}
|
|
287
|
+
|
|
267
288
|
if (current.depth > maxDepth) {
|
|
268
289
|
throw new ToolCallEmulationError(
|
|
269
290
|
`structured-output envelope exceeds depth limit of ${maxDepth}`,
|
|
270
291
|
);
|
|
271
292
|
}
|
|
272
|
-
|
|
293
|
+
|
|
294
|
+
// JSON.parse turns out-of-range literals such as 1e999 into ±Infinity; it never yields NaN.
|
|
295
|
+
if (current.value === Infinity || current.value === -Infinity) {
|
|
273
296
|
throw new ToolCallEmulationError("answer must be valid JSON");
|
|
274
297
|
}
|
|
275
|
-
|
|
298
|
+
|
|
299
|
+
// Only JSON arrays and objects are Object instances; primitives and null are leaves.
|
|
300
|
+
if (!(current.value instanceof Object)) continue;
|
|
276
301
|
|
|
277
302
|
for (const value of Object.values(current.value)) {
|
|
278
303
|
stack.push({ value, depth: current.depth + 1 });
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { describe, expect, it } from "vitest";
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
|
-
|
|
4
|
+
renderJsonSchemaZodText,
|
|
5
5
|
renderJsonSchemaTypeText,
|
|
6
6
|
renderParsedJsonSchemaTypeText,
|
|
7
7
|
} from "./json-schema-type-text";
|
|
@@ -133,10 +133,10 @@ describe("renderJsonSchemaTypeText", () => {
|
|
|
133
133
|
});
|
|
134
134
|
});
|
|
135
135
|
|
|
136
|
-
describe("
|
|
136
|
+
describe("renderJsonSchemaZodText", () => {
|
|
137
137
|
it("renders a compact object shape with required, optional, and default annotations", () => {
|
|
138
138
|
expect(
|
|
139
|
-
|
|
139
|
+
renderJsonSchemaZodText(
|
|
140
140
|
{
|
|
141
141
|
type: "object",
|
|
142
142
|
properties: {
|
|
@@ -159,7 +159,7 @@ describe("renderJsonSchemaZodShapeText", () => {
|
|
|
159
159
|
|
|
160
160
|
it("shortens long string enums with an inline remainder comment", () => {
|
|
161
161
|
expect(
|
|
162
|
-
|
|
162
|
+
renderJsonSchemaZodText(
|
|
163
163
|
{
|
|
164
164
|
type: "object",
|
|
165
165
|
properties: {
|
|
@@ -180,7 +180,7 @@ describe("renderJsonSchemaZodShapeText", () => {
|
|
|
180
180
|
|
|
181
181
|
it("renders nested objects, arrays, unions, literals, and unknown nodes", () => {
|
|
182
182
|
expect(
|
|
183
|
-
|
|
183
|
+
renderJsonSchemaZodText({
|
|
184
184
|
type: "object",
|
|
185
185
|
properties: {
|
|
186
186
|
filters: {
|
|
@@ -7,7 +7,13 @@
|
|
|
7
7
|
* 모르는 키워드는 unknown 으로 접어 절대 던지지 않는다.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
import { z } from "zod";
|
|
11
|
+
|
|
12
|
+
import {
|
|
13
|
+
isJsonObject,
|
|
14
|
+
type JsonObject,
|
|
15
|
+
type JsonValue,
|
|
16
|
+
} from "../../utils/providers/common/provider-types";
|
|
11
17
|
|
|
12
18
|
/** TS/zod 표시 코드 공용 식별자 판별 — zod-code-format 의 키 unquote 도 이걸 쓴다. */
|
|
13
19
|
export const IDENT_SOURCE = "[A-Za-z_$][\\w$]*";
|
|
@@ -17,90 +23,127 @@ function renderKey(key: string): string {
|
|
|
17
23
|
return IDENT_RE.test(key) ? key : JSON.stringify(key);
|
|
18
24
|
}
|
|
19
25
|
|
|
20
|
-
function renderPrimitive(type:
|
|
26
|
+
function renderPrimitive(type: JsonValue | undefined): string {
|
|
21
27
|
if (type === "string") return "string";
|
|
28
|
+
|
|
22
29
|
if (type === "number" || type === "integer") return "number";
|
|
30
|
+
|
|
23
31
|
if (type === "boolean") return "boolean";
|
|
32
|
+
|
|
24
33
|
if (type === "null") return "null";
|
|
34
|
+
|
|
25
35
|
return "unknown";
|
|
26
36
|
}
|
|
27
37
|
|
|
28
|
-
function renderZodPrimitive(type:
|
|
38
|
+
function renderZodPrimitive(type: JsonValue | undefined): string {
|
|
29
39
|
if (type === "string") return "z.string()";
|
|
40
|
+
|
|
30
41
|
if (type === "number" || type === "integer") return "z.number()";
|
|
42
|
+
|
|
31
43
|
if (type === "boolean") return "z.boolean()";
|
|
44
|
+
|
|
32
45
|
if (type === "null") return "z.null()";
|
|
46
|
+
|
|
33
47
|
return "z.unknown()";
|
|
34
48
|
}
|
|
35
49
|
|
|
36
|
-
function renderZodEnum(values:
|
|
50
|
+
function renderZodEnum(values: JsonValue[], enumValueLimit?: number): string {
|
|
37
51
|
if (values.length === 0) return "z.never()";
|
|
38
52
|
|
|
39
53
|
const visibleValues =
|
|
40
54
|
enumValueLimit === undefined ? values : values.slice(0, Math.max(0, enumValueLimit));
|
|
55
|
+
|
|
41
56
|
const omittedCount = values.length - visibleValues.length;
|
|
42
57
|
const suffix = omittedCount > 0 ? ` /* +${omittedCount} */` : "";
|
|
43
58
|
|
|
44
|
-
if (values.every((value) =>
|
|
59
|
+
if (values.every((value) => z.string().safeParse(value).success)) {
|
|
45
60
|
return `z.enum([${visibleValues.map((value) => JSON.stringify(value)).join(", ")}${suffix}])`;
|
|
46
61
|
}
|
|
47
62
|
|
|
48
63
|
const literals = visibleValues.map((value) => `z.literal(${JSON.stringify(value)})`);
|
|
64
|
+
|
|
49
65
|
if (literals.length === 1 && omittedCount === 0) return literals[0] ?? "z.never()";
|
|
66
|
+
|
|
50
67
|
return `z.union([${literals.join(", ")}${suffix}])`;
|
|
51
68
|
}
|
|
52
69
|
|
|
53
|
-
function
|
|
70
|
+
function schemaProperties(schema: JsonObject): JsonObject {
|
|
71
|
+
return isJsonObject(schema.properties) ? schema.properties : {};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function requiredKeys(schema: JsonObject): Set<string> {
|
|
75
|
+
const required = schema.required;
|
|
76
|
+
|
|
77
|
+
return new Set(
|
|
78
|
+
Array.isArray(required) ? required.flatMap((key) => z.string().safeParse(key).data ?? []) : [],
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function renderZodNode(
|
|
83
|
+
node: JsonValue | undefined,
|
|
84
|
+
depth: number,
|
|
85
|
+
enumValueLimit?: number,
|
|
86
|
+
): string {
|
|
54
87
|
if (node === true) return "z.unknown()";
|
|
55
|
-
|
|
56
|
-
|
|
88
|
+
|
|
89
|
+
if (!isJsonObject(node)) return "z.unknown()";
|
|
90
|
+
const schema = node;
|
|
57
91
|
|
|
58
92
|
if (Array.isArray(schema.enum)) return renderZodEnum(schema.enum, enumValueLimit);
|
|
93
|
+
|
|
59
94
|
if (schema.const !== undefined) return `z.literal(${JSON.stringify(schema.const)})`;
|
|
60
95
|
|
|
61
|
-
const variants =
|
|
96
|
+
const variants = schema.anyOf ?? schema.oneOf;
|
|
97
|
+
|
|
62
98
|
if (Array.isArray(variants) && variants.length > 0) {
|
|
63
99
|
const rendered = [
|
|
64
100
|
...new Set(variants.map((variant) => renderZodNode(variant, depth, enumValueLimit))),
|
|
65
101
|
];
|
|
102
|
+
|
|
66
103
|
return rendered.length === 1
|
|
67
104
|
? (rendered[0] ?? "z.unknown()")
|
|
68
105
|
: `z.union([${rendered.join(", ")}])`;
|
|
69
106
|
}
|
|
70
107
|
|
|
71
108
|
const type = schema.type;
|
|
109
|
+
|
|
72
110
|
if (Array.isArray(type)) {
|
|
73
111
|
const rendered = [...new Set(type.map(renderZodPrimitive))];
|
|
112
|
+
|
|
74
113
|
return rendered.length === 1
|
|
75
114
|
? (rendered[0] ?? "z.unknown()")
|
|
76
115
|
: `z.union([${rendered.join(", ")}])`;
|
|
77
116
|
}
|
|
78
117
|
|
|
79
118
|
if (type === "object" || (type === undefined && schema.properties)) {
|
|
80
|
-
const properties = (schema
|
|
81
|
-
const required =
|
|
119
|
+
const properties = schemaProperties(schema);
|
|
120
|
+
const required = requiredKeys(schema);
|
|
82
121
|
const keys = Object.keys(properties);
|
|
122
|
+
|
|
83
123
|
if (keys.length === 0) return "z.object({})";
|
|
124
|
+
|
|
84
125
|
const orderedKeys = [
|
|
85
126
|
...keys.filter((key) => required.has(key)),
|
|
86
127
|
...keys.filter((key) => !required.has(key)),
|
|
87
128
|
];
|
|
88
129
|
|
|
89
130
|
const inner = " ".repeat(depth + 1);
|
|
131
|
+
|
|
90
132
|
const lines = orderedKeys.map((key) => {
|
|
91
133
|
const propertySchema = properties[key];
|
|
92
134
|
const rendered = renderZodNode(propertySchema, depth + 1, enumValueLimit);
|
|
93
135
|
const optional = required.has(key) ? rendered : `${rendered}.optional()`;
|
|
136
|
+
|
|
94
137
|
const defaultValue =
|
|
95
|
-
propertySchema &&
|
|
96
|
-
|
|
97
|
-
!Array.isArray(propertySchema) &&
|
|
98
|
-
Object.hasOwn(propertySchema, "default")
|
|
99
|
-
? JSON.stringify((propertySchema as SchemaNode).default)
|
|
138
|
+
isJsonObject(propertySchema) && Object.hasOwn(propertySchema, "default")
|
|
139
|
+
? JSON.stringify(propertySchema.default)
|
|
100
140
|
: undefined;
|
|
141
|
+
|
|
101
142
|
const defaultComment = defaultValue === undefined ? "" : ` // default=${defaultValue}`;
|
|
143
|
+
|
|
102
144
|
return `${inner}${renderKey(key)}: ${optional},${defaultComment}`;
|
|
103
145
|
});
|
|
146
|
+
|
|
104
147
|
return `z.object({\n${lines.join("\n")}\n${" ".repeat(depth)}})`;
|
|
105
148
|
}
|
|
106
149
|
|
|
@@ -111,43 +154,52 @@ function renderZodNode(node: unknown, depth: number, enumValueLimit?: number): s
|
|
|
111
154
|
return renderZodPrimitive(type);
|
|
112
155
|
}
|
|
113
156
|
|
|
114
|
-
function renderNode(node:
|
|
157
|
+
function renderNode(node: JsonValue | undefined, depth: number): string {
|
|
115
158
|
if (node === true) return "unknown";
|
|
116
|
-
|
|
117
|
-
|
|
159
|
+
|
|
160
|
+
if (!isJsonObject(node)) return "unknown";
|
|
161
|
+
const schema = node;
|
|
118
162
|
|
|
119
163
|
if (Array.isArray(schema.enum)) {
|
|
120
164
|
return schema.enum.map((value) => JSON.stringify(value)).join(" | ");
|
|
121
165
|
}
|
|
166
|
+
|
|
122
167
|
if (schema.const !== undefined) return JSON.stringify(schema.const);
|
|
123
168
|
|
|
124
|
-
const variants =
|
|
169
|
+
const variants = schema.anyOf ?? schema.oneOf;
|
|
170
|
+
|
|
125
171
|
if (Array.isArray(variants) && variants.length > 0) {
|
|
126
172
|
return [...new Set(variants.map((variant) => renderNode(variant, depth)))].join(" | ");
|
|
127
173
|
}
|
|
128
174
|
|
|
129
175
|
const type = schema.type;
|
|
176
|
+
|
|
130
177
|
if (Array.isArray(type)) {
|
|
131
178
|
return [...new Set(type.map(renderPrimitive))].join(" | ");
|
|
132
179
|
}
|
|
133
180
|
|
|
134
181
|
if (type === "object" || (type === undefined && schema.properties)) {
|
|
135
|
-
const properties = (schema
|
|
136
|
-
const required =
|
|
182
|
+
const properties = schemaProperties(schema);
|
|
183
|
+
const required = requiredKeys(schema);
|
|
137
184
|
const keys = Object.keys(properties);
|
|
185
|
+
|
|
138
186
|
if (keys.length === 0) return "Record<string, unknown>";
|
|
139
187
|
const inner = " ".repeat(depth + 1);
|
|
188
|
+
|
|
140
189
|
const lines = keys.map(
|
|
141
190
|
(key) =>
|
|
142
191
|
`${inner}${renderKey(key)}${required.has(key) ? "" : "?"}: ${renderNode(properties[key], depth + 1)}`,
|
|
143
192
|
);
|
|
193
|
+
|
|
144
194
|
return `{\n${lines.join("\n")}\n${" ".repeat(depth)}}`;
|
|
145
195
|
}
|
|
146
196
|
|
|
147
197
|
if (type === "array") {
|
|
148
198
|
const item = renderNode(schema.items, depth);
|
|
199
|
+
|
|
149
200
|
// 유니온 요소는 괄호가 없으면 `A | B[]` 로 잘못 읽힌다.
|
|
150
201
|
if (item.includes(" | ")) return `(${item})[]`;
|
|
202
|
+
|
|
151
203
|
return `${item}[]`;
|
|
152
204
|
}
|
|
153
205
|
|
|
@@ -155,19 +207,22 @@ function renderNode(node: unknown, depth: number): string {
|
|
|
155
207
|
}
|
|
156
208
|
|
|
157
209
|
/** 이미 파싱된 스키마 값용 — 호출부가 같은 JSON 을 두 번 파싱하지 않게 한다. */
|
|
158
|
-
export function renderParsedJsonSchemaTypeText(schema:
|
|
210
|
+
export function renderParsedJsonSchemaTypeText(schema: JsonValue, name = "Response"): string {
|
|
159
211
|
return `type ${name} = ${renderNode(schema, 0)}`;
|
|
160
212
|
}
|
|
161
213
|
|
|
162
|
-
/** Tool input 계약용 표시 전용 Zod
|
|
163
|
-
export function
|
|
214
|
+
/** Tool input 계약용 표시 전용 Zod 코드. 검증 제약은 의도적으로 생략한다. */
|
|
215
|
+
export function renderJsonSchemaZodText(schema: JsonValue, enumValueLimit?: number): string {
|
|
164
216
|
return renderZodNode(schema, 0, enumValueLimit);
|
|
165
217
|
}
|
|
166
218
|
|
|
167
219
|
/** 실패(파싱 불가 등) 시 null — 호출부가 표시 자체를 생략한다. */
|
|
168
220
|
export function renderJsonSchemaTypeText(schemaJson: string, name = "Response"): string | null {
|
|
169
221
|
try {
|
|
170
|
-
|
|
222
|
+
// JSON.parse without a reviver yields only JSON values.
|
|
223
|
+
const schema: JsonValue = JSON.parse(schemaJson);
|
|
224
|
+
|
|
225
|
+
return renderParsedJsonSchemaTypeText(schema, name);
|
|
171
226
|
} catch {
|
|
172
227
|
return null;
|
|
173
228
|
}
|