hazo_llm_api 1.2.13 → 1.3.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.md +321 -8
- package/config/hazo_llm_api_config.ini +33 -0
- package/dist/components/index.d.ts +2 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +2 -0
- package/dist/components/index.js.map +1 -1
- package/dist/components/llm_call_inspector/index.d.ts +6 -0
- package/dist/components/llm_call_inspector/index.d.ts.map +1 -0
- package/dist/components/llm_call_inspector/index.js +5 -0
- package/dist/components/llm_call_inspector/index.js.map +1 -0
- package/dist/components/llm_call_inspector/llm_call_inspector.d.ts +18 -0
- package/dist/components/llm_call_inspector/llm_call_inspector.d.ts.map +1 -0
- package/dist/components/llm_call_inspector/llm_call_inspector.js +103 -0
- package/dist/components/llm_call_inspector/llm_call_inspector.js.map +1 -0
- package/dist/components/llm_cost_dashboard/index.d.ts +6 -0
- package/dist/components/llm_cost_dashboard/index.d.ts.map +1 -0
- package/dist/components/llm_cost_dashboard/index.js +5 -0
- package/dist/components/llm_cost_dashboard/index.js.map +1 -0
- package/dist/components/llm_cost_dashboard/llm_cost_dashboard.d.ts +16 -0
- package/dist/components/llm_cost_dashboard/llm_cost_dashboard.d.ts.map +1 -0
- package/dist/components/llm_cost_dashboard/llm_cost_dashboard.js +154 -0
- package/dist/components/llm_cost_dashboard/llm_cost_dashboard.js.map +1 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/lib/cascade/cascade_runner.d.ts +50 -0
- package/dist/lib/cascade/cascade_runner.d.ts.map +1 -0
- package/dist/lib/cascade/cascade_runner.js +115 -0
- package/dist/lib/cascade/cascade_runner.js.map +1 -0
- package/dist/lib/cascade/index.d.ts +5 -0
- package/dist/lib/cascade/index.d.ts.map +1 -0
- package/dist/lib/cascade/index.js +4 -0
- package/dist/lib/cascade/index.js.map +1 -0
- package/dist/lib/cascade/types.d.ts +35 -0
- package/dist/lib/cascade/types.d.ts.map +1 -0
- package/dist/lib/cascade/types.js +14 -0
- package/dist/lib/cascade/types.js.map +1 -0
- package/dist/lib/cost_cap/cost_cap.d.ts +40 -0
- package/dist/lib/cost_cap/cost_cap.d.ts.map +1 -0
- package/dist/lib/cost_cap/cost_cap.js +150 -0
- package/dist/lib/cost_cap/cost_cap.js.map +1 -0
- package/dist/lib/cost_cap/index.d.ts +3 -0
- package/dist/lib/cost_cap/index.d.ts.map +1 -0
- package/dist/lib/cost_cap/index.js +2 -0
- package/dist/lib/cost_cap/index.js.map +1 -0
- package/dist/lib/database/init_api_log.d.ts +10 -0
- package/dist/lib/database/init_api_log.d.ts.map +1 -0
- package/dist/lib/database/init_api_log.js +91 -0
- package/dist/lib/database/init_api_log.js.map +1 -0
- package/dist/lib/hazo_connect/direct_db_connect.d.ts +11 -7
- package/dist/lib/hazo_connect/direct_db_connect.d.ts.map +1 -1
- package/dist/lib/hazo_connect/direct_db_connect.js +59 -6
- package/dist/lib/hazo_connect/direct_db_connect.js.map +1 -1
- package/dist/lib/hazo_connect/types.d.ts +35 -3
- package/dist/lib/hazo_connect/types.d.ts.map +1 -1
- package/dist/lib/llm_api/embed_cache.d.ts +15 -0
- package/dist/lib/llm_api/embed_cache.d.ts.map +1 -0
- package/dist/lib/llm_api/embed_cache.js +53 -0
- package/dist/lib/llm_api/embed_cache.js.map +1 -0
- package/dist/lib/llm_api/hazo_llm_document_text.d.ts.map +1 -1
- package/dist/lib/llm_api/hazo_llm_document_text.js +56 -14
- package/dist/lib/llm_api/hazo_llm_document_text.js.map +1 -1
- package/dist/lib/llm_api/hazo_llm_dynamic_data_extract.d.ts.map +1 -1
- package/dist/lib/llm_api/hazo_llm_dynamic_data_extract.js +19 -1
- package/dist/lib/llm_api/hazo_llm_dynamic_data_extract.js.map +1 -1
- package/dist/lib/llm_api/hazo_llm_embed.d.ts +10 -0
- package/dist/lib/llm_api/hazo_llm_embed.d.ts.map +1 -0
- package/dist/lib/llm_api/hazo_llm_embed.js +80 -0
- package/dist/lib/llm_api/hazo_llm_embed.js.map +1 -0
- package/dist/lib/llm_api/hazo_llm_image_image.d.ts.map +1 -1
- package/dist/lib/llm_api/hazo_llm_image_image.js +56 -14
- package/dist/lib/llm_api/hazo_llm_image_image.js.map +1 -1
- package/dist/lib/llm_api/hazo_llm_image_text.d.ts.map +1 -1
- package/dist/lib/llm_api/hazo_llm_image_text.js +56 -14
- package/dist/lib/llm_api/hazo_llm_image_text.js.map +1 -1
- package/dist/lib/llm_api/hazo_llm_prompt_chain.d.ts.map +1 -1
- package/dist/lib/llm_api/hazo_llm_prompt_chain.js +17 -1
- package/dist/lib/llm_api/hazo_llm_prompt_chain.js.map +1 -1
- package/dist/lib/llm_api/hazo_llm_text_image.d.ts.map +1 -1
- package/dist/lib/llm_api/hazo_llm_text_image.js +56 -14
- package/dist/lib/llm_api/hazo_llm_text_image.js.map +1 -1
- package/dist/lib/llm_api/hazo_llm_text_text.d.ts.map +1 -1
- package/dist/lib/llm_api/hazo_llm_text_text.js +90 -15
- package/dist/lib/llm_api/hazo_llm_text_text.js.map +1 -1
- package/dist/lib/llm_api/index.d.ts +29 -1
- package/dist/lib/llm_api/index.d.ts.map +1 -1
- package/dist/lib/llm_api/index.js +433 -6
- package/dist/lib/llm_api/index.js.map +1 -1
- package/dist/lib/llm_api/prompt_parts_helper.d.ts +15 -0
- package/dist/lib/llm_api/prompt_parts_helper.d.ts.map +1 -0
- package/dist/lib/llm_api/prompt_parts_helper.js +9 -0
- package/dist/lib/llm_api/prompt_parts_helper.js.map +1 -0
- package/dist/lib/llm_api/types.d.ts +187 -2
- package/dist/lib/llm_api/types.d.ts.map +1 -1
- package/dist/lib/llm_api/types.js +4 -0
- package/dist/lib/llm_api/types.js.map +1 -1
- package/dist/lib/maintenance/purge_log_job.d.ts +23 -0
- package/dist/lib/maintenance/purge_log_job.d.ts.map +1 -0
- package/dist/lib/maintenance/purge_log_job.js +42 -0
- package/dist/lib/maintenance/purge_log_job.js.map +1 -0
- package/dist/lib/observability/log_context.d.ts +15 -0
- package/dist/lib/observability/log_context.d.ts.map +1 -0
- package/dist/lib/observability/log_context.js +32 -0
- package/dist/lib/observability/log_context.js.map +1 -0
- package/dist/lib/observability/log_writer.d.ts +35 -0
- package/dist/lib/observability/log_writer.d.ts.map +1 -0
- package/dist/lib/observability/log_writer.js +106 -0
- package/dist/lib/observability/log_writer.js.map +1 -0
- package/dist/lib/observability/queries.d.ts +15 -0
- package/dist/lib/observability/queries.d.ts.map +1 -0
- package/dist/lib/observability/queries.js +78 -0
- package/dist/lib/observability/queries.js.map +1 -0
- package/dist/lib/observability/types.d.ts +77 -0
- package/dist/lib/observability/types.d.ts.map +1 -0
- package/dist/lib/observability/types.js +8 -0
- package/dist/lib/observability/types.js.map +1 -0
- package/dist/lib/pricing/pricing.d.ts +49 -0
- package/dist/lib/pricing/pricing.d.ts.map +1 -0
- package/dist/lib/pricing/pricing.js +153 -0
- package/dist/lib/pricing/pricing.js.map +1 -0
- package/dist/lib/pricing/pricing.json +75 -0
- package/dist/lib/pricing/types.d.ts +58 -0
- package/dist/lib/pricing/types.d.ts.map +1 -0
- package/dist/lib/pricing/types.js +8 -0
- package/dist/lib/pricing/types.js.map +1 -0
- package/dist/lib/providers/anthropic/anthropic_client.d.ts +71 -0
- package/dist/lib/providers/anthropic/anthropic_client.d.ts.map +1 -0
- package/dist/lib/providers/anthropic/anthropic_client.js +134 -0
- package/dist/lib/providers/anthropic/anthropic_client.js.map +1 -0
- package/dist/lib/providers/anthropic/anthropic_provider.d.ts +60 -0
- package/dist/lib/providers/anthropic/anthropic_provider.d.ts.map +1 -0
- package/dist/lib/providers/anthropic/anthropic_provider.js +273 -0
- package/dist/lib/providers/anthropic/anthropic_provider.js.map +1 -0
- package/dist/lib/providers/anthropic/anthropic_response_to_usage.d.ts +21 -0
- package/dist/lib/providers/anthropic/anthropic_response_to_usage.d.ts.map +1 -0
- package/dist/lib/providers/anthropic/anthropic_response_to_usage.js +46 -0
- package/dist/lib/providers/anthropic/anthropic_response_to_usage.js.map +1 -0
- package/dist/lib/providers/anthropic/index.d.ts +3 -0
- package/dist/lib/providers/anthropic/index.d.ts.map +1 -0
- package/dist/lib/providers/anthropic/index.js +2 -0
- package/dist/lib/providers/anthropic/index.js.map +1 -0
- package/dist/lib/providers/deepseek/deepseek_client.d.ts +55 -0
- package/dist/lib/providers/deepseek/deepseek_client.d.ts.map +1 -0
- package/dist/lib/providers/deepseek/deepseek_client.js +129 -0
- package/dist/lib/providers/deepseek/deepseek_client.js.map +1 -0
- package/dist/lib/providers/deepseek/deepseek_provider.d.ts +50 -0
- package/dist/lib/providers/deepseek/deepseek_provider.d.ts.map +1 -0
- package/dist/lib/providers/deepseek/deepseek_provider.js +147 -0
- package/dist/lib/providers/deepseek/deepseek_provider.js.map +1 -0
- package/dist/lib/providers/deepseek/deepseek_response_to_usage.d.ts +21 -0
- package/dist/lib/providers/deepseek/deepseek_response_to_usage.d.ts.map +1 -0
- package/dist/lib/providers/deepseek/deepseek_response_to_usage.js +40 -0
- package/dist/lib/providers/deepseek/deepseek_response_to_usage.js.map +1 -0
- package/dist/lib/providers/deepseek/index.d.ts +3 -0
- package/dist/lib/providers/deepseek/index.d.ts.map +1 -0
- package/dist/lib/providers/deepseek/index.js +2 -0
- package/dist/lib/providers/deepseek/index.js.map +1 -0
- package/dist/lib/providers/gemini/gemini_provider.d.ts.map +1 -1
- package/dist/lib/providers/gemini/gemini_provider.js +40 -4
- package/dist/lib/providers/gemini/gemini_provider.js.map +1 -1
- package/dist/lib/providers/gemini/gemini_response_to_usage.d.ts +37 -0
- package/dist/lib/providers/gemini/gemini_response_to_usage.d.ts.map +1 -0
- package/dist/lib/providers/gemini/gemini_response_to_usage.js +49 -0
- package/dist/lib/providers/gemini/gemini_response_to_usage.js.map +1 -0
- package/dist/lib/providers/index.d.ts +3 -0
- package/dist/lib/providers/index.d.ts.map +1 -1
- package/dist/lib/providers/index.js +3 -0
- package/dist/lib/providers/index.js.map +1 -1
- package/dist/lib/providers/openai/index.d.ts +3 -0
- package/dist/lib/providers/openai/index.d.ts.map +1 -0
- package/dist/lib/providers/openai/index.js +2 -0
- package/dist/lib/providers/openai/index.js.map +1 -0
- package/dist/lib/providers/openai/openai_client.d.ts +99 -0
- package/dist/lib/providers/openai/openai_client.d.ts.map +1 -0
- package/dist/lib/providers/openai/openai_client.js +187 -0
- package/dist/lib/providers/openai/openai_client.js.map +1 -0
- package/dist/lib/providers/openai/openai_provider.d.ts +66 -0
- package/dist/lib/providers/openai/openai_provider.d.ts.map +1 -0
- package/dist/lib/providers/openai/openai_provider.js +297 -0
- package/dist/lib/providers/openai/openai_provider.js.map +1 -0
- package/dist/lib/providers/openai/openai_response_to_usage.d.ts +21 -0
- package/dist/lib/providers/openai/openai_response_to_usage.d.ts.map +1 -0
- package/dist/lib/providers/openai/openai_response_to_usage.js +50 -0
- package/dist/lib/providers/openai/openai_response_to_usage.js.map +1 -0
- package/dist/lib/providers/qwen/qwen_provider.d.ts.map +1 -1
- package/dist/lib/providers/qwen/qwen_provider.js +52 -5
- package/dist/lib/providers/qwen/qwen_provider.js.map +1 -1
- package/dist/lib/providers/qwen/qwen_response_to_usage.d.ts +36 -0
- package/dist/lib/providers/qwen/qwen_response_to_usage.d.ts.map +1 -0
- package/dist/lib/providers/qwen/qwen_response_to_usage.js +50 -0
- package/dist/lib/providers/qwen/qwen_response_to_usage.js.map +1 -0
- package/dist/lib/providers/types.d.ts +16 -6
- package/dist/lib/providers/types.d.ts.map +1 -1
- package/dist/lib/providers/types.js +1 -0
- package/dist/lib/providers/types.js.map +1 -1
- package/dist/lib/utils.d.ts +13 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/dist/lib/utils.js +16 -0
- package/dist/lib/utils.js.map +1 -0
- package/dist/server.d.ts +16 -2
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +29 -2
- package/dist/server.js.map +1 -1
- package/migrations/hazo_llm_api_log.sql +69 -0
- package/package.json +19 -5
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* llm_api_purge_log_job — deletes hazo_llm_api_log rows older than retention_days.
|
|
3
|
+
*
|
|
4
|
+
* Usage (consumer app):
|
|
5
|
+
* ```typescript
|
|
6
|
+
* import { createJobsClient, register_maintenance_jobs } from 'hazo_jobs/server';
|
|
7
|
+
* import { llm_api_purge_log_job } from 'hazo_llm_api/server';
|
|
8
|
+
*
|
|
9
|
+
* const client = createJobsClient({ connect: { adapter }, dialect: 'sqlite' });
|
|
10
|
+
* const worker = client.worker({
|
|
11
|
+
* workerId: 'maint-worker',
|
|
12
|
+
* types: [llm_api_purge_log_job.type],
|
|
13
|
+
* });
|
|
14
|
+
* await register_maintenance_jobs(client, worker, [llm_api_purge_log_job]);
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
import { get_hazo_connect } from '../llm_api/index.js';
|
|
18
|
+
export const llm_api_purge_log_job = {
|
|
19
|
+
type: 'hazo_llm_api.purge_log',
|
|
20
|
+
defaultCron: '0 3 * * *', // daily at 03:00 UTC
|
|
21
|
+
defaultPayload: { retention_days: 90 },
|
|
22
|
+
description: 'Delete hazo_llm_api_log rows older than retention_days',
|
|
23
|
+
handler: async (job) => {
|
|
24
|
+
const connect = get_hazo_connect();
|
|
25
|
+
if (!connect) {
|
|
26
|
+
throw new Error('hazo_llm_api purge_log: no database adapter configured; ' +
|
|
27
|
+
'call initialize_llm_api() before starting the maintenance worker.');
|
|
28
|
+
}
|
|
29
|
+
if (!connect.raw_sql) {
|
|
30
|
+
throw new Error('hazo_llm_api purge_log: the configured HazoConnect does not expose raw_sql; ' +
|
|
31
|
+
'purge requires direct SQL access.');
|
|
32
|
+
}
|
|
33
|
+
const { retention_days } = job.payload;
|
|
34
|
+
const cutoff = new Date(Date.now() - retention_days * 86400000).toISOString();
|
|
35
|
+
const is_pg = connect.dialect === 'pg';
|
|
36
|
+
const sql = is_pg
|
|
37
|
+
? 'DELETE FROM hazo_llm_api_log WHERE created_at < $1'
|
|
38
|
+
: 'DELETE FROM hazo_llm_api_log WHERE created_at < ?';
|
|
39
|
+
await connect.raw_sql(sql, [cutoff]);
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
//# sourceMappingURL=purge_log_job.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"purge_log_job.js","sourceRoot":"","sources":["../../../src/lib/maintenance/purge_log_job.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAOvD,MAAM,CAAC,MAAM,qBAAqB,GAAoC;IACpE,IAAI,EAAE,wBAAwB;IAC9B,WAAW,EAAE,WAAW,EAAE,qBAAqB;IAC/C,cAAc,EAAE,EAAE,cAAc,EAAE,EAAE,EAAE;IACtC,WAAW,EAAE,wDAAwD;IAErE,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;QACrB,MAAM,OAAO,GAAG,gBAAgB,EAAE,CAAC;QAEnC,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CACb,0DAA0D;gBAC1D,mEAAmE,CACpE,CAAC;QACJ,CAAC;QAED,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;YACrB,MAAM,IAAI,KAAK,CACb,8EAA8E;gBAC9E,mCAAmC,CACpC,CAAC;QACJ,CAAC;QAED,MAAM,EAAE,cAAc,EAAE,GAAG,GAAG,CAAC,OAAO,CAAC;QACvC,MAAM,MAAM,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,cAAc,GAAG,QAAU,CAAC,CAAC,WAAW,EAAE,CAAC;QAEhF,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,KAAK,IAAI,CAAC;QACvC,MAAM,GAAG,GAAG,KAAK;YACf,CAAC,CAAC,oDAAoD;YACtD,CAAC,CAAC,mDAAmD,CAAC;QAExD,MAAM,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;IACvC,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Safe wrapper around hazo_logs' AsyncLocalStorage context.
|
|
3
|
+
*
|
|
4
|
+
* hazo_logs is an OPTIONAL peer dep. When it's not installed, this module returns null
|
|
5
|
+
* and downstream callers fall back to writing null session_id / reference into the log.
|
|
6
|
+
*/
|
|
7
|
+
export interface SafeLogContext {
|
|
8
|
+
sessionId?: string;
|
|
9
|
+
reference?: string;
|
|
10
|
+
}
|
|
11
|
+
/** Returns the current ALS context if hazo_logs is installed AND a session is active; null otherwise. */
|
|
12
|
+
export declare function safe_get_log_context(): Promise<SafeLogContext | null>;
|
|
13
|
+
/** Test helper — clears the cached getter so the next call re-imports. */
|
|
14
|
+
export declare function reset_log_context_for_test(): void;
|
|
15
|
+
//# sourceMappingURL=log_context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log_context.d.ts","sourceRoot":"","sources":["../../../src/lib/observability/log_context.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,WAAW,cAAc;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAgBD,yGAAyG;AACzG,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAI3E;AAED,0EAA0E;AAC1E,wBAAgB,0BAA0B,IAAI,IAAI,CAEjD"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Safe wrapper around hazo_logs' AsyncLocalStorage context.
|
|
3
|
+
*
|
|
4
|
+
* hazo_logs is an OPTIONAL peer dep. When it's not installed, this module returns null
|
|
5
|
+
* and downstream callers fall back to writing null session_id / reference into the log.
|
|
6
|
+
*/
|
|
7
|
+
let cached_getter = undefined;
|
|
8
|
+
async function load_getter() {
|
|
9
|
+
if (cached_getter !== undefined)
|
|
10
|
+
return cached_getter;
|
|
11
|
+
try {
|
|
12
|
+
const mod = await import("hazo_logs/server");
|
|
13
|
+
cached_getter = mod.getLogContext;
|
|
14
|
+
return cached_getter;
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
cached_getter = null;
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/** Returns the current ALS context if hazo_logs is installed AND a session is active; null otherwise. */
|
|
22
|
+
export async function safe_get_log_context() {
|
|
23
|
+
const getter = await load_getter();
|
|
24
|
+
if (getter === null)
|
|
25
|
+
return null;
|
|
26
|
+
return getter() ?? null;
|
|
27
|
+
}
|
|
28
|
+
/** Test helper — clears the cached getter so the next call re-imports. */
|
|
29
|
+
export function reset_log_context_for_test() {
|
|
30
|
+
cached_getter = undefined;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=log_context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log_context.js","sourceRoot":"","sources":["../../../src/lib/observability/log_context.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH,IAAI,aAAa,GAA0D,SAAS,CAAC;AAErF,KAAK,UAAU,WAAW;IACxB,IAAI,aAAa,KAAK,SAAS;QAAE,OAAO,aAAa,CAAC;IACtD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,kBAAyB,CAAC,CAAC;QACpD,aAAa,GAAG,GAAG,CAAC,aAAmD,CAAC;QACxE,OAAO,aAAa,CAAC;IACvB,CAAC;IAAC,MAAM,CAAC;QACP,aAAa,GAAG,IAAI,CAAC;QACrB,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,yGAAyG;AACzG,MAAM,CAAC,KAAK,UAAU,oBAAoB;IACxC,MAAM,MAAM,GAAG,MAAM,WAAW,EAAE,CAAC;IACnC,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IACjC,OAAO,MAAM,EAAE,IAAI,IAAI,CAAC;AAC1B,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,0BAA0B;IACxC,aAAa,GAAG,SAAS,CAAC;AAC5B,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default afterResponse hook: writes one row to hazo_llm_api_log per LLM call.
|
|
3
|
+
*
|
|
4
|
+
* Failures are swallowed (logged as warn) — the hook MUST NOT throw, so it never
|
|
5
|
+
* disrupts the calling service function.
|
|
6
|
+
*/
|
|
7
|
+
import type { HazoConnect } from "../hazo_connect/types.js";
|
|
8
|
+
import type { Logger, AfterResponseHook } from "../llm_api/types.js";
|
|
9
|
+
export interface DefaultLogWriterOpts {
|
|
10
|
+
/** HazoConnect instance providing raw_sql access to hazo_llm_api_log. */
|
|
11
|
+
connect: HazoConnect;
|
|
12
|
+
/** Logger for warning on write failures. */
|
|
13
|
+
logger: Logger;
|
|
14
|
+
/**
|
|
15
|
+
* Optional callback returning consumer-defined key/value pairs stored in
|
|
16
|
+
* context_json. Runs once per call, failures are swallowed.
|
|
17
|
+
*/
|
|
18
|
+
extract_context?: (ctx: {
|
|
19
|
+
service_type: string;
|
|
20
|
+
provider: string;
|
|
21
|
+
request_params: Record<string, unknown>;
|
|
22
|
+
}) => Record<string, unknown> | Promise<Record<string, unknown>>;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Build an afterResponse hook that writes one row to hazo_llm_api_log per call.
|
|
26
|
+
*
|
|
27
|
+
* The returned hook:
|
|
28
|
+
* - Never throws (all errors are caught and logged as warn)
|
|
29
|
+
* - Computes cost via the bundled pricing table
|
|
30
|
+
* - Captures prompt_area/prompt_key from request params when present
|
|
31
|
+
* - Reads session_id/reference from hazo_logs AsyncLocalStorage when available
|
|
32
|
+
* - Merges consumer-supplied context via extract_context option
|
|
33
|
+
*/
|
|
34
|
+
export declare function create_default_after_response_hook(opts: DefaultLogWriterOpts): AfterResponseHook;
|
|
35
|
+
//# sourceMappingURL=log_writer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log_writer.d.ts","sourceRoot":"","sources":["../../../src/lib/observability/log_writer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,KAAK,EAAE,MAAM,EAAE,iBAAiB,EAAsB,MAAM,qBAAqB,CAAC;AAQzF,MAAM,WAAW,oBAAoB;IACnC,yEAAyE;IACzE,OAAO,EAAE,WAAW,CAAC;IAErB,4CAA4C;IAC5C,MAAM,EAAE,MAAM,CAAC;IAEf;;;OAGG;IACH,eAAe,CAAC,EAAE,CAAC,GAAG,EAAE;QACtB,YAAY,EAAE,MAAM,CAAC;QACrB,QAAQ,EAAE,MAAM,CAAC;QACjB,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACzC,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CAClE;AAED;;;;;;;;;GASG;AACH,wBAAgB,kCAAkC,CAChD,IAAI,EAAE,oBAAoB,GACzB,iBAAiB,CAYnB"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default afterResponse hook: writes one row to hazo_llm_api_log per LLM call.
|
|
3
|
+
*
|
|
4
|
+
* Failures are swallowed (logged as warn) — the hook MUST NOT throw, so it never
|
|
5
|
+
* disrupts the calling service function.
|
|
6
|
+
*/
|
|
7
|
+
import { randomUUID } from "crypto";
|
|
8
|
+
import { compute_cost } from "../pricing/pricing.js";
|
|
9
|
+
import { safe_get_log_context } from "./log_context.js";
|
|
10
|
+
/**
|
|
11
|
+
* Build an afterResponse hook that writes one row to hazo_llm_api_log per call.
|
|
12
|
+
*
|
|
13
|
+
* The returned hook:
|
|
14
|
+
* - Never throws (all errors are caught and logged as warn)
|
|
15
|
+
* - Computes cost via the bundled pricing table
|
|
16
|
+
* - Captures prompt_area/prompt_key from request params when present
|
|
17
|
+
* - Reads session_id/reference from hazo_logs AsyncLocalStorage when available
|
|
18
|
+
* - Merges consumer-supplied context via extract_context option
|
|
19
|
+
*/
|
|
20
|
+
export function create_default_after_response_hook(opts) {
|
|
21
|
+
return async (ctx) => {
|
|
22
|
+
try {
|
|
23
|
+
await write_row(ctx, opts);
|
|
24
|
+
}
|
|
25
|
+
catch (err) {
|
|
26
|
+
opts.logger.warn("Failed to write hazo_llm_api_log row", {
|
|
27
|
+
error: err instanceof Error ? err.message : String(err),
|
|
28
|
+
service_type: ctx.service_type,
|
|
29
|
+
provider: ctx.provider,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
// =============================================================================
|
|
35
|
+
// Internal helpers
|
|
36
|
+
// =============================================================================
|
|
37
|
+
async function write_row(ctx, opts) {
|
|
38
|
+
// raw_sql is optional on HazoConnect — bail gracefully when absent.
|
|
39
|
+
if (!opts.connect.raw_sql) {
|
|
40
|
+
opts.logger.warn("hazo_llm_api_log: connect.raw_sql is not available; skipping log write", { service_type: ctx.service_type, provider: ctx.provider });
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const log_ctx = await safe_get_log_context();
|
|
44
|
+
const params = (ctx.params ?? {});
|
|
45
|
+
// Resolve consumer-defined context (swallow failures).
|
|
46
|
+
let extracted = {};
|
|
47
|
+
if (opts.extract_context) {
|
|
48
|
+
try {
|
|
49
|
+
extracted = await opts.extract_context({
|
|
50
|
+
service_type: ctx.service_type,
|
|
51
|
+
provider: ctx.provider,
|
|
52
|
+
request_params: params,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
catch (err) {
|
|
56
|
+
opts.logger.warn("extract_context threw; context_json will be empty", {
|
|
57
|
+
error: err instanceof Error ? err.message : String(err),
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
// Enrich usage with cost if pricing is known.
|
|
62
|
+
const raw_usage = ctx.response.usage;
|
|
63
|
+
const usage = raw_usage ? compute_cost(raw_usage) : undefined;
|
|
64
|
+
const success_val = ctx.response.success ? 1 : 0;
|
|
65
|
+
const error_info = ctx.response.error_info;
|
|
66
|
+
// Decompose pricing_applied into flat columns.
|
|
67
|
+
const pricing = usage?.pricing_applied;
|
|
68
|
+
const pricing_kind = pricing?.kind ?? null;
|
|
69
|
+
const pricing_input = pricing && pricing.kind === "text" ? pricing.input_per_1m_usd : null;
|
|
70
|
+
const pricing_output = pricing && pricing.kind === "text" ? pricing.output_per_1m_usd : null;
|
|
71
|
+
const pricing_image = pricing && pricing.kind === "image" ? pricing.per_image_usd : null;
|
|
72
|
+
const row = {
|
|
73
|
+
id: randomUUID(),
|
|
74
|
+
service_type: ctx.service_type,
|
|
75
|
+
provider: ctx.provider,
|
|
76
|
+
model: usage?.model ?? null,
|
|
77
|
+
success: success_val,
|
|
78
|
+
tokens_input: usage?.tokens.input ?? null,
|
|
79
|
+
tokens_output: usage?.tokens.output ?? null,
|
|
80
|
+
tokens_cached_input: usage?.tokens.cached_input ?? null,
|
|
81
|
+
tokens_total: usage?.tokens.total ?? null,
|
|
82
|
+
cost_usd: usage?.cost_usd ?? null,
|
|
83
|
+
pricing_kind,
|
|
84
|
+
pricing_input_per_1m_usd: pricing_input,
|
|
85
|
+
pricing_output_per_1m_usd: pricing_output,
|
|
86
|
+
pricing_per_image_usd: pricing_image,
|
|
87
|
+
latency_ms: usage?.latency_ms ?? ctx.duration_ms ?? null,
|
|
88
|
+
finish_reason: usage?.finish_reason ?? null,
|
|
89
|
+
error_code: error_info?.code ?? null,
|
|
90
|
+
error_message: error_info?.message ?? null,
|
|
91
|
+
prompt_area: typeof params.prompt_area === "string" ? params.prompt_area : null,
|
|
92
|
+
prompt_key: typeof params.prompt_key === "string" ? params.prompt_key : null,
|
|
93
|
+
prompt_id: typeof params.prompt_id === "string" ? params.prompt_id : null,
|
|
94
|
+
session_id: log_ctx?.sessionId ?? null,
|
|
95
|
+
reference: log_ctx?.reference ?? null,
|
|
96
|
+
attempts_count: 1,
|
|
97
|
+
context_json: JSON.stringify(extracted),
|
|
98
|
+
};
|
|
99
|
+
const columns = Object.keys(row).join(", ");
|
|
100
|
+
const placeholders = Object.keys(row)
|
|
101
|
+
.map(() => "?")
|
|
102
|
+
.join(", ");
|
|
103
|
+
const values = Object.values(row);
|
|
104
|
+
await opts.connect.raw_sql(`INSERT INTO hazo_llm_api_log (${columns}) VALUES (${placeholders})`, values);
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=log_writer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log_writer.js","sourceRoot":"","sources":["../../../src/lib/observability/log_writer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { HazoConnect } from "../hazo_connect/types.js";
|
|
2
|
+
import type { Logger } from "../llm_api/types.js";
|
|
3
|
+
import type { UsageSummaryOptions, UsageSummaryResponse, ApiLogRow } from "./types.js";
|
|
4
|
+
interface QueryOpts {
|
|
5
|
+
connect: HazoConnect;
|
|
6
|
+
logger: Logger;
|
|
7
|
+
}
|
|
8
|
+
/** Returns aggregated counts/cost across hazo_llm_api_log, optionally grouped + filtered. */
|
|
9
|
+
export declare function get_llm_usage_summary(opts: QueryOpts & UsageSummaryOptions): Promise<UsageSummaryResponse>;
|
|
10
|
+
/** Returns the full log row for a given id, or null if absent. */
|
|
11
|
+
export declare function get_llm_call_detail(opts: QueryOpts & {
|
|
12
|
+
id: string;
|
|
13
|
+
}): Promise<ApiLogRow | null>;
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=queries.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queries.d.ts","sourceRoot":"","sources":["../../../src/lib/observability/queries.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,KAAK,EACV,mBAAmB,EACnB,oBAAoB,EAGpB,SAAS,EACV,MAAM,YAAY,CAAC;AAMpB,UAAU,SAAS;IACjB,OAAO,EAAE,WAAW,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,6FAA6F;AAC7F,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,SAAS,GAAG,mBAAmB,GACpC,OAAO,CAAC,oBAAoB,CAAC,CAkE/B;AAED,kEAAkE;AAClE,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,SAAS,GAAG;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAMrG"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
const ALLOWED_GROUPS = [
|
|
2
|
+
"provider", "model", "service_type", "session_id", "reference", "date",
|
|
3
|
+
];
|
|
4
|
+
/** Returns aggregated counts/cost across hazo_llm_api_log, optionally grouped + filtered. */
|
|
5
|
+
export async function get_llm_usage_summary(opts) {
|
|
6
|
+
const wheres = [];
|
|
7
|
+
const values = [];
|
|
8
|
+
if (opts.from) {
|
|
9
|
+
wheres.push("created_at >= ?");
|
|
10
|
+
values.push(opts.from);
|
|
11
|
+
}
|
|
12
|
+
if (opts.to) {
|
|
13
|
+
wheres.push("created_at <= ?");
|
|
14
|
+
values.push(opts.to);
|
|
15
|
+
}
|
|
16
|
+
const w = opts.where ?? {};
|
|
17
|
+
if (w.provider) {
|
|
18
|
+
wheres.push("provider = ?");
|
|
19
|
+
values.push(w.provider);
|
|
20
|
+
}
|
|
21
|
+
if (w.model) {
|
|
22
|
+
wheres.push("model = ?");
|
|
23
|
+
values.push(w.model);
|
|
24
|
+
}
|
|
25
|
+
if (w.service_type) {
|
|
26
|
+
wheres.push("service_type = ?");
|
|
27
|
+
values.push(w.service_type);
|
|
28
|
+
}
|
|
29
|
+
if (typeof w.success === "boolean") {
|
|
30
|
+
wheres.push("success = ?");
|
|
31
|
+
values.push(w.success ? 1 : 0);
|
|
32
|
+
}
|
|
33
|
+
if (w.session_id) {
|
|
34
|
+
wheres.push("session_id = ?");
|
|
35
|
+
values.push(w.session_id);
|
|
36
|
+
}
|
|
37
|
+
const where_clause = wheres.length > 0 ? "WHERE " + wheres.join(" AND ") : "";
|
|
38
|
+
// Whitelist group_by inputs to prevent SQL injection
|
|
39
|
+
const safe_groups = (opts.group_by ?? []).filter((g) => ALLOWED_GROUPS.includes(g));
|
|
40
|
+
const group_select_parts = safe_groups.map(g => g === "date" ? "substr(created_at, 1, 10) AS date" : g);
|
|
41
|
+
const group_select = group_select_parts.length > 0 ? group_select_parts.join(", ") + "," : "";
|
|
42
|
+
const group_clause = safe_groups.length > 0
|
|
43
|
+
? "GROUP BY " + safe_groups.map(g => g === "date" ? "substr(created_at, 1, 10)" : g).join(", ")
|
|
44
|
+
: "";
|
|
45
|
+
const limit_clause = opts.limit ? `LIMIT ${Math.floor(opts.limit)}` : "";
|
|
46
|
+
const sql = `
|
|
47
|
+
SELECT
|
|
48
|
+
${group_select}
|
|
49
|
+
COUNT(*) AS count,
|
|
50
|
+
COALESCE(SUM(cost_usd), 0) AS total_cost_usd,
|
|
51
|
+
COALESCE(SUM(tokens_input), 0) AS total_tokens_input,
|
|
52
|
+
COALESCE(SUM(tokens_output), 0) AS total_tokens_output,
|
|
53
|
+
COALESCE(AVG(latency_ms), 0) AS avg_latency_ms
|
|
54
|
+
FROM hazo_llm_api_log
|
|
55
|
+
${where_clause}
|
|
56
|
+
${group_clause}
|
|
57
|
+
${limit_clause}
|
|
58
|
+
`;
|
|
59
|
+
const rows = await opts.connect.raw_sql(sql, values);
|
|
60
|
+
const totals_sql = `
|
|
61
|
+
SELECT
|
|
62
|
+
COUNT(*) AS count,
|
|
63
|
+
COALESCE(SUM(cost_usd), 0) AS total_cost_usd,
|
|
64
|
+
COALESCE(SUM(tokens_input), 0) AS total_tokens_input,
|
|
65
|
+
COALESCE(SUM(tokens_output), 0) AS total_tokens_output
|
|
66
|
+
FROM hazo_llm_api_log
|
|
67
|
+
${where_clause}
|
|
68
|
+
`;
|
|
69
|
+
const totals_rows = await opts.connect.raw_sql(totals_sql, values);
|
|
70
|
+
const totals = totals_rows[0] ?? { count: 0, total_cost_usd: 0, total_tokens_input: 0, total_tokens_output: 0 };
|
|
71
|
+
return { rows, totals };
|
|
72
|
+
}
|
|
73
|
+
/** Returns the full log row for a given id, or null if absent. */
|
|
74
|
+
export async function get_llm_call_detail(opts) {
|
|
75
|
+
const rows = await opts.connect.raw_sql("SELECT * FROM hazo_llm_api_log WHERE id = ? LIMIT 1", [opts.id]);
|
|
76
|
+
return rows[0] ?? null;
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=queries.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queries.js","sourceRoot":"","sources":["../../../src/lib/observability/queries.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Observability types for hazo_llm_api.
|
|
3
|
+
*
|
|
4
|
+
* Defines the shape of rows in hazo_llm_api_log and the options for usage
|
|
5
|
+
* summary queries.
|
|
6
|
+
*/
|
|
7
|
+
export interface ApiLogRow {
|
|
8
|
+
id: string;
|
|
9
|
+
created_at: string;
|
|
10
|
+
service_type: string;
|
|
11
|
+
provider: string;
|
|
12
|
+
model: string | null;
|
|
13
|
+
success: 0 | 1 | boolean;
|
|
14
|
+
tokens_input: number | null;
|
|
15
|
+
tokens_output: number | null;
|
|
16
|
+
tokens_cached_input: number | null;
|
|
17
|
+
tokens_total: number | null;
|
|
18
|
+
cost_usd: number | null;
|
|
19
|
+
pricing_kind: string | null;
|
|
20
|
+
pricing_input_per_1m_usd: number | null;
|
|
21
|
+
pricing_output_per_1m_usd: number | null;
|
|
22
|
+
pricing_per_image_usd: number | null;
|
|
23
|
+
latency_ms: number | null;
|
|
24
|
+
finish_reason: string | null;
|
|
25
|
+
error_code: string | null;
|
|
26
|
+
error_message: string | null;
|
|
27
|
+
prompt_area: string | null;
|
|
28
|
+
prompt_key: string | null;
|
|
29
|
+
prompt_id: string | null;
|
|
30
|
+
session_id: string | null;
|
|
31
|
+
reference: string | null;
|
|
32
|
+
attempts_count: number;
|
|
33
|
+
context_json: string;
|
|
34
|
+
}
|
|
35
|
+
export interface UsageSummaryWhere {
|
|
36
|
+
provider?: string;
|
|
37
|
+
model?: string;
|
|
38
|
+
service_type?: string;
|
|
39
|
+
success?: boolean;
|
|
40
|
+
session_id?: string;
|
|
41
|
+
}
|
|
42
|
+
export type UsageSummaryGroupBy = "provider" | "model" | "service_type" | "session_id" | "reference" | "date";
|
|
43
|
+
export interface UsageSummaryOptions {
|
|
44
|
+
from?: string;
|
|
45
|
+
to?: string;
|
|
46
|
+
group_by?: UsageSummaryGroupBy[];
|
|
47
|
+
where?: UsageSummaryWhere;
|
|
48
|
+
limit?: number;
|
|
49
|
+
}
|
|
50
|
+
export interface UsageSummaryRow {
|
|
51
|
+
[group_key: string]: string | number | null;
|
|
52
|
+
count: number;
|
|
53
|
+
total_cost_usd: number;
|
|
54
|
+
total_tokens_input: number;
|
|
55
|
+
total_tokens_output: number;
|
|
56
|
+
avg_latency_ms: number;
|
|
57
|
+
}
|
|
58
|
+
export interface UsageSummaryResponse {
|
|
59
|
+
rows: UsageSummaryRow[];
|
|
60
|
+
totals: {
|
|
61
|
+
count: number;
|
|
62
|
+
total_cost_usd: number;
|
|
63
|
+
total_tokens_input: number;
|
|
64
|
+
total_tokens_output: number;
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Fetch aggregated usage summary. Parameters match UsageSummaryOptions.
|
|
69
|
+
* Returns { rows: UsageSummaryRow[], totals: {...} }.
|
|
70
|
+
*/
|
|
71
|
+
export type FetchSummaryFn = (opts: UsageSummaryOptions) => Promise<UsageSummaryResponse>;
|
|
72
|
+
/**
|
|
73
|
+
* Fetch a single call detail row by ID.
|
|
74
|
+
* Returns null if not found.
|
|
75
|
+
*/
|
|
76
|
+
export type FetchDetailFn = (id: string) => Promise<ApiLogRow | null>;
|
|
77
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/lib/observability/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,OAAO,EAAE,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC;IACzB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,wBAAwB,EAAE,MAAM,GAAG,IAAI,CAAC;IACxC,yBAAyB,EAAE,MAAM,GAAG,IAAI,CAAC;IACzC,qBAAqB,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,MAAM,mBAAmB,GAC3B,UAAU,GACV,OAAO,GACP,cAAc,GACd,YAAY,GACZ,WAAW,GACX,MAAM,CAAC;AAEX,MAAM,WAAW,mBAAmB;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,mBAAmB,EAAE,CAAC;IACjC,KAAK,CAAC,EAAE,iBAAiB,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,eAAe;IAC9B,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAC5C,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,MAAM,CAAC;IACvB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,eAAe,EAAE,CAAC;IACxB,MAAM,EAAE;QACN,KAAK,EAAE,MAAM,CAAC;QACd,cAAc,EAAE,MAAM,CAAC;QACvB,kBAAkB,EAAE,MAAM,CAAC;QAC3B,mBAAmB,EAAE,MAAM,CAAC;KAC7B,CAAC;CACH;AAMD;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,IAAI,EAAE,mBAAmB,KAAK,OAAO,CAAC,oBAAoB,CAAC,CAAC;AAE1F;;;GAGG;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/lib/observability/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pricing module.
|
|
3
|
+
*
|
|
4
|
+
* - Bundled rates live in pricing.json (loaded once on first use).
|
|
5
|
+
* - Consumers can override via update_pricing() or set_pricing_overrides() at runtime.
|
|
6
|
+
* - compute_cost() takes a UsageInfo and returns it enriched with cost_usd + pricing_applied.
|
|
7
|
+
*
|
|
8
|
+
* Pricing key convention: "<provider>/<model>" (lowercase provider).
|
|
9
|
+
*/
|
|
10
|
+
import type { PricingEntry, PricingTable, UsageInfo } from "./types.js";
|
|
11
|
+
import type { HazoConnect } from "../hazo_connect/types.js";
|
|
12
|
+
import type { Logger } from "../llm_api/types.js";
|
|
13
|
+
/** Idempotent. Reads the bundled pricing.json into the in-memory table. */
|
|
14
|
+
export declare function load_pricing(): void;
|
|
15
|
+
/** Test helper — clears the in-memory cache so the next load_pricing() re-reads. */
|
|
16
|
+
export declare function reset_pricing_for_test(): void;
|
|
17
|
+
/** Look up the pricing entry for "<provider>/<model>". Returns null if absent. */
|
|
18
|
+
export declare function get_pricing(key: string): PricingEntry | null;
|
|
19
|
+
/** Override one entry at runtime. */
|
|
20
|
+
export declare function update_pricing(key: string, entry: PricingEntry): void;
|
|
21
|
+
/** Merge multiple overrides (used by initialize_llm_api({ pricing_overrides })). */
|
|
22
|
+
export declare function set_pricing_overrides(overrides: PricingTable): void;
|
|
23
|
+
/**
|
|
24
|
+
* Compute cost for a usage record using the current pricing table.
|
|
25
|
+
*
|
|
26
|
+
* Returns a NEW UsageInfo with cost_usd + pricing_applied populated when possible,
|
|
27
|
+
* or with both undefined when the model is unpriced.
|
|
28
|
+
*/
|
|
29
|
+
export declare function compute_cost(usage: UsageInfo): UsageInfo;
|
|
30
|
+
export interface RecomputeOpts {
|
|
31
|
+
connect: HazoConnect;
|
|
32
|
+
logger: Logger;
|
|
33
|
+
/** ISO date — only recompute rows created at or after this timestamp. */
|
|
34
|
+
from?: string;
|
|
35
|
+
/** ISO date — only recompute rows created at or before this timestamp. */
|
|
36
|
+
to?: string;
|
|
37
|
+
/** Restrict to specific model names. */
|
|
38
|
+
models?: string[];
|
|
39
|
+
/** When true, report changes but do not write. Default false. */
|
|
40
|
+
dry_run?: boolean;
|
|
41
|
+
}
|
|
42
|
+
export interface RecomputeResult {
|
|
43
|
+
total_inspected: number;
|
|
44
|
+
updated: number;
|
|
45
|
+
/** Populated in dry_run mode — number of rows that would have been updated. */
|
|
46
|
+
would_update: number;
|
|
47
|
+
}
|
|
48
|
+
export declare function recompute_costs(opts: RecomputeOpts): Promise<RecomputeResult>;
|
|
49
|
+
//# sourceMappingURL=pricing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pricing.d.ts","sourceRoot":"","sources":["../../../src/lib/pricing/pricing.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACxE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AASlD,2EAA2E;AAC3E,wBAAgB,YAAY,IAAI,IAAI,CAInC;AAED,oFAAoF;AACpF,wBAAgB,sBAAsB,IAAI,IAAI,CAE7C;AAED,kFAAkF;AAClF,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAG5D;AAED,qCAAqC;AACrC,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,GAAG,IAAI,CAGrE;AAED,oFAAoF;AACpF,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,YAAY,GAAG,IAAI,CAKnE;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,SAAS,GAAG,SAAS,CA6BxD;AAMD,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,WAAW,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,yEAAyE;IACzE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,0EAA0E;IAC1E,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,wCAAwC;IACxC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,iEAAiE;IACjE,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,eAAe;IAC9B,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,+EAA+E;IAC/E,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,wBAAsB,eAAe,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,eAAe,CAAC,CA4EnF"}
|