@agent-native/core 0.209.1 → 0.209.2-nightly-20261015213030

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 (89) hide show
  1. package/dist/agent/actions/list-model-providers.js +15 -2
  2. package/dist/agent/app-model-defaults.d.ts +9 -13
  3. package/dist/agent/app-model-defaults.js +23 -5
  4. package/dist/agent/default-agent-engine.d.ts +5 -3
  5. package/dist/agent/default-agent-engine.js +38 -8
  6. package/dist/agent/durable-background.d.ts +2 -0
  7. package/dist/agent/durable-background.js +2 -0
  8. package/dist/agent/engine/registry.js +6 -0
  9. package/dist/agent/production-agent.js +58 -5
  10. package/dist/automations/service.d.ts +2 -0
  11. package/dist/automations/service.js +4 -1
  12. package/dist/client/analytics.js +48 -1
  13. package/dist/client/application-state.js +7 -2
  14. package/dist/client/chat/agentkit-protocol.js +12 -3
  15. package/dist/client/client-bootstrap.js +2 -0
  16. package/dist/client/problem-report.d.ts +11 -0
  17. package/dist/client/problem-report.js +19 -0
  18. package/dist/client/recorder.d.ts +88 -0
  19. package/dist/client/recorder.js +585 -0
  20. package/dist/client/route-chunk-recovery.js +4 -1
  21. package/dist/client/sign-out.js +2 -0
  22. package/dist/client/use-action.js +3 -0
  23. package/dist/collab/routes.d.ts +1 -1
  24. package/dist/collab/struct-routes.d.ts +1 -1
  25. package/dist/file-upload/actions/upload-image.d.ts +2 -2
  26. package/dist/integrations/google-docs-poller.js +12 -5
  27. package/dist/integrations/plugin.js +86 -19
  28. package/dist/integrations/request-scope.d.ts +16 -0
  29. package/dist/integrations/request-scope.js +27 -0
  30. package/dist/integrations/webhook-handler.d.ts +2 -0
  31. package/dist/integrations/webhook-handler.js +38 -18
  32. package/dist/jobs/background-automation-runner.d.ts +2 -0
  33. package/dist/jobs/background-automation-runner.js +25 -2
  34. package/dist/jobs/scheduler.js +36 -22
  35. package/dist/mcp/screen-memory-stdio.d.ts +7 -7
  36. package/dist/org/context.d.ts +12 -0
  37. package/dist/org/context.js +26 -11
  38. package/dist/org/index.d.ts +1 -1
  39. package/dist/problem-report/actions/read-problem-report.d.ts +27 -0
  40. package/dist/problem-report/actions/read-problem-report.js +103 -0
  41. package/dist/problem-report/actions/save-problem-report.d.ts +35 -0
  42. package/dist/problem-report/actions/save-problem-report.js +36 -0
  43. package/dist/problem-report/format.d.ts +7 -0
  44. package/dist/problem-report/format.js +110 -0
  45. package/dist/problem-report/schema.d.ts +41 -0
  46. package/dist/problem-report/schema.js +34 -0
  47. package/dist/progress/routes.d.ts +1 -1
  48. package/dist/provider-api/actions/custom-provider-registration.d.ts +8 -8
  49. package/dist/provider-api/actions/provider-api.d.ts +14 -14
  50. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  51. package/dist/resources/handlers.d.ts +1 -1
  52. package/dist/scripts/agent-engines/manage-agent-engine.js +9 -4
  53. package/dist/scripts/agent-engines/set-agent-engine.js +7 -1
  54. package/dist/server/action-discovery.js +11 -0
  55. package/dist/server/action-routes.js +2 -0
  56. package/dist/server/agent-chat-ai-setup.d.ts +2 -3
  57. package/dist/server/agent-chat-ai-setup.js +18 -4
  58. package/dist/server/agent-chat-plugin.js +97 -22
  59. package/dist/server/agent-chat-stream.d.ts +17 -5
  60. package/dist/server/agent-chat-stream.js +15 -0
  61. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  62. package/dist/server/agent-engine-default-model-route.d.ts +2 -2
  63. package/dist/server/agent-engine-default-model-route.js +39 -6
  64. package/dist/server/agent-engine-ollama-models-route.d.ts +2 -2
  65. package/dist/server/agent-engine-status-cache.d.ts +4 -0
  66. package/dist/server/agent-engine-status-cache.js +2 -0
  67. package/dist/server/agent-run-context.d.ts +9 -0
  68. package/dist/server/agent-run-context.js +82 -17
  69. package/dist/server/builder-browser.js +18 -3
  70. package/dist/server/chatgpt-subscription-oauth.js +12 -17
  71. package/dist/server/core-routes-plugin.d.ts +1 -0
  72. package/dist/server/core-routes-plugin.js +46 -9
  73. package/dist/server/loopback.d.ts +1 -0
  74. package/dist/server/loopback.js +30 -0
  75. package/dist/server/origin-allowlist.d.ts +2 -0
  76. package/dist/server/origin-allowlist.js +13 -1
  77. package/dist/server/realtime-token.d.ts +1 -1
  78. package/dist/server/request-context.d.ts +4 -0
  79. package/dist/templates/chat/app/components/layout/Sidebar.tsx +11 -1
  80. package/dist/templates/factory/.agents/skills/review-latest-feedback/SKILL.md +2 -2
  81. package/dist/templates/factory/.agents/skills/review-latest-feedback/references/channel-inventory.md +31 -0
  82. package/dist/triggers/dispatcher.js +117 -31
  83. package/docs/content/recorder.mdx +259 -0
  84. package/docs/content/template-clips-developers.mdx +9 -8
  85. package/docs/content/template-clips-features.mdx +8 -7
  86. package/package.json +5 -3
  87. package/src/templates/chat/app/components/layout/Sidebar.tsx +11 -1
  88. package/src/templates/factory/.agents/skills/review-latest-feedback/SKILL.md +2 -2
  89. package/src/templates/factory/.agents/skills/review-latest-feedback/references/channel-inventory.md +31 -0
