@intuned/browser-dev 0.1.17-dev.0 → 0.1.17-dev10

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.
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.loadRuntime = exports.loadGetAiGatewayConfig = void 0;
6
+ exports.loadRuntime = exports.loadRunInfo = exports.loadGetAiGatewayConfig = void 0;
7
7
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
8
8
  const loadRuntime = async () => {
9
9
  try {
@@ -14,6 +14,16 @@ const loadRuntime = async () => {
14
14
  }
15
15
  };
16
16
  exports.loadRuntime = loadRuntime;
17
+ const loadRunInfo = async () => {
18
+ try {
19
+ const runtime = await Promise.resolve().then(() => _interopRequireWildcard(require("@intuned/runtime")));
20
+ const fn = runtime.runInfo;
21
+ return typeof fn === "function" ? fn() : undefined;
22
+ } catch {
23
+ return undefined;
24
+ }
25
+ };
26
+ exports.loadRunInfo = loadRunInfo;
17
27
  const loadGetAiGatewayConfig = async () => {
18
28
  const runtime = await Promise.resolve().then(() => _interopRequireWildcard(require("@intuned/runtime")));
19
29
  const fn = runtime.getAiGatewayConfig;
@@ -10,6 +10,7 @@ var _OpenAI = require("./providers/OpenAI");
10
10
  var _Gemini = require("./providers/Gemini");
11
11
  var _dotenv = require("dotenv");
12
12
  var _loadRuntime = require("../../common/loadRuntime");
13
+ var _runInfoHeaders = require("./runInfoHeaders");
13
14
  (0, _dotenv.config)();
14
15
  class APIGateway {
15
16
  useGateway = false;
@@ -79,10 +80,15 @@ class APIGateway {
79
80
  baseUrl,
80
81
  apiKey
81
82
  } = getAiGatewayConfig();
83
+ const runInfoHeaders = (0, _runInfoHeaders.buildRunInfoHeaders)(await (0, _loadRuntime.loadRunInfo)());
84
+ const mergedHeaders = {
85
+ ...runInfoHeaders,
86
+ ...(extraHeaders ?? {})
87
+ };
82
88
  return {
83
89
  model: this.model,
84
90
  apiKey,
85
- extraHeaders,
91
+ extraHeaders: Object.keys(mergedHeaders).length > 0 ? mergedHeaders : undefined,
86
92
  baseUrl
87
93
  };
88
94
  } catch (error) {
@@ -9,16 +9,19 @@ var _jwtTokenManager = require("../../../common/jwtTokenManager");
9
9
  const createAnthropicInstance = input => {
10
10
  const {
11
11
  apiKey,
12
+ headers,
12
13
  baseUrl
13
14
  } = input;
14
15
  if (apiKey && baseUrl === undefined) {
15
16
  return (0, _anthropic.createAnthropic)({
16
- apiKey
17
+ apiKey,
18
+ headers
17
19
  });
18
20
  } else {
19
21
  const baseURLWithV1 = baseUrl ? `${baseUrl}/v1` : undefined;
20
22
  return (0, _anthropic.createAnthropic)({
21
23
  apiKey,
24
+ headers,
22
25
  baseURL: baseURLWithV1,
23
26
  fetch: _jwtTokenManager.backendFunctionsTokenManager.fetchWithToken.bind(_jwtTokenManager.backendFunctionsTokenManager)
24
27
  });
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.buildRunInfoHeaders = buildRunInfoHeaders;
7
+ function buildRunInfoHeaders(runInfo) {
8
+ const headers = {};
9
+ if (!runInfo) {
10
+ return headers;
11
+ }
12
+ if (runInfo.jobId) {
13
+ headers["x-intuned-job-id"] = runInfo.jobId;
14
+ }
15
+ if (runInfo.jobRunId) {
16
+ headers["x-intuned-job-run-id"] = runInfo.jobRunId;
17
+ }
18
+ if (runInfo.runId) {
19
+ headers["x-intuned-run-id"] = runInfo.runId;
20
+ }
21
+ if (runInfo.authSessionId) {
22
+ headers["x-intuned-auth-session-id"] = runInfo.authSessionId;
23
+ }
24
+ return headers;
25
+ }
@@ -27,7 +27,8 @@ _vitest.vi.mock("../providers/Gemini", () => ({
27
27
  }));
28
28
  _vitest.vi.mock("../../../common/loadRuntime", () => ({
29
29
  loadRuntime: _vitest.vi.fn(),
30
- loadGetAiGatewayConfig: _vitest.vi.fn()
30
+ loadGetAiGatewayConfig: _vitest.vi.fn(),
31
+ loadRunInfo: _vitest.vi.fn()
31
32
  }));
32
33
  const mockGetModelProvider = _vitest.vi.mocked(_getModelProvider.getModelProvider);
33
34
  const mockCreateAnthropicInstance = _vitest.vi.mocked(_Anthropic.createAnthropicInstance);
@@ -35,6 +36,7 @@ const mockCreateOpenAIInstance = _vitest.vi.mocked(_OpenAI.createOpenAIInstance)
35
36
  const mockCreateGoogleInstance = _vitest.vi.mocked(_Gemini.createGoogleInstance);
36
37
  const mockLoadRuntime = _vitest.vi.mocked(_loadRuntime.loadRuntime);
37
38
  const mockLoadGetAiGatewayConfig = _vitest.vi.mocked(_loadRuntime.loadGetAiGatewayConfig);
39
+ const mockLoadRunInfo = _vitest.vi.mocked(_loadRuntime.loadRunInfo);
38
40
  (0, _extendedTest.describe)("APIGateway", () => {
39
41
  let originalEnv;
40
42
  (0, _extendedTest.beforeEach)(() => {
@@ -49,6 +51,7 @@ const mockLoadGetAiGatewayConfig = _vitest.vi.mocked(_loadRuntime.loadGetAiGatew
49
51
  GOOGLE_API_KEY: undefined
50
52
  };
51
53
  _vitest.vi.clearAllMocks();
54
+ mockLoadRunInfo.mockResolvedValue(undefined);
52
55
  });
53
56
  (0, _extendedTest.afterEach)(() => {
54
57
  process.env = originalEnv;
@@ -201,6 +204,99 @@ const mockLoadGetAiGatewayConfig = _vitest.vi.mocked(_loadRuntime.loadGetAiGatew
201
204
  await gateway["ensureInitialized"]();
202
205
  await (0, _extendedTest.expect)(gateway["getModelConfig"]()).rejects.toThrow("Failed to load gateway configuration from @intuned/runtime");
203
206
  });
207
+ (0, _extendedTest.it)("should attach x-intuned-* headers from runInfo in gateway mode", async () => {
208
+ mockGetModelProvider.mockReturnValue("anthropic");
209
+ mockLoadRuntime.mockResolvedValue(() => ({
210
+ runId: "test"
211
+ }));
212
+ mockLoadGetAiGatewayConfig.mockResolvedValue(() => ({
213
+ baseUrl: "https://gw.example.com/intuned-ai-gateway",
214
+ apiKey: "resolved-token"
215
+ }));
216
+ mockLoadRunInfo.mockResolvedValue({
217
+ runEnvironment: "DEPLOYED",
218
+ jobId: "job-1",
219
+ jobRunId: "run-1",
220
+ runId: "r-1",
221
+ authSessionId: "auth-1"
222
+ });
223
+ const gateway = new _aiApiGateway.APIGateway({
224
+ model: "claude-3-sonnet"
225
+ });
226
+ await gateway["ensureInitialized"]();
227
+ const result = await gateway["getModelConfig"]();
228
+ (0, _extendedTest.expect)(result.extraHeaders).toEqual({
229
+ "x-intuned-job-id": "job-1",
230
+ "x-intuned-job-run-id": "run-1",
231
+ "x-intuned-run-id": "r-1",
232
+ "x-intuned-auth-session-id": "auth-1"
233
+ });
234
+ });
235
+ (0, _extendedTest.it)("should only attach headers for present runInfo fields", async () => {
236
+ mockGetModelProvider.mockReturnValue("anthropic");
237
+ mockLoadRuntime.mockResolvedValue(() => ({
238
+ runId: "test"
239
+ }));
240
+ mockLoadGetAiGatewayConfig.mockResolvedValue(() => ({
241
+ baseUrl: "https://gw.example.com/intuned-ai-gateway",
242
+ apiKey: "resolved-token"
243
+ }));
244
+ mockLoadRunInfo.mockResolvedValue({
245
+ runEnvironment: "DEPLOYED",
246
+ jobId: "job-1"
247
+ });
248
+ const gateway = new _aiApiGateway.APIGateway({
249
+ model: "claude-3-sonnet"
250
+ });
251
+ await gateway["ensureInitialized"]();
252
+ const result = await gateway["getModelConfig"]();
253
+ (0, _extendedTest.expect)(result.extraHeaders).toEqual({
254
+ "x-intuned-job-id": "job-1"
255
+ });
256
+ });
257
+ (0, _extendedTest.it)("should let caller-provided headers override runInfo-derived ones", async () => {
258
+ mockGetModelProvider.mockReturnValue("anthropic");
259
+ mockLoadRuntime.mockResolvedValue(() => ({
260
+ runId: "test"
261
+ }));
262
+ mockLoadGetAiGatewayConfig.mockResolvedValue(() => ({
263
+ baseUrl: "https://gw.example.com/intuned-ai-gateway",
264
+ apiKey: "resolved-token"
265
+ }));
266
+ mockLoadRunInfo.mockResolvedValue({
267
+ runEnvironment: "DEPLOYED",
268
+ jobId: "from-runinfo"
269
+ });
270
+ const gateway = new _aiApiGateway.APIGateway({
271
+ model: "claude-3-sonnet"
272
+ });
273
+ await gateway["ensureInitialized"]();
274
+ const result = await gateway["getModelConfig"]({
275
+ "x-intuned-job-id": "from-caller",
276
+ "Custom-Header": "value"
277
+ });
278
+ (0, _extendedTest.expect)(result.extraHeaders).toEqual({
279
+ "x-intuned-job-id": "from-caller",
280
+ "Custom-Header": "value"
281
+ });
282
+ });
283
+ (0, _extendedTest.it)("should leave extraHeaders undefined when no runInfo and no caller headers", async () => {
284
+ mockGetModelProvider.mockReturnValue("anthropic");
285
+ mockLoadRuntime.mockResolvedValue(() => ({
286
+ runId: "test"
287
+ }));
288
+ mockLoadGetAiGatewayConfig.mockResolvedValue(() => ({
289
+ baseUrl: "https://gw.example.com/intuned-ai-gateway",
290
+ apiKey: "resolved-token"
291
+ }));
292
+ mockLoadRunInfo.mockResolvedValue(undefined);
293
+ const gateway = new _aiApiGateway.APIGateway({
294
+ model: "claude-3-sonnet"
295
+ });
296
+ await gateway["ensureInitialized"]();
297
+ const result = await gateway["getModelConfig"]();
298
+ (0, _extendedTest.expect)(result.extraHeaders).toBeUndefined();
299
+ });
204
300
  });
205
301
  (0, _extendedTest.describe)("createProviderInstance", () => {
206
302
  (0, _extendedTest.it)("should create anthropic instance with gateway mode", async () => {
@@ -228,6 +324,38 @@ const mockLoadGetAiGatewayConfig = _vitest.vi.mocked(_loadRuntime.loadGetAiGatew
228
324
  });
229
325
  (0, _extendedTest.expect)(result).toBe(mockInstance);
230
326
  });
327
+ (0, _extendedTest.it)("should pass runInfo-derived headers to the anthropic gateway provider", async () => {
328
+ mockGetModelProvider.mockReturnValue("anthropic");
329
+ mockLoadRuntime.mockResolvedValue(() => ({
330
+ runId: "test"
331
+ }));
332
+ mockLoadGetAiGatewayConfig.mockResolvedValue(() => ({
333
+ baseUrl: "https://functions.example.com/api/workspace123/functions/integration456/intuned-ai-gateway",
334
+ apiKey: "resolved-token"
335
+ }));
336
+ mockLoadRunInfo.mockResolvedValue({
337
+ runEnvironment: "DEPLOYED",
338
+ jobId: "job-1",
339
+ jobRunId: "run-1"
340
+ });
341
+ const mockInstance = {
342
+ chat: _vitest.vi.fn()
343
+ };
344
+ mockCreateAnthropicInstance.mockReturnValue(mockInstance);
345
+ const gateway = new _aiApiGateway.APIGateway({
346
+ model: "claude-3-sonnet"
347
+ });
348
+ await gateway.createProviderInstance();
349
+ (0, _extendedTest.expect)(mockCreateAnthropicInstance).toHaveBeenCalledWith({
350
+ apiKey: "resolved-token",
351
+ headers: {
352
+ "x-intuned-job-id": "job-1",
353
+ "x-intuned-job-run-id": "run-1"
354
+ },
355
+ model: "claude-3-sonnet",
356
+ baseUrl: "https://functions.example.com/api/workspace123/functions/integration456/intuned-ai-gateway"
357
+ });
358
+ });
231
359
  (0, _extendedTest.it)("should create openai instance with direct API key", async () => {
232
360
  mockGetModelProvider.mockReturnValue("openai");
233
361
  const mockInstance = {
@@ -8,10 +8,10 @@ var _anthropicModel = require("../models/anthropicModel");
8
8
  var _neverthrow = require("neverthrow");
9
9
  var Errors = _interopRequireWildcard(require("../types/errors"));
10
10
  var _utils = require("./utils");
11
+ var _Logger = require("../../common/Logger");
11
12
  var _aiModelsValidations = require("../common/aiModelsValidations");
12
13
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
13
14
  async function extractStructuredDataUsingClaude(input) {
14
- var _unwrappedResponse$us, _unwrappedResponse$us2;
15
15
  const {
16
16
  entityName,
17
17
  model,
@@ -118,11 +118,17 @@ async function extractStructuredDataUsingClaude(input) {
118
118
  }
119
119
  const result = (0, _utils.getResultFromOutputSchema)(originalJsonSchema, entityName, tool.input);
120
120
  const callCost = response.value.response.headers.get("x-ai-cost-in-cents");
121
- const costInCents = (0, _utils.parseCostInCents)(callCost);
122
- const totalTokens = (((_unwrappedResponse$us = unwrappedResponse.usage) === null || _unwrappedResponse$us === void 0 ? void 0 : _unwrappedResponse$us.input_tokens) ?? 0) + (((_unwrappedResponse$us2 = unwrappedResponse.usage) === null || _unwrappedResponse$us2 === void 0 ? void 0 : _unwrappedResponse$us2.output_tokens) ?? 0);
121
+ if (input.logAiCallCost) {
122
+ if (apiKey) {
123
+ _Logger.logger.info(`extractor ${input.identifier}: AI cost is not calculated (using custom API key)`);
124
+ } else if (callCost) {
125
+ const cost = parseFloat(callCost);
126
+ if (!isNaN(cost)) {
127
+ _Logger.logger.info(`extractor ${input.identifier}: AI cost is $${cost / 100}`);
128
+ }
129
+ }
130
+ }
123
131
  return (0, _neverthrow.ok)({
124
- result,
125
- costInCents,
126
- totalTokens
132
+ result
127
133
  });
128
134
  }
@@ -7,10 +7,11 @@ exports.extractStructuredDataUsingOpenAi = extractStructuredDataUsingOpenAi;
7
7
  var _neverthrow = require("neverthrow");
8
8
  var Errors = _interopRequireWildcard(require("../types/errors"));
9
9
  var _utils = require("./utils");
10
+ var _Logger = require("../../common/Logger");
10
11
  var _openaiModel = require("../models/openaiModel");
11
12
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
12
13
  async function extractStructuredDataUsingOpenAi(input) {
13
- var _completion$value$dat, _completion$value$dat2, _completion$value$dat3;
14
+ var _completion$value$dat, _completion$value$dat2;
14
15
  const {
15
16
  entityName,
16
17
  model,
@@ -49,16 +50,13 @@ async function extractStructuredDataUsingOpenAi(input) {
49
50
  content.push(...imageContent);
50
51
  }
51
52
  const modelName = input.model;
52
- const supportsCustomTemperature = !/^(o\d|gpt-5)/i.test(modelName);
53
53
  const toolName = `extract_${entityName}`;
54
54
  const openAiInstance = (0, _openaiModel.createOpenAIInstance)({
55
55
  apiKey
56
56
  });
57
57
  const completion = await (0, _neverthrow.fromPromise)(openAiInstance.chat.completions.create({
58
- max_completion_tokens: 4000,
59
- ...(supportsCustomTemperature ? {
60
- temperature: 0
61
- } : {}),
58
+ max_tokens: 4000,
59
+ temperature: 0,
62
60
  model: modelName,
63
61
  messages: [{
64
62
  role: "system",
@@ -117,11 +115,17 @@ async function extractStructuredDataUsingOpenAi(input) {
117
115
  const result = (0, _utils.getResultFromOutputSchema)(originalJsonSchema, entityName, parsedData.value);
118
116
  const formatted = (0, _utils.cleanupAiResult)(result);
119
117
  const callCost = completion.value.response.headers.get("x-ai-cost-in-cents");
120
- const costInCents = (0, _utils.parseCostInCents)(callCost);
121
- const totalTokens = (_completion$value$dat3 = completion.value.data.usage) === null || _completion$value$dat3 === void 0 ? void 0 : _completion$value$dat3.total_tokens;
118
+ if (input.logAiCallCost) {
119
+ if (apiKey) {
120
+ _Logger.logger.info(`extractor ${input.identifier}: AI cost is not calculated (using custom API key)`);
121
+ } else if (callCost) {
122
+ const cost = parseFloat(callCost);
123
+ if (!isNaN(cost)) {
124
+ _Logger.logger.info(`extractor ${input.identifier}: AI cost is $${cost / 100}`);
125
+ }
126
+ }
127
+ }
122
128
  return (0, _neverthrow.ok)({
123
- result: formatted,
124
- costInCents,
125
- totalTokens
129
+ result: formatted
126
130
  });
127
131
  }
@@ -7,10 +7,11 @@ exports.extractStructuredDataUsingAiInstance = extractStructuredDataUsingAiInsta
7
7
  var _neverthrow = require("neverthrow");
8
8
  var Errors = _interopRequireWildcard(require("../types/errors"));
9
9
  var _utils = require("./utils");
10
+ var _Logger = require("../../common/Logger");
10
11
  var _ai = require("ai");
11
12
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
12
13
  async function extractStructuredDataUsingAiInstance(input) {
13
- var _apiResult$value$tool, _apiResult$value$tool2, _apiResult$value$resp, _apiResult$value$usag;
14
+ var _apiResult$value$tool, _apiResult$value$tool2, _apiResult$value$resp;
14
15
  const {
15
16
  entityName,
16
17
  model,
@@ -19,7 +20,9 @@ async function extractStructuredDataUsingAiInstance(input) {
19
20
  text,
20
21
  extraUserMessages,
21
22
  images,
22
- apiName
23
+ apiKey,
24
+ apiName,
25
+ maxTokens
23
26
  } = input;
24
27
  const processedJsonSchema = (0, _utils.processInputSchema)(originalJsonSchema, entityName);
25
28
  const content = [];
@@ -103,11 +106,17 @@ async function extractStructuredDataUsingAiInstance(input) {
103
106
  const result = (0, _utils.getResultFromOutputSchema)(originalJsonSchema, entityName, extractedData);
104
107
  const formatted = (0, _utils.cleanupAiResult)(result);
105
108
  const callCost = (_apiResult$value$resp = apiResult.value.response.headers) === null || _apiResult$value$resp === void 0 ? void 0 : _apiResult$value$resp["x-ai-cost-in-cents"];
106
- const costInCents = (0, _utils.parseCostInCents)(callCost);
107
- const totalTokens = (_apiResult$value$usag = apiResult.value.usage) === null || _apiResult$value$usag === void 0 ? void 0 : _apiResult$value$usag.totalTokens;
109
+ if (input.logAiCallCost) {
110
+ if (apiKey) {
111
+ _Logger.logger.info(`extractor ${input.identifier}: AI cost is not calculated (using custom API key)`);
112
+ } else if (callCost) {
113
+ const cost = parseFloat(callCost);
114
+ if (!isNaN(cost)) {
115
+ _Logger.logger.info(`extractor ${input.identifier}: AI cost is $${cost / 100}`);
116
+ }
117
+ }
118
+ }
108
119
  return (0, _neverthrow.ok)({
109
- result: formatted,
110
- costInCents,
111
- totalTokens
120
+ result: formatted
112
121
  });
113
122
  }
@@ -13,7 +13,6 @@ var _extractStructuredDataUsingOpenAi = require("./extractStructuredDataUsingOpe
13
13
  var _utils = require("./utils");
14
14
  var _extractStructuredDataUsingGoogle = require("./extractStructuredDataUsingGoogle");
15
15
  var _getModelProvider = require("../../common/getModelProvider");
16
- var _Logger = require("../../common/Logger");
17
16
  function isClaudeModel(model) {
18
17
  return (0, _getModelProvider.getModelProvider)(model) === "anthropic";
19
18
  }
@@ -48,18 +47,9 @@ async function extractStructuredDataUsingAi(input) {
48
47
  return (0, _neverthrow.err)(extractionResult.error);
49
48
  }
50
49
  const {
51
- result,
52
- costInCents,
53
- totalTokens
50
+ result
54
51
  } = extractionResult.value;
55
- if (costInCents !== undefined) {
56
- _Logger.logger.info(`Total LLM Cost In Cents: ${costInCents}`);
57
- } else if (totalTokens !== undefined) {
58
- _Logger.logger.info(`Total LLM Tokens: ${totalTokens}`);
59
- }
60
52
  return (0, _neverthrow.ok)({
61
- result: (0, _utils.cleanupAiResult)(result),
62
- costInCents,
63
- totalTokens
53
+ result: (0, _utils.cleanupAiResult)(result)
64
54
  });
65
55
  }
@@ -6,17 +6,11 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.cleanupAiResult = cleanupAiResult;
7
7
  exports.getRandomItems = getRandomItems;
8
8
  exports.getResultFromOutputSchema = getResultFromOutputSchema;
9
- exports.parseCostInCents = parseCostInCents;
10
9
  exports.processInputSchema = processInputSchema;
11
10
  function getRandomItems(arr, numItems) {
12
11
  const shuffled = arr.sort(() => 0.5 - Math.random());
13
12
  return shuffled.slice(0, numItems);
14
13
  }
15
- function parseCostInCents(headerValue) {
16
- if (!headerValue) return undefined;
17
- const cost = parseFloat(headerValue);
18
- return isNaN(cost) ? undefined : cost;
19
- }
20
14
  function processInputSchema(originalJsonSchema, entityName) {
21
15
  const internalSchema = structuredClone(originalJsonSchema);
22
16
  delete internalSchema.description;
@@ -9,7 +9,18 @@ declare module "@intuned/runtime" {
9
9
  password: string;
10
10
  }
11
11
 
12
+ export interface RunInfo {
13
+ runEnvironment: string;
14
+ runId?: string;
15
+ jobId?: string;
16
+ jobRunId?: string;
17
+ queueId?: string;
18
+ proxy?: string;
19
+ authSessionId?: string;
20
+ }
21
+
12
22
  export function getExecutionContext(): any;
23
+ export function runInfo(): RunInfo;
13
24
  export function extendTimeout(): void;
14
25
  export function runWithContext<R, TArgs extends any[]>(
15
26
  contextData: any,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intuned/browser-dev",
3
- "version": "0.1.17-dev.0",
3
+ "version": "0.1.17-dev10",
4
4
  "description": "runner package for intuned functions",
5
5
  "types": "./dist/index.d.ts",
6
6
  "typesVersions": {
@@ -1,8 +0,0 @@
1
- {
2
- "permissions": {
3
- "allow": [
4
- "Bash(yarn list:*)",
5
- "Bash(npm ls:*)"
6
- ]
7
- }
8
- }
@@ -1,120 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- Accumulate total LLM cost (in cents) across all runs in a results JSONL file.
4
-
5
- For each line in the results JSONL:
6
- - read the `log_url` field
7
- - download that logs JSONL
8
- - find every log line whose message contains "Total LLM Cost In Cents: <number>"
9
- - sum all those numbers
10
-
11
- Usage:
12
- python accumulate_llm_cost.py /path/to/results.jsonl
13
- python accumulate_llm_cost.py /path/to/results.jsonl --workers 16
14
- """
15
-
16
- import argparse
17
- import json
18
- import re
19
- import sys
20
- import urllib.request
21
- from concurrent.futures import ThreadPoolExecutor, as_completed
22
-
23
- # Matches: "Total LLM Cost In Cents: 01.1" -> captures "01.1"
24
- COST_RE = re.compile(r"Total LLM Cost In Cents:\s*([0-9]*\.?[0-9]+)", re.IGNORECASE)
25
-
26
-
27
- def download_text(url: str, timeout: int = 120) -> str:
28
- req = urllib.request.Request(url, headers={"User-Agent": "llm-cost-accumulator"})
29
- with urllib.request.urlopen(req, timeout=timeout) as resp:
30
- return resp.read().decode("utf-8", errors="replace")
31
-
32
-
33
- def costs_from_log_text(text: str):
34
- """Yield every cost value found in a logs JSONL blob."""
35
- for line in text.splitlines():
36
- line = line.strip()
37
- if not line:
38
- continue
39
- message = None
40
- try:
41
- obj = json.loads(line)
42
- message = obj.get("message")
43
- except json.JSONDecodeError:
44
- # fall back to scanning the raw line
45
- message = line
46
- if not message:
47
- continue
48
- for m in COST_RE.finditer(str(message)):
49
- yield float(m.group(1))
50
-
51
-
52
- def process_run(record: dict):
53
- """Return (label, total_cents, hit_count, error) for one results record."""
54
- api = record.get("apiInfo", {})
55
- name = api.get("name", "?")
56
- run_id = api.get("runId") or record.get("projectJobRun", {}).get("id", "?")
57
- label = f"{name} / {run_id}"
58
-
59
- log_url = api.get("log_url")
60
- if not log_url:
61
- return label, 0.0, 0, "no log_url"
62
-
63
- try:
64
- text = download_text(log_url)
65
- except Exception as e: # noqa: BLE001
66
- return label, 0.0, 0, f"download failed: {e}"
67
-
68
- costs = list(costs_from_log_text(text))
69
- return label, sum(costs), len(costs), None
70
-
71
-
72
- def main():
73
- parser = argparse.ArgumentParser(description=__doc__)
74
- parser.add_argument("results", help="Path to the results JSONL file")
75
- parser.add_argument("--workers", type=int, default=8, help="Parallel downloads")
76
- parser.add_argument("--quiet", action="store_true", help="Only print the grand total")
77
- args = parser.parse_args()
78
-
79
- with open(args.results, "r", encoding="utf-8") as f:
80
- records = []
81
- for ln, line in enumerate(f, 1):
82
- line = line.strip()
83
- if not line:
84
- continue
85
- try:
86
- records.append(json.loads(line))
87
- except json.JSONDecodeError as e:
88
- print(f" [warn] skipping malformed line {ln}: {e}", file=sys.stderr)
89
-
90
- if not args.quiet:
91
- print(f"Loaded {len(records)} run(s) from {args.results}\n")
92
-
93
- grand_total = 0.0
94
- total_hits = 0
95
- errors = 0
96
-
97
- with ThreadPoolExecutor(max_workers=args.workers) as pool:
98
- futures = {pool.submit(process_run, rec): rec for rec in records}
99
- for fut in as_completed(futures):
100
- label, total, hits, err = fut.result()
101
- if err:
102
- errors += 1
103
- if not args.quiet:
104
- print(f" [error] {label}: {err}")
105
- continue
106
- grand_total += total
107
- total_hits += hits
108
- if not args.quiet:
109
- print(f" {label}: {total:.4f} cents ({hits} entr{'y' if hits == 1 else 'ies'})")
110
-
111
- print("\n" + "=" * 60)
112
- print(f"Runs processed : {len(records)}")
113
- print(f"Cost entries : {total_hits}")
114
- print(f"Errors : {errors}")
115
- print(f"TOTAL LLM COST : {grand_total:.4f} cents (${grand_total / 100:.4f})")
116
- print("=" * 60)
117
-
118
-
119
- if __name__ == "__main__":
120
- main()