whale-code 6.5.7 → 6.5.9
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.md +14 -2
- package/dist/cli/services/agent-loop.js +26 -2
- package/dist/cli/services/agent-loop.js.map +1 -1
- package/dist/cli/services/hooks.js +2 -1
- package/dist/cli/services/hooks.js.map +1 -1
- package/dist/cli/services/telemetry-spans.js +1 -0
- package/dist/cli/services/telemetry-spans.js.map +1 -1
- package/dist/cli/services/telemetry.d.ts +23 -0
- package/dist/cli/services/telemetry.js +45 -1
- package/dist/cli/services/telemetry.js.map +1 -1
- package/dist/server/handlers/__test-utils__/test-db.d.ts +17 -3
- package/dist/server/handlers/__test-utils__/test-db.js +113 -14
- package/dist/server/handlers/__test-utils__/test-db.js.map +1 -1
- package/dist/server/handlers/affiliates.d.ts +9 -0
- package/dist/server/handlers/affiliates.js +197 -0
- package/dist/server/handlers/affiliates.js.map +1 -0
- package/dist/server/handlers/api-docs.d.ts +4 -2
- package/dist/server/handlers/api-docs.js +204 -1681
- package/dist/server/handlers/api-docs.js.map +1 -1
- package/dist/server/handlers/campaigns.d.ts +9 -0
- package/dist/server/handlers/campaigns.js +237 -0
- package/dist/server/handlers/campaigns.js.map +1 -0
- package/dist/server/handlers/catalog-schemas.js +9 -9
- package/dist/server/handlers/catalog-schemas.js.map +1 -1
- package/dist/server/handlers/catalog.js +1 -1
- package/dist/server/handlers/catalog.js.map +1 -1
- package/dist/server/handlers/comms-documents.js +28 -2
- package/dist/server/handlers/comms-documents.js.map +1 -1
- package/dist/server/handlers/comms-pdf-generation.js +25 -3
- package/dist/server/handlers/comms-pdf-generation.js.map +1 -1
- package/dist/server/handlers/comms-pdf-helpers.js +4 -4
- package/dist/server/handlers/comms-pdf-helpers.js.map +1 -1
- package/dist/server/handlers/comms.d.ts +100 -0
- package/dist/server/handlers/comms.js +146 -12
- package/dist/server/handlers/comms.js.map +1 -1
- package/dist/server/handlers/coupons.d.ts +9 -0
- package/dist/server/handlers/coupons.js +220 -0
- package/dist/server/handlers/coupons.js.map +1 -0
- package/dist/server/handlers/embeddings.js +1 -1
- package/dist/server/handlers/embeddings.js.map +1 -1
- package/dist/server/handlers/enrichment.js +2 -622
- package/dist/server/handlers/enrichment.js.map +1 -1
- package/dist/server/handlers/fulfillment.d.ts +9 -0
- package/dist/server/handlers/fulfillment.js +209 -0
- package/dist/server/handlers/fulfillment.js.map +1 -0
- package/dist/server/handlers/google-ads.d.ts +24 -0
- package/dist/server/handlers/google-ads.js +2199 -0
- package/dist/server/handlers/google-ads.js.map +1 -0
- package/dist/server/handlers/invoices.d.ts +9 -0
- package/dist/server/handlers/invoices.js +252 -0
- package/dist/server/handlers/invoices.js.map +1 -0
- package/dist/server/handlers/loyalty.d.ts +9 -0
- package/dist/server/handlers/loyalty.js +197 -0
- package/dist/server/handlers/loyalty.js.map +1 -0
- package/dist/server/handlers/meta-ads-graph-api.js +18 -3
- package/dist/server/handlers/meta-ads-graph-api.js.map +1 -1
- package/dist/server/handlers/phone.d.ts +9 -0
- package/dist/server/handlers/phone.js +197 -0
- package/dist/server/handlers/phone.js.map +1 -0
- package/dist/server/handlers/pipeline.d.ts +9 -0
- package/dist/server/handlers/pipeline.js +277 -0
- package/dist/server/handlers/pipeline.js.map +1 -0
- package/dist/server/handlers/qr-codes.d.ts +9 -0
- package/dist/server/handlers/qr-codes.js +198 -0
- package/dist/server/handlers/qr-codes.js.map +1 -0
- package/dist/server/handlers/reviews.d.ts +9 -0
- package/dist/server/handlers/reviews.js +171 -0
- package/dist/server/handlers/reviews.js.map +1 -0
- package/dist/server/handlers/segments.d.ts +9 -0
- package/dist/server/handlers/segments.js +229 -0
- package/dist/server/handlers/segments.js.map +1 -0
- package/dist/server/handlers/social.d.ts +9 -0
- package/dist/server/handlers/social.js +81 -0
- package/dist/server/handlers/social.js.map +1 -0
- package/dist/server/handlers/tax.d.ts +9 -0
- package/dist/server/handlers/tax.js +182 -0
- package/dist/server/handlers/tax.js.map +1 -0
- package/dist/server/handlers/wallet.d.ts +9 -0
- package/dist/server/handlers/wallet.js +203 -0
- package/dist/server/handlers/wallet.js.map +1 -0
- package/dist/server/handlers/webhooks-mgmt.d.ts +9 -0
- package/dist/server/handlers/webhooks-mgmt.js +181 -0
- package/dist/server/handlers/webhooks-mgmt.js.map +1 -0
- package/dist/server/handlers/wholesale.d.ts +9 -0
- package/dist/server/handlers/wholesale.js +219 -0
- package/dist/server/handlers/wholesale.js.map +1 -0
- package/dist/server/index.js +20 -9
- package/dist/server/index.js.map +1 -1
- package/dist/server/lib/clickhouse-buffer.js +1 -0
- package/dist/server/lib/clickhouse-buffer.js.map +1 -1
- package/dist/server/lib/coa-renderer.d.ts +1 -1
- package/dist/server/lib/coa-renderer.js +32 -10
- package/dist/server/lib/coa-renderer.js.map +1 -1
- package/dist/server/server-worker.d.ts +1 -0
- package/dist/server/server-worker.js +464 -3
- package/dist/server/server-worker.js.map +1 -1
- package/dist/server/tool-router.js +118 -4
- package/dist/server/tool-router.js.map +1 -1
- package/package.json +28 -4
- package/vendor/ink/package.json +0 -2
- package/whale-logo.png +0 -0
|
@@ -123,6 +123,7 @@ export function auditRowToSpan(row) {
|
|
|
123
123
|
return {
|
|
124
124
|
span_id: row.span_id || randomHexId(),
|
|
125
125
|
trace_id: row.trace_id || row.request_id || randomUUID(),
|
|
126
|
+
parent_span_id: row.parent_span_id || details.parent_span_id || undefined,
|
|
126
127
|
store_id: row.store_id || undefined,
|
|
127
128
|
service_name: row.service_name || "agent-server",
|
|
128
129
|
operation_name: row.action || undefined,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"clickhouse-buffer.js","names":["randomUUID","getClickHouseClient","spanBuffer","FLUSH_INTERVAL","FLUSH_MAX","flushTimer","queueSpan","span","push","length","flushSpans","setTimeout","clearTimeout","batch","splice","client","insert","auditRowToSpan","row","details","now","Date","toISOString","input_tokens","detailInputTokens","output_tokens","detailOutputTokens","total_cost","detailCost","model","detailModel","genAiModel","genAiInput","genAiOutput","genAiCost","genAiCacheRead","genAiCacheCreation","cache_read_tokens","detailCacheRead","cache_creation_tokens","detailCacheCreation","stop_reason","detailStopReason","turn_number","detailTurnNumber","turn_count","detailTurnCount","parent_conversation_id","detailParentConvId","input_bytes","detailInputBytes","output_bytes","detailOutputBytes","error_type","detailErrorType","retryable","detailRetryable","remainingDetails","toolName","resource_type","resource_id","undefined","tool_name","promptTokens","completionTokens","tokenCostUsd","modelName","span_id","randomHexId","trace_id","request_id","store_id","service_name","operation_name","action","span_kind","source","started_at","start_time","ended_at","end_time","duration_ms","status_code","severity","model_name","prompt_tokens","completion_tokens","total_tokens","token_cost_usd","agent_id","conversation_id","error_message","attributes","Object","keys","JSON","stringify","user_id","environment","user_email","classifyErrorType","errorMessage","lower","toLowerCase","includes","bytes","Uint8Array","crypto","getRandomValues","Array","from","map","b","toString","padStart","join"],"sources":["../../../src/server/lib/clickhouse-buffer.ts"],"sourcesContent":["/**\n * ClickHouse Span Buffer — batches spans for bulk insert to ClickHouse ai_spans.\n *\n * Same batching semantics (500ms / 100 records).\n * Also provides auditRowToSpan() to convert legacy row shapes to ClickHouseSpan.\n */\n\nimport { randomUUID } from \"node:crypto\";\nimport { type ClickHouseSpan, getClickHouseClient } from \"./clickhouse-client.js\";\n\n// ============================================================================\n// Buffer config\n// ============================================================================\n\nconst spanBuffer: ClickHouseSpan[] = [];\nconst FLUSH_INTERVAL = 500; // ms\nconst FLUSH_MAX = 100; // max records before force flush\nlet flushTimer: ReturnType<typeof setTimeout> | null = null;\n\n// ============================================================================\n// Public API\n// ============================================================================\n\n/**\n * Queue a span for batch insert to ClickHouse.\n */\nexport function queueSpan(span: ClickHouseSpan): void {\n spanBuffer.push(span);\n\n if (spanBuffer.length >= FLUSH_MAX) {\n flushSpans();\n } else if (!flushTimer) {\n flushTimer = setTimeout(() => {\n flushTimer = null;\n flushSpans();\n }, FLUSH_INTERVAL);\n }\n}\n\n/**\n * Flush all buffered spans to ClickHouse.\n * Call this on server shutdown or at end of request processing.\n */\nexport async function flushSpans(): Promise<void> {\n if (flushTimer) {\n clearTimeout(flushTimer);\n flushTimer = null;\n }\n\n if (spanBuffer.length > 0) {\n const batch = spanBuffer.splice(0, spanBuffer.length);\n const client = getClickHouseClient();\n await client.insert(\"ai_spans\", batch as unknown as Record<string, unknown>[]);\n }\n}\n\n// ============================================================================\n// Mapper: audit_log row → ClickHouseSpan\n// ============================================================================\n\n/**\n * Convert an existing audit_log row to a ClickHouseSpan.\n *\n * Field mapping:\n * ai_spans.action → operation_name\n * ai_spans.source → source\n * ai_spans.severity → severity\n * ai_spans.store_id → store_id\n * ai_spans.duration_ms → duration_ms\n * ai_spans.error_message → error_message\n * ai_spans.trace_id → trace_id\n * ai_spans.span_id → span_id\n * ai_spans.span_kind → span_kind\n * ai_spans.service_name → service_name\n * ai_spans.status_code → status_code\n * ai_spans.start_time → started_at\n * ai_spans.end_time → ended_at\n * ai_spans.conversation_id → conversation_id\n * ai_spans.user_id → user_id\n * ai_spans.input_tokens → prompt_tokens\n * ai_spans.output_tokens → completion_tokens\n * ai_spans.total_cost → token_cost_usd\n * ai_spans.model → model_name\n * ai_spans.resource_id (mcp_tool) → tool_name\n * ai_spans.details (remaining) → attributes (JSON string)\n */\nexport function auditRowToSpan(row: Record<string, unknown>): ClickHouseSpan {\n const details = (row.details || {}) as Record<string, unknown>;\n const now = new Date().toISOString();\n\n // Extract known fields from details that map to top-level ClickHouse columns\n const {\n input_tokens: detailInputTokens,\n output_tokens: detailOutputTokens,\n total_cost: detailCost,\n model: detailModel,\n \"gen_ai.request.model\": genAiModel,\n \"gen_ai.usage.input_tokens\": genAiInput,\n \"gen_ai.usage.output_tokens\": genAiOutput,\n \"gen_ai.usage.cost\": genAiCost,\n \"gen_ai.usage.cache_read_tokens\": genAiCacheRead,\n \"gen_ai.usage.cache_creation_tokens\": genAiCacheCreation,\n cache_read_tokens: detailCacheRead,\n cache_creation_tokens: detailCacheCreation,\n stop_reason: detailStopReason,\n turn_number: detailTurnNumber,\n turn_count: detailTurnCount,\n parent_conversation_id: detailParentConvId,\n input_bytes: detailInputBytes,\n output_bytes: detailOutputBytes,\n error_type: detailErrorType,\n retryable: detailRetryable,\n ...remainingDetails\n } = details;\n\n // Determine tool_name from resource_id when it's an mcp_tool\n const toolName = row.resource_type === \"mcp_tool\"\n ? (row.resource_id as string) || undefined\n : (details.tool_name as string) || undefined;\n\n // Compute token fields — prefer top-level, fall back to details.\n // Use ?? (not ||) for numeric fields so that 0 is not treated as falsy.\n const promptTokens = (row.input_tokens as number)\n ?? (genAiInput as number)\n ?? (detailInputTokens as number)\n ?? undefined;\n const completionTokens = (row.output_tokens as number)\n ?? (genAiOutput as number)\n ?? (detailOutputTokens as number)\n ?? undefined;\n const tokenCostUsd = (row.total_cost as number)\n ?? (genAiCost as number)\n ?? (detailCost as number)\n ?? undefined;\n const modelName = (row.model as string)\n || (genAiModel as string)\n || (detailModel as string)\n || undefined;\n\n return {\n span_id: (row.span_id as string) || randomHexId(),\n trace_id: (row.trace_id as string) || (row.request_id as string) || randomUUID(),\n store_id: (row.store_id as string) || undefined,\n service_name: (row.service_name as string) || \"agent-server\",\n operation_name: (row.action as string) || undefined,\n span_kind: (row.span_kind as string) || \"INTERNAL\",\n source: (row.source as string) || undefined,\n started_at: (row.start_time as string) || now,\n ended_at: (row.end_time as string) || now,\n duration_ms: (row.duration_ms as number) ?? 0,\n status_code: (row.status_code as string) || \"OK\",\n severity: (row.severity as string) || \"info\",\n model_name: modelName,\n prompt_tokens: promptTokens,\n completion_tokens: completionTokens,\n total_tokens: promptTokens && completionTokens ? promptTokens + completionTokens : undefined,\n token_cost_usd: tokenCostUsd,\n agent_id: (row.resource_id as string) || (details.agent_id as string) || undefined,\n conversation_id: (row.conversation_id as string) || undefined,\n tool_name: toolName,\n error_message: (row.error_message as string) || undefined,\n attributes: Object.keys(remainingDetails).length > 0 ? JSON.stringify(remainingDetails) : undefined,\n request_id: (row.request_id as string) || undefined,\n user_id: (row.user_id as string) || undefined,\n environment: \"production\",\n // Enriched columns (003_enrich_spans)\n user_email: (row.user_email as string) || undefined,\n error_type: (row.error_type as string) || (detailErrorType as string) || undefined,\n retryable: (detailRetryable as boolean) ? 1 : (row.severity === \"error\" ? 0 : undefined),\n resource_type: (row.resource_type as string) || undefined,\n cache_read_tokens: (genAiCacheRead as number) ?? (detailCacheRead as number) ?? undefined,\n cache_creation_tokens: (genAiCacheCreation as number) ?? (detailCacheCreation as number) ?? undefined,\n input_bytes: (row.input_bytes as number) ?? (detailInputBytes as number) ?? undefined,\n output_bytes: (row.output_bytes as number) ?? (detailOutputBytes as number) ?? undefined,\n stop_reason: (row.stop_reason as string) || (detailStopReason as string) || undefined,\n turn_number: (row.turn_number as number) ?? (detailTurnNumber as number) ?? (detailTurnCount as number) ?? undefined,\n parent_conversation_id: (row.parent_conversation_id as string) || (detailParentConvId as string) || undefined,\n };\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\n/**\n * Classify an error message into a standard error_type category.\n * Used by auditRowToSpan and callers to populate the error_type column.\n */\nexport function classifyErrorType(errorMessage: string | null | undefined): string | undefined {\n if (!errorMessage) return undefined;\n const lower = errorMessage.toLowerCase();\n if (lower.includes(\"rate limit\") || lower.includes(\"429\")) return \"rate_limit\";\n if (lower.includes(\"auth\") || lower.includes(\"401\") || lower.includes(\"403\")) return \"auth\";\n if (lower.includes(\"timeout\") || lower.includes(\"timed out\")) return \"timeout\";\n if (lower.includes(\"validation\") || lower.includes(\"invalid\")) return \"validation\";\n if (lower.includes(\"not found\") || lower.includes(\"404\")) return \"not_found\";\n if (lower.includes(\"overloaded\") || lower.includes(\"529\")) return \"overloaded\";\n if (lower.includes(\"circuit breaker\")) return \"circuit_breaker\";\n return undefined;\n}\n\nfunction randomHexId(): string {\n const bytes = new Uint8Array(8);\n crypto.getRandomValues(bytes);\n return Array.from(bytes).map(b => b.toString(16).padStart(2, \"0\")).join(\"\");\n}\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"clickhouse-buffer.js","names":["randomUUID","getClickHouseClient","spanBuffer","FLUSH_INTERVAL","FLUSH_MAX","flushTimer","queueSpan","span","push","length","flushSpans","setTimeout","clearTimeout","batch","splice","client","insert","auditRowToSpan","row","details","now","Date","toISOString","input_tokens","detailInputTokens","output_tokens","detailOutputTokens","total_cost","detailCost","model","detailModel","genAiModel","genAiInput","genAiOutput","genAiCost","genAiCacheRead","genAiCacheCreation","cache_read_tokens","detailCacheRead","cache_creation_tokens","detailCacheCreation","stop_reason","detailStopReason","turn_number","detailTurnNumber","turn_count","detailTurnCount","parent_conversation_id","detailParentConvId","input_bytes","detailInputBytes","output_bytes","detailOutputBytes","error_type","detailErrorType","retryable","detailRetryable","remainingDetails","toolName","resource_type","resource_id","undefined","tool_name","promptTokens","completionTokens","tokenCostUsd","modelName","span_id","randomHexId","trace_id","request_id","parent_span_id","store_id","service_name","operation_name","action","span_kind","source","started_at","start_time","ended_at","end_time","duration_ms","status_code","severity","model_name","prompt_tokens","completion_tokens","total_tokens","token_cost_usd","agent_id","conversation_id","error_message","attributes","Object","keys","JSON","stringify","user_id","environment","user_email","classifyErrorType","errorMessage","lower","toLowerCase","includes","bytes","Uint8Array","crypto","getRandomValues","Array","from","map","b","toString","padStart","join"],"sources":["../../../src/server/lib/clickhouse-buffer.ts"],"sourcesContent":["/**\n * ClickHouse Span Buffer — batches spans for bulk insert to ClickHouse ai_spans.\n *\n * Same batching semantics (500ms / 100 records).\n * Also provides auditRowToSpan() to convert legacy row shapes to ClickHouseSpan.\n */\n\nimport { randomUUID } from \"node:crypto\";\nimport { type ClickHouseSpan, getClickHouseClient } from \"./clickhouse-client.js\";\n\n// ============================================================================\n// Buffer config\n// ============================================================================\n\nconst spanBuffer: ClickHouseSpan[] = [];\nconst FLUSH_INTERVAL = 500; // ms\nconst FLUSH_MAX = 100; // max records before force flush\nlet flushTimer: ReturnType<typeof setTimeout> | null = null;\n\n// ============================================================================\n// Public API\n// ============================================================================\n\n/**\n * Queue a span for batch insert to ClickHouse.\n */\nexport function queueSpan(span: ClickHouseSpan): void {\n spanBuffer.push(span);\n\n if (spanBuffer.length >= FLUSH_MAX) {\n flushSpans();\n } else if (!flushTimer) {\n flushTimer = setTimeout(() => {\n flushTimer = null;\n flushSpans();\n }, FLUSH_INTERVAL);\n }\n}\n\n/**\n * Flush all buffered spans to ClickHouse.\n * Call this on server shutdown or at end of request processing.\n */\nexport async function flushSpans(): Promise<void> {\n if (flushTimer) {\n clearTimeout(flushTimer);\n flushTimer = null;\n }\n\n if (spanBuffer.length > 0) {\n const batch = spanBuffer.splice(0, spanBuffer.length);\n const client = getClickHouseClient();\n await client.insert(\"ai_spans\", batch as unknown as Record<string, unknown>[]);\n }\n}\n\n// ============================================================================\n// Mapper: audit_log row → ClickHouseSpan\n// ============================================================================\n\n/**\n * Convert an existing audit_log row to a ClickHouseSpan.\n *\n * Field mapping:\n * ai_spans.action → operation_name\n * ai_spans.source → source\n * ai_spans.severity → severity\n * ai_spans.store_id → store_id\n * ai_spans.duration_ms → duration_ms\n * ai_spans.error_message → error_message\n * ai_spans.trace_id → trace_id\n * ai_spans.span_id → span_id\n * ai_spans.span_kind → span_kind\n * ai_spans.service_name → service_name\n * ai_spans.status_code → status_code\n * ai_spans.start_time → started_at\n * ai_spans.end_time → ended_at\n * ai_spans.conversation_id → conversation_id\n * ai_spans.user_id → user_id\n * ai_spans.input_tokens → prompt_tokens\n * ai_spans.output_tokens → completion_tokens\n * ai_spans.total_cost → token_cost_usd\n * ai_spans.model → model_name\n * ai_spans.resource_id (mcp_tool) → tool_name\n * ai_spans.details (remaining) → attributes (JSON string)\n */\nexport function auditRowToSpan(row: Record<string, unknown>): ClickHouseSpan {\n const details = (row.details || {}) as Record<string, unknown>;\n const now = new Date().toISOString();\n\n // Extract known fields from details that map to top-level ClickHouse columns\n const {\n input_tokens: detailInputTokens,\n output_tokens: detailOutputTokens,\n total_cost: detailCost,\n model: detailModel,\n \"gen_ai.request.model\": genAiModel,\n \"gen_ai.usage.input_tokens\": genAiInput,\n \"gen_ai.usage.output_tokens\": genAiOutput,\n \"gen_ai.usage.cost\": genAiCost,\n \"gen_ai.usage.cache_read_tokens\": genAiCacheRead,\n \"gen_ai.usage.cache_creation_tokens\": genAiCacheCreation,\n cache_read_tokens: detailCacheRead,\n cache_creation_tokens: detailCacheCreation,\n stop_reason: detailStopReason,\n turn_number: detailTurnNumber,\n turn_count: detailTurnCount,\n parent_conversation_id: detailParentConvId,\n input_bytes: detailInputBytes,\n output_bytes: detailOutputBytes,\n error_type: detailErrorType,\n retryable: detailRetryable,\n ...remainingDetails\n } = details;\n\n // Determine tool_name from resource_id when it's an mcp_tool\n const toolName = row.resource_type === \"mcp_tool\"\n ? (row.resource_id as string) || undefined\n : (details.tool_name as string) || undefined;\n\n // Compute token fields — prefer top-level, fall back to details.\n // Use ?? (not ||) for numeric fields so that 0 is not treated as falsy.\n const promptTokens = (row.input_tokens as number)\n ?? (genAiInput as number)\n ?? (detailInputTokens as number)\n ?? undefined;\n const completionTokens = (row.output_tokens as number)\n ?? (genAiOutput as number)\n ?? (detailOutputTokens as number)\n ?? undefined;\n const tokenCostUsd = (row.total_cost as number)\n ?? (genAiCost as number)\n ?? (detailCost as number)\n ?? undefined;\n const modelName = (row.model as string)\n || (genAiModel as string)\n || (detailModel as string)\n || undefined;\n\n return {\n span_id: (row.span_id as string) || randomHexId(),\n trace_id: (row.trace_id as string) || (row.request_id as string) || randomUUID(),\n parent_span_id: (row.parent_span_id as string) || (details.parent_span_id as string) || undefined,\n store_id: (row.store_id as string) || undefined,\n service_name: (row.service_name as string) || \"agent-server\",\n operation_name: (row.action as string) || undefined,\n span_kind: (row.span_kind as string) || \"INTERNAL\",\n source: (row.source as string) || undefined,\n started_at: (row.start_time as string) || now,\n ended_at: (row.end_time as string) || now,\n duration_ms: (row.duration_ms as number) ?? 0,\n status_code: (row.status_code as string) || \"OK\",\n severity: (row.severity as string) || \"info\",\n model_name: modelName,\n prompt_tokens: promptTokens,\n completion_tokens: completionTokens,\n total_tokens: promptTokens && completionTokens ? promptTokens + completionTokens : undefined,\n token_cost_usd: tokenCostUsd,\n agent_id: (row.resource_id as string) || (details.agent_id as string) || undefined,\n conversation_id: (row.conversation_id as string) || undefined,\n tool_name: toolName,\n error_message: (row.error_message as string) || undefined,\n attributes: Object.keys(remainingDetails).length > 0 ? JSON.stringify(remainingDetails) : undefined,\n request_id: (row.request_id as string) || undefined,\n user_id: (row.user_id as string) || undefined,\n environment: \"production\",\n // Enriched columns (003_enrich_spans)\n user_email: (row.user_email as string) || undefined,\n error_type: (row.error_type as string) || (detailErrorType as string) || undefined,\n retryable: (detailRetryable as boolean) ? 1 : (row.severity === \"error\" ? 0 : undefined),\n resource_type: (row.resource_type as string) || undefined,\n cache_read_tokens: (genAiCacheRead as number) ?? (detailCacheRead as number) ?? undefined,\n cache_creation_tokens: (genAiCacheCreation as number) ?? (detailCacheCreation as number) ?? undefined,\n input_bytes: (row.input_bytes as number) ?? (detailInputBytes as number) ?? undefined,\n output_bytes: (row.output_bytes as number) ?? (detailOutputBytes as number) ?? undefined,\n stop_reason: (row.stop_reason as string) || (detailStopReason as string) || undefined,\n turn_number: (row.turn_number as number) ?? (detailTurnNumber as number) ?? (detailTurnCount as number) ?? undefined,\n parent_conversation_id: (row.parent_conversation_id as string) || (detailParentConvId as string) || undefined,\n };\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\n/**\n * Classify an error message into a standard error_type category.\n * Used by auditRowToSpan and callers to populate the error_type column.\n */\nexport function classifyErrorType(errorMessage: string | null | undefined): string | undefined {\n if (!errorMessage) return undefined;\n const lower = errorMessage.toLowerCase();\n if (lower.includes(\"rate limit\") || lower.includes(\"429\")) return \"rate_limit\";\n if (lower.includes(\"auth\") || lower.includes(\"401\") || lower.includes(\"403\")) return \"auth\";\n if (lower.includes(\"timeout\") || lower.includes(\"timed out\")) return \"timeout\";\n if (lower.includes(\"validation\") || lower.includes(\"invalid\")) return \"validation\";\n if (lower.includes(\"not found\") || lower.includes(\"404\")) return \"not_found\";\n if (lower.includes(\"overloaded\") || lower.includes(\"529\")) return \"overloaded\";\n if (lower.includes(\"circuit breaker\")) return \"circuit_breaker\";\n return undefined;\n}\n\nfunction randomHexId(): string {\n const bytes = new Uint8Array(8);\n crypto.getRandomValues(bytes);\n return Array.from(bytes).map(b => b.toString(16).padStart(2, \"0\")).join(\"\");\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
export interface COAData {
|
|
2
2
|
labName?: string;
|
|
3
|
+
labAddress?: string;
|
|
3
4
|
labContact?: string;
|
|
4
5
|
logoUrl?: string;
|
|
5
6
|
labWebsite?: string;
|
|
6
7
|
labDirector?: string;
|
|
7
8
|
directorTitle?: string;
|
|
8
9
|
signatureUrl?: string;
|
|
9
|
-
approvalDate?: string;
|
|
10
10
|
sampleName: string;
|
|
11
11
|
sampleId: string;
|
|
12
12
|
strain?: string;
|
|
@@ -750,9 +750,15 @@ const PanelPageHeader = ({
|
|
|
750
750
|
style: styles.companySubname
|
|
751
751
|
}, (data.labName || "").split(" ").slice(1).join(" ") || "")), e(View, {
|
|
752
752
|
style: styles.divider
|
|
753
|
-
}), e(Text, {
|
|
753
|
+
}), e(View, null, e(Text, {
|
|
754
754
|
style: styles.labContact
|
|
755
|
-
}, data.labContact || "")
|
|
755
|
+
}, data.labContact || ""), data.labAddress ? e(Text, {
|
|
756
|
+
style: {
|
|
757
|
+
fontSize: 7,
|
|
758
|
+
color: colors.gray600,
|
|
759
|
+
lineHeight: 1.3
|
|
760
|
+
}
|
|
761
|
+
}, data.labAddress) : null)), e(Text, {
|
|
756
762
|
style: {
|
|
757
763
|
...styles.docTitle,
|
|
758
764
|
fontSize: 10,
|
|
@@ -917,7 +923,7 @@ const PanelPageFooter = ({
|
|
|
917
923
|
style: styles.signatureTitle
|
|
918
924
|
}, data.directorTitle || "Laboratory Director"), e(Text, {
|
|
919
925
|
style: styles.signatureTitle
|
|
920
|
-
}, data.
|
|
926
|
+
}, data.dateTested || "\u2014"), e(Text, {
|
|
921
927
|
style: {
|
|
922
928
|
fontSize: 7,
|
|
923
929
|
color: colors.gray500,
|
|
@@ -1427,9 +1433,15 @@ const CannabisCOADocument = ({
|
|
|
1427
1433
|
style: styles.companySubname
|
|
1428
1434
|
}, (data.labName || "").split(" ").slice(1).join(" ") || "")), e(View, {
|
|
1429
1435
|
style: styles.divider
|
|
1430
|
-
}), e(Text, {
|
|
1436
|
+
}), e(View, null, e(Text, {
|
|
1431
1437
|
style: styles.labContact
|
|
1432
|
-
}, data.labContact || "")
|
|
1438
|
+
}, data.labContact || ""), data.labAddress ? e(Text, {
|
|
1439
|
+
style: {
|
|
1440
|
+
fontSize: 7,
|
|
1441
|
+
color: colors.gray600,
|
|
1442
|
+
lineHeight: 1.3
|
|
1443
|
+
}
|
|
1444
|
+
}, data.labAddress) : null)), e(Text, {
|
|
1433
1445
|
style: styles.docTitle
|
|
1434
1446
|
}, "Certificate of Analysis")), e(View, {
|
|
1435
1447
|
style: styles.sampleSection
|
|
@@ -1778,14 +1790,24 @@ const CannabisCOADocument = ({
|
|
|
1778
1790
|
style: styles.signatureTitle
|
|
1779
1791
|
}, data.directorTitle || "Laboratory Director"), e(Text, {
|
|
1780
1792
|
style: styles.signatureTitle
|
|
1781
|
-
}, data.
|
|
1793
|
+
}, data.dateTested || "\u2014")))), data.fullPanel ? e(View, {
|
|
1794
|
+
style: {
|
|
1795
|
+
position: "absolute",
|
|
1796
|
+
bottom: 20,
|
|
1797
|
+
left: 20,
|
|
1798
|
+
right: 20,
|
|
1799
|
+
flexDirection: "row",
|
|
1800
|
+
justifyContent: "flex-end",
|
|
1801
|
+
borderTopWidth: 1,
|
|
1802
|
+
borderTopColor: colors.gray200,
|
|
1803
|
+
paddingTop: 8
|
|
1804
|
+
}
|
|
1805
|
+
}, e(Text, {
|
|
1782
1806
|
style: {
|
|
1783
1807
|
fontSize: 7,
|
|
1784
|
-
color: colors.
|
|
1785
|
-
marginTop: 8,
|
|
1786
|
-
textAlign: "right"
|
|
1808
|
+
color: colors.gray600
|
|
1787
1809
|
}
|
|
1788
|
-
}, `Page 1 of ${totalPages}`) : null))
|
|
1810
|
+
}, `Page 1 of ${totalPages}`)) : null));
|
|
1789
1811
|
if (data.fullPanel) {
|
|
1790
1812
|
pages.push(e(SafetyTestingPage, {
|
|
1791
1813
|
key: "page2",
|