@@ -15,6 +15,7 @@ import { agentNativeApiDisabledReason, assertAgentNativeApiEnabled, } from "./ap
15
15
  import { getBrowserTabId } from "./browser-tab-id.js";
16
16
  import { clientBuildId, clientCompatibilityVersion, reloadForClientCompatibilityMismatch, } from "./build-compatibility.js";
17
17
  import { ensureEmbedAuthFetchInterceptor, isEmbedAuthActive, } from "./embed-auth.js";
18
+ import { recordActionStart } from "./recorder.js";
18
19
  import { currentRouteTemplate } from "./route-template.js";
19
20
  import { recheckSessionAfterUnauthorized } from "./use-session.js";
20
21
  function actionPrefix() {
@@ -490,6 +491,7 @@ async function actionFetch(name, method, params, options) {
490
491
  const hiddenEpochAtStart = pageHiddenEpoch;
491
492
  const hiddenAtStart = typeof document !== "undefined" && document.visibilityState !== "visible";
492
493
  const timeoutMs = options?.timeoutMs ?? DEFAULT_ACTION_TIMEOUT_MS;
494
+ const recordActionEnd = recordActionStart(name, method);
493
495
  let response;
494
496
  let responseAt;
495
497
  let error;
@@ -509,6 +511,7 @@ async function actionFetch(name, method, params, options) {
509
511
  }
510
512
  finally {
511
513
  try {
514
+ recordActionEnd({ error, response, signal: options?.signal });
512
515
  const completedAt = actionTelemetryNow();
513
516
  const durationMs = Math.max(0, completedAt - startedAt);
514
517
  const sampling = getActionResponseSampling(error, durationMs, response);
@@ -13,8 +13,8 @@ export declare const getCollabState: import("h3").EventHandlerWithFetch<import("
13
13
  };
14
14
  }>>;
15
15
  export declare const postCollabUpdate: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
16
- error: string;
17
16
  ok?: undefined;
17
+ error: string;
18
18
  } | {
19
19
  error?: undefined;
20
20
  ok: boolean;
@@ -1,6 +1,6 @@
1
1
  export declare const postCollabJson: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
2
- ok?: undefined;
3
2
  error: string;
3
+ ok?: undefined;
4
4
  } | {
5
5
  error?: undefined;
6
6
  ok: boolean;
@@ -33,9 +33,9 @@ declare const _default: import("../../action.js").ActionDefinition<{
33
33
  idempotencyKey: string;
34
34
  deleted: boolean;
35
35
  } | {
36
+ id?: undefined;
36
37
  error: string;
37
38
  url?: undefined;
38
- id?: undefined;
39
39
  provider?: undefined;
40
40
  configured?: undefined;
41
41
  } | {
@@ -45,8 +45,8 @@ declare const _default: import("../../action.js").ActionDefinition<{
45
45
  configured?: undefined;
46
46
  error?: undefined;
47
47
  } | {
48
- url?: undefined;
49
48
  id?: undefined;
49
+ url?: undefined;
50
50
  provider?: undefined;
51
51
  error: string;
52
52
  configured: boolean;
@@ -7,12 +7,12 @@ import { startRun } from "../agent/run-manager.js";
7
7
  import { buildAssistantMessage, extractThreadMeta, } from "../agent/thread-data-builder.js";
8
8
  import { attachToolSearch } from "../agent/tool-search.js";
9
9
  import { createThread, getThread, setThreadSourceIfMissing, updateThreadData, } from "../chat-threads/store.js";
10
- import { resolveOrgIdForEmail } from "../org/context.js";
11
10
  import { startIntervalJob, } from "../server/interval-job.js";
12
11
  import { runWithRequestContext } from "../server/request-context.js";
13
12
  import { getServiceAccountAccessToken, getServiceAccountEmail, getStartPageToken, googleDocsAdapter, listChanges, listDocComments, } from "./adapters/google-docs.js";
14
13
  import { getIntegrationConfig, integrationConfigWriteEpoch, saveIntegrationConfig, saveIntegrationConfigIfUnchanged, } from "./config-store.js";
15
14
  import { createGoogleDocsChannelAuth, verifyGoogleDocsChannel, } from "./google-docs-webhook.js";
15
+ import { integrationRequestContext, resolveIntegrationRequestScope, } from "./request-scope.js";
16
16
  import { getThreadMapping, saveThreadMapping } from "./thread-mapping-store.js";
17
17
  const PLATFORM = "google-docs";
18
18
  const DEFAULT_TRIGGER = "@agent";
@@ -466,6 +466,10 @@ export async function handlePushNotification() {
466
466
  }
467
467
  async function processComment(fileId, commentId, text, senderName, options, existingThreadId) {
468
468
  const adapter = googleDocsAdapter();
469
+ const requestScope = await resolveIntegrationRequestScope({
470
+ ownerEmail: options.ownerEmail,
471
+ });
472
+ const requestContext = integrationRequestContext(requestScope);
469
473
  const key = commentKey(fileId, commentId);
470
474
  const incoming = {
471
475
  platform: PLATFORM,
@@ -481,10 +485,10 @@ async function processComment(fileId, commentId, text, senderName, options, exis
481
485
  };
482
486
  let threadId = existingThreadId;
483
487
  if (!threadId) {
484
- const thread = await createThread(options.ownerEmail, {
488
+ const thread = await runWithRequestContext({ userEmail: options.ownerEmail, ...requestContext }, () => createThread(options.ownerEmail, {
485
489
  title: `Google Doc: ${senderName}`,
486
490
  source,
487
- });
491
+ }));
488
492
  await saveThreadMapping(PLATFORM, key, thread.id, { fileId, commentId });
489
493
  threadId = thread.id;
490
494
  }
@@ -532,9 +536,12 @@ async function processComment(fileId, commentId, text, senderName, options, exis
532
536
  const tools = filterInitialEngineTools(availableTools, options.initialToolNames);
533
537
  const runId = `gdocs-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
534
538
  const capturedThreadId = threadId;
535
- const orgId = (await resolveOrgIdForEmail(options.ownerEmail)) ?? undefined;
536
539
  startRun(runId, capturedThreadId, async (send, signal) => {
537
- await runWithRequestContext({ userEmail: options.ownerEmail, orgId, isIntegrationCaller: true }, () => runAgentLoopDirectWithSoftTimeout({
540
+ await runWithRequestContext({
541
+ userEmail: options.ownerEmail,
542
+ ...requestContext,
543
+ isIntegrationCaller: true,
544
+ }, () => runAgentLoopDirectWithSoftTimeout({
538
545
  engine,
539
546
  model: options.model,
540
547
  systemPrompt: options.systemPrompt,
@@ -4,7 +4,7 @@ import { AGENT_BACKGROUND_PROCESSOR_FIELD, AGENT_BACKGROUND_PROCESSOR_INTEGRATIO
4
4
  import { abortRun } from "../agent/run-manager.js";
5
5
  import { AppConfigurationError, getAppConfig } from "../app-config/index.js";
6
6
  import { isServerlessRuntime } from "../db/client.js";
7
- import { getOrgContext, resolveOrgIdForEmail } from "../org/context.js";
7
+ import { getOrgContext } from "../org/context.js";
8
8
  import { loadResourcesForPrompt } from "../server/agent-chat-plugin.js";
9
9
  import { withConfiguredAppBasePath } from "../server/app-base-path.js";
10
10
  import { getSession } from "../server/auth.js";
@@ -49,6 +49,7 @@ import { startRemotePushDeliveryJob } from "./remote-push-delivery-job.js";
49
49
  import { listRemotePushNotificationsForOwner, listRemotePushRegistrationsForOwner, queueRemotePushNotifications, toPublicRemotePushRegistration, unregisterRemotePushRegistrationForOwner, upsertRemotePushRegistration, } from "./remote-push-store.js";
50
50
  import { startRemoteCommandsRetryJob } from "./remote-retry-job.js";
51
51
  import { insertRemoteRunEvents, listRemoteRunEvents, } from "./remote-run-events-store.js";
52
+ import { integrationRequestContext, resolveIntegrationRequestScope, } from "./request-scope.js";
52
53
  import { listIntegrationScopes, saveIntegrationScope } from "./scope-store.js";
53
54
  import { buildSlackAgentManifest } from "./slack-manifest.js";
54
55
  import { assertSlackInstallAccess, buildSlackAuthorizeUrl, exchangeSlackOAuthCode, slackOAuthResponseToInstallation, testSlackAuth, } from "./slack-oauth.js";
@@ -579,7 +580,7 @@ export function createIntegrationsPlugin(options) {
579
580
  .then(operation)
580
581
  .finally(release);
581
582
  };
582
- const createGoogleDocsPollerOptions = (requestBaseUrl) => {
583
+ const createGoogleDocsPollerOptions = (ownerEmail, requestBaseUrl) => {
583
584
  const configuredBaseUrl = getAppConfig().integrations.webhookBaseUrl;
584
585
  const baseUrl = configuredBaseUrl || requestBaseUrl;
585
586
  const webhookUrl = baseUrl
@@ -591,7 +592,7 @@ export function createIntegrationsPlugin(options) {
591
592
  initialToolNames,
592
593
  model: model ?? "",
593
594
  apiKey: getApiKey(),
594
- ownerEmail: "integration@google-docs",
595
+ ownerEmail,
595
596
  webhookUrl,
596
597
  };
597
598
  };
@@ -599,12 +600,22 @@ export function createIntegrationsPlugin(options) {
599
600
  adapters,
600
601
  webhookUrl: (baseUrl, platform) => `${baseUrl}${P}/${platform}/webhook`,
601
602
  async setEnabled(platform, enabled, { actorEmail, baseUrl }) {
602
- await saveIntegrationConfig(platform, { enabled }, "default", actorEmail);
603
- if (platform !== "google-docs")
603
+ if (platform === "google-docs") {
604
+ if (enabled) {
605
+ const ownerEmail = actorEmail?.trim();
606
+ if (!ownerEmail) {
607
+ throw new Error("Google Docs requires a signed-in owner to start polling.");
608
+ }
609
+ await saveIntegrationConfig(platform, { enabled }, "default", ownerEmail);
610
+ await runGoogleDocsPollerTransition(() => startGoogleDocsPoller(createGoogleDocsPollerOptions(ownerEmail, baseUrl)));
611
+ }
612
+ else {
613
+ await saveIntegrationConfig(platform, { enabled }, "default", actorEmail);
614
+ await runGoogleDocsPollerTransition(stopGoogleDocsPoller);
615
+ }
604
616
  return;
605
- await runGoogleDocsPollerTransition(enabled
606
- ? () => startGoogleDocsPoller(createGoogleDocsPollerOptions(baseUrl))
607
- : stopGoogleDocsPoller);
617
+ }
618
+ await saveIntegrationConfig(platform, { enabled }, "default", actorEmail);
608
619
  },
609
620
  async registerWebhook(platform, baseUrl) {
610
621
  if (platform !== "telegram") {
@@ -715,15 +726,26 @@ export function createIntegrationsPlugin(options) {
715
726
  return null;
716
727
  }
717
728
  const orgCtx = await getOrgContext(event).catch(() => null);
718
- return {
719
- ownerEmail: session.email,
720
- orgId: orgCtx?.orgId ?? session.orgId ?? null,
721
- };
729
+ try {
730
+ return {
731
+ ownerEmail: session.email,
732
+ ...(await resolveIntegrationRequestScope({
733
+ ownerEmail: session.email,
734
+ orgId: orgCtx?.orgId ?? session.orgId ?? null,
735
+ principalType: "user",
736
+ })),
737
+ };
738
+ }
739
+ catch (error) {
740
+ console.error("[integrations] Could not resolve signed-in user's organization scope:", error);
741
+ setResponseStatus(event, 503);
742
+ return null;
743
+ }
722
744
  }
723
745
  function toCredentialContext(ctx, opts) {
724
746
  return {
725
747
  userEmail: ctx.ownerEmail,
726
- ...(ctx.orgId ? { orgId: ctx.orgId } : {}),
748
+ ...integrationRequestContext(ctx),
727
749
  ...(opts?.isIntegrationCaller ? { isIntegrationCaller: true } : {}),
728
750
  };
729
751
  }
@@ -731,10 +753,12 @@ export function createIntegrationsPlugin(options) {
731
753
  const ownerEmail = typeof config?.owner === "string" ? config.owner.trim() : "";
732
754
  if (!ownerEmail)
733
755
  return null;
734
- const orgId = await resolveOrgIdForEmail(ownerEmail).catch(() => null);
735
756
  return {
736
757
  userEmail: ownerEmail,
737
- ...(orgId ? { orgId } : {}),
758
+ ...integrationRequestContext(await resolveIntegrationRequestScope({
759
+ ownerEmail,
760
+ principalType: "user",
761
+ })),
738
762
  isIntegrationCaller: true,
739
763
  };
740
764
  }
@@ -1632,9 +1656,24 @@ export function createIntegrationsPlugin(options) {
1632
1656
  setResponseStatus(event, 404);
1633
1657
  return { error: "Unknown platform" };
1634
1658
  }
1659
+ const principalType = taskPayload.kind === "system-notice"
1660
+ ? "service"
1661
+ : "principalType" in taskPayload
1662
+ ? (taskPayload.principalType ?? "user")
1663
+ : "user";
1664
+ const orgScope = ("orgScope" in taskPayload ? taskPayload.orgScope : undefined) ??
1665
+ (task.orgId === null && principalType === "user"
1666
+ ? "personal"
1667
+ : undefined);
1668
+ const requestScope = await resolveIntegrationRequestScope({
1669
+ ownerEmail: task.ownerEmail,
1670
+ orgId: task.orgId,
1671
+ orgScope,
1672
+ principalType,
1673
+ });
1635
1674
  const processingResult = await runWithRequestContext({
1636
1675
  userEmail: task.ownerEmail,
1637
- ...(task.orgId ? { orgId: task.orgId } : {}),
1676
+ ...integrationRequestContext(requestScope),
1638
1677
  isIntegrationCaller: true,
1639
1678
  }, async () => {
1640
1679
  if (!campaignContinuation &&
@@ -2283,9 +2322,22 @@ export function createIntegrationsPlugin(options) {
2283
2322
  error: err instanceof Error ? err.message : "Slack access denied",
2284
2323
  };
2285
2324
  }
2325
+ let requestScope;
2326
+ try {
2327
+ requestScope = await resolveIntegrationRequestScope({
2328
+ ownerEmail: session.email,
2329
+ orgId: org?.orgId ?? session.orgId ?? null,
2330
+ principalType: "user",
2331
+ });
2332
+ }
2333
+ catch (error) {
2334
+ console.error("[slack] Could not resolve install scope:", error);
2335
+ setResponseStatus(event, 503);
2336
+ return { error: "Could not verify your account scope." };
2337
+ }
2286
2338
  return await runWithRequestContext({
2287
2339
  userEmail: session.email,
2288
- orgId: org?.orgId ?? session.orgId ?? undefined,
2340
+ ...integrationRequestContext(requestScope),
2289
2341
  }, async () => {
2290
2342
  const clientId = await resolveSecret("SLACK_CLIENT_ID");
2291
2343
  const clientSecret = await resolveSecret("SLACK_CLIENT_SECRET");
@@ -2349,9 +2401,14 @@ export function createIntegrationsPlugin(options) {
2349
2401
  orgId: org?.orgId ?? session.orgId ?? null,
2350
2402
  orgRole: org?.role ?? null,
2351
2403
  });
2404
+ const requestScope = await resolveIntegrationRequestScope({
2405
+ ownerEmail: access.ownerEmail,
2406
+ orgId: access.orgId,
2407
+ principalType: "user",
2408
+ });
2352
2409
  return await runWithRequestContext({
2353
2410
  userEmail: access.ownerEmail,
2354
- orgId: access.orgId ?? undefined,
2411
+ ...integrationRequestContext(requestScope),
2355
2412
  }, async () => {
2356
2413
  const clientId = await resolveSecret("SLACK_CLIENT_ID");
2357
2414
  const clientSecret = await resolveSecret("SLACK_CLIENT_SECRET");
@@ -2694,7 +2751,17 @@ export function createIntegrationsPlugin(options) {
2694
2751
  startRemotePushDeliveryJob();
2695
2752
  if (adapterMap.has("google-docs")) {
2696
2753
  setTimeout(() => {
2697
- void runGoogleDocsPollerTransition(() => startGoogleDocsPoller(createGoogleDocsPollerOptions()));
2754
+ void runGoogleDocsPollerTransition(async () => {
2755
+ const config = await getIntegrationConfig("google-docs");
2756
+ const ownerEmail = config?.owner?.trim();
2757
+ if (!config?.configData?.enabled)
2758
+ return;
2759
+ if (!ownerEmail) {
2760
+ console.error("[google-docs] Cannot start poller without a configured owner");
2761
+ return;
2762
+ }
2763
+ await startGoogleDocsPoller(createGoogleDocsPollerOptions(ownerEmail));
2764
+ });
2698
2765
  }, 2000);
2699
2766
  }
2700
2767
  }
@@ -0,0 +1,16 @@
1
+ export type IntegrationRequestScope = {
2
+ orgId: string | null;
3
+ orgScope?: "personal";
4
+ defaultAgentEngineScope?: "deployment";
5
+ };
6
+ export declare function resolveIntegrationRequestScope(input: {
7
+ ownerEmail: string;
8
+ orgId?: string | null;
9
+ orgScope?: "personal";
10
+ principalType?: "user" | "service";
11
+ }): Promise<IntegrationRequestScope>;
12
+ export declare function integrationRequestContext(scope: IntegrationRequestScope): {
13
+ orgId?: string;
14
+ orgScope?: "personal";
15
+ defaultAgentEngineScope?: "deployment";
16
+ };
@@ -0,0 +1,27 @@
1
+ import { resolveOrgScopeForEmail } from "../org/context.js";
2
+ export async function resolveIntegrationRequestScope(input) {
3
+ const explicitOrgId = input.orgId?.trim();
4
+ if (explicitOrgId)
5
+ return { orgId: explicitOrgId };
6
+ if (input.orgScope === "personal") {
7
+ return { orgId: null, orgScope: "personal" };
8
+ }
9
+ if (input.principalType === "service") {
10
+ return { orgId: null, defaultAgentEngineScope: "deployment" };
11
+ }
12
+ const scope = await resolveOrgScopeForEmail(input.ownerEmail);
13
+ if (scope.status === "organization")
14
+ return { orgId: scope.orgId };
15
+ if (scope.status === "personal")
16
+ return { orgId: null, orgScope: "personal" };
17
+ throw new Error("The integration owner's organization scope could not be resolved.");
18
+ }
19
+ export function integrationRequestContext(scope) {
20
+ return {
21
+ ...(scope.orgId ? { orgId: scope.orgId } : {}),
22
+ ...(scope.orgScope ? { orgScope: scope.orgScope } : {}),
23
+ ...(scope.defaultAgentEngineScope
24
+ ? { defaultAgentEngineScope: scope.defaultAgentEngineScope }
25
+ : {}),
26
+ };
27
+ }
@@ -8,6 +8,8 @@ export type IntegrationResponseDeliveryTaskPayload = {
8
8
  kind: "response-delivery";
9
9
  incoming: IncomingMessage;
10
10
  message: OutgoingMessage;
11
+ principalType?: "user" | "service";
12
+ orgScope?: "personal";
11
13
  placeholderRef?: string;
12
14
  strictTargetRef?: boolean;
13
15
  internalThreadId?: string;
@@ -12,7 +12,7 @@ import { buildAssistantMessage, extractThreadMeta, threadDataToEngineMessages, }
12
12
  import { attachToolSearch } from "../agent/tool-search.js";
13
13
  import { createThread, getThread, grantThreadUserShare, setThreadSourceIfMissing, } from "../chat-threads/store.js";
14
14
  import { updateThreadData } from "../chat-threads/store.js";
15
- import { getOrgA2ASecret, resolveOrgIdForEmail } from "../org/context.js";
15
+ import { getOrgA2ASecret } from "../org/context.js";
16
16
  import { withConfiguredAppBasePath } from "../server/app-base-path.js";
17
17
  import { getAppProductionUrl } from "../server/app-url.js";
18
18
  import { runWithRequestContext } from "../server/request-context.js";
@@ -26,6 +26,7 @@ import { claimIntegrationCampaignDeliveryForTask, claimIntegrationCampaign, comp
26
26
  import { dispatchPendingIntegrationTask, integrationDispatchScopeValue, } from "./integration-durable-dispatch.js";
27
27
  import { loadIntegrationMemoryPrompt } from "./integration-memory.js";
28
28
  import { insertPendingTask, isDuplicateEventError, stageTaskDeliveryPayload, } from "./pending-tasks-store.js";
29
+ import { integrationRequestContext, resolveIntegrationRequestScope, } from "./request-scope.js";
29
30
  import { integrationScopeSubjectKey } from "./scope-store.js";
30
31
  import { getThreadMapping, saveThreadMapping } from "./thread-mapping-store.js";
31
32
  import { listIntegrationUsageBudgets, releaseIntegrationUsageBudget, reserveIntegrationUsageBudget, settleIntegrationUsageBudget, } from "./usage-budget-store.js";
@@ -221,15 +222,12 @@ function immediateWebhookResponse(adapter, incoming) {
221
222
  }
222
223
  async function enqueueAndDispatch(event, incoming, options, handlerStartedAt = Date.now()) {
223
224
  const taskId = crypto.randomUUID();
224
- let orgId = options.orgId ?? null;
225
- if (options.orgId === undefined) {
226
- try {
227
- orgId = (await resolveOrgIdForEmail(options.ownerEmail)) ?? null;
228
- }
229
- catch {
230
- orgId = null;
231
- }
232
- }
225
+ const requestScope = await resolveIntegrationRequestScope({
226
+ ownerEmail: options.ownerEmail,
227
+ orgId: options.orgId,
228
+ principalType: options.principalType,
229
+ });
230
+ const orgId = requestScope.orgId;
233
231
  let placeholderRef;
234
232
  try {
235
233
  if (options.adapter.postProcessingPlaceholder) {
@@ -246,6 +244,7 @@ async function enqueueAndDispatch(event, incoming, options, handlerStartedAt = D
246
244
  incoming,
247
245
  placeholderRef,
248
246
  principalType: options.principalType ?? "user",
247
+ ...(requestScope.orgScope ? { orgScope: requestScope.orgScope } : {}),
249
248
  });
250
249
  await insertPendingTask({
251
250
  id: taskId,
@@ -294,6 +293,9 @@ export function resolveBaseUrl(event) {
294
293
  }
295
294
  export async function processIntegrationTask(task, options, campaignOptions) {
296
295
  const parsed = JSON.parse(task.payload);
296
+ const principalType = parsed.principalType ?? options.principalType ?? "user";
297
+ const orgScope = parsed.orgScope ??
298
+ (task.orgId === null && principalType === "user" ? "personal" : undefined);
297
299
  if (!campaignOptions?.continuationInvocation) {
298
300
  await recordInboundIntegrationAudit(task, parsed.incoming);
299
301
  }
@@ -301,8 +303,9 @@ export async function processIntegrationTask(task, options, campaignOptions) {
301
303
  taskId: task.id,
302
304
  attempts: task.attempts,
303
305
  placeholderRef: parsed.placeholderRef,
304
- orgId: task.orgId ?? undefined,
305
- principalType: parsed.principalType ?? options.principalType ?? "user",
306
+ orgId: task.orgId,
307
+ orgScope,
308
+ principalType,
306
309
  durableCampaign: campaignOptions?.enabled === true,
307
310
  });
308
311
  }
@@ -341,6 +344,14 @@ async function recordInboundIntegrationAudit(task, incoming) {
341
344
  }
342
345
  async function processIncomingMessage(incoming, options, opts = {}) {
343
346
  const { adapter, systemPrompt, actions, initialToolNames, model, apiKey, ownerEmail, engine: engineOption, } = options;
347
+ const requestScope = await resolveIntegrationRequestScope({
348
+ ownerEmail,
349
+ orgId: opts.orgId === undefined ? options.orgId : opts.orgId,
350
+ orgScope: opts.orgScope,
351
+ principalType: opts.principalType,
352
+ });
353
+ const orgId = requestScope.orgId;
354
+ const requestContext = integrationRequestContext(requestScope);
344
355
  let effectiveSystemPrompt = systemPrompt + buildRuntimeContextPrompt();
345
356
  const deliveryOptions = {
346
357
  placeholderRef: opts.placeholderRef,
@@ -395,7 +406,7 @@ async function processIncomingMessage(incoming, options, opts = {}) {
395
406
  const budgetReservations = await reserveApplicableIntegrationBudgets({
396
407
  incoming,
397
408
  ownerEmail,
398
- orgId: opts.orgId ?? null,
409
+ orgId,
399
410
  reservationId: opts.taskId ?? `integration:${incoming.externalThreadId}`,
400
411
  });
401
412
  if (!budgetReservations.allowed) {
@@ -404,6 +415,8 @@ async function processIncomingMessage(incoming, options, opts = {}) {
404
415
  kind: "response-delivery",
405
416
  incoming,
406
417
  message: outgoing,
418
+ principalType: opts.principalType ?? "user",
419
+ ...(requestScope.orgScope ? { orgScope: requestScope.orgScope } : {}),
407
420
  ...(opts.placeholderRef ? { placeholderRef: opts.placeholderRef } : {}),
408
421
  };
409
422
  try {
@@ -438,8 +451,7 @@ async function processIncomingMessage(incoming, options, opts = {}) {
438
451
  let thread;
439
452
  try {
440
453
  if (!mapping) {
441
- const threadOrgId = opts.orgId ?? (await resolveOrgIdForEmail(ownerEmail));
442
- const createdThread = await runWithRequestContext({ userEmail: ownerEmail, orgId: threadOrgId ?? undefined }, () => createThread(ownerEmail, {
454
+ const createdThread = await runWithRequestContext({ userEmail: ownerEmail, ...requestContext }, () => createThread(ownerEmail, {
443
455
  title: `${adapter.label}: ${incoming.senderName || incoming.senderId || "User"}`,
444
456
  source: {
445
457
  platform: incoming.platform,
@@ -524,6 +536,8 @@ async function processIncomingMessage(incoming, options, opts = {}) {
524
536
  kind: "response-delivery",
525
537
  incoming,
526
538
  message: exhaustedMessage,
539
+ principalType: opts.principalType ?? "user",
540
+ ...(requestScope.orgScope ? { orgScope: requestScope.orgScope } : {}),
527
541
  ...(exhaustedProgress?.responseTargetRef
528
542
  ? {
529
543
  placeholderRef: exhaustedProgress.responseTargetRef,
@@ -669,13 +683,11 @@ async function processIncomingMessage(incoming, options, opts = {}) {
669
683
  ],
670
684
  });
671
685
  }
672
- let orgId;
673
686
  let artifactSecrets;
674
687
  let runnableActions;
675
688
  let tools;
676
689
  let availableTools;
677
690
  try {
678
- orgId = opts.orgId ?? (await resolveOrgIdForEmail(ownerEmail));
679
691
  artifactSecrets = await resolveIntegrationArtifactSecrets(orgId);
680
692
  runnableActions = attachToolSearch({ ...actions });
681
693
  availableTools = actionsToEngineTools(runnableActions);
@@ -721,7 +733,7 @@ async function processIncomingMessage(incoming, options, opts = {}) {
721
733
  startRun(runId, threadId, async (send, signal) => {
722
734
  await runWithRequestContext({
723
735
  userEmail: ownerEmail,
724
- orgId: orgId ?? undefined,
736
+ ...requestContext,
725
737
  isIntegrationCaller: true,
726
738
  integration: opts.taskId
727
739
  ? {
@@ -924,6 +936,10 @@ async function processIncomingMessage(incoming, options, opts = {}) {
924
936
  kind: "response-delivery",
925
937
  incoming,
926
938
  message: outgoing,
939
+ principalType: opts.principalType ?? "user",
940
+ ...(requestScope.orgScope
941
+ ? { orgScope: requestScope.orgScope }
942
+ : {}),
927
943
  ...(progress?.responseTargetRef
928
944
  ? {
929
945
  placeholderRef: progress.responseTargetRef,
@@ -1150,6 +1166,10 @@ async function processIncomingMessage(incoming, options, opts = {}) {
1150
1166
  kind: "response-delivery",
1151
1167
  incoming,
1152
1168
  message: outgoingForDelivery,
1169
+ principalType: opts.principalType ?? "user",
1170
+ ...(requestScope.orgScope
1171
+ ? { orgScope: requestScope.orgScope }
1172
+ : {}),
1153
1173
  internalThreadId: threadId,
1154
1174
  }),
1155
1175
  ...(threadCheckpoint?.userMessageId
@@ -122,6 +122,8 @@ export declare function runBackgroundAutomation(options: BackgroundAutomationRun
122
122
  export declare function checkBackgroundAutomationCredentials(identity: {
123
123
  ownerEmail: string;
124
124
  orgId?: string;
125
+ orgScope?: "personal";
126
+ defaultAgentEngineScope?: "deployment";
125
127
  }, deps: BackgroundAutomationDeps, automationModel?: string): Promise<{
126
128
  ok: true;
127
129
  engine: AgentEngine;
@@ -16,7 +16,7 @@ import { withDbExec } from "../db/client.js";
16
16
  import { automationOutcomeMessagesForUser } from "../localization/automation-outcome-messages.js";
17
17
  import { automationRecoveryMessagesForLocale } from "../localization/automation-recovery-messages.js";
18
18
  import { queryOrgMembers } from "../org/context.js";
19
- import { organizationIdFromResourceOwner, } from "../resources/store.js";
19
+ import { organizationIdFromResourceOwner, SHARED_OWNER, } from "../resources/store.js";
20
20
  import { captureError } from "../server/capture-error.js";
21
21
  import { BuilderCredentialLookupError, CredentialStoreUnavailableError, } from "../server/credential-provider.js";
22
22
  import { runWithRequestContext, } from "../server/request-context.js";
@@ -146,6 +146,17 @@ export async function resolveBackgroundAutomationIdentity(automation) {
146
146
  const orgId = recoveredFactoryOwnerOrgId(automation.meta, automation.resource.path, automation.resource.owner) ??
147
147
  automation.meta.orgId ??
148
148
  undefined;
149
+ if (!orgId &&
150
+ automation.resource.owner !== "__shared__" &&
151
+ !organizationIdFromResourceOwner(automation.resource.owner)) {
152
+ const resolved = await resolveAutomationExecutionIdentity(automation.resource.owner, automation.meta);
153
+ if (!resolved.ok)
154
+ return resolved;
155
+ const validity = await validateAutomationRunIdentity(resolved.identity.userEmail);
156
+ if (!validity.ok)
157
+ return validity;
158
+ return resolved;
159
+ }
149
160
  const validity = await validateAutomationRunIdentity(userEmail, orgId);
150
161
  return validity.ok
151
162
  ? {
@@ -153,6 +164,9 @@ export async function resolveBackgroundAutomationIdentity(automation) {
153
164
  identity: {
154
165
  userEmail,
155
166
  orgId,
167
+ ...(!orgId && automation.resource.owner === SHARED_OWNER
168
+ ? { defaultAgentEngineScope: "deployment" }
169
+ : {}),
156
170
  eventOwner: userEmail.toLowerCase(),
157
171
  },
158
172
  }
@@ -555,7 +569,16 @@ async function resolveBackgroundAutomationModel(engine, automationModel, deps) {
555
569
  */
556
570
  export async function checkBackgroundAutomationCredentials(identity, deps, automationModel) {
557
571
  try {
558
- const { engine, model } = await runWithRequestContext({ userEmail: identity.ownerEmail, orgId: identity.orgId }, async () => {
572
+ const { engine, model } = await runWithRequestContext({
573
+ userEmail: identity.ownerEmail,
574
+ orgId: identity.orgId,
575
+ ...(identity.orgScope === "personal"
576
+ ? { orgScope: "personal" }
577
+ : {}),
578
+ ...(identity.defaultAgentEngineScope === "deployment"
579
+ ? { defaultAgentEngineScope: "deployment" }
580
+ : {}),
581
+ }, async () => {
559
582
  const engine = await resolveUsableBackgroundEngine(identity, deps, () => undefined);
560
583
  const model = await resolveBackgroundAutomationModel(engine, automationModel, deps);
561
584
  return { engine, model };