@agent-native/core 0.136.0 → 0.136.3

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 (120) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/analytics/.agents/skills/analysis-workspace/SKILL.md +31 -5
  3. package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +7 -0
  4. package/corpus/templates/analytics/.agents/skills/gong/SKILL.md +52 -19
  5. package/corpus/templates/analytics/.agents/skills/provider-api/SKILL.md +25 -3
  6. package/corpus/templates/analytics/AGENTS.md +6 -7
  7. package/corpus/templates/analytics/actions/gong-calls.ts +3 -3
  8. package/corpus/templates/analytics/actions/provider-api-catalog.ts +1 -1
  9. package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +1 -1
  10. package/corpus/templates/analytics/app/i18n-data.ts +46 -0
  11. package/corpus/templates/analytics/app/pages/Settings.tsx +67 -1
  12. package/corpus/templates/analytics/app/pages/settings/settings-search.ts +6 -0
  13. package/corpus/templates/analytics/changelog/2026-08-03-dashboard-builds-now-finish-without-an-extra-confirmation.md +6 -0
  14. package/corpus/templates/analytics/changelog/2026-08-03-error-alert-emails-are-opt-in.md +6 -0
  15. package/corpus/templates/analytics/server/lib/agent-chat-plan-mode.ts +10 -9
  16. package/corpus/templates/analytics/server/lib/error-capture.ts +38 -10
  17. package/corpus/templates/analytics/server/lib/gong.ts +27 -4
  18. package/corpus/templates/analytics/server/plugins/agent-chat.ts +64 -4
  19. package/corpus/templates/analytics/shared/analytics-user-prefs.ts +7 -0
  20. package/corpus/templates/clips/.agents/skills/video-sharing/SKILL.md +15 -6
  21. package/corpus/templates/clips/actions/apply-rewind-extension.ts +9 -0
  22. package/corpus/templates/clips/actions/cleanup-dictation.ts +2 -2
  23. package/corpus/templates/clips/actions/cleanup-transcript.ts +8 -11
  24. package/corpus/templates/clips/actions/clear-edits.ts +15 -2
  25. package/corpus/templates/clips/actions/create-recording-agent-link.ts +10 -0
  26. package/corpus/templates/clips/actions/finalize-meeting.ts +6 -6
  27. package/corpus/templates/clips/actions/finalize-recording.ts +33 -8
  28. package/corpus/templates/clips/actions/lib/ensure-seekable-video.ts +1 -3
  29. package/corpus/templates/clips/actions/list-recordings.ts +39 -24
  30. package/corpus/templates/clips/actions/list-transactional-email-ai-requests.ts +4 -1
  31. package/corpus/templates/clips/actions/regenerate-title.ts +2 -2
  32. package/corpus/templates/clips/actions/stitch-recordings.ts +36 -7
  33. package/corpus/templates/clips/app/components/editor/rewind-extension-dialog.tsx +1 -4
  34. package/corpus/templates/clips/app/components/editor/stitch-manager.tsx +3 -1
  35. package/corpus/templates/clips/app/components/library/recording-card.tsx +9 -0
  36. package/corpus/templates/clips/app/components/player/recording-views-badge.tsx +52 -7
  37. package/corpus/templates/clips/app/hooks/use-library.ts +1 -0
  38. package/corpus/templates/clips/app/hooks/use-transactional-email-bridge.ts +17 -10
  39. package/corpus/templates/clips/app/i18n/en-US.ts +3 -0
  40. package/corpus/templates/clips/app/lib/timestamp-mapping.ts +5 -0
  41. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +1 -0
  42. package/corpus/templates/clips/app/routes/share.$shareId.tsx +2 -0
  43. package/corpus/templates/clips/changelog/2026-07-31-agent-views-now-show-the-agent-s-name-from-the-link-it-was-g.md +6 -0
  44. package/corpus/templates/clips/changelog/2026-07-31-clip-cards-and-the-watch-share-page-header-now-show-agent-vi.md +6 -0
  45. package/corpus/templates/clips/changelog/2026-08-01-recordings-stored-in-private-s3-compatible-buckets-finalize-.md +6 -0
  46. package/corpus/templates/clips/changelog/2026-08-03-clip-cleanup-titles-and-meeting-summaries-now-use-luna-by-de.md +6 -0
  47. package/corpus/templates/clips/changelog/2026-08-03-get-a-monthly-recap-email-showing-how-many-people-and-ai-age.md +6 -0
  48. package/corpus/templates/clips/changelog/2026-08-03-get-an-email-the-first-time-an-ai-agent-reads-one-of-your-cl.md +6 -0
  49. package/corpus/templates/clips/learnings.defaults.md +2 -2
  50. package/corpus/templates/clips/package.json +1 -1
  51. package/corpus/templates/clips/scripts/send-real-recap.ts +165 -0
  52. package/corpus/templates/clips/scripts/send-test-emails.ts +60 -0
  53. package/corpus/templates/clips/server/db/schema.ts +4 -0
  54. package/corpus/templates/clips/server/jobs/transactional-emails.ts +256 -0
  55. package/corpus/templates/clips/server/lib/agent-views.ts +38 -11
  56. package/corpus/templates/clips/server/lib/media-storage-provenance.ts +16 -0
  57. package/corpus/templates/clips/server/lib/public-agent-context.ts +3 -1
  58. package/corpus/templates/clips/server/lib/recap-metrics.ts +373 -0
  59. package/corpus/templates/clips/server/lib/s3-upload-provider.ts +84 -4
  60. package/corpus/templates/clips/server/lib/transactional-email-store.ts +41 -2
  61. package/corpus/templates/clips/server/lib/transactional-email-templates.ts +245 -3
  62. package/corpus/templates/clips/server/plugins/db.ts +16 -0
  63. package/corpus/templates/clips/server/register-secrets.ts +2 -2
  64. package/corpus/templates/clips/server/routes/api/public-recording.get.ts +7 -2
  65. package/corpus/templates/clips/server/routes/api/video/[recordingId].get.ts +42 -1
  66. package/corpus/templates/design/actions/take-design-screenshot.ts +5 -3
  67. package/corpus/templates/design/package.json +1 -1
  68. package/corpus/templates/design/server/lib/playwright-runtime.ts +13 -5
  69. package/corpus/templates/mail/actions/get-automation-settings.ts +4 -12
  70. package/corpus/templates/mail/app/pages/SettingsPage.tsx +1 -1
  71. package/corpus/templates/mail/changelog/2026-08-03-inbox-automations-now-prefer-the-lowest-cost-luna-model-when.md +6 -0
  72. package/corpus/templates/mail/server/lib/automation-engine.ts +19 -14
  73. package/corpus/templates/mail/server/lib/automation-model.ts +110 -0
  74. package/corpus/templates/mail/server/plugins/agent-chat.ts +1 -1
  75. package/corpus/templates/slides/actions/generate-slides-ai.ts +92 -24
  76. package/corpus/templates/slides/changelog/2026-08-03-legacy-slide-outlines-now-prefer-the-lowest-cost-luna-model-.md +6 -0
  77. package/corpus/templates/tasks/package.json +2 -2
  78. package/dist/agent/production-agent.d.ts +2 -2
  79. package/dist/agent/production-agent.js +1 -1
  80. package/dist/catalog.json +2 -0
  81. package/dist/client/AgentTaskCard.js +4 -2
  82. package/dist/client/i18n.js +3 -0
  83. package/dist/client/settings/VoiceTranscriptionSection.js +2 -2
  84. package/dist/collab/awareness.d.ts +2 -2
  85. package/dist/collab/routes.d.ts +1 -1
  86. package/dist/collab/struct-routes.d.ts +1 -1
  87. package/dist/localization/default-messages.d.ts +5 -0
  88. package/dist/localization/default-messages.js +5 -0
  89. package/dist/mcp/oauth-client-metadata.d.ts +7 -0
  90. package/dist/mcp/oauth-client-metadata.js +47 -0
  91. package/dist/mcp/oauth-route.js +7 -3
  92. package/dist/mcp/oauth-store.d.ts +2 -0
  93. package/dist/mcp/oauth-store.js +25 -3
  94. package/dist/notifications/routes.d.ts +1 -1
  95. package/dist/observability/routes.d.ts +3 -3
  96. package/dist/observability/traces.d.ts +1 -1
  97. package/dist/observability/traces.js +2 -1
  98. package/dist/progress/routes.d.ts +1 -1
  99. package/dist/provider-api/index.js +29 -1
  100. package/dist/secrets/routes.d.ts +6 -6
  101. package/dist/server/agent-access.d.ts +3 -1
  102. package/dist/server/agent-access.js +2 -1
  103. package/dist/server/agent-chat/browser-team-tools.d.ts +1 -0
  104. package/dist/server/agent-chat/browser-team-tools.js +5 -4
  105. package/dist/server/agent-chat/context-tools.js +2 -2
  106. package/dist/server/agent-chat-plugin.js +13 -6
  107. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  108. package/dist/server/agent-teams-run-queue.d.ts +2 -0
  109. package/dist/server/agent-teams.d.ts +2 -0
  110. package/dist/server/agent-teams.js +45 -2
  111. package/dist/server/request-context.d.ts +2 -0
  112. package/dist/server/short-lived-token.d.ts +7 -0
  113. package/dist/server/short-lived-token.js +7 -1
  114. package/dist/server/ssr-handler.js +19 -1
  115. package/dist/server/transcribe-voice.d.ts +1 -1
  116. package/dist/server/transcribe-voice.js +24 -16
  117. package/dist/vite/client.d.ts +37 -1
  118. package/dist/vite/client.js +110 -1
  119. package/docs/content/template-assets.mdx +14 -4
  120. package/package.json +3 -4
