@agent-native/core 0.98.7 → 0.98.9

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 (81) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/core/CHANGELOG.md +12 -0
  3. package/corpus/core/docs/content/external-agents.mdx +17 -11
  4. package/corpus/core/docs/content/locales/ar-SA/external-agents.mdx +6 -2
  5. package/corpus/core/docs/content/locales/de-DE/external-agents.mdx +6 -2
  6. package/corpus/core/docs/content/locales/es-ES/external-agents.mdx +6 -2
  7. package/corpus/core/docs/content/locales/fr-FR/external-agents.mdx +6 -2
  8. package/corpus/core/docs/content/locales/hi-IN/external-agents.mdx +6 -2
  9. package/corpus/core/docs/content/locales/ja-JP/external-agents.mdx +6 -2
  10. package/corpus/core/docs/content/locales/ko-KR/external-agents.mdx +6 -2
  11. package/corpus/core/docs/content/locales/pt-BR/external-agents.mdx +6 -2
  12. package/corpus/core/docs/content/locales/zh-CN/external-agents.mdx +6 -2
  13. package/corpus/core/docs/content/locales/zh-TW/external-agents.mdx +6 -2
  14. package/corpus/core/package.json +1 -1
  15. package/corpus/core/src/client/session-replay.ts +29 -7
  16. package/corpus/core/src/integrations/adapters/slack.ts +13 -2
  17. package/corpus/core/src/integrations/pending-tasks-retry-job.ts +2 -1
  18. package/corpus/core/src/integrations/pending-tasks-store.ts +1 -1
  19. package/corpus/core/src/integrations/plugin.ts +183 -48
  20. package/corpus/core/src/integrations/types.ts +7 -0
  21. package/corpus/core/src/mcp/build-server.ts +99 -26
  22. package/corpus/templates/calendar/.agents/skills/event-management/SKILL.md +31 -2
  23. package/corpus/templates/calendar/AGENTS.md +11 -0
  24. package/corpus/templates/calendar/README.md +2 -1
  25. package/corpus/templates/calendar/actions/create-event.ts +7 -6
  26. package/corpus/templates/calendar/actions/event-action-helpers.ts +49 -0
  27. package/corpus/templates/calendar/actions/update-event.ts +225 -14
  28. package/corpus/templates/calendar/app/components/calendar/DayView.tsx +185 -70
  29. package/corpus/templates/calendar/app/components/calendar/EventCard.tsx +26 -4
  30. package/corpus/templates/calendar/app/components/calendar/EventDetailPanel.tsx +112 -69
  31. package/corpus/templates/calendar/app/components/calendar/EventDetailPopover.tsx +621 -524
  32. package/corpus/templates/calendar/app/components/calendar/WeekView.tsx +275 -164
  33. package/corpus/templates/calendar/app/components/calendar/WorkingLocationEditor.tsx +222 -0
  34. package/corpus/templates/calendar/app/hooks/use-events.ts +151 -79
  35. package/corpus/templates/calendar/app/i18n/zh-TW.ts +6 -0
  36. package/corpus/templates/calendar/app/i18n-data.ts +60 -0
  37. package/corpus/templates/calendar/app/lib/all-day-layout.ts +126 -0
  38. package/corpus/templates/calendar/app/lib/event-form-utils.ts +18 -1
  39. package/corpus/templates/calendar/app/lib/event-mutation-inputs.ts +1 -1
  40. package/corpus/templates/calendar/app/lib/working-location.ts +163 -0
  41. package/corpus/templates/calendar/app/pages/CalendarView.tsx +21 -2
  42. package/corpus/templates/calendar/changelog/2026-07-07-working-locations-from-google-calendar-now-appear-as-native-.md +6 -0
  43. package/corpus/templates/calendar/server/lib/calendar-availability.ts +2 -0
  44. package/corpus/templates/calendar/server/lib/google-api.ts +6 -1
  45. package/corpus/templates/calendar/server/lib/google-calendar.ts +49 -19
  46. package/corpus/templates/calendar/shared/api.ts +2 -0
  47. package/dist/client/session-replay.d.ts.map +1 -1
  48. package/dist/client/session-replay.js +24 -7
  49. package/dist/client/session-replay.js.map +1 -1
  50. package/dist/collab/routes.d.ts +2 -2
  51. package/dist/integrations/adapters/slack.js +11 -2
  52. package/dist/integrations/adapters/slack.js.map +1 -1
  53. package/dist/integrations/pending-tasks-retry-job.d.ts.map +1 -1
  54. package/dist/integrations/pending-tasks-retry-job.js +2 -1
  55. package/dist/integrations/pending-tasks-retry-job.js.map +1 -1
  56. package/dist/integrations/pending-tasks-store.js +1 -1
  57. package/dist/integrations/pending-tasks-store.js.map +1 -1
  58. package/dist/integrations/plugin.d.ts.map +1 -1
  59. package/dist/integrations/plugin.js +140 -34
  60. package/dist/integrations/plugin.js.map +1 -1
  61. package/dist/integrations/types.d.ts +7 -0
  62. package/dist/integrations/types.d.ts.map +1 -1
  63. package/dist/integrations/types.js.map +1 -1
  64. package/dist/mcp/build-server.d.ts.map +1 -1
  65. package/dist/mcp/build-server.js +82 -28
  66. package/dist/mcp/build-server.js.map +1 -1
  67. package/dist/notifications/routes.d.ts +1 -1
  68. package/dist/observability/routes.d.ts +5 -5
  69. package/dist/secrets/routes.d.ts +9 -9
  70. package/docs/content/external-agents.mdx +17 -11
  71. package/docs/content/locales/ar-SA/external-agents.mdx +6 -2
  72. package/docs/content/locales/de-DE/external-agents.mdx +6 -2
  73. package/docs/content/locales/es-ES/external-agents.mdx +6 -2
  74. package/docs/content/locales/fr-FR/external-agents.mdx +6 -2
  75. package/docs/content/locales/hi-IN/external-agents.mdx +6 -2
  76. package/docs/content/locales/ja-JP/external-agents.mdx +6 -2
  77. package/docs/content/locales/ko-KR/external-agents.mdx +6 -2
  78. package/docs/content/locales/pt-BR/external-agents.mdx +6 -2
  79. package/docs/content/locales/zh-CN/external-agents.mdx +6 -2
  80. package/docs/content/locales/zh-TW/external-agents.mdx +6 -2
  81. package/package.json +1 -1
package/corpus/README.md CHANGED
@@ -28,4 +28,4 @@ rg -n "defineAction|useActionQuery" node_modules/@agent-native/core/corpus
28
28
  ## Generated Counts
29
29
 
30
30
  - core files: 2239
31
- - template files: 5508
31
+ - template files: 5512
@@ -1,5 +1,17 @@
1
1
  # @agent-native/core
2
2
 
3
+ ## 0.98.9
4
+
5
+ ### Patch Changes
6
+
7
+ - 944c202: Preserve structured payloads from read-only MCP actions so external agents can inspect detailed records and replay data directly.
8
+
9
+ ## 0.98.8
10
+
11
+ ### Patch Changes
12
+
13
+ - 2065b5e: Deliver integration identity notices through the durable webhook queue, fail closed for anonymous Slack direct messages unless explicitly enabled, preserve verified identity through transient re-hydration failures, redact signed object URLs from replays, and bound retryable replay upload failures.
14
+
3
15
  ## 0.98.7
4
16
 
5
17
  ### Patch Changes
@@ -381,7 +381,7 @@ Apps that want direct tools to "just work" without maintaining a long allow-list
381
381
 
382
382
  ```ts
383
383
  export default createAgentChatPlugin({
384
- appId: "analytics",
384
+ appId: "example-app",
385
385
  externalAgents: {
386
386
  authenticatedReads: "auto",
387
387
  writes: "ask_app_only",
@@ -391,6 +391,8 @@ export default createAgentChatPlugin({
391
391
  });
392
392
  ```
393
393
 
394
+ This is a generic policy example. Analytics intentionally sets `authenticatedReads: "off"` and exposes only its reviewed `connectorCatalog` actions.
395
+
394
396
  `authenticatedReads: "auto"` adds only actions that explicitly declare all of the following:
395
397
 
396
398
  - `http: { method: "GET" }`
@@ -415,23 +417,27 @@ record. Actions must still use the normal `accessFilter`, `resolveAccess`, or
415
417
  shared resources follow their share/org rules, and cross-organization reads are
416
418
  rejected.
417
419
 
420
+ An app that supplies `resolveExecutionContext` explicitly replaces this default identity ladder. Its resolver must independently reject unverified callers, guests, external members, and unlinked workspaces before returning a principal.
421
+
418
422
  The default Slack integration follows the same rule. A verified Slack DM is
