@agent-native/core 0.220.0-nightly-20261024033422 → 0.220.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.
Files changed (38) hide show
  1. package/dist/a2a/handlers.js +7 -6
  2. package/dist/a2a/types.d.ts +1 -0
  3. package/dist/agent/engine/tool-call-journal-seed.js +24 -20
  4. package/dist/agent/execution-fence.d.ts +1 -1
  5. package/dist/agent/execution-fence.js +8 -1
  6. package/dist/agent/production-agent.js +31 -6
  7. package/dist/agent/reaped-run-thread.js +38 -3
  8. package/dist/agent/run-migrations.js +22 -0
  9. package/dist/agent/run-store.d.ts +19 -2
  10. package/dist/agent/run-store.fencing.worker.js +21 -1
  11. package/dist/agent/run-store.js +359 -35
  12. package/dist/agent/tool-approval-store.d.ts +13 -0
  13. package/dist/agent/tool-approval-store.js +64 -0
  14. package/dist/automation/index.d.ts +1 -1
  15. package/dist/client/background-agent-session.d.ts +4 -0
  16. package/dist/client/background-agent-session.js +17 -1
  17. package/dist/client/chat/runtime.js +38 -6
  18. package/dist/collab/routes.d.ts +2 -2
  19. package/dist/db/schema-snapshot.generated.js +14 -1
  20. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  21. package/dist/jobs/automation-recovery.d.ts +4 -0
  22. package/dist/jobs/automation-recovery.js +7 -0
  23. package/dist/jobs/background-automation-runner.js +19 -2
  24. package/dist/jobs/scheduler.js +3 -1
  25. package/dist/mcp/org-directory.d.ts +8 -7
  26. package/dist/mcp/org-directory.js +82 -1
  27. package/dist/notifications/routes.d.ts +1 -1
  28. package/dist/observability/routes.d.ts +7 -7
  29. package/dist/progress/routes.d.ts +1 -1
  30. package/dist/resources/handlers.d.ts +2 -2
  31. package/dist/secrets/routes.d.ts +10 -10
  32. package/dist/server/agent-chat-plugin.d.ts +10 -1
  33. package/dist/server/agent-chat-plugin.js +178 -11
  34. package/dist/server/agent-discovery.js +11 -49
  35. package/dist/server/agent-engine-default-model-route.d.ts +1 -1
  36. package/dist/server/agent-engine-ollama-models-route.d.ts +2 -2
  37. package/dist/usage/store.js +36 -33
  38. package/package.json +4 -4
@@ -1,5 +1,5 @@
1
1
  import type { Message as A2AMessage } from "../a2a/types.js";
2
- import { type ActionEntry, type AgentActionSurfaceDetails, type AgentActionSurfaceResolution } from "../agent/production-agent.js";
2
+ import { type ActionEntry, type AgentActionSurfaceDetails, type AgentActionSurfaceResolution, type AgentLoopUsage } from "../agent/production-agent.js";
3
3
  import { type ActiveRun } from "../agent/run-manager.js";
4
4
  import { foldAgentChatRunCompletion } from "../agent/thread-data-builder.js";
5
5
  import type { AgentChatEvent, AgentChatScope } from "../agent/types.js";
@@ -79,6 +79,15 @@ export declare function createSerializedA2ATaskStatusWriter(taskId: string, writ
79
79
  flush: () => Promise<void>;
80
80
  };
81
81
  export declare function runA2AAgentLoopWithRunManager(runOptions: Parameters<typeof runA2AAgentLoop>[0], pluginOptions: Pick<AgentChatPluginOptions, "delegatedRunPolicy" | "finalResponseGuard" | "runSoftTimeoutMs">, timeoutOptions: Parameters<typeof runA2AAgentLoop>[2], delegatedOptions?: Parameters<typeof runA2AAgentLoop>[3], taskSignal?: AbortSignal): Promise<Awaited<ReturnType<typeof runA2AAgentLoop>>>;
82
+ export declare function runA2AWithUsageLedger<T>(run: Promise<T>, input: {
83
+ usage: AgentLoopUsage;
84
+ ownerEmail: string;
85
+ orgId: string | null;
86
+ appId?: string;
87
+ taskId: string;
88
+ processingAttemptId?: string;
89
+ persistUsage?: (record: import("../usage/store.js").UsageRecord) => Promise<void>;
90
+ }): Promise<T>;
82
91
  export declare function resolveA2ARecoverableArtifactSecret(orgId?: string | null | undefined): Promise<string | undefined>;
