@agent-native/core 0.133.3 → 0.134.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 +62 -0
- package/corpus/core/docs/content/observability.mdx +41 -1
- package/corpus/core/docs/content/template-content-developers.mdx +1 -1
- package/corpus/core/docs/content/tracking.mdx +25 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/agent/run-manager.ts +7 -0
- package/corpus/core/src/client/agent-chat-adapter.ts +10 -0
- package/corpus/core/src/client/analytics.ts +105 -1
- package/corpus/core/src/deploy/build.ts +38 -1
- package/corpus/core/src/observability/posthog-ai.ts +294 -0
- package/corpus/core/src/observability/routes.ts +29 -6
- package/corpus/core/src/observability/traces.ts +287 -12
- package/corpus/core/src/observability/types.ts +11 -0
- package/corpus/core/src/secrets/register-framework-secrets.ts +16 -0
- package/corpus/core/src/server/agent-run-context.ts +21 -0
- package/corpus/core/src/server/capture-error.ts +8 -0
- package/corpus/core/src/server/core-routes-plugin.ts +75 -4
- package/corpus/core/src/server/deploy-environment.ts +57 -0
- package/corpus/core/src/server/error-noise-filter.ts +268 -0
- package/corpus/core/src/server/posthog-config.ts +75 -0
- package/corpus/core/src/server/request-context.ts +6 -0
- package/corpus/core/src/server/sentry-config.ts +4 -8
- package/corpus/core/src/server/sentry-plugin.ts +13 -29
- package/corpus/core/src/server/sentry.ts +13 -156
- package/corpus/core/src/server/ssr-handler.ts +6 -1
- package/corpus/core/src/shared/mcp-embed-headers.ts +1 -1
- package/corpus/core/src/templates/workspace-core/.agents/skills/observability/SKILL.md +36 -10
- package/corpus/core/src/templates/workspace-core/.agents/skills/tracking/SKILL.md +55 -1
- package/corpus/core/src/tracking/error-capture.ts +44 -109
- package/corpus/core/src/tracking/index.ts +11 -0
- package/corpus/core/src/tracking/posthog-exception.ts +305 -0
- package/corpus/core/src/tracking/providers.ts +91 -14
- package/corpus/core/src/tracking/redaction.ts +105 -0
- package/corpus/templates/clips/changelog/2026-07-29-meeting-notes-no-longer-transcribe-the-other-side-twice-when.md +6 -0
- package/corpus/templates/clips/desktop/src/hooks/useMeetingTranscription.ts +37 -48
- package/corpus/templates/clips/desktop/src/lib/transcription-capture.ts +7 -5
- package/corpus/templates/clips/desktop/src/lib/transcription-engine.ts +182 -106
- package/corpus/templates/clips/desktop/src/overlays/live-transcript.tsx +43 -14
- package/corpus/templates/clips/desktop/src/overlays/recording-pill.tsx +3 -3
- package/corpus/templates/clips/desktop/src-tauri/src/echo_guard.rs +443 -0
- package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +1 -0
- package/corpus/templates/clips/desktop/src-tauri/src/whisper_speech.rs +125 -16
- package/corpus/templates/content/.agents/skills/document-editing/references/databases.md +6 -4
- package/corpus/templates/content/actions/_database-membership-lock.ts +25 -0
- package/corpus/templates/content/actions/_database-row-batch.ts +6 -2
- package/corpus/templates/content/actions/_database-source-utils.ts +289 -129
- package/corpus/templates/content/actions/_database-utils.ts +12 -3
- package/corpus/templates/content/actions/add-content-database-source-field-property.ts +39 -21
- package/corpus/templates/content/actions/attach-content-database-source.ts +4 -1
- package/corpus/templates/content/actions/change-content-database-source-role.ts +3 -5
- package/corpus/templates/content/actions/duplicate-document-property.ts +59 -46
- package/corpus/templates/content/actions/execute-builder-source-execution.ts +77 -71
- package/corpus/templates/content/actions/materialize-builder-required-fields.ts +7 -0
- package/corpus/templates/content/actions/remove-database-items.ts +183 -0
- package/corpus/templates/content/actions/set-document-property.ts +57 -39
- package/corpus/templates/content/actions/sync-local-folder-source.ts +7 -0
- package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +471 -329
- package/corpus/templates/content/app/components/editor/database/row-access.ts +45 -0
- package/corpus/templates/content/app/components/editor/database/shared.tsx +141 -38
- package/corpus/templates/content/app/hooks/use-content-database.ts +2 -2
- package/corpus/templates/content/app/i18n-data.ts +130 -0
- package/corpus/templates/content/changelog/2026-07-30-database-rows-can-now-be-removed-without-deleting-their-page.md +6 -0
- package/corpus/templates/content/parity/eval-scenarios.ts +2 -2
- package/corpus/templates/content/parity/matrix.md +1 -1
- package/corpus/templates/content/parity/matrix.ts +4 -5
- package/corpus/templates/content/shared/api.ts +4 -0
- package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +26 -11
- package/corpus/templates/design/actions/take-design-screenshot.ts +7 -0
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +11 -3
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +4 -1
- package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +54 -17
- package/corpus/templates/design/app/components/design/design-canvas/local-runtime.ts +126 -0
- package/corpus/templates/design/app/components/templates/TemplatePreview.tsx +2 -0
- package/corpus/templates/design/app/pages/Index.tsx +3 -1
- package/corpus/templates/design/app/pages/Present.tsx +2 -1
- package/corpus/templates/design/changelog/2026-07-30-a-broken-inline-script-in-a-generated-screen-is-now-caught-o.md +6 -0
- package/corpus/templates/design/changelog/2026-07-30-design-html-is-now-validated-with-a-spec-grade-html-parser-i.md +6 -0
- package/corpus/templates/design/changelog/2026-07-30-designs-now-load-their-tailwind-and-alpine-runtimes-from-the.md +6 -0
- package/corpus/templates/design/changelog/2026-07-30-designs-with-a-broken-alpine-expression-are-now-caught-on-sa.md +6 -0
- package/corpus/templates/design/changelog/2026-07-30-editing-a-design-no-longer-strips-its-styling-the-canvas-kep.md +6 -0
- package/corpus/templates/design/package.json +4 -0
- package/corpus/templates/design/shared/html-integrity.ts +802 -556
- package/dist/agent/run-manager.d.ts.map +1 -1
- package/dist/agent/run-manager.js +7 -0
- package/dist/agent/run-manager.js.map +1 -1
- package/dist/client/agent-chat-adapter.d.ts.map +1 -1
- package/dist/client/agent-chat-adapter.js +12 -0
- package/dist/client/agent-chat-adapter.js.map +1 -1
- package/dist/client/analytics.d.ts +8 -0
- package/dist/client/analytics.d.ts.map +1 -1
- package/dist/client/analytics.js +95 -1
- package/dist/client/analytics.js.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/deploy/build.d.ts.map +1 -1
- package/dist/deploy/build.js +38 -1
- package/dist/deploy/build.js.map +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/observability/posthog-ai.d.ts +126 -0
- package/dist/observability/posthog-ai.d.ts.map +1 -0
- package/dist/observability/posthog-ai.js +190 -0
- package/dist/observability/posthog-ai.js.map +1 -0
- package/dist/observability/routes.d.ts +3 -3
- package/dist/observability/routes.d.ts.map +1 -1
- package/dist/observability/routes.js +26 -6
- package/dist/observability/routes.js.map +1 -1
- package/dist/observability/traces.d.ts +9 -0
- package/dist/observability/traces.d.ts.map +1 -1
- package/dist/observability/traces.js +219 -10
- package/dist/observability/traces.js.map +1 -1
- package/dist/observability/types.d.ts +10 -0
- package/dist/observability/types.d.ts.map +1 -1
- package/dist/observability/types.js +1 -0
- package/dist/observability/types.js.map +1 -1
- package/dist/progress/routes.d.ts +1 -1
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/secrets/register-framework-secrets.d.ts.map +1 -1
- package/dist/secrets/register-framework-secrets.js +14 -0
- package/dist/secrets/register-framework-secrets.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/agent-run-context.d.ts +8 -0
- package/dist/server/agent-run-context.d.ts.map +1 -1
- package/dist/server/agent-run-context.js +18 -0
- package/dist/server/agent-run-context.js.map +1 -1
- package/dist/server/capture-error.d.ts +8 -0
- package/dist/server/capture-error.d.ts.map +1 -1
- package/dist/server/capture-error.js.map +1 -1
- package/dist/server/core-routes-plugin.d.ts +0 -23
- package/dist/server/core-routes-plugin.d.ts.map +1 -1
- package/dist/server/core-routes-plugin.js +71 -7
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/dist/server/deploy-environment.d.ts +17 -0
- package/dist/server/deploy-environment.d.ts.map +1 -0
- package/dist/server/deploy-environment.js +47 -0
- package/dist/server/deploy-environment.js.map +1 -0
- package/dist/server/error-noise-filter.d.ts +80 -0
- package/dist/server/error-noise-filter.d.ts.map +1 -0
- package/dist/server/error-noise-filter.js +173 -0
- package/dist/server/error-noise-filter.js.map +1 -0
- package/dist/server/posthog-config.d.ts +28 -0
- package/dist/server/posthog-config.d.ts.map +1 -0
- package/dist/server/posthog-config.js +53 -0
- package/dist/server/posthog-config.js.map +1 -0
- package/dist/server/request-context.d.ts +6 -0
- package/dist/server/request-context.d.ts.map +1 -1
- package/dist/server/request-context.js.map +1 -1
- package/dist/server/sentry-config.d.ts +1 -0
- package/dist/server/sentry-config.d.ts.map +1 -1
- package/dist/server/sentry-config.js +3 -1
- package/dist/server/sentry-config.js.map +1 -1
- package/dist/server/sentry-plugin.d.ts.map +1 -1
- package/dist/server/sentry-plugin.js +12 -27
- package/dist/server/sentry-plugin.js.map +1 -1
- package/dist/server/sentry.d.ts.map +1 -1
- package/dist/server/sentry.js +8 -124
- package/dist/server/sentry.js.map +1 -1
- package/dist/server/ssr-handler.d.ts.map +1 -1
- package/dist/server/ssr-handler.js +6 -1
- package/dist/server/ssr-handler.js.map +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/shared/mcp-embed-headers.d.ts +1 -1
- package/dist/shared/mcp-embed-headers.d.ts.map +1 -1
- package/dist/shared/mcp-embed-headers.js +1 -1
- package/dist/shared/mcp-embed-headers.js.map +1 -1
- package/dist/templates/workspace-core/.agents/skills/observability/SKILL.md +36 -10
- package/dist/templates/workspace-core/.agents/skills/tracking/SKILL.md +55 -1
- package/dist/tracking/error-capture.d.ts +7 -0
- package/dist/tracking/error-capture.d.ts.map +1 -1
- package/dist/tracking/error-capture.js +10 -73
- package/dist/tracking/error-capture.js.map +1 -1
- package/dist/tracking/index.d.ts +1 -0
- package/dist/tracking/index.d.ts.map +1 -1
- package/dist/tracking/index.js +1 -0
- package/dist/tracking/index.js.map +1 -1
- package/dist/tracking/posthog-exception.d.ts +103 -0
- package/dist/tracking/posthog-exception.d.ts.map +1 -0
- package/dist/tracking/posthog-exception.js +181 -0
- package/dist/tracking/posthog-exception.js.map +1 -0
- package/dist/tracking/providers.d.ts +14 -0
- package/dist/tracking/providers.d.ts.map +1 -1
- package/dist/tracking/providers.js +63 -11
- package/dist/tracking/providers.js.map +1 -1
- package/dist/tracking/redaction.d.ts +25 -0
- package/dist/tracking/redaction.d.ts.map +1 -0
- package/dist/tracking/redaction.js +85 -0
- package/dist/tracking/redaction.js.map +1 -0
- package/docs/content/observability.mdx +41 -1
- package/docs/content/template-content-developers.mdx +1 -1
- package/docs/content/tracking.mdx +25 -0
- package/package.json +1 -1
- package/src/agent/run-manager.ts +7 -0
- package/src/client/agent-chat-adapter.ts +10 -0
- package/src/client/analytics.ts +105 -1
- package/src/deploy/build.ts +38 -1
- package/src/observability/posthog-ai.ts +294 -0
- package/src/observability/routes.ts +29 -6
- package/src/observability/traces.ts +287 -12
- package/src/observability/types.ts +11 -0
- package/src/secrets/register-framework-secrets.ts +16 -0
- package/src/server/agent-run-context.ts +21 -0
- package/src/server/capture-error.ts +8 -0
- package/src/server/core-routes-plugin.ts +75 -4
- package/src/server/deploy-environment.ts +57 -0
- package/src/server/error-noise-filter.ts +268 -0
- package/src/server/posthog-config.ts +75 -0
- package/src/server/request-context.ts +6 -0
- package/src/server/sentry-config.ts +4 -8
- package/src/server/sentry-plugin.ts +13 -29
- package/src/server/sentry.ts +13 -156
- package/src/server/ssr-handler.ts +6 -1
- package/src/shared/mcp-embed-headers.ts +1 -1
- package/src/templates/workspace-core/.agents/skills/observability/SKILL.md +36 -10
- package/src/templates/workspace-core/.agents/skills/tracking/SKILL.md +55 -1
- package/src/tracking/error-capture.ts +44 -109
- package/src/tracking/index.ts +11 -0
- package/src/tracking/posthog-exception.ts +305 -0
- package/src/tracking/providers.ts +91 -14
- package/src/tracking/redaction.ts +105 -0
- package/corpus/templates/content/actions/delete-database-items.ts +0 -89
|
@@ -59,6 +59,15 @@ export declare function instrumentAgentLoop(opts: {
|
|
|
59
59
|
};
|
|
60
60
|
/** Raw user-authored message before prompt/context enrichment. */
|
|
61
61
|
sentimentInput?: string;
|
|
62
|
+
/**
|
|
63
|
+
* Browser session id of the request that started this run, when it came from
|
|
64
|
+
* a page. Emitted as PostHog's `$session_id` so agent traces join to session
|
|
65
|
+
* replay — distinct from `$ai_session_id`, which is the thread.
|
|
66
|
+
*
|
|
67
|
+
* Defaults to the in-flight request context, which the agent-chat route
|
|
68
|
+
* populates from the `X-Agent-Native-Session-Id` header.
|
|
69
|
+
*/
|
|
70
|
+
browserSessionId?: string;
|
|
62
71
|
classifyError?: (error: unknown) => {
|
|
63
72
|
status?: "success" | "error";
|
|
64
73
|
errorMessage?: string | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"traces.d.ts","sourceRoot":"","sources":["../../src/observability/traces.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,gBAAgB,EAChB,cAAc,EACf,MAAM,8BAA8B,CAAC;AACtC,OAAO,KAAK,EAAE,cAAc,EAAkB,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"traces.d.ts","sourceRoot":"","sources":["../../src/observability/traces.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { getRequestContext } from "../server/request-context.js";
|
|
2
|
+
import { MAX_AI_CONTENT_BYTES, MAX_AI_SPANS_PER_RUN, boundAiContent, emitAiSpanEvent, emitAiTraceEvent, toAiErrorDetail, } from "./posthog-ai.js";
|
|
1
3
|
import { endAgentSpan, startAgentSpan } from "./tracing.js";
|
|
2
4
|
import { trackingIdentityProperties } from "./tracking-identity.js";
|
|
3
5
|
import { DEFAULT_OBSERVABILITY_CONFIG } from "./types.js";
|
|
@@ -47,6 +49,13 @@ function emitLlmGenerationTrackingEvent(args) {
|
|
|
47
49
|
? args.inputTokens + args.outputTokens
|
|
48
50
|
: undefined;
|
|
49
51
|
const error = args.errorMessage ?? undefined;
|
|
52
|
+
const terminalCode = args.terminalOutcome?.state === "failed" ||
|
|
53
|
+
args.terminalOutcome?.state === "input_required"
|
|
54
|
+
? args.terminalOutcome.code
|
|
55
|
+
: undefined;
|
|
56
|
+
const terminalRetryable = args.terminalOutcome?.state === "failed"
|
|
57
|
+
? args.terminalOutcome.retryable
|
|
58
|
+
: undefined;
|
|
50
59
|
const properties = {
|
|
51
60
|
...trackingIdentityProperties(),
|
|
52
61
|
source: "agent_observability",
|
|
@@ -73,13 +82,8 @@ function emitLlmGenerationTrackingEvent(args) {
|
|
|
73
82
|
tools: args.tools,
|
|
74
83
|
tools_truncated: args.toolsTruncated,
|
|
75
84
|
terminal_state: args.terminalOutcome?.state,
|
|
76
|
-
terminal_code:
|
|
77
|
-
|
|
78
|
-
? args.terminalOutcome.code
|
|
79
|
-
: undefined,
|
|
80
|
-
terminal_retryable: args.terminalOutcome?.state === "failed"
|
|
81
|
-
? args.terminalOutcome.retryable
|
|
82
|
-
: undefined,
|
|
85
|
+
terminal_code: terminalCode,
|
|
86
|
+
terminal_retryable: terminalRetryable,
|
|
83
87
|
delegated: args.delegation ? true : undefined,
|
|
84
88
|
delegation_protocol: args.delegation?.protocol,
|
|
85
89
|
caller_app: args.delegation?.callerApp,
|
|
@@ -92,19 +96,35 @@ function emitLlmGenerationTrackingEvent(args) {
|
|
|
92
96
|
$ai_trace_id: args.runId,
|
|
93
97
|
$ai_session_id: args.threadId ?? undefined,
|
|
94
98
|
$ai_span_id: args.llmSpanId,
|
|
95
|
-
$ai_span_name:
|
|
96
|
-
|
|
99
|
+
$ai_span_name: args.model,
|
|
100
|
+
// Parent is the run's trace, not the internal `agent_run` span id — the
|
|
101
|
+
// latter is never emitted to PostHog, so pointing at it orphaned the
|
|
102
|
+
// generation and PostHog rendered a placeholder trace around it.
|
|
103
|
+
$ai_parent_id: args.runId,
|
|
97
104
|
$ai_model: args.model,
|
|
98
105
|
$ai_provider: provider,
|
|
99
106
|
$ai_input_tokens: args.inputTokens,
|
|
100
107
|
$ai_output_tokens: args.outputTokens,
|
|
101
108
|
$ai_latency: Math.round((args.durationMs / 1000) * 1000) / 1000,
|
|
102
109
|
$ai_is_error: args.status === "error",
|
|
103
|
-
$ai_error: error
|
|
110
|
+
$ai_error: args.status === "error"
|
|
111
|
+
? toAiErrorDetail(error, {
|
|
112
|
+
state: args.terminalOutcome?.state,
|
|
113
|
+
code: terminalCode,
|
|
114
|
+
retryable: terminalRetryable,
|
|
115
|
+
})
|
|
116
|
+
: undefined,
|
|
104
117
|
$ai_cache_read_input_tokens: args.cacheReadTokens,
|
|
105
118
|
$ai_cache_creation_input_tokens: args.cacheWriteTokens,
|
|
106
119
|
$ai_request_count: 1,
|
|
107
120
|
$ai_total_cost_usd: costUsd,
|
|
121
|
+
$ai_input: args.aiInput,
|
|
122
|
+
$ai_output_choices: args.aiOutputChoices,
|
|
123
|
+
$ai_tools: args.aiTools,
|
|
124
|
+
$ai_input_truncated: args.aiInputTruncated || undefined,
|
|
125
|
+
$ai_output_truncated: args.aiOutputTruncated || undefined,
|
|
126
|
+
$ai_time_to_first_token: args.firstTokenMs,
|
|
127
|
+
$session_id: args.browserSessionId,
|
|
108
128
|
};
|
|
109
129
|
if (args.experimentAssignments?.length) {
|
|
110
130
|
properties.experiment_ids = args.experimentAssignments
|
|
@@ -137,6 +157,75 @@ function emitLlmGenerationTrackingEvent(args) {
|
|
|
137
157
|
// Tracking must never affect the agent run or trace persistence.
|
|
138
158
|
}
|
|
139
159
|
}
|
|
160
|
+
/**
|
|
161
|
+
* Build the PostHog content fields for a run's `$ai_generation`.
|
|
162
|
+
*
|
|
163
|
+
* This is one generation per run carrying the run's whole message list, not one
|
|
164
|
+
* per model round-trip: the engine layer reports aggregate usage only
|
|
165
|
+
* (`onUsage`) and exposes no per-step hook. Consequence to know when reading a
|
|
166
|
+
* trace — per-round-trip latency and intermediate assistant turns are not
|
|
167
|
+
* visible; a multi-step run collapses into a single generation node.
|
|
168
|
+
*
|
|
169
|
+
* `$ai_output_choices` is emitted whenever tool calls happened even with
|
|
170
|
+
* `capturePrompts` off, because PostHog derives `$ai_tools_called` /
|
|
171
|
+
* `$ai_tool_call_count` from tool-call blocks inside it and nothing else. The
|
|
172
|
+
* assistant's text content stays gated; only the structural call list ships.
|
|
173
|
+
*/
|
|
174
|
+
function buildGenerationContent(args) {
|
|
175
|
+
const { config } = args;
|
|
176
|
+
const input = config.capturePrompts
|
|
177
|
+
? boundAiContent(redactSensitiveFields(args.messages))
|
|
178
|
+
: undefined;
|
|
179
|
+
const toolCalls = args.toolSpans
|
|
180
|
+
.slice(0, MAX_TRACKED_GENERATION_TOOL_CALLS)
|
|
181
|
+
.map((span) => ({
|
|
182
|
+
type: "function",
|
|
183
|
+
id: span.id,
|
|
184
|
+
function: {
|
|
185
|
+
name: span.name,
|
|
186
|
+
// Already redacted at span construction, and only present when
|
|
187
|
+
// `captureToolArgs` is on.
|
|
188
|
+
...(span.metadata?.input !== undefined
|
|
189
|
+
? { arguments: span.metadata.input }
|
|
190
|
+
: {}),
|
|
191
|
+
},
|
|
192
|
+
}));
|
|
193
|
+
const hasChoice = config.capturePrompts || toolCalls.length > 0;
|
|
194
|
+
const output = hasChoice
|
|
195
|
+
? boundAiContent([
|
|
196
|
+
{
|
|
197
|
+
role: "assistant",
|
|
198
|
+
...(config.capturePrompts
|
|
199
|
+
? { content: redactToolErrorMessage(args.assistantText) }
|
|
200
|
+
: {}),
|
|
201
|
+
...(toolCalls.length ? { tool_calls: toolCalls } : {}),
|
|
202
|
+
},
|
|
203
|
+
])
|
|
204
|
+
: undefined;
|
|
205
|
+
const toolList = Array.isArray(args.tools)
|
|
206
|
+
? args.tools
|
|
207
|
+
.filter((tool) => !!tool && typeof tool.name === "string")
|
|
208
|
+
.map((tool) => ({
|
|
209
|
+
type: "function",
|
|
210
|
+
function: {
|
|
211
|
+
name: tool.name,
|
|
212
|
+
...(typeof tool.description === "string"
|
|
213
|
+
? { description: tool.description }
|
|
214
|
+
: {}),
|
|
215
|
+
},
|
|
216
|
+
}))
|
|
217
|
+
: [];
|
|
218
|
+
return {
|
|
219
|
+
aiInput: input?.value,
|
|
220
|
+
aiOutputChoices: output?.value,
|
|
221
|
+
// Tool definitions are app configuration rather than user content, so they
|
|
222
|
+
// are not gated — without them a trace shows calls to tools nobody can
|
|
223
|
+
// identify. Schemas are excluded to keep the event small.
|
|
224
|
+
aiTools: toolList.length ? toolList : undefined,
|
|
225
|
+
aiInputTruncated: input?.truncated,
|
|
226
|
+
aiOutputTruncated: output?.truncated,
|
|
227
|
+
};
|
|
228
|
+
}
|
|
140
229
|
/** Keys whose values are stripped from persisted tool inputs when
|
|
141
230
|
* `captureToolArgs` is enabled. Matched case-insensitively and tolerant
|
|
142
231
|
* of `_` / `-` separators. M14 in the MCP/A2A audit: tool calls
|
|
@@ -198,6 +287,9 @@ export async function instrumentAgentLoop(opts) {
|
|
|
198
287
|
}))
|
|
199
288
|
.catch(() => null)
|
|
200
289
|
: Promise.resolve(null);
|
|
290
|
+
// Falls back to the in-flight request so callers deep in the agent stack
|
|
291
|
+
// don't have to thread it down by hand.
|
|
292
|
+
const browserSessionId = opts.browserSessionId ?? getRequestContext()?.browserSessionId;
|
|
201
293
|
// Optional OpenTelemetry root span for this run. No-ops unless a host has
|
|
202
294
|
// installed `@opentelemetry/api` and registered a provider. The promise is
|
|
203
295
|
// resolved before the loop runs so child tool/model spans can parent under
|
|
@@ -225,6 +317,10 @@ export async function instrumentAgentLoop(opts) {
|
|
|
225
317
|
const toolNameToCounters = new Map();
|
|
226
318
|
const toolCallIdToCounter = new Map();
|
|
227
319
|
const generationToolCalls = new Map();
|
|
320
|
+
// Assistant text, accumulated only when prompt capture is on so a disabled
|
|
321
|
+
// config never holds message content in memory in the first place.
|
|
322
|
+
const assistantTextParts = [];
|
|
323
|
+
let assistantTextLength = 0;
|
|
228
324
|
let toolCallCount = 0;
|
|
229
325
|
let successfulTools = 0;
|
|
230
326
|
let failedTools = 0;
|
|
@@ -266,6 +362,12 @@ export async function instrumentAgentLoop(opts) {
|
|
|
266
362
|
};
|
|
267
363
|
const instrumentedSend = (event) => {
|
|
268
364
|
try {
|
|
365
|
+
if (config.capturePrompts &&
|
|
366
|
+
event.type === "text" &&
|
|
367
|
+
assistantTextLength < MAX_AI_CONTENT_BYTES) {
|
|
368
|
+
assistantTextParts.push(event.text);
|
|
369
|
+
assistantTextLength += event.text.length;
|
|
370
|
+
}
|
|
269
371
|
// Some guardrails intentionally stop the loop by emitting a terminal
|
|
270
372
|
// event and returning usage instead of throwing. Preserve that terminal
|
|
271
373
|
// state in telemetry so a tripwire/loop-limit/provider error cannot be
|
|
@@ -552,6 +654,13 @@ export async function instrumentAgentLoop(opts) {
|
|
|
552
654
|
? Math.max(0, usage.firstEngineEventAtMs - runStart)
|
|
553
655
|
: undefined;
|
|
554
656
|
const llmSpanId = spanId();
|
|
657
|
+
const generationContent = buildGenerationContent({
|
|
658
|
+
config,
|
|
659
|
+
messages: loopOpts.messages,
|
|
660
|
+
tools: loopOpts.tools,
|
|
661
|
+
assistantText: assistantTextParts.join(""),
|
|
662
|
+
toolSpans: spans.filter((s) => s.spanType === "tool_call"),
|
|
663
|
+
});
|
|
555
664
|
const llmSpan = {
|
|
556
665
|
id: llmSpanId,
|
|
557
666
|
runId,
|
|
@@ -607,6 +716,8 @@ export async function instrumentAgentLoop(opts) {
|
|
|
607
716
|
createdAt: runStart,
|
|
608
717
|
experimentAssignments: opts.experimentAssignments,
|
|
609
718
|
modelSelectionSource: opts.modelSelectionSource,
|
|
719
|
+
browserSessionId,
|
|
720
|
+
...generationContent,
|
|
610
721
|
});
|
|
611
722
|
}
|
|
612
723
|
const parentSpan = {
|
|
@@ -629,6 +740,104 @@ export async function instrumentAgentLoop(opts) {
|
|
|
629
740
|
createdAt: runStart,
|
|
630
741
|
};
|
|
631
742
|
spans.push(parentSpan);
|
|
743
|
+
// PostHog LLM analytics: the run is a `$ai_trace`, each tool call an
|
|
744
|
+
// `$ai_span` under it. Emitted from the collected spans rather than from a
|
|
745
|
+
// second instrumentation pass, so the tree PostHog shows and the tree we
|
|
746
|
+
// persist cannot drift apart.
|
|
747
|
+
try {
|
|
748
|
+
const aiError = runStatus === "error"
|
|
749
|
+
? toAiErrorDetail(errorMessage, {
|
|
750
|
+
state: terminalOutcome?.state,
|
|
751
|
+
code: terminalOutcome?.state === "failed" ||
|
|
752
|
+
terminalOutcome?.state === "input_required"
|
|
753
|
+
? terminalOutcome.code
|
|
754
|
+
: undefined,
|
|
755
|
+
retryable: terminalOutcome?.state === "failed"
|
|
756
|
+
? terminalOutcome.retryable
|
|
757
|
+
: undefined,
|
|
758
|
+
})
|
|
759
|
+
: undefined;
|
|
760
|
+
const provider = llmProviderFromEngine(typeof loopOpts.engine?.name === "string"
|
|
761
|
+
? loopOpts.engine.name
|
|
762
|
+
: undefined, usage?.model ?? loopOpts.model);
|
|
763
|
+
const toolSpans = config.captureLlmSpans
|
|
764
|
+
? spans.filter((s) => s.spanType === "tool_call")
|
|
765
|
+
: [];
|
|
766
|
+
const emittedToolSpans = toolSpans.slice(0, MAX_AI_SPANS_PER_RUN);
|
|
767
|
+
const droppedToolSpans = toolSpans.length - emittedToolSpans.length;
|
|
768
|
+
emitAiTraceEvent({
|
|
769
|
+
runId,
|
|
770
|
+
threadId,
|
|
771
|
+
userId,
|
|
772
|
+
spanName: "agent_run",
|
|
773
|
+
model: usage?.model ?? loopOpts.model,
|
|
774
|
+
provider,
|
|
775
|
+
latencySeconds: Math.round(totalDurationMs) / 1000,
|
|
776
|
+
isError: runStatus === "error",
|
|
777
|
+
error: aiError,
|
|
778
|
+
inputTokens: usage?.usageReported ? usage.inputTokens : undefined,
|
|
779
|
+
outputTokens: usage?.usageReported ? usage.outputTokens : undefined,
|
|
780
|
+
costUsd: usage?.usageReported
|
|
781
|
+
? costUsdFromCenticents(costCentsX100)
|
|
782
|
+
: undefined,
|
|
783
|
+
createdAt: runStart,
|
|
784
|
+
browserSessionId,
|
|
785
|
+
extraProperties: {
|
|
786
|
+
...trackingIdentityProperties(),
|
|
787
|
+
source: "agent_observability",
|
|
788
|
+
run_id: runId,
|
|
789
|
+
thread_id: threadId,
|
|
790
|
+
// A truncated run must not read as a complete one.
|
|
791
|
+
...(droppedToolSpans > 0
|
|
792
|
+
? {
|
|
793
|
+
$ai_spans_dropped: droppedToolSpans,
|
|
794
|
+
$ai_spans_emitted: emittedToolSpans.length,
|
|
795
|
+
}
|
|
796
|
+
: {}),
|
|
797
|
+
},
|
|
798
|
+
});
|
|
799
|
+
for (const span of emittedToolSpans) {
|
|
800
|
+
// `span.errorMessage` is the raw tool result. It routinely contains
|
|
801
|
+
// upstream response bodies with Authorization headers and standalone
|
|
802
|
+
// API keys, so it gets the same redaction + bounding the generation
|
|
803
|
+
// event's `tools[].error_message` already applies, and the same
|
|
804
|
+
// `captureToolResults` gate — exporting it here otherwise reintroduced
|
|
805
|
+
// the leak that gate exists to prevent. `$ai_is_error` still marks the
|
|
806
|
+
// failure when the content is withheld.
|
|
807
|
+
const toolErrorMessage = span.status === "error" &&
|
|
808
|
+
span.errorMessage &&
|
|
809
|
+
config.captureToolResults
|
|
810
|
+
? truncateToolErrorMessage(redactToolErrorMessage(span.errorMessage))
|
|
811
|
+
: undefined;
|
|
812
|
+
emitAiSpanEvent({
|
|
813
|
+
runId,
|
|
814
|
+
threadId,
|
|
815
|
+
userId,
|
|
816
|
+
spanId: span.id,
|
|
817
|
+
spanName: span.name,
|
|
818
|
+
latencySeconds: Math.round(span.durationMs) / 1000,
|
|
819
|
+
isError: span.status === "error",
|
|
820
|
+
error: toolErrorMessage
|
|
821
|
+
? toAiErrorDetail(toolErrorMessage)
|
|
822
|
+
: undefined,
|
|
823
|
+
createdAt: span.createdAt,
|
|
824
|
+
browserSessionId,
|
|
825
|
+
// `metadata.input` is already redacted and only present when
|
|
826
|
+
// `captureToolArgs` is on; absent stays absent.
|
|
827
|
+
inputState: span.metadata?.input,
|
|
828
|
+
outputState: toolErrorMessage,
|
|
829
|
+
extraProperties: {
|
|
830
|
+
...trackingIdentityProperties(),
|
|
831
|
+
source: "agent_observability",
|
|
832
|
+
span_type: "tool_call",
|
|
833
|
+
},
|
|
834
|
+
});
|
|
835
|
+
}
|
|
836
|
+
// coercion-ok: a throw here would skip trace persistence below
|
|
837
|
+
}
|
|
838
|
+
catch {
|
|
839
|
+
// LLM analytics must never affect the run or trace persistence.
|
|
840
|
+
}
|
|
632
841
|
const summary = {
|
|
633
842
|
runId,
|
|
634
843
|
threadId,
|