@agent-native/core 0.109.0 → 0.109.1
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/corpus/README.md +2 -2
- package/corpus/core/CHANGELOG.md +7 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/a2a/client.ts +24 -2
- package/corpus/core/src/a2a/correlation.ts +50 -0
- package/corpus/core/src/a2a/handlers.ts +140 -14
- package/corpus/core/src/a2a/index.ts +1 -0
- package/corpus/core/src/a2a/invoke.ts +10 -1
- package/corpus/core/src/a2a/task-store.ts +146 -6
- package/corpus/core/src/a2a/types.ts +16 -0
- package/corpus/core/src/action.ts +2 -0
- package/corpus/core/src/agent/production-agent.ts +23 -0
- package/corpus/core/src/client/use-run-stuck-detection.ts +27 -1
- package/corpus/core/src/db/client.ts +55 -0
- package/corpus/core/src/observability/traces.ts +172 -19
- package/corpus/core/src/scripts/call-agent.ts +53 -2
- package/corpus/core/src/server/agent-chat/action-filters-a2a.ts +72 -25
- package/corpus/core/src/server/agent-chat-plugin.ts +107 -6
- package/corpus/core/src/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +21 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/observability/SKILL.md +7 -1
- package/corpus/core/src/templates/workspace-core/.agents/skills/tracking/SKILL.md +1 -1
- package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +1 -1
- package/corpus/templates/analytics/changelog/2026-07-17-analytics-now-includes-a-default-alert-for-spikes-in-stuck-agent-chats.md +6 -0
- package/corpus/templates/analytics/docs/schemas/first-party-analytics.md +23 -14
- package/corpus/templates/analytics/docs/schemas/tracked-events.md +5 -1
- package/corpus/templates/analytics/server/jobs/analytics-alerts.ts +3 -3
- package/corpus/templates/analytics/server/lib/analytics-alerts.ts +209 -87
- package/corpus/templates/clips/actions/finalize-recording.ts +541 -62
- package/corpus/templates/clips/app/components/player/playback-comment-overlay.tsx +17 -2
- package/corpus/templates/clips/app/components/player/video-player.tsx +14 -2
- package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +2 -2
- package/corpus/templates/clips/app/routes/r.$recordingId.tsx +1 -1
- package/corpus/templates/clips/app/routes/record.tsx +3 -3
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +6 -3
- package/corpus/templates/clips/changelog/2026-07-17-clips-now-retries-storage-verification-in-the-background-ins.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-17-fixed-broken-thumbnail-icons-appearing-over-playable-clip-em.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-17-playback-comments-stay-readable-at-faster-playback-speeds.md +6 -0
- package/corpus/templates/clips/chrome-extension/src/finalize-recovery.ts +3 -0
- package/corpus/templates/clips/chrome-extension/src/offscreen.ts +3 -3
- package/corpus/templates/clips/desktop/src/app.tsx +18 -6
- package/corpus/templates/clips/desktop/src/lib/recorder.ts +111 -13
- package/corpus/templates/clips/desktop/src/lib/upload-verification.ts +16 -7
- package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +2 -4
- package/corpus/templates/clips/desktop/src-tauri/src/native_screen/live_upload.rs +32 -15
- package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +45 -18
- package/corpus/templates/clips/server/jobs/media-verification.ts +130 -0
- package/corpus/templates/clips/server/lib/builder-media-compression.ts +15 -0
- package/corpus/templates/clips/server/lib/media-verification-state.ts +38 -0
- package/corpus/templates/clips/server/lib/player-thumbnail-url.ts +31 -0
- package/corpus/templates/clips/server/lib/post-finalize-dispatch.ts +10 -3
- package/corpus/templates/clips/server/plugins/auth.ts +5 -5
- package/corpus/templates/clips/server/plugins/calendar-jobs.ts +2 -0
- package/corpus/templates/clips/server/routes/api/_agent-native-background/post-finalize-worker.post.ts +12 -2
- package/corpus/templates/clips/server/routes/api/public-recording.get.ts +6 -1
- package/corpus/templates/clips/server/routes/api/thumbnail/[recordingId].get.ts +340 -0
- package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/abort.post.ts +24 -7
- package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/chunk.post.ts +91 -7
- package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/status.get.ts +14 -0
- package/corpus/templates/clips/shared/finalize-recovery.ts +61 -2
- package/corpus/templates/clips/shared/share-meta.ts +1 -1
- package/dist/a2a/client.d.ts +11 -2
- package/dist/a2a/client.d.ts.map +1 -1
- package/dist/a2a/client.js +16 -3
- package/dist/a2a/client.js.map +1 -1
- package/dist/a2a/correlation.d.ts +10 -0
- package/dist/a2a/correlation.d.ts.map +1 -0
- package/dist/a2a/correlation.js +40 -0
- package/dist/a2a/correlation.js.map +1 -0
- package/dist/a2a/handlers.d.ts.map +1 -1
- package/dist/a2a/handlers.js +100 -15
- package/dist/a2a/handlers.js.map +1 -1
- package/dist/a2a/index.d.ts +1 -1
- package/dist/a2a/index.d.ts.map +1 -1
- package/dist/a2a/index.js.map +1 -1
- package/dist/a2a/invoke.d.ts +4 -1
- package/dist/a2a/invoke.d.ts.map +1 -1
- package/dist/a2a/invoke.js +3 -0
- package/dist/a2a/invoke.js.map +1 -1
- package/dist/a2a/task-store.d.ts +12 -1
- package/dist/a2a/task-store.d.ts.map +1 -1
- package/dist/a2a/task-store.js +96 -6
- package/dist/a2a/task-store.js.map +1 -1
- package/dist/a2a/types.d.ts +15 -0
- package/dist/a2a/types.d.ts.map +1 -1
- package/dist/a2a/types.js.map +1 -1
- package/dist/action.d.ts +2 -0
- package/dist/action.d.ts.map +1 -1
- package/dist/action.js.map +1 -1
- package/dist/agent/production-agent.d.ts +9 -0
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +14 -0
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/client/use-run-stuck-detection.d.ts.map +1 -1
- package/dist/client/use-run-stuck-detection.js +25 -1
- package/dist/client/use-run-stuck-detection.js.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/db/client.d.ts +7 -0
- package/dist/db/client.d.ts.map +1 -1
- package/dist/db/client.js +33 -0
- package/dist/db/client.js.map +1 -1
- package/dist/observability/routes.d.ts +5 -5
- package/dist/observability/traces.d.ts +9 -0
- package/dist/observability/traces.d.ts.map +1 -1
- package/dist/observability/traces.js +137 -19
- package/dist/observability/traces.js.map +1 -1
- package/dist/resources/handlers.d.ts +2 -2
- package/dist/scripts/call-agent.d.ts.map +1 -1
- package/dist/scripts/call-agent.js +35 -3
- package/dist/scripts/call-agent.js.map +1 -1
- package/dist/secrets/routes.d.ts +9 -9
- package/dist/server/agent-chat/action-filters-a2a.d.ts +18 -2
- package/dist/server/agent-chat/action-filters-a2a.d.ts.map +1 -1
- package/dist/server/agent-chat/action-filters-a2a.js +35 -7
- package/dist/server/agent-chat/action-filters-a2a.js.map +1 -1
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +93 -6
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +21 -0
- package/dist/templates/workspace-core/.agents/skills/observability/SKILL.md +7 -1
- package/dist/templates/workspace-core/.agents/skills/tracking/SKILL.md +1 -1
- package/package.json +1 -1
- package/src/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +21 -0
- package/src/templates/workspace-core/.agents/skills/observability/SKILL.md +7 -1
- package/src/templates/workspace-core/.agents/skills/tracking/SKILL.md +1 -1
|
@@ -23,6 +23,10 @@ import {
|
|
|
23
23
|
isLoopbackAddress,
|
|
24
24
|
isTrustedLocalRuntime,
|
|
25
25
|
} from "../a2a/auth-policy.js";
|
|
26
|
+
import {
|
|
27
|
+
sanitizeA2ACorrelationId,
|
|
28
|
+
sanitizeA2ACorrelationMetadata,
|
|
29
|
+
} from "../a2a/correlation.js";
|
|
26
30
|
import { applyAgentTextEventToBuffer } from "../a2a/response-text.js";
|
|
27
31
|
import {
|
|
28
32
|
createA2AApproval,
|
|
@@ -115,6 +119,7 @@ import {
|
|
|
115
119
|
type ForkThreadSourceSnapshot,
|
|
116
120
|
} from "../chat-threads/store.js";
|
|
117
121
|
import { createDbAdminAgentTools } from "../db-admin/agent-tools.js";
|
|
122
|
+
import { isTransientDatabaseError } from "../db/client.js";
|
|
118
123
|
import {
|
|
119
124
|
verifyInternalToken,
|
|
120
125
|
extractBearerToken,
|
|
@@ -185,6 +190,55 @@ import {
|
|
|
185
190
|
export { handleSharedThreadRequest };
|
|
186
191
|
export type { SharedThreadRouteDependencies };
|
|
187
192
|
|
|
193
|
+
function withTransientDatabaseFallback(
|
|
194
|
+
route: string,
|
|
195
|
+
handler: (event: H3Event) => unknown,
|
|
196
|
+
) {
|
|
197
|
+
return defineEventHandler(async (event) => {
|
|
198
|
+
try {
|
|
199
|
+
return await handler(event);
|
|
200
|
+
} catch (error) {
|
|
201
|
+
if (!isTransientDatabaseError(error)) throw error;
|
|
202
|
+
|
|
203
|
+
const method = getMethod(event);
|
|
204
|
+
const retrySafe = method === "GET" || method === "HEAD";
|
|
205
|
+
|
|
206
|
+
const databaseError = error as {
|
|
207
|
+
code?: unknown;
|
|
208
|
+
cause?: { code?: unknown };
|
|
209
|
+
};
|
|
210
|
+
captureError(new Error("Transient database failure in agent chat"), {
|
|
211
|
+
route,
|
|
212
|
+
method,
|
|
213
|
+
tags: {
|
|
214
|
+
source: "agent-chat",
|
|
215
|
+
failureClass: "transient-database",
|
|
216
|
+
},
|
|
217
|
+
extra: {
|
|
218
|
+
databaseErrorName: error instanceof Error ? error.name : typeof error,
|
|
219
|
+
databaseErrorCode:
|
|
220
|
+
typeof databaseError.code === "string"
|
|
221
|
+
? databaseError.code
|
|
222
|
+
: undefined,
|
|
223
|
+
databaseCauseCode:
|
|
224
|
+
typeof databaseError.cause?.code === "string"
|
|
225
|
+
? databaseError.cause.code
|
|
226
|
+
: undefined,
|
|
227
|
+
},
|
|
228
|
+
});
|
|
229
|
+
setResponseStatus(event, 503);
|
|
230
|
+
if (retrySafe) setResponseHeader(event, "Retry-After", "2");
|
|
231
|
+
return {
|
|
232
|
+
error: retrySafe
|
|
233
|
+
? "The database is temporarily unavailable. Please retry."
|
|
234
|
+
: "The database became unavailable while processing this request. Refresh before deciding whether to retry.",
|
|
235
|
+
code: "database_unavailable",
|
|
236
|
+
retryable: retrySafe,
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
|
|
188
242
|
// Lazy fs — loaded via dynamic import() on first use.
|
|
189
243
|
// This avoids require() which bundlers convert to createRequire(import.meta.url)
|
|
190
244
|
// that crashes on CF Workers where import.meta.url is undefined.
|
|
@@ -1209,6 +1263,7 @@ export function createAgentChatPlugin(
|
|
|
1209
1263
|
|
|
1210
1264
|
const { mountA2A } = await import("../a2a/server.js");
|
|
1211
1265
|
mountA2A(nitroApp, {
|
|
1266
|
+
appId: options?.appId,
|
|
1212
1267
|
name: options?.appId
|
|
1213
1268
|
? options.appId.charAt(0).toUpperCase() + options.appId.slice(1)
|
|
1214
1269
|
: "Agent",
|
|
@@ -1217,7 +1272,7 @@ export function createAgentChatPlugin(
|
|
|
1217
1272
|
publicSkillsOnly: true,
|
|
1218
1273
|
streaming: true,
|
|
1219
1274
|
durableBackgroundRuns: options?.durableBackgroundRuns,
|
|
1220
|
-
executeReadOnlyAction: async ({ action, input }) => {
|
|
1275
|
+
executeReadOnlyAction: async ({ action, input, invocationId }) => {
|
|
1221
1276
|
const actions = filterDirectA2AActions(
|
|
1222
1277
|
mcpFullActions ?? allScripts,
|
|
1223
1278
|
options ?? {},
|
|
@@ -1234,10 +1289,12 @@ export function createAgentChatPlugin(
|
|
|
1234
1289
|
actions: { [action]: entry },
|
|
1235
1290
|
name: action,
|
|
1236
1291
|
input,
|
|
1237
|
-
callId: `a2a-action-${
|
|
1292
|
+
callId: `a2a-action-${invocationId}`,
|
|
1238
1293
|
ownerEmail: getRequestUserEmail(),
|
|
1239
1294
|
orgId: getRequestOrgId() ?? null,
|
|
1240
1295
|
caller: "a2a",
|
|
1296
|
+
networkProtocol: "a2a",
|
|
1297
|
+
networkId: invocationId,
|
|
1241
1298
|
});
|
|
1242
1299
|
if (result.status === "approval_required") {
|
|
1243
1300
|
return {
|
|
@@ -1574,6 +1631,11 @@ export function createAgentChatPlugin(
|
|
|
1574
1631
|
const recoverableArtifactStatusWriter =
|
|
1575
1632
|
createSerializedA2ATaskStatusWriter(context.taskId);
|
|
1576
1633
|
const controller = new AbortController();
|
|
1634
|
+
const correlation = sanitizeA2ACorrelationMetadata(context.metadata);
|
|
1635
|
+
const telemetryThreadId =
|
|
1636
|
+
sanitizeA2ACorrelationId(context.contextId) ??
|
|
1637
|
+
correlation.callerThreadId ??
|
|
1638
|
+
context.taskId;
|
|
1577
1639
|
|
|
1578
1640
|
console.log(
|
|
1579
1641
|
`[A2A] Starting agent loop: ${a2aToolSurface.tools.length}/${a2aToolSurface.availableTools.length} initial tools, prompt ${systemPrompt.length} chars`,
|
|
@@ -1598,6 +1660,11 @@ export function createAgentChatPlugin(
|
|
|
1598
1660
|
toolCallCacheKey(approved.tool, approved.input),
|
|
1599
1661
|
),
|
|
1600
1662
|
executionMode: "act",
|
|
1663
|
+
runId: context.taskId,
|
|
1664
|
+
networkProtocol: "a2a",
|
|
1665
|
+
networkId: context.taskId,
|
|
1666
|
+
threadId: context.taskId,
|
|
1667
|
+
turnId: context.taskId,
|
|
1601
1668
|
send: (event) => {
|
|
1602
1669
|
a2aEvents.push(event);
|
|
1603
1670
|
if (event.type === "tool_start") {
|
|
@@ -1658,6 +1725,26 @@ export function createAgentChatPlugin(
|
|
|
1658
1725
|
options?.durableBackgroundRuns === true &&
|
|
1659
1726
|
isInBackgroundFunctionRuntime(),
|
|
1660
1727
|
},
|
|
1728
|
+
{
|
|
1729
|
+
telemetry: {
|
|
1730
|
+
runId: context.taskId,
|
|
1731
|
+
threadId: telemetryThreadId,
|
|
1732
|
+
userId: userEmail,
|
|
1733
|
+
delegation: {
|
|
1734
|
+
protocol: "a2a",
|
|
1735
|
+
taskId: context.taskId,
|
|
1736
|
+
...(correlation.callerApp
|
|
1737
|
+
? { callerApp: correlation.callerApp }
|
|
1738
|
+
: {}),
|
|
1739
|
+
...(correlation.parentRunId
|
|
1740
|
+
? { parentRunId: correlation.parentRunId }
|
|
1741
|
+
: {}),
|
|
1742
|
+
...(correlation.parentTurnId
|
|
1743
|
+
? { parentTurnId: correlation.parentTurnId }
|
|
1744
|
+
: {}),
|
|
1745
|
+
},
|
|
1746
|
+
},
|
|
1747
|
+
},
|
|
1661
1748
|
);
|
|
1662
1749
|
|
|
1663
1750
|
// The continuation can observe terminal output immediately, so make
|
|
@@ -1814,6 +1901,7 @@ export function createAgentChatPlugin(
|
|
|
1814
1901
|
: {}),
|
|
1815
1902
|
askAgent: async (message: string) => {
|
|
1816
1903
|
const ownerEmail = getRequestUserEmail();
|
|
1904
|
+
const mcpRunId = crypto.randomUUID();
|
|
1817
1905
|
const { getOwnerActiveApiKey } =
|
|
1818
1906
|
await import("../agent/production-agent.js");
|
|
1819
1907
|
const ownerApiKey = ownerEmail
|
|
@@ -1942,9 +2030,14 @@ export function createAgentChatPlugin(
|
|
|
1942
2030
|
},
|
|
1943
2031
|
],
|
|
1944
2032
|
actions: mcpActions,
|
|
1945
|
-
ownerEmail
|
|
2033
|
+
ownerEmail,
|
|
1946
2034
|
orgId: getRequestOrgId() ?? null,
|
|
1947
2035
|
executionMode: "act",
|
|
2036
|
+
runId: mcpRunId,
|
|
2037
|
+
networkProtocol: "mcp",
|
|
2038
|
+
networkId: mcpRunId,
|
|
2039
|
+
threadId: mcpRunId,
|
|
2040
|
+
turnId: mcpRunId,
|
|
1948
2041
|
send: (event) => {
|
|
1949
2042
|
accumulatedText = applyAgentTextEventToBuffer(
|
|
1950
2043
|
accumulatedText,
|
|
@@ -1962,6 +2055,14 @@ export function createAgentChatPlugin(
|
|
|
1962
2055
|
options?.durableBackgroundRuns === true &&
|
|
1963
2056
|
isInBackgroundFunctionRuntime(),
|
|
1964
2057
|
},
|
|
2058
|
+
{
|
|
2059
|
+
telemetry: {
|
|
2060
|
+
runId: mcpRunId,
|
|
2061
|
+
threadId: mcpRunId,
|
|
2062
|
+
userId: ownerEmail ?? null,
|
|
2063
|
+
delegation: { protocol: "mcp" },
|
|
2064
|
+
},
|
|
2065
|
+
},
|
|
1965
2066
|
);
|
|
1966
2067
|
|
|
1967
2068
|
return accumulatedText || "(no response)";
|
|
@@ -4234,7 +4335,7 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
|
|
|
4234
4335
|
// GET /runs/active?threadId=X — check if there's an active run for a thread
|
|
4235
4336
|
getH3App(nitroApp).use(
|
|
4236
4337
|
`${routePath}/runs`,
|
|
4237
|
-
|
|
4338
|
+
withTransientDatabaseFallback(`${routePath}/runs`, async (event) => {
|
|
4238
4339
|
// Auth check — ensure the user is authenticated
|
|
4239
4340
|
const owner = await getOwnerFromEvent(event);
|
|
4240
4341
|
|
|
@@ -4753,7 +4854,7 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
|
|
|
4753
4854
|
`${getOrigin(event)}${routePath}/shared/${encodeURIComponent(token)}`;
|
|
4754
4855
|
getH3App(nitroApp).use(
|
|
4755
4856
|
`${routePath}/threads`,
|
|
4756
|
-
|
|
4857
|
+
withTransientDatabaseFallback(`${routePath}/threads`, async (event) => {
|
|
4757
4858
|
const owner = await getOwnerFromEvent(event);
|
|
4758
4859
|
const orgId = await getOrgIdFromEvent(event);
|
|
4759
4860
|
const method = getMethod(event);
|
|
@@ -5383,7 +5484,7 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
|
|
|
5383
5484
|
// earlier-mounted handlers (mode, save-key, files, skills, mentions, threads) handle them.
|
|
5384
5485
|
getH3App(nitroApp).use(
|
|
5385
5486
|
routePath,
|
|
5386
|
-
|
|
5487
|
+
withTransientDatabaseFallback(routePath, async (event) => {
|
|
5387
5488
|
// Skip sub-path requests — they're handled by earlier-mounted handlers
|
|
5388
5489
|
const url = event.node?.req?.url || event.path || "";
|
|
5389
5490
|
const afterBase = url.slice(
|
|
@@ -144,6 +144,27 @@ message delegation for planning, synthesis, multi-step work, or mutations.
|
|
|
144
144
|
Inside an agent loop, `call-agent` exposes the same path with `action` + `input`;
|
|
145
145
|
omit `message` and `taskId` in that mode.
|
|
146
146
|
|
|
147
|
+
### Retry safety and trace linkage
|
|
148
|
+
|
|
149
|
+
`call-agent` automatically derives an owner-scoped idempotency key from the
|
|
150
|
+
originating turn, target, and exact message. If a retry reaches the receiver
|
|
151
|
+
after the caller timed out, asynchronous `message/send` returns the existing
|
|
152
|
+
active or completed task instead of starting a duplicate agent run. Failed and
|
|
153
|
+
canceled tasks release the key for an intentional retry; synchronous calls are
|
|
154
|
+
never deduplicated. Lower-level clients may pass an
|
|
155
|
+
`idempotencyKey` explicitly; keep it stable for the same logical submission and
|
|
156
|
+
change it when the work changes. Dedupe is scoped to the JWT-authenticated
|
|
157
|
+
owner and verified org, and keys are limited to 128 characters.
|
|
158
|
+
|
|
159
|
+
The caller also forwards bounded correlation metadata (`callerApp`,
|
|
160
|
+
`callerThreadId`, `parentRunId`, `parentTurnId`, and direct-read
|
|
161
|
+
`invocationId`). These fields
|
|
162
|
+
are telemetry hints only. Receivers must continue to derive identity,
|
|
163
|
+
ownership, org scope, access, and approval from the verified request context.
|
|
164
|
+
Delegated model loops emit `$ai_generation` with A2A/MCP lineage, while direct
|
|
165
|
+
reads emit the content-free `$a2a_read_invoke` event; neither event includes
|
|
166
|
+
action arguments or results.
|
|
167
|
+
|
|
147
168
|
### Advanced: `A2AClient` (full control)
|
|
148
169
|
|
|
149
170
|
```ts
|
|
@@ -285,7 +285,13 @@ LLM generation:
|
|
|
285
285
|
- Agent Native Analytics shape: the same event lands in `analytics_events` with
|
|
286
286
|
mirrored query-friendly properties such as `run_id`, `thread_id`,
|
|
287
287
|
`cost_cents_x100`, `duration_ms`, `tool_calls`, `successful_tools`,
|
|
288
|
-
`failed_tools`, and `status`.
|
|
288
|
+
`failed_tools`, and `status`. A content-free `tools` array includes at most
|
|
289
|
+
50 tool names, start offsets, durations, statuses, and coarse error classes;
|
|
290
|
+
interrupted calls are finalized as errors, and failed runs still emit with
|
|
291
|
+
zero or known usage. `tools_truncated` marks longer runs while the rollup counts remain complete.
|
|
292
|
+
Delegated runs add `delegation_protocol`, `caller_app`, `a2a_task_id`, and
|
|
293
|
+
`parent_run_id` when available. `parent_turn_id` is separate because one
|
|
294
|
+
logical turn may span multiple concrete runs.
|
|
289
295
|
|
|
290
296
|
Do not build a separate LLM-observability ingestion API unless there is a clear
|
|
291
297
|
reason the tracking provider registry cannot express the use case. Keep prompt,
|
|
@@ -141,7 +141,7 @@ Other framework-level baseline events:
|
|
|
141
141
|
- `signup` from Better Auth user creation, with `auth_provider`, `auth_user_id`, and first-touch referral attribution (`referral_source`, `referrer_user`, `referral_medium`, `referral_campaign`, `utm_*`, `first_touch_path`, `landing_referrer` — see "Referral / viral attribution" above)
|
|
142
142
|
- `builder connect clicked` and `builder connect popup blocked` from browser Connect Builder CTAs
|
|
143
143
|
- `builder connect started`, `builder connect succeeded`, `builder connect failed`, `builder disconnect succeeded`, and `builder disconnect failed` from the Builder connection routes, with LLM connection context when resolvable
|
|
144
|
-
- `$ai_generation` from instrumented agent loops, with PostHog AI Observability fields such as `$ai_trace_id`, `$ai_session_id`, `$ai_model`, `$ai_provider`, `$ai_input_tokens`, `$ai_output_tokens`, `$ai_latency`, `$ai_total_cost_usd`, and mirrored Agent Native query fields such as `run_id`, `thread_id`, `cost_cents_x100`, `duration_ms`, `tool_calls`, and `status`. Prompt, tool argument, and output content is
|
|
144
|
+
- `$ai_generation` from instrumented agent loops, with PostHog AI Observability fields such as `$ai_trace_id`, `$ai_session_id`, `$ai_model`, `$ai_provider`, `$ai_input_tokens`, `$ai_output_tokens`, `$ai_latency`, `$ai_total_cost_usd`, and mirrored Agent Native query fields such as `run_id`, `thread_id`, `cost_cents_x100`, `duration_ms`, `tool_calls`, and `status`. A bounded `tools` array contains names, start offsets, durations, statuses, and coarse error classes only; interrupted tools and failed runs remain visible, and delegated runs include protocol/task/parent-run/parent-turn correlation. Prompt, tool argument, result, and output content is excluded.
|
|
145
145
|
|
|
146
146
|
For new lifecycle events, call `track()` server-side when the server is the source of truth, and `trackEvent()` client-side only for browser interactions.
|
|
147
147
|
|
|
@@ -15,7 +15,7 @@ function resolveScope() {
|
|
|
15
15
|
|
|
16
16
|
export default defineAction({
|
|
17
17
|
description:
|
|
18
|
-
"Query the built-in first-party Analytics source: events recorded through this app's analytics collector endpoint (/track) and session replay summaries recorded through /api/analytics/replay. This source does not require an external provider connection. Use it for questions about app/site traffic, product events, template/app usage, conversions, session recordings, LLM/agent observability, model cost, token volume, latency, and other first-party data collected by this analytics app. Use source-specific actions such as BigQuery, GA4, Mixpanel, PostHog, or Amplitude when the user asks for those sources or the relevant data lives there. SQL may read analytics_events and session_recordings only; session_replay_chunks is intentionally unavailable, and reads are automatically scoped to the current user/org. analytics_events columns include event_name, timestamp, event_date, user_id, anonymous_id, user_key, session_id, app, template, signed_in, url, path, hostname, referrer, properties, and context. LLM observability events use event_name = '$ai_generation'; useful properties include $ai_trace_id/run_id, $ai_session_id/thread_id, $ai_model/model, $ai_provider/provider, $ai_input_tokens/input_tokens, $ai_output_tokens/output_tokens, cache_read_tokens, cache_write_tokens, cost_cents_x100, $ai_total_cost_usd/cost_usd, duration_ms/$ai_latency, status, tool_calls, successful_tools, failed_tools, and error_message/$ai_error. session_recordings columns include id, session_id, user_id, anonymous_id, user_key, started_at, ended_at, duration_ms, chunk_count, event_count, page_count, error_count, rage_click_count, app, template, status, first_url, last_url, path, hostname, referrer, and metadata.",
|
|
18
|
+
"Query the built-in first-party Analytics source: events recorded through this app's analytics collector endpoint (/track) and session replay summaries recorded through /api/analytics/replay. This source does not require an external provider connection. Use it for questions about app/site traffic, product events, template/app usage, conversions, session recordings, LLM/agent observability, model cost, token volume, latency, and other first-party data collected by this analytics app. Use source-specific actions such as BigQuery, GA4, Mixpanel, PostHog, or Amplitude when the user asks for those sources or the relevant data lives there. SQL may read analytics_events and session_recordings only; session_replay_chunks is intentionally unavailable, and reads are automatically scoped to the current user/org. analytics_events columns include event_name, timestamp, event_date, user_id, anonymous_id, user_key, session_id, app, template, signed_in, url, path, hostname, referrer, properties, and context. LLM observability events use event_name = '$ai_generation'; useful properties include $ai_trace_id/run_id, $ai_session_id/thread_id, $ai_model/model, $ai_provider/provider, $ai_input_tokens/input_tokens, $ai_output_tokens/output_tokens, cache_read_tokens, cache_write_tokens, cost_cents_x100, $ai_total_cost_usd/cost_usd, duration_ms/$ai_latency, status, tool_calls, successful_tools, failed_tools, tools, tools_truncated, delegated, delegation_protocol, caller_app, a2a_task_id, parent_run_id, parent_turn_id, and error_message/$ai_error. The bounded tools array contains names, relative start times, durations, statuses, and coarse error classes only, never args or results; failed runs and interrupted tools remain queryable. session_recordings columns include id, session_id, user_id, anonymous_id, user_key, started_at, ended_at, duration_ms, chunk_count, event_count, page_count, error_count, rage_click_count, app, template, status, first_url, last_url, path, hostname, referrer, and metadata.",
|
|
19
19
|
schema: z.object({
|
|
20
20
|
sql: z
|
|
21
21
|
.string()
|
|
@@ -117,20 +117,29 @@ event_name = '$ai_sentiment'
|
|
|
117
117
|
|
|
118
118
|
Useful query fields live in `properties`:
|
|
119
119
|
|
|
120
|
-
| Property | Description
|
|
121
|
-
| ------------------------------------------------ |
|
|
122
|
-
| `$ai_trace_id`, `run_id` | Agent run id
|
|
123
|
-
| `$ai_session_id`, `thread_id` | Chat/thread id, when available
|
|
124
|
-
| `$ai_model`, `model` | Model used
|
|
125
|
-
| `$ai_provider`, `provider` | Engine/provider name
|
|
126
|
-
| `$ai_input_tokens`, `input_tokens` | Input tokens
|
|
127
|
-
| `$ai_output_tokens`, `output_tokens` | Output tokens
|
|
128
|
-
| `cache_read_tokens`, `cache_write_tokens` | Prompt-cache token counts
|
|
129
|
-
| `$ai_total_cost_usd`, `cost_usd` | Estimated run cost in USD
|
|
130
|
-
| `cost_cents_x100` | Estimated run cost in centicents
|
|
131
|
-
| `$ai_latency`, `duration_ms` | Run duration in seconds / milliseconds
|
|
132
|
-
| `tool_calls`, `successful_tools`, `failed_tools` |
|
|
133
|
-
|
|
|
120
|
+
| Property | Description |
|
|
121
|
+
| ------------------------------------------------ | ------------------------------------------------------------------------------------------------- |
|
|
122
|
+
| `$ai_trace_id`, `run_id` | Agent run id |
|
|
123
|
+
| `$ai_session_id`, `thread_id` | Chat/thread id, when available |
|
|
124
|
+
| `$ai_model`, `model` | Model used |
|
|
125
|
+
| `$ai_provider`, `provider` | Engine/provider name |
|
|
126
|
+
| `$ai_input_tokens`, `input_tokens` | Input tokens |
|
|
127
|
+
| `$ai_output_tokens`, `output_tokens` | Output tokens |
|
|
128
|
+
| `cache_read_tokens`, `cache_write_tokens` | Prompt-cache token counts |
|
|
129
|
+
| `$ai_total_cost_usd`, `cost_usd` | Estimated run cost in USD |
|
|
130
|
+
| `cost_cents_x100` | Estimated run cost in centicents |
|
|
131
|
+
| `$ai_latency`, `duration_ms` | Run duration in seconds / milliseconds |
|
|
132
|
+
| `tool_calls`, `successful_tools`, `failed_tools` | Complete tool-call counts |
|
|
133
|
+
| `tools`, `tools_truncated` | First 50 tool names, offsets, durations, statuses, and error classes, including interrupted calls |
|
|
134
|
+
| `delegated`, `delegation_protocol`, `caller_app` | Delegated-run attribution |
|
|
135
|
+
| `a2a_task_id`, `parent_run_id`, `parent_turn_id` | Cross-app trace linkage, when available |
|
|
136
|
+
| `$ai_is_error`, `status`, `$ai_error` | Error status and message, when applicable |
|
|
137
|
+
|
|
138
|
+
The `tools` array never includes tool arguments, results, or error messages.
|
|
139
|
+
Use `tools_truncated` with the complete `tool_calls` count when a run exceeds
|
|
140
|
+
the 50-entry detail cap.
|
|
141
|
+
Failed runs still emit a generation row with zero or known usage so delegated
|
|
142
|
+
timeouts and setup failures remain visible.
|
|
134
143
|
|
|
135
144
|
Explicit thumbs feedback is content-free and uses these `$ai_feedback`
|
|
136
145
|
properties:
|
|
@@ -29,7 +29,11 @@ Events tracked by application instrumentation and stored in the configured appli
|
|
|
29
29
|
`$ai_model`, `$ai_provider`, `$ai_input_tokens`, `$ai_output_tokens`,
|
|
30
30
|
`$ai_latency`, `$ai_total_cost_usd`, `run_id`, `thread_id`,
|
|
31
31
|
`cost_cents_x100`, `duration_ms`, `tool_calls`, `status`, and error fields.
|
|
32
|
-
|
|
32
|
+
A bounded `tools` array records only tool names, relative start times,
|
|
33
|
+
durations, statuses, and coarse error classes; interrupted tools and failed
|
|
34
|
+
runs remain visible, and `tools_truncated` marks runs above the 50-entry cap.
|
|
35
|
+
Delegated runs also include protocol, caller, task, parent-run, and
|
|
36
|
+
parent-turn linkage. Prompt, argument, result, and response content are excluded.
|
|
33
37
|
|
|
34
38
|
### Content Editing
|
|
35
39
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
claimAnalyticsAlertRuleEvaluation,
|
|
3
|
-
|
|
3
|
+
ensureDefaultAnalyticsAlertRules,
|
|
4
4
|
evaluateAndNotifyAnalyticsAlertRule,
|
|
5
5
|
listEnabledAnalyticsAlertRules,
|
|
6
6
|
markAnalyticsAlertRuleError,
|
|
@@ -45,8 +45,8 @@ export async function runAnalyticsAlertsOnce(
|
|
|
45
45
|
|
|
46
46
|
try {
|
|
47
47
|
const sweepLimit = maxRulesPerSweep(options.limit);
|
|
48
|
-
await
|
|
49
|
-
console.error("[analytics-alerts] Default
|
|
48
|
+
await ensureDefaultAnalyticsAlertRules().catch((err) => {
|
|
49
|
+
console.error("[analytics-alerts] Default alert seed failed:", err);
|
|
50
50
|
});
|
|
51
51
|
let rules: Awaited<ReturnType<typeof listEnabledAnalyticsAlertRules>>;
|
|
52
52
|
try {
|