83
92
  export declare function buildLeanRunPolicyPrompt(codeEditingSurfaceRestriction: string, prodCodeExecPromptNote: string): string;
84
93
  export declare function filterPromptActionsToSurface(actions: Record<string, ActionEntry>, allowedActionNames?: readonly string[]): Record<string, ActionEntry>;
@@ -20,15 +20,16 @@ import { SYSTEM_PROMPT_CACHE_SPLIT } from "../agent/engine/prompt-cache.js";
20
20
  import { PROVIDER_TO_ENV } from "../agent/engine/provider-env-vars.js";
21
21
  import { currentExecutionFence, withExecutionFence, } from "../agent/execution-fence.js";
22
22
  import { hostedHarnessSystemPrompt } from "../agent/harness/hosted.js";
23
- import { createProductionAgentHandler, endsAtContinuationBoundary, actionsToEngineTools, executeAgentToolCall, filterActionsByAllowedNames, normalizeAgentActionSurfaceResolution, getActiveRunForThreadAsync, getJevContextCredentials, abortRunDurably, abortRunAndTurnDurably, abortRunAtSafeBoundaryDurably, abortTurnByRefDurably, abortTurnDurably, subscribeToRun, } from "../agent/production-agent.js";
23
+ import { createProductionAgentHandler, endsAtContinuationBoundary, actionsToEngineTools, executeAgentToolCall, filterActionsByAllowedNames, normalizeAgentActionSurfaceResolution, getActiveRunForThreadAsync, getJevContextCredentials, abortRunDurably, abortRunAndTurnDurably, abortRunAtSafeBoundaryDurably, abortTurnByRefDurably, abortTurnDurably, subscribeToRun, mergeAgentLoopUsage, } from "../agent/production-agent.js";
24
24
  import { applyProviderModelSelection, providerForEngineName, resolveProviderModelSelectionAtScope, } from "../agent/provider-model-selection.js";
25
25
  import { startRun } from "../agent/run-manager.js";
26
26
  import { callerHasRunAccess, callerHasThreadAccess, } from "../agent/run-ownership.js";
27
- import { getRunById, readBackgroundRunClaim } from "../agent/run-store.js";
27
+ import { AgentRunJournalUnreadableError, getRunById, readBackgroundRunClaim, retryRunThreadProjection, } from "../agent/run-store.js";
28
28
  import { buildAssistantMessageFromRunJournal } from "../agent/run-thread-projector.js";
29
29
  import { buildCurrentTimeUserContext, buildRuntimeContextPrompt, } from "../agent/runtime-context.js";
30
30
  import { buildAssistantMessage, buildUserMessage, applySubmittedUserMessage, containsInlineAttachmentPayload, foldAgentChatRunCompletion, extractThreadMeta, foldUnstartedTurnFailure, mergeThreadDataForClientSave, } from "../agent/thread-data-builder.js";
31
31
  import { appendThreadDebugHistory } from "../agent/thread-debug-history.js";
32
+ import { denyAgentToolApproval } from "../agent/tool-approval-store.js";
32
33
  import { attachToolSearch } from "../agent/tool-search.js";
33
34
  import { getAppConfig } from "../app-config/index.js";
34
35
  import { readAppStateForCurrentTab } from "../application-state/script-helpers.js";
@@ -518,6 +519,56 @@ export async function runA2AAgentLoopWithRunManager(runOptions, pluginOptions, t
518
519
  }
519
520
  return result;
520
521
  }
