@circuitwall/jarela 2.3.0 → 2.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.next/standalone/.next/BUILD_ID +1 -1
- package/.next/standalone/.next/app-path-routes-manifest.json +5 -5
- package/.next/standalone/.next/build-manifest.json +2 -2
- package/.next/standalone/.next/prerender-manifest.json +4 -4
- package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_global-error.html +1 -1
- package/.next/standalone/.next/server/app/_global-error.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_not-found.html +14 -2
- package/.next/standalone/.next/server/app/_not-found.rsc +16 -4
- package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +16 -4
- package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +16 -4
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/api/v1/access/[identity]/route.js +7 -0
- package/.next/standalone/.next/server/app/api/v1/access/route.js +7 -0
- package/.next/standalone/.next/server/app/api/v1/agents/[id]/compact/route.js +7 -0
- package/.next/standalone/.next/server/app/api/v1/agents/[id]/display-filters/route.js +17 -5
- package/.next/standalone/.next/server/app/api/v1/agents/[id]/route.js +7 -0
- package/.next/standalone/.next/server/app/api/v1/agents/[id]/thread/route.js +17 -5
- package/.next/standalone/.next/server/app/api/v1/agents/route.js +7 -0
- package/.next/standalone/.next/server/app/api/v1/allowed-sites/[hostname]/route.js +7 -0
- package/.next/standalone/.next/server/app/api/v1/allowed-sites/route.js +7 -0
- package/.next/standalone/.next/server/app/api/v1/artifacts/lifecycle/route.js +7 -0
- package/.next/standalone/.next/server/app/api/v1/bridges/[id]/chats/route.js +26 -32
- package/.next/standalone/.next/server/app/api/v1/bridges/[id]/chats/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/v1/bridges/[id]/ignores/[remote_jid]/route.js +18 -7
- package/.next/standalone/.next/server/app/api/v1/bridges/[id]/ignores/route.js +18 -7
- package/.next/standalone/.next/server/app/api/v1/bridges/[id]/lookup/route.js +26 -32
- package/.next/standalone/.next/server/app/api/v1/bridges/[id]/lookup/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/v1/bridges/[id]/pair/route.js +27 -33
- package/.next/standalone/.next/server/app/api/v1/bridges/[id]/pair/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/v1/bridges/[id]/route.js +26 -32
- package/.next/standalone/.next/server/app/api/v1/bridges/[id]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/v1/bridges/[id]/routes/[route_id]/route.js +28 -12
- package/.next/standalone/.next/server/app/api/v1/bridges/[id]/routes/route.js +28 -12
- package/.next/standalone/.next/server/app/api/v1/bridges/[id]/status/route.js +26 -32
- package/.next/standalone/.next/server/app/api/v1/bridges/[id]/status/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/v1/bridges/kinds/route.js +9 -2
- package/.next/standalone/.next/server/app/api/v1/bridges/kinds/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/v1/bridges/route.js +19 -7
- package/.next/standalone/.next/server/app/api/v1/bridges/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/v1/dashboard/metrics/route.js +17 -5
- package/.next/standalone/.next/server/app/api/v1/dashboard/pricing/route.js +7 -0
- package/.next/standalone/.next/server/app/api/v1/dashboard/pricing-task/route.js +1 -1
- package/.next/standalone/.next/server/app/api/v1/documents/search/route.js +7 -0
- package/.next/standalone/.next/server/app/api/v1/documents/settings/route.js +7 -0
- package/.next/standalone/.next/server/app/api/v1/documents/sources/[id]/route.js +1 -1
- package/.next/standalone/.next/server/app/api/v1/documents/sources/route.js +1 -1
- package/.next/standalone/.next/server/app/api/v1/env-sync/allowlist/route.js +7 -0
- package/.next/standalone/.next/server/app/api/v1/env-sync/route.js +7 -0
- package/.next/standalone/.next/server/app/api/v1/events/route.js +26 -32
- package/.next/standalone/.next/server/app/api/v1/events/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/v1/extension/agents/route.js +1 -1
- package/.next/standalone/.next/server/app/api/v1/extension/browser/activate/route.js +7 -0
- package/.next/standalone/.next/server/app/api/v1/extension/browser/foreground/route.js +7 -0
- package/.next/standalone/.next/server/app/api/v1/extension/browser/history/route.js +7 -0
- package/.next/standalone/.next/server/app/api/v1/extension/browser/poll/route.js +7 -0
- package/.next/standalone/.next/server/app/api/v1/extension/browser/progress/route.js +7 -0
- package/.next/standalone/.next/server/app/api/v1/extension/browser/result/route.js +7 -0
- package/.next/standalone/.next/server/app/api/v1/extension/browser/retry/route.js +7 -0
- package/.next/standalone/.next/server/app/api/v1/extension/browser/status/route.js +7 -0
- package/.next/standalone/.next/server/app/api/v1/extension/browser/tabs/route.js +7 -0
- package/.next/standalone/.next/server/app/api/v1/extension/fill/route.js +1 -1
- package/.next/standalone/.next/server/app/api/v1/extension/refine/route.js +1 -1
- package/.next/standalone/.next/server/app/api/v1/extension/turn/route.js +1 -1
- package/.next/standalone/.next/server/app/api/v1/extensions/route.js +1 -1
- package/.next/standalone/.next/server/app/api/v1/extensions/tools/[name]/config/route.js +1 -1
- package/.next/standalone/.next/server/app/api/v1/extensions/tools/[name]/route.js +1 -1
- package/.next/standalone/.next/server/app/api/v1/extensions/tools/[name]/secrets/route.js +1 -1
- package/.next/standalone/.next/server/app/api/v1/harnesses/[id]/route.js +7 -0
- package/.next/standalone/.next/server/app/api/v1/harnesses/default/route.js +7 -0
- package/.next/standalone/.next/server/app/api/v1/harnesses/route.js +7 -0
- package/.next/standalone/.next/server/app/api/v1/health/route.js +17 -5
- package/.next/standalone/.next/server/app/api/v1/integrations/[name]/route.js +7 -0
- package/.next/standalone/.next/server/app/api/v1/integrations/gmail/oauth/callback/route.js +7 -0
- package/.next/standalone/.next/server/app/api/v1/integrations/gmail/oauth/start/route.js +7 -0
- package/.next/standalone/.next/server/app/api/v1/integrations/gmail/oauth/status/route.js +7 -0
- package/.next/standalone/.next/server/app/api/v1/integrations/outlook/oauth/callback/route.js +7 -0
- package/.next/standalone/.next/server/app/api/v1/integrations/outlook/oauth/start/route.js +7 -0
- package/.next/standalone/.next/server/app/api/v1/integrations/outlook/oauth/status/route.js +7 -0
- package/.next/standalone/.next/server/app/api/v1/integrations/route.js +7 -0
- package/.next/standalone/.next/server/app/api/v1/lifecycle/adoption/route.js +17 -5
- package/.next/standalone/.next/server/app/api/v1/maps/embed/route.js +7 -0
- package/.next/standalone/.next/server/app/api/v1/mcp-servers/[name]/route.js +17 -5
- package/.next/standalone/.next/server/app/api/v1/mcp-servers/route.js +17 -5
- package/.next/standalone/.next/server/app/api/v1/memory/[namespace]/[key]/route.js +7 -0
- package/.next/standalone/.next/server/app/api/v1/memory/policy/route.js +7 -0
- package/.next/standalone/.next/server/app/api/v1/memory/route.js +7 -0
- package/.next/standalone/.next/server/app/api/v1/memory/search/route.js +7 -0
- package/.next/standalone/.next/server/app/api/v1/models/[name]/compact-threads/route.js +7 -0
- package/.next/standalone/.next/server/app/api/v1/models/[name]/route.js +7 -0
- package/.next/standalone/.next/server/app/api/v1/models/route.js +7 -0
- package/.next/standalone/.next/server/app/api/v1/packages/defaults/[id]/route.js +28 -4
- package/.next/standalone/.next/server/app/api/v1/packages/reload/route.js +28 -4
- package/.next/standalone/.next/server/app/api/v1/packages/route.js +28 -4
- package/.next/standalone/.next/server/app/api/v1/page-capture/route.js +1 -1
- package/.next/standalone/.next/server/app/api/v1/pending-actions/[id]/approve/route.js +27 -12
- package/.next/standalone/.next/server/app/api/v1/profile/location/route.js +7 -0
- package/.next/standalone/.next/server/app/api/v1/profile/route.js +7 -0
- package/.next/standalone/.next/server/app/api/v1/providers/[provider]/models/route.js +585 -58
- package/.next/standalone/.next/server/app/api/v1/providers/[provider]/probe/route.js +7 -0
- package/.next/standalone/.next/server/app/api/v1/providers/github-copilot/auth/route.js +7 -0
- package/.next/standalone/.next/server/app/api/v1/providers/route.js +7 -0
- package/.next/standalone/.next/server/app/api/v1/proxy-config/route.js +7 -0
- package/.next/standalone/.next/server/app/api/v1/redaction/init/route.js +7 -0
- package/.next/standalone/.next/server/app/api/v1/redaction/route.js +7 -0
- package/.next/standalone/.next/server/app/api/v1/scheduled-tasks/[id]/route.js +17 -5
- package/.next/standalone/.next/server/app/api/v1/scheduled-tasks/[id]/run/route.js +1 -1
- package/.next/standalone/.next/server/app/api/v1/scheduled-tasks/route.js +7 -0
- package/.next/standalone/.next/server/app/api/v1/security/idle-timeout/route.js +7 -0
- package/.next/standalone/.next/server/app/api/v1/security/pin/route.js +7 -0
- package/.next/standalone/.next/server/app/api/v1/security/state/route.js +7 -0
- package/.next/standalone/.next/server/app/api/v1/security/unlock/route.js +7 -0
- package/.next/standalone/.next/server/app/api/v1/security/verify-pin/route.js +7 -0
- package/.next/standalone/.next/server/app/api/v1/skills/[id]/route.js +7 -0
- package/.next/standalone/.next/server/app/api/v1/skills/repos/[id]/route.js +7 -0
- package/.next/standalone/.next/server/app/api/v1/skills/repos/route.js +7 -0
- package/.next/standalone/.next/server/app/api/v1/skills/route.js +7 -0
- package/.next/standalone/.next/server/app/api/v1/tasks/[agent_id]/route.js +7 -0
- package/.next/standalone/.next/server/app/api/v1/tasks/route.js +7 -0
- package/.next/standalone/.next/server/app/api/v1/threads/[thread_id]/activity/route.js +7 -0
- package/.next/standalone/.next/server/app/api/v1/threads/[thread_id]/context-pin/route.js +12 -6
- package/.next/standalone/.next/server/app/api/v1/threads/[thread_id]/route.js +125 -26
- package/.next/standalone/.next/server/app/api/v1/threads/[thread_id]/run/route.js +1 -2
- package/.next/standalone/.next/server/app/api/v1/threads/route.js +17 -5
- package/.next/standalone/.next/server/app/api/v1/tools/route.js +1 -1
- package/.next/standalone/.next/server/app/api/v1/update/apply/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/v1/voice/transcribe/route.js +17 -5
- package/.next/standalone/.next/server/app/api/v1/voice/tts/route.js +17 -5
- package/.next/standalone/.next/server/app/api/v1/watchers/[id]/route.js +17 -5
- package/.next/standalone/.next/server/app/api/v1/watchers/[id]/run/route.js +1 -1
- package/.next/standalone/.next/server/app/api/v1/watchers/route.js +1 -1
- package/.next/standalone/.next/server/app/page.js +27323 -27034
- package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/setup/page.js +8 -0
- package/.next/standalone/.next/server/app/setup/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app-paths-manifest.json +5 -5
- package/.next/standalone/.next/server/chunks/1388.js +106 -36
- package/.next/standalone/.next/server/chunks/2068.js +47 -10
- package/.next/standalone/.next/server/chunks/210.js +6 -6
- package/.next/standalone/.next/server/chunks/2447.js +10 -5
- package/.next/standalone/.next/server/chunks/2653.js +80 -1
- package/.next/standalone/.next/server/chunks/3042.js +10 -8
- package/.next/standalone/.next/server/chunks/{4540.js → 309.js} +104 -38
- package/.next/standalone/.next/server/chunks/{2350.js → 3272.js} +104 -37
- package/.next/standalone/.next/server/chunks/3524.js +150 -67
- package/.next/standalone/.next/server/chunks/3566.js +1 -1
- package/.next/standalone/.next/server/chunks/4189.js +1 -1
- package/.next/standalone/.next/server/chunks/4596.js +28 -4
- package/.next/standalone/.next/server/chunks/46.js +91 -31
- package/.next/standalone/.next/server/chunks/466.js +53 -7
- package/.next/standalone/.next/server/chunks/4955.js +30 -3
- package/.next/standalone/.next/server/chunks/5585.js +28 -4
- package/.next/standalone/.next/server/chunks/5908.js +63 -42
- package/.next/standalone/.next/server/chunks/6142.js +10 -2
- package/.next/standalone/.next/server/chunks/8461.js +10 -8
- package/.next/standalone/.next/server/chunks/9032.js +5 -5
- package/.next/standalone/.next/server/chunks/9164.js +487 -177
- package/.next/standalone/.next/server/chunks/9304.js +51 -12
- package/.next/standalone/.next/server/chunks/{423.js → 9590.js} +84 -24
- package/.next/standalone/.next/server/middleware-build-manifest.js +2 -2
- package/.next/standalone/.next/server/middleware.js +89 -21
- package/.next/standalone/.next/server/pages/404.html +14 -2
- package/.next/standalone/.next/server/pages/500.html +1 -1
- package/.next/standalone/.next/server/preview-props.json +3 -3
- package/.next/standalone/.next/server/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/static/chunks/{1395-e4a99912b8f83044.js → 1395-bfe1f3ef760c0f50.js} +54 -8
- package/.next/standalone/.next/static/chunks/app/{layout-9bc0b10127cb7d42.js → layout-7b24ad13faa3944b.js} +69 -2
- package/.next/standalone/.next/static/chunks/app/{page-213a623b37226452.js → page-2ef8d75d40eb4311.js} +10643 -10295
- package/.next/standalone/.next/static/css/c160ea862133acd2.css +5 -0
- package/.next/standalone/docs/adoption/changesets.json +2805 -0
- package/.next/standalone/package.json +1 -1
- package/CHANGELOG.md +52 -0
- package/api/client.models.test.ts +10 -0
- package/api/client.startup.test.ts +129 -0
- package/api/client.ts +51 -9
- package/api/thread-metadata.test.ts +72 -0
- package/api/types.ts +6 -3
- package/app/api/v1/providers/[provider]/models/route.test.ts +216 -6
- package/app/api/v1/providers/[provider]/models/route.ts +259 -40
- package/app/api/v1/threads/[thread_id]/route.ts +26 -23
- package/app/api/v1/threads/[thread_id]/run/route.ts +0 -1
- package/app/globals.css +119 -29
- package/app/layout.tsx +12 -0
- package/components/agents/AgentsPanel.tsx +5 -13
- package/components/chat/ChatView.tsx +9 -18
- package/components/chat/InputBar.tsx +1 -1
- package/components/chat/MessageBubble.tsx +13 -1
- package/components/chat/MessageList.test.tsx +45 -4
- package/components/chat/MessageList.tsx +123 -89
- package/components/chat/ToolList.tsx +88 -84
- package/components/chat/useThreadActivity.test.tsx +2 -2
- package/components/chat/useThreadActivity.ts +2 -2
- package/components/chat/useThreadData.ts +1 -30
- package/components/chat/useThreadMetadataPolling.test.tsx +128 -0
- package/components/chat/useThreadMetadataPolling.ts +50 -0
- package/components/chat/useUserProfileAndAgent.test.tsx +31 -0
- package/components/chat/useUserProfileAndAgent.ts +13 -2
- package/components/dashboard/DashboardPanel.tsx +1 -1
- package/components/dashboard/Series.tsx +34 -21
- package/components/dashboard/SummaryCards.tsx +1 -1
- package/components/integrations/NetworkSection.tsx +2 -2
- package/components/layout/AppShell.tsx +22 -7
- package/components/layout/MenuPanel.tsx +14 -24
- package/components/profile/ProfilePanel.tsx +2 -2
- package/components/settings/AppearancePanel.tsx +70 -3
- package/components/settings/SettingsPanel.tsx +2 -2
- package/components/tools/ToolsPanel.tsx +2 -7
- package/components/ui/AppearancePreferences.test.tsx +68 -0
- package/components/ui/BootScreen.test.tsx +44 -0
- package/components/ui/BootScreen.tsx +24 -11
- package/components/ui/NotificationStatus.test.tsx +2 -2
- package/components/ui/NotificationStatus.tsx +5 -5
- package/components/ui/SubTabBar.tsx +2 -3
- package/contexts/ThemeContext.tsx +84 -1
- package/hooks/useAgentSession.test.ts +12 -1
- package/hooks/useAgentSession.ts +6 -4
- package/hooks/useUrlSync.test.ts +13 -0
- package/hooks/useUrlSync.ts +0 -4
- package/lib/agents/citation-checker.test.ts +40 -2
- package/lib/agents/citation-checker.ts +56 -11
- package/lib/agents/context-boundary.ts +5 -6
- package/lib/agents/instruction-edits.test.ts +120 -0
- package/lib/agents/instruction-edits.ts +65 -42
- package/lib/agents/prepare/request.ts +0 -2
- package/lib/agents/prepare/system-prompt.test.ts +10 -0
- package/lib/agents/prepare/system-prompt.ts +8 -2
- package/lib/agents/proposals.test.ts +76 -0
- package/lib/agents/proposals.ts +13 -5
- package/lib/agents/run-thread.auto-boundary.test.ts +125 -5
- package/lib/agents/run-thread.ts +24 -9
- package/lib/agents/sqlite-checkpoint-saver.test.ts +91 -0
- package/lib/agents/warm-summary-background.ts +22 -2
- package/lib/agents/warm-topics.test.ts +155 -1
- package/lib/agents/warm-topics.ts +27 -7
- package/lib/bridges/dispatcher.ts +1 -0
- package/lib/bridges/message-role.test.ts +81 -0
- package/lib/bridges/message-role.ts +23 -10
- package/lib/bridges/types.ts +6 -0
- package/lib/bridges/whatsapp-link.test.ts +32 -0
- package/lib/bridges/whatsapp-link.ts +21 -0
- package/lib/bridges/whatsapp.inbound.test.ts +239 -0
- package/lib/bridges/whatsapp.sender.test.ts +80 -1
- package/lib/bridges/whatsapp.ts +76 -38
- package/lib/db/migrations.test.ts +61 -0
- package/lib/db/migrations.ts +13 -0
- package/lib/embeddings/performance.test.ts +114 -0
- package/lib/pricing/snapshot.test.ts +70 -0
- package/lib/pricing/snapshot.ts +10 -2
- package/lib/proxy/dispatcher.test.ts +119 -1
- package/lib/proxy/dispatcher.ts +22 -9
- package/lib/stores/agent-configs.ts +10 -5
- package/lib/stores/bridges.test.ts +81 -0
- package/lib/stores/bridges.ts +9 -8
- package/lib/stores/dashboard-metrics-cache.test.ts +99 -0
- package/lib/stores/dashboard-metrics.ts +30 -4
- package/lib/stores/message-embedding-jobs.test.ts +27 -0
- package/lib/stores/message-embedding-jobs.ts +5 -3
- package/lib/stores/message-usage.test.ts +21 -1
- package/lib/stores/pricing-cache.test.ts +31 -0
- package/lib/stores/pricing.ts +3 -0
- package/lib/stores/proxy-config.test.ts +120 -0
- package/lib/stores/proxy-config.ts +22 -4
- package/lib/stores/threads.ts +12 -8
- package/lib/tools/communications/calendar.test.ts +43 -2
- package/lib/tools/communications/calendar.ts +2 -0
- package/lib/tools/communications/gmail.test.ts +51 -1
- package/lib/tools/communications/gmail.ts +44 -2
- package/lib/tools/communications/outlook-calendar.ts +2 -0
- package/lib/tools/communications/outlook.test.ts +33 -2
- package/lib/tools/communications/outlook.ts +2 -0
- package/lib/tools/filesystem/edit-match.test.ts +133 -0
- package/lib/tools/filesystem/edit-match.ts +7 -2
- package/lib/tools/packages/default-packages.test.ts +21 -0
- package/lib/tools/packages/optional-package.test.ts +72 -0
- package/lib/tools/packages/optional-package.ts +33 -4
- package/lib/tools/support/result-refs.test.ts +131 -0
- package/lib/tools/support/result-refs.ts +41 -9
- package/lib/ui/navigate.test.ts +13 -0
- package/lib/ui/navigate.ts +10 -2
- package/lib/utils/source-link.test.ts +51 -0
- package/lib/utils/source-link.ts +45 -0
- package/package.json +1 -1
- package/.next/standalone/.next/static/css/312542a5725ba0d5.css +0 -5
- /package/.next/standalone/.next/static/{bMRK5y3ruT7c3WtBfCQOG → 544OFJV-q0RC6Gjgje4LT}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{bMRK5y3ruT7c3WtBfCQOG → 544OFJV-q0RC6Gjgje4LT}/_ssgManifest.js +0 -0
|
@@ -678,9 +678,10 @@ function isIntegrationProbe(name) {
|
|
|
678
678
|
/* harmony export */ });
|
|
679
679
|
/* unused harmony exports outlookSearchTool, outlookGetMessageTool, outlookListFoldersTool, outlookModifyMessageTool, outlookCreateDraftTool, outlookTrashMessageTool, outlookSendEmailTool */
|
|
680
680
|
/* harmony import */ var _langchain_core_tools__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(49585);
|
|
681
|
-
/* harmony import */ var
|
|
682
|
-
/* harmony import */ var
|
|
683
|
-
/* harmony import */ var
|
|
681
|
+
/* harmony import */ var zod__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(17033);
|
|
682
|
+
/* harmony import */ var _lib_utils_html__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(85212);
|
|
683
|
+
/* harmony import */ var _lib_utils_text__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(69494);
|
|
684
|
+
/* harmony import */ var _lib_utils_source_link__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(76385);
|
|
684
685
|
/* harmony import */ var _packages_langchain_package__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(18932);
|
|
685
686
|
/* harmony import */ var _lib_integrations_microsoft_oauth__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(46291);
|
|
686
687
|
/**
|
|
@@ -700,6 +701,7 @@ function isIntegrationProbe(name) {
|
|
|
700
701
|
|
|
701
702
|
|
|
702
703
|
|
|
704
|
+
|
|
703
705
|
// Exposed for the integrations test endpoint.
|
|
704
706
|
function _resolveOutlookAuth() {
|
|
705
707
|
return (0,_lib_integrations_microsoft_oauth__WEBPACK_IMPORTED_MODULE_2__/* .resolveMicrosoftAuth */ .jG)();
|
|
@@ -725,7 +727,8 @@ function summarizeMessage(m) {
|
|
|
725
727
|
categories: m.categories ?? [],
|
|
726
728
|
folder_id: m.parentFolderId ?? null,
|
|
727
729
|
snippet: m.bodyPreview ?? null,
|
|
728
|
-
web_link: m.webLink ?? null
|
|
730
|
+
web_link: m.webLink ?? null,
|
|
731
|
+
cite_as: (0,_lib_utils_source_link__WEBPACK_IMPORTED_MODULE_3__/* .citeAs */ .w)(m.subject, m.webLink, "Outlook message")
|
|
729
732
|
};
|
|
730
733
|
}
|
|
731
734
|
const BODY_CAP = 30000;
|
|
@@ -761,9 +764,9 @@ const outlookSearchTool = (0,_langchain_core_tools__WEBPACK_IMPORTED_MODULE_0__/
|
|
|
761
764
|
}, {
|
|
762
765
|
name: "outlook_search",
|
|
763
766
|
description: "Search the user's Outlook mailbox using KQL (Microsoft's keyword query language). " + "Returns message metadata (from, to, subject, received, snippet, labels) plus @odata.count " + "and next_link when available. Examples: " + "'from:notifications@github.com', 'subject:invoice hasAttachment:true', " + "'isRead:false received>=2026-05-17'. **Use this before calling outlook_get_message** — " + "the snippet is often enough.",
|
|
764
|
-
schema:
|
|
765
|
-
query:
|
|
766
|
-
max_results:
|
|
767
|
+
schema: zod__WEBPACK_IMPORTED_MODULE_4__/* .object */ .Ikc({
|
|
768
|
+
query: zod__WEBPACK_IMPORTED_MODULE_4__/* .string */ .YjP().describe("KQL query string"),
|
|
769
|
+
max_results: zod__WEBPACK_IMPORTED_MODULE_4__/* .number */ .aig().int().optional().describe("Max messages (default 25, max 100)")
|
|
767
770
|
})
|
|
768
771
|
});
|
|
769
772
|
const outlookGetMessageTool = (0,_langchain_core_tools__WEBPACK_IMPORTED_MODULE_0__/* .tool */ .z6)(async ({ id })=>{
|
|
@@ -775,10 +778,10 @@ const outlookGetMessageTool = (0,_langchain_core_tools__WEBPACK_IMPORTED_MODULE_
|
|
|
775
778
|
if (m.error) return JSON.stringify(m);
|
|
776
779
|
const summary = summarizeMessage(m);
|
|
777
780
|
const rawBody = m.body?.content ?? "";
|
|
778
|
-
const plain = m.body?.contentType === "html" ? (0,
|
|
781
|
+
const plain = m.body?.contentType === "html" ? (0,_lib_utils_html__WEBPACK_IMPORTED_MODULE_5__/* .stripHtml */ .Q)(rawBody, {
|
|
779
782
|
preserveParagraphs: true
|
|
780
783
|
}) : rawBody;
|
|
781
|
-
const { text: body, truncated } = (0,
|
|
784
|
+
const { text: body, truncated } = (0,_lib_utils_text__WEBPACK_IMPORTED_MODULE_6__/* .truncateBytes */ .Q)(plain, BODY_CAP);
|
|
782
785
|
return JSON.stringify({
|
|
783
786
|
...summary,
|
|
784
787
|
body,
|
|
@@ -787,8 +790,8 @@ const outlookGetMessageTool = (0,_langchain_core_tools__WEBPACK_IMPORTED_MODULE_
|
|
|
787
790
|
}, {
|
|
788
791
|
name: "outlook_get_message",
|
|
789
792
|
description: "Fetch one Outlook message by id, including full headers and the decoded text body " + "(HTML stripped to plain text when needed). Body capped at 30KB with `truncated:true` " + "when cut off.",
|
|
790
|
-
schema:
|
|
791
|
-
id:
|
|
793
|
+
schema: zod__WEBPACK_IMPORTED_MODULE_4__/* .object */ .Ikc({
|
|
794
|
+
id: zod__WEBPACK_IMPORTED_MODULE_4__/* .string */ .YjP().describe("Outlook message id (from outlook_search results)")
|
|
792
795
|
})
|
|
793
796
|
});
|
|
794
797
|
const outlookListFoldersTool = (0,_langchain_core_tools__WEBPACK_IMPORTED_MODULE_0__/* .tool */ .z6)(async ()=>{
|
|
@@ -814,7 +817,7 @@ const outlookListFoldersTool = (0,_langchain_core_tools__WEBPACK_IMPORTED_MODULE
|
|
|
814
817
|
}, {
|
|
815
818
|
name: "outlook_list_folders",
|
|
816
819
|
description: "List all Outlook mail folders. Use the `id` (or `well_known` name like 'inbox', " + "'drafts', 'sentitems', 'deleteditems', 'archive') with outlook_modify_message to move " + "a message between folders.",
|
|
817
|
-
schema:
|
|
820
|
+
schema: zod__WEBPACK_IMPORTED_MODULE_4__/* .object */ .Ikc({})
|
|
818
821
|
});
|
|
819
822
|
const outlookModifyMessageTool = (0,_langchain_core_tools__WEBPACK_IMPORTED_MODULE_0__/* .tool */ .z6)(async ({ id, mark_read, move_to_folder })=>{
|
|
820
823
|
const auth = (0,_lib_integrations_microsoft_oauth__WEBPACK_IMPORTED_MODULE_2__/* .resolveMicrosoftAuth */ .jG)();
|
|
@@ -857,10 +860,10 @@ const outlookModifyMessageTool = (0,_langchain_core_tools__WEBPACK_IMPORTED_MODU
|
|
|
857
860
|
}, {
|
|
858
861
|
name: "outlook_modify_message",
|
|
859
862
|
description: "Modify an Outlook message: mark read/unread and/or move to another folder. Use " + "`mark_read: true` to mark read, `mark_read: false` to mark unread. `move_to_folder` " + "accepts a folder id from outlook_list_folders or a well-known name (e.g. 'archive', " + "'deleteditems'). Note that moving returns a NEW message id because Graph clones the " + "item into the destination folder.",
|
|
860
|
-
schema:
|
|
861
|
-
id:
|
|
862
|
-
mark_read:
|
|
863
|
-
move_to_folder:
|
|
863
|
+
schema: zod__WEBPACK_IMPORTED_MODULE_4__/* .object */ .Ikc({
|
|
864
|
+
id: zod__WEBPACK_IMPORTED_MODULE_4__/* .string */ .YjP().describe("Outlook message id"),
|
|
865
|
+
mark_read: zod__WEBPACK_IMPORTED_MODULE_4__/* .boolean */ .zMY().optional().describe("Mark read (true) or unread (false)"),
|
|
866
|
+
move_to_folder: zod__WEBPACK_IMPORTED_MODULE_4__/* .string */ .YjP().optional().describe("Destination folder id or well-known name")
|
|
864
867
|
})
|
|
865
868
|
});
|
|
866
869
|
const outlookCreateDraftTool = (0,_langchain_core_tools__WEBPACK_IMPORTED_MODULE_0__/* .tool */ .z6)(async ({ to, cc, subject, body, content_type })=>{
|
|
@@ -899,12 +902,12 @@ const outlookCreateDraftTool = (0,_langchain_core_tools__WEBPACK_IMPORTED_MODULE
|
|
|
899
902
|
}, {
|
|
900
903
|
name: "outlook_create_draft",
|
|
901
904
|
description: "Create an Outlook draft email (saved to the Drafts folder, NOT sent). The user opens " + "Outlook to review and click Send. `to` and `cc` are arrays of plain email addresses. " + "`content_type` defaults to 'text'; pass 'html' if `body` contains HTML markup.",
|
|
902
|
-
schema:
|
|
903
|
-
to:
|
|
904
|
-
cc:
|
|
905
|
-
subject:
|
|
906
|
-
body:
|
|
907
|
-
content_type:
|
|
905
|
+
schema: zod__WEBPACK_IMPORTED_MODULE_4__/* .object */ .Ikc({
|
|
906
|
+
to: zod__WEBPACK_IMPORTED_MODULE_4__/* .array */ .YOg(zod__WEBPACK_IMPORTED_MODULE_4__/* .string */ .YjP().email()).min(1).describe("Primary recipient emails"),
|
|
907
|
+
cc: zod__WEBPACK_IMPORTED_MODULE_4__/* .array */ .YOg(zod__WEBPACK_IMPORTED_MODULE_4__/* .string */ .YjP().email()).optional().describe("CC recipient emails"),
|
|
908
|
+
subject: zod__WEBPACK_IMPORTED_MODULE_4__/* .string */ .YjP().optional().describe("Subject line"),
|
|
909
|
+
body: zod__WEBPACK_IMPORTED_MODULE_4__/* .string */ .YjP().max(DRAFT_BODY_MAX_CHARS).optional().describe("Email body (max 100,000 characters)"),
|
|
910
|
+
content_type: zod__WEBPACK_IMPORTED_MODULE_4__/* ["enum"] */ .k5n([
|
|
908
911
|
"text",
|
|
909
912
|
"html"
|
|
910
913
|
]).optional().describe("Body content type (default 'text')")
|
|
@@ -933,8 +936,8 @@ const outlookTrashMessageTool = (0,_langchain_core_tools__WEBPACK_IMPORTED_MODUL
|
|
|
933
936
|
}, {
|
|
934
937
|
name: "outlook_trash_message",
|
|
935
938
|
description: "Move an Outlook message to Deleted Items (recoverable from the trash for 30 days). " + "Does NOT permanently delete. Returns the new message id assigned after the move.",
|
|
936
|
-
schema:
|
|
937
|
-
id:
|
|
939
|
+
schema: zod__WEBPACK_IMPORTED_MODULE_4__/* .object */ .Ikc({
|
|
940
|
+
id: zod__WEBPACK_IMPORTED_MODULE_4__/* .string */ .YjP().describe("Outlook message id to trash")
|
|
938
941
|
})
|
|
939
942
|
});
|
|
940
943
|
const outlookSendEmailTool = (0,_langchain_core_tools__WEBPACK_IMPORTED_MODULE_0__/* .tool */ .z6)(async ({ to, cc, bcc, subject, body, content_type, save_to_sent_items })=>{
|
|
@@ -982,17 +985,17 @@ const outlookSendEmailTool = (0,_langchain_core_tools__WEBPACK_IMPORTED_MODULE_0
|
|
|
982
985
|
}, {
|
|
983
986
|
name: "outlook_send_email",
|
|
984
987
|
description: "Send an Outlook email immediately via Microsoft Graph. Only use when the user explicitly asks " + "to send now; otherwise create a draft with outlook_create_draft. Supports text or HTML bodies " + "via `content_type`. If this returns a 403 scope error, ask the user to reconnect Outlook so " + "Mail.Send is granted.",
|
|
985
|
-
schema:
|
|
986
|
-
to:
|
|
987
|
-
cc:
|
|
988
|
-
bcc:
|
|
989
|
-
subject:
|
|
990
|
-
body:
|
|
991
|
-
content_type:
|
|
988
|
+
schema: zod__WEBPACK_IMPORTED_MODULE_4__/* .object */ .Ikc({
|
|
989
|
+
to: zod__WEBPACK_IMPORTED_MODULE_4__/* .array */ .YOg(zod__WEBPACK_IMPORTED_MODULE_4__/* .string */ .YjP().email()).min(1).describe("Primary recipient emails"),
|
|
990
|
+
cc: zod__WEBPACK_IMPORTED_MODULE_4__/* .array */ .YOg(zod__WEBPACK_IMPORTED_MODULE_4__/* .string */ .YjP().email()).optional().describe("CC recipient emails"),
|
|
991
|
+
bcc: zod__WEBPACK_IMPORTED_MODULE_4__/* .array */ .YOg(zod__WEBPACK_IMPORTED_MODULE_4__/* .string */ .YjP().email()).optional().describe("BCC recipient emails"),
|
|
992
|
+
subject: zod__WEBPACK_IMPORTED_MODULE_4__/* .string */ .YjP().optional().describe("Subject line"),
|
|
993
|
+
body: zod__WEBPACK_IMPORTED_MODULE_4__/* .string */ .YjP().max(SEND_BODY_MAX_CHARS).optional().describe("Email body (max 100,000 characters)"),
|
|
994
|
+
content_type: zod__WEBPACK_IMPORTED_MODULE_4__/* ["enum"] */ .k5n([
|
|
992
995
|
"text",
|
|
993
996
|
"html"
|
|
994
997
|
]).optional().describe("Body content type (default 'text')"),
|
|
995
|
-
save_to_sent_items:
|
|
998
|
+
save_to_sent_items: zod__WEBPACK_IMPORTED_MODULE_4__/* .boolean */ .zMY().optional().describe("Whether Graph should save the message to Sent Items (default true)")
|
|
996
999
|
})
|
|
997
1000
|
});
|
|
998
1001
|
(0,_packages_langchain_package__WEBPACK_IMPORTED_MODULE_1__/* .registerLangChainPackage */ .p)({
|
|
@@ -3832,12 +3835,13 @@ function drainQueuedBoundary(threadId) {
|
|
|
3832
3835
|
function runBoundaryCompaction(threadId, boundarySeq, options) {
|
|
3833
3836
|
const baseThread = (0,threads/* getThread */.fG)(threadId);
|
|
3834
3837
|
const basePinSeq = baseThread?.hot_since_seq ?? null;
|
|
3838
|
+
const baseLock = baseThread?.auto_boundary_locked_until_msg_count ?? 0;
|
|
3835
3839
|
void (0,thread_compaction_state/* runTrackedCompaction */.PL)(threadId, "auto", boundarySeq, async (attempt)=>{
|
|
3836
3840
|
await Promise.resolve();
|
|
3837
|
-
await commitBoundaryCompaction(threadId, boundarySeq, basePinSeq, options, attempt);
|
|
3841
|
+
await commitBoundaryCompaction(threadId, boundarySeq, basePinSeq, baseLock, options, attempt);
|
|
3838
3842
|
}).catch((err)=>console.warn(`[context-boundary:auto] compaction failed thread=${threadId}: ${String(err)}`)).finally(()=>drainQueuedBoundary(threadId));
|
|
3839
3843
|
}
|
|
3840
|
-
async function commitBoundaryCompaction(threadId, boundarySeq, basePinSeq, options, attempt) {
|
|
3844
|
+
async function commitBoundaryCompaction(threadId, boundarySeq, basePinSeq, baseLock, options, attempt) {
|
|
3841
3845
|
const committed = await compactThreadWarmContext(threadId, boundarySeq, {
|
|
3842
3846
|
expectedHotSinceSeq: basePinSeq,
|
|
3843
3847
|
alignTopicBoundary: true,
|
|
@@ -3845,7 +3849,18 @@ async function commitBoundaryCompaction(threadId, boundarySeq, basePinSeq, optio
|
|
|
3845
3849
|
...options,
|
|
3846
3850
|
attempt
|
|
3847
3851
|
});
|
|
3848
|
-
if (!committed)
|
|
3852
|
+
if (!committed) {
|
|
3853
|
+
// A pass that resolved to no change (the active topic still starts at the
|
|
3854
|
+
// current pin) must not be retried on every following turn either. Skip
|
|
3855
|
+
// it when the boundary or lock changed mid-pass (e.g. the user cleared or
|
|
3856
|
+
// moved the boundary): that newer state wins over this stale pass.
|
|
3857
|
+
const lockUntil = options.autoBoundaryLockedUntilMessageCount;
|
|
3858
|
+
const current = (0,threads/* getThread */.fG)(threadId);
|
|
3859
|
+
if (lockUntil !== undefined && current && (current.hot_since_seq ?? null) === basePinSeq && (current.auto_boundary_locked_until_msg_count ?? 0) === baseLock && lockUntil > baseLock) {
|
|
3860
|
+
(0,threads/* setAutoBoundaryLock */.NU)(threadId, lockUntil);
|
|
3861
|
+
}
|
|
3862
|
+
return;
|
|
3863
|
+
}
|
|
3849
3864
|
console.info(`[context-boundary:auto] thread=${threadId} committed boundary_seq=${committed.boundarySeq} warm_msgs=${committed.sourceMessages}`);
|
|
3850
3865
|
}
|
|
3851
3866
|
async function findTopicBoundary(threadId, boundarySeq) {
|
|
@@ -7187,10 +7202,13 @@ function fuzzyUniqueRange(raw, oldString) {
|
|
|
7187
7202
|
if (oldLines.some((line)=>line.length === 0)) return [];
|
|
7188
7203
|
const rawLines = raw.split(/\r\n|\r|\n/);
|
|
7189
7204
|
const rawLineStarts = [];
|
|
7205
|
+
const eol = /\r\n|\r|\n/g;
|
|
7190
7206
|
let offset = 0;
|
|
7191
7207
|
for (const line of rawLines){
|
|
7192
7208
|
rawLineStarts.push(offset);
|
|
7193
|
-
offset
|
|
7209
|
+
eol.lastIndex = offset + line.length;
|
|
7210
|
+
const brk = eol.exec(raw);
|
|
7211
|
+
offset = offset + line.length + (brk ? brk[0].length : 0);
|
|
7194
7212
|
}
|
|
7195
7213
|
const scores = [];
|
|
7196
7214
|
for(let i = 0; i + oldLines.length <= rawLines.length; i++){
|
|
@@ -7247,7 +7265,9 @@ function findAllExact(haystack, needle) {
|
|
|
7247
7265
|
function findWithTransforms(raw, oldString, fns) {
|
|
7248
7266
|
const bufT = composeTransforms(raw, fns);
|
|
7249
7267
|
const oldT = composeTransforms(oldString, fns);
|
|
7250
|
-
|
|
7268
|
+
// A needle that normalizes to bare whitespace would match an arbitrary
|
|
7269
|
+
// line break, so it can never identify an edit target.
|
|
7270
|
+
if (oldT.text.trim().length === 0) return [];
|
|
7251
7271
|
const starts = findAllExact(bufT.text, oldT.text);
|
|
7252
7272
|
return starts.map((s)=>({
|
|
7253
7273
|
start: bufT.toOriginal[s],
|
|
@@ -10698,6 +10718,8 @@ var pricing = __webpack_require__(95601);
|
|
|
10698
10718
|
|
|
10699
10719
|
const CHARS_PER_TOKEN = 4;
|
|
10700
10720
|
const DEFAULT_WINDOW_DAYS = 30;
|
|
10721
|
+
const METRICS_CACHE_MS = 5000;
|
|
10722
|
+
let metricsCache = null;
|
|
10701
10723
|
function recalculateSnapshotCost(input, tables) {
|
|
10702
10724
|
const rates = (0,pricing/* modelRatesFor */.En)(tables, input.provider, input.modelId);
|
|
10703
10725
|
if (rates.inputPer1M == null && rates.outputPer1M == null) return input.recordedCostUsd;
|
|
@@ -10710,7 +10732,17 @@ async function getDashboardMetrics(days = DEFAULT_WINDOW_DAYS) {
|
|
|
10710
10732
|
const now = new Date();
|
|
10711
10733
|
const boundedDays = Number.isFinite(days) ? Math.min(120, Math.max(7, Math.floor(days))) : DEFAULT_WINDOW_DAYS;
|
|
10712
10734
|
const since = new Date(now.getTime() - boundedDays * 24 * 60 * 60 * 1000).toISOString();
|
|
10713
|
-
const
|
|
10735
|
+
const db = (0,lib_db/* getDb */.L)();
|
|
10736
|
+
const tables = (0,pricing/* getPricingTables */.iH)();
|
|
10737
|
+
// total_changes covers this connection; data_version covers other writers.
|
|
10738
|
+
const { changes } = db.prepare("SELECT total_changes() AS changes").get();
|
|
10739
|
+
const { data_version: dataVersion } = db.prepare("PRAGMA data_version").get();
|
|
10740
|
+
if (metricsCache?.db === db && metricsCache.changes === changes && metricsCache.dataVersion === dataVersion && metricsCache.tables === tables && metricsCache.metrics.days === boundedDays && metricsCache.metrics.generated_at.slice(0, 10) === now.toISOString().slice(0, 10) && now.getTime() - metricsCache.createdAt >= 0 && now.getTime() - metricsCache.createdAt < METRICS_CACHE_MS) {
|
|
10741
|
+
return metricsCache.metrics;
|
|
10742
|
+
}
|
|
10743
|
+
const usageRows = db.prepare(`SELECT m.created_at, m.role,
|
|
10744
|
+
CASE WHEN mu.input_tokens IS NULL THEN m.content ELSE '' END AS content,
|
|
10745
|
+
m.tool_events, m.thread_id, t.agent_id,
|
|
10714
10746
|
a.name AS agent_name, mc.provider AS provider,
|
|
10715
10747
|
mc.model_id AS model_id,
|
|
10716
10748
|
COALESCE(ta.model_config_name, a.model_config_name, dmc.name) AS model_config_name,
|
|
@@ -10760,7 +10792,6 @@ async function getDashboardMetrics(days = DEFAULT_WINDOW_DAYS) {
|
|
|
10760
10792
|
snapshotThreadIds.add(r.thread_id);
|
|
10761
10793
|
}
|
|
10762
10794
|
}
|
|
10763
|
-
const tables = (0,pricing/* getPricingTables */.iH)();
|
|
10764
10795
|
const { byProvider, generatedAt } = tables;
|
|
10765
10796
|
const dayMap = seedDayBuckets(now, boundedDays);
|
|
10766
10797
|
const agentMap = new Map();
|
|
@@ -11076,7 +11107,7 @@ async function getDashboardMetrics(days = DEFAULT_WINDOW_DAYS) {
|
|
|
11076
11107
|
by_model: dayModels
|
|
11077
11108
|
};
|
|
11078
11109
|
}
|
|
11079
|
-
|
|
11110
|
+
const metrics = {
|
|
11080
11111
|
generated_at: now.toISOString(),
|
|
11081
11112
|
days: boundedDays,
|
|
11082
11113
|
summary: {
|
|
@@ -11132,6 +11163,15 @@ async function getDashboardMetrics(days = DEFAULT_WINDOW_DAYS) {
|
|
|
11132
11163
|
notes: "Dashboard cost is recalculated from captured provider token usage and the latest matching rates. The original per-turn cost snapshots remain unchanged; legacy rows use content-length token estimates."
|
|
11133
11164
|
}
|
|
11134
11165
|
};
|
|
11166
|
+
metricsCache = {
|
|
11167
|
+
db,
|
|
11168
|
+
changes,
|
|
11169
|
+
dataVersion,
|
|
11170
|
+
tables,
|
|
11171
|
+
createdAt: now.getTime(),
|
|
11172
|
+
metrics
|
|
11173
|
+
};
|
|
11174
|
+
return metrics;
|
|
11135
11175
|
}
|
|
11136
11176
|
function seedDayBuckets(now, days) {
|
|
11137
11177
|
const out = new Map();
|
|
@@ -11675,6 +11715,7 @@ const PRICE_LINE_RE = new RegExp([
|
|
|
11675
11715
|
String.raw`\$\s*\d+(?:\.\d+)?\s*(?:/|per)\s*(?:image|minute|request)`
|
|
11676
11716
|
].join("|"), "gi");
|
|
11677
11717
|
const GOOGLE_RESULT_RE = /href="\/url\?q=([^"&]+)[^"]*"/gi;
|
|
11718
|
+
const GOOGLE_OWN_HOST_RE = /^(?:www|accounts|support|maps|policies|webcache)?\.?google\.[a-z.]+$/i;
|
|
11678
11719
|
function toCanonicalProvider(id) {
|
|
11679
11720
|
const lower = id.toLowerCase();
|
|
11680
11721
|
if (lower.includes("google") || lower.includes("gemini")) return "google";
|
|
@@ -11706,7 +11747,8 @@ async function refreshPricingSnapshot(opts) {
|
|
|
11706
11747
|
const existing = await readPricingSnapshot();
|
|
11707
11748
|
if (!force && existing) {
|
|
11708
11749
|
const ageDays = (Date.now() - Date.parse(existing.generated_at)) / (24 * 60 * 60 * 1000);
|
|
11709
|
-
|
|
11750
|
+
// A future generated_at (clock skew, copied snapshot) must not pin the cache as fresh.
|
|
11751
|
+
if (Number.isFinite(ageDays) && ageDays >= 0 && ageDays < ttlDays) {
|
|
11710
11752
|
return {
|
|
11711
11753
|
refreshed: false,
|
|
11712
11754
|
reason: "fresh",
|
|
@@ -11843,6 +11885,8 @@ function parseGoogleResultLinks(html) {
|
|
|
11843
11885
|
const out = [];
|
|
11844
11886
|
const seen = new Set();
|
|
11845
11887
|
let m;
|
|
11888
|
+
// Shared /g regex: an early break leaves lastIndex mid-string for the next page.
|
|
11889
|
+
GOOGLE_RESULT_RE.lastIndex = 0;
|
|
11846
11890
|
while((m = GOOGLE_RESULT_RE.exec(html)) !== null){
|
|
11847
11891
|
const raw = m[1] ?? "";
|
|
11848
11892
|
let url = "";
|
|
@@ -11852,7 +11896,11 @@ function parseGoogleResultLinks(html) {
|
|
|
11852
11896
|
continue;
|
|
11853
11897
|
}
|
|
11854
11898
|
if (!/^https?:\/\//i.test(url)) continue;
|
|
11855
|
-
|
|
11899
|
+
try {
|
|
11900
|
+
if (GOOGLE_OWN_HOST_RE.test(new URL(url).hostname)) continue;
|
|
11901
|
+
} catch {
|
|
11902
|
+
continue;
|
|
11903
|
+
}
|
|
11856
11904
|
if (seen.has(url)) continue;
|
|
11857
11905
|
seen.add(url);
|
|
11858
11906
|
out.push(url);
|
|
@@ -13511,58 +13559,79 @@ function containsText(source, needle, ignoreCase) {
|
|
|
13511
13559
|
if (!ignoreCase) return source.includes(needle);
|
|
13512
13560
|
return source.toLowerCase().includes(needle.toLowerCase());
|
|
13513
13561
|
}
|
|
13514
|
-
|
|
13515
|
-
|
|
13516
|
-
|
|
13517
|
-
|
|
13518
|
-
|
|
13519
|
-
|
|
13520
|
-
|
|
13521
|
-
|
|
13522
|
-
|
|
13523
|
-
|
|
13524
|
-
...
|
|
13562
|
+
const FENCE_RE = /^\s{0,3}(`{3,}|~{3,})/;
|
|
13563
|
+
const HORIZONTAL_RULE_RE = /^\s{0,3}([-*_])(?:\s*\1){2,}\s*$/;
|
|
13564
|
+
/**
|
|
13565
|
+
* Drop duplicate segments from `parts`, which alternates content (even
|
|
13566
|
+
* indexes) and the original separator that follows it (odd indexes).
|
|
13567
|
+
* Separators are preserved verbatim, so only removed segments change the
|
|
13568
|
+
* text. `keyOf` returns null for a segment that must always be kept.
|
|
13569
|
+
*/ function dedupeSegments(parts, keyOf, keep) {
|
|
13570
|
+
const contentIdx = parts.map((_, i)=>i).filter((i)=>i % 2 === 0);
|
|
13571
|
+
const visit = keep === "first" ? contentIdx : [
|
|
13572
|
+
...contentIdx
|
|
13525
13573
|
].reverse();
|
|
13526
13574
|
const seen = new Set();
|
|
13575
|
+
const dropped = new Set();
|
|
13527
13576
|
for (const idx of visit){
|
|
13528
|
-
const key =
|
|
13529
|
-
if (
|
|
13530
|
-
|
|
13531
|
-
|
|
13532
|
-
|
|
13533
|
-
|
|
13534
|
-
|
|
13535
|
-
|
|
13577
|
+
const key = keyOf(idx);
|
|
13578
|
+
if (key === null) continue;
|
|
13579
|
+
if (seen.has(key)) dropped.add(idx);
|
|
13580
|
+
else seen.add(key);
|
|
13581
|
+
}
|
|
13582
|
+
if (dropped.size === 0) return {
|
|
13583
|
+
text: parts.join(""),
|
|
13584
|
+
removed: 0
|
|
13585
|
+
};
|
|
13586
|
+
let text = "";
|
|
13587
|
+
let emitted = false;
|
|
13588
|
+
for (const idx of contentIdx){
|
|
13589
|
+
if (dropped.has(idx)) continue;
|
|
13590
|
+
if (emitted && idx > 0) text += parts[idx - 1];
|
|
13591
|
+
text += parts[idx];
|
|
13592
|
+
emitted = true;
|
|
13536
13593
|
}
|
|
13537
|
-
const next = lines.filter((_, idx)=>keep.has(idx));
|
|
13538
13594
|
return {
|
|
13539
|
-
text
|
|
13540
|
-
removed:
|
|
13595
|
+
text,
|
|
13596
|
+
removed: dropped.size
|
|
13541
13597
|
};
|
|
13542
13598
|
}
|
|
13599
|
+
function dedupeLines(source, opts) {
|
|
13600
|
+
const parts = source.split(/(\r?\n)/);
|
|
13601
|
+
// Fence markers, fenced code and horizontal rules repeat by design; a
|
|
13602
|
+
// closing ``` is always a "duplicate" of the opening one.
|
|
13603
|
+
const protectedIdx = new Set();
|
|
13604
|
+
let fence = null;
|
|
13605
|
+
for(let i = 0; i < parts.length; i += 2){
|
|
13606
|
+
const marker = FENCE_RE.exec(parts[i])?.[1];
|
|
13607
|
+
if (fence !== null) {
|
|
13608
|
+
protectedIdx.add(i);
|
|
13609
|
+
if (marker && marker[0] === fence[0] && marker.length >= fence.length && /^\s*[`~]+\s*$/.test(parts[i])) fence = null;
|
|
13610
|
+
} else if (marker) {
|
|
13611
|
+
protectedIdx.add(i);
|
|
13612
|
+
fence = marker;
|
|
13613
|
+
} else if (HORIZONTAL_RULE_RE.test(parts[i])) {
|
|
13614
|
+
protectedIdx.add(i);
|
|
13615
|
+
}
|
|
13616
|
+
}
|
|
13617
|
+
return dedupeSegments(parts, (i)=>{
|
|
13618
|
+
if (protectedIdx.has(i)) return null;
|
|
13619
|
+
const normalized = opts.trim ? parts[i].trim() : parts[i];
|
|
13620
|
+
if (opts.skipBlank && normalized.length === 0) return null;
|
|
13621
|
+
return opts.ignoreCase ? normalized.toLowerCase() : normalized;
|
|
13622
|
+
}, opts.keep);
|
|
13623
|
+
}
|
|
13543
13624
|
function dedupeParagraphs(source, opts) {
|
|
13544
|
-
const
|
|
13545
|
-
const
|
|
13546
|
-
|
|
13625
|
+
const tail = /\s*$/.exec(source)?.[0] ?? "";
|
|
13626
|
+
const parts = source.slice(0, source.length - tail.length).split(/(\r?\n(?:[ \t]*\r?\n)+)/);
|
|
13627
|
+
const out = dedupeSegments(parts, (i)=>{
|
|
13628
|
+
if (parts[i].trim().length === 0) return null;
|
|
13629
|
+
const base = opts.trim ? parts[i].trim() : parts[i];
|
|
13547
13630
|
return opts.ignoreCase ? base.toLowerCase() : base;
|
|
13548
|
-
});
|
|
13549
|
-
const keep = new Set();
|
|
13550
|
-
const visit = opts.keep === "first" ? [
|
|
13551
|
-
...keys.keys()
|
|
13552
|
-
] : [
|
|
13553
|
-
...keys.keys()
|
|
13554
|
-
].reverse();
|
|
13555
|
-
const seen = new Set();
|
|
13556
|
-
for (const idx of visit){
|
|
13557
|
-
const key = keys[idx];
|
|
13558
|
-
if (seen.has(key)) continue;
|
|
13559
|
-
seen.add(key);
|
|
13560
|
-
keep.add(idx);
|
|
13561
|
-
}
|
|
13562
|
-
const next = paragraphs.filter((_, idx)=>keep.has(idx));
|
|
13631
|
+
}, opts.keep);
|
|
13563
13632
|
return {
|
|
13564
|
-
text:
|
|
13565
|
-
removed:
|
|
13633
|
+
text: out.text + tail,
|
|
13634
|
+
removed: out.removed
|
|
13566
13635
|
};
|
|
13567
13636
|
}
|
|
13568
13637
|
|
|
@@ -14363,7 +14432,7 @@ function version_getCurrentVersion() {
|
|
|
14363
14432
|
}
|
|
14364
14433
|
|
|
14365
14434
|
;// ./docs/adoption/changesets.json
|
|
14366
|
-
const changesets_namespaceObject = /*#__PURE__*/JSON.parse('{"schema_version":1,"changesets":[{"version":"2.0.1","previous_version":"2.0.0","date":"2026-10-11","hints":[],"commits":["chore(release): bump to 2.0.1","fix(npm): remove oversized runtime assets"],"prompts":[],"tools":[]},{"version":"2.0.2","previous_version":"2.0.1","date":"2026-10-11","hints":[],"commits":["chore(release): bump to 2.0.2","fix(npm): exclude nested server source maps"],"prompts":[],"tools":[]},{"version":"2.0.3","previous_version":"2.0.2","date":"2026-10-12","hints":[],"commits":["chore(release): bump to 2.0.3","fix(npm): remove maps before npm packing"],"prompts":[],"tools":[]},{"version":"2.0.4","previous_version":"2.0.3","date":"2026-10-12","hints":[],"commits":["chore(release): bump to 2.0.4","fix(npm): use installed onnx runtime dependencies"],"prompts":[],"tools":[]},{"version":"2.0.5","previous_version":"2.0.4","date":"2026-10-13","hints":[],"commits":["chore(release): bump to 2.0.5","fix(providers): detect streams that end without events","fix(http): fix gzip response decoding","docs(site): update guides, theme, and architecture diagrams","refactor(bridges): add capability-driven bridge modules","fix(security): update vulnerable media parser","refactor(modules): split built-in provider and package registries"],"prompts":[],"tools":[]},{"version":"2.1.0","previous_version":"2.0.5","date":"2026-10-14","hints":[],"commits":["chore(release): bump to 2.1.0","fix(release): add model download retries and cache","fix(chat): render grouped summary topic previews","fix(workflows): validate legacy checklist items","docs(pricing): document aggregator data sources","feat(core): add verified workflows, pricing signals, and summaries"],"prompts":[{"id":"static.agent.tool-usage-sop","source":"lib/agents/prepare/system-prompt.ts","change":"changed","added_lines":["0. Classify the request. Informational answers may be direct; read/retrieve requests need a read tool; write/change requests need a state-changing tool; destructive requests also need the required confirmation. Use only these operation labels when describing work: read, write, execute, send, schedu…"],"removed_lines":["0. Classify the request. Informational answers may be direct; read/retrieve requests need a read tool; write/change requests need a state-changing tool; destructive requests also need the required confirmation. Use only these operation labels when describing work: read, write, execute, send, schedu…"],"omitted_lines":0},{"id":"system.Tool usage SOP","source":"lib/agents/prepare/system-prompt.ts","change":"changed","added_lines":["0. Classify the request. Informational answers may be direct; read/retrieve requests need a read tool; write/change requests need a state-changing tool; destructive requests also need the required confirmation. Use only these operation labels when describing work: read, write, execute, send, schedu…"],"removed_lines":["0. Classify the request. Informational answers may be direct; read/retrieve requests need a read tool; write/change requests need a state-changing tool; destructive requests also need the required confirmation. Use only these operation labels when describing work: read, write, execute, send, schedu…"],"omitted_lines":0}],"tools":[{"name":"refresh_model_pricing","change":"changed","description_changed":true,"description":"Refresh provider pricing pages and separate OpenRouter/LiteLLM reference feeds, then recalculate dashboard estimates using provider-page rates only. Returns rate changes, source health, confidence, and current-versus-recorded dashboard totals. These are estimates, not invoice amounts.","previous_description":"Refresh the configured official LLM pricing sources and recalculate dashboard estimates using the latest rates. Returns rate changes, source health, confidence, and current-versus-recorded dashboard totals. These are estimates, not invoice amounts.","params_added":[],"params_removed":[],"params_changed":[],"required_added":[],"required_removed":[]},{"name":"workflow_progress","change":"changed","description_changed":true,"description":"Report structured progress for a substantial multi-step task. Use only when the task has several dependent phases, likely spans turns, or needs explicit verification; skip simple tasks and work already covered by native tool progress. For agent-created workflows, send the full current items snapshot on every call and reuse the same workflow_id. Keep secrets and private data out of workflow fields. Mark items done only with observed validation evidence; use needs_attention for blockers; phase=complete requires every item done or skipped. Every item needs input, expected output, and concrete va…","previous_description":"Report structured progress for a substantial multi-step task. Use only when the task has several dependent phases, likely spans turns, or needs explicit verification; skip simple tasks and work already covered by native tool progress. For agent-created workflows, send the full current items snapshot on every call and reuse the same workflow_id. Keep secrets and private data out of workflow fields. Mark items done only after verifying the action; use needs_attention for blockers; phase=complete requires every item done or skipped. The system-owned version_adoption workflow has its own durable …","params_added":["validation_evidence"],"params_removed":[],"params_changed":["items"],"required_added":[],"required_removed":[]}]},{"version":"2.2.0","previous_version":"2.1.0","date":"2026-10-15","hints":[],"commits":["chore(release): bump to 2.2.0","feat(embeddings): add on-demand local model download","fix(build): exclude foreign runtimes from standalone bundles"],"prompts":[],"tools":[]},{"version":"2.2.1","previous_version":"2.2.0","date":"2026-10-15","hints":[],"commits":["chore(release): bump to 2.2.1","fix(api): skip browser http cache for client requests","feat(models): add model enable toggle and atomic default","fix(github-copilot): remove retired pat route"],"prompts":[],"tools":[]},{"version":"2.3.0","previous_version":"2.2.1","date":"2026-10-16","hints":["If an agent\'s instructions or skills tell it to leave fact capture to compaction or to avoid `memory_upsert`, remove that guidance, since agents now save facts during the turn.","If a scheduled task or watcher prompt asks the agent to write memory facts, keep that in the agent\'s own turn; automation channel summaries no longer extract facts."],"commits":["chore(repo): remove dead exports and the unused deepseek package","fix(chat): restore thread activity and bound compaction per thread","fix(chat): render automation recaps in the warm summary card","fix(chat): restore the compacting state after switching agents","fix(chat): allow compacting bridge-only threads, report via toasts","fix(scripts): align make targets and install the current working tree","feat(agents): add topic pipeline to automation channel summaries","feat(agents): add validated topic pipeline for warm compaction","feat(agents): add proactive, validated memory saving for agents","fix(chat): group older summaries into collapsible topic rows","feat(agents): add auto-retry for failed workflow step contracts","feat(chat): add per-step retry to workflow checklists","feat(lifecycle): add release changesets for version adoption","fix(chat): keep boundary locate from snapping to bottom"],"prompts":[{"id":"static.agent.compaction-group","source":"lib/agents/compaction-pipeline.ts","change":"added","added_lines":[],"removed_lines":[],"omitted_lines":0},{"id":"static.agent.compaction-group-automation","source":"lib/agents/compaction-pipeline.ts","change":"added","added_lines":[],"removed_lines":[],"omitted_lines":0},{"id":"static.agent.compaction-topic-recap","source":"lib/agents/compaction-pipeline.ts","change":"added","added_lines":[],"removed_lines":[],"omitted_lines":0},{"id":"static.agent.compaction-topic-recap-automation","source":"lib/agents/compaction-pipeline.ts","change":"added","added_lines":[],"removed_lines":[],"omitted_lines":0},{"id":"static.agent.conversation-summary","source":"lib/agents/conversation-summary.ts","change":"changed","added_lines":["A topic groups every consecutive message about one subject and must","span at least two messages (a request and its reply); fold a stray","single message into the adjacent topic instead of giving it its own."],"removed_lines":[],"omitted_lines":0},{"id":"static.agent.tool-usage-sop","source":"lib/agents/prepare/system-prompt.ts","change":"changed","added_lines":["0. Classify the request. Informational answers may be direct; read/retrieve requests need a read tool; write/change requests need a state-changing tool; destructive requests also need the required confirmation. Use only these operation labels when describing work: read, write, execute, send, schedu…"],"removed_lines":["0. Classify the request. Informational answers may be direct; read/retrieve requests need a read tool; write/change requests need a state-changing tool; destructive requests also need the required confirmation. Use only these operation labels when describing work: read, write, execute, send, schedu…"],"omitted_lines":0},{"id":"system.Memory & recall","source":"lib/agents/prepare/system-prompt.ts","change":"changed","added_lines":["You have long-term memory across sessions, shared with every other Jarela agent. A record you save is available to other agents immediately. Background compaction also extracts facts later, but it runs late and can miss details, so it is a backstop, not your save step.","Proactive save procedure — run it whenever information fits the active memory policy, without waiting to be asked:","1. Trigger: the user states a preference, a fact about themselves or their work, a decision, a constraint, or a correction to something saved; or a tool result verifies a durable fact. Routine status, one-off chatter, secrets, credentials, and raw transcripts never qualify.","2. Check: memory_search (or memory_read for a known key) for an existing record on the same subject. Update that stable key rather than creating a duplicate or contradictory copy.","3. Write: call memory_upsert in the same turn, before your final reply, with namespace=\'facts\', a stable descriptive key, standalone content, concise tags, confidence=\'explicit\' for user-stated information (\'verified\' when tool-backed, \'inferred\' only when useful and reversible), observed_at when t…","4. Validate: the memory_upsert result must contain ok:true and the key you sent. If it failed, correct the arguments and retry once; if it still fails, tell the user it was not saved.","5. Cite: end your reply with one short line naming each saved key, for example \'Saved to memory: facts/answer-format-preference\'. Omit the line when nothing was saved."],"removed_lines":["You have long-term memory across sessions.","- Use memory_upsert proactively for structured records. Use namespace=\'facts\', concise tags, confidence=\'explicit\' for user-stated information, observed_at when the information was true, and expires_at for temporary facts. Keep memory_write only for legacy/free-form notes."],"omitted_lines":0},{"id":"system.Tool usage SOP","source":"lib/agents/prepare/system-prompt.ts","change":"changed","added_lines":["0. Classify the request. Informational answers may be direct; read/retrieve requests need a read tool; write/change requests need a state-changing tool; destructive requests also need the required confirmation. Use only these operation labels when describing work: read, write, execute, send, schedu…"],"removed_lines":["0. Classify the request. Informational answers may be direct; read/retrieve requests need a read tool; write/change requests need a state-changing tool; destructive requests also need the required confirmation. Use only these operation labels when describing work: read, write, execute, send, schedu…"],"omitted_lines":0}],"tools":[{"name":"memory_upsert","change":"changed","description_changed":true,"description":"Store a durable, structured memory record for proactive semantic recall. Use namespace=\'facts\' for information that should surface in future conversations. Store explicit user preferences, verified facts, decisions, constraints, and reusable project context; do not store transient chat details or secrets. Use an expiry for temporary facts, and status=\'archived\' to soft-retire a record instead of deleting it. Save proactively in the same turn the information appears so other agents can use it immediately; do not defer to background compaction.","previous_description":"Store a durable, structured memory record for proactive semantic recall. Use namespace=\'facts\' for information that should surface in future conversations. Store explicit user preferences, verified facts, decisions, constraints, and reusable project context; do not store transient chat details or secrets. Use an expiry for temporary facts, and status=\'archived\' to soft-retire a record instead of deleting it.","params_added":[],"params_removed":[],"params_changed":[],"required_added":[],"required_removed":[]},{"name":"workflow_progress","change":"changed","description_changed":true,"description":"Report structured progress for a substantial multi-step task. Use only when the task has several dependent phases, likely spans turns, or needs explicit verification; skip simple tasks and work already covered by native tool progress. For agent-created workflows, send the full current items snapshot on every call and reuse the same workflow_id. Keep secrets and private data out of workflow fields. Mark items done only with observed validation evidence; use needs_attention for blockers; phase=complete requires every item done or skipped. A rejected update, or a step left checking or needs_atte…","previous_description":"Report structured progress for a substantial multi-step task. Use only when the task has several dependent phases, likely spans turns, or needs explicit verification; skip simple tasks and work already covered by native tool progress. For agent-created workflows, send the full current items snapshot on every call and reuse the same workflow_id. Keep secrets and private data out of workflow fields. Mark items done only with observed validation evidence; use needs_attention for blockers; phase=complete requires every item done or skipped. Every item needs input, expected output, and concrete va…","params_added":["needs_user"],"params_removed":[],"params_changed":[],"required_added":[],"required_removed":[]}]}]}');
|
|
14435
|
+
const changesets_namespaceObject = /*#__PURE__*/JSON.parse('{"schema_version":1,"changesets":[{"version":"2.0.1","previous_version":"2.0.0","date":"2026-10-11","hints":[],"commits":["chore(release): bump to 2.0.1","fix(npm): remove oversized runtime assets"],"prompts":[],"tools":[]},{"version":"2.0.2","previous_version":"2.0.1","date":"2026-10-11","hints":[],"commits":["chore(release): bump to 2.0.2","fix(npm): exclude nested server source maps"],"prompts":[],"tools":[]},{"version":"2.0.3","previous_version":"2.0.2","date":"2026-10-12","hints":[],"commits":["chore(release): bump to 2.0.3","fix(npm): remove maps before npm packing"],"prompts":[],"tools":[]},{"version":"2.0.4","previous_version":"2.0.3","date":"2026-10-12","hints":[],"commits":["chore(release): bump to 2.0.4","fix(npm): use installed onnx runtime dependencies"],"prompts":[],"tools":[]},{"version":"2.0.5","previous_version":"2.0.4","date":"2026-10-13","hints":[],"commits":["chore(release): bump to 2.0.5","fix(providers): detect streams that end without events","fix(http): fix gzip response decoding","docs(site): update guides, theme, and architecture diagrams","refactor(bridges): add capability-driven bridge modules","fix(security): update vulnerable media parser","refactor(modules): split built-in provider and package registries"],"prompts":[],"tools":[]},{"version":"2.1.0","previous_version":"2.0.5","date":"2026-10-14","hints":[],"commits":["chore(release): bump to 2.1.0","fix(release): add model download retries and cache","fix(chat): render grouped summary topic previews","fix(workflows): validate legacy checklist items","docs(pricing): document aggregator data sources","feat(core): add verified workflows, pricing signals, and summaries"],"prompts":[{"id":"static.agent.tool-usage-sop","source":"lib/agents/prepare/system-prompt.ts","change":"changed","added_lines":["0. Classify the request. Informational answers may be direct; read/retrieve requests need a read tool; write/change requests need a state-changing tool; destructive requests also need the required confirmation. Use only these operation labels when describing work: read, write, execute, send, schedu…"],"removed_lines":["0. Classify the request. Informational answers may be direct; read/retrieve requests need a read tool; write/change requests need a state-changing tool; destructive requests also need the required confirmation. Use only these operation labels when describing work: read, write, execute, send, schedu…"],"omitted_lines":0},{"id":"system.Tool usage SOP","source":"lib/agents/prepare/system-prompt.ts","change":"changed","added_lines":["0. Classify the request. Informational answers may be direct; read/retrieve requests need a read tool; write/change requests need a state-changing tool; destructive requests also need the required confirmation. Use only these operation labels when describing work: read, write, execute, send, schedu…"],"removed_lines":["0. Classify the request. Informational answers may be direct; read/retrieve requests need a read tool; write/change requests need a state-changing tool; destructive requests also need the required confirmation. Use only these operation labels when describing work: read, write, execute, send, schedu…"],"omitted_lines":0}],"tools":[{"name":"refresh_model_pricing","change":"changed","description_changed":true,"description":"Refresh provider pricing pages and separate OpenRouter/LiteLLM reference feeds, then recalculate dashboard estimates using provider-page rates only. Returns rate changes, source health, confidence, and current-versus-recorded dashboard totals. These are estimates, not invoice amounts.","previous_description":"Refresh the configured official LLM pricing sources and recalculate dashboard estimates using the latest rates. Returns rate changes, source health, confidence, and current-versus-recorded dashboard totals. These are estimates, not invoice amounts.","params_added":[],"params_removed":[],"params_changed":[],"required_added":[],"required_removed":[]},{"name":"workflow_progress","change":"changed","description_changed":true,"description":"Report structured progress for a substantial multi-step task. Use only when the task has several dependent phases, likely spans turns, or needs explicit verification; skip simple tasks and work already covered by native tool progress. For agent-created workflows, send the full current items snapshot on every call and reuse the same workflow_id. Keep secrets and private data out of workflow fields. Mark items done only with observed validation evidence; use needs_attention for blockers; phase=complete requires every item done or skipped. Every item needs input, expected output, and concrete va…","previous_description":"Report structured progress for a substantial multi-step task. Use only when the task has several dependent phases, likely spans turns, or needs explicit verification; skip simple tasks and work already covered by native tool progress. For agent-created workflows, send the full current items snapshot on every call and reuse the same workflow_id. Keep secrets and private data out of workflow fields. Mark items done only after verifying the action; use needs_attention for blockers; phase=complete requires every item done or skipped. The system-owned version_adoption workflow has its own durable …","params_added":["validation_evidence"],"params_removed":[],"params_changed":["items"],"required_added":[],"required_removed":[]}]},{"version":"2.2.0","previous_version":"2.1.0","date":"2026-10-15","hints":[],"commits":["chore(release): bump to 2.2.0","feat(embeddings): add on-demand local model download","fix(build): exclude foreign runtimes from standalone bundles"],"prompts":[],"tools":[]},{"version":"2.2.1","previous_version":"2.2.0","date":"2026-10-15","hints":[],"commits":["chore(release): bump to 2.2.1","fix(api): skip browser http cache for client requests","feat(models): add model enable toggle and atomic default","fix(github-copilot): remove retired pat route"],"prompts":[],"tools":[]},{"version":"2.3.0","previous_version":"2.2.1","date":"2026-10-16","hints":["If an agent\'s instructions or skills tell it to leave fact capture to compaction or to avoid `memory_upsert`, remove that guidance, since agents now save facts during the turn.","If a scheduled task or watcher prompt asks the agent to write memory facts, keep that in the agent\'s own turn; automation channel summaries no longer extract facts."],"commits":["chore(repo): remove dead exports and the unused deepseek package","fix(chat): restore thread activity and bound compaction per thread","fix(chat): render automation recaps in the warm summary card","fix(chat): restore the compacting state after switching agents","fix(chat): allow compacting bridge-only threads, report via toasts","fix(scripts): align make targets and install the current working tree","feat(agents): add topic pipeline to automation channel summaries","feat(agents): add validated topic pipeline for warm compaction","feat(agents): add proactive, validated memory saving for agents","fix(chat): group older summaries into collapsible topic rows","feat(agents): add auto-retry for failed workflow step contracts","feat(chat): add per-step retry to workflow checklists","feat(lifecycle): add release changesets for version adoption","fix(chat): keep boundary locate from snapping to bottom"],"prompts":[{"id":"static.agent.compaction-group","source":"lib/agents/compaction-pipeline.ts","change":"added","added_lines":[],"removed_lines":[],"omitted_lines":0},{"id":"static.agent.compaction-group-automation","source":"lib/agents/compaction-pipeline.ts","change":"added","added_lines":[],"removed_lines":[],"omitted_lines":0},{"id":"static.agent.compaction-topic-recap","source":"lib/agents/compaction-pipeline.ts","change":"added","added_lines":[],"removed_lines":[],"omitted_lines":0},{"id":"static.agent.compaction-topic-recap-automation","source":"lib/agents/compaction-pipeline.ts","change":"added","added_lines":[],"removed_lines":[],"omitted_lines":0},{"id":"static.agent.conversation-summary","source":"lib/agents/conversation-summary.ts","change":"changed","added_lines":["A topic groups every consecutive message about one subject and must","span at least two messages (a request and its reply); fold a stray","single message into the adjacent topic instead of giving it its own."],"removed_lines":[],"omitted_lines":0},{"id":"static.agent.tool-usage-sop","source":"lib/agents/prepare/system-prompt.ts","change":"changed","added_lines":["0. Classify the request. Informational answers may be direct; read/retrieve requests need a read tool; write/change requests need a state-changing tool; destructive requests also need the required confirmation. Use only these operation labels when describing work: read, write, execute, send, schedu…"],"removed_lines":["0. Classify the request. Informational answers may be direct; read/retrieve requests need a read tool; write/change requests need a state-changing tool; destructive requests also need the required confirmation. Use only these operation labels when describing work: read, write, execute, send, schedu…"],"omitted_lines":0},{"id":"system.Memory & recall","source":"lib/agents/prepare/system-prompt.ts","change":"changed","added_lines":["You have long-term memory across sessions, shared with every other Jarela agent. A record you save is available to other agents immediately. Background compaction also extracts facts later, but it runs late and can miss details, so it is a backstop, not your save step.","Proactive save procedure — run it whenever information fits the active memory policy, without waiting to be asked:","1. Trigger: the user states a preference, a fact about themselves or their work, a decision, a constraint, or a correction to something saved; or a tool result verifies a durable fact. Routine status, one-off chatter, secrets, credentials, and raw transcripts never qualify.","2. Check: memory_search (or memory_read for a known key) for an existing record on the same subject. Update that stable key rather than creating a duplicate or contradictory copy.","3. Write: call memory_upsert in the same turn, before your final reply, with namespace=\'facts\', a stable descriptive key, standalone content, concise tags, confidence=\'explicit\' for user-stated information (\'verified\' when tool-backed, \'inferred\' only when useful and reversible), observed_at when t…","4. Validate: the memory_upsert result must contain ok:true and the key you sent. If it failed, correct the arguments and retry once; if it still fails, tell the user it was not saved.","5. Cite: end your reply with one short line naming each saved key, for example \'Saved to memory: facts/answer-format-preference\'. Omit the line when nothing was saved."],"removed_lines":["You have long-term memory across sessions.","- Use memory_upsert proactively for structured records. Use namespace=\'facts\', concise tags, confidence=\'explicit\' for user-stated information, observed_at when the information was true, and expires_at for temporary facts. Keep memory_write only for legacy/free-form notes."],"omitted_lines":0},{"id":"system.Tool usage SOP","source":"lib/agents/prepare/system-prompt.ts","change":"changed","added_lines":["0. Classify the request. Informational answers may be direct; read/retrieve requests need a read tool; write/change requests need a state-changing tool; destructive requests also need the required confirmation. Use only these operation labels when describing work: read, write, execute, send, schedu…"],"removed_lines":["0. Classify the request. Informational answers may be direct; read/retrieve requests need a read tool; write/change requests need a state-changing tool; destructive requests also need the required confirmation. Use only these operation labels when describing work: read, write, execute, send, schedu…"],"omitted_lines":0}],"tools":[{"name":"memory_upsert","change":"changed","description_changed":true,"description":"Store a durable, structured memory record for proactive semantic recall. Use namespace=\'facts\' for information that should surface in future conversations. Store explicit user preferences, verified facts, decisions, constraints, and reusable project context; do not store transient chat details or secrets. Use an expiry for temporary facts, and status=\'archived\' to soft-retire a record instead of deleting it. Save proactively in the same turn the information appears so other agents can use it immediately; do not defer to background compaction.","previous_description":"Store a durable, structured memory record for proactive semantic recall. Use namespace=\'facts\' for information that should surface in future conversations. Store explicit user preferences, verified facts, decisions, constraints, and reusable project context; do not store transient chat details or secrets. Use an expiry for temporary facts, and status=\'archived\' to soft-retire a record instead of deleting it.","params_added":[],"params_removed":[],"params_changed":[],"required_added":[],"required_removed":[]},{"name":"workflow_progress","change":"changed","description_changed":true,"description":"Report structured progress for a substantial multi-step task. Use only when the task has several dependent phases, likely spans turns, or needs explicit verification; skip simple tasks and work already covered by native tool progress. For agent-created workflows, send the full current items snapshot on every call and reuse the same workflow_id. Keep secrets and private data out of workflow fields. Mark items done only with observed validation evidence; use needs_attention for blockers; phase=complete requires every item done or skipped. A rejected update, or a step left checking or needs_atte…","previous_description":"Report structured progress for a substantial multi-step task. Use only when the task has several dependent phases, likely spans turns, or needs explicit verification; skip simple tasks and work already covered by native tool progress. For agent-created workflows, send the full current items snapshot on every call and reuse the same workflow_id. Keep secrets and private data out of workflow fields. Mark items done only with observed validation evidence; use needs_attention for blockers; phase=complete requires every item done or skipped. Every item needs input, expected output, and concrete va…","params_added":["needs_user"],"params_removed":[],"params_changed":[],"required_added":[],"required_removed":[]}]},{"version":"2.4.0","previous_version":"2.3.0","date":"2026-10-16","hints":["If an agent\'s instructions or skills tell it not to include links or URLs in replies, decide whether it should now cite sources with the provided `cite_as` and chat links.","If you listed `localhost` or `127.0.0.1` in the proxy bypass list only to reach local services, you can remove them; loopback is always direct now."],"commits":["fix(core): keep proxy loopback direct, unicode fact keys, agent tuning","fix(agents): avoid repeated compaction from bridge rows and topic pins","fix(core): keep per-chat backlog, permalink refs and code fences","fix(core): fix edge cases in edits, paging, bridges and pricing","feat(integrations): add source permalinks to mail, calendar, chats"],"prompts":[{"id":"static.agent.tool-usage-sop","source":"lib/agents/prepare/system-prompt.ts","change":"changed","added_lines":["10. Link the source. When your reply refers to a specific email, calendar event, or chat that a tool result or bridge message gave you, link it: paste the item\'s cite_as value verbatim when present, otherwise use its web_link, html_link, or chat_link URL as a markdown link. Use only links you were …"],"removed_lines":[],"omitted_lines":0},{"id":"system.Delivery channel","source":"lib/agents/prepare/system-prompt.ts","change":"changed","added_lines":["WhatsApp does not render markdown links: write any link as the bare URL, even where a cite_as value is given."],"removed_lines":[],"omitted_lines":0},{"id":"system.Tool usage SOP","source":"lib/agents/prepare/system-prompt.ts","change":"changed","added_lines":["10. Link the source. When your reply refers to a specific email, calendar event, or chat that a tool result or bridge message gave you, link it: paste the item\'s cite_as value verbatim when present, otherwise use its web_link, html_link, or chat_link URL as a markdown link. Use only links you were …"],"removed_lines":[],"omitted_lines":0}],"tools":[]},{"version":"2.5.0","previous_version":"2.4.0","date":"2026-10-18","hints":[],"commits":["perf(chat): reuse startup reads when opening an agent","fix(chat): use available width and contain tool pill content","perf(db): use indexed reads and reuse chat history renders","fix(ui): align configuration panel widths","fix(packages): use workspace fallback for optional packages","feat(ui): add appearance presets and reorganize panels","fix(models): align live catalog capability metadata","fix(models): update provider model catalogs"],"prompts":[{"id":"system.Enabled tools","source":"lib/agents/prepare/system-prompt.ts","change":"changed","added_lines":["You can execute the 83 tool(s) listed below directly, plus 0 further permitted tool(s) through invoke_tool. 166 known tool(s) are not enabled for this agent; 0 known tool(s) are globally unavailable."],"removed_lines":["You can execute the 83 tool(s) listed below directly, plus 0 further permitted tool(s) through invoke_tool. 39 known tool(s) are not enabled for this agent; 0 known tool(s) are globally unavailable."],"omitted_lines":0}],"tools":[{"name":"confluence_add_comment","change":"added","description_changed":false,"description":"Add a footer comment to a Confluence page (v2). Pass exactly one of `body_text` or `body_storage`. Pass `parent_comment_id` (from confluence_get_comments) to reply in a thread.","params_added":["async_run","body_storage","body_text","deadline_ms","page_id","parent_comment_id","stream"],"params_removed":[],"params_changed":[],"required_added":["page_id"],"required_removed":[]},{"name":"confluence_add_label","change":"added","description_changed":false,"description":"Add one or more labels to a Confluence page (additive — does not replace existing labels). Uses the v1 endpoint (v2 only reads labels as of 2026).","params_added":["async_run","deadline_ms","labels","page_id","stream"],"params_removed":[],"params_changed":[],"required_added":["labels","page_id"],"required_removed":[]},{"name":"confluence_create_page","change":"added","description_changed":false,"description":"Create a Confluence page (v2). Pass `space_key` (e.g. \'ENG\') — auto-resolved to v2 spaceId. Pass exactly one of `body_text` (plain text → storage XHTML automatically) or `body_storage` (raw XHTML for advanced edits). `parent_id` makes it a child page. Disable to make the agent unable to author Confluence pages.","params_added":["async_run","body_storage","body_text","deadline_ms","parent_id","space_key","stream","title"],"params_removed":[],"params_changed":[],"required_added":["space_key","title"],"required_removed":[]},{"name":"confluence_delete_attachment","change":"added","description_changed":false,"description":"Delete a Confluence attachment by id (v2). Default soft-deletes (trash, restorable). Pass purge=true for permanent deletion, which **also requires `confirm` to equal attachment_id** as a guardrail.","params_added":["async_run","attachment_id","confirm","deadline_ms","purge","stream"],"params_removed":[],"params_changed":[],"required_added":["attachment_id"],"required_removed":[]},{"name":"confluence_delete_comment","change":"added","description_changed":false,"description":"Permanently delete a Confluence comment (v2). Pass `kind: \'footer\' | \'inline\'`. **Destructive — no undo.** Disable to make the agent unable to delete comments.","params_added":["async_run","comment_id","deadline_ms","kind","stream"],"params_removed":[],"params_changed":[],"required_added":["comment_id","kind"],"required_removed":[]},{"name":"confluence_delete_page","change":"added","description_changed":false,"description":"Delete a Confluence page (v2). Default soft-deletes (page goes to trash, restorable). Pass purge=true for permanent deletion, which **also requires `confirm` to equal page_id** as a guardrail. Disable to make the agent unable to delete pages.","params_added":["async_run","confirm","deadline_ms","page_id","purge","stream"],"params_removed":[],"params_changed":[],"required_added":["page_id"],"required_removed":[]},{"name":"confluence_get_attachment_content","change":"added","description_changed":false,"description":"Fetch an attachment\'s bytes by its download_link (from confluence_list_attachments). Returns UTF-8 text (capped at 50KB) for text-like content types, or base64 for binary. Override the auto-detection via `as_text`.","params_added":["as_text","async_run","deadline_ms","download_link","stream"],"params_removed":[],"params_changed":[],"required_added":["download_link"],"required_removed":[]},{"name":"confluence_get_comments","change":"added","description_changed":false,"description":"List footer comments (and inline comments by default) on a Confluence page. Returns id, version, author_id, created_at, body_storage, parent_comment_id (for threading). Tolerates the known v2 inline-comments 404 bug — surfaces it as `inline_warning` rather than failing.","params_added":["async_run","deadline_ms","include_inline","page_id","stream"],"params_removed":[],"params_changed":[],"required_added":["page_id"],"required_removed":[]},{"name":"confluence_get_labels","change":"added","description_changed":false,"description":"List labels on a Confluence page (cursor-paginated). Default limit 50 (max 250).","params_added":["async_run","cursor","deadline_ms","limit","page_id","stream"],"params_removed":[],"params_changed":[],"required_added":["page_id"],"required_removed":[]},{"name":"confluence_get_page","change":"added","description_changed":false,"description":"Fetch a Confluence page by id (v2). Returns title, space_id, parent_id, version, and BOTH body_storage (round-trippable into confluence_update_page) and body_view (rendered HTML, easier to summarize). Each body capped at 20KB.","params_added":["async_run","deadline_ms","page_id","stream"],"params_removed":[],"params_changed":[],"required_added":["page_id"],"required_removed":[]},{"name":"confluence_get_page_ancestors","change":"added","description_changed":false,"description":"Return the parent chain (root → leaf) for a Confluence page. Useful for breadcrumbs and understanding where a page lives in the tree.","params_added":["async_run","deadline_ms","page_id","stream"],"params_removed":[],"params_changed":[],"required_added":["page_id"],"required_removed":[]},{"name":"confluence_get_page_by_title","change":"added","description_changed":false,"description":"Find Confluence page(s) by exact title within a space. Auto-resolves `space_key` (e.g. \'ENG\') to the v2 space id. Returns up to 5 matches; pass `include_body: true` to also include storage XHTML.","params_added":["async_run","deadline_ms","include_body","space_key","stream","title"],"params_removed":[],"params_changed":[],"required_added":["space_key","title"],"required_removed":[]},{"name":"confluence_get_page_children","change":"added","description_changed":false,"description":"List direct children of a Confluence page (cursor-paginated). Pass `cursor` from a prior call\'s `next_cursor` to fetch the next page. Default limit 25 (max 250).","params_added":["async_run","cursor","deadline_ms","limit","page_id","stream"],"params_removed":[],"params_changed":[],"required_added":["page_id"],"required_removed":[]},{"name":"confluence_list_attachments","change":"added","description_changed":false,"description":"List attachments on a Confluence page (cursor-paginated). Returns id, title, media_type, file_size, download_link. Use confluence_get_attachment_content with the download_link to fetch bytes.","params_added":["async_run","cursor","deadline_ms","limit","page_id","stream"],"params_removed":[],"params_changed":[],"required_added":["page_id"],"required_removed":[]},{"name":"confluence_list_spaces","change":"added","description_changed":false,"description":"List Confluence spaces (cursor-paginated). Returns id, key, name, type, status, homepage_id. Useful for discovering space keys to pass to confluence_create_page or confluence_get_page_by_title.","params_added":["async_run","cursor","deadline_ms","limit","status","stream","type"],"params_removed":[],"params_changed":[],"required_added":[],"required_removed":[]},{"name":"confluence_move_page","change":"added","description_changed":false,"description":"Reorder/reparent a Confluence page (v2). `position`: \'before\' or \'after\' to place as a sibling of `target_id`; \'append\' to make it a child of `target_id`. Non-destructive.","params_added":["async_run","deadline_ms","page_id","position","stream","target_id"],"params_removed":[],"params_changed":[],"required_added":["page_id","position","target_id"],"required_removed":[]},{"name":"confluence_remove_label","change":"added","description_changed":false,"description":"Remove a single label from a Confluence page. Uses the v1 endpoint (v2 Label group is still read-only as of 2026). Counterpart to confluence_add_label.","params_added":["async_run","deadline_ms","label","page_id","stream"],"params_removed":[],"params_changed":[],"required_added":["label","page_id"],"required_removed":[]},{"name":"confluence_search","change":"added","description_changed":false,"description":"Search Confluence pages with CQL (Confluence Query Language). Examples: \'type=page AND title~\\"runbook\\"\', \'space=ENG AND lastmodified > now(\\"-7d\\")\'.","params_added":["async_run","cql","deadline_ms","max_results","stream"],"params_removed":[],"params_changed":[],"required_added":["cql"],"required_removed":[]},{"name":"confluence_update_comment","change":"added","description_changed":false,"description":"Edit an existing Confluence comment (v2). Pass `kind: \'footer\' | \'inline\'` to route to the correct endpoint. Same `body_text` xor `body_storage` pattern as confluence_add_comment. If version_number is omitted, the tool auto-fetches the current version and sends current+1 (Confluence requires strict +1 increments).","params_added":["async_run","body_storage","body_text","comment_id","deadline_ms","kind","stream","version_message","version_number"],"params_removed":[],"params_changed":[],"required_added":["comment_id","kind"],"required_removed":[]},{"name":"confluence_update_page","change":"added","description_changed":false,"description":"Update an existing Confluence page (v2). Pass exactly one of `body_text` or `body_storage`. If `version_number` is omitted, the tool auto-fetches the current version and sends current+1 (Confluence requires strict +1 increments; gaps cause 409). If `title` is omitted, the existing title is preserved. Avoid back-to-back updates within ~1 second — Confluence may return 409 even with the correct version. Disable to make the agent read-only on pages.","params_added":["async_run","body_storage","body_text","deadline_ms","page_id","stream","title","version_message","version_number"],"params_removed":[],"params_changed":[],"required_added":["page_id"],"required_removed":[]},{"name":"confluence_upload_attachment","change":"added","description_changed":false,"description":"Attach a file to a Confluence page. Pass content_base64 for binary or content_text for plain UTF-8. Uses the v1 multipart endpoint (v2 has no attachment-create endpoint as of 2026). Disable to make the agent unable to add attachments.","params_added":["async_run","comment","content_base64","content_text","deadline_ms","filename","minor_edit","page_id","stream"],"params_removed":[],"params_changed":[],"required_added":["filename","page_id"],"required_removed":[]},{"name":"github_add_comment","change":"added","description_changed":false,"description":"Post a comment on an issue or pull request (GitHub treats both the same). **PREFER THIS over shell-exec\'ing the `gh` CLI.** Body is rendered as GitHub-flavored Markdown.","params_added":["async_run","body","deadline_ms","number","owner","repo","stream"],"params_removed":[],"params_changed":[],"required_added":["body","number","owner","repo"],"required_removed":[]},{"name":"github_create_issue","change":"added","description_changed":false,"description":"Open a new issue in a repository. **PREFER THIS over shell-exec\'ing the `gh` CLI.** Labels and assignees must already exist on the repo — invalid values produce a 422.","params_added":["assignees","async_run","body","deadline_ms","labels","owner","repo","stream","title"],"params_removed":[],"params_changed":[],"required_added":["owner","repo","title"],"required_removed":[]},{"name":"github_create_pull","change":"added","description_changed":false,"description":"Open a pull request. **PREFER THIS over shell-exec\'ing the `gh` CLI.** `head` is the branch with your changes (use `user:branch` for cross-fork PRs); `base` is the branch you want to merge into. Returns 422 if the head/base pair has no diff or if the branches don\'t exist.","params_added":["async_run","base","body","deadline_ms","draft","head","maintainer_can_modify","owner","repo","stream","title"],"params_removed":[],"params_changed":[],"required_added":["base","head","owner","repo","title"],"required_removed":[]},{"name":"github_create_review","change":"added","description_changed":false,"description":"Submit a pull-request review (approve / request changes / leave a comment). **PREFER THIS over shell-exec\'ing the `gh` CLI.** `event=APPROVE` doesn\'t require a body. `event=REQUEST_CHANGES` requires a body. Line-level inline review comments aren\'t supported by this tool yet — use the GitHub UI for those.","params_added":["async_run","body","commit_id","deadline_ms","event","number","owner","repo","stream"],"params_removed":[],"params_changed":[],"required_added":["event","number","owner","repo"],"required_removed":[]},{"name":"github_get_file","change":"added","description_changed":false,"description":"Read a file\'s contents from a repo at an optional ref (branch / tag / commit SHA). **PREFER THIS over shell-exec\'ing the `gh` CLI.** Returns up to 20 KB of UTF-8 text; longer files are truncated with `truncated: true`. Binary files return `binary: true` and `size_bytes` instead of `content`. GitHub itself rejects files larger than ~1 MB on this endpoint.","params_added":["async_run","deadline_ms","owner","path","ref","repo","stream"],"params_removed":[],"params_changed":[],"required_added":["owner","path","repo"],"required_removed":[]},{"name":"github_get_issue","change":"added","description_changed":false,"description":"Fetch a single issue (or PR — same endpoint) by number. Returns body capped at 20KB, plus labels, assignees, and timestamps. **PREFER THIS over shell-exec\'ing the `gh` CLI.**","params_added":["async_run","deadline_ms","number","owner","repo","stream"],"params_removed":[],"params_changed":[],"required_added":["number","owner","repo"],"required_removed":[]},{"name":"github_get_pull","change":"added","description_changed":false,"description":"Fetch detail on a single pull request — head/base SHAs, mergeable state, additions/deletions, changed files count, review comment count. **PREFER THIS over shell-exec\'ing the `gh` CLI.** Note: `mergeable` may be null on a freshly-pushed PR; GitHub computes it asynchronously.","params_added":["async_run","deadline_ms","number","owner","repo","stream"],"params_removed":[],"params_changed":[],"required_added":["number","owner","repo"],"required_removed":[]},{"name":"github_get_repo","change":"added","description_changed":false,"description":"Fetch repo summary (default branch, visibility, description, topics, star/fork counts, open-issue count). **PREFER THIS over shell-exec\'ing the `gh` CLI.** Useful before opening an issue (to confirm the repo exists / pick the right default branch).","params_added":["async_run","deadline_ms","owner","repo","stream"],"params_removed":[],"params_changed":[],"required_added":["owner","repo"],"required_removed":[]},{"name":"github_list_branches","change":"added","description_changed":false,"description":"List branches in a repository with their head SHAs and protection state. **PREFER THIS over shell-exec\'ing the `gh` CLI.** Useful before opening a PR (confirm the head branch exists and is the SHA you expect).","params_added":["async_run","deadline_ms","max_results","owner","repo","stream"],"params_removed":[],"params_changed":[],"required_added":["owner","repo"],"required_removed":[]},{"name":"github_list_issue_comments","change":"added","description_changed":false,"description":"List comments on an issue or PR. **PREFER THIS over shell-exec\'ing the `gh` CLI.** Each comment body is capped at 8 KB; `truncated: true` flags ones that hit the cap.","params_added":["async_run","deadline_ms","max_results","number","owner","repo","stream"],"params_removed":[],"params_changed":[],"required_added":["number","owner","repo"],"required_removed":[]},{"name":"github_list_pull_files","change":"added","description_changed":false,"description":"List files changed in a pull request, with per-file additions/deletions and (capped) patch text. **PREFER THIS over shell-exec\'ing the `gh` CLI.** Each patch caps at 8 KB; `patch_truncated: true` means the diff was longer than that. GitHub itself caps the response at 3000 files.","params_added":["async_run","deadline_ms","max_results","number","owner","repo","stream"],"params_removed":[],"params_changed":[],"required_added":["number","owner","repo"],"required_removed":[]},{"name":"github_list_pull_reviews","change":"added","description_changed":false,"description":"List reviews submitted on a pull request (approvals, change-requests, comment-only). **PREFER THIS over shell-exec\'ing the `gh` CLI.** Use this to check whether a PR is approved before calling github_merge_pull.","params_added":["async_run","deadline_ms","max_results","number","owner","repo","stream"],"params_removed":[],"params_changed":[],"required_added":["number","owner","repo"],"required_removed":[]},{"name":"github_list_pulls","change":"added","description_changed":false,"description":"List pull requests for a repository, optionally filtered by state / head branch / base branch. **PREFER THIS over shell-exec\'ing the `gh` CLI.** For richer detail on a single PR (mergeable, review state, file count) call github_get_pull.","params_added":["async_run","base","deadline_ms","head","max_results","owner","repo","state","stream"],"params_removed":[],"params_changed":[],"required_added":["owner","repo"],"required_removed":[]},{"name":"github_merge_pull","change":"added","description_changed":false,"description":"Merge a pull request. **PREFER THIS over shell-exec\'ing the `gh` CLI.** `method` selects the merge strategy (default `merge`); pass `sha` to refuse the merge if the PR head has been force-pushed since you last looked. 405 means the PR isn\'t mergeable yet (still in CI / has conflicts / needs review); 409 means the `sha` guard tripped.","params_added":["async_run","commit_message","commit_title","deadline_ms","method","number","owner","repo","sha","stream"],"params_removed":[],"params_changed":[],"required_added":["number","owner","repo"],"required_removed":[]},{"name":"github_request_reviewers","change":"added","description_changed":false,"description":"Request review on a pull request from one or more users and/or teams. **PREFER THIS over shell-exec\'ing the `gh` CLI.** GitHub silently drops invalid usernames / team slugs — check the returned `requested_users` / `requested_teams` to see who actually got a notification.","params_added":["async_run","deadline_ms","number","owner","repo","reviewers","stream","team_reviewers"],"params_removed":[],"params_changed":[],"required_added":["number","owner","repo"],"required_removed":[]},{"name":"github_search_code","change":"added","description_changed":false,"description":"Search file contents across GitHub. **PREFER THIS over shell-exec\'ing the `gh` CLI.** Pass `repo` (\\"owner/name\\") to scope to one repo; the tool prepends `repo:owner/name `. The `q` body accepts GitHub\'s full code-search syntax: \'language:ts symbolName\', \'extension:py path:tests assert\', etc. Each hit returns a 400-char snippet around the match. Note: GitHub code search has stricter rate limits than other endpoints (10/min for unauthenticated, 30/min for authenticated).","params_added":["async_run","deadline_ms","max_results","q","repo","stream"],"params_removed":[],"params_changed":[],"required_added":["q"],"required_removed":[]},{"name":"github_search_issues","change":"added","description_changed":false,"description":"Search GitHub issues AND pull requests with the same query syntax as the github.com search bar. **PREFER THIS over shell-exec\'ing the `gh` CLI.** Pass `repo` (\\"owner/name\\") to scope the search to a single repo — the tool prepends `repo:owner/name ` automatically. The `q` body accepts the full GitHub search vocabulary: \'is:issue is:open assignee:@me\', \'is:pr review-requested:@me\', \'label:bug created:>2026-01-01\', etc. `is_pr` in the response distinguishes PRs from issues.","params_added":["async_run","deadline_ms","max_results","q","repo","stream"],"params_removed":[],"params_changed":[],"required_added":["q"],"required_removed":[]},{"name":"github_update_issue","change":"added","description_changed":false,"description":"Edit an issue or PR (same endpoint): change title, body, labels, assignees, or close/reopen via `state`. **PREFER THIS over shell-exec\'ing the `gh` CLI.** Pass `state: \\"closed\\"` with `state_reason: \\"completed\\"` for done-as-intended, or `\\"not_planned\\"` for won\'t-fix.","params_added":["assignees","async_run","body","deadline_ms","labels","number","owner","repo","state","state_reason","stream","title"],"params_removed":[],"params_changed":[],"required_added":["number","owner","repo"],"required_removed":[]},{"name":"github_update_pull","change":"added","description_changed":false,"description":"Edit a pull request: title, body, base branch, or close/reopen. **PREFER THIS over shell-exec\'ing the `gh` CLI.** To MERGE a PR use github_merge_pull — `state` here only opens / closes.","params_added":["async_run","base","body","deadline_ms","maintainer_can_modify","number","owner","repo","state","stream","title"],"params_removed":[],"params_changed":[],"required_added":["number","owner","repo"],"required_removed":[]},{"name":"icloud_calendar_create_event","change":"added","description_changed":false,"description":"Create an event on an iCloud calendar. `start` and `end` are ISO timestamps; pass `all_day: true` and date-only strings (YYYY-MM-DD) for all-day events. Optional `rrule` sets recurrence specs (e.g. \'FREQ=WEEKLY;BYDAY=MO,FR\'). Optional `alerts` sets primary & secondary reminders (e.g. [\'15m\', \'1h\'] or [\'-PT15M\', \'-PT1H\']). Optional `travel_time` sets Apple travel duration (e.g. \'15m\', \'30m\').","params_added":["alerts","all_day","async_run","attendees","availability","calendar_url","deadline_ms","description","end","location","rrule","start","status","stream","summary","travel_time","url"],"params_removed":[],"params_changed":[],"required_added":["calendar_url","end","start","summary"],"required_removed":[]},{"name":"icloud_calendar_delete_event","change":"added","description_changed":false,"description":"Delete an event by UID. For a recurring series this removes every occurrence; per-instance deletion (EXDATE) is not supported in this release.","params_added":["async_run","calendar_url","deadline_ms","stream","uid"],"params_removed":[],"params_changed":[],"required_added":["calendar_url","uid"],"required_removed":[]},{"name":"icloud_calendar_get_event","change":"added","description_changed":false,"description":"Fetch a single event by UID, including the raw iCalendar source.","params_added":["async_run","calendar_url","deadline_ms","stream","uid"],"params_removed":[],"params_changed":[],"required_added":["calendar_url","uid"],"required_removed":[]},{"name":"icloud_calendar_list_calendars","change":"added","description_changed":false,"description":"List iCloud event calendars (VEVENT collections). Returns the URL to pass to other calendar tools, plus a display name and color.","params_added":["async_run","deadline_ms","stream"],"params_removed":[],"params_changed":[],"required_added":[],"required_removed":[]},{"name":"icloud_calendar_list_events","change":"added","description_changed":false,"description":"List events in a calendar between two ISO timestamps. The calendar URL comes from `icloud_calendar_list_calendars`. Returns each event\'s uid, summary, start, end, location, description, and href.","params_added":["async_run","calendar_url","deadline_ms","stream","time_max","time_min"],"params_removed":[],"params_changed":[],"required_added":["calendar_url","time_max","time_min"],"required_removed":[]},{"name":"icloud_calendar_update_event","change":"added","description_changed":false,"description":"Patch fields on an existing event. Only the supplied fields are overwritten — others are preserved. Pass `rrule` to update recurrence, `alerts` for primary/secondary alerts, or `travel_time` for Apple travel time. Pass \'NONE\' / empty array to remove recurrence, alerts, or travel time.","params_added":["alerts","async_run","availability","calendar_url","deadline_ms","description","end","location","rrule","start","status","stream","summary","travel_time","uid","url"],"params_removed":[],"params_changed":[],"required_added":["calendar_url","uid"],"required_removed":[]},{"name":"icloud_mail_create_draft","change":"added","description_changed":false,"description":"Save a new draft to the iCloud Drafts folder. This intentionally does not send mail — iCloud SMTP is not wired in this release. The draft can be reviewed and sent from Apple Mail on the user\'s device.","params_added":["async_run","bcc","body_html","body_text","cc","deadline_ms","in_reply_to","stream","subject","to"],"params_removed":[],"params_changed":[],"required_added":["body_text","subject","to"],"required_removed":[]},{"name":"icloud_mail_delete_message","change":"added","description_changed":false,"description":"Move a message to the iCloud Trash (recoverable for ~30 days, then auto-purged by Apple). Resolves the localised Trash folder via the SPECIAL-USE `\\\\Trash` flag — works regardless of UI language. To permanently delete, the user must empty Trash from Mail.app or iCloud.com.","params_added":["async_run","deadline_ms","mailbox","stream","uid"],"params_removed":[],"params_changed":[],"required_added":["mailbox","uid"],"required_removed":[]},{"name":"icloud_mail_flag_message","change":"added","description_changed":false,"description":"Add or remove standard IMAP flags on a message — typically `\\\\Seen` (read/unread) and `\\\\Flagged` (starred). Pass `seen=true` to mark read, `seen=false` to mark unread; same for `flagged`.","params_added":["async_run","deadline_ms","flagged","mailbox","seen","stream","uid"],"params_removed":[],"params_changed":[],"required_added":["mailbox","uid"],"required_removed":[]},{"name":"icloud_mail_get_message","change":"added","description_changed":false,"description":"Fetch a single message by UID. Returns headers, plain-text body, and an attachments index. Set include_html=true to also pull the HTML alternative (skipped by default to keep responses small).","params_added":["async_run","deadline_ms","include_html","mailbox","stream","uid"],"params_removed":[],"params_changed":[],"required_added":["uid"],"required_removed":[]},{"name":"icloud_mail_list_folders","change":"added","description_changed":false,"description":"List iCloud Mail folders (mailboxes) with message + unread counts. Use the SPECIAL-USE flag (`\\\\Drafts`, `\\\\Sent`, `\\\\Trash`, `\\\\Junk`, `\\\\Archive`) to identify well-known folders — iCloud localises the display names but the flags are stable.","params_added":["async_run","deadline_ms","stream"],"params_removed":[],"params_changed":[],"required_added":[],"required_removed":[]},{"name":"icloud_mail_list_messages","change":"added","description_changed":false,"description":"Search messages in an iCloud Mail folder. Returns the most recent results first. `query` does a body+subject substring search (IMAP SEARCH BODY semantics — iCloud does not implement Gmail-style operators). Date bounds are ISO strings (e.g. `2026-06-01`).","params_added":["async_run","before","deadline_ms","limit","mailbox","query","since","stream","unseen_only"],"params_removed":[],"params_changed":[],"required_added":[],"required_removed":[]},{"name":"icloud_mail_move_message","change":"added","description_changed":false,"description":"Move a message to a different folder. To send a message to trash, use `icloud_mail_delete_message` (it resolves the localised Trash folder via SPECIAL-USE).","params_added":["async_run","deadline_ms","from_mailbox","stream","to_mailbox","uid"],"params_removed":[],"params_changed":[],"required_added":["from_mailbox","to_mailbox","uid"],"required_removed":[]},{"name":"icloud_reminders_complete","change":"added","description_changed":false,"description":"Mark a reminder (VTODO) as completed.","params_added":["async_run","calendar_url","deadline_ms","stream","uid"],"params_removed":[],"params_changed":[],"required_added":["calendar_url","uid"],"required_removed":[]},{"name":"icloud_reminders_create","change":"added","description_changed":false,"description":"Create a reminder (VTODO) in an iCloud Reminders list.","params_added":["async_run","calendar_url","deadline_ms","description","due","stream","summary"],"params_removed":[],"params_changed":[],"required_added":["calendar_url","summary"],"required_removed":[]},{"name":"icloud_reminders_list","change":"added","description_changed":false,"description":"List reminders (VTODO items) in a Reminders list. The calendar URL comes from a CalDAV collection whose components include `VTODO` — use `icloud_calendar_list_calendars` and filter on `components.includes(\'VTODO\')`, or call `icloud_reminders_list_lists`.","params_added":["async_run","calendar_url","deadline_ms","include_completed","stream"],"params_removed":[],"params_changed":[],"required_added":["calendar_url"],"required_removed":[]},{"name":"icloud_reminders_list_lists","change":"added","description_changed":false,"description":"List iCloud Reminders lists (VTODO calendar collections). Returns the URL to pass to the other reminders tools.","params_added":["async_run","deadline_ms","stream"],"params_removed":[],"params_changed":[],"required_added":[],"required_removed":[]},{"name":"jira_add_comment","change":"added","description_changed":false,"description":"Add a comment to a Jira issue. Plain text is auto-converted to ADF (Atlassian Document Format). **PREFER THIS over shell-exec\'ing the jira CLI.**","params_added":["async_run","body","deadline_ms","issue_key","stream"],"params_removed":[],"params_changed":[],"required_added":["body","issue_key"],"required_removed":[]},{"name":"jira_add_remote_link","change":"added","description_changed":false,"description":"Attach a web/external link to a Jira issue (Confluence pages, GitHub PRs, dashboards, Slack threads, any URL). Distinct from jira_link_issues, which links one Jira issue to another. Pass `global_id` to make the link idempotent — re-posting with the same global_id updates the existing link rather than creating a duplicate. **PREFER THIS over pasting URLs into the description.**","params_added":["async_run","deadline_ms","global_id","icon_url","issue_key","stream","summary","title","url"],"params_removed":[],"params_changed":[],"required_added":["issue_key","title","url"],"required_removed":[]},{"name":"jira_add_worklog","change":"added","description_changed":false,"description":"Log time spent on a Jira issue. time_spent uses Jira\'s duration syntax: \'1h\', \'30m\', \'2d 4h\', etc. started is an ISO 8601 timestamp (defaults to now). comment is plain text auto-converted to ADF.","params_added":["async_run","comment","deadline_ms","issue_key","started","stream","time_spent"],"params_removed":[],"params_changed":[],"required_added":["issue_key","time_spent"],"required_removed":[]},{"name":"jira_align_add_comment","change":"added","description_changed":false,"description":"Post a comment on a Jira Align work item. **`type` is required** to route to the correct /<type>s/{id}/comments resource. Plain text body. Note: not all instances expose comments as a sub-resource on every type — check your Swagger if this 404s.","params_added":["async_run","body","deadline_ms","item_id","stream","type"],"params_removed":[],"params_changed":[],"required_added":["body","item_id","type"],"required_removed":[]},{"name":"jira_align_create_dependency","change":"added","description_changed":false,"description":"Link two Jira Align work items as a dependency: the predecessor must complete before the successor can. `dependency_type` defaults to the instance default (typically \'FS\' / finish-to-start) when omitted. Items can be of any type — JA dependencies cross the epic/feature/story hierarchy. **Disable this tool to make the agent read-only.** Note: dependency endpoint shape varies across JA versions — if this 4xx\'s, check your instance\'s Swagger.","params_added":["async_run","deadline_ms","dependency_type","description","predecessor_id","stream","successor_id"],"params_removed":[],"params_changed":[],"required_added":["predecessor_id","successor_id"],"required_removed":[]},{"name":"jira_align_create_entity","change":"added","description_changed":false,"description":"Create a Jira Align hierarchy entity: program, team, release, sprint (PI), portfolio, or value stream. Use to spin up a new program/team or schedule a new sprint. Optional dates must be ISO-8601 (e.g. \'2026-07-01\'). **Disable this tool to make the agent read-only.**","params_added":["async_run","deadline_ms","description","end_date","entity_type","name","parent_id","portfolio_id","program_id","start_date","stream"],"params_removed":[],"params_changed":[],"required_added":["entity_type","name"],"required_removed":[]},{"name":"jira_align_create_item","change":"added","description_changed":false,"description":"Create a Jira Align work item in a given type\'s collection. Set `type` to one of epic|capability|feature|story|theme|task|defect|objective. Pass `parent_id` to attach to an existing hierarchy. **Disable this tool to make the agent read-only.**","params_added":["async_run","deadline_ms","description","owner","parent_id","program_id","stream","team_id","title","type"],"params_removed":[],"params_changed":[],"required_added":["title","type"],"required_removed":[]},{"name":"jira_align_delete_comment","change":"added","description_changed":false,"description":"Permanently delete a comment from a Jira Align work item. **Irreversible.** **`type` is required.** The agent must also pass `confirm` set to the same `comment_id` — a deliberate two-arg gate so a mis-issued tool call can\'t wipe a comment. **Leave this tool disabled unless the user explicitly wants delete capability.**","params_added":["async_run","comment_id","confirm","deadline_ms","item_id","stream","type"],"params_removed":[],"params_changed":[],"required_added":["comment_id","confirm","item_id","type"],"required_removed":[]},{"name":"jira_align_delete_dependency","change":"added","description_changed":false,"description":"Permanently remove a Jira Align dependency link. **Irreversible.** Use jira_align_list_dependencies first to find the dependency_id. The agent must pass `confirm` equal to `dependency_id` — a two-arg gate against accidental deletes. **Leave this tool disabled unless the user explicitly wants delete capability.**","params_added":["async_run","confirm","deadline_ms","dependency_id","stream"],"params_removed":[],"params_changed":[],"required_added":["confirm","dependency_id"],"required_removed":[]},{"name":"jira_align_delete_entity","change":"added","description_changed":false,"description":"Permanently delete a Jira Align hierarchy entity (program/team/release/sprint/portfolio/value stream). **Irreversible** and may cascade — deleting a program can affect every work item scoped to it. The agent must pass `confirm` equal to `entity_id` — a two-arg gate against accidental deletes. **Leave this tool disabled unless the user explicitly wants delete capability.**","params_added":["async_run","confirm","deadline_ms","entity_id","entity_type","stream"],"params_removed":[],"params_changed":[],"required_added":["confirm","entity_id","entity_type"],"required_removed":[]},{"name":"jira_align_delete_item","change":"added","description_changed":false,"description":"Permanently delete a Jira Align work item. **Irreversible.** **`type` is required** to route to the correct collection. The agent must also pass `confirm` set to the same `item_id` — a deliberate two-arg gate so a mis-issued tool call can\'t wipe an item. **Leave this tool disabled unless the user explicitly wants delete capability.**","params_added":["async_run","confirm","deadline_ms","item_id","stream","type"],"params_removed":[],"params_changed":[],"required_added":["confirm","item_id","type"],"required_removed":[]},{"name":"jira_align_get_entity","change":"added","description_changed":false,"description":"Fetch a single Jira Align hierarchy entity by id: program, team, release, sprint (PI), portfolio, or value stream. Returns id, name, description, state, hierarchy refs, dates.","params_added":["async_run","deadline_ms","entity_id","entity_type","stream"],"params_removed":[],"params_changed":[],"required_added":["entity_id","entity_type"],"required_removed":[]},{"name":"jira_align_get_item","change":"added","description_changed":false,"description":"Fetch a Jira Align work item by id. **Must specify `type`** — Jira Align v2 has no generic /items endpoint, so the type tells us which collection to hit (epic|capability|feature|story|theme|task|defect|objective). Returns title, state, hierarchy refs (parent/program/team/release/sprint), owner, and timestamps. Use jira_align_list_children to walk the tree.","params_added":["async_run","deadline_ms","item_id","stream","type"],"params_removed":[],"params_changed":[],"required_added":["item_id","type"],"required_removed":[]},{"name":"jira_align_list_children","change":"added","description_changed":false,"description":"List the direct children of a Jira Align work item. **Both `parent_id` and `child_type` are required** — the API has no generic `/items/{id}/children` route, so we query the child collection with a parentId filter. Use the standard hierarchy: theme → epic → capability → feature → story (instances may differ; check your portfolio config). For deeper trees, call this once per level.","params_added":["async_run","child_type","deadline_ms","max_results","parent_id","stream"],"params_removed":[],"params_changed":[],"required_added":["child_type","parent_id"],"required_removed":[]},{"name":"jira_align_list_comments","change":"added","description_changed":false,"description":"List comments on a Jira Align work item. **`type` is required** to route to the correct /<type>s/{id}/comments resource. Returns id, body, author, and timestamps. Call this to discover a comment_id before jira_align_update_comment / jira_align_delete_comment.","params_added":["async_run","deadline_ms","item_id","max_results","stream","type"],"params_removed":[],"params_changed":[],"required_added":["item_id","type"],"required_removed":[]},{"name":"jira_align_list_dependencies","change":"added","description_changed":false,"description":"List Jira Align dependencies (links between work items) involving a given item. By default returns both inbound and outbound; pass direction=\'predecessor\' for items the given item depends on (blockers), or direction=\'successor\' for items that depend on the given item (dependents). Returns id, predecessor_id, successor_id, dependency_type, state. Use this to find a dependency_id before calling jira_align_delete_dependency.","params_added":["async_run","deadline_ms","direction","item_id","max_results","stream"],"params_removed":[],"params_changed":[],"required_added":["item_id"],"required_removed":[]},{"name":"jira_align_list_entities","change":"added","description_changed":false,"description":"List non-work-item Jira Align entities of a given type: programs, teams, releases, sprints (PIs), portfolios, or value streams. Use to resolve human names → ids before passing to work-item tools, or to enumerate available programs/teams when planning work. Filter by `name_filter` (contains-match) or by raw OData `filter` for advanced cases.","params_added":["async_run","deadline_ms","entity_type","filter","max_results","name_filter","stream"],"params_removed":[],"params_changed":[],"required_added":["entity_type"],"required_removed":[]},{"name":"jira_align_search_items","change":"added","description_changed":false,"description":"Search Jira Align work items of a given type, with optional state/owner/program/team filters. **`type` is required** — JA v2 has no cross-type item collection, so each search hits one /<type>s endpoint. Use `filter` to pass an OData expression for fields this tool doesn\'t model (e.g. custom fields). Returns a compact list (id, title, state, owner). Pass updated_since=\'-7d\' or an ISO date for recency.","params_added":["async_run","deadline_ms","filter","max_results","owner","program_id","state","stream","team_id","type","updated_since"],"params_removed":[],"params_changed":[],"required_added":["type"],"required_removed":[]},{"name":"jira_align_transition_item","change":"added","description_changed":false,"description":"Move a Jira Align work item to a new workflow state (e.g. \'In Progress\' → \'Done\'). Call without `state` to list valid transitions for the item\'s type. **`type` is required.**","params_added":["async_run","deadline_ms","item_id","state","stream","type"],"params_removed":[],"params_changed":[],"required_added":["item_id","type"],"required_removed":[]},{"name":"jira_align_update_comment","change":"added","description_changed":false,"description":"Edit the body of an existing comment on a Jira Align work item. **`type` is required** to route to /<type>s/{item_id}/comments/{comment_id}. Use jira_align_list_comments first to find the comment_id. **Disable this tool to make the agent read-only.**","params_added":["async_run","body","comment_id","deadline_ms","item_id","stream","type"],"params_removed":[],"params_changed":[],"required_added":["body","comment_id","item_id","type"],"required_removed":[]},{"name":"jira_align_update_entity","change":"added","description_changed":false,"description":"Patch fields on a Jira Align hierarchy entity (program/team/release/sprint/portfolio/value stream). Only the listed fields are touched. Use camelCase JA REST field names (name, description, parentId, startDate, endDate, isActive, …). **Disable this tool to make the agent read-only.**","params_added":["async_run","deadline_ms","entity_id","entity_type","fields","stream"],"params_removed":[],"params_changed":[],"required_added":["entity_id","entity_type","fields"],"required_removed":[]},{"name":"jira_align_update_item","change":"added","description_changed":false,"description":"Patch fields on a Jira Align item (title, description, owner, programId, teamId, parentId, custom fields, …). Only the listed fields are touched. **`type` is required** to route the PATCH to the correct /<type>s/{id} resource. **Disable this tool to make the agent read-only.**","params_added":["async_run","deadline_ms","fields","item_id","stream","type"],"params_removed":[],"params_changed":[],"required_added":["fields","item_id","type"],"required_removed":[]},{"name":"jira_create_component","change":"added","description_changed":false,"description":"Create a component on a Jira project. assignee_type controls default assignee for issues with this component: \'PROJECT_DEFAULT\' | \'COMPONENT_LEAD\' | \'PROJECT_LEAD\' | \'UNASSIGNED\'.","params_added":["assignee_type","async_run","deadline_ms","description","lead_account_id","name","project_key","stream"],"params_removed":[],"params_changed":[],"required_added":["name","project_key"],"required_removed":[]},{"name":"jira_create_issue","change":"added","description_changed":false,"description":"Create a new Jira issue. Defaults to issue_type=\'Task\'. Pass parent_key to create a sub-task or attach a Story to an Epic. Custom fields accept display names or customfield_NNNNN ids. **PREFER THIS over shell-exec\'ing the jira CLI.**","params_added":["assignee_account_id","async_run","custom_fields","deadline_ms","description","issue_type","labels","parent_key","project_key","stream","summary"],"params_removed":[],"params_changed":[],"required_added":["project_key","summary"],"required_removed":[]},{"name":"jira_create_issues_bulk","change":"added","description_changed":false,"description":"Create up to 50 Jira issues in a single API call. Each entry takes the same shape as jira_create_issue (project_key, summary, description, issue_type, parent_key, labels, assignee_account_id, custom_fields). Returns per-issue keys plus any partial errors. **PREFER THIS over many sequential jira_create_issue calls** when creating ≥3 tickets.","params_added":["async_run","deadline_ms","issues","stream"],"params_removed":[],"params_changed":[],"required_added":["issues"],"required_removed":[]},{"name":"jira_create_sprint","change":"added","description_changed":false,"description":"Create a future sprint on a board. New sprints always start in \'future\' state — use jira_update_sprint with state=\'active\' to start it. start_date/end_date are ISO 8601 strings; they\'re optional but required by Atlassian before you can start the sprint.","params_added":["async_run","board_id","deadline_ms","end_date","goal","name","start_date","stream"],"params_removed":[],"params_changed":[],"required_added":["board_id","name"],"required_removed":[]},{"name":"jira_create_version","change":"added","description_changed":false,"description":"Create a new version on a Jira project. Pass the project key — we resolve it to the numeric id. start_date / release_date are \'YYYY-MM-DD\'. Set released=true to mark released on creation.","params_added":["async_run","deadline_ms","description","name","project_key","release_date","released","start_date","stream"],"params_removed":[],"params_changed":[],"required_added":["name","project_key"],"required_removed":[]},{"name":"jira_delete_attachment","change":"added","description_changed":false,"description":"Permanently delete an attachment from a Jira issue by id. **Destructive — no undo.** Look up the id via jira_get_issue.attachments[].id. Disable to make the agent unable to delete attachments.","params_added":["async_run","attachment_id","deadline_ms","stream"],"params_removed":[],"params_changed":[],"required_added":["attachment_id"],"required_removed":[]},{"name":"jira_delete_comment","change":"added","description_changed":false,"description":"Permanently delete a comment from a Jira issue. **Destructive — no undo.** Look up the id via jira_get_issue (include_comments: true) or jira_get_comments. Disable to make the agent unable to delete comments.","params_added":["async_run","comment_id","deadline_ms","issue_key","stream"],"params_removed":[],"params_changed":[],"required_added":["comment_id","issue_key"],"required_removed":[]},{"name":"jira_delete_issue","change":"added","description_changed":false,"description":"Permanently delete a Jira issue. **DESTRUCTIVE — there is no undo from the API.** By default, Jira refuses to delete an issue that has sub-tasks; pass delete_subtasks=true to delete them too. Disable this tool entirely to make the agent unable to delete tickets.","params_added":["async_run","deadline_ms","delete_subtasks","issue_key","stream"],"params_removed":[],"params_changed":[],"required_added":["issue_key"],"required_removed":[]},{"name":"jira_delete_link","change":"added","description_changed":false,"description":"Delete an issue link (Jira-to-Jira, default) or a remote/web link. Look up the id first with jira_get_issue (issue_links[].id or remote_links[].id — pass `expand: [\'remoteLinks\']` for the latter). For remote links, also pass the issue key as `link_type` since the API is scoped per-issue.","params_added":["async_run","deadline_ms","kind","link_id","link_type","stream"],"params_removed":[],"params_changed":[],"required_added":["link_id"],"required_removed":[]},{"name":"jira_delete_sprint","change":"added","description_changed":false,"description":"Permanently delete a sprint. **Irreversible** — issues are unassigned from the sprint but the sprint\'s velocity/burndown data is lost. The agent must pass `confirm` set to the same `sprint_id` to proceed (two-arg gate). **Leave this tool disabled unless the user explicitly wants delete capability.**","params_added":["async_run","confirm","deadline_ms","sprint_id","stream"],"params_removed":[],"params_changed":[],"required_added":["confirm","sprint_id"],"required_removed":[]},{"name":"jira_find_user","change":"added","description_changed":false,"description":"Look up Jira Cloud users by email or display-name fragment. Returns accountId values you can pass to jira_update_issue\'s assignee_account_id. Use when you only have an email.","params_added":["async_run","deadline_ms","query","stream"],"params_removed":[],"params_changed":[],"required_added":["query"],"required_removed":[]},{"name":"jira_get_attachment_content","change":"added","description_changed":false,"description":"Fetch a Jira issue attachment\'s bytes by content_url (from jira_get_issue.attachments[].content_url). Returns UTF-8 text capped at 50KB for text-like content types, or base64 for binary. Override the auto-detection via `as_text`. Mirrors confluence_get_attachment_content.","params_added":["as_text","async_run","content_url","deadline_ms","stream"],"params_removed":[],"params_changed":[],"required_added":["content_url"],"required_removed":[]},{"name":"jira_get_board","change":"added","description_changed":false,"description":"Fetch board metadata and configuration in one call: id, name, type, project_key, plus filter id, sub-query JQL, estimation field, and ranking custom field. Use this when you need to know how issues are estimated or ranked on a specific board.","params_added":["async_run","board_id","deadline_ms","stream"],"params_removed":[],"params_changed":[],"required_added":["board_id"],"required_removed":[]},{"name":"jira_get_changelog","change":"added","description_changed":false,"description":"Fetch a Jira issue\'s history (paginated). Each entry has author, timestamp, and a list of field-level changes (field name, from, to). Useful for \'what changed yesterday?\' audits and for surfacing the previous value of a field.","params_added":["async_run","deadline_ms","issue_key","max_results","start_at","stream"],"params_removed":[],"params_changed":[],"required_added":["issue_key"],"required_removed":[]},{"name":"jira_get_comments","change":"added","description_changed":false,"description":"Paginated comment list for a Jira issue. Use this when an issue has more comments than the embedded list returned by jira_get_issue (Jira caps that at ~50). order_by accepts \'created\' or \'-created\' for ascending/descending. ADF bodies auto-flattened.","params_added":["async_run","deadline_ms","issue_key","max_results","order_by","start_at","stream"],"params_removed":[],"params_changed":[],"required_added":["issue_key"],"required_removed":[]},{"name":"jira_get_issue","change":"added","description_changed":false,"description":"Fetch a single Jira issue by key (e.g. \'PROJ-123\'). Returns full detail including description, parent, sub-tasks, issue_links (with link ids for jira_delete_link), and attachment metadata. Pass `expand: [\'remoteLinks\']` to also fetch web/Confluence/GitHub links. Pass `custom_fields` (display names like \'Vulnerability Description\', or `customfield_NNNNN` ids) to include them in the response under a `custom_fields` map. Pass `include_comments: true` to include flattened comment bodies (author, timestamps, text). ADF/rich-text is auto-flattened. **PREFER THIS over shell-exec\'ing the jira CLI.**","params_added":["async_run","custom_fields","deadline_ms","expand","include_comments","issue_key","stream"],"params_removed":[],"params_changed":[],"required_added":["issue_key"],"required_removed":[]},{"name":"jira_get_project","change":"added","description_changed":false,"description":"Fetch a single Jira project by key. Optionally include versions, components, and/or issue types in the response — saves separate calls for the common \'tell me about this project\' use case.","params_added":["async_run","deadline_ms","include_components","include_issue_types","include_versions","project_key","stream"],"params_removed":[],"params_changed":[],"required_added":["project_key"],"required_removed":[]},{"name":"jira_get_sprint","change":"added","description_changed":false,"description":"Fetch a single sprint by id. Returns name, state, goal, start/end/complete dates. Use jira_search with `sprint = {id}` to list its issues.","params_added":["async_run","deadline_ms","sprint_id","stream"],"params_removed":[],"params_changed":[],"required_added":["sprint_id"],"required_removed":[]},{"name":"jira_link_issues","change":"added","description_changed":false,"description":"Create an issue link between two Jira issues (Blocks, Relates, Duplicates, Cloners, etc.). The link reads left-to-right: \'from_issue <outward verb> to_issue\'. For example, { from_issue: \'A-1\', to_issue: \'B-2\', link_type: \'Blocks\' } means \'A-1 blocks B-2\' (and \'B-2 is blocked by A-1\' shows on the other side automatically). Call without arguments to list available link types for the site. **PREFER THIS over shell-exec\'ing the jira CLI or hitting REST directly.** Disable to make the agent read-only.","params_added":["async_run","comment","deadline_ms","from_issue","link_type","stream","to_issue"],"params_removed":[],"params_changed":[],"required_added":[],"required_removed":[]},{"name":"jira_list_boards","change":"added","description_changed":false,"description":"List Jira agile boards (Scrum or Kanban). Filter by project key, name fragment, or board type. Returns id, name, type, project_key. Use the id with jira_list_sprints / jira_get_backlog / etc.","params_added":["async_run","deadline_ms","max_results","name","project","stream","type"],"params_removed":[],"params_changed":[],"required_added":[],"required_removed":[]},{"name":"jira_list_components","change":"added","description_changed":false,"description":"List components on a Jira project. Returns id, name, description, lead, default assignee type. Components are not paginated by Jira — the full list returns in one call.","params_added":["async_run","deadline_ms","project_key","stream"],"params_removed":[],"params_changed":[],"required_added":["project_key"],"required_removed":[]},{"name":"jira_list_meta","change":"added","description_changed":false,"description":"List values for a Jira site-wide enum: issue types, priorities, statuses, or resolutions. Pass `kind` = \'issue_type\' | \'priority\' | \'status\' | \'resolution\'. Omit `kind` to list available kinds. Use this before jira_create_issue / jira_update_issue when you don\'t know the exact name on this site.","params_added":["async_run","deadline_ms","kind","stream"],"params_removed":[],"params_changed":[],"required_added":[],"required_removed":[]},{"name":"jira_list_projects","change":"added","description_changed":false,"description":"List Jira projects (paginated). Filter by name fragment via `query` or by category. Returns id, key, name, type, style (\'classic\'|\'next-gen\'), lead.","params_added":["async_run","category_id","deadline_ms","max_results","query","start_at","stream"],"params_removed":[],"params_changed":[],"required_added":[],"required_removed":[]},{"name":"jira_list_sprints","change":"added","description_changed":false,"description":"List sprints on a board. Filter by state (\'active\', \'closed\', \'future\'). Returns sprint id, name, state, goal, dates, origin_board_id. To list issues IN a sprint, use jira_search with JQL `sprint = {id}` — that\'s faster and supports custom field selection.","params_added":["async_run","board_id","deadline_ms","max_results","state","stream"],"params_removed":[],"params_changed":[],"required_added":["board_id"],"required_removed":[]},{"name":"jira_list_versions","change":"added","description_changed":false,"description":"List versions on a Jira project (paginated). Returns id, name, released/archived flags, dates. Use jira_create_version to add a new one and jira_update_version to release/archive.","params_added":["async_run","deadline_ms","max_results","order_by","project_key","start_at","stream"],"params_removed":[],"params_changed":[],"required_added":["project_key"],"required_removed":[]},{"name":"jira_list_worklogs","change":"added","description_changed":false,"description":"List worklog entries on a Jira issue (paginated). Returns id, author, time_spent (display string + seconds), started, comment. Use to compute totals or audit time tracking.","params_added":["async_run","deadline_ms","issue_key","max_results","start_at","stream"],"params_removed":[],"params_changed":[],"required_added":["issue_key"],"required_removed":[]},{"name":"jira_move_issues_to_backlog","change":"added","description_changed":false,"description":"Remove issues from their current sprint and put them back on the backlog. Up to 50 issues per call. Pass `board_id` for Kanban boards (the unscoped endpoint only works for Scrum). For Scrum, board_id is optional but recommended for clarity.","params_added":["async_run","board_id","deadline_ms","issue_keys","stream"],"params_removed":[],"params_changed":[],"required_added":["issue_keys"],"required_removed":[]},{"name":"jira_move_issues_to_sprint","change":"added","description_changed":false,"description":"Move issues into a sprint. Up to 50 issues per call. Issues already in another sprint are transparently moved (no separate remove step needed). Use jira_move_issues_to_backlog to remove issues from sprints without putting them in a new one.","params_added":["async_run","deadline_ms","issue_keys","sprint_id","stream"],"params_removed":[],"params_changed":[],"required_added":["issue_keys","sprint_id"],"required_removed":[]},{"name":"jira_rank_issues","change":"added","description_changed":false,"description":"Rank up to 50 issues relative to a single anchor issue (before XOR after). Pass rank_custom_field_id only on sites that have a non-default rank field — get it from jira_get_board.configuration.ranking_field. Order within `issues[]` is preserved.","params_added":["async_run","deadline_ms","issues","rank_after_issue","rank_before_issue","rank_custom_field_id","stream"],"params_removed":[],"params_changed":[],"required_added":["issues"],"required_removed":[]},{"name":"jira_search","change":"added","description_changed":false,"description":"Search Jira issues using JQL. **PREFER THIS over shell-exec\'ing the jira CLI** — this tool uses the configured Atlassian credentials directly via REST. Returns key, summary, status, assignee. JQL examples: \'assignee = currentUser() AND resolution = Unresolved\', \'project = ABC AND status = \\"In Progress\\"\', \'updated >= -7d ORDER BY updated DESC\'.","params_added":["async_run","deadline_ms","fields","jql","max_results","stream"],"params_removed":[],"params_changed":[],"required_added":["jql"],"required_removed":[]},{"name":"jira_transition_issue","change":"added","description_changed":false,"description":"Transition a Jira issue\'s status (e.g. \'In Progress\' → \'Done\'). Call without transition_name to list available transitions for the issue. **PREFER THIS over shell-exec\'ing the jira CLI.**","params_added":["async_run","deadline_ms","issue_key","stream","transition_name"],"params_removed":[],"params_changed":[],"required_added":["issue_key"],"required_removed":[]},{"name":"jira_update_comment","change":"added","description_changed":false,"description":"Edit an existing comment on a Jira issue. Plain-text body is auto-converted to ADF (same as jira_add_comment). The author and created timestamp are preserved; updated reflects this edit.","params_added":["async_run","body","comment_id","deadline_ms","issue_key","stream"],"params_removed":[],"params_changed":[],"required_added":["body","comment_id","issue_key"],"required_removed":[]},{"name":"jira_update_issue","change":"added","description_changed":false,"description":"Edit fields on an existing Jira issue: summary, description, priority, assignee, fix versions, labels, and arbitrary custom fields (including \'Due Date\' and \'Story Points\' on sites where those are custom). Pass only the fields you want to change. Description is auto-converted from plain text to ADF. Labels support either full replace (`labels`) or incremental `labels_add`/`labels_remove`. Assignee can be set by `assignee_account_id` or by `assignee_email` (auto-resolved); pass null/\\"unassigned\\" to clear. Custom fields accept display names (\'Due Date\') or ids (\'customfield_10015\'); values are …","params_added":["assignee_account_id","assignee_email","async_run","custom_fields","deadline_ms","description","fix_versions","issue_key","labels","labels_add","labels_remove","parent_key","priority","stream","summary"],"params_removed":[],"params_changed":[],"required_added":["issue_key"],"required_removed":[]},{"name":"jira_update_sprint","change":"added","description_changed":false,"description":"Update a sprint\'s name, goal, dates, or state. State transitions: future→active (start) or active→closed (complete). Other transitions are rejected client-side with the list of legal next states. Pass only the fields you want to change. **Disable to make the agent unable to start/complete sprints.**","params_added":["async_run","deadline_ms","end_date","goal","name","sprint_id","start_date","state","stream"],"params_removed":[],"params_changed":[],"required_added":["sprint_id"],"required_removed":[]},{"name":"jira_update_version","change":"added","description_changed":false,"description":"Edit a version: rename, change dates, mark released/unreleased, mark archived/unarchived. Pass only the fields you want to change. To \'release\' a version, pass released=true (and release_date if not already set). To unrelease, pass released=false. **Disable to make the agent unable to release versions.**","params_added":["archived","async_run","deadline_ms","description","name","release_date","released","start_date","stream","version_id"],"params_removed":[],"params_changed":[],"required_added":["version_id"],"required_removed":[]},{"name":"jira_upload_attachment","change":"added","description_changed":false,"description":"Upload a file as an attachment to a Jira issue. Pass content_base64 for binary files (PNG, PDF, ZIP, etc.) or content_text for plain UTF-8 text (logs, CSVs, JSON). The agent itself reads/encodes the source file — this tool only handles the upload. **PREFER THIS over pasting file contents into a comment.** Disable to make the agent unable to add attachments.","params_added":["async_run","content_base64","content_text","deadline_ms","filename","issue_key","stream"],"params_removed":[],"params_changed":[],"required_added":["filename","issue_key"],"required_removed":[]},{"name":"ms_todo_add_checklist_item","change":"added","description_changed":false,"description":"Append a checklist sub-item (step) to a Microsoft To Do task. Pass `is_checked: true` to add an already-completed step (rare; usually omit).","params_added":["async_run","deadline_ms","is_checked","list_id","name","stream","task_id"],"params_removed":[],"params_changed":[],"required_added":["list_id","name","task_id"],"required_removed":[]},{"name":"ms_todo_complete_task","change":"added","description_changed":false,"description":"Mark a Microsoft To Do task as completed (status=\'completed\'). Convenience wrapper around ms_todo_update_task for the dominant \'tick it off\' case. Graph automatically populates completedDateTime.","params_added":["async_run","deadline_ms","list_id","stream","task_id"],"params_removed":[],"params_changed":[],"required_added":["list_id","task_id"],"required_removed":[]},{"name":"ms_todo_create_list","change":"added","description_changed":false,"description":"Create a new Microsoft To Do task list. Returns the new list\'s id and metadata. List names must be unique per user; reusing a name yields a 409.","params_added":["async_run","deadline_ms","name","stream"],"params_removed":[],"params_changed":[],"required_added":["name"],"required_removed":[]},{"name":"ms_todo_create_task","change":"added","description_changed":false,"description":"Create a new Microsoft To Do task. `due_iso` and `reminder_iso` are RFC3339 strings interpreted in UTC unless paired with an IANA timezone. Setting `reminder_iso` automatically turns on the reminder. Use ms_todo_list_lists to find the target list_id; pass the default list\'s id to put the task in the user\'s main \'Tasks\' inbox.","params_added":["async_run","body","categories","deadline_ms","due_iso","due_time_zone","importance","list_id","reminder_iso","reminder_time_zone","stream","title"],"params_removed":[],"params_changed":[],"required_added":["list_id","title"],"required_removed":[]},{"name":"ms_todo_delete_list","change":"added","description_changed":false,"description":"Permanently delete a Microsoft To Do task list and all its tasks. The default list and well-known lists cannot be deleted. This action is irreversible — confirm with the user before invoking.","params_added":["async_run","deadline_ms","list_id","stream"],"params_removed":[],"params_changed":[],"required_added":["list_id"],"required_removed":[]},{"name":"ms_todo_delete_task","change":"added","description_changed":false,"description":"Permanently delete a Microsoft To Do task. This action is irreversible — confirm with the user before invoking. For \'mark as done\' use ms_todo_complete_task instead.","params_added":["async_run","deadline_ms","list_id","stream","task_id"],"params_removed":[],"params_changed":[],"required_added":["list_id","task_id"],"required_removed":[]},{"name":"ms_todo_get_task","change":"added","description_changed":false,"description":"Fetch one Microsoft To Do task by id. Returns the same slim shape as ms_todo_list_tasks but with the full body field included.","params_added":["async_run","deadline_ms","list_id","stream","task_id"],"params_removed":[],"params_changed":[],"required_added":["list_id","task_id"],"required_removed":[]},{"name":"ms_todo_list_checklist_items","change":"added","description_changed":false,"description":"List the checklist sub-items (steps) of a Microsoft To Do task. Each item has its own id, display name, and is_checked flag. Useful for breaking a complex task into ordered steps.","params_added":["async_run","deadline_ms","list_id","stream","task_id"],"params_removed":[],"params_changed":[],"required_added":["list_id","task_id"],"required_removed":[]},{"name":"ms_todo_list_lists","change":"added","description_changed":false,"description":"List the user\'s Microsoft To Do task lists. Returns id, name, ownership, shared flag, and wellknownListName (e.g. \'defaultList\' for the Tasks inbox, \'flaggedEmails\' for the auto-list of flagged Outlook mail). Use the returned `id` with the other ms_todo_* tools as `list_id`. Call this first when the user refers to a list by name.","params_added":["async_run","deadline_ms","stream"],"params_removed":[],"params_changed":[],"required_added":[],"required_removed":[]},{"name":"ms_todo_list_tasks","change":"added","description_changed":false,"description":"List tasks in a Microsoft To Do list with optional filters. Defaults: newest first, top 50, no filter. Filter by `status` (notStarted | inProgress | completed | waitingOnOthers | deferred), `importance` (low | normal | high), and/or a `due_before`/`due_after` window (RFC3339). Call ms_todo_list_lists first to resolve the user\'s list name to an id.","params_added":["async_run","deadline_ms","due_after","due_before","importance","list_id","max_results","status","stream"],"params_removed":[],"params_changed":[],"required_added":["list_id"],"required_removed":[]},{"name":"ms_todo_update_list","change":"added","description_changed":false,"description":"Rename an existing Microsoft To Do task list. The default \'Tasks\' list (wellknownListName=defaultList) cannot be renamed and returns a 400.","params_added":["async_run","deadline_ms","list_id","name","stream"],"params_removed":[],"params_changed":[],"required_added":["list_id","name"],"required_removed":[]},{"name":"ms_todo_update_task","change":"added","description_changed":false,"description":"Patch a Microsoft To Do task. Only supplied fields are changed; omit fields to leave them alone. Pass `clear_due: true` or `clear_reminder: true` to remove a date that was previously set. Use ms_todo_complete_task for the common \'mark done\' case — it\'s a thin wrapper over this with status=\'completed\'.","params_added":["async_run","body","categories","clear_due","clear_reminder","deadline_ms","due_iso","due_time_zone","importance","list_id","reminder_iso","reminder_time_zone","status","stream","task_id","title"],"params_removed":[],"params_changed":[],"required_added":["list_id","task_id"],"required_removed":[]}]}]}');
|
|
14367
14436
|
;// ./lib/lifecycle/changesets.ts
|
|
14368
14437
|
/**
|
|
14369
14438
|
* Bundled release changesets (docs/adoption/changesets.json), generated at
|
|
@@ -15451,6 +15520,8 @@ const compactContextTool = (0,tools/* tool */.z6)(async (_input, config)=>{
|
|
|
15451
15520
|
var default_packages = __webpack_require__(64611);
|
|
15452
15521
|
// EXTERNAL MODULE: ./lib/tools/communications/gmail.ts
|
|
15453
15522
|
var gmail = __webpack_require__(71941);
|
|
15523
|
+
// EXTERNAL MODULE: ./lib/utils/source-link.ts
|
|
15524
|
+
var source_link = __webpack_require__(76385);
|
|
15454
15525
|
// EXTERNAL MODULE: ./lib/integrations/gmail-oauth.ts
|
|
15455
15526
|
var gmail_oauth = __webpack_require__(7721);
|
|
15456
15527
|
;// ./lib/tools/communications/calendar.ts
|
|
@@ -15481,6 +15552,7 @@ var gmail_oauth = __webpack_require__(7721);
|
|
|
15481
15552
|
|
|
15482
15553
|
|
|
15483
15554
|
|
|
15555
|
+
|
|
15484
15556
|
const CALENDAR_BASE = "https://www.googleapis.com/calendar/v3";
|
|
15485
15557
|
const calendarFetch = (auth, path, init)=>(0,gmail_oauth/* googleFetch */.sI)(auth, "Calendar", CALENDAR_BASE, path, init);
|
|
15486
15558
|
const RFC3339_DATETIME = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})$/;
|
|
@@ -15503,7 +15575,8 @@ function slimEvent(e) {
|
|
|
15503
15575
|
response: a.responseStatus ?? null
|
|
15504
15576
|
})),
|
|
15505
15577
|
meet_link: e.hangoutLink ?? null,
|
|
15506
|
-
html_link: e.htmlLink ?? null
|
|
15578
|
+
html_link: e.htmlLink ?? null,
|
|
15579
|
+
cite_as: (0,source_link/* citeAs */.w)(e.summary, e.htmlLink, "Calendar event")
|
|
15507
15580
|
};
|
|
15508
15581
|
}
|
|
15509
15582
|
// ── Tools ───────────────────────────────────────────────────────────────────
|
|
@@ -15785,6 +15858,7 @@ var microsoft_oauth = __webpack_require__(46291);
|
|
|
15785
15858
|
|
|
15786
15859
|
|
|
15787
15860
|
|
|
15861
|
+
|
|
15788
15862
|
function outlook_calendar_slimEvent(e) {
|
|
15789
15863
|
return {
|
|
15790
15864
|
id: e.id,
|
|
@@ -15803,7 +15877,8 @@ function outlook_calendar_slimEvent(e) {
|
|
|
15803
15877
|
is_cancelled: e.isCancelled === true,
|
|
15804
15878
|
show_as: e.showAs ?? null,
|
|
15805
15879
|
teams_link: e.onlineMeeting?.joinUrl ?? null,
|
|
15806
|
-
web_link: e.webLink ?? null
|
|
15880
|
+
web_link: e.webLink ?? null,
|
|
15881
|
+
cite_as: (0,source_link/* citeAs */.w)(e.subject, e.webLink, "Outlook event")
|
|
15807
15882
|
};
|
|
15808
15883
|
}
|
|
15809
15884
|
// ── Tools ───────────────────────────────────────────────────────────────────
|
|
@@ -21782,12 +21857,17 @@ function upsertAgentConfigTransaction(input) {
|
|
|
21782
21857
|
const db = (0,_lib_db__WEBPACK_IMPORTED_MODULE_0__/* .getDb */ .L)();
|
|
21783
21858
|
const existing = getAgentConfig(input.id);
|
|
21784
21859
|
const created_at = existing?.created_at ?? t;
|
|
21785
|
-
const
|
|
21860
|
+
const existingMbti = toMbti(existing?.adaptive_mbti);
|
|
21861
|
+
const mbti = input.adaptive_mbti ?? existingMbti ?? "INTJ";
|
|
21786
21862
|
const preset = _lib_agents_adaptive_persona_presets__WEBPACK_IMPORTED_MODULE_2__/* .MBTI_PRESETS */ .e[mbti];
|
|
21787
|
-
|
|
21788
|
-
|
|
21789
|
-
|
|
21790
|
-
const
|
|
21863
|
+
// Omitted sliders keep their tuned values; they only fall back to the
|
|
21864
|
+
// preset when the type changes or the agent is new. Otherwise every
|
|
21865
|
+
// partial update (approved proposals, tool edits) reset them.
|
|
21866
|
+
const keepTuned = existing !== null && existing !== undefined && mbti === existingMbti;
|
|
21867
|
+
const strength = input.adaptive_persona_strength ?? (keepTuned ? existing.adaptive_persona_strength : preset.strength);
|
|
21868
|
+
const empathy = input.adaptive_empathy ?? (keepTuned ? existing.adaptive_empathy : preset.empathy);
|
|
21869
|
+
const expressiveness = input.adaptive_expressiveness ?? (keepTuned ? existing.adaptive_expressiveness : preset.expressiveness);
|
|
21870
|
+
const verbosity = input.adaptive_verbosity ?? (keepTuned ? existing.adaptive_verbosity : preset.verbosity);
|
|
21791
21871
|
if (input.is_default) db.prepare("UPDATE agent_configs SET is_default=0").run();
|
|
21792
21872
|
// harness_id: explicit `undefined` means "keep existing"; explicit `null`
|
|
21793
21873
|
// means "use the global default". Empty string is normalised to null too,
|
|
@@ -22023,23 +22103,27 @@ async function readToolResultRef(args) {
|
|
|
22023
22103
|
}
|
|
22024
22104
|
const offset = Math.max(0, Math.floor(args.offset ?? 0));
|
|
22025
22105
|
const limit = Math.min(MAX_READ_BYTES, Math.max(1, Math.floor(args.limit ?? DEFAULT_PREVIEW_BYTES)));
|
|
22026
|
-
let buf;
|
|
22027
22106
|
try {
|
|
22028
22107
|
const file = await node_fs__WEBPACK_IMPORTED_MODULE_0__.promises.open(abs, "r");
|
|
22029
22108
|
try {
|
|
22030
22109
|
const stat = await file.stat();
|
|
22031
|
-
|
|
22032
|
-
|
|
22033
|
-
|
|
22034
|
-
const
|
|
22110
|
+
// Read a few bytes either side so the window can be moved onto UTF-8
|
|
22111
|
+
// character boundaries; paging must never split a multi-byte character.
|
|
22112
|
+
const windowStart = Math.min(Math.max(0, offset - 3), stat.size);
|
|
22113
|
+
const windowLength = Math.max(0, Math.min(stat.size - windowStart, offset - windowStart + limit + 3));
|
|
22114
|
+
const buf = Buffer.alloc(windowLength);
|
|
22115
|
+
if (windowLength > 0) await file.read(buf, 0, windowLength, windowStart);
|
|
22116
|
+
const { start, end } = utf8Window(buf, Math.min(offset, stat.size) - windowStart, limit);
|
|
22117
|
+
const actualOffset = windowStart + start;
|
|
22118
|
+
const nextOffset = windowStart + end;
|
|
22035
22119
|
return {
|
|
22036
22120
|
ok: true,
|
|
22037
22121
|
status: "done",
|
|
22038
22122
|
name: args.name,
|
|
22039
|
-
offset,
|
|
22123
|
+
offset: actualOffset,
|
|
22040
22124
|
limit,
|
|
22041
22125
|
bytes: stat.size,
|
|
22042
|
-
result: buf.toString("utf8"),
|
|
22126
|
+
result: buf.subarray(start, end).toString("utf8"),
|
|
22043
22127
|
next_offset: nextOffset < stat.size ? nextOffset : null,
|
|
22044
22128
|
done: nextOffset >= stat.size
|
|
22045
22129
|
};
|
|
@@ -22055,6 +22139,26 @@ async function readToolResultRef(args) {
|
|
|
22055
22139
|
};
|
|
22056
22140
|
}
|
|
22057
22141
|
}
|
|
22142
|
+
const isUtf8Continuation = (byte)=>byte !== undefined && (byte & 0xc0) === 0x80;
|
|
22143
|
+
// Moves `[start, start + limit)` inside `buf` onto character boundaries: the
|
|
22144
|
+
// start backs up to its lead byte, and the end backs up so it does not cut a
|
|
22145
|
+
// character — unless that character alone exceeds `limit`, in which case the
|
|
22146
|
+
// whole character is returned so paging always makes progress.
|
|
22147
|
+
function utf8Window(buf, start, limit) {
|
|
22148
|
+
let s = Math.max(0, Math.min(start, buf.length));
|
|
22149
|
+
while(s > 0 && isUtf8Continuation(buf[s]))s--;
|
|
22150
|
+
let e = Math.min(buf.length, s + limit);
|
|
22151
|
+
if (e < buf.length && isUtf8Continuation(buf[e])) {
|
|
22152
|
+
let lead = e;
|
|
22153
|
+
while(lead > s && isUtf8Continuation(buf[lead]))lead--;
|
|
22154
|
+
if (lead > s) e = lead;
|
|
22155
|
+
else while(e < buf.length && isUtf8Continuation(buf[e]))e++;
|
|
22156
|
+
}
|
|
22157
|
+
return {
|
|
22158
|
+
start: s,
|
|
22159
|
+
end: e
|
|
22160
|
+
};
|
|
22161
|
+
}
|
|
22058
22162
|
function serializeToolResult(result) {
|
|
22059
22163
|
if (typeof result === "string") return result;
|
|
22060
22164
|
return JSON.stringify(result) ?? String(result);
|
|
@@ -22072,10 +22176,21 @@ function buildPreview(value, mimeType) {
|
|
|
22072
22176
|
try {
|
|
22073
22177
|
const parsed = JSON.parse(value);
|
|
22074
22178
|
if (Array.isArray(parsed)) {
|
|
22075
|
-
|
|
22179
|
+
// Cap by bytes as well as items: a few huge rows must not smuggle the
|
|
22180
|
+
// whole result back inline.
|
|
22181
|
+
for(let n = Math.min(parsed.length, JSON_ARRAY_PREVIEW_ITEMS); n > 0; n--){
|
|
22182
|
+
const preview = parsed.slice(0, n);
|
|
22183
|
+
const bytes = Buffer.byteLength(JSON.stringify(preview));
|
|
22184
|
+
if (bytes <= DEFAULT_PREVIEW_BYTES) return {
|
|
22185
|
+
value: preview,
|
|
22186
|
+
bytes,
|
|
22187
|
+
total_count: parsed.length
|
|
22188
|
+
};
|
|
22189
|
+
}
|
|
22190
|
+
const text = takeUtf8Prefix(value, DEFAULT_PREVIEW_BYTES);
|
|
22076
22191
|
return {
|
|
22077
|
-
value:
|
|
22078
|
-
bytes: Buffer.byteLength(
|
|
22192
|
+
value: text,
|
|
22193
|
+
bytes: Buffer.byteLength(text),
|
|
22079
22194
|
total_count: parsed.length
|
|
22080
22195
|
};
|
|
22081
22196
|
}
|
|
@@ -22098,6 +22213,8 @@ function takeUtf8Prefix(value, maxBytes) {
|
|
|
22098
22213
|
if (Buffer.byteLength(value.slice(0, mid)) <= maxBytes) lo = mid;
|
|
22099
22214
|
else hi = mid - 1;
|
|
22100
22215
|
}
|
|
22216
|
+
const code = value.charCodeAt(lo - 1);
|
|
22217
|
+
if (lo > 0 && code >= 0xd800 && code <= 0xdbff) lo--;
|
|
22101
22218
|
return value.slice(0, lo);
|
|
22102
22219
|
}
|
|
22103
22220
|
function safeToolName(name) {
|
|
@@ -26018,8 +26135,21 @@ const MEMORY_WRITE_NAMESPACES = new Set([
|
|
|
26018
26135
|
function rowsInRange(rows, topic) {
|
|
26019
26136
|
return rows.filter((row)=>row.seq >= (topic.start_seq ?? Infinity) && row.seq <= (topic.end_seq ?? -Infinity));
|
|
26020
26137
|
}
|
|
26138
|
+
// Unicode-aware so non-Latin subjects get distinct keys; an ASCII-only slug
|
|
26139
|
+
// collapsed them all to "" and the uplift skipped them. Subjects with no
|
|
26140
|
+
// letters or digits fall back to a stable hash.
|
|
26021
26141
|
function slugifyForMemoryKey(subject) {
|
|
26022
|
-
|
|
26142
|
+
const slug = subject.normalize("NFC").toLowerCase().replace(/[^\p{L}\p{M}\p{N}]+/gu, "-").replace(/^-+|-+$/g, "");
|
|
26143
|
+
const capped = Array.from(slug).slice(0, 80).join("").replace(/-+$/, "");
|
|
26144
|
+
return capped || `fact-${fnv1a(subject)}`;
|
|
26145
|
+
}
|
|
26146
|
+
function fnv1a(text) {
|
|
26147
|
+
let hash = 0x811c9dc5;
|
|
26148
|
+
for(let i = 0; i < text.length; i++){
|
|
26149
|
+
hash ^= text.charCodeAt(i);
|
|
26150
|
+
hash = Math.imul(hash, 0x01000193);
|
|
26151
|
+
}
|
|
26152
|
+
return (hash >>> 0).toString(16).padStart(8, "0");
|
|
26023
26153
|
}
|
|
26024
26154
|
/**
|
|
26025
26155
|
* Merge facts by subject (case-insensitive) and memory key. Later entries win,
|
|
@@ -26031,9 +26161,18 @@ function slugifyForMemoryKey(subject) {
|
|
|
26031
26161
|
for (const list of lists){
|
|
26032
26162
|
for (const fact of list){
|
|
26033
26163
|
const subjectId = fact.subject.trim().toLowerCase();
|
|
26034
|
-
const
|
|
26035
|
-
|
|
26036
|
-
|
|
26164
|
+
const sameKeySubject = fact.key ? keyToSubject.get(fact.key) : undefined;
|
|
26165
|
+
for (const replaced of [
|
|
26166
|
+
sameKeySubject,
|
|
26167
|
+
subjectId
|
|
26168
|
+
]){
|
|
26169
|
+
if (replaced === undefined) continue;
|
|
26170
|
+
// Drop the replaced fact's key mapping too, so a later fact reusing
|
|
26171
|
+
// that key cannot delete whatever now lives under this subject.
|
|
26172
|
+
const previousKey = merged.get(replaced)?.key;
|
|
26173
|
+
if (previousKey) keyToSubject.delete(previousKey);
|
|
26174
|
+
merged.delete(replaced);
|
|
26175
|
+
}
|
|
26037
26176
|
merged.set(subjectId, fact);
|
|
26038
26177
|
if (fact.key) keyToSubject.set(fact.key, subjectId);
|
|
26039
26178
|
}
|
|
@@ -29862,14 +30001,15 @@ function stripWrapperFields(args) {
|
|
|
29862
30001
|
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
29863
30002
|
/* harmony export */ Wz: () => (/* binding */ _resolveGmailAuth)
|
|
29864
30003
|
/* harmony export */ });
|
|
29865
|
-
/* unused harmony exports buildRawMessage, gmailSearchTool, gmailGetMessageTool, gmailListLabelsTool, gmailModifyMessageTool, gmailCreateDraftTool, gmailSendEmailTool, gmailTrashMessageTool */
|
|
30004
|
+
/* unused harmony exports gmailWebLink, buildRawMessage, gmailSearchTool, gmailGetMessageTool, gmailListLabelsTool, gmailModifyMessageTool, gmailCreateDraftTool, gmailSendEmailTool, gmailTrashMessageTool */
|
|
29866
30005
|
/* harmony import */ var _langchain_core_tools__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(49585);
|
|
29867
|
-
/* harmony import */ var
|
|
30006
|
+
/* harmony import */ var zod__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(17033);
|
|
29868
30007
|
/* harmony import */ var _lib_utils_html__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(85212);
|
|
29869
|
-
/* harmony import */ var
|
|
30008
|
+
/* harmony import */ var _lib_utils_text__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(69494);
|
|
29870
30009
|
/* harmony import */ var _packages_langchain_package__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(18932);
|
|
29871
30010
|
/* harmony import */ var _lib_integrations_gmail_oauth__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(7721);
|
|
29872
30011
|
/* harmony import */ var _lib_utils_error__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(4379);
|
|
30012
|
+
/* harmony import */ var _lib_utils_source_link__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(76385);
|
|
29873
30013
|
/**
|
|
29874
30014
|
* Native Gmail tools — direct REST API calls to gmail.googleapis.com, no MCP.
|
|
29875
30015
|
*
|
|
@@ -29897,6 +30037,7 @@ function stripWrapperFields(args) {
|
|
|
29897
30037
|
|
|
29898
30038
|
|
|
29899
30039
|
|
|
30040
|
+
|
|
29900
30041
|
// Exposed for the integrations test endpoint.
|
|
29901
30042
|
function _resolveGmailAuth() {
|
|
29902
30043
|
return (0,_lib_integrations_gmail_oauth__WEBPACK_IMPORTED_MODULE_2__/* .resolveGoogleAuth */ .wq)();
|
|
@@ -29921,6 +30062,31 @@ function resolveGmailAuthForTool() {
|
|
|
29921
30062
|
};
|
|
29922
30063
|
}
|
|
29923
30064
|
}
|
|
30065
|
+
// ── Source links ────────────────────────────────────────────────────────────
|
|
30066
|
+
// Gmail's web URL scheme is undocumented. `#all/<threadId>` opens the
|
|
30067
|
+
// conversation from All Mail whatever its labels, and `/u/<email>/` selects
|
|
30068
|
+
// the signed-in account (`/u/0/` is whichever account signed in first).
|
|
30069
|
+
const GMAIL_API_ID = /^[0-9a-f]{8,32}$/i;
|
|
30070
|
+
function gmailWebLink(threadId, account) {
|
|
30071
|
+
if (!threadId || !GMAIL_API_ID.test(threadId)) return null;
|
|
30072
|
+
const slot = account ? encodeURIComponent(account) : "0";
|
|
30073
|
+
return `https://mail.google.com/mail/u/${slot}/#all/${threadId}`;
|
|
30074
|
+
}
|
|
30075
|
+
const accountEmailCache = new Map();
|
|
30076
|
+
// getProfile works with every Gmail scope; a failure only drops the account
|
|
30077
|
+
// from the link, so it is not retried within the process.
|
|
30078
|
+
function gmailAccountEmail(auth) {
|
|
30079
|
+
const key = auth.refresh_token.slice(0, 20);
|
|
30080
|
+
let pending = accountEmailCache.get(key);
|
|
30081
|
+
if (!pending) {
|
|
30082
|
+
pending = gmailFetch(auth, "/profile").then((p)=>{
|
|
30083
|
+
const email = p.emailAddress;
|
|
30084
|
+
return typeof email === "string" && email.includes("@") ? email : null;
|
|
30085
|
+
}).catch(()=>null);
|
|
30086
|
+
accountEmailCache.set(key, pending);
|
|
30087
|
+
}
|
|
30088
|
+
return pending;
|
|
30089
|
+
}
|
|
29924
30090
|
// ── Decoders / helpers ──────────────────────────────────────────────────────
|
|
29925
30091
|
// Gmail uses base64url (no padding, +/ → -_). Node's Buffer handles it directly.
|
|
29926
30092
|
function decodeBase64Url(s) {
|
|
@@ -29993,6 +30159,7 @@ const gmailSearchTool = (0,_langchain_core_tools__WEBPACK_IMPORTED_MODULE_0__/*
|
|
|
29993
30159
|
messages: []
|
|
29994
30160
|
});
|
|
29995
30161
|
}
|
|
30162
|
+
const account = await gmailAccountEmail(auth);
|
|
29996
30163
|
// Parallel metadata fetch; the API recommends batching but for ≤100 ids
|
|
29997
30164
|
// parallel single calls are simpler and well within quota.
|
|
29998
30165
|
const details = await Promise.all(ids.map(async (id)=>{
|
|
@@ -30001,15 +30168,19 @@ const gmailSearchTool = (0,_langchain_core_tools__WEBPACK_IMPORTED_MODULE_0__/*
|
|
|
30001
30168
|
id,
|
|
30002
30169
|
error: m.error
|
|
30003
30170
|
};
|
|
30171
|
+
const subject = header(m.payload?.headers, "Subject");
|
|
30172
|
+
const webLink = gmailWebLink(m.threadId, account);
|
|
30004
30173
|
return {
|
|
30005
30174
|
id: m.id,
|
|
30006
30175
|
thread_id: m.threadId,
|
|
30007
30176
|
from: header(m.payload?.headers, "From"),
|
|
30008
30177
|
to: header(m.payload?.headers, "To"),
|
|
30009
|
-
subject
|
|
30178
|
+
subject,
|
|
30010
30179
|
date: header(m.payload?.headers, "Date"),
|
|
30011
30180
|
snippet: m.snippet ?? null,
|
|
30012
|
-
labels: m.labelIds ?? []
|
|
30181
|
+
labels: m.labelIds ?? [],
|
|
30182
|
+
web_link: webLink,
|
|
30183
|
+
cite_as: (0,_lib_utils_source_link__WEBPACK_IMPORTED_MODULE_5__/* .citeAs */ .w)(subject, webLink, "Gmail message")
|
|
30013
30184
|
};
|
|
30014
30185
|
}));
|
|
30015
30186
|
return JSON.stringify({
|
|
@@ -30021,9 +30192,9 @@ const gmailSearchTool = (0,_langchain_core_tools__WEBPACK_IMPORTED_MODULE_0__/*
|
|
|
30021
30192
|
}, {
|
|
30022
30193
|
name: "gmail_search",
|
|
30023
30194
|
description: "Search the user's Gmail with Gmail query syntax. Returns message metadata (from, to, subject, " + "date, snippet, labels) plus Gmail's resultSizeEstimate and next page token so '1 result' " + "doesn't get mistaken for '1 unread email'. Examples: 'is:unread newer_than:1d', " + "'from:notifications@github.com', 'subject:invoice has:attachment', 'in:inbox -category:promotions'. " + "Use this before calling gmail_get_message — the snippet is often enough.",
|
|
30024
|
-
schema:
|
|
30025
|
-
query:
|
|
30026
|
-
max_results:
|
|
30195
|
+
schema: zod__WEBPACK_IMPORTED_MODULE_6__/* .object */ .Ikc({
|
|
30196
|
+
query: zod__WEBPACK_IMPORTED_MODULE_6__/* .string */ .YjP().describe("Gmail query string"),
|
|
30197
|
+
max_results: zod__WEBPACK_IMPORTED_MODULE_6__/* .number */ .aig().int().optional().describe("Max messages (default 25, max 100)")
|
|
30027
30198
|
})
|
|
30028
30199
|
});
|
|
30029
30200
|
const gmailGetMessageTool = (0,_langchain_core_tools__WEBPACK_IMPORTED_MODULE_0__/* .tool */ .z6)(async ({ id })=>{
|
|
@@ -30032,15 +30203,19 @@ const gmailGetMessageTool = (0,_langchain_core_tools__WEBPACK_IMPORTED_MODULE_0_
|
|
|
30032
30203
|
const m = await gmailFetch(auth, `/messages/${encodeURIComponent(id)}?format=full`);
|
|
30033
30204
|
if (m.error) return JSON.stringify(m);
|
|
30034
30205
|
const body = extractBody(m.payload);
|
|
30035
|
-
const { text: capped, truncated } = (0,
|
|
30206
|
+
const { text: capped, truncated } = (0,_lib_utils_text__WEBPACK_IMPORTED_MODULE_7__/* .truncateBytes */ .Q)(body, MAX_BODY_BYTES);
|
|
30207
|
+
const subject = header(m.payload?.headers, "Subject");
|
|
30208
|
+
const webLink = gmailWebLink(m.threadId, await gmailAccountEmail(auth));
|
|
30036
30209
|
return JSON.stringify({
|
|
30037
30210
|
id: m.id,
|
|
30038
30211
|
thread_id: m.threadId,
|
|
30212
|
+
web_link: webLink,
|
|
30213
|
+
cite_as: (0,_lib_utils_source_link__WEBPACK_IMPORTED_MODULE_5__/* .citeAs */ .w)(subject, webLink, "Gmail message"),
|
|
30039
30214
|
labels: m.labelIds ?? [],
|
|
30040
30215
|
from: header(m.payload?.headers, "From"),
|
|
30041
30216
|
to: header(m.payload?.headers, "To"),
|
|
30042
30217
|
cc: header(m.payload?.headers, "Cc"),
|
|
30043
|
-
subject
|
|
30218
|
+
subject,
|
|
30044
30219
|
date: header(m.payload?.headers, "Date"),
|
|
30045
30220
|
message_id: header(m.payload?.headers, "Message-Id") ?? header(m.payload?.headers, "Message-ID"),
|
|
30046
30221
|
snippet: m.snippet ?? null,
|
|
@@ -30050,8 +30225,8 @@ const gmailGetMessageTool = (0,_langchain_core_tools__WEBPACK_IMPORTED_MODULE_0_
|
|
|
30050
30225
|
}, {
|
|
30051
30226
|
name: "gmail_get_message",
|
|
30052
30227
|
description: "Fetch one Gmail message by id, including full headers and the decoded text body (text/plain " + "preferred, HTML stripped if only HTML is available). Body capped at 30KB with `truncated:true` " + "when cut off.",
|
|
30053
|
-
schema:
|
|
30054
|
-
id:
|
|
30228
|
+
schema: zod__WEBPACK_IMPORTED_MODULE_6__/* .object */ .Ikc({
|
|
30229
|
+
id: zod__WEBPACK_IMPORTED_MODULE_6__/* .string */ .YjP().describe("Gmail message id (from gmail_search results)")
|
|
30055
30230
|
})
|
|
30056
30231
|
});
|
|
30057
30232
|
const gmailListLabelsTool = (0,_langchain_core_tools__WEBPACK_IMPORTED_MODULE_0__/* .tool */ .z6)(async ()=>{
|
|
@@ -30069,7 +30244,7 @@ const gmailListLabelsTool = (0,_langchain_core_tools__WEBPACK_IMPORTED_MODULE_0_
|
|
|
30069
30244
|
}, {
|
|
30070
30245
|
name: "gmail_list_labels",
|
|
30071
30246
|
description: "List all Gmail labels (system + user). System label ids are uppercase (INBOX, UNREAD, " + "STARRED, IMPORTANT, SPAM, TRASH, SENT, DRAFT, CATEGORY_*). User labels have lowercase " + "alphanumeric ids like 'Label_42'. Use the id values with gmail_modify_message.",
|
|
30072
|
-
schema:
|
|
30247
|
+
schema: zod__WEBPACK_IMPORTED_MODULE_6__/* .object */ .Ikc({})
|
|
30073
30248
|
});
|
|
30074
30249
|
const gmailModifyMessageTool = (0,_langchain_core_tools__WEBPACK_IMPORTED_MODULE_0__/* .tool */ .z6)(async ({ id, add_labels, remove_labels })=>{
|
|
30075
30250
|
const auth = resolveGmailAuthForTool();
|
|
@@ -30095,10 +30270,10 @@ const gmailModifyMessageTool = (0,_langchain_core_tools__WEBPACK_IMPORTED_MODULE
|
|
|
30095
30270
|
}, {
|
|
30096
30271
|
name: "gmail_modify_message",
|
|
30097
30272
|
description: "Add or remove labels on a Gmail message. Common patterns: " + "archive = remove_labels=['INBOX']; mark read = remove_labels=['UNREAD']; " + "star = add_labels=['STARRED']; mark important = add_labels=['IMPORTANT']. " + "Use gmail_list_labels first if you don't know a user label id.",
|
|
30098
|
-
schema:
|
|
30099
|
-
id:
|
|
30100
|
-
add_labels:
|
|
30101
|
-
remove_labels:
|
|
30273
|
+
schema: zod__WEBPACK_IMPORTED_MODULE_6__/* .object */ .Ikc({
|
|
30274
|
+
id: zod__WEBPACK_IMPORTED_MODULE_6__/* .string */ .YjP().describe("Gmail message id"),
|
|
30275
|
+
add_labels: zod__WEBPACK_IMPORTED_MODULE_6__/* .array */ .YOg(zod__WEBPACK_IMPORTED_MODULE_6__/* .string */ .YjP()).optional().describe("Label ids to add"),
|
|
30276
|
+
remove_labels: zod__WEBPACK_IMPORTED_MODULE_6__/* .array */ .YOg(zod__WEBPACK_IMPORTED_MODULE_6__/* .string */ .YjP()).optional().describe("Label ids to remove")
|
|
30102
30277
|
})
|
|
30103
30278
|
});
|
|
30104
30279
|
const gmailCreateDraftTool = (0,_langchain_core_tools__WEBPACK_IMPORTED_MODULE_0__/* .tool */ .z6)(async ({ to, cc, bcc, subject, body, content_type, in_reply_to_id })=>{
|
|
@@ -30153,17 +30328,17 @@ const gmailCreateDraftTool = (0,_langchain_core_tools__WEBPACK_IMPORTED_MODULE_0
|
|
|
30153
30328
|
}, {
|
|
30154
30329
|
name: "gmail_create_draft",
|
|
30155
30330
|
description: "Create a Gmail draft. Prefer drafts unless the user explicitly asks to send immediately. " + "`content_type` defaults to 'text'; pass 'html' if `body` contains HTML markup. " + "When replying to an existing message, pass `in_reply_to_id` (the parent " + "message id from gmail_search/gmail_get_message) — the tool will set Message-Id/References/" + "threadId so the draft appears inside the right Gmail thread.",
|
|
30156
|
-
schema:
|
|
30157
|
-
to:
|
|
30158
|
-
cc:
|
|
30159
|
-
bcc:
|
|
30160
|
-
subject:
|
|
30161
|
-
body:
|
|
30162
|
-
content_type:
|
|
30331
|
+
schema: zod__WEBPACK_IMPORTED_MODULE_6__/* .object */ .Ikc({
|
|
30332
|
+
to: zod__WEBPACK_IMPORTED_MODULE_6__/* .array */ .YOg(zod__WEBPACK_IMPORTED_MODULE_6__/* .string */ .YjP()).describe("Recipient email addresses"),
|
|
30333
|
+
cc: zod__WEBPACK_IMPORTED_MODULE_6__/* .array */ .YOg(zod__WEBPACK_IMPORTED_MODULE_6__/* .string */ .YjP()).optional(),
|
|
30334
|
+
bcc: zod__WEBPACK_IMPORTED_MODULE_6__/* .array */ .YOg(zod__WEBPACK_IMPORTED_MODULE_6__/* .string */ .YjP()).optional(),
|
|
30335
|
+
subject: zod__WEBPACK_IMPORTED_MODULE_6__/* .string */ .YjP(),
|
|
30336
|
+
body: zod__WEBPACK_IMPORTED_MODULE_6__/* .string */ .YjP().max(DRAFT_BODY_MAX_CHARS).describe("Email body (max 100,000 characters)"),
|
|
30337
|
+
content_type: zod__WEBPACK_IMPORTED_MODULE_6__/* ["enum"] */ .k5n([
|
|
30163
30338
|
"text",
|
|
30164
30339
|
"html"
|
|
30165
30340
|
]).optional().describe("Body content type (default 'text')"),
|
|
30166
|
-
in_reply_to_id:
|
|
30341
|
+
in_reply_to_id: zod__WEBPACK_IMPORTED_MODULE_6__/* .string */ .YjP().optional().describe("Gmail message id to reply to (for threading)")
|
|
30167
30342
|
})
|
|
30168
30343
|
});
|
|
30169
30344
|
const gmailSendEmailTool = (0,_langchain_core_tools__WEBPACK_IMPORTED_MODULE_0__/* .tool */ .z6)(async ({ to, cc, bcc, subject, body, content_type, in_reply_to_id })=>{
|
|
@@ -30213,17 +30388,17 @@ const gmailSendEmailTool = (0,_langchain_core_tools__WEBPACK_IMPORTED_MODULE_0__
|
|
|
30213
30388
|
}, {
|
|
30214
30389
|
name: "gmail_send_email",
|
|
30215
30390
|
description: "Send a Gmail email immediately. Only use when the user explicitly asks to send now; " + "otherwise create a draft with gmail_create_draft. Supports text or HTML bodies via `content_type`. " + "When replying, pass `in_reply_to_id` so Gmail threads the sent message correctly.",
|
|
30216
|
-
schema:
|
|
30217
|
-
to:
|
|
30218
|
-
cc:
|
|
30219
|
-
bcc:
|
|
30220
|
-
subject:
|
|
30221
|
-
body:
|
|
30222
|
-
content_type:
|
|
30391
|
+
schema: zod__WEBPACK_IMPORTED_MODULE_6__/* .object */ .Ikc({
|
|
30392
|
+
to: zod__WEBPACK_IMPORTED_MODULE_6__/* .array */ .YOg(zod__WEBPACK_IMPORTED_MODULE_6__/* .string */ .YjP()).min(1).describe("Recipient email addresses"),
|
|
30393
|
+
cc: zod__WEBPACK_IMPORTED_MODULE_6__/* .array */ .YOg(zod__WEBPACK_IMPORTED_MODULE_6__/* .string */ .YjP()).optional(),
|
|
30394
|
+
bcc: zod__WEBPACK_IMPORTED_MODULE_6__/* .array */ .YOg(zod__WEBPACK_IMPORTED_MODULE_6__/* .string */ .YjP()).optional(),
|
|
30395
|
+
subject: zod__WEBPACK_IMPORTED_MODULE_6__/* .string */ .YjP(),
|
|
30396
|
+
body: zod__WEBPACK_IMPORTED_MODULE_6__/* .string */ .YjP().max(SEND_BODY_MAX_CHARS).describe("Email body (max 100,000 characters)"),
|
|
30397
|
+
content_type: zod__WEBPACK_IMPORTED_MODULE_6__/* ["enum"] */ .k5n([
|
|
30223
30398
|
"text",
|
|
30224
30399
|
"html"
|
|
30225
30400
|
]).optional().describe("Body content type (default 'text')"),
|
|
30226
|
-
in_reply_to_id:
|
|
30401
|
+
in_reply_to_id: zod__WEBPACK_IMPORTED_MODULE_6__/* .string */ .YjP().optional().describe("Gmail message id to reply to (for threading)")
|
|
30227
30402
|
})
|
|
30228
30403
|
});
|
|
30229
30404
|
const gmailTrashMessageTool = (0,_langchain_core_tools__WEBPACK_IMPORTED_MODULE_0__/* .tool */ .z6)(async ({ id })=>{
|
|
@@ -30241,8 +30416,8 @@ const gmailTrashMessageTool = (0,_langchain_core_tools__WEBPACK_IMPORTED_MODULE_
|
|
|
30241
30416
|
}, {
|
|
30242
30417
|
name: "gmail_trash_message",
|
|
30243
30418
|
description: "Move a Gmail message to Trash (reversible for 30 days, not permanent delete). Only call this " + "when the user has explicitly asked to trash/delete a message — never on your own initiative " + "as part of a triage flow. Prefer gmail_modify_message remove_labels=['INBOX'] to archive.",
|
|
30244
|
-
schema:
|
|
30245
|
-
id:
|
|
30419
|
+
schema: zod__WEBPACK_IMPORTED_MODULE_6__/* .object */ .Ikc({
|
|
30420
|
+
id: zod__WEBPACK_IMPORTED_MODULE_6__/* .string */ .YjP().describe("Gmail message id")
|
|
30246
30421
|
})
|
|
30247
30422
|
});
|
|
30248
30423
|
(0,_packages_langchain_package__WEBPACK_IMPORTED_MODULE_1__/* .registerLangChainPackage */ .p)({
|
|
@@ -31422,6 +31597,51 @@ async function indexAllSources(opts) {
|
|
|
31422
31597
|
}
|
|
31423
31598
|
|
|
31424
31599
|
|
|
31600
|
+
/***/ }),
|
|
31601
|
+
|
|
31602
|
+
/***/ 76385:
|
|
31603
|
+
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
|
31604
|
+
|
|
31605
|
+
"use strict";
|
|
31606
|
+
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
31607
|
+
/* harmony export */ w: () => (/* binding */ citeAs)
|
|
31608
|
+
/* harmony export */ });
|
|
31609
|
+
/* unused harmony export httpsUrlOrNull */
|
|
31610
|
+
/**
|
|
31611
|
+
* Source-link fields for tool results, so an agent can link a reply back to
|
|
31612
|
+
* the email, calendar event, or chat it came from without building URLs.
|
|
31613
|
+
*
|
|
31614
|
+
* `cite_as` is a ready-made markdown link the system prompt tells agents to
|
|
31615
|
+
* paste verbatim. Building it in code keeps the label and URL well-formed:
|
|
31616
|
+
* a stray `]` in a subject or `)` in a URL would otherwise break the link.
|
|
31617
|
+
*/ const MAX_LABEL_CHARS = 80;
|
|
31618
|
+
/** Returns `url` when it is an absolute https URL, otherwise null. */ function httpsUrlOrNull(url) {
|
|
31619
|
+
if (!url) return null;
|
|
31620
|
+
try {
|
|
31621
|
+
const parsed = new URL(url);
|
|
31622
|
+
return parsed.protocol === "https:" ? parsed.href : null;
|
|
31623
|
+
} catch {
|
|
31624
|
+
return null;
|
|
31625
|
+
}
|
|
31626
|
+
}
|
|
31627
|
+
function markdownLabel(label, fallback) {
|
|
31628
|
+
const flat = (label ?? "").replace(/\s+/g, " ").trim();
|
|
31629
|
+
const capped = flat.length > MAX_LABEL_CHARS ? `${flat.slice(0, MAX_LABEL_CHARS - 1).trimEnd()}…` : flat;
|
|
31630
|
+
return (capped || fallback).replace(/[\\[\]]/g, (c)=>`\\${c}`);
|
|
31631
|
+
}
|
|
31632
|
+
function markdownDestination(url) {
|
|
31633
|
+
return url.replace(/[()\s<>]/g, (c)=>`%${c.charCodeAt(0).toString(16).toUpperCase().padStart(2, "0")}`);
|
|
31634
|
+
}
|
|
31635
|
+
/**
|
|
31636
|
+
* Pre-built markdown link for `cite_as`, or null when there is no usable URL.
|
|
31637
|
+
* Only https URLs qualify: the chat renderer drops other schemes.
|
|
31638
|
+
*/ function citeAs(label, url, fallbackLabel = "source") {
|
|
31639
|
+
const safe = httpsUrlOrNull(url);
|
|
31640
|
+
if (!safe) return null;
|
|
31641
|
+
return `[${markdownLabel(label, fallbackLabel)}](${markdownDestination(safe)})`;
|
|
31642
|
+
}
|
|
31643
|
+
|
|
31644
|
+
|
|
31425
31645
|
/***/ }),
|
|
31426
31646
|
|
|
31427
31647
|
/***/ 82703:
|
|
@@ -32138,7 +32358,7 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
32138
32358
|
IC: () => (/* binding */ withInterruptMarker)
|
|
32139
32359
|
});
|
|
32140
32360
|
|
|
32141
|
-
// UNUSED EXPORTS: INTERRUPT_MARKER, MAX_RATE_LIMIT_RETRY_AFTER_MS, RunThreadError, appendHistoryMessage, buildFabricationNudge, buildRetryContextSummary, contentText, isHotContextNearBudget, looksLikeStall, persistThreadRunUserMessage, rateLimitRetryDelayMs, retryTextOverlapRatio, shouldEmitChunk, shouldRetryTransientError, toolCallSignature, transientRetryDelayMs
|
|
32361
|
+
// UNUSED EXPORTS: INTERRUPT_MARKER, MAX_RATE_LIMIT_RETRY_AFTER_MS, RunThreadError, appendHistoryMessage, buildFabricationNudge, buildRetryContextSummary, contentText, hotTurnCooldownUntil, isHotContextNearBudget, looksLikeStall, persistThreadRunUserMessage, rateLimitRetryDelayMs, retryTextOverlapRatio, shouldEmitChunk, shouldRetryTransientError, toolCallSignature, transientRetryDelayMs
|
|
32142
32362
|
|
|
32143
32363
|
// EXTERNAL MODULE: ./lib/agents/action-vocabulary.ts
|
|
32144
32364
|
var action_vocabulary = __webpack_require__(56033);
|
|
@@ -35867,7 +36087,8 @@ function buildSharedToolCatalogContext() {
|
|
|
35867
36087
|
"6. Read large results by reference. A tool result with truncated=true is only a preview; do not treat it as complete. Use result_ref.name with tool_result_get and offset/limit to read only the slice you need.",
|
|
35868
36088
|
"7. Verify before reporting. A read-only result does not prove a new write. Claim a new write, send, schedule, delete, or configuration change only after the matching state-changing tool returns success in this turn. Trusted runtime system signals and their matching retrieved results can substantiate earlier named operations; attribute those outcomes to their receipts, never imply a new action or repeat completed work for proof.",
|
|
35869
36089
|
"8. Stop and ask. Do not retry a tool denied for agent_not_allowed, category_disabled, dropin_tool_disabled, credentials_missing or integration_unconfigured. The first three are permission decisions and the last two mean the integration is not set up \u2014 propose a configuration change or tell the user what to configure.",
|
|
35870
|
-
"9. Completion-reporting turns are read-only. permission_reason=signal_continuation_read_only forbids state-changing tools in this turn, including through invoke_tool. Do not bypass it with shell commands or treat an old user message as renewed permission; report the completed outcome and wait for a new user turn."
|
|
36090
|
+
"9. Completion-reporting turns are read-only. permission_reason=signal_continuation_read_only forbids state-changing tools in this turn, including through invoke_tool. Do not bypass it with shell commands or treat an old user message as renewed permission; report the completed outcome and wait for a new user turn.",
|
|
36091
|
+
"10. Link the source. When your reply refers to a specific email, calendar event, or chat that a tool result or bridge message gave you, link it: paste the item's cite_as value verbatim when present, otherwise use its web_link, html_link, or chat_link URL as a markdown link. Use only links you were given; never construct, guess, or edit one. If the item has no link, name it without one."
|
|
35871
36092
|
].join("\n");
|
|
35872
36093
|
}
|
|
35873
36094
|
function compareToolPermissionEntries(a, b) {
|
|
@@ -35947,9 +36168,14 @@ function buildDeliveryChannelContext(channel) {
|
|
|
35947
36168
|
return [
|
|
35948
36169
|
"--- Delivery channel ---",
|
|
35949
36170
|
`This message reached you over ${platform}${named}, not the regular chat UI.`,
|
|
35950
|
-
`You DO have access to ${platform} for this conversation: any reply you produce is sent back through that channel automatically. Do not tell the user the platform is unavailable; just answer the message
|
|
35951
|
-
|
|
36171
|
+
`You DO have access to ${platform} for this conversation: any reply you produce is sent back through that channel automatically. Do not tell the user the platform is unavailable; just answer the message.`,
|
|
36172
|
+
PLAIN_TEXT_DELIVERY_KINDS.has(channel.kind) ? `${platform} does not render markdown links: write any link as the bare URL, even where a cite_as value is given.` : ""
|
|
36173
|
+
].filter(Boolean).join("\n");
|
|
35952
36174
|
}
|
|
36175
|
+
const PLAIN_TEXT_DELIVERY_KINDS = new Set([
|
|
36176
|
+
"whatsapp",
|
|
36177
|
+
"sms"
|
|
36178
|
+
]);
|
|
35953
36179
|
function buildUserContext() {
|
|
35954
36180
|
const userProfile = (0,user_profile/* getUserProfile */.VM)();
|
|
35955
36181
|
const parts = [];
|
|
@@ -36033,7 +36259,7 @@ function buildSourceLinkContext(agent, manifest) {
|
|
|
36033
36259
|
"--- Citation format ---",
|
|
36034
36260
|
intro,
|
|
36035
36261
|
"PRIMARY (inline links): cite by writing a standard markdown link inline: `[short label](https://example.com/path)` or `[file name](/abs/path.ts)` or `[earlier reply](#msg-<id>)`. Wrap the cited PHRASE itself as the link text when natural — `Jade has [ice skating at 16:00](?thread=…&agent=…)` reads better than a trailing `[1]`.",
|
|
36036
|
-
"When a tool result contains a `cite_as` field (delegate_to_agent does, and so do
|
|
36262
|
+
"When a tool result contains a `cite_as` field (delegate_to_agent does, and so do the email and calendar tools), paste that exact value somewhere in your reply — it's a pre-built markdown link to the source. Anything you summarize from a delegate or from a web/file tool result MUST carry at least one inline link back to where it came from; a summary with zero links reads as if you made the facts up.",
|
|
36037
36263
|
"For web_search / fetch_webpage results, the URL is right there in the tool output — use it: `[headline or short label](https://...)`. For file_read results, link the absolute path: `[filename.ext](/abs/path/filename.ext)`.",
|
|
36038
36264
|
"FALLBACK (declared refs block): if a source is awkward to cite inline (e.g. you summarized 4 articles in one paragraph), you MAY end your reply with a fenced block exactly like this:",
|
|
36039
36265
|
"```jarela-references",
|
|
@@ -36532,17 +36758,27 @@ const SOURCE_PRODUCING_TOOLS_RESULT = new Set([
|
|
|
36532
36758
|
"fetch_webpage",
|
|
36533
36759
|
"web_fetch"
|
|
36534
36760
|
]);
|
|
36535
|
-
|
|
36536
|
-
//
|
|
36537
|
-
//
|
|
36538
|
-
//
|
|
36761
|
+
const TRACKING_PARAM_RE = /^(?:utm(?:_.*)?|fbclid|gclid|dclid|msclkid|mc_cid|mc_eid|igshid|ref_src)$/i;
|
|
36762
|
+
// Drop tracking params and in-page anchors for URLs and normalize
|
|
36763
|
+
// backslashes for paths so a citation that adds `?utm_source=...` or uses
|
|
36764
|
+
// forward slashes on Windows still matches the visited entry. Identifying
|
|
36765
|
+
// query params (Outlook `?ItemID=`, `watch?v=`) and hash routes (Gmail
|
|
36766
|
+
// `#all/<id>`) are kept verbatim: they are case-sensitive and are the only
|
|
36767
|
+
// thing that distinguishes two message permalinks. Also fold `~/...` to the
|
|
36768
|
+
// resolved home dir so `~/Downloads/x` and `C:\Users\andre\Downloads\x` de-dupe.
|
|
36539
36769
|
function normalizeSource(raw) {
|
|
36540
36770
|
const trimmed = raw.trim();
|
|
36541
36771
|
if (!trimmed) return "";
|
|
36542
36772
|
if (/^https?:\/\//i.test(trimmed)) {
|
|
36543
36773
|
try {
|
|
36544
36774
|
const u = new URL(trimmed);
|
|
36545
|
-
|
|
36775
|
+
const base = `${u.protocol}//${u.host}${u.pathname}`.replace(/\/+$/, "").toLowerCase();
|
|
36776
|
+
const params = [
|
|
36777
|
+
...u.searchParams
|
|
36778
|
+
].filter(([key])=>!TRACKING_PARAM_RE.test(key)).sort(([a], [b])=>a < b ? -1 : a > b ? 1 : 0);
|
|
36779
|
+
const query = params.length > 0 ? `?${new URLSearchParams(params).toString()}` : "";
|
|
36780
|
+
const hashRoute = u.hash.includes("/") ? u.hash : "";
|
|
36781
|
+
return base + query + hashRoute;
|
|
36546
36782
|
} catch {
|
|
36547
36783
|
return trimmed.toLowerCase();
|
|
36548
36784
|
}
|
|
@@ -36891,15 +37127,8 @@ ${sent}`;
|
|
|
36891
37127
|
*/ function parseCitationVerdict(text) {
|
|
36892
37128
|
if (!text) return null;
|
|
36893
37129
|
const stripped = text.replace(/```(?:json)?\s*/gi, "").replace(/```/g, "").trim();
|
|
36894
|
-
const
|
|
36895
|
-
if (!
|
|
36896
|
-
let parsed;
|
|
36897
|
-
try {
|
|
36898
|
-
parsed = JSON.parse(m[0]);
|
|
36899
|
-
} catch {
|
|
36900
|
-
return null;
|
|
36901
|
-
}
|
|
36902
|
-
if (!parsed || typeof parsed !== "object") return null;
|
|
37130
|
+
const parsed = findClaimsObject(stripped);
|
|
37131
|
+
if (!parsed) return null;
|
|
36903
37132
|
const claimsRaw = parsed.claims;
|
|
36904
37133
|
if (!Array.isArray(claimsRaw)) return null;
|
|
36905
37134
|
const claims = [];
|
|
@@ -36926,6 +37155,41 @@ ${sent}`;
|
|
|
36926
37155
|
}
|
|
36927
37156
|
return claims;
|
|
36928
37157
|
}
|
|
37158
|
+
// Models often wrap the verdict in prose that itself contains braces, so a
|
|
37159
|
+
// single greedy `{...}` match can start or end in the wrong place. Try each
|
|
37160
|
+
// `{` as a start and parse the balanced object it opens (string-aware).
|
|
37161
|
+
function findClaimsObject(text) {
|
|
37162
|
+
for(let start = text.indexOf("{"); start !== -1; start = text.indexOf("{", start + 1)){
|
|
37163
|
+
const end = balancedObjectEnd(text, start);
|
|
37164
|
+
if (end === -1) continue;
|
|
37165
|
+
const candidate = text.slice(start, end + 1);
|
|
37166
|
+
if (!candidate.includes('"claims"')) continue;
|
|
37167
|
+
try {
|
|
37168
|
+
const parsed = JSON.parse(candidate);
|
|
37169
|
+
if (parsed && typeof parsed === "object" && "claims" in parsed) return parsed;
|
|
37170
|
+
} catch {}
|
|
37171
|
+
}
|
|
37172
|
+
return null;
|
|
37173
|
+
}
|
|
37174
|
+
function balancedObjectEnd(text, start) {
|
|
37175
|
+
let depth = 0;
|
|
37176
|
+
let inString = false;
|
|
37177
|
+
for(let i = start; i < text.length; i++){
|
|
37178
|
+
const ch = text[i];
|
|
37179
|
+
if (inString) {
|
|
37180
|
+
if (ch === "\\") i++;
|
|
37181
|
+
else if (ch === '"') inString = false;
|
|
37182
|
+
} else if (ch === '"') {
|
|
37183
|
+
inString = true;
|
|
37184
|
+
} else if (ch === "{") {
|
|
37185
|
+
depth++;
|
|
37186
|
+
} else if (ch === "}") {
|
|
37187
|
+
depth--;
|
|
37188
|
+
if (depth === 0) return i;
|
|
37189
|
+
}
|
|
37190
|
+
}
|
|
37191
|
+
return -1;
|
|
37192
|
+
}
|
|
36929
37193
|
function collectStringsFromPayload(payload, out) {
|
|
36930
37194
|
if (!payload) return;
|
|
36931
37195
|
if (typeof payload === "string") {
|
|
@@ -37089,17 +37353,31 @@ function hotTurnBoundary(threadId, agentCfg, scope, bridgeKey) {
|
|
|
37089
37353
|
const boundary = userMessages[userMessages.length - turnLimit];
|
|
37090
37354
|
return boundary?.seq ?? null;
|
|
37091
37355
|
}
|
|
37092
|
-
|
|
37356
|
+
// The topic-aware boundary keeps the whole active topic hot, so user turns
|
|
37357
|
+
// since the pin usually still exceed the limit right after a commit. Without a
|
|
37358
|
+
// cooldown every following turn re-runs the topic LLM pass only to land on the
|
|
37359
|
+
// same pin. Skip the next half-limit turns (2 rows per turn) before re-checking.
|
|
37360
|
+
function hotTurnCooldownUntil(messageCount, hotTurnLimit) {
|
|
37361
|
+
const turnLimit = hotTurnLimit ?? types/* DEFAULT_HOT_TURN_LIMIT */.u_;
|
|
37362
|
+
const skipTurns = Math.max(1, Math.ceil(Math.max(1, turnLimit) / 2));
|
|
37363
|
+
return messageCount + skipTurns * 2 + 1;
|
|
37364
|
+
}
|
|
37365
|
+
async function maybeAutoCompactOversizedThread(agentId, threadId, onCompacting, preserveNewestMessages = 0) {
|
|
37093
37366
|
const cap = (0,config/* getConfig */.z)().maxThreadMessages;
|
|
37094
37367
|
const keepLast = autoCompactionKeepLast(cap);
|
|
37095
37368
|
const retainedMessages = keepLast + preserveNewestMessages;
|
|
37096
37369
|
const triggerAt = cap + (cap - keepLast);
|
|
37097
|
-
if (!Number.isFinite(cap) || cap <= 0
|
|
37370
|
+
if (!Number.isFinite(cap) || cap <= 0) return;
|
|
37371
|
+
// Only foreground rows are ever pruned; counting bridge/watcher/scheduled
|
|
37372
|
+
// rows would re-trigger an LLM compaction on every turn of a busy bridge
|
|
37373
|
+
// agent without ever bringing the count back under the cap.
|
|
37374
|
+
const messageCount = (0,threads/* countForegroundThreadMessages */.Tb)(threadId);
|
|
37375
|
+
if (messageCount < triggerAt) return;
|
|
37098
37376
|
try {
|
|
37099
37377
|
// A pin that already keeps the hot tier within the retained range must not
|
|
37100
37378
|
// be pulled back to the cutoff, nor re-summarised by an LLM on every turn.
|
|
37101
37379
|
const pinSeq = (0,threads/* getThread */.fG)(threadId)?.hot_since_seq ?? null;
|
|
37102
|
-
if (pinSeq !== null && (0,threads/*
|
|
37380
|
+
if (pinSeq !== null && (0,threads/* countForegroundThreadMessages */.Tb)(threadId, pinSeq) <= retainedMessages) {
|
|
37103
37381
|
(0,threads/* pruneThreadMessages */.vC)(threadId, retainedMessages, pinSeq);
|
|
37104
37382
|
return;
|
|
37105
37383
|
}
|
|
@@ -37138,7 +37416,6 @@ async function persistThreadRunUserMessage(req) {
|
|
|
37138
37416
|
if (!trimmed && !req.attachments?.length) {
|
|
37139
37417
|
throw new RunThreadError(400, "message required", "message_required");
|
|
37140
37418
|
}
|
|
37141
|
-
const messageCountBefore = thread.message_count;
|
|
37142
37419
|
const autoBoundaryScope = req.context_profile?.history_scope ?? (req.user_category === "bridge" ? "bridge" : "foreground");
|
|
37143
37420
|
const idleMsBefore = isAutoBoundaryEligibleCategory(req.user_category) ? conversationIdleMs(req.thread_id, autoBoundaryScope, req.history_bridge_key ?? undefined) : null;
|
|
37144
37421
|
const spilledAttachments = req.attachments?.length ? await spillAttachments(req.attachments) : undefined;
|
|
@@ -37158,7 +37435,6 @@ async function persistThreadRunUserMessage(req) {
|
|
|
37158
37435
|
});
|
|
37159
37436
|
return {
|
|
37160
37437
|
attachments: spilledAttachments,
|
|
37161
|
-
messageCountBefore,
|
|
37162
37438
|
idleMsBefore,
|
|
37163
37439
|
userMessageId: userMessage.msg_id,
|
|
37164
37440
|
storedContent: stored
|
|
@@ -37305,7 +37581,7 @@ function appendHistoryMessage(history, injected) {
|
|
|
37305
37581
|
let toolPermissionMap = baseToolPermissionMap;
|
|
37306
37582
|
let allowedTools = requestedAllowedTools;
|
|
37307
37583
|
if (!req._skip_persist_message && isAutoBoundaryEligibleCategory(req.user_category) && !hasPendingQueuedUserMessage(req.thread_id)) {
|
|
37308
|
-
await maybeAutoCompactOversizedThread(agentCfg.id, req.thread_id, req.
|
|
37584
|
+
await maybeAutoCompactOversizedThread(agentCfg.id, req.thread_id, req._onCompacting, req._user_message_persisted ? 2 : 0);
|
|
37309
37585
|
}
|
|
37310
37586
|
// Persist the user turn (including any attachments) before the LLM stream
|
|
37311
37587
|
// so reload-mid-stream still shows the prompt. The stall-retry path sets
|
|
@@ -37347,7 +37623,11 @@ function appendHistoryMessage(history, injected) {
|
|
|
37347
37623
|
const locked = !!latestThread && latestThread.message_count < (latestThread.auto_boundary_locked_until_msg_count ?? 0);
|
|
37348
37624
|
if (!locked) {
|
|
37349
37625
|
const boundary = hotTurnBoundary(req.thread_id, agentCfg, autoBoundaryScope);
|
|
37350
|
-
if (boundary !== null)
|
|
37626
|
+
if (boundary !== null) {
|
|
37627
|
+
(0,warm_summary_background/* kickBoundaryCompaction */.Wg)(req.thread_id, boundary, {
|
|
37628
|
+
autoBoundaryLockedUntilMessageCount: hotTurnCooldownUntil(latestThread?.message_count ?? 0, agentCfg.hot_turn_limit)
|
|
37629
|
+
});
|
|
37630
|
+
}
|
|
37351
37631
|
}
|
|
37352
37632
|
}
|
|
37353
37633
|
}
|
|
@@ -38814,12 +39094,11 @@ function isBasicToolCategory(category) {
|
|
|
38814
39094
|
|
|
38815
39095
|
// Every caller of moveThreadContextBoundary represents a user-initiated
|
|
38816
39096
|
// boundary change (drag the line, the manual /compact command, or the agent's
|
|
38817
|
-
// compact_context tool acting on the user's say-so)
|
|
38818
|
-
//
|
|
38819
|
-
//
|
|
38820
|
-
//
|
|
38821
|
-
//
|
|
38822
|
-
// choice doesn't get silently re-moved on the very next turn.
|
|
39097
|
+
// compact_context tool acting on the user's say-so). Suppresses the
|
|
39098
|
+
// hot-turn-limit compaction in lib/agents/run-thread.ts for the next N
|
|
39099
|
+
// eligible turns so a manual choice doesn't get silently re-moved on the very
|
|
39100
|
+
// next turn. The auto-detector arms a shorter cooldown of its own
|
|
39101
|
+
// (hotTurnCooldownUntil) so it doesn't re-run on every turn either.
|
|
38823
39102
|
// Counted in messages (~2 per turn: one user + one assistant row) since
|
|
38824
39103
|
// that's what's already on the thread row — no extra query or per-turn
|
|
38825
39104
|
// write needed to check it.
|
|
@@ -40098,6 +40377,13 @@ function readSnapshotSync() {
|
|
|
40098
40377
|
try {
|
|
40099
40378
|
const p = snapshotPath();
|
|
40100
40379
|
const stat = (0,external_node_fs_.statSync)(p);
|
|
40380
|
+
if (cached?.path === p && cached.mtimeMs === stat.mtimeMs) {
|
|
40381
|
+
return {
|
|
40382
|
+
path: p,
|
|
40383
|
+
snapshot: null,
|
|
40384
|
+
mtimeMs: stat.mtimeMs
|
|
40385
|
+
};
|
|
40386
|
+
}
|
|
40101
40387
|
const raw = (0,external_node_fs_.readFileSync)(p, "utf8");
|
|
40102
40388
|
return {
|
|
40103
40389
|
path: p,
|
|
@@ -40862,12 +41148,35 @@ function createRuntimeRequire(anchor) {
|
|
|
40862
41148
|
function managedPackagePath(packageName) {
|
|
40863
41149
|
return (0,node_path__WEBPACK_IMPORTED_MODULE_0__.join)((0,_langchain_packages__WEBPACK_IMPORTED_MODULE_1__/* .getPackagesDir */ .V_)(), "node_modules", packageName);
|
|
40864
41150
|
}
|
|
41151
|
+
function resolveOptionalPackage(packageName) {
|
|
41152
|
+
const managedReq = createRuntimeRequire((0,node_path__WEBPACK_IMPORTED_MODULE_0__.join)((0,_langchain_packages__WEBPACK_IMPORTED_MODULE_1__/* .getPackagesDir */ .V_)(), "_anchor"));
|
|
41153
|
+
try {
|
|
41154
|
+
return {
|
|
41155
|
+
req: managedReq,
|
|
41156
|
+
path: managedReq.resolve(managedPackagePath(packageName))
|
|
41157
|
+
};
|
|
41158
|
+
} catch {
|
|
41159
|
+
// Workspace builds expose bundled @circuitwall packages from the app root.
|
|
41160
|
+
}
|
|
41161
|
+
if (process.env.JARELA_PACKAGES_DIR?.trim()) return null;
|
|
41162
|
+
if (!packageName.startsWith("@circuitwall/")) return null;
|
|
41163
|
+
const appReq = createRuntimeRequire((0,node_path__WEBPACK_IMPORTED_MODULE_0__.join)(process.cwd(), "package.json"));
|
|
41164
|
+
try {
|
|
41165
|
+
return {
|
|
41166
|
+
req: appReq,
|
|
41167
|
+
path: appReq.resolve(packageName)
|
|
41168
|
+
};
|
|
41169
|
+
} catch {
|
|
41170
|
+
return null;
|
|
41171
|
+
}
|
|
41172
|
+
}
|
|
40865
41173
|
function loadOptionalPackage(packageName) {
|
|
40866
41174
|
const override = testOverrides.get(packageName);
|
|
40867
41175
|
if (override) return override;
|
|
41176
|
+
const resolved = resolveOptionalPackage(packageName);
|
|
41177
|
+
if (!resolved) return null;
|
|
40868
41178
|
try {
|
|
40869
|
-
|
|
40870
|
-
return req(managedPackagePath(packageName));
|
|
41179
|
+
return resolved.req(resolved.path);
|
|
40871
41180
|
} catch (err) {
|
|
40872
41181
|
// Keep the optional boundary non-fatal, but leave the actual load failure
|
|
40873
41182
|
// visible so missing peer dependencies are diagnosable from server logs.
|
|
@@ -40899,9 +41208,10 @@ function optionalFunction(packageName, exportName, fallback) {
|
|
|
40899
41208
|
};
|
|
40900
41209
|
}
|
|
40901
41210
|
function isOptionalPackageInstalled(packageName) {
|
|
41211
|
+
const resolved = resolveOptionalPackage(packageName);
|
|
41212
|
+
if (!resolved) return false;
|
|
40902
41213
|
try {
|
|
40903
|
-
|
|
40904
|
-
req(managedPackagePath(packageName));
|
|
41214
|
+
resolved.req(resolved.path);
|
|
40905
41215
|
return true;
|
|
40906
41216
|
} catch (err) {
|
|
40907
41217
|
console.error(`[optional-package] failed to load ${packageName}: ${err instanceof Error ? err.message : String(err)}`);
|