419
423
  matched to an existing Agent Native organization member and persisted as a
420
424
  workspace/user identity link before the agent runs, and the resulting user/org
421
- context loads that user's resources, instructions, and skills. Hydrated
422
- workspace members whose email is missing or not yet an organization member run
423
- as an anonymous org-scoped service principal instead — the same
424
- org-wide-visibility tier shared channels get with an agent-visible note and
425
- a one-time Slack heads-up explaining how to gain personal access. Hydration
426
- failures, guests and external (Slack Connect) members, and workspaces not
427
- connected to an organization receive a polite decline reply instead of a
428
- silent drop. Shared Slack channels use a service principal instead of
425
+ context loads that user's resources, instructions, and skills. By default, a
426
+ hydrated workspace member whose email is missing or is not yet an organization
427
+ member is declined. Apps may explicitly set
428
+ `allowAnonymousOrgScopedSlackDm: true` to run those members as an anonymous
429
+ org-scoped service principal instead the same org-wide-visibility tier shared
430
+ channels get, never user-private access with an agent-visible note and a
431
+ one-time Slack heads-up explaining how to gain personal access. This opt-in
432
+ never admits hydration failures, unverified callers, guests or external (Slack
433
+ Connect) members, or workspaces not connected to an organization; those receive
434
+ a polite decline reply instead of a silent drop. Shared Slack channels use a service principal instead of
429
435
  borrowing one participant's private permissions. Managed Slack OAuth requests
430
436
  the `users:read.email` bot scope, and the generated Slack app manifest
431
437
  requests it too. Existing Slack installs must be reconnected/reinstalled to
432
438
  grant a newly added scope; legacy bot-token installs must add the scope in
433
- Slack manually. Without it, DMs run in the anonymous org-scoped tier rather
434
- than with personal access.
439
+ Slack manually. Without it, DMs fail closed unless the app explicitly enables
440
+ `allowAnonymousOrgScopedSlackDm`.
435
441
 
436
442
  ### Full tier (explicit opt-in only) {#full-tier}
437
443
 
@@ -380,7 +380,7 @@ https://dispatch.agent-native.com/_agent-native/mcp
380
380
 
381
381
  ```ts
382
382
  export default createAgentChatPlugin({
383
- appId: "analytics",
383
+ appId: "example-app",
384
384
  externalAgents: {
385
385
  authenticatedReads: "auto",
386
386
  writes: "ask_app_only",
@@ -390,6 +390,8 @@ export default createAgentChatPlugin({
390
390
  });
391
391
  ```
392
392
 
393
+ هذا مثال عام للسياسة. يضبط Analytics الخيار `authenticatedReads: "off"` عمدًا، ولا يعرض سوى إجراءات `connectorCatalog` التي خضعت للمراجعة.
394
+
393
395
  يضيف `authenticatedReads: "auto"` فقط الإجراءات التي تعلن صراحةً كل ما يلي:
394
396
 
395
397
  - `http: { method: "GET" }`