522
+ export async function runA2AWithUsageLedger(run, input) {
523
+ const outcome = await run.then((value) => ({ ok: true, value }), (error) => ({ ok: false, error }));
524
+ let usageError;
525
+ let usageFailed = false;
526
+ if (input.usage.usageReported) {
527
+ try {
528
+ const record = {
529
+ ownerEmail: input.ownerEmail,
530
+ inputTokens: input.usage.inputTokens,
531
+ outputTokens: input.usage.outputTokens,
532
+ cacheReadTokens: input.usage.cacheReadTokens,
533
+ cacheWriteTokens: input.usage.cacheWriteTokens,
534
+ builderCreditsUsed: input.usage.builderCreditsUsed,
535
+ engineName: input.usage.engineName,
536
+ model: input.usage.model,
537
+ app: input.appId,
538
+ orgId: input.orgId ?? undefined,
539
+ label: "a2a",
540
+ // A replay in the same lease replaces its receipt; later leases
541
+ // retain their own usage segments under a different ref.
542
+ refId: input.processingAttemptId
543
+ ? `${input.taskId}:${input.processingAttemptId}`
544
+ : input.taskId,
545
+ runId: input.taskId,
546
+ threadId: input.taskId,
547
+ taskId: input.taskId,
548
+ };
549
+ if (input.persistUsage) {
550
+ await input.persistUsage(record);
551
+ }
552
+ else {
553
+ const { recordUsage } = await import("../usage/store.js");
554
+ await recordUsage(record);
555
+ }
556
+ }
557
+ catch (error) {
558
+ usageFailed = true;
559
+ usageError = error;
560
+ }
561
+ }
562
+ if (!outcome.ok) {
563
+ if (usageFailed) {
564
+ throw new AggregateError([outcome.error, usageError], "A2A run and usage persistence both failed.");
565
+ }
566
+ throw outcome.error;
567
+ }
568
+ if (usageFailed)
569
+ throw usageError;
570
+ return outcome.value;
571
+ }
521
572
  const A2A_ACTIVITY_CHECKPOINT_MIN_INTERVAL_MS = 2_000;