@@ -26,6 +26,7 @@ export interface OAuthClientRow {
26
26
  grantTypes: string[];
27
27
  responseTypes: string[];
28
28
  tokenEndpointAuthMethod: string;
29
+ applicationType: "native" | "web";
29
30
  createdAt: number | null;
30
31
  }
31
32
  export interface OAuthCodeRow {
@@ -66,6 +67,7 @@ export declare function registerOAuthClient(params: {
66
67
  grantTypes?: string[];
67
68
  responseTypes?: string[];
68
69
  tokenEndpointAuthMethod?: string;
70
+ applicationType?: "native" | "web";
69
71
  }): Promise<OAuthClientRow>;
70
72
  export declare function getOAuthClient(clientId: string): Promise<OAuthClientRow | null>;
71
73
  export declare function createOAuthCode(params: {
@@ -7,7 +7,8 @@
7
7
  */
8
8
  import { randomBytes, randomUUID, createHash } from "node:crypto";
9
9
  import { getDbExec, isConnectionError, intType, isPostgres, } from "../db/client.js";
10
- import { ensureTableExists } from "../db/ddl-guard.js";
10
+ import { ensureColumnExists, ensureTableExists } from "../db/ddl-guard.js";
11
+ import { applicationTypeForRedirectUris } from "./oauth-client-metadata.js";
11
12
  let _initPromise;
12
13
  export const MCP_OAUTH_CODE_TTL_MS = 10 * 60_000;
13
14
  /**
@@ -76,6 +77,7 @@ async function ensureTable() {
76
77
  grant_types TEXT,
77
78
  response_types TEXT,
78
79
  token_endpoint_auth_method TEXT,
80
+ application_type TEXT,
79
81
  created_at ${intType()}
80
82
  )
81
83
  `;
@@ -118,6 +120,7 @@ async function ensureTable() {
118
120
  // DDL when the table is actually missing, wrapped in a
119
121
  // transaction-scoped lock_timeout so a contended lock fails fast.
120
122
  await ensureTableExists("mcp_oauth_clients", createClientsSql);
123
+ await ensureColumnExists("mcp_oauth_clients", "application_type", `ALTER TABLE mcp_oauth_clients ADD COLUMN IF NOT EXISTS application_type TEXT`);
121
124
  await ensureTableExists("mcp_oauth_codes", createCodesSql);
122
125
  await ensureTableExists("mcp_oauth_refresh_tokens", createRefreshTokensSql);
123
126
  return;
@@ -125,6 +128,17 @@ async function ensureTable() {
125
128
  // SQLite (local dev): no ACCESS EXCLUSIVE lock problem — keep existing
126
129
  // create-then-execute behaviour.
127
130
  await client.execute(createClientsSql);
131
+ try {
132
+ await client.execute(`ALTER TABLE mcp_oauth_clients ADD COLUMN IF NOT EXISTS application_type TEXT`);
133
+ }
134
+ catch {
135
+ try {
136
+ await client.execute(`ALTER TABLE mcp_oauth_clients ADD COLUMN application_type TEXT`);
137
+ }
138
+ catch {
139
+ // Fresh and previously migrated databases already have the column.
140
+ }
141
+ }
128
142
  await client.execute(createCodesSql);
129
143
  await client.execute(createRefreshTokensSql);
130
144
  })().catch((err) => {
@@ -160,16 +174,21 @@ function numOrNull(v) {
160
174
  return Number.isFinite(n) ? n : null;
161
175
  }
162
176
  function mapClientRow(row) {
177
+ const redirectUris = parseJsonStringArray(row.redirect_uris ?? row.redirectUris);
178
+ const storedApplicationType = row.application_type ?? row.applicationType;
163
179
  return {
164
180
  clientId: row.client_id ?? row.clientId,
165
181
  clientName: row.client_name ?? row.clientName ?? null,
166
- redirectUris: parseJsonStringArray(row.redirect_uris ?? row.redirectUris),
182
+ redirectUris,
167
183
  grantTypes: parseJsonStringArray(row.grant_types ?? row.grantTypes, [
168
184
  "authorization_code",
169
185
  "refresh_token",
170
186
  ]),
171
187
  responseTypes: parseJsonStringArray(row.response_types ?? row.responseTypes, ["code"]),
172
188
  tokenEndpointAuthMethod: row.token_endpoint_auth_method ?? row.tokenEndpointAuthMethod ?? "none",
189
+ applicationType: storedApplicationType === "native" || storedApplicationType === "web"
190
+ ? storedApplicationType
191
+ : applicationTypeForRedirectUris(redirectUris),
173
192
  createdAt: numOrNull(row.created_at ?? row.createdAt),
174
193
  };
175
194
  }
@@ -235,8 +254,9 @@ export async function registerOAuthClient(params) {
235
254
  ? params.responseTypes
236
255
  : ["code"];
237
256
  const tokenEndpointAuthMethod = params.tokenEndpointAuthMethod || "none";
257
+ const applicationType = params.applicationType ?? "web";
238
258
  await client.execute({
239
- sql: `INSERT INTO mcp_oauth_clients (client_id, client_name, redirect_uris, grant_types, response_types, token_endpoint_auth_method, created_at) VALUES (?, ?, ?, ?, ?, ?, ?)`,
259
+ sql: `INSERT INTO mcp_oauth_clients (client_id, client_name, redirect_uris, grant_types, response_types, token_endpoint_auth_method, application_type, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
240
260
  args: [
241
261
  clientId,
242
262
  params.clientName ?? null,
@@ -244,6 +264,7 @@ export async function registerOAuthClient(params) {
244
264
  JSON.stringify(grantTypes),
245
265
  JSON.stringify(responseTypes),
246
266
  tokenEndpointAuthMethod,
267
+ applicationType,
247
268
  now,
248
269
  ],
249
270
  });
@@ -254,6 +275,7 @@ export async function registerOAuthClient(params) {
254
275
  grantTypes,
255
276
  responseTypes,
256
277
  tokenEndpointAuthMethod,
278
+ applicationType,
257
279
  createdAt: now,
258
280
  };
259
281
  }
@@ -28,7 +28,7 @@ export declare function createNotificationsHandler(): import("h3").EventHandlerW
28
28
  } | {
29
29
  count?: undefined;
30
30
  updated?: undefined;
31
- ok: boolean;
32
31
  error?: undefined;
32
+ ok: boolean;
33
33
  }>>;
34
34
  //# sourceMappingURL=routes.d.ts.map
@@ -41,16 +41,16 @@ export declare function createObservabilityHandler(): import("h3").EventHandlerW
41
41
  thumbsUpRate: number;
42
42
  avgEvalScore: number;
43
43
  } | {
44
+ error?: undefined;
44
45
  summary: import("./types.js").TraceSummary;
45
46
  spans: import("./types.js").TraceSpan[];
46
47
  id?: undefined;
47
- error?: undefined;
48
48
  ok?: undefined;
49
49
  } | {
50
+ error?: undefined;
50
51
  summary?: undefined;
51
52
  spans?: undefined;
52
53
  id: string;
53
- error?: undefined;
54
54
  ok?: undefined;
55
55
  } | {
56
56
  summary?: undefined;
@@ -59,10 +59,10 @@ export declare function createObservabilityHandler(): import("h3").EventHandlerW
59
59
  error: any;
60
60
  ok?: undefined;
61
61
  } | {
62
+ error?: undefined;
62
63
  summary?: undefined;
63
64
  spans?: undefined;
64
65
  id?: undefined;
65
- error?: undefined;
66
66
  ok: boolean;
67
67
  }>>;
68
68
  //# sourceMappingURL=routes.d.ts.map
@@ -51,7 +51,7 @@ export declare function instrumentAgentLoop(opts: {
51
51
  }>;
52
52
  modelSelectionSource?: string;
53
53
  delegation?: {
54
- protocol: "a2a" | "mcp";
54
+ protocol: "a2a" | "mcp" | "agent-team";
55
55
  callerApp?: string;
56
56
  taskId?: string;
57
57
  parentRunId?: string;
@@ -87,7 +87,8 @@ function emitLlmGenerationTrackingEvent(args) {
87
87
  delegated: args.delegation ? true : undefined,
88
88
  delegation_protocol: args.delegation?.protocol,
89
89
  caller_app: args.delegation?.callerApp,
90
- a2a_task_id: args.delegation?.taskId,
90
+ delegation_task_id: args.delegation?.taskId,
91
+ a2a_task_id: args.delegation?.protocol === "a2a" ? args.delegation.taskId : undefined,
91
92
  parent_run_id: args.delegation?.parentRunId,
92
93
  parent_turn_id: args.delegation?.parentTurnId,
93
94
  model_selection_source: args.modelSelectionSource,
@@ -15,7 +15,7 @@ export declare function createProgressHandler(): import("h3").EventHandlerWithFe
15
15
  error: string;
16
16
  ok?: undefined;
17
17
  } | {
18
- ok: boolean;
19
18
  error?: undefined;
19
+ ok: boolean;
20
20
  }>>;
21
21
  //# sourceMappingURL=routes.d.ts.map
@@ -462,9 +462,37 @@ const PROVIDER_CONFIGS = {
462
462
  ],
463
463
  notes: [
464
464
  "For broad corpus work, call /calls/extensive with provider-api-request and stageAs/saveToFile. Gong returns the next cursor at records.cursor and expects the next cursor in the POST body at cursor, so use pagination { nextCursorPath: 'records.cursor', cursorBodyPath: 'cursor' } for stageAs or fetchAllPages { cursorPath: 'records.cursor', cursorBodyPath: 'cursor' } for saveToFile.",
465
- "Batch transcripts with POST /calls/transcript and body { filter: { callIds: [...] } } after narrowing or staging call ids.",
465
+ "The public Gong REST API does not expose an arbitrary transcript-text filter. Use configured keyword tracker results from /calls/extensive when they cover the requested term; otherwise batch transcripts with POST /calls/transcript and body { filter: { callIds: [...] } } after narrowing or staging call ids.",
466
466
  ],
467
467
  corpusRecipes: [
468
+ {
469
+ label: "Stage Gong calls with configured keyword tracker hits",
470
+ useWhen: "Use when the requested term or phrase already exists as a Gong keyword tracker and the answer can use tracker matches instead of arbitrary transcript-text search.",
471
+ workflow: [
472
+ "Call /calls/extensive with the narrowest date, workspace, or owner filters available and contentSelector.exposedFields.content.trackers = true.",
473
+ "Stage the calls pages with provider-api-request stageAs or saveToFile; use the POST-body cursor at records.cursor for complete pagination.",
474
+ "Use query-staged-dataset or a Data Program to flatten content.trackers, filter by tracker id/name/phrase, and aggregate counts or occurrences.",
475
+ "Tracker results are provider-indexed evidence for configured trackers, not an arbitrary transcript search. For an unconfigured term, use Gong native Search when connected or the transcript batch recipe below.",
476
+ ],
477
+ request: {
478
+ method: "POST",
479
+ path: "/calls/extensive",
480
+ body: {
481
+ filter: { fromDateTime: "<iso-date-time>" },
482
+ contentSelector: {
483
+ exposedFields: {
484
+ content: { trackers: true, trackerOccurrences: true },
485
+ },
486
+ },
487
+ },
488
+ },
489
+ pagination: {
490
+ itemsPath: "calls",
491
+ nextCursorPath: "records.cursor",
492
+ cursorBodyPath: "cursor",
493
+ maxPages: 200,
494
+ },
495
+ },
468
496
  {
469
497
  label: "Batch-search Gong call transcripts from staged call ids",
470
498
  useWhen: "Use when the user asks to search, count, or prove absence across Gong transcript text for a bounded cohort of call ids.",
@@ -37,17 +37,17 @@ export declare function createWriteSecretHandler(): import("h3").EventHandlerWit
37
37
  status?: undefined;
38
38
  ok?: undefined;
39
39
  } | {
40
+ error?: undefined;
40
41
  ok: boolean;
41
42
  status: string;
42
- error?: undefined;
43
43
  } | {
44
44
  error: string;
45
45
  removed?: undefined;
46
46
  ok?: undefined;
47
47
  } | {
48
+ error?: undefined;
48
49
  ok: boolean;
49
50
  removed: boolean;
50
- error?: undefined;
51
51
  }>>;
52
52
  /**
53
53
  * POST /_agent-native/secrets/:key/test — re-run the validator against the
@@ -58,13 +58,13 @@ export declare function createTestSecretHandler(): import("h3").EventHandlerWith
58
58
  note?: undefined;
59
59
  ok?: undefined;
60
60
  } | {
61
+ error?: undefined;
61
62
  ok: boolean;
62
63
  note?: undefined;
63
- error?: undefined;
64
64
  } | {
65
+ error?: undefined;
65
66
  ok: boolean;
66
67
  note: string;
67
- error?: undefined;
68
68
  } | {
69
69
  note?: undefined;
70
70
  ok: boolean;
@@ -95,12 +95,12 @@ export interface AdHocSecretPayload {
95
95
  export declare function createAdHocSecretHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<AdHocSecretPayload[] | {
96
96
  error: string;
97
97
  } | {
98
+ error?: undefined;
98
99
  ok: boolean;
99
100
  key: string;
100
- error?: undefined;
101
101
  } | {
102
+ error?: undefined;
102
103
  ok: boolean;
103
104
  removed: boolean;
104
- error?: undefined;
105
105
  }>>;
106
106
  //# sourceMappingURL=routes.d.ts.map
@@ -3,6 +3,8 @@ import { type VerifyResult } from "./short-lived-token.js";
3
3
  export { AGENT_ACCESS_PARAM, DEFAULT_AGENT_ACCESS_TTL_SECONDS, appendAgentAccessParam, buildAgentAccessApiUrl, buildAgentAccessUrl, normalizeAgentAccessBasePath, normalizeAgentAccessOrigin, scopedAgentAccessResourceId, toAgentAccessUrl, type AgentAccessApiUrlOptions, type AgentAccessResourceScope, type AgentAccessUrlOptions, } from "../shared/agent-access.js";
4
4
  export interface ScopedAgentAccessTokenOptions extends AgentAccessResourceScope {
5
5
  viewerEmail?: string;
6
+ /** Display name of the agent the link is for. Signed, but display-only. */
7
+ agentLabel?: string;
6
8
  ttlSeconds?: number;
7
9
  }
8
10
  export interface ScopedAgentAccessGrant {
@@ -10,7 +12,7 @@ export interface ScopedAgentAccessGrant {
10
12
  expiresAt: string;
11
13
  ttlSeconds: number;
12
14
  }
13
- export declare function signScopedAgentAccessToken({ resourceKind, resourceId, viewerEmail, ttlSeconds, }: ScopedAgentAccessTokenOptions): string;
15
+ export declare function signScopedAgentAccessToken({ resourceKind, resourceId, viewerEmail, agentLabel, ttlSeconds, }: ScopedAgentAccessTokenOptions): string;
14
16
  export declare function verifyScopedAgentAccessToken(token: string, scope: AgentAccessResourceScope): VerifyResult;
15
17
  export declare function createScopedAgentAccessGrant(options: ScopedAgentAccessTokenOptions): ScopedAgentAccessGrant;
16
18
  //# sourceMappingURL=agent-access.d.ts.map
@@ -1,10 +1,11 @@
1
1
  import { DEFAULT_AGENT_ACCESS_TTL_SECONDS, scopedAgentAccessResourceId, } from "../shared/agent-access.js";
2
2
  import { signShortLivedToken, verifyShortLivedToken, } from "./short-lived-token.js";
3
3
  export { AGENT_ACCESS_PARAM, DEFAULT_AGENT_ACCESS_TTL_SECONDS, appendAgentAccessParam, buildAgentAccessApiUrl, buildAgentAccessUrl, normalizeAgentAccessBasePath, normalizeAgentAccessOrigin, scopedAgentAccessResourceId, toAgentAccessUrl, } from "../shared/agent-access.js";
4
- export function signScopedAgentAccessToken({ resourceKind, resourceId, viewerEmail, ttlSeconds = DEFAULT_AGENT_ACCESS_TTL_SECONDS, }) {
4
+ export function signScopedAgentAccessToken({ resourceKind, resourceId, viewerEmail, agentLabel, ttlSeconds = DEFAULT_AGENT_ACCESS_TTL_SECONDS, }) {
5
5
  return signShortLivedToken({
6
6
  resourceId: scopedAgentAccessResourceId(resourceKind, resourceId),
7
7
  viewerEmail,
8
+ agentLabel,
8
9
  ttlSeconds,
9
10
  });
10
11
  }
@@ -16,6 +16,7 @@ export declare function createTeamTools(deps: {
16
16
  getEngine: () => AgentEngine;
17
17
  getModel: () => string;
18
18
  getParentThreadId: () => string;
19
+ getParentRunId?: () => string;
19
20
  getSend: () => ((event: import("../../agent/types.js").AgentChatEvent) => void) | null;
20
21
  }): Record<string, ActionEntry>;
21
22
  //# sourceMappingURL=browser-team-tools.d.ts.map
@@ -316,7 +316,7 @@ export function createTeamTools(deps) {
316
316
  return {
317
317
  "agent-teams": {
318
318
  tool: {
319
- description: "Manage background sub-agent tasks. Use action 'spawn' to start a new sub-agent, 'status' to check progress, 'read-result' to get a finished task's output, 'send' to message a running sub-agent, or 'list' to see all tasks. A successful spawn only means the task started and is running; do not report it as finished until status/read-result shows a terminal status.",
319
+ description: "Manage background tasks that run in their own task thread. Use action 'spawn' to start one, 'status' to check progress, 'read-result' to get a finished task's output, 'send' to message a running task, or 'list' to see all tasks. A successful spawn only means the task started and is running; do not report it as finished until status/read-result shows a terminal status. This is a background task, not a source-control branch.",
320
320
  parameters: {
321
321
  type: "object",
322
322
  properties: {
@@ -335,7 +335,7 @@ export function createTeamTools(deps) {
335
335
  },
336
336
  name: {
337
337
  type: "string",
338
- description: "(spawn) Short name for the sub-agent tab (e.g. 'Research', 'Draft email'). If omitted, derived from the task.",
338
+ description: "(spawn) Short name for the background task (e.g. 'Research', 'Draft email'). If omitted, derived from the task.",
339
339
  },
340
340
  agent: {
341
341
  type: "string",
@@ -402,6 +402,7 @@ export function createTeamTools(deps) {
402
402
  model: selectedModel,
403
403
  name: selectedName || undefined,
404
404
  parentThreadId: deps.getParentThreadId(),
405
+ parentRunId: deps.getParentRunId?.(),
405
406
  parentSend: (event) => {
406
407
  if (capturedSend)
407
408
  capturedSend(event);
@@ -414,7 +415,7 @@ export function createTeamTools(deps) {
414
415
  status: task.status,
415
416
  parentThreadId: task.parentThreadId,
416
417
  state: "launched_pending_completion",
417
- message: "Sub-agent launched and is still running. Use status or read-result later; do not describe this task as completed from the spawn response alone.",
418
+ message: "Background task launched in its own task thread and is still running. Use status or read-result later; do not describe this task as completed from the spawn response alone.",
418
419
  description: task.description,
419
420
  name: task.name ?? selectedName,
420
421
  });
@@ -483,7 +484,7 @@ export function createTeamTools(deps) {
483
484
  const { listTasks } = await import("../agent-teams.js");
484
485
  const tasks = await listTasks();
485
486
  if (tasks.length === 0) {
486
- return "No sub-agent tasks.";
487
+ return "No background tasks.";
487
488
  }
488
489
  return JSON.stringify(tasks.map((t) => ({
489
490
  taskId: t.taskId,
@@ -44,8 +44,8 @@ You can search and restore previous chat conversations using \`chat-history\`:
44
44
  When the user asks to find a previous conversation, use \`chat-history\` with action "search" first to find matching threads, then action "open" to restore the one they want.`,
45
45
  "agent-teams": `### Agent Teams — Orchestration
46
46
 
47
- You can delegate to background sub-agents with the \`agent-teams\` tool:
48
- - \`agent-teams\` (action: "spawn") — Launch a sub-agent on a task. It runs in its own thread with a clean context while you stay available; a live preview card appears in the chat. The spawn result confirms launch only, not completion. Optionally pass a custom agent profile from \`agents/*.md\` via the \`agent\` parameter.
47
+ You can delegate to background tasks with the \`agent-teams\` tool. Call them background tasks or sub-agent tasks, never branches; reserve "branch" for source-control or Builder code handoffs:
48
+ - \`agent-teams\` (action: "spawn") — Launch a background task on a self-contained job. It runs in its own task thread with a clean context while you stay available; a live preview card appears in the chat. The spawn result confirms launch only, not completion. Optionally pass a custom agent profile from \`agents/*.md\` via the \`agent\` parameter.
49
49
  - \`agent-teams\` (action: "status") — Check a running sub-agent's progress.
50
50
  - \`agent-teams\` (action: "read-result") — Read a finished sub-agent's output.
51
51
  - \`agent-teams\` (action: "send") — Message a running sub-agent.
@@ -2086,6 +2086,7 @@ export function createAgentChatPlugin(options) {
2086
2086
  },
2087
2087
  getModel: () => getRequestRunContext()?.model ?? resolvedModel,
2088
2088
  getParentThreadId: () => getRequestRunContext()?.threadId ?? "",
2089
+ getParentRunId: () => getRequestRunContext()?.runId ?? "",
2089
2090
  getSend: () => {
2090
2091
  // Return the send for the current run's thread
2091
2092
  const threadId = getRequestRunContext()?.threadId ?? "";
@@ -2517,12 +2518,14 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
2517
2518
  }
2518
2519
  },
2519
2520
  onRunPrepared: persistSubmittedUserMessage,
2520
- onRunStart: async (send, threadId) => {
2521
+ onRunStart: async (send, threadId, runId) => {
2521
2522
  await recordPreRunGitStatus(threadId);
2522
2523
  _runSendByThread.set(threadId, send);
2523
2524
  const runCtx = ensureRequestRunContext();
2524
- if (runCtx)
2525
+ if (runCtx) {
2525
2526
  runCtx.threadId = threadId;
2527
+ runCtx.runId = runId;
2528
+ }
2526
2529
  },
2527
2530
  onRunComplete: async (run, threadId) => {
2528
2531
  if (threadId)
@@ -2562,12 +2565,14 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
2562
2565
  }
2563
2566
  },
2564
2567
  onRunPrepared: persistSubmittedUserMessage,
2565
- onRunStart: async (send, threadId) => {
2568
+ onRunStart: async (send, threadId, runId) => {
2566
2569
  await recordPreRunGitStatus(threadId);
2567
2570
  _runSendByThread.set(threadId, send);
2568
2571
  const runCtx = ensureRequestRunContext();
2569
- if (runCtx)
2572
+ if (runCtx) {
2570
2573
  runCtx.threadId = threadId;
2574
+ runCtx.runId = runId;
2575
+ }
2571
2576
  },
2572
2577
  onRunComplete: async (run, threadId) => {
2573
2578
  if (threadId)
@@ -2710,12 +2715,14 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
2710
2715
  }
2711
2716
  },
2712
2717
  onRunPrepared: persistSubmittedUserMessage,
2713
- onRunStart: async (send, threadId) => {
2718
+ onRunStart: async (send, threadId, runId) => {
2714
2719
  await recordPreRunGitStatus(threadId);
2715
2720
  _runSendByThread.set(threadId, send);
2716
2721
  const runCtx = ensureRequestRunContext();
2717
- if (runCtx)
2722
+ if (runCtx) {
2718
2723
  runCtx.threadId = threadId;
2724
+ runCtx.runId = runId;
2725
+ }
2719
2726
  },
2720
2727
  onRunComplete: async (run, threadId) => {
2721
2728
  if (threadId)
@@ -27,11 +27,11 @@ export declare function resolveAgentEngineApiKeyWriteTarget(event: H3Event, scop
27
27
  export declare function createAgentEngineApiKeyHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
28
28
  error: any;
29
29
  } | {
30
+ error?: undefined;
30
31
  ok: boolean;
31
32
  key: string;
32
33
  baseUrlKey?: string;
33
34
  scope: AgentEngineApiKeyScope;
34
- error?: undefined;
35
35
  }>>;
36
36
  export {};
37
37
  //# sourceMappingURL=agent-engine-api-key-route.d.ts.map
@@ -27,6 +27,8 @@ export interface AgentTeamRunPayload {
27
27
  agentRef?: string;
28
28
  /** Parent thread to post a completion recap to. */
29
29
  parentThreadId?: string;
30
+ /** Parent run that launched this durable background task. */
31
+ parentRunId?: string;
30
32
  /** Display name for the sub-agent tab. */
31
33
  name?: string;
32
34
  /** Logical-turn id, stable across continuation chunks so durable assistant
@@ -194,6 +194,8 @@ export interface SpawnTaskOptions {
194
194
  parentSend: (event: AgentChatEvent) => void;
195
195
  /** Parent thread ID — used to auto-respond when the sub-agent finishes */
196
196
  parentThreadId?: string;
197
+ /** Parent run ID used to correlate child telemetry after durable handoff. */
198
+ parentRunId?: string;
197
199
  /** Display name for the sub-agent tab (carried into the dispatch payload). */
198
200
  name?: string;
199
201
  /**
@@ -982,6 +982,7 @@ export async function spawnTask(opts) {
982
982
  instructions: opts.instructions,
983
983
  model: opts.model,
984
984
  ...(opts.parentThreadId ? { parentThreadId: opts.parentThreadId } : {}),
985
+ ...(opts.parentRunId ? { parentRunId: opts.parentRunId } : {}),
985
986
  ...(opts.name ? { name: opts.name } : {}),
986
987
  // Stable across continuation chunks so the durable assistant message folds.
987
988
  turnId: runId,
@@ -1309,7 +1310,7 @@ export async function processAgentTeamRun(opts) {
1309
1310
  // cap is hit. Fall back to depth 1 for legacy tasks persisted
1310
1311
  // before delegationDepth was tracked.
1311
1312
  () => runWithDelegationDepth(task.delegationDepth ?? 1, async () => {
1312
- chunkUsage = await runAgentLoop({
1313
+ const agentLoopOpts = {
1313
1314
  engine: config.engine,
1314
1315
  model: config.model,
1315
1316
  // Agent-team runs are delegated turns too. Keep their
@@ -1328,7 +1329,49 @@ export async function processAgentTeamRun(opts) {
1328
1329
  send: wrappedSend,
1329
1330
  signal,
1330
1331
  finalResponseGuard: createTaskMessageFinalGuard(opts.taskId),
1331
- });
1332
+ };
1333
+ let instrumented = false;
1334
+ try {
1335
+ const { getObservabilityConfig, instrumentAgentLoop } = await import("../observability/traces.js");
1336
+ const observabilityConfig = await getObservabilityConfig();
1337
+ if (observabilityConfig.enabled) {
1338
+ instrumented = true;
1339
+ chunkUsage = await instrumentAgentLoop({
1340
+ runAgentLoop,
1341
+ loopOpts: agentLoopOpts,
1342
+ runId,
1343
+ threadId: task.threadId,
1344
+ userId: ownerEmail || null,
1345
+ config: observabilityConfig,
1346
+ metadata: {
1347
+ source: "agent_team",
1348
+ agent_team_task_id: opts.taskId,
1349
+ continuation_count: claimed.continuationCount,
1350
+ ...(payload.parentThreadId
1351
+ ? { parent_thread_id: payload.parentThreadId }
1352
+ : {}),
1353
+ },
1354
+ delegation: {
1355
+ protocol: "agent-team",
1356
+ callerApp: "agent-teams",
1357
+ taskId: opts.taskId,
1358
+ ...(payload.parentRunId
1359
+ ? { parentRunId: payload.parentRunId }
1360
+ : {}),
1361
+ },
1362
+ });
1363
+ }
1364
+ }
1365
+ catch (error) {
1366
+ // Configuration is best effort. Once the wrapper starts,
1367
+ // preserve its errors so a failed child is not reported
1368
+ // as a successful run with missing telemetry.
1369
+ if (instrumented)
1370
+ throw error;
1371
+ }
1372
+ if (!instrumented) {
1373
+ chunkUsage = await runAgentLoop(agentLoopOpts);
1374
+ }
1332
1375
  }));
1333
1376
  }, async (run) => {
1334
1377
  clearInterval(heartbeat);
@@ -45,6 +45,8 @@ export interface RequestRunContext {
45
45
  userApiKey?: string;
46
46
  /** Thread ID for the current run (set by onRunStart). */
47
47
  threadId?: string;
48
+ /** Run ID for the current run (set by onRunStart). */
49
+ runId?: string;
48
50
  /** System prompt actually sent to the model for this run. */
49
51
  systemPrompt?: string;
50
52
  /** Engine instance for this run (set by onEngineResolved). */
@@ -26,6 +26,12 @@ export interface ShortLivedTokenClaims {
26
26
  resourceId: string;
27
27
  /** Optional viewer email for audit / analytics — not used for authorisation. */
28
28
  viewerEmail?: string;
29
+ /**
30
+ * Optional display name of the agent the token was minted for. Signed so a
31
+ * reader cannot rename itself, but audit/display-only like `viewerEmail` —
32
+ * never consult it for authorisation.
33
+ */
34
+ agentLabel?: string;
29
35
  /** Override default TTL (seconds). */
30
36
  ttlSeconds?: number;
31
37
  }
@@ -36,6 +42,7 @@ export interface ShortLivedTokenClaims {
36
42
  export type VerifyResult = {
37
43
  ok: true;
38
44
  viewerEmail?: string;
45
+ agentLabel?: string;
39
46
  } | {
40
47
  ok: false;
41
48
  reason: string;
@@ -65,6 +65,8 @@ export function signShortLivedToken(claims) {
65
65
  };
66
66
  if (claims.viewerEmail)
67
67
  payload.viewerEmail = claims.viewerEmail;
68
+ if (claims.agentLabel)
69
+ payload.agentLabel = claims.agentLabel;
68
70
  const payloadStr = base64UrlEncode(JSON.stringify(payload));
69
71
  const sig = base64UrlEncode(crypto.createHmac("sha256", getSigningKey()).update(payloadStr).digest());
70
72
  return `${payloadStr}.${sig}`;
@@ -117,7 +119,11 @@ export function verifyShortLivedToken(token, expectedResourceId) {
117
119
  if (claims.resourceId !== expectedResourceId) {
118
120
  return { ok: false, reason: "wrong_resource" };
119
121
  }
120
- return { ok: true, viewerEmail: claims.viewerEmail };
122
+ return {
123
+ ok: true,
124
+ viewerEmail: claims.viewerEmail,
125
+ agentLabel: claims.agentLabel,
126
+ };
121
127
  }
122
128
  // ── Realtime subscribe tokens ────────────────────────────────────────────────
123
129
  //
@@ -257,6 +257,24 @@ function removeDocumentCsp(headers) {
257
257
  headers.delete("content-security-policy");
258
258
  headers.delete("content-security-policy-report-only");
259
259
  }
260
+ /**
261
+ * Render an error message safely as a `text/plain` body.
262
+ *
263
+ * Vite ids its virtual modules with a leading NUL (`\0virtual:react-router/…`),
264
+ * and those ids travel verbatim inside module-resolution error messages. One raw
265
+ * NUL is enough for curl to refuse to print the response as text, hiding the only
266
+ * line that says what broke. Escape the control bytes rather than deleting them:
267
+ * the NUL is part of the real resolved id, so a reader who greps for it or pastes
268
+ * it into a bug report must be able to see that it is there.
269
+ */
270
+ function textSafeErrorMessage(err) {
271
+ const message = String(err?.message ?? err);
272
+ // C0 controls except tab, newline, and carriage return, which are real formatting.
273
+ return message.replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f]/g, (char) => {
274
+ const code = char.codePointAt(0) ?? 0;
275
+ return code === 0 ? "\\0" : `\\x${code.toString(16).padStart(2, "0")}`;
276
+ });
277
+ }
260
278
  function isFrameworkOrAssetPath(pathname) {
261
279
  return (isMcpPublicPath(pathname) ||
262
280
  pathname.startsWith("/.well-known/") ||
@@ -368,7 +386,7 @@ export function createH3SSRHandler(getBuild) {
368
386
  const isProd = process.env.NODE_ENV === "production";
369
387
  const body = isProd
370
388
  ? "Internal Server Error"
371
- : `Internal Server Error: ${err?.message ?? err}`;
389
+ : `Internal Server Error: ${textSafeErrorMessage(err)}`;
372
390
  return new Response(body, {
373
391
  status: 500,
374
392
  headers: { "content-type": "text/plain" },
@@ -20,7 +20,7 @@ export declare function createTranscribeVoiceHandler(): import("h3").EventHandle
20
20
  error: string;
21
21
  text?: undefined;
22
22
  } | {
23
- text: string;
24
23
  error?: undefined;
24
+ text: string;
25
25
  }>>;
26
26
  //# sourceMappingURL=transcribe-voice.d.ts.map