@@ -404,7 +406,9 @@ export default createAgentChatPlugin({
404
406
 
405
407
  هذا استبعاد صارم يعتمد على الاسم، وليس مجرد إغفال في البيانات الوصفية: أدوات قاعدة البيانات وseed وجلسة المتصفح والامتدادات وسياق الأشعة السينية العامة لا يُكشف عنها تلقائيًا أبدًا، حتى لو وسم تغيير مستقبلي إحداها عن طريق الخطأ بمجموعة أعلام القراءة المصادق عليها الكاملة — فهي تتطلب دائمًا إدخالًا صريحًا في `connectorCatalog`.
406
408
 
407
- تطابق رسائل Slack الخاصة التي تم التحقق منها عضوًا موجودًا في مؤسسة Agent Native، وتحفظ رابط هوية مساحة العمل/المستخدم قبل تشغيل الوكيل؛ ثم يحمّل سياق المستخدم/المؤسسة الناتج موارد ذلك المستخدم وتعليماته ومهاراته. أما أعضاء مساحة العمل الذين نجحت عملية جلب بياناتهم لكن بريدهم الإلكتروني مفقود أو لم ينضموا بعد إلى المؤسسة، فيعملون بهوية خدمة مجهولة ضمن نطاق المؤسسة — وهي طبقة الرؤية نفسها على مستوى المؤسسة التي تستخدمها القنوات المشتركة مع ملاحظة يراها الوكيل وتنبيه لمرة واحدة في Slack يشرح كيفية الحصول على وصول شخصي. تتلقى حالات فشل جلب البيانات والضيوف والأعضاء الخارجيون (Slack Connect) ومساحات العمل غير المرتبطة بمؤسسة ردًا مهذبًا بالرفض بدل إسقاط الرسالة بصمت. تستخدم قنوات Slack المشتركة هوية خدمة ولا تستعير الأذونات الخاصة لأي مشارك. يطلب OAuth المُدار والنموذج المُنشأ لتطبيق Slack نطاق البوت `users:read.email`. يجب إعادة ربط/تثبيت عمليات التثبيت الحالية لمنح نطاق أُضيف حديثًا، بينما يجب أن تضيف عمليات التثبيت القديمة التي تستخدم رمز بوت النطاق يدويًا في Slack. من دونه، تعمل الرسائل الخاصة ضمن الطبقة المجهولة ذات نطاق المؤسسة بدل الوصول الشخصي.
409
+ يستبدل التطبيق الذي يوفّر `resolveExecutionContext` تسلسل الهوية الافتراضي هذا صراحةً. ويجب على أداة الحل الخاصة به أن ترفض بشكل مستقل المتصلين غير المتحقق منهم والضيوف والأعضاء الخارجيين ومساحات العمل غير المرتبطة قبل إرجاع هوية رئيسية.
410
+
411
+ تطابق رسائل Slack الخاصة التي تم التحقق منها عضوًا موجودًا في مؤسسة Agent Native، وتحفظ رابط هوية مساحة العمل/المستخدم قبل تشغيل الوكيل؛ ثم يحمّل سياق المستخدم/المؤسسة الناتج موارد ذلك المستخدم وتعليماته ومهاراته. يُرفض افتراضيًا عضو مساحة العمل الذي نجح جلب بياناته لكن بريده الإلكتروني مفقود أو لم ينضم بعد إلى المؤسسة. يمكن للتطبيقات ضبط `allowAnonymousOrgScopedSlackDm: true` صراحةً لتشغيل هؤلاء الأعضاء بهوية خدمة مجهولة ضمن نطاق المؤسسة — وهي طبقة الرؤية نفسها على مستوى المؤسسة التي تستخدمها القنوات المشتركة، من دون أي وصول خاص بالمستخدم — مع ملاحظة يراها الوكيل وتنبيه لمرة واحدة في Slack يشرح كيفية الحصول على وصول شخصي. لا يسمح هذا الاشتراك أبدًا بحالات فشل جلب البيانات أو المتصلين غير المتحقق منهم أو الضيوف أو الأعضاء الخارجيين (Slack Connect) أو مساحات العمل غير المرتبطة بمؤسسة؛ بل تتلقى هذه الحالات ردًا مهذبًا بالرفض بدل إسقاط الرسالة بصمت. تستخدم قنوات Slack المشتركة هوية خدمة ولا تستعير الأذونات الخاصة لأي مشارك. يطلب OAuth المُدار والنموذج المُنشأ لتطبيق Slack نطاق البوت `users:read.email`. يجب إعادة ربط/تثبيت عمليات التثبيت الحالية لمنح نطاق أُضيف حديثًا، بينما يجب أن تضيف عمليات التثبيت القديمة التي تستخدم رمز بوت النطاق يدويًا في Slack. ومن دونه، تُرفض الرسائل الخاصة ما لم يفعّل التطبيق `allowAnonymousOrgScopedSlackDm` صراحةً.
408
412
 
409
413
  ### الطبقة الكاملة (الاشتراك الصريح فقط) {#full-tier}
410
414
 
@@ -382,7 +382,7 @@ Apps, deren direkte Lesetools ohne lange Zulassungsliste funktionieren sollen, k
382
382
 
383
383
  ```ts
384
384
  export default createAgentChatPlugin({
385
- appId: "analytics",
385
+ appId: "example-app",
386
386
  externalAgents: {
387
387
  authenticatedReads: "auto",
388
388
  writes: "ask_app_only",
@@ -392,6 +392,8 @@ export default createAgentChatPlugin({
392
392
  });
393
393
  ```
394
394
 
395
+ Dies ist ein allgemeines Richtlinienbeispiel. Analytics setzt `authenticatedReads: "off"` absichtlich und stellt nur die geprüften `connectorCatalog`-Actions bereit.
396
+
395
397
  `authenticatedReads: "auto"` fügt nur Actions hinzu, die ausdrücklich alle folgenden Merkmale deklarieren:
396
398
 
397
399
  - `http: { method: "GET" }`
@@ -406,7 +408,9 @@ Core-`db-schema` und `db-query` werden nicht automatisch als externe Lesezugriff
406
408
 
407
409
  Dies ist ein harter, namensbasierter Ausschluss und keine bloße Auslassung in den Metadaten: generische Datenbank-, Seed-, Browser-Sitzungs-, Erweiterungs- und Kontext-Röntgen-Tools werden niemals automatisch freigegeben, selbst wenn eine zukünftige Änderung eines davon versehentlich mit dem vollständigen Satz an Flags für authentifizierte Lesezugriffe versieht — sie benötigen immer einen expliziten `connectorCatalog`-Eintrag.
408
410
 
409
- Eine verifizierte Slack-DM wird vor dem Start des Agenten einem bestehenden Mitglied der Agent-Native-Organisation zugeordnet und als Identitätsverknüpfung zwischen Workspace und Benutzer gespeichert. Der daraus entstehende Benutzer-/Organisationskontext lädt die Ressourcen, Anweisungen und Skills dieses Benutzers. Erfolgreich geladene Workspace-Mitglieder, deren E-Mail-Adresse fehlt oder die noch kein Organisationsmitglied sind, werden stattdessen als anonymer, auf die Organisation begrenzter Service-Principal ausgeführt — mit derselben organisationsweiten Sichtbarkeit wie gemeinsame Kanäle. Der Agent erhält dazu einen sichtbaren Hinweis, und Slack erklärt einmalig, wie persönlicher Zugriff erlangt werden kann. Bei fehlgeschlagener Profilladung, Gästen und externen Mitgliedern (Slack Connect) sowie Workspaces ohne Organisationsverknüpfung wird höflich abgelehnt, statt die Nachricht stillschweigend zu verwerfen. Gemeinsame Slack-Kanäle verwenden einen Service-Principal und übernehmen keine privaten Berechtigungen eines Teilnehmers. Managed OAuth und das generierte Slack-App-Manifest fordern den Bot-Scope `users:read.email`. Bestehende Installationen müssen erneut verbunden/installiert werden, um einen neu hinzugefügten Scope zu gewähren; ältere Bot-Token-Installationen müssen ihn in Slack manuell hinzufügen. Ohne diesen Scope werden DMs in der anonymen, organisationsbegrenzten Stufe statt mit persönlichem Zugriff ausgeführt.
411
+ Eine App, die `resolveExecutionContext` bereitstellt, ersetzt diese standardmäßige Identitätsprüfung ausdrücklich. Ihr Resolver muss nicht verifizierte Aufrufer, Gäste, externe Mitglieder und nicht verknüpfte Workspaces eigenständig ablehnen, bevor er einen Principal zurückgibt.
412
+
413
+ Eine verifizierte Slack-DM wird vor dem Start des Agenten einem bestehenden Mitglied der Agent-Native-Organisation zugeordnet und als Identitätsverknüpfung zwischen Workspace und Benutzer gespeichert. Der daraus entstehende Benutzer-/Organisationskontext lädt die Ressourcen, Anweisungen und Skills dieses Benutzers. Standardmäßig werden erfolgreich geladene Workspace-Mitglieder abgelehnt, wenn ihre E-Mail-Adresse fehlt oder sie noch kein Organisationsmitglied sind. Apps können ausdrücklich `allowAnonymousOrgScopedSlackDm: true` setzen, um diese Mitglieder stattdessen als anonymen, auf die Organisation begrenzten Service-Principal auszuführen — mit derselben organisationsweiten Sichtbarkeit wie gemeinsame Kanäle, aber niemals mit benutzerprivatem Zugriff. Der Agent erhält dazu einen sichtbaren Hinweis, und Slack erklärt einmalig, wie persönlicher Zugriff erlangt werden kann. Dieses Opt-in lässt niemals fehlgeschlagene Profilladungen, nicht verifizierte Aufrufer, Gäste, externe Mitglieder (Slack Connect) oder Workspaces ohne Organisationsverknüpfung zu; diese werden höflich abgelehnt, statt die Nachricht stillschweigend zu verwerfen. Gemeinsame Slack-Kanäle verwenden einen Service-Principal und übernehmen keine privaten Berechtigungen eines Teilnehmers. Managed OAuth und das generierte Slack-App-Manifest fordern den Bot-Scope `users:read.email`. Bestehende Installationen müssen erneut verbunden/installiert werden, um einen neu hinzugefügten Scope zu gewähren; ältere Bot-Token-Installationen müssen ihn in Slack manuell hinzufügen. Ohne diesen Scope werden DMs abgelehnt, sofern die App `allowAnonymousOrgScopedSlackDm` nicht ausdrücklich aktiviert.
410
414
 
411
415
  ### Vollständige Stufe (nur explizites Opt-in) {#full-tier}
412
416
 
@@ -382,7 +382,7 @@ Las aplicaciones que quieran que las herramientas de lectura directas funcionen
382
382
 
383
383
  ```ts
384
384
  export default createAgentChatPlugin({
385
- appId: "analytics",
385
+ appId: "example-app",
386
386
  externalAgents: {
387
387
  authenticatedReads: "auto",
388
388
  writes: "ask_app_only",
@@ -392,6 +392,8 @@ export default createAgentChatPlugin({
392
392
  });
393
393
  ```
394
394
 
395
+ Este es un ejemplo genérico de la política. Analytics configura intencionadamente `authenticatedReads: "off"` y solo expone las actions revisadas de `connectorCatalog`.
396
+
395
397
  `authenticatedReads: "auto"` añade solo las actions que declaran explícitamente todo lo siguiente:
396
398
 
397
399
  - `http: { method: "GET" }`
@@ -406,7 +408,9 @@ La política es autenticada, no anónima. La identidad de MCP OAuth/connect se c
406
408
 
407
409
  Se trata de una exclusión estricta basada en el nombre, no solo de una omisión de metadatos: las herramientas genéricas de base de datos, seed, sesión del navegador, extensiones y rayos X de contexto nunca se exponen automáticamente, aunque un cambio futuro anote alguna de ellas por error con el conjunto completo de indicadores de lectura autenticada — siempre requieren una entrada explícita en `connectorCatalog`.
408
410
 
409
- Antes de ejecutar el agente, un mensaje directo verificado de Slack se asocia a un miembro existente de la organización de Agent Native y se guarda el vínculo de identidad entre el espacio de trabajo y el usuario. El contexto resultante del usuario y la organización carga los recursos, las instrucciones y las habilidades de ese usuario. Los miembros del espacio de trabajo cuyo perfil se ha obtenido correctamente, pero que no tienen correo electrónico o aún no pertenecen a la organización, se ejecutan como un principal de servicio anónimo limitado a la organización: el mismo nivel de visibilidad para toda la organización que usan los canales compartidos. El agente recibe una nota visible y Slack muestra una sola vez cómo obtener acceso personal. Si falla la obtención del perfil, si se trata de invitados o miembros externos (Slack Connect), o si el espacio de trabajo no está conectado a una organización, se envía una respuesta cortés de rechazo en vez de descartar el mensaje en silencio. Los canales compartidos de Slack usan un principal de servicio y no heredan los permisos privados de ningún participante. OAuth administrado y el manifiesto generado de la aplicación de Slack solicitan el ámbito de bot `users:read.email`. Las instalaciones existentes deben volver a conectarse o instalarse para conceder un ámbito recién añadido; las instalaciones antiguas con token de bot deben añadirlo manualmente en Slack. Sin él, los mensajes directos se ejecutan en el nivel anónimo limitado a la organización, no con acceso personal.
411
+ Una aplicación que proporciona `resolveExecutionContext` sustituye explícitamente esta secuencia de identidad predeterminada. Su resolver debe rechazar de forma independiente a los autores no verificados, invitados, miembros externos y espacios de trabajo no vinculados antes de devolver un principal.
412
+
413
+ Antes de ejecutar el agente, un mensaje directo verificado de Slack se asocia a un miembro existente de la organización de Agent Native y se guarda el vínculo de identidad entre el espacio de trabajo y el usuario. El contexto resultante del usuario y la organización carga los recursos, las instrucciones y las habilidades de ese usuario. De forma predeterminada, se rechaza a los miembros del espacio de trabajo cuyo perfil se obtuvo correctamente pero que no tienen correo electrónico o aún no pertenecen a la organización. Las aplicaciones pueden configurar explícitamente `allowAnonymousOrgScopedSlackDm: true` para ejecutar a esos miembros como un principal de servicio anónimo limitado a la organización: el mismo nivel de visibilidad para toda la organización que usan los canales compartidos, pero nunca acceso privado del usuario. El agente recibe una nota visible y Slack muestra una sola vez cómo obtener acceso personal. Esta opción nunca admite fallos de obtención del perfil, autores no verificados, invitados, miembros externos (Slack Connect) ni espacios de trabajo no vinculados a una organización; esos casos reciben una respuesta cortés de rechazo. Los canales compartidos de Slack usan un principal de servicio y no heredan los permisos privados de ningún participante. OAuth administrado y el manifiesto generado de la aplicación de Slack solicitan el ámbito de bot `users:read.email`. Las instalaciones existentes deben volver a conectarse o instalarse para conceder un ámbito recién añadido; las instalaciones antiguas con token de bot deben añadirlo manualmente en Slack. Sin él, los mensajes directos se rechazan salvo que la aplicación habilite explícitamente `allowAnonymousOrgScopedSlackDm`.
410
414
 
411
415
  ### Nivel completo (solo suscripción explícita) {#full-tier}
412
416
 
@@ -382,7 +382,7 @@ Les applications qui souhaitent que les outils de lecture directe fonctionnent s
382
382
 
383
383
  ```ts
384
384
  export default createAgentChatPlugin({
385
- appId: "analytics",
385
+ appId: "example-app",
386
386
  externalAgents: {
387
387
  authenticatedReads: "auto",
388
388
  writes: "ask_app_only",
@@ -392,6 +392,8 @@ export default createAgentChatPlugin({
392
392
  });
393
393
  ```
394
394
 
395
+ Il s'agit d'un exemple de politique générique. Analytics définit intentionnellement `authenticatedReads: "off"` et n'expose que les actions `connectorCatalog` qui ont été examinées.
396
+
395
397
  `authenticatedReads: "auto"` ajoute uniquement les actions qui déclarent explicitement tous les éléments suivants :
396
398
 
397
399
  - `http: { method: "GET" }`
@@ -406,7 +408,9 @@ Les outils Core `db-schema` et `db-query` ne sont pas automatiquement exposés c
406
408
 
407
409
  Il s'agit d'une exclusion stricte basée sur le nom, et non d'une simple omission de métadonnées : les outils génériques de base de données, de seed, de session de navigateur, d'extensions et de radiographie contextuelle ne sont jamais exposés automatiquement, même si une modification future annote accidentellement l'un d'eux avec l'ensemble complet des indicateurs de lecture authentifiée — ils nécessitent toujours une entrée explicite dans `connectorCatalog`.
408
410
 
409
- Avant l'exécution de l'agent, un message direct Slack vérifié est associé à un membre existant de l'organisation Agent Native et le lien d'identité entre l'espace de travail et l'utilisateur est enregistré. Le contexte utilisateur/organisation qui en résulte charge les ressources, les instructions et les compétences de cet utilisateur. Les membres de l'espace de travail dont le profil a bien été chargé, mais dont l'adresse e-mail est absente ou qui ne sont pas encore membres de l'organisation, sont exécutés comme principal de service anonyme limité à l'organisation : le même niveau de visibilité à l'échelle de l'organisation que celui des canaux partagés. L'agent reçoit une note visible et Slack explique une fois comment obtenir un accès personnel. En cas d'échec du chargement du profil, pour les invités et membres externes (Slack Connect), ou pour les espaces de travail non connectés à une organisation, une réponse de refus polie est envoyée au lieu d'ignorer silencieusement le message. Les canaux Slack partagés utilisent un principal de service et n'empruntent pas les autorisations privées d'un participant. OAuth géré et le manifeste d'application Slack généré demandent la portée de bot `users:read.email`. Les installations existantes doivent être reconnectées ou réinstallées pour accorder une portée nouvellement ajoutée ; les anciennes installations par jeton de bot doivent l'ajouter manuellement dans Slack. Sans cette portée, les messages directs s'exécutent dans le niveau anonyme limité à l'organisation plutôt qu'avec un accès personnel.
411
+ Une application qui fournit `resolveExecutionContext` remplace explicitement cette chaîne d'identité par défaut. Son résolveur doit refuser indépendamment les appelants non vérifiés, les invités, les membres externes et les espaces de travail non liés avant de renvoyer un principal.
412
+
413
+ Avant l'exécution de l'agent, un message direct Slack vérifié est associé à un membre existant de l'organisation Agent Native et le lien d'identité entre l'espace de travail et l'utilisateur est enregistré. Le contexte utilisateur/organisation qui en résulte charge les ressources, les instructions et les compétences de cet utilisateur. Par défaut, les membres de l'espace de travail dont le profil a bien été chargé, mais dont l'adresse e-mail est absente ou qui ne sont pas encore membres de l'organisation, sont refusés. Les applications peuvent définir explicitement `allowAnonymousOrgScopedSlackDm: true` pour exécuter ces membres comme principal de service anonyme limité à l'organisation : le même niveau de visibilité à l'échelle de l'organisation que celui des canaux partagés, sans jamais accéder aux données privées de l'utilisateur. L'agent reçoit une note visible et Slack explique une fois comment obtenir un accès personnel. Cette option n'admet jamais les échecs de chargement du profil, les appelants non vérifiés, les invités, les membres externes (Slack Connect) ni les espaces de travail non liés à une organisation ; ces cas reçoivent une réponse de refus polie. Les canaux Slack partagés utilisent un principal de service et n'empruntent pas les autorisations privées d'un participant. OAuth géré et le manifeste d'application Slack généré demandent la portée de bot `users:read.email`. Les installations existantes doivent être reconnectées ou réinstallées pour accorder une portée nouvellement ajoutée ; les anciennes installations par jeton de bot doivent l'ajouter manuellement dans Slack. Sans cette portée, les messages directs sont refusés sauf si l'application active explicitement `allowAnonymousOrgScopedSlackDm`.
410
414
 
411
415
  ### Niveau complet (adhésion explicite uniquement) {#full-tier}
412
416
 
@@ -380,7 +380,7 @@ MCP सर्वर प्रत्येक कॉलर को डिफ़ॉ
380
380
 
381
381
  ```ts
382
382
  export default createAgentChatPlugin({
383
- appId: "analytics",
383
+ appId: "example-app",
384
384
  externalAgents: {
385
385
  authenticatedReads: "auto",
386
386
  writes: "ask_app_only",
@@ -390,6 +390,8 @@ export default createAgentChatPlugin({
390
390
  });
391
391
  ```
392
392
 
393
+ यह नीति का सामान्य उदाहरण है। Analytics जानबूझकर `authenticatedReads: "off"` सेट करता है और केवल समीक्षा किए गए `connectorCatalog` actions को उपलब्ध कराता है।
394
+
393
395
  `authenticatedReads: "auto"` केवल उन actions को जोड़ता है जो स्पष्ट रूप से ये सभी घोषित करते हैं:
394
396
 
395
397
  - `http: { method: "GET" }`
@@ -404,7 +406,9 @@ Core के `db-schema` और `db-query` को स्वचालित बा
404
406
 
405
407
  यह नाम-आधारित सख्त बहिष्करण है, केवल मेटाडेटा की चूक नहीं: सामान्य डेटाबेस/seed/ब्राउज़र-सत्र/एक्सटेंशन/संदर्भ-एक्सरे टूल कभी भी स्वचालित रूप से उजागर नहीं होते, भले ही भविष्य का कोई बदलाव गलती से इनमें से किसी एक को पूर्ण authenticated-read फ़्लैग सेट के साथ चिह्नित कर दे — उन्हें हमेशा एक स्पष्ट `connectorCatalog` प्रविष्टि की आवश्यकता होती है।
406
408
 
407
- एजेंट चलने से पहले सत्यापित Slack DM को Agent Native संगठन के किसी मौजूदा सदस्य से मिलाया जाता है और workspace/user पहचान लिंक सहेजा जाता है। इससे बने user/org संदर्भ में उस उपयोगकर्ता के संसाधन, निर्देश और skills लोड होते हैं। जिन workspace सदस्यों का प्रोफ़ाइल सफलतापूर्वक मिला है लेकिन ईमेल उपलब्ध नहीं है या वे अभी संगठन के सदस्य नहीं हैं, वे इसके बजाय संगठन-स्कोप वाले अनाम service principal के रूप में चलते हैं — साझा चैनलों वाली संगठन-व्यापी दृश्यता के उसी स्तर पर — साथ में एजेंट को दिखाई देने वाला नोट और व्यक्तिगत पहुँच पाने का तरीका बताने वाली एक बार की Slack सूचना। प्रोफ़ाइल लोड न होने, मेहमान या बाहरी (Slack Connect) सदस्य होने, या workspace के किसी संगठन से जुड़े होने पर संदेश को चुपचाप छोड़ने के बजाय विनम्र अस्वीकृति भेजी जाती है। साझा Slack चैनल service principal का उपयोग करते हैं और किसी प्रतिभागी की निजी permissions नहीं लेते। Managed OAuth और generated Slack app manifest दोनों bot scope `users:read.email` मांगते हैं। नया scope देने के लिए मौजूदा installations को reconnect/reinstall करना होगा; पुराने bot-token installations को इसे Slack में manually जोड़ना होगा। इसके बिना DM व्यक्तिगत पहुँच के बजाय संगठन-स्कोप वाले अनाम स्तर में चलते हैं।
409
+ `resolveExecutionContext` देने वाला ऐप इस डिफ़ॉल्ट पहचान क्रम को स्पष्ट रूप से बदल देता है। उसके resolver को principal लौटाने से पहले असत्यापित callers, guests, external members और unlinked workspaces को स्वतंत्र रूप से अस्वीकार करना होगा।
410
+
411
+ एजेंट चलने से पहले सत्यापित Slack DM को Agent Native संगठन के किसी मौजूदा सदस्य से मिलाया जाता है और workspace/user पहचान लिंक सहेजा जाता है। इससे बने user/org संदर्भ में उस उपयोगकर्ता के संसाधन, निर्देश और skills लोड होते हैं। डिफ़ॉल्ट रूप से सफलतापूर्वक प्रोफ़ाइल मिले ऐसे workspace सदस्य अस्वीकार किए जाते हैं जिनका ईमेल उपलब्ध नहीं है या जो अभी संगठन के सदस्य नहीं हैं। ऐप इन सदस्यों को संगठन-स्कोप वाले अनाम service principal के रूप में चलाने के लिए स्पष्ट रूप से `allowAnonymousOrgScopedSlackDm: true` सेट कर सकते हैं — साझा चैनलों वाली संगठन-व्यापी दृश्यता के उसी स्तर पर, लेकिन कभी भी उपयोगकर्ता-निजी पहुँच के साथ नहीं — साथ में एजेंट को दिखाई देने वाला नोट और व्यक्तिगत पहुँच पाने का तरीका बताने वाली एक बार की Slack सूचना। यह opt-in प्रोफ़ाइल लोड न होने, असत्यापित callers, guests, external (Slack Connect) members या किसी संगठन से न जुड़े workspace को कभी अनुमति नहीं देता; उन्हें विनम्र अस्वीकृति मिलती है। साझा Slack चैनल service principal का उपयोग करते हैं और किसी प्रतिभागी की निजी permissions नहीं लेते। Managed OAuth और generated Slack app manifest दोनों bot scope `users:read.email` मांगते हैं। नया scope देने के लिए मौजूदा installations को reconnect/reinstall करना होगा; पुराने bot-token installations को इसे Slack में manually जोड़ना होगा। इसके बिना DM fail closed होते हैं, जब तक ऐप स्पष्ट रूप से `allowAnonymousOrgScopedSlackDm` सक्षम न करे।
408
412
 
409
413
  ### पूर्ण स्तरीय (केवल स्पष्ट ऑप्ट-इन) {#full-tier}
410
414
 
@@ -380,7 +380,7 @@ MCP サーバーは、ホスト型コネクタ (ChatGPT、Claude)、コード
380
380
 
381
381
  ```ts
382
382
  export default createAgentChatPlugin({
383
- appId: "analytics",
383
+ appId: "example-app",
384
384
  externalAgents: {
385
385
  authenticatedReads: "auto",
386
386
  writes: "ask_app_only",
@@ -390,6 +390,8 @@ export default createAgentChatPlugin({
390
390
  });
391
391
  ```
392
392
 
393
+ これは一般的なポリシーの例です。Analytics は意図的に `authenticatedReads: "off"` を設定し、レビュー済みの `connectorCatalog` アクションだけを公開します。
394
+
393
395
  `authenticatedReads: "auto"` が追加するのは、次のすべてを明示的に宣言したアクションだけです。
394
396
 
395
397
  - `http: { method: "GET" }`
@@ -404,7 +406,9 @@ Core の `db-schema` と `db-query` は外部の自動読み取りとして公
404
406
 
405
407
  これは名前ベースの厳格な除外であり、単なるメタデータの記載漏れではありません。汎用のデータベース、seed、ブラウザ セッション、拡張、コンテキスト Xray のツールは、将来の変更で誤って完全な認証済み読み取りフラグセットが付与された場合でも、自動的に公開されることは決してありません — これらには常に明示的な `connectorCatalog` エントリが必要です。
406
408
 
407
- 検証済みの Slack DM は、エージェントを実行する前に既存の Agent Native 組織メンバーと照合され、ワークスペース/ユーザーの ID リンクとして保存されます。生成されたユーザー/組織コンテキストには、そのユーザーのリソース、指示、スキルが読み込まれます。プロフィールの取得には成功したものの、メールアドレスがない、またはまだ組織メンバーではないワークスペース メンバーは、代わりに組織スコープの匿名サービスプリンシパルとして実行されます。これは共有チャンネルと同じ組織全体の可視性レベルであり、エージェントに表示される注記と、個人アクセスの取得方法を説明する 1 回限りの Slack 通知が付きます。プロフィール取得の失敗、ゲストや外部 (Slack Connect) メンバー、組織に接続されていないワークスペースには、メッセージを黙って破棄せず、丁寧な拒否応答を返します。Slack の共有チャンネルはサービスプリンシパルを使い、参加者の個人的な権限を借用しません。管理対象 OAuth と生成される Slack アプリ マニフェストは、bot スコープ `users:read.email` を要求します。新たに追加されたスコープを付与するには、既存のインストールを再接続/再インストールする必要があります。従来の bot トークンによるインストールでは、Slack でスコープを手動追加してください。このスコープがない場合、DM は個人アクセスではなく組織スコープの匿名レベルで実行されます。
409
+ `resolveExecutionContext` を指定するアプリは、このデフォルトの ID 判定を明示的に置き換えます。そのリゾルバーはプリンシパルを返す前に、未検証の呼び出し元、ゲスト、外部メンバー、未接続のワークスペースを独自に拒否する必要があります。
410
+
411
+ 検証済みの Slack DM は、エージェントを実行する前に既存の Agent Native 組織メンバーと照合され、ワークスペース/ユーザーの ID リンクとして保存されます。生成されたユーザー/組織コンテキストには、そのユーザーのリソース、指示、スキルが読み込まれます。デフォルトでは、プロフィールの取得に成功しても、メールアドレスがない、またはまだ組織メンバーではないワークスペース メンバーは拒否されます。アプリは `allowAnonymousOrgScopedSlackDm: true` を明示的に設定することで、それらのメンバーを組織スコープの匿名サービスプリンシパルとして実行できます。これは共有チャンネルと同じ組織全体の可視性レベルですが、ユーザーの非公開データには決してアクセスしません。エージェントに表示される注記と、個人アクセスの取得方法を説明する 1 回限りの Slack 通知が付きます。この opt-in は、プロフィール取得の失敗、未検証の呼び出し元、ゲストや外部 (Slack Connect) メンバー、組織に接続されていないワークスペースを許可しません。それらには丁寧な拒否応答を返します。Slack の共有チャンネルはサービスプリンシパルを使い、参加者の個人的な権限を借用しません。管理対象 OAuth と生成される Slack アプリ マニフェストは、bot スコープ `users:read.email` を要求します。新たに追加されたスコープを付与するには、既存のインストールを再接続/再インストールする必要があります。従来の bot トークンによるインストールでは、Slack でスコープを手動追加してください。このスコープがない場合、アプリが `allowAnonymousOrgScopedSlackDm` を明示的に有効にしない限り、DM は拒否されます。
408
412
 
409
413
  ### フルティア (明示的なオプトインのみ) {#full-tier}
410
414
 
@@ -380,7 +380,7 @@ MCP 서버는 호스팅된 커넥터(ChatGPT, Claude), 코드 클라이언트(Cl
380
380
 
381
381
  ```ts
382
382
  export default createAgentChatPlugin({
383
- appId: "analytics",
383
+ appId: "example-app",
384
384
  externalAgents: {
385
385
  authenticatedReads: "auto",
386
386
  writes: "ask_app_only",
@@ -390,6 +390,8 @@ export default createAgentChatPlugin({
390
390
  });
391
391
  ```
392
392
 
393
+ 이는 일반적인 정책 예시입니다. Analytics는 의도적으로 `authenticatedReads: "off"`를 설정하고 검토된 `connectorCatalog` action만 노출합니다.
394
+
393
395
  `authenticatedReads: "auto"`는 다음을 모두 명시적으로 선언한 action만 추가합니다.
394
396
 
395
397
  - `http: { method: "GET" }`
@@ -404,7 +406,9 @@ Core `db-schema`와 `db-query`는 자동 외부 읽기로 공개되지 않습니
404
406
 
405
407
  이는 이름 기반의 강력한 제외이며 단순한 메타데이터 누락이 아닙니다. 일반 데이터베이스, seed, 브라우저 세션, 확장, context-xray 도구는 향후 변경으로 인해 실수로 전체 인증된 읽기 플래그 집합이 지정되더라도 절대 자동으로 노출되지 않습니다 — 이러한 도구는 항상 명시적인 `connectorCatalog` 항목이 필요합니다.
406
408
 
407
- 검증된 Slack DM은 에이전트가 실행되기 전에 기존 Agent Native 조직 구성원과 연결되고 workspace/user ID 링크로 저장됩니다. 결과 생성된 사용자/조직 컨텍스트에는 해당 사용자의 리소스, 지침 및 skills가 로드됩니다. 프로필을 정상적으로 가져왔지만 이메일이 없거나 아직 조직 구성원이 아닌 workspace 구성원은 조직 범위의 익명 service principal 실행됩니다. 이는 공유 채널과 동일한 조직 전체 공개 수준이며, 에이전트에 표시되는 메모와 개인 액세스를 얻는 방법을 설명하는 일회성 Slack 안내가 함께 제공됩니다. 프로필 가져오기 실패, 게스트 및 외부(Slack Connect) 구성원, 조직에 연결되지 않은 workspace에는 메시지를 조용히 버리는 대신 정중한 거절 응답을 보냅니다. Slack 공유 채널은 service principal을 사용하며 참여자의 개인 권한을 빌리지 않습니다. 관리형 OAuth와 생성된 Slack 앱 매니페스트는 모두 bot scope `users:read.email`을 요청합니다. 새로 추가된 scope부여하려면 기존 설치를 다시 연결/설치해야 하며, 이전 bot-token 설치는 Slack에서 scope를 수동으로 추가해야 합니다. 이 scope가 없으면 DM은 개인 액세스 대신 조직 범위의 익명 수준에서 실행됩니다.
409
+ `resolveExecutionContext`를 제공하는 앱은 기본 ID 확인 절차를 명시적으로 대체합니다. 해당 resolver는 principal 반환하기 전에 검증되지 않은 호출자, 게스트, 외부 구성원, 연결되지 않은 workspace를 독립적으로 거부해야 합니다.
410
+
411
+ 검증된 Slack DM은 에이전트가 실행되기 전에 기존 Agent Native 조직 구성원과 연결되고 workspace/user ID 링크로 저장됩니다. 그 결과 생성된 사용자/조직 컨텍스트에는 해당 사용자의 리소스, 지침 및 skills가 로드됩니다. 기본적으로 프로필을 정상적으로 가져왔지만 이메일이 없거나 아직 조직 구성원이 아닌 workspace 구성원은 거부됩니다. 앱은 `allowAnonymousOrgScopedSlackDm: true`를 명시적으로 설정해 이러한 구성원을 조직 범위의 익명 service principal로 실행할 수 있습니다. 이는 공유 채널과 동일한 조직 전체 공개 수준이지만 사용자 비공개 데이터에는 절대 접근하지 않습니다. 에이전트에 표시되는 메모와 개인 액세스를 얻는 방법을 설명하는 일회성 Slack 안내가 함께 제공됩니다. 이 opt-in은 프로필 가져오기 실패, 검증되지 않은 호출자, 게스트, 외부(Slack Connect) 구성원 또는 조직에 연결되지 않은 workspace를 허용하지 않으며, 이들에게는 정중한 거절 응답을 보냅니다. Slack 공유 채널은 service principal을 사용하며 참여자의 개인 권한을 빌리지 않습니다. 관리형 OAuth와 생성된 Slack 앱 매니페스트는 모두 bot scope `users:read.email`을 요청합니다. 새로 추가된 scope를 부여하려면 기존 설치를 다시 연결/설치해야 하며, 이전 bot-token 설치는 Slack에서 scope를 수동으로 추가해야 합니다. 이 scope가 없으면 앱이 `allowAnonymousOrgScopedSlackDm`을 명시적으로 활성화하지 않는 한 DM은 거부됩니다.
408
412
 
409
413
  ### 전체 등급(명시적 선택만 해당) {#full-tier}
410
414
 
@@ -382,7 +382,7 @@ Aplicativos que desejam que as ferramentas de leitura direta funcionem sem mante
382
382
 
383
383
  ```ts
384
384
  export default createAgentChatPlugin({
385
- appId: "analytics",
385
+ appId: "example-app",
386
386
  externalAgents: {
387
387
  authenticatedReads: "auto",
388
388
  writes: "ask_app_only",
@@ -392,6 +392,8 @@ export default createAgentChatPlugin({
392
392
  });
393
393
  ```
394
394
 
395
+ Este é um exemplo genérico da política. O Analytics define intencionalmente `authenticatedReads: "off"` e expõe somente as actions revisadas de `connectorCatalog`.
396
+
395
397
  `authenticatedReads: "auto"` adiciona somente actions que declaram explicitamente todos os itens a seguir:
396
398
 
397
399
  - `http: { method: "GET" }`
@@ -406,7 +408,9 @@ Os `db-schema` e `db-query` do Core não são expostos automaticamente como leit
406
408
 
407
409
  Trata-se de uma exclusão rígida baseada em nome, não apenas uma omissão de metadados: ferramentas genéricas de banco de dados, seed, sessão de navegador, extensões e raio X de contexto nunca são expostas automaticamente, mesmo que uma mudança futura marque acidentalmente uma delas com o conjunto completo de flags de leitura autenticada — elas sempre exigem uma entrada explícita em `connectorCatalog`.
408
410
 
409
- Antes de o agente ser executado, uma DM verificada do Slack é associada a um membro existente da organização Agent Native e o vínculo de identidade entre workspace e usuário é salvo. O contexto resultante de usuário/organização carrega os recursos, as instruções e as skills desse usuário. Membros do workspace cujo perfil foi carregado, mas cujo e-mail está ausente ou que ainda não pertencem à organização, são executados como um principal de serviço anônimo com escopo da organização — o mesmo nível de visibilidade para toda a organização usado pelos canais compartilhados — com uma observação visível ao agente e um aviso único no Slack explicando como obter acesso pessoal. Falhas no carregamento do perfil, convidados e membros externos (Slack Connect), e workspaces não conectados a uma organização recebem uma resposta educada de recusa em vez de a mensagem ser descartada silenciosamente. Canais compartilhados do Slack usam um principal de serviço e não herdam as permissões privadas de um participante. O OAuth gerenciado e o manifesto gerado do aplicativo Slack solicitam o escopo de bot `users:read.email`. Instalações existentes precisam ser reconectadas/reinstaladas para conceder um escopo recém-adicionado; instalações antigas com token de bot precisam adicioná-lo manualmente no Slack. Sem ele, as DMs são executadas no nível anônimo com escopo da organização, e não com acesso pessoal.
411
+ Um aplicativo que fornece `resolveExecutionContext` substitui explicitamente essa cadeia de identidade padrão. O resolver deve rejeitar de forma independente autores não verificados, convidados, membros externos e workspaces não vinculados antes de retornar um principal.
412
+
413
+ Antes de o agente ser executado, uma DM verificada do Slack é associada a um membro existente da organização Agent Native e o vínculo de identidade entre workspace e usuário é salvo. O contexto resultante de usuário/organização carrega os recursos, as instruções e as skills desse usuário. Por padrão, membros do workspace cujo perfil foi carregado, mas cujo e-mail está ausente ou que ainda não pertencem à organização, são recusados. Os aplicativos podem definir explicitamente `allowAnonymousOrgScopedSlackDm: true` para executar esses membros como um principal de serviço anônimo com escopo da organização — o mesmo nível de visibilidade para toda a organização usado pelos canais compartilhados, mas nunca acesso privado do usuário — com uma observação visível ao agente e um aviso único no Slack explicando como obter acesso pessoal. Essa opção nunca admite falhas no carregamento do perfil, autores não verificados, convidados, membros externos (Slack Connect) ou workspaces não conectados a uma organização; esses casos recebem uma resposta educada de recusa. Canais compartilhados do Slack usam um principal de serviço e não herdam as permissões privadas de um participante. O OAuth gerenciado e o manifesto gerado do aplicativo Slack solicitam o escopo de bot `users:read.email`. Instalações existentes precisam ser reconectadas/reinstaladas para conceder um escopo recém-adicionado; instalações antigas com token de bot precisam adicioná-lo manualmente no Slack. Sem ele, as DMs são recusadas, a menos que o aplicativo habilite explicitamente `allowAnonymousOrgScopedSlackDm`.
410
414
 
411
415
  ### Nível completo (somente aceitação explícita) {#full-tier}
412
416
 
@@ -379,7 +379,7 @@ MCP 服务器默认为每个调用者提供一个**紧凑的目录** — 托管
379
379
 
380
380
  ```ts
381
381
  export default createAgentChatPlugin({
382
- appId: "analytics",
382
+ appId: "example-app",
383
383
  externalAgents: {
384
384
  authenticatedReads: "auto",
385
385
  writes: "ask_app_only",
@@ -389,6 +389,8 @@ export default createAgentChatPlugin({
389
389
  });
390
390
  ```
391
391
 
392
+ 这是一个通用政策示例。Analytics 会有意设置 `authenticatedReads: "off"`,并且只公开经过审核的 `connectorCatalog` action。
393
+
392
394
  `authenticatedReads: "auto"` 只会添加明确声明了以下全部内容的 action:
393
395
 
394
396
  - `http: { method: "GET" }`
@@ -403,7 +405,9 @@ Core `db-schema` 和 `db-query` 不会自动作为外部读取公开。它们仍
403
405
 
404
406
  这是一种基于名称的硬性排除,而不仅仅是元数据遗漏:通用的数据库、seed、浏览器会话、扩展和上下文 X 射线工具永远不会被自动公开,即使未来的更改意外地为其中某个工具标注了完整的已认证读取标志组合也是如此 — 它们始终需要在 `connectorCatalog` 中显式声明。
405
407
 
406
- 经过验证的 Slack 私信会在代理运行前匹配现有的 Agent Native 组织成员,并保存工作区/用户身份关联;由此生成的用户/组织上下文会加载该用户的资源、指令和技能。对于已成功获取资料但缺少电子邮件或尚未成为组织成员的工作区成员,系统会改用组织范围的匿名服务主体运行——其组织级可见性与共享频道相同——同时向代理显示说明,并通过 Slack 一次性提示如何获得个人访问权限。如果资料获取失败、用户是访客或外部(Slack Connect)成员,或者工作区尚未连接组织,系统会礼貌回复拒绝,而不是静默丢弃消息。Slack 共享频道使用服务主体,不会借用任何参与者的私人权限。托管 OAuth 和生成的 Slack 应用 manifest 都会请求 bot scope `users:read.email`。已有安装必须重新连接/安装才能授予新增的 scope;旧版 bot token 安装则必须在 Slack 中手动添加该 scope。没有此 scope 时,私信会在组织范围的匿名层级运行,而不会获得个人访问权限。
408
+ 提供 `resolveExecutionContext` 的应用会明确替换此默认身份判定流程。其解析器必须在返回主体前自行拒绝未经验证的调用者、访客、外部成员以及未关联的工作区。
409
+
410
+ 经过验证的 Slack 私信会在代理运行前匹配现有的 Agent Native 组织成员,并保存工作区/用户身份关联;由此生成的用户/组织上下文会加载该用户的资源、指令和技能。默认情况下,已成功获取资料但缺少电子邮件或尚未成为组织成员的工作区成员会被拒绝。应用可以明确设置 `allowAnonymousOrgScopedSlackDm: true`,让这些成员改用组织范围的匿名服务主体运行——其组织级可见性与共享频道相同,但绝不包含用户私有访问——同时向代理显示说明,并通过 Slack 一次性提示如何获得个人访问权限。此选择加入绝不会允许资料获取失败、未经验证的调用者、访客、外部(Slack Connect)成员或尚未连接组织的工作区;这些情况会收到礼貌的拒绝回复。Slack 共享频道使用服务主体,不会借用任何参与者的私人权限。托管 OAuth 和生成的 Slack 应用 manifest 都会请求 bot scope `users:read.email`。已有安装必须重新连接/安装才能授予新增的 scope;旧版 bot token 安装则必须在 Slack 中手动添加该 scope。没有此 scope 时,私信会被拒绝,除非应用明确启用 `allowAnonymousOrgScopedSlackDm`。
407
411
 
408
412
  ### 完整层(仅限明确选择加入) {#full-tier}
409
413
 
@@ -379,7 +379,7 @@ MCP 伺服器預設為每個呼叫者提供一個**緊湊的目錄** — 託管
379
379
 
380
380
  ```ts
381
381
  export default createAgentChatPlugin({
382
- appId: "analytics",
382
+ appId: "example-app",
383
383
  externalAgents: {
384
384
  authenticatedReads: "auto",
385
385
  writes: "ask_app_only",
@@ -389,6 +389,8 @@ export default createAgentChatPlugin({
389
389
  });
390
390
  ```
391
391
 
392
+ 這是一般政策範例。Analytics 會刻意設定 `authenticatedReads: "off"`,而且只公開經過審查的 `connectorCatalog` action。
393
+
392
394
  `authenticatedReads: "auto"` 只會加入明確宣告以下全部內容的 action:
393
395
 
394
396
  - `http: { method: "GET" }`
@@ -403,7 +405,9 @@ Core `db-schema` 與 `db-query` 不會自動公開為外部讀取。它們仍可
403
405
 
404
406
  這是一種以名稱為依據的硬性排除,而不只是中繼資料的遺漏:通用的資料庫、seed、瀏覽器工作階段、擴充功能與 context-xray 工具永遠不會自動公開,即使未來的變更意外為其中某個工具標註了完整的已驗證讀取旗標組合也一樣 — 它們一律需要在 `connectorCatalog` 中明確宣告。
405
407
 
406
- 經過驗證的 Slack 私訊會在代理執行前配對現有的 Agent Native 組織成員,並儲存工作區/使用者身分連結;由此產生的使用者/組織內容會載入該使用者的資源、指示和技能。對於已成功取得資料但缺少電子郵件或尚未成為組織成員的工作區成員,系統會改以組織範圍的匿名服務主體執行——其組織級可見性與共用頻道相同——同時向代理顯示說明,並透過 Slack 一次性提示如何取得個人存取權。如果資料取得失敗、使用者是訪客或外部(Slack Connect)成員,或工作區尚未連接組織,系統會禮貌回覆拒絕,而不是靜默捨棄訊息。Slack 共用頻道使用服務主體,不會借用任何參與者的私人權限。託管 OAuth 與產生的 Slack 應用程式 manifest 都會要求 bot scope `users:read.email`。現有安裝必須重新連接/安裝,才能授予新增的 scope;舊版 bot token 安裝則必須在 Slack 中手動加入該 scope。若沒有此 scope,私訊會在組織範圍的匿名層級執行,而不會取得個人存取權。
408
+ 提供 `resolveExecutionContext` 的應用程式會明確取代這套預設身分判定流程。其解析器必須在傳回主體之前,自行拒絕未經驗證的呼叫者、訪客、外部成員以及未連結的工作區。
409
+
410
+ 經過驗證的 Slack 私訊會在代理執行前配對現有的 Agent Native 組織成員,並儲存工作區/使用者身分連結;由此產生的使用者/組織內容會載入該使用者的資源、指示和技能。預設情況下,已成功取得資料但缺少電子郵件或尚未成為組織成員的工作區成員會被拒絕。應用程式可以明確設定 `allowAnonymousOrgScopedSlackDm: true`,讓這些成員改用組織範圍的匿名服務主體執行——其組織級可見性與共用頻道相同,但絕不包含使用者私人存取——同時向代理顯示說明,並透過 Slack 一次性提示如何取得個人存取權。這項選擇加入絕不允許資料取得失敗、未經驗證的呼叫者、訪客、外部(Slack Connect)成員或尚未連接組織的工作區;這些情況會收到禮貌的拒絕回覆。Slack 共用頻道使用服務主體,不會借用任何參與者的私人權限。託管 OAuth 與產生的 Slack 應用程式 manifest 都會要求 bot scope `users:read.email`。現有安裝必須重新連接/安裝,才能授予新增的 scope;舊版 bot token 安裝則必須在 Slack 中手動加入該 scope。若沒有此 scope,私訊會被拒絕,除非應用程式明確啟用 `allowAnonymousOrgScopedSlackDm`。
407
411
 
408
412
  ### 完整層(僅限明確選取加入) {#full-tier}
409
413
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-native/core",
3
- "version": "0.98.7",
3
+ "version": "0.98.9",
4
4
  "description": "Framework for agent-native application development — where AI agents and UI share SQL state, actions, and context",
5
5
  "homepage": "https://github.com/BuilderIO/agent-native#readme",
6
6
  "bugs": {
@@ -74,6 +74,8 @@ interface SessionReplayState {
74
74
  queue: QueuedReplayEvent[];
75
75
  queuedBytes: number;
76
76
  retryBatches: QueuedReplayEvent[][];
77
+ /** Consecutive retryable 4xx responses for the current recording episode. */
78
+ transientClientErrorFailures: number;
77
79
  flushTimer: number | null;
78
80
  maxDurationTimer: number | null;
79
81
  flushing: boolean;
@@ -441,6 +443,7 @@ function getState(): SessionReplayState {
441
443
  queue: [],
442
444
  queuedBytes: 0,
443
445
  retryBatches: [],
446
+ transientClientErrorFailures: 0,
444
447
  flushTimer: null,
445
448
  maxDurationTimer: null,
446
449
  flushing: false,
@@ -463,6 +466,7 @@ function getState(): SessionReplayState {
463
466
  const state = g[SESSION_REPLAY_STATE_KEY]!;
464
467
  // Keep Vite HMR safe when an older recorder state survives a module reload.
465
468
  state.resourceNodes ??= new Map();
469
+ state.transientClientErrorFailures ??= 0;
466
470
  state.restoreIframeBridge ??= null;
467
471
  state.pendingFlushReason ??= null;
468
472
  state.pendingFlushWaiters ??= [];
@@ -1058,14 +1062,12 @@ const REPLAY_RESOURCE_TAGS = new Set([
1058
1062
  "audio",
1059
1063
  "track",
1060
1064
  "input",
1061
- "object",
1062
1065
  "link",
1063
1066
  ]);
1064
1067
  const NO_REPLAY_RESOURCE_ATTRIBUTES = new Set<string>();
1065
1068
  const REPLAY_SRC_ATTRIBUTES = new Set(["src"]);
1066
1069
  const REPLAY_SRCSET_ATTRIBUTES = new Set(["src", "srcset"]);
1067
1070
  const REPLAY_VIDEO_ATTRIBUTES = new Set(["src", "poster"]);
1068
- const REPLAY_OBJECT_ATTRIBUTES = new Set(["data"]);
1069
1071
  const REPLAY_HREF_ATTRIBUTES = new Set(["href"]);
1070
1072
 
1071
1073
  function replayAttributeString(
@@ -1107,8 +1109,6 @@ function replayPreservedResourceAttributes(
1107
1109
  case "audio":
1108
1110
  case "track":
1109
1111
  return REPLAY_SRC_ATTRIBUTES;
1110
- case "object":
1111
- return REPLAY_OBJECT_ATTRIBUTES;
1112
1112
  case "input":
1113
1113
  return node.type === "image"
1114
1114
  ? REPLAY_SRC_ATTRIBUTES
@@ -1462,12 +1462,19 @@ class ReplayUploadHttpError extends Error {
1462
1462
 
1463
1463
  /** 4xx statuses where retrying the exact same batch can never succeed.
1464
1464
  * Keep this deliberately narrow: 401/403/404 can be temporary during auth or
1465
- * deploy transitions, and stopping forever on one of those would silently
1466
- * black out the rest of a long-lived SPA session. */
1465
+ * deploy transitions, so they get a small retry budget before the rejected
1466
+ * episode is stopped. The budget prevents a persistent configuration failure
1467
+ * from pinning retryBatches while rrweb events grow without bound. */
1467
1468
  function isDefinitiveReplayUploadClientError(status: number): boolean {
1468
1469
  return status === 400 || status === 409 || status === 413 || status === 422;
1469
1470
  }
1470
1471
 
1472
+ const MAX_TRANSIENT_REPLAY_CLIENT_FAILURES = 3;
1473
+
1474
+ function isTransientReplayUploadClientError(status: number): boolean {
1475
+ return status === 401 || status === 403 || status === 404;
1476
+ }
1477
+
1471
1478
  async function sendReplayUpload(
1472
1479
  options: NormalizedSessionReplayOptions,
1473
1480
  body: string,
@@ -1741,6 +1748,7 @@ export async function flushSessionReplay(reason = "manual"): Promise<void> {
1741
1748
  });
1742
1749
  if (!reservedSequence) advanceReplaySequence(state, payload);
1743
1750
  state.automaticConflictRestartAttempted = false;
1751
+ state.transientClientErrorFailures = 0;
1744
1752
  uploaded = true;
1745
1753
  } catch (error) {
1746
1754
  if (reservedSequence) rollbackReplaySequenceReservation(state, payload);
@@ -1753,9 +1761,22 @@ export async function flushSessionReplay(reason = "manual"): Promise<void> {
1753
1761
  const splitBatch = rejectedStatus === 413 ? splitReplayBatch(events) : null;
1754
1762
  const isUnsplittableOversizedBatch =
1755
1763
  rejectedStatus === 413 && splitBatch === null;
1764
+ const isTransientClientError =
1765
+ rejectedStatus !== null &&
1766
+ isTransientReplayUploadClientError(rejectedStatus);
1767
+ if (isTransientClientError) {
1768
+ state.transientClientErrorFailures += 1;
1769
+ } else {
1770
+ state.transientClientErrorFailures = 0;
1771
+ }
1772
+ const exhaustedTransientClientRetries =
1773
+ isTransientClientError &&
1774
+ state.transientClientErrorFailures >=
1775
+ MAX_TRANSIENT_REPLAY_CLIENT_FAILURES;
1756
1776
  const isDefinitiveClientError =
1757
1777
  error instanceof ReplayUploadHttpError &&
1758
- isDefinitiveReplayUploadClientError(error.status) &&
1778
+ (isDefinitiveReplayUploadClientError(error.status) ||
1779
+ exhaustedTransientClientRetries) &&
1759
1780
  !splitBatch &&
1760
1781
  !isUnsplittableOversizedBatch;
1761
1782
  if (splitBatch) {
@@ -2916,6 +2937,7 @@ export async function startSessionReplay(
2916
2937
  // This is a new caller-initiated recording episode. A prior episode's
2917
2938
  // conflict-loop guard must not prevent this one from recovering once.
2918
2939
  state.automaticConflictRestartAttempted = false;
2940
+ state.transientClientErrorFailures = 0;
2919
2941
  const startGeneration = ++state.startGeneration;
2920
2942
 
2921
2943
  let startPromise: Promise<SessionReplayStartResult>;
@@ -538,12 +538,12 @@ export function slackAdapter(
538
538
  const token = await resolveBotToken(incoming);
539
539
  if (!token) {
540
540
  if (dedupeKey) slackSystemNoticeCache.delete(dedupeKey);
541
- return;
541
+ throw new Error("Slack bot token not configured for system notice");
542
542
  }
543
543
  const channelId = incoming.platformContext.channelId;
544
544
  if (typeof channelId !== "string" || !channelId) {
545
545
  if (dedupeKey) slackSystemNoticeCache.delete(dedupeKey);
546
- return;
546
+ throw new Error("Slack channel id missing for system notice");
547
547
  }
548
548
  const threadTs =
549
549
  typeof incoming.platformContext.threadTs === "string"
@@ -1242,6 +1242,17 @@ async function hydrateSlackIdentity(
1242
1242
  ): Promise<IncomingMessage> {
1243
1243
  const identity = await resolveSlackUserIdentity(token, incoming);
1244
1244
  if (!identity) {
1245
+ // Context hydration can call users.info again after the webhook identity
1246
+ // pass. A transient failure on that second lookup is not evidence that a
1247
+ // previously verified sender became unverified; preserve the stronger
1248
+ // identity instead of replacing it with a negative-cache result.
1249
+ if (
1250
+ incoming.senderVerified === true &&
1251
+ incoming.senderEmail?.trim() &&
1252
+ incoming.actorTrust?.verified === true
1253
+ ) {
1254
+ return incoming;
1255
+ }
1245
1256
  return {
1246
1257
  ...incoming,
1247
1258
  senderVerified: false,
@@ -115,7 +115,8 @@ export async function retryStuckPendingTasks(
115
115
  SET status = 'failed',
116
116
  updated_at = ?,
117
117
  error_message = COALESCE(error_message, ?),
118
- payload = '{}'
118
+ payload = '{}',
119
+ external_event_key = NULL
119
120
  WHERE id = ?
120
121
  AND status = ?
121
122
  `,
@@ -364,7 +364,7 @@ export async function markTaskFailed(
364
364
  const now = Date.now();
365
365
  await client.execute({
366
366
  sql: `UPDATE integration_pending_tasks
367
- SET status = ?, updated_at = ?, error_message = ?, payload = ?
367
+ SET status = ?, updated_at = ?, error_message = ?, payload = ?, external_event_key = NULL
368
368
  WHERE id = ?`,
369
369
  args: ["failed", now, errorMessage.slice(0, 2000), "{}", id],
370
370
  });