522
573
  export async function resolveA2ARecoverableArtifactSecret(orgId = getRequestOrgId()) {
523
574
  const globalSecret = process.env.A2A_SECRET?.trim();
@@ -827,12 +878,12 @@ export function createAgentChatPlugin(options) {
827
878
  const initPromise = (async () => {
828
879
  const { awaitBootstrap } = await import("./framework-request-handler.js");
829
880
  await awaitBootstrap(nitroApp);
830
- const appProfileAppId = options?.appId ??
881
+ const runtimeAppId = options?.appId ??
831
882
  getAppConfig().app.id ??
832
883
  getAppConfig().app.template ??
833
884
  getAppConfig().app.workspaceId ??
834
- getAppConfig().app.packageName ??
835
- "app";
885
+ getAppConfig().app.packageName;
886
+ const appProfileAppId = runtimeAppId ?? "app";
836
887
  // Never make route readiness wait on an org-global stale-run sweep.
837
888
  // `/runs/active` reaps the requested run on demand, and the periodic
838
889
  // recovery sweep below handles abandoned runs with no connected client.
@@ -2170,6 +2221,14 @@ export function createAgentChatPlugin(options) {
2170
2221
  const a2aEvents = [];
2171
2222
  const a2aToolResults = [];
2172
2223
  let a2aOutcome;
2224
+ const a2aUsage = {
2225
+ inputTokens: 0,
2226
+ outputTokens: 0,
2227
+ cacheReadTokens: 0,
2228
+ cacheWriteTokens: 0,
2229
+ engineName: a2aEngine.name,
2230
+ model,
2231
+ };
2173
2232
  let lastRecoverableArtifactText = "";
2174
2233
  let activityState = createA2AAgentActivityState();
2175
2234
  let lastActivityCheckpointAt = 0;
@@ -2208,7 +2267,7 @@ export function createAgentChatPlugin(options) {
2208
2267
  correlation.callerThreadId ??
2209
2268
  context.taskId;
2210
2269
  console.log(`[A2A] Starting agent loop: ${a2aToolSurface.tools.length}/${a2aToolSurface.availableTools.length} initial tools, prompt ${systemPrompt.length} chars`);
2211
- await runA2AAgentLoopWithRunManager({
2270
+ const a2aRun = runA2AAgentLoopWithRunManager({
2212
2271
  engine: a2aEngine,
2213
2272
  model,
2214
2273
  systemPrompt,
@@ -2224,7 +2283,7 @@ export function createAgentChatPlugin(options) {
2224
2283
  orgId: getRequestOrgId() ?? null,
2225
2284
  // Without it, every action with an `access` policy is refused
2226
2285
  // for lack of an application identity.
2227
- appId: options?.appId,
2286
+ appId: runtimeAppId,
2228
2287
  executionMode: "act",
2229
2288
  runId: context.taskId,
2230
2289
  networkProtocol: "a2a",
@@ -2238,6 +2297,12 @@ export function createAgentChatPlugin(options) {
2238
2297
  onOutcome: (outcome) => {
2239
2298
  a2aOutcome = outcome;
2240
2299
  },
2300
+ onUsage: (usage) => {
2301
+ mergeAgentLoopUsage(a2aUsage, {
2302
+ ...usage,
2303
+ usageReported: true,
2304
+ });
2305
+ },
2241
2306
  send: (event) => {
2242
2307
  a2aEvents.push(event);
2243
2308
  const nextActivityState = applyA2AAgentActivityEvent(activityState, event);
@@ -2317,6 +2382,14 @@ export function createAgentChatPlugin(options) {
2317
2382
  },
2318
2383
  },
2319
2384
  }, context.signal);
2385
+ await runA2AWithUsageLedger(a2aRun, {
2386
+ usage: a2aUsage,
2387
+ ownerEmail: userEmail,
2388
+ orgId: getRequestOrgId() ?? null,
2389
+ appId: runtimeAppId,
2390
+ taskId: context.taskId,
2391
+ processingAttemptId: context.processingAttemptId,
2392
+ });
2320
2393
  // The continuation can observe terminal output immediately, so make
2321
2394
  // its latest mutation checkpoint durable first.
2322
2395
  checkpointActivity(true);
@@ -5260,6 +5333,41 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
5260
5333
  const canViewRun = (runId) => callerHasRunAccess(owner, runId, "viewer", { orgId });
5261
5334
  const canEditRun = (runId) => callerHasRunAccess(owner, runId, "editor", { orgId });
5262
5335
  const canEditThread = (threadId) => callerHasThreadAccess(owner, threadId, "editor", { orgId });
5336
+ // Route: POST /runs/:id/retry-projection
5337
+ // An editor may retry a pending fold after repairing its source.
5338
+ const retryProjectionMatch = url.match(/\/runs\/([^/?]+)\/retry-projection(?:[/?]|$)/) ||
5339
+ url.match(/^\/([^/?]+)\/retry-projection(?:[/?]|$)/);
5340
+ if (retryProjectionMatch && method === "POST") {
5341
+ const runId = decodeURIComponent(retryProjectionMatch[1]);
5342
+ if (!(await canEditRun(runId))) {
5343
+ setResponseStatus(event, 404);
5344
+ return { error: "Run not found" };
5345
+ }
5346
+ const run = await getRunById(runId);
5347
+ if (!run) {
5348
+ setResponseStatus(event, 404);
5349
+ return { error: "Run not found" };
5350
+ }
5351
+ try {
5352
+ const result = await retryRunThreadProjection(runId);
5353
+ if (result.state === "untracked") {
5354
+ setResponseStatus(event, 404);
5355
+ return { error: "Run not found" };
5356
+ }
5357
+ return { ok: true, ...result };
5358
+ }
5359
+ catch (error) {
5360
+ if (error instanceof AgentRunJournalUnreadableError) {
5361
+ setResponseStatus(event, 422);
5362
+ return {
5363
+ ok: false,
5364
+ error: "Projection source remains unreadable",
5365
+ threadProjectionErrorCode: error.errorCode,
5366
+ };
5367
+ }
5368
+ throw error;
5369
+ }
5370
+ }
5263
5371
  // Route: POST /runs/turn/:turnId/abort
5264
5372
  // Covers the short window where the client has sent a turn but the
5265
5373
  // server has not yet created its background run id.
@@ -5898,7 +6006,7 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
5898
6006
  const runs = await runWithRequestContext({ userEmail: owner, orgId }, () => listRunsForThread(thread.id, { runIds }));
5899
6007
  return {
5900
6008
  queriedRunIds: runIds,
5901
- runs: runs.map(({ id, status, startedAt, completedAt, errorCode, abortReason, terminalReason, }) => ({
6009
+ runs: runs.map(({ id, status, startedAt, completedAt, errorCode, abortReason, terminalReason, threadProjectionErrorCode, }) => ({
5902
6010
  id,
5903
6011
  status,
5904
6012
  startedAt,
@@ -5906,11 +6014,64 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
5906
6014
  errorCode,
5907
6015
  abortReason,
5908
6016
  terminalReason,
6017
+ threadProjectionErrorCode,
5909
6018
  })),
5910
6019
  };
5911
6020
  };
5912
6021
  // ── Specific thread: GET/PUT/DELETE /threads/:id ──
5913
6022
  if (threadId) {
6023
+ if (method === "POST" &&
6024
+ isThreadSubroute("approval-resolution") &&
6025
+ threadTail.length === 1) {
6026
+ const thread = await resolveThreadAccess(owner, threadId, "editor", { orgId });
6027
+ if (!thread || !threadMatchesRequestedScope(thread)) {
6028
+ return threadNotFound();
6029
+ }
6030
+ const body = await readBody(event);
6031
+ const record = body &&
6032
+ typeof body === "object" &&
6033
+ !Array.isArray(body) &&
6034
+ body;
6035
+ const approvalId = typeof record?.approvalId === "string"
6036
+ ? record.approvalId.trim()
6037
+ : "";
6038
+ if (!approvalId || record?.decision !== "deny") {
6039
+ setResponseStatus(event, 400);
6040
+ return { error: "Invalid approval resolution" };
6041
+ }
6042
+ const resolved = await denyAgentToolApproval({
6043
+ approvalId,
6044
+ ownerEmail: owner,
6045
+ orgId,
6046
+ threadId,
6047
+ });
6048
+ if (resolved === "not_applied") {
6049
+ setResponseStatus(event, 409);
6050
+ return {
6051
+ error: "Approval denial could not be applied",
6052
+ code: "approval_denial_not_applied",
6053
+ retryable: false,
6054
+ };
6055
+ }
6056
+ if (resolved === "already_resolved") {
6057
+ setResponseStatus(event, 409);
6058
+ return {
6059
+ error: "Approval is no longer pending",
6060
+ code: "approval_not_pending",
6061
+ retryable: false,
6062
+ };
6063
+ }
6064
+ scheduleQueuedSubmissionInboxDrain({
6065
+ threadId,
6066
+ turnContinues: false,
6067
+ waitUntil: getRequestRunContext()?.waitUntil,
6068
+ drain: drainQueuedSubmissionInbox,
6069
+ onError: (error) => {
6070
+ console.error(`[agent-chat] denied-approval inbox drain failed for ${threadId}:`, error);
6071
+ },
6072
+ });
6073
+ return { ok: true };
6074
+ }
5914
6075
  if (method === "GET" &&
5915
6076
  threadTail[0] === "queue" &&
5916
6077
  threadTail[1] &&
@@ -7610,6 +7771,9 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
7610
7771
  console.error("[agent-chat] durable stale-run reap failed:", error);
7611
7772
  return null;
7612
7773
  });
7774
+ const staleRunReapIncomplete = staleRunsReaped === null ||
7775
+ staleRunsReaped.failed > 0 ||
7776
+ staleRunsReaped.truncated;
7613
7777
  const staleAgentTeamRuns = await reconcileStaleAgentTeamRuns(event).catch((error) => {
7614
7778
  console.error("[agent-chat] durable Agent Teams reconciliation failed:", error);
7615
7779
  return null;
@@ -7660,7 +7824,8 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
7660
7824
  };
7661
7825
  }
7662
7826
  if (!triggerAvailability.available) {
7663
- if (appSweepHandlers.failed.length > 0 ||
7827
+ if (staleRunReapIncomplete ||
7828
+ appSweepHandlers.failed.length > 0 ||
7664
7829
  automationFailureAlerts === null ||
7665
7830
  queuedSubmissionDrain === null ||
7666
7831
  queuedSubmissionDrain.failed > 0 ||
@@ -7669,7 +7834,8 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
7669
7834
  setResponseStatus(event, 500);
7670
7835
  }
7671
7836
  return {
7672
- ok: appSweepHandlers.failed.length === 0 &&
7837
+ ok: !staleRunReapIncomplete &&
7838
+ appSweepHandlers.failed.length === 0 &&
7673
7839
  automationFailureAlerts !== null &&
7674
7840
  queuedSubmissionDrain !== null &&
7675
7841
  queuedSubmissionDrain.failed === 0 &&
@@ -7688,7 +7854,8 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
7688
7854
  }
7689
7855
  try {
7690
7856
  await processRecurringJobs(schedulerDeps);
7691
- if (appSweepHandlers.failed.length > 0 ||
7857
+ if (staleRunReapIncomplete ||
7858
+ appSweepHandlers.failed.length > 0 ||
7692
7859
  automationFailureAlerts === null ||
7693
7860
  queuedSubmissionDrain === null ||
7694
7861
  queuedSubmissionDrain.failed > 0 ||
@@ -577,59 +577,21 @@ function mergeDiscoveredAgent(agentsById, candidate) {
577
577
  async function discoverOrgDirectoryApps(selfAppId) {
578
578
  const selfId = selfAppId ? normalizeAgentId(selfAppId) : undefined;
579
579
  try {
580
- const { fetchOrgAppsResult, resolveOrgDirectoryOrigin } = await import("../mcp/org-directory.js");
581
- const configuredBaseUrl = resolveOrgDirectoryOrigin();
582
- let result = await fetchOrgAppsResult({ selfId });
583
- let baseUrl = configuredBaseUrl;
584
- if (result.status === "unavailable" && result.reason === "not-configured") {
585
- const orgId = getRequestOrgId();
586
- if (!orgId) {
587
- return {
588
- status: "setup-required",
589
- reason: "organization-not-selected",
590
- };
591
- }
592
- const { getOrgWorkspaceUrl } = await import("../org/context.js");
593
- const workspaceUrl = await getOrgWorkspaceUrl(orgId);
594
- if (!workspaceUrl) {
595
- return { status: "setup-required", reason: "workspace-url-not-set" };
596
- }
597
- let workspaceOrigin;
598
- try {
599
- const parsed = new URL(workspaceUrl);
600
- if ((parsed.protocol !== "http:" && parsed.protocol !== "https:") ||
601
- parsed.username ||
602
- parsed.password ||
603
- parsed.search ||
604
- parsed.hash ||
605
- (parsed.pathname !== "/" && parsed.pathname !== "")) {
606
- return { status: "setup-required", reason: "invalid-workspace-url" };
607
- }
608
- workspaceOrigin = parsed.origin;
609
- }
610
- catch {
611
- return { status: "setup-required", reason: "invalid-workspace-url" };
612
- }
613
- baseUrl = `${workspaceOrigin}/dispatch`;
614
- result = await fetchOrgAppsResult({ directoryBaseUrl: baseUrl, selfId });
615
- }
616
- if (result.status === "unavailable" &&
617
- result.reason === "missing-route" &&
618
- baseUrl) {
619
- const rootUrl = new URL(baseUrl).origin;
620
- if (rootUrl !== baseUrl.replace(/\/+$/, "")) {
621
- result = await fetchOrgAppsResult({
622
- directoryBaseUrl: rootUrl,
623
- selfId,
624
- });
625
- }
626
- }
580
+ const { fetchOrgAppsResult } = await import("../mcp/org-directory.js");
581
+ const result = await fetchOrgAppsResult({ selfId });
627
582
  if (result.status === "available")
628
583
  return result;
629
584
  if (result.reason === "authorization")
630
585
  return { status: "forbidden" };
631
- if (result.reason === "not-configured" ||
632
- result.reason === "invalid-origin") {
586
+ if (result.reason === "not-configured") {
587
+ return {
588
+ status: "setup-required",
589
+ reason: getRequestOrgId()
590
+ ? "workspace-url-not-set"
591
+ : "organization-not-selected",
592
+ };
593
+ }
594
+ if (result.reason === "invalid-origin") {
633
595
  return { status: "setup-required", reason: result.reason };
634
596
  }
635
597
  return { status: "unavailable", reason: result.reason };
@@ -8,8 +8,8 @@ export declare const AGENT_ENGINE_API_KEY_ACTION_NAME = "agent-engine-api-key";
8
8
  * resolveEngine's credential detection.
9
9
  */
10
10
  export declare function createAgentEngineDisconnectHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
11
- ok?: undefined;
12
11
  error: string;
12
+ ok?: undefined;
13
13
  scope?: undefined;
14
14
  } | {
15
15
  ok: boolean;
@@ -1,9 +1,9 @@
1
1
  export declare function createAgentEngineOllamaModelsHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
2
+ ok?: undefined;
2
3
  error: string;
3
4
  models?: undefined;
4
- ok?: undefined;
5
5
  } | {
6
+ error?: undefined;
6
7
  ok: boolean;
7
8
  models: string[];
8
- error?: undefined;
9
9
  }>>;
@@ -252,48 +252,51 @@ export async function recordUsage(recordOrOwner, inputTokens, outputTokens, mode
252
252
  const resolvedLabel = label ?? "chat";
253
253
  const resolvedRef = refId ?? "";
254
254
  const resolvedOrgId = orgId ?? getRequestOrgId() ?? null;
255
- if (resolvedRef) {
256
- await client.execute({
257
- sql: `DELETE FROM token_usage
258
- WHERE label = ? AND ref_id = ?
259
- AND (org_id IS NULL OR org_id = ?)`,
260
- args: [resolvedLabel, resolvedRef, resolvedOrgId],
261
- });
262
- }
263
255
  const resolvedCostSource = costSource ?? (costCentsX100 == null ? "estimated" : "reported");
264
256
  const costX100 = resolvedCostSource === "unavailable"
265
257
  ? 0
266
258
  : (costCentsX100 ??
267
259
  calculateCost(inTok, outTok, modelName, cacheReadTokens, cacheWriteTokens));
268
260
  const id = Date.now() * 1000 + Math.floor(Math.random() * 1000);
261
+ const insertArgs = [
262
+ id,
263
+ ownerEmail,
264
+ inTok,
265
+ outTok,
266
+ cacheReadTokens,
267
+ cacheWriteTokens,
268
+ costX100,
269
+ builderCreditsUsed ?? null,
270
+ engineName ?? null,
271
+ resolvedCostSource,
272
+ modelName,
273
+ resolvedLabel,
274
+ resolvedApp,
275
+ resolvedRef,
276
+ resolvedOrgId,
277
+ runId ?? null,
278
+ threadId ?? null,
279
+ taskId ?? null,
280
+ integrationScopeId ?? null,
281
+ sourcePlatform ?? null,
282
+ sourceId ?? null,
283
+ Date.now(),
284
+ ];
285
+ const replaceRefSql = resolvedRef
286
+ ? `WITH prior_usage AS (
287
+ DELETE FROM token_usage
288
+ WHERE label = ? AND ref_id = ?
289
+ AND (org_id IS NULL OR org_id = ?)
290
+ RETURNING id
291
+ ) `
292
+ : "";
269
293
  await client.execute({
270
- sql: `INSERT INTO token_usage
294
+ sql: `${replaceRefSql}INSERT INTO token_usage
271
295
  (id, owner_email, input_tokens, output_tokens, cache_read_tokens, cache_write_tokens, cost_cents_x100, builder_credits_used, engine_name, cost_source, model, label, app, ref_id, org_id, run_id, thread_id, task_id, integration_scope_id, source_platform, source_id, created_at)
272
296
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
273
- args: [
274
- id,
275
- ownerEmail,
276
- inTok,
277
- outTok,
278
- cacheReadTokens,
279
- cacheWriteTokens,
280
- costX100,
281
- builderCreditsUsed ?? null,
282
- engineName ?? null,
283
- resolvedCostSource,
284
- modelName,
285
- resolvedLabel,
286
- resolvedApp,
287
- resolvedRef,
288
- resolvedOrgId,
289
- runId ?? null,
290
- threadId ?? null,
291
- taskId ?? null,
292
- integrationScopeId ?? null,
293
- sourcePlatform ?? null,
294
- sourceId ?? null,
295
- Date.now(),
296
- ],
297
+ args: resolvedRef
298
+ ? [resolvedLabel, resolvedRef, resolvedOrgId, ...insertArgs]
299
+ : insertArgs,
297
300
  });
298
301
  void import("./alerts-store.js")
299
302
  .then(({ enqueueUsageAlertEvaluation }) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-native/core",
3
- "version": "0.220.0-nightly-20261024033422",
3
+ "version": "0.220.0",
4
4
  "description": "The agentic application framework for building autonomous agents with intuitive UIs",
5
5
  "homepage": "https://github.com/BuilderIO/agent-native#readme",
6
6
  "bugs": {
@@ -730,8 +730,8 @@
730
730
  "yaml": "^2.9.0",
731
731
  "yjs": "^13.6.33",
732
732
  "zod": "^4.3.6",
733
- "@agent-native/agentkit": "^0.220.0-nightly-20261024033422",
734
- "@agent-native/recap-cli": "^0.5.88"
733
+ "@agent-native/agentkit": "^0.220.0",
734
+ "@agent-native/recap-cli": "^0.5.89"
735
735
  },
736
736
  "devDependencies": {
737
737
  "@ai-sdk/anthropic": "^3.0.71",
@@ -801,7 +801,7 @@
801
801
  "xlsx": "^0.18.5"
802
802
  },
803
803
  "peerDependencies": {
804
- "@agent-native/core-corpus": "0.220.0-nightly-20261024033422",
804
+ "@agent-native/core-corpus": ">=0.196.0",
805
805
  "@ai-sdk/anthropic": ">=3",
806
806
  "@ai-sdk/cohere": ">=3",
807
807
  "@ai-sdk/google": ">=3",