@cartanova/qgrid-cli 2.3.8 → 2.4.0
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 +131 -0
- package/README.md +60 -44
- package/bundle/web-dist/client/assets/{index-OQd6CclQ.js → index-DVdnvcvo.js} +3 -3
- package/bundle/web-dist/client/assets/{logs-8T91eoLY.js → logs-B82PGnxD.js} +1 -1
- package/bundle/web-dist/client/assets/{routes--GqHRT2A.js → routes-CvCEcpZ7.js} +1 -1
- package/bundle/web-dist/client/assets/{show-cHMucIDC.js → show-DWRh--ML.js} +1 -1
- package/bundle/web-dist/client/assets/{tokens-BXAJUeCJ.js → tokens-DOu_ZFUL.js} +1 -1
- package/bundle/web-dist/client/index.html +1 -1
- package/bundle/web-dist/server/entry-server.generated.js +1 -1
- package/dist/cli.js +86 -5
- package/package.json +7 -3
- package/postinstall.mjs +119 -0
- package/skills/qgrid/SKILL.md +54 -0
- package/skills/qgrid/agents/openai.yaml +4 -0
- package/skills/qgrid/references/ai-sdk-provider-contract.md +100 -0
- package/skills/qgrid/references/anthropic-claude-code-runtime.md +170 -0
- package/skills/qgrid/references/cli-env-and-server-boot.md +68 -0
- package/skills/qgrid/references/decision-rationale.md +179 -0
- package/skills/qgrid/references/docs-workflow.md +32 -0
- package/skills/qgrid/references/openai-codex-runtime.md +153 -0
- package/skills/qgrid/references/prompt-cache-and-usage.md +101 -0
- package/skills/qgrid/references/provider-runtime-differences.md +54 -0
- package/skills/qgrid/references/repo-map.md +37 -0
- package/skills/qgrid/references/request-log-run-lifecycle.md +76 -0
- package/skills/qgrid/references/sonamu-api-web-flow.md +47 -0
- package/skills/qgrid/references/token-auth-quota-lifecycle.md +205 -0
- package/skills/qgrid/references/tool-calling-and-multiturn.md +144 -0
- package/skills/qgrid/references/verification-and-debugging.md +193 -0
- package/bundle/dist/migrations/20260705140615_alter_request_log_steps_alter1.js +0 -14
- package/bundle/src/migrations/20260705140615_alter_request_log_steps_alter1.ts +0 -13
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
# Decision Rationale
|
|
2
|
+
|
|
3
|
+
Use this reference when the question is "why is qgrid designed this way?" or before changing an established runtime contract. Current code is the source of truth for behavior; repo docs are the source of truth for the decision trail.
|
|
4
|
+
|
|
5
|
+
Do not copy these notes blindly into implementation. Use them to find the relevant docs, then inspect the current code and tests.
|
|
6
|
+
|
|
7
|
+
## Contents
|
|
8
|
+
|
|
9
|
+
- AI SDK provider boundary
|
|
10
|
+
- Tool calling and request-log lifecycle
|
|
11
|
+
- OpenAI/Codex runtime
|
|
12
|
+
- Anthropic/Claude Code runtime
|
|
13
|
+
- Token sync and quota thresholds
|
|
14
|
+
- Request logs, metrics, and dashboard
|
|
15
|
+
- CLI packaging and server boot
|
|
16
|
+
- Image generation
|
|
17
|
+
|
|
18
|
+
## AI SDK Provider Boundary
|
|
19
|
+
|
|
20
|
+
Sources:
|
|
21
|
+
|
|
22
|
+
- `docs/plans/2026-05-07-feat-qgrid-ai-sdk-provider-plan.md`
|
|
23
|
+
- `docs/solutions/conventions/qgrid-provider-options-boundary.md`
|
|
24
|
+
- `docs/plans/2026-05-26-refactor-ai-sdk-wrapper-correlation-boundary-plan.md`
|
|
25
|
+
|
|
26
|
+
Key decisions:
|
|
27
|
+
|
|
28
|
+
- `packages/ai-sdk` is the active public SDK. `packages/sdk` is deprecated and should be read only for legacy context.
|
|
29
|
+
- qgrid's AI SDK provider follows the AI SDK `LanguageModelV3` contract. Generic usage belongs to AI SDK docs; qgrid-specific docs should focus on qgrid routing, logging, cache/session behavior, and `providerOptions.qgrid`.
|
|
30
|
+
- qgrid-specific options live under `providerOptions.qgrid`, not under provider-specific namespaces such as `providerOptions.openai`. Consumers should not need to branch on Codex versus Claude internals.
|
|
31
|
+
- `projectName` is provider config/payload camelCase. `project_name` is the Sonamu/database request-log column. Prefer `QGRID_PROJECT_NAME` as the project-wide default so request logs and metrics remain filterable at volume.
|
|
32
|
+
- `fallbackModels` may exist as a typed future option, but it is not a server wire contract until the server implements fallback routing. Do not forward it as behavior just because the type exists.
|
|
33
|
+
- The SDK should stay a thin adapter. Server APIs own request-log lifecycle, provider dispatch, structured-output emulation, and provider runtime details.
|
|
34
|
+
|
|
35
|
+
## Tool Calling And Request-Log Lifecycle
|
|
36
|
+
|
|
37
|
+
Sources:
|
|
38
|
+
|
|
39
|
+
- `docs/plans/2026-05-07-feat-qgrid-ai-sdk-provider-plan.md`
|
|
40
|
+
- `docs/plans/2026-05-20-feat-request-log-run-lifecycle-api-plan.md`
|
|
41
|
+
- `docs/plans/2026-05-26-refactor-ai-sdk-wrapper-correlation-boundary-plan.md`
|
|
42
|
+
- `docs/solutions/tooling-decisions/anthropic-structured-stream-keep-required-and-fail-honestly.md`
|
|
43
|
+
|
|
44
|
+
Key decisions:
|
|
45
|
+
|
|
46
|
+
- qgrid tool calling is intentionally implemented through structured-output emulation, not native provider tool use. The provider call returns a structured action with tool calls; the AI SDK loop executes tools and sends follow-up turns.
|
|
47
|
+
- Tools and `jsonSchema` are mutually exclusive at the qgrid dispatcher boundary because both need the provider structured-output slot.
|
|
48
|
+
- Tool-call request logs are a multi-step run: create run, append generate/tool steps, then finish run. This makes AI SDK multi-step behavior visible in the dashboard instead of logging only one opaque completion.
|
|
49
|
+
- Tool results update the existing `tool_call` step by `request_log_id + tool_call_id`. They are not logged as a second unrelated completion row.
|
|
50
|
+
- `runContext.requestLogId` is intentionally direct. qgrid SDK and server are in the same product boundary, so an opaque indirection was not worth the complexity.
|
|
51
|
+
- Lifecycle endpoints remain public because `createQgridLogger` records non-qgrid AI SDK calls into qgrid logs without forcing those calls through the qgrid provider.
|
|
52
|
+
- Structured-output failures should fail honestly. Especially on Claude Code, partial or invalid structured output must not be rescued into a fake success.
|
|
53
|
+
|
|
54
|
+
## OpenAI/Codex Runtime
|
|
55
|
+
|
|
56
|
+
Sources:
|
|
57
|
+
|
|
58
|
+
- `docs/plans/2026-05-18-feat-codex-app-server-backend-pivot-plan.md`
|
|
59
|
+
- `docs/plans/2026-05-30-feat-codex-builtin-tool-suppression-plan.md`
|
|
60
|
+
- `docs/plans/2026-06-06-feat-codex-thread-reuse-prompt-cache-plan.md`
|
|
61
|
+
- `docs/solutions/logic-errors/qgrid-prompt-cache-hit-rate-metric-miscalculation.md`
|
|
62
|
+
|
|
63
|
+
Key decisions:
|
|
64
|
+
|
|
65
|
+
- OpenAI uses Codex `app-server` directly over stdio, not `codex exec`. The app-server path gives qgrid OAuth login, persistent workers, and thread handles.
|
|
66
|
+
- Workers are persistent and token-scoped. qgrid can spawn multiple workers per token, but each worker is single-flight for turns. This differs from Anthropic, which fresh-spawns per request.
|
|
67
|
+
- qgrid unsets normal OpenAI API-key paths and logs in with ChatGPT/OAuth credentials. This keeps the runtime aligned with subscription-token pooling rather than API billing.
|
|
68
|
+
- Built-in Codex tools, apps, skills, web search, shell, and large instruction blocks are suppressed. The primary reason is tool-call correctness: Codex built-ins can steal calls that qgrid expects to represent as emulated AI SDK tool calls. Token savings are secondary.
|
|
69
|
+
- Thread reuse exists because Codex/OpenAI prompt cache keys are tied to the Codex conversation/thread. New `thread/start` calls miss cache even with identical prefixes.
|
|
70
|
+
- Reuse must be explicit through a server-issued coordinate such as `threadCoord`. Do not use content hashes or hidden closures; same-looking prompts from different sessions can cross-contaminate.
|
|
71
|
+
- Reuse fallback should be cold and correct. Invalid worker id, epoch mismatch, missing thread, busy worker timeout, or over-threshold token should not corrupt a conversation.
|
|
72
|
+
- Cache and usage metrics use per-turn usage. For Codex, `tokenUsage.total` is conversation cumulative; request logs must use `tokenUsage.last`.
|
|
73
|
+
- OpenAI/Codex cached tokens are included in `input_tokens`. Cache-hit denominator is `input_tokens`, not `input + cache_read + cache_creation`.
|
|
74
|
+
|
|
75
|
+
## Anthropic/Claude Code Runtime
|
|
76
|
+
|
|
77
|
+
Sources:
|
|
78
|
+
|
|
79
|
+
- `docs/brainstorms/2026-06-16-anthropic-provider-revival-problem-definition.md`
|
|
80
|
+
- `docs/plans/2026-06-24-001-refactor-anthropic-cold-only-routing-plan.md`
|
|
81
|
+
- `docs/solutions/integration-issues/claude-cli-drops-assistant-role-in-stream-json.md`
|
|
82
|
+
- `docs/solutions/tooling-decisions/anthropic-structured-stream-keep-required-and-fail-honestly.md`
|
|
83
|
+
- `docs/plans/2026-06-23-001-feat-anthropic-1m-context-plan.md`
|
|
84
|
+
- `docs/solutions/security-issues/claude-cli-anthropic-api-key-leak-audit.md`
|
|
85
|
+
- `docs/solutions/security-issues/qgrid-cross-user-context-leak-via-claude-settings-sources.md`
|
|
86
|
+
- `docs/solutions/integration-issues/claude-code-oauth-tokens-share-prompt-cache.md`
|
|
87
|
+
|
|
88
|
+
Key decisions:
|
|
89
|
+
|
|
90
|
+
- Anthropic is an internal Claude subscription OAuth path. The API-key provider was not pursued because it does not serve qgrid's subscription-pooling value.
|
|
91
|
+
- Anthropic is cold-only. It does not use Codex-style thread reuse because Claude Code prompt cache is prefix-based and AI SDK consumers already send full message history for each step.
|
|
92
|
+
- The shared `threadCoord` response shape may still appear for provider symmetry, but AI SDK storage/replay is disabled for `anthropic/*` models.
|
|
93
|
+
- Claude Code `stream-json` drops structural assistant role replay in the outbound API payload. qgrid flattens prior history into text because structural role replay through the CLI is not reliable.
|
|
94
|
+
- Claude Code `--json-schema` is not constrained native tool calling. It creates a `StructuredOutput` tool and validates after model generation. Keep schemas strict and fail on non-success subtypes or retry exhaustion.
|
|
95
|
+
- `MAX_STRUCTURED_OUTPUT_RETRIES=1` means one attempt. Do not set it to 0 expecting "no retry but one attempt"; that can mean no useful attempt.
|
|
96
|
+
- 1M context support is measured per model and is a mitigation, not a guarantee. It reduces compaction/hang frequency for huge prompts, but does not make every structured prompt reliable.
|
|
97
|
+
- Spawn env must be whitelisted. Never pass inherited `ANTHROPIC_API_KEY`, `ANTHROPIC_AUTH_TOKEN`, or `ANTHROPIC_BASE_URL` unless intentionally building an API-key/proxy path.
|
|
98
|
+
- `--setting-sources project` is required for shared-service isolation. User/local Claude settings can load hooks or memory and leak context across requests.
|
|
99
|
+
- Claude Code OAuth prompt cache sharing across tokens in the same workspace is an observed cost behavior, not a product contract. Monitor it; do not promise it.
|
|
100
|
+
|
|
101
|
+
## Token Sync And Quota Thresholds
|
|
102
|
+
|
|
103
|
+
Sources:
|
|
104
|
+
|
|
105
|
+
- `docs/plans/2026-05-02-feat-token-sync-via-pg-listen-notify-plan.md`
|
|
106
|
+
- `docs/brainstorms/2026-06-30-token-quota-threshold-requirements.md`
|
|
107
|
+
- `docs/plans/2026-06-30-001-feat-token-quota-threshold-plan.md`
|
|
108
|
+
|
|
109
|
+
Key decisions:
|
|
110
|
+
|
|
111
|
+
- Token changes propagate with PostgreSQL `LISTEN/NOTIFY` plus periodic reconcile. Reconcile is kept because notifications can be missed during disconnects.
|
|
112
|
+
- Trigger setup is boot-time idempotent SQL, not a raw migration file, because the Sonamu migration directory is managed and raw files can conflict.
|
|
113
|
+
- Trigger payloads stay small (`op`, `id`). Dispatchers reload token rows instead of trusting a large notification body.
|
|
114
|
+
- The token subscriber disables statement/idle timeouts for `LISTEN` and uses reconnect backoff.
|
|
115
|
+
- `quota_threshold` is a routing guardrail, not a load balancer. It prevents an individual token from crossing a configured utilization percentage; it does not equalize traffic.
|
|
116
|
+
- Threshold values are nullable integers from 1 to 100. `0` is not valid; `100` means exclude only at full utilization.
|
|
117
|
+
- Provider criteria differ by primary window: Anthropic uses `five_hour.utilization`; OpenAI uses `primary.usedPercent`.
|
|
118
|
+
- Threshold gates are by token id, not token name. Names are display/logging labels and can change.
|
|
119
|
+
- Lookup failure is fail-open with logs/metrics. Hard failure happens only when usage was read successfully and the token is over threshold.
|
|
120
|
+
- OpenAI needs the gate in reuse, idle selection, and queue drain paths. A reusable but over-threshold worker must fall back cold to another eligible token when possible.
|
|
121
|
+
|
|
122
|
+
## Request Logs, Metrics, And Dashboard
|
|
123
|
+
|
|
124
|
+
Sources:
|
|
125
|
+
|
|
126
|
+
- `docs/plans/2026-05-21-feat-qgrid-logger-telemetry-integration-plan.md`
|
|
127
|
+
- `docs/brainstorms/2026-07-01-request-log-ttft-metric-requirements.md`
|
|
128
|
+
- `docs/solutions/logic-errors/qgrid-prompt-cache-hit-rate-metric-miscalculation.md`
|
|
129
|
+
- `docs/solutions/performance-issues/sonamu-findmany-aggregate-slowdown.md`
|
|
130
|
+
- `docs/solutions/performance-issues/qgrid-request-logs-subset-and-distinct-query-optimization.md`
|
|
131
|
+
|
|
132
|
+
Key decisions:
|
|
133
|
+
|
|
134
|
+
- The dashboard/logging layer is a core qgrid value, not an incidental web UI. It lets operators see cost, cache, TTFT, token routing, tool steps, and project-level workloads.
|
|
135
|
+
- `createQgridLogger` exists so teams can keep using native AI SDK providers while still recording those calls in qgrid request logs. It should not throw into user code.
|
|
136
|
+
- Request-log TTFT is the first generate-step TTFT. It intentionally measures generation responsiveness, not queue time or full request latency.
|
|
137
|
+
- Cache-hit metrics must be derived consistently from normalized provider accounting. Keep metric logic centralized when possible.
|
|
138
|
+
- Request-log list queries should avoid large text/blob columns unless the UI needs them. The list view is for scanning, not payload archival.
|
|
139
|
+
- Aggregate endpoints can intentionally duplicate filters in raw SQL instead of reusing `findMany`. Materializing full rows for aggregates was measured as too slow.
|
|
140
|
+
- Project-name filters matter at scale. Encourage `QGRID_PROJECT_NAME` so dashboards can distinguish workloads without inspecting prompts.
|
|
141
|
+
- Setup agents are part of the intended local qgrid workflow. They should ask for or add a project label during setup because retroactively untangling anonymous request logs is expensive once multiple projects or workflows share a qgrid server.
|
|
142
|
+
|
|
143
|
+
## CLI Packaging And Server Boot
|
|
144
|
+
|
|
145
|
+
Sources:
|
|
146
|
+
|
|
147
|
+
- `docs/plans/2026-04-06-feat-package-split-sdk-cli-plan.md`
|
|
148
|
+
- `docs/plans/2026-04-13-refactor-cli-bundle-rollback-plan.md`
|
|
149
|
+
- `references/cli-env-and-server-boot.md`
|
|
150
|
+
|
|
151
|
+
Key decisions:
|
|
152
|
+
|
|
153
|
+
- CLI and SDK were split so AI consumers do not install Sonamu, database, and runtime-server dependencies just to call qgrid.
|
|
154
|
+
- The CLI is a direct Node/bundle runner, not a Docker wrapper. Docker was removed to keep `npm i -g ...` plus `qgrid start` usable without local Docker setup.
|
|
155
|
+
- CLI user-facing configuration is intentionally small: database connection, port, public callback URL, server URL, and project name. Bundle bootstrapping details are implementation internals.
|
|
156
|
+
- The CLI checks runtime CLIs (`codex`, `claude`) because qgrid delegates provider execution to those local binaries.
|
|
157
|
+
- The dashboard version should follow the CLI package version because the dashboard is shipped by the CLI bundle, not as an independently versioned web product.
|
|
158
|
+
- qgrid skills ship with the CLI package, not a separate skills package. qgrid cannot be used with the AI SDK alone; a local qgrid CLI server is required, so CLI install is the right moment to sync `.agents/skills/qgrid` and `.claude/skills/qgrid` into the consuming project.
|
|
159
|
+
|
|
160
|
+
## Image Generation
|
|
161
|
+
|
|
162
|
+
Sources:
|
|
163
|
+
|
|
164
|
+
- `docs/brainstorms/2026-07-05-qgrid-image-generation-requirements.md`
|
|
165
|
+
- `docs/plans/2026-07-05-001-feat-codex-image-generation-plan.md`
|
|
166
|
+
- `docs/brainstorms/2026-07-06-qgrid-image-persistence-requirements.md`
|
|
167
|
+
- `docs/brainstorms/2026-07-06-codex-image-cost-estimate.md`
|
|
168
|
+
|
|
169
|
+
Key decisions:
|
|
170
|
+
|
|
171
|
+
- Image generation is OpenAI/Codex-only and request-level opt-in. It is essentially a Codex-hosted `image_generation` tool call, not qgrid directly calling the OpenAI Images API. Always-on image tools would change every turn's tool configuration and threaten prompt-cache stability.
|
|
172
|
+
- It is non-stream only. Codex returns completed base64 image payloads, not useful image deltas.
|
|
173
|
+
- Image turns are cold one-shot threads and are excluded from thread reuse. This prevents base64 payloads from entering reusable conversation state and cache prefixes.
|
|
174
|
+
- qgrid performs preflight capability/model gates and postflight "image count must be greater than zero" checks. Codex can otherwise silently return text when image generation is unavailable or unused.
|
|
175
|
+
- Returned images are inline base64 content parts for consumers and AI SDK `file` parts. qgrid does not promise aspect ratio, edits, or reference-image control on this path.
|
|
176
|
+
- `imageGenerationOptions` currently supports quality and size. The worker instruction and request-log pricing assumption use `gpt-image-2`, with defaults `medium` and `1536x1024`.
|
|
177
|
+
- qgrid does not manage generated images as durable assets through a `generated_images` table or object-storage layer. Current request logs can still contain inline image data URLs for inspection and synthetic `image_generation` tool-call steps.
|
|
178
|
+
- Image cost is stored separately in `request_logs.image_cost_usd`; `request_logs.cost_usd` remains the Codex driver model token cost. Because Codex does not expose exact image tool usage, `image_cost_usd` is a price-table estimate and may be inaccurate.
|
|
179
|
+
- Inspect current plans, tests, and implementation before changing behavior; the Codex tool surface can change underneath qgrid.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Docs Workflow
|
|
2
|
+
|
|
3
|
+
Use this reference for qgrid planning, diagnosis, and review workflow.
|
|
4
|
+
|
|
5
|
+
The project workflow is documented in `docs/WORKFLOW.md`.
|
|
6
|
+
|
|
7
|
+
## Standard flow
|
|
8
|
+
|
|
9
|
+
1. Brainstorm and plan before substantial work.
|
|
10
|
+
2. Store local docs under `docs/` using existing directories:
|
|
11
|
+
- `docs/brainstorms/`
|
|
12
|
+
- `docs/plans/`
|
|
13
|
+
- `docs/diagnosis/`
|
|
14
|
+
- `docs/solutions/`
|
|
15
|
+
3. Use peer review for plans and docs when requested.
|
|
16
|
+
4. Accept review feedback by default unless there is a concrete tradeoff-based reason not to.
|
|
17
|
+
|
|
18
|
+
## Existing docs are context
|
|
19
|
+
|
|
20
|
+
Before changing runtime-sensitive areas, search `docs/diagnosis`, `docs/solutions`, and recent `docs/plans` for prior decisions. qgrid has important historical decisions around:
|
|
21
|
+
|
|
22
|
+
- Codex thread reuse and prompt cache.
|
|
23
|
+
- Claude Code fresh spawn.
|
|
24
|
+
- structured output strictness.
|
|
25
|
+
- Anthropic usage categories.
|
|
26
|
+
- request log cache hit metrics.
|
|
27
|
+
- quota threshold routing.
|
|
28
|
+
- token isolation and auth env leaks.
|
|
29
|
+
|
|
30
|
+
Do not copy stale docs blindly. Use docs to identify decisions and then verify against current code.
|
|
31
|
+
|
|
32
|
+
When a repo doc establishes or changes durable rationale for a qgrid feature, reflect the stable decision in `references/decision-rationale.md`. Keep the skill reference as a compact index of why the decision exists and where the source docs live; do not copy full plans or brainstorms into the skill.
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# OpenAI Codex Runtime
|
|
2
|
+
|
|
3
|
+
Use this reference before changing OpenAI provider behavior, Codex worker lifecycle, thread reuse, cache behavior, OAuth refresh, image-generation gates, or quota routing.
|
|
4
|
+
|
|
5
|
+
## Contents
|
|
6
|
+
|
|
7
|
+
- Process model
|
|
8
|
+
- Codex configuration
|
|
9
|
+
- Initialization and auth
|
|
10
|
+
- Thread and turn flow
|
|
11
|
+
- Thread retention
|
|
12
|
+
- Queue and routing
|
|
13
|
+
- Usage and notifications
|
|
14
|
+
- Streaming
|
|
15
|
+
- Image generation status
|
|
16
|
+
|
|
17
|
+
## Process model
|
|
18
|
+
|
|
19
|
+
OpenAI tokens use persistent Codex app-server workers.
|
|
20
|
+
|
|
21
|
+
- Dispatcher: `packages/api/src/utils/providers/openai/openai-dispatcher.ts`.
|
|
22
|
+
- Worker: `packages/api/src/utils/providers/openai/codex-worker.ts`.
|
|
23
|
+
- RPC client: `packages/api/src/utils/providers/openai/codex-rpc.ts`.
|
|
24
|
+
- Process command: `codex app-server --listen stdio://`.
|
|
25
|
+
- Workers per token: `QGRID_WORKERS_PER_TOKEN`, default 3, capped at 5.
|
|
26
|
+
- Worker id: `tokenId * 10 + workerIndex`.
|
|
27
|
+
- Worker home: `/tmp/qgrid-codex/${tokenId}-${workerIndex}` when `workerIndex` exists.
|
|
28
|
+
- Worker cwd: `${CODEX_HOME}/cwd`.
|
|
29
|
+
|
|
30
|
+
Workers are persistent. Turns are single-flight per worker (`busy` flag). When all eligible workers are busy, requests enter an in-memory queue.
|
|
31
|
+
|
|
32
|
+
## Codex configuration
|
|
33
|
+
|
|
34
|
+
qgrid writes a worker-local `config.toml` under `CODEX_HOME` before spawning Codex. The intent is to use Codex as a plain generation backend, not as a coding agent.
|
|
35
|
+
|
|
36
|
+
Disabled by config:
|
|
37
|
+
|
|
38
|
+
- web search
|
|
39
|
+
- shell tool
|
|
40
|
+
- tool search/suggest
|
|
41
|
+
- multi-agent
|
|
42
|
+
- image generation by default
|
|
43
|
+
- apps/plugins
|
|
44
|
+
- view_image
|
|
45
|
+
- bundled skills/instructions
|
|
46
|
+
- permissions/apps/environment instruction blocks
|
|
47
|
+
|
|
48
|
+
Spawn env is intentionally small:
|
|
49
|
+
|
|
50
|
+
- `PATH`
|
|
51
|
+
- `TMPDIR`
|
|
52
|
+
- `CODEX_HOME`
|
|
53
|
+
- `CODEX_EXEC_SERVER_URL=none`
|
|
54
|
+
|
|
55
|
+
Do not re-enable built-in Codex tools/instructions unless the user explicitly asks for agentic Codex behavior.
|
|
56
|
+
|
|
57
|
+
## Initialization and auth
|
|
58
|
+
|
|
59
|
+
Worker initialization:
|
|
60
|
+
|
|
61
|
+
1. Spawn Codex app-server over stdio.
|
|
62
|
+
2. Create `CodexRpcClient`.
|
|
63
|
+
3. Send `initialize`.
|
|
64
|
+
4. Login with ChatGPT/OAuth credentials.
|
|
65
|
+
5. Bind Codex server-request `account/chatgptAuthTokens/refresh` to qgrid's token refresh handler.
|
|
66
|
+
|
|
67
|
+
If Codex asks to refresh ChatGPT auth tokens, qgrid handles it through `handleChatgptAuthTokensRefresh(tokenId)`.
|
|
68
|
+
|
|
69
|
+
## Thread and turn flow
|
|
70
|
+
|
|
71
|
+
Cold path:
|
|
72
|
+
|
|
73
|
+
1. `thread/start` with `ephemeral: true`.
|
|
74
|
+
2. `baseInstructions` is a minimal assistant prompt.
|
|
75
|
+
3. `developerInstructions` carries the qgrid system prompt.
|
|
76
|
+
4. Optional `thread/inject_items` injects full history.
|
|
77
|
+
5. `turn/start` runs current input.
|
|
78
|
+
|
|
79
|
+
Reuse path:
|
|
80
|
+
|
|
81
|
+
1. qgrid verifies the incoming `threadCoord`.
|
|
82
|
+
2. Dispatcher reacquires the exact worker by `workerId`.
|
|
83
|
+
3. It checks worker readiness, active status, epoch, thread presence, and quota threshold.
|
|
84
|
+
4. It waits up to 5 seconds for that worker to become free.
|
|
85
|
+
5. It calls `turn/start` on the existing thread with delta input only.
|
|
86
|
+
|
|
87
|
+
Thread metadata is stored only inside the worker process. Worker restart increments `epoch` and clears thread metadata. Thread reuse must fall back cold if epoch or thread lookup fails.
|
|
88
|
+
|
|
89
|
+
## Thread retention
|
|
90
|
+
|
|
91
|
+
Worker thread metadata:
|
|
92
|
+
|
|
93
|
+
- idle TTL: 10 minutes.
|
|
94
|
+
- max threads per worker: 16.
|
|
95
|
+
- cleanup is lazy before creating a new thread.
|
|
96
|
+
|
|
97
|
+
There is no explicit close RPC for old ephemeral threads; qgrid removes them from the reuse map and stops routing turns to them.
|
|
98
|
+
|
|
99
|
+
## Queue and routing
|
|
100
|
+
|
|
101
|
+
OpenAI worker selection:
|
|
102
|
+
|
|
103
|
+
- Prefer reuse worker when a valid reuse coordinate exists.
|
|
104
|
+
- Otherwise select an idle ready active worker round-robin across eligible workers.
|
|
105
|
+
- If no worker is free, enqueue.
|
|
106
|
+
- Queue timeout: 60 seconds.
|
|
107
|
+
- Max queue size: 50.
|
|
108
|
+
|
|
109
|
+
Quota threshold:
|
|
110
|
+
|
|
111
|
+
- `quota_threshold` is stored on tokens.
|
|
112
|
+
- Dispatcher reads rate limits through a ready worker.
|
|
113
|
+
- Rate limit reads are cached for 60 seconds.
|
|
114
|
+
- Lookup failure is fail-open.
|
|
115
|
+
- If all ready active tokens are over threshold, throw `QuotaThresholdExceededError`.
|
|
116
|
+
|
|
117
|
+
## Usage and notifications
|
|
118
|
+
|
|
119
|
+
Codex RPC notifications drive result collection:
|
|
120
|
+
|
|
121
|
+
- `item/agentMessage/delta`: text deltas and TTFT.
|
|
122
|
+
- `item/completed`: final text and image-generation results.
|
|
123
|
+
- `thread/tokenUsage/updated`: token usage.
|
|
124
|
+
- `turn/completed`: duration and terminal status.
|
|
125
|
+
- `error`: terminal error.
|
|
126
|
+
|
|
127
|
+
When using thread reuse, use `tokenUsage.last`, not `tokenUsage.total`, for request logs. `.total` is conversation cumulative and mixes previous turns, which corrupts per-request cache hit metrics.
|
|
128
|
+
|
|
129
|
+
## Streaming
|
|
130
|
+
|
|
131
|
+
Streaming uses the same worker/thread execution with callbacks:
|
|
132
|
+
|
|
133
|
+
- `onThreadId` emits the thread id when a new thread is created.
|
|
134
|
+
- `onTurnId` emits turn id after `turn/start`.
|
|
135
|
+
- qgrid can interrupt OpenAI turns on SSE close by calling `turn/interrupt` across ready workers.
|
|
136
|
+
|
|
137
|
+
## Image generation
|
|
138
|
+
|
|
139
|
+
Image generation is OpenAI/Codex-only and implemented as an opt-in Codex `image_generation` tool call. It is not a direct OpenAI Images API call from qgrid.
|
|
140
|
+
|
|
141
|
+
- It is opt-in through `imageGeneration`.
|
|
142
|
+
- `imageGenerationOptions` carries quality/size hints and the cost-estimation basis.
|
|
143
|
+
- It is non-stream only; streaming path rejects it.
|
|
144
|
+
- It always uses a cold one-shot thread and does not issue a reusable coordinate.
|
|
145
|
+
- It enables `features.image_generation` only on that thread; global config remains disabled.
|
|
146
|
+
- It swaps the normal "text only" base instruction for an image-permitting instruction on that thread.
|
|
147
|
+
- It gates on provider capability and model multimodality.
|
|
148
|
+
- Failure kinds are `gate`, `not_called`, and `incomplete`.
|
|
149
|
+
- Codex notifications expose image items through `item/started` and `item/completed`; qgrid treats non-empty base64 `result` as the completion signal, not the item `status` string.
|
|
150
|
+
- Completed images are surfaced as qgrid `image` content parts and AI SDK `file` parts with `mediaType: "image/png"`.
|
|
151
|
+
- qgrid uses `gpt-image-2` as the image-tool pricing/model assumption. Codex does not expose exact image tool token usage, so `image_cost_usd` is an estimate from the public price table, not exact billing.
|
|
152
|
+
|
|
153
|
+
Before modifying this area, inspect latest docs/plans/brainstorms and current tests.
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# Prompt Cache And Usage
|
|
2
|
+
|
|
3
|
+
Use this reference for `sessionKey`, `threadCoord`, prompt cache, request-log usage metrics, and cost accounting.
|
|
4
|
+
|
|
5
|
+
## qgrid thread coordinates
|
|
6
|
+
|
|
7
|
+
Client-facing `QgridThreadCoord`:
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
{
|
|
11
|
+
workerId: number;
|
|
12
|
+
threadId: string;
|
|
13
|
+
epoch: number;
|
|
14
|
+
systemHash: string;
|
|
15
|
+
}
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
- Server issues this after a provider turn.
|
|
19
|
+
- Client returns it through `runContext.threadCoord`.
|
|
20
|
+
- AI SDK hides this behind `providerOptions.qgrid.sessionKey` for OpenAI models.
|
|
21
|
+
- `systemHash` is the first 16 hex chars of SHA-256 over the system prompt.
|
|
22
|
+
- Reuse is eligible only when incoming `systemHash` matches current system prompt.
|
|
23
|
+
|
|
24
|
+
## AI SDK `sessionKey`
|
|
25
|
+
|
|
26
|
+
`packages/ai-sdk/src/index.ts` stores `threadCoord` in a module-level map by `sessionKey` for 10 minutes.
|
|
27
|
+
|
|
28
|
+
- OpenAI models: `sessionKey` can replay the stored coordinate.
|
|
29
|
+
- Anthropic models: `reusableSessionKey` returns `undefined`, so the coordinate is not stored or replayed.
|
|
30
|
+
- Tool-call loop run context and non-tool multi-turn context share the same `runContext` boundary.
|
|
31
|
+
|
|
32
|
+
## OpenAI/Codex cache behavior
|
|
33
|
+
|
|
34
|
+
Codex sets OpenAI prompt-cache affinity from the Codex conversation/thread id. qgrid originally got cache misses by creating a new thread for every request. Thread reuse fixes this by keeping the same Codex thread for a logical conversation.
|
|
35
|
+
|
|
36
|
+
Cache hit requires:
|
|
37
|
+
|
|
38
|
+
1. `QGRID_OPENAI_THREAD_REUSE` is not `"false"`.
|
|
39
|
+
2. AI SDK sends a stable `sessionKey`.
|
|
40
|
+
3. Server receives a `threadCoord`.
|
|
41
|
+
4. `systemHash` matches.
|
|
42
|
+
5. The target worker exists, is ready/active, has same `epoch`, and still has the thread.
|
|
43
|
+
6. The worker becomes free within the reuse wait window.
|
|
44
|
+
7. Prefix content remains stable.
|
|
45
|
+
|
|
46
|
+
When reuse succeeds, qgrid sends only delta input to `turn/start`. When reuse fails, qgrid falls back to cold execution with full prompt plus history injection.
|
|
47
|
+
|
|
48
|
+
Important cache breakers:
|
|
49
|
+
|
|
50
|
+
- Different system prompt.
|
|
51
|
+
- Worker restart or thread TTL eviction.
|
|
52
|
+
- Schema/output format changes near the prefix. Codex places `outputSchema` in a prefix-sensitive area, so changing schemas turn-by-turn can break cache even on the same thread.
|
|
53
|
+
- Image generation requests, which intentionally use cold one-shot threads and do not issue reuse coordinates.
|
|
54
|
+
|
|
55
|
+
## Anthropic/Claude Code cache behavior
|
|
56
|
+
|
|
57
|
+
Anthropic uses fresh Claude Code process spawn per request. qgrid does not replay Anthropic `sessionKey`.
|
|
58
|
+
|
|
59
|
+
Prompt cache can still work when prefixes are stable, but:
|
|
60
|
+
|
|
61
|
+
- Full history is replayed through stream-json after flattening.
|
|
62
|
+
- Cache write/read can be eventually consistent; immediate next request is not guaranteed to hit.
|
|
63
|
+
- Claude Code OAuth token cache behavior has provider-specific quirks documented in `docs/solutions`.
|
|
64
|
+
- Avoid putting volatile schema text into the system prompt. qgrid uses `--json-schema` / `StructuredOutput` for structured output.
|
|
65
|
+
|
|
66
|
+
## Usage normalization
|
|
67
|
+
|
|
68
|
+
qgrid's standard usage meaning:
|
|
69
|
+
|
|
70
|
+
- `input_tokens`: total input for this request, including cache read and cache creation input.
|
|
71
|
+
- `cache_read_tokens`: cached input read.
|
|
72
|
+
- `cache_creation_tokens`: input written to prompt cache.
|
|
73
|
+
- `output_tokens`: output tokens.
|
|
74
|
+
|
|
75
|
+
OpenAI/Codex already reports `inputTokens` as total input including cached input. Use Codex `tokenUsage.last` for per-request logs, not `tokenUsage.total`.
|
|
76
|
+
|
|
77
|
+
Anthropic native usage categories are mutually exclusive:
|
|
78
|
+
|
|
79
|
+
- `input_tokens`
|
|
80
|
+
- `cache_creation_input_tokens`
|
|
81
|
+
- `cache_read_input_tokens`
|
|
82
|
+
|
|
83
|
+
qgrid normalizes Anthropic by summing those three into standard `inputTokens` and preserving cache read/write as subfields.
|
|
84
|
+
|
|
85
|
+
## Cache hit rate
|
|
86
|
+
|
|
87
|
+
For qgrid-standard usage, hit rate denominator is `input_tokens`, not `input_tokens + cache_read_tokens + cache_creation_tokens`.
|
|
88
|
+
|
|
89
|
+
Do not double-count cache subfields. This was a real dashboard bug: OpenAI cache hit rates could be displayed near half their actual value when cache tokens were added to the denominator again.
|
|
90
|
+
|
|
91
|
+
## Cost accounting
|
|
92
|
+
|
|
93
|
+
`packages/api/src/utils/providers/common/model-cost.ts` contains model price fallback.
|
|
94
|
+
|
|
95
|
+
- OpenAI cost normally uses qgrid's price table.
|
|
96
|
+
- OpenAI image generation stores a separate `image_cost_usd` estimate. It assumes Codex's image tool is priced as `gpt-image-2` for the selected/default quality and size, because qgrid does not receive exact image tool usage from Codex.
|
|
97
|
+
- Anthropic Claude Code may return `total_cost_usd`; qgrid prefers provider cost when present and positive.
|
|
98
|
+
- Anthropic cache creation uses 5-minute cache write price in fallback tables.
|
|
99
|
+
- OpenAI long-context surcharge applies to the whole request when input exceeds the model threshold, not just the excess tokens.
|
|
100
|
+
|
|
101
|
+
When changing models or prices, verify against current official pricing before editing the table.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Provider Runtime Differences
|
|
2
|
+
|
|
3
|
+
Use this reference when comparing OpenAI and Anthropic behavior, debugging provider-specific bugs, or reviewing cross-provider changes.
|
|
4
|
+
|
|
5
|
+
| Topic | OpenAI via Codex | Anthropic via Claude Code |
|
|
6
|
+
|---|---|---|
|
|
7
|
+
| Process lifetime | Persistent `codex app-server` workers | Fresh `claude` process per request |
|
|
8
|
+
| Worker pool | Token x `QGRID_WORKERS_PER_TOKEN`, default 3, max 5 | No workers; in-memory token pool only |
|
|
9
|
+
| Worker id | `tokenId * 10 + workerIndex` | `tokenId` |
|
|
10
|
+
| Epoch | Worker spawn counter; changes on restart | Always `0` |
|
|
11
|
+
| Request concurrency | One turn per worker; queue when all eligible workers busy | Fresh process per request; token selection uses least-used RR |
|
|
12
|
+
| Model routing | `openai/*`; qgrid strips provider prefix before provider call | `anthropic/*`; provider canonicalizes model and strips prefix/`[1m]` |
|
|
13
|
+
| Prefix-less models | Fallback not implemented | Fallback not implemented |
|
|
14
|
+
| Thread/session | Ephemeral Codex thread stored in worker memory | Fresh Claude `--session-id` per request |
|
|
15
|
+
| `sessionKey` | AI SDK stores and replays `threadCoord` for thread reuse | AI SDK intentionally disables storage/replay |
|
|
16
|
+
| Multi-turn | Reuse sends delta input to existing Codex thread; cold fallback injects full history | Fresh spawn receives flattened full history through stream-json |
|
|
17
|
+
| Cache key | Codex conversation/thread id is prompt-cache affinity | Anthropic prefix cache via Claude Code; fresh spawn still can cache stable prefixes |
|
|
18
|
+
| Built-in tools | Codex tools/apps/plugins/skills disabled by worker config | Claude tools disabled via `--tools ""`; `StructuredOutput` allowed only for schema |
|
|
19
|
+
| AI SDK tools | Emulated via qgrid structured output schema, then mapped to AI SDK `tool-call` content | Same emulation path; not native Claude Code tools |
|
|
20
|
+
| Structured output | Codex `outputSchema` passed to `turn/start`; schema changes can affect prefix cache | Claude `--json-schema` through `StructuredOutput` tool; strict schemas required |
|
|
21
|
+
| Usage accounting | Codex usage already reports `inputTokens` including cached input | Native Anthropic categories are mutually exclusive; qgrid sums them into total input |
|
|
22
|
+
| Cost source | qgrid model price fallback | Prefer Claude Code `total_cost_usd`, else qgrid price fallback |
|
|
23
|
+
| Settings isolation | Per-worker `CODEX_HOME` and config.toml | Shared project cwd plus per-token `CLAUDE_CONFIG_DIR` |
|
|
24
|
+
| Streaming close | Can interrupt Codex turn with `turn/interrupt` | Abort kills the fresh child process |
|
|
25
|
+
| Image generation | In progress, OpenAI/Codex non-stream only | Explicitly unsupported |
|
|
26
|
+
|
|
27
|
+
## Routing contract
|
|
28
|
+
|
|
29
|
+
Provider routing happens in `packages/api/src/application/qgrid/qgrid.dispatcher.ts`.
|
|
30
|
+
|
|
31
|
+
- `openai/<model>` routes to `OpenAIDispatcher`.
|
|
32
|
+
- `anthropic/<model>` routes to `AnthropicDispatcher`.
|
|
33
|
+
- models without provider prefix produce "Direct LLM API fallback not implemented".
|
|
34
|
+
|
|
35
|
+
Do not silently route prefix-less Claude model names such as `claude-sonnet-4-6` to Anthropic. Tests intentionally guard against this.
|
|
36
|
+
|
|
37
|
+
## Shared contracts
|
|
38
|
+
|
|
39
|
+
Both providers return `GenerateResult` with:
|
|
40
|
+
|
|
41
|
+
- `text`
|
|
42
|
+
- `tokenName`
|
|
43
|
+
- `usage`
|
|
44
|
+
- `durationMs`
|
|
45
|
+
- optional `ttftMs`
|
|
46
|
+
- optional provider cost
|
|
47
|
+
- canonical `model`
|
|
48
|
+
- `threadCoord`
|
|
49
|
+
|
|
50
|
+
`qgrid.dispatcher.ts` maps this into `QueryOutput`, applies tool-call emulation, calculates fallback cost, and issues a client-facing `QgridThreadCoord` by adding `systemHash`.
|
|
51
|
+
|
|
52
|
+
Both providers receive strictified output schemas from `buildStrictOutputSchema`.
|
|
53
|
+
|
|
54
|
+
Tool calling uses this shared strict-schema path. It is not native provider tool calling on either route.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Repo Map
|
|
2
|
+
|
|
3
|
+
Use this map to orient qgrid work quickly.
|
|
4
|
+
|
|
5
|
+
## Active packages
|
|
6
|
+
|
|
7
|
+
- `packages/api`: Sonamu server, qgrid API frame, provider dispatchers, token/request-log models, migrations, OAuth, runtime integration.
|
|
8
|
+
- `packages/ai-sdk`: active public AI SDK provider and logger integration. Prefer this for public SDK behavior and examples.
|
|
9
|
+
- `packages/web`: dashboard UI. Usually depends on Sonamu-generated API clients and API model shape.
|
|
10
|
+
- `packages/cli`: global `qgrid` command, bundled server boot, dependency checks, DB preflight, and qgrid Codex/Claude Code skill sync. The CLI package ships `skills/qgrid` and its `postinstall` links it into consuming projects.
|
|
11
|
+
- `scripts` and `packages/api/scripts`: smoke tests, debug scripts, runtime probes.
|
|
12
|
+
- `docs`: local planning, diagnosis, and solution history. `docs/WORKFLOW.md` is the collaboration convention.
|
|
13
|
+
|
|
14
|
+
## Deprecated/context-only package
|
|
15
|
+
|
|
16
|
+
- `packages/sdk`: deprecated. Read only for historical context or migration clues. Do not implement new features, docs, or examples against this package unless explicitly asked for legacy compatibility.
|
|
17
|
+
|
|
18
|
+
## Runtime hot spots
|
|
19
|
+
|
|
20
|
+
- Provider router: `packages/api/src/application/qgrid/qgrid.dispatcher.ts`.
|
|
21
|
+
- Conversation/thread reuse: `packages/api/src/application/qgrid/conv-routing.ts`.
|
|
22
|
+
- Query API and SSE stream: `packages/api/src/application/qgrid/qgrid.frame.ts`.
|
|
23
|
+
- Request logging lifecycle: `packages/api/src/application/qgrid/qgrid-run-lifecycle.ts`.
|
|
24
|
+
- Token LISTEN/NOTIFY sync: `packages/api/src/application/qgrid/token-subscriber.ts`.
|
|
25
|
+
- Token trigger setup: `packages/api/src/application/qgrid/token-trigger-setup.ts`.
|
|
26
|
+
- OpenAI Codex runtime: `packages/api/src/utils/providers/openai/*`.
|
|
27
|
+
- Anthropic Claude Code runtime: `packages/api/src/utils/providers/anthropic/*`.
|
|
28
|
+
- Cost/usage accounting: `packages/api/src/utils/providers/common/model-cost.ts`.
|
|
29
|
+
- Tool-call emulation: `packages/api/src/application/qgrid/tool-emulation.ts`.
|
|
30
|
+
|
|
31
|
+
## Web/Sonamu hot spots
|
|
32
|
+
|
|
33
|
+
- Entity definitions: `packages/api/src/application/**/**.entity.json`.
|
|
34
|
+
- API models/types: `packages/api/src/application/**/**.model.ts`, `*.types.ts`.
|
|
35
|
+
- Generated API files: `packages/api/src/application/sonamu.generated*`, `packages/web/src/services` when present, generated route/client files.
|
|
36
|
+
- Dashboard components: `packages/web/src/components/qgrid/*`.
|
|
37
|
+
- Dashboard routes: `packages/web/src/routes/*`.
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# Request Log Run Lifecycle
|
|
2
|
+
|
|
3
|
+
Use this reference when changing request logging, tool-call loop logging, telemetry logger integration, request log steps, or dashboard metrics.
|
|
4
|
+
|
|
5
|
+
## Modes
|
|
6
|
+
|
|
7
|
+
qgrid query supports `logMode`:
|
|
8
|
+
|
|
9
|
+
- `auto`: save one request_log after a simple request succeeds.
|
|
10
|
+
- `run`: create/update a run and append steps for multi-step/tool-call flows.
|
|
11
|
+
- `none`: no automatic logging.
|
|
12
|
+
|
|
13
|
+
If `logMode` is omitted, `qgrid.frame.ts` uses `run` when `isStep` is true and `auto` otherwise.
|
|
14
|
+
|
|
15
|
+
## Query flow
|
|
16
|
+
|
|
17
|
+
For `logMode: "run"`:
|
|
18
|
+
|
|
19
|
+
1. `beforeQuery(args)` creates or extends a run.
|
|
20
|
+
2. `QgridDispatcher.query` or `queryStream` executes the provider call.
|
|
21
|
+
3. `afterQuery(...)` records result/step data and returns `runContext`.
|
|
22
|
+
4. qgrid merges lifecycle `requestLogId` with provider `threadCoord`.
|
|
23
|
+
5. Errors call `finishRunWithError`; stream close can call abort handling.
|
|
24
|
+
|
|
25
|
+
For `auto`:
|
|
26
|
+
|
|
27
|
+
- qgrid saves a single request log row after the provider returns.
|
|
28
|
+
- It records token name, project name, model, prompts, response, usage, duration, TTFT, driver cost, image cost estimate, effort, history, status, tool-call count, and image-generation flag.
|
|
29
|
+
- Image results are also appended as synthetic `image_generation` tool-call steps so the detail page can inspect the generated image and pricing assumption.
|
|
30
|
+
|
|
31
|
+
## Tool-call loop
|
|
32
|
+
|
|
33
|
+
The AI SDK provider tracks pending tool-call IDs. When the next AI SDK call contains all required tool results, it sends:
|
|
34
|
+
|
|
35
|
+
- existing `runContext`
|
|
36
|
+
- `toolResults`
|
|
37
|
+
- `logMode: "run"`
|
|
38
|
+
|
|
39
|
+
qgrid converts tool results into continuation input for providers. Cold fallback still includes a "continue using these results" text input.
|
|
40
|
+
|
|
41
|
+
Tool calls are produced through qgrid structured-output emulation, not native provider tool calling. The request log lifecycle records the emulated generate step, pending tool-call step rows, tool results on follow-up, and the final generate step. For full semantics, read `tool-calling-and-multiturn.md`.
|
|
42
|
+
|
|
43
|
+
## Usage fields
|
|
44
|
+
|
|
45
|
+
Stored request log usage uses qgrid-standard semantics:
|
|
46
|
+
|
|
47
|
+
- `input_tokens`: total input, including cache read/write.
|
|
48
|
+
- `cache_read_tokens`: cached input read.
|
|
49
|
+
- `cache_creation_tokens`: prompt cache write input.
|
|
50
|
+
- `output_tokens`: output tokens.
|
|
51
|
+
- `cost_usd`: integer micro-USD in DB; displayed USD is `cost_usd / 1_000_000`.
|
|
52
|
+
- `image_cost_usd`: integer micro-USD estimate for Codex image generation output.
|
|
53
|
+
- `image_cost_method`: string such as `assumed:gpt-image-2:medium:1536x1024:png`.
|
|
54
|
+
|
|
55
|
+
OpenAI/Codex: use per-turn `.last` usage from `thread/tokenUsage/updated`.
|
|
56
|
+
|
|
57
|
+
Anthropic: normalize native mutually exclusive categories by summing input + cache creation + cache read into total input.
|
|
58
|
+
|
|
59
|
+
For image requests, keep `cost_usd` as the Codex driver model token cost. Image output cost is separate because qgrid observes Codex's `image_generation` result, not the OpenAI Images API usage object. Treat `image_cost_usd` as a price-table estimate that may be inaccurate if Codex changes its underlying image accounting.
|
|
60
|
+
|
|
61
|
+
## Legacy normalization
|
|
62
|
+
|
|
63
|
+
`RequestLogModel` normalizes legacy Anthropic rows where stored `input_tokens` may not include cache read/write. Keep this in mind when changing cost or display logic.
|
|
64
|
+
|
|
65
|
+
## TTFT
|
|
66
|
+
|
|
67
|
+
TTFT is tracked by wrapping first provider delta:
|
|
68
|
+
|
|
69
|
+
- OpenAI: first `item/agentMessage/delta`.
|
|
70
|
+
- Anthropic: first text or structured partial JSON delta.
|
|
71
|
+
|
|
72
|
+
If missing, qgrid maps TTFT to `0` in `QueryOutput` and nullable/optional places as appropriate.
|
|
73
|
+
|
|
74
|
+
## Logger integration
|
|
75
|
+
|
|
76
|
+
`packages/ai-sdk/src/logger.ts` lets non-qgrid providers write logs into qgrid. It skips model provider `qgrid` to avoid double logging. Preserve stale-run cleanup because AI SDK telemetry may emit start without a final event on provider failures.
|