bopodev-api 0.1.14 → 0.1.15

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bopodev-api",
3
- "version": "0.1.14",
3
+ "version": "0.1.15",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "files": [
@@ -17,9 +17,9 @@
17
17
  "nanoid": "^5.1.5",
18
18
  "ws": "^8.19.0",
19
19
  "zod": "^4.1.5",
20
- "bopodev-db": "0.1.14",
21
- "bopodev-contracts": "0.1.14",
22
- "bopodev-agent-sdk": "0.1.14"
20
+ "bopodev-agent-sdk": "0.1.15",
21
+ "bopodev-contracts": "0.1.15",
22
+ "bopodev-db": "0.1.15"
23
23
  },
24
24
  "devDependencies": {
25
25
  "@types/cors": "^2.8.19",
@@ -773,6 +773,16 @@ export async function runHeartbeatForAgent(
773
773
  externalAbortSignal: activeRunAbort.signal
774
774
  });
775
775
  executionSummary = execution.summary;
776
+ const normalizedUsage = execution.usage ?? {
777
+ inputTokens: Math.max(0, execution.tokenInput),
778
+ cachedInputTokens: 0,
779
+ outputTokens: Math.max(0, execution.tokenOutput),
780
+ ...(execution.usdCost > 0 ? { costUsd: execution.usdCost } : {}),
781
+ ...(execution.summary ? { summary: execution.summary } : {})
782
+ };
783
+ const effectiveTokenInput = normalizedUsage.inputTokens + normalizedUsage.cachedInputTokens;
784
+ const effectiveTokenOutput = normalizedUsage.outputTokens;
785
+ const effectiveRuntimeUsdCost = normalizedUsage.costUsd ?? (execution.usdCost > 0 ? execution.usdCost : 0);
776
786
  const afterAdapterHook = await runPluginHook(db, {
777
787
  hook: "afterAdapterExecute",
778
788
  context: {
@@ -806,8 +816,10 @@ export async function runHeartbeatForAgent(
806
816
  runtimeModelId: effectivePricingModelId ?? runtimeModelId,
807
817
  pricingProviderType: effectivePricingProviderType,
808
818
  pricingModelId: effectivePricingModelId,
809
- tokenInput: execution.tokenInput,
810
- tokenOutput: execution.tokenOutput,
819
+ tokenInput: effectiveTokenInput,
820
+ tokenOutput: effectiveTokenOutput,
821
+ runtimeUsdCost: effectiveRuntimeUsdCost,
822
+ failureType: readTraceString(execution.trace, "failureType"),
811
823
  issueId: primaryIssueId,
812
824
  projectId: primaryProjectId,
813
825
  agentId,
@@ -865,8 +877,8 @@ export async function runHeartbeatForAgent(
865
877
  if (
866
878
  execution.nextState ||
867
879
  executionUsdCost > 0 ||
868
- execution.tokenInput > 0 ||
869
- execution.tokenOutput > 0 ||
880
+ effectiveTokenInput > 0 ||
881
+ effectiveTokenOutput > 0 ||
870
882
  execution.status !== "skipped"
871
883
  ) {
872
884
  await db
@@ -875,7 +887,7 @@ export async function runHeartbeatForAgent(
875
887
  stateBlob: JSON.stringify(execution.nextState ?? state),
876
888
  runtimeModel: effectivePricingModelId ?? persistedRuntime.runtimeModel ?? null,
877
889
  usedBudgetUsd: sql`${agents.usedBudgetUsd} + ${executionUsdCost}`,
878
- tokenUsage: sql`${agents.tokenUsage} + ${execution.tokenInput + execution.tokenOutput}`,
890
+ tokenUsage: sql`${agents.tokenUsage} + ${effectiveTokenInput + effectiveTokenOutput}`,
879
891
  updatedAt: new Date()
880
892
  })
881
893
  .where(and(eq(agents.companyId, companyId), eq(agents.id, agentId)));
@@ -883,8 +895,8 @@ export async function runHeartbeatForAgent(
883
895
 
884
896
  const shouldAdvanceIssuesToReview = shouldPromoteIssuesToReview({
885
897
  summary: execution.summary,
886
- tokenInput: execution.tokenInput,
887
- tokenOutput: execution.tokenOutput,
898
+ tokenInput: effectiveTokenInput,
899
+ tokenOutput: effectiveTokenOutput,
888
900
  usdCost: executionUsdCost,
889
901
  trace: executionTrace,
890
902
  outcome: executionOutcome
@@ -929,8 +941,8 @@ export async function runHeartbeatForAgent(
929
941
  summary: execution.summary,
930
942
  outcome: executionOutcome,
931
943
  usage: {
932
- tokenInput: execution.tokenInput,
933
- tokenOutput: execution.tokenOutput,
944
+ tokenInput: effectiveTokenInput,
945
+ tokenOutput: effectiveTokenOutput,
934
946
  usdCost: executionUsdCost
935
947
  }
936
948
  }
@@ -1062,9 +1074,9 @@ export async function runHeartbeatForAgent(
1062
1074
  outcome: executionOutcome,
1063
1075
  issueIds,
1064
1076
  usage: {
1065
- tokenInput: execution.tokenInput,
1066
- tokenOutput: execution.tokenOutput,
1067
- usdCost: execution.usdCost,
1077
+ tokenInput: effectiveTokenInput,
1078
+ tokenOutput: effectiveTokenOutput,
1079
+ usdCost: executionUsdCost,
1068
1080
  source: readTraceString(execution.trace, "usageSource") ?? "unknown"
1069
1081
  },
1070
1082
  trace: execution.trace ?? null,
@@ -2430,6 +2442,8 @@ async function appendFinishedRunCostEntry(input: {
2430
2442
  pricingModelId?: string | null;
2431
2443
  tokenInput: number;
2432
2444
  tokenOutput: number;
2445
+ runtimeUsdCost?: number;
2446
+ failureType?: string | null;
2433
2447
  issueId?: string | null;
2434
2448
  projectId?: string | null;
2435
2449
  agentId?: string | null;
@@ -2446,24 +2460,41 @@ async function appendFinishedRunCostEntry(input: {
2446
2460
  });
2447
2461
 
2448
2462
  const shouldPersist = input.status === "ok" || input.status === "failed";
2449
- if (shouldPersist) {
2463
+ const runtimeUsdCost = Math.max(0, input.runtimeUsdCost ?? 0);
2464
+ const pricedUsdCost = Math.max(0, pricingDecision.usdCost);
2465
+ const shouldUseRuntimeUsdCost = pricedUsdCost <= 0 && runtimeUsdCost > 0;
2466
+ const baseUsdCost = shouldUseRuntimeUsdCost ? runtimeUsdCost : pricedUsdCost;
2467
+ const effectiveUsdCost =
2468
+ baseUsdCost > 0
2469
+ ? baseUsdCost
2470
+ : input.status === "failed" && input.failureType !== "spawn_error"
2471
+ ? 0.000001
2472
+ : 0;
2473
+ const effectivePricingSource = pricingDecision.pricingSource;
2474
+ const shouldPersistWithUsage =
2475
+ shouldPersist && (input.tokenInput > 0 || input.tokenOutput > 0 || effectiveUsdCost > 0);
2476
+ if (shouldPersistWithUsage) {
2450
2477
  await appendCost(input.db, {
2451
2478
  companyId: input.companyId,
2452
2479
  providerType: input.providerType,
2453
2480
  runtimeModelId: input.runtimeModelId,
2454
2481
  pricingProviderType: pricingDecision.pricingProviderType,
2455
2482
  pricingModelId: pricingDecision.pricingModelId,
2456
- pricingSource: pricingDecision.pricingSource,
2483
+ pricingSource: effectivePricingSource,
2457
2484
  tokenInput: input.tokenInput,
2458
2485
  tokenOutput: input.tokenOutput,
2459
- usdCost: pricingDecision.usdCost.toFixed(6),
2486
+ usdCost: effectiveUsdCost.toFixed(6),
2460
2487
  issueId: input.issueId ?? null,
2461
2488
  projectId: input.projectId ?? null,
2462
2489
  agentId: input.agentId ?? null
2463
2490
  });
2464
2491
  }
2465
2492
 
2466
- return pricingDecision;
2493
+ return {
2494
+ ...pricingDecision,
2495
+ pricingSource: effectivePricingSource,
2496
+ usdCost: effectiveUsdCost
2497
+ };
2467
2498
  }
2468
2499
 
2469
2500
  function isHeartbeatDue(cronExpression: string, lastRunAt: Date | null, now: Date) {