@elizaos/ui 2.0.0-alpha.382 → 2.0.0-alpha.385
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/apps/app-companion/src/components/avatar/VrmViewer.d.ts.map +1 -1
- package/apps/app-companion/src/components/avatar/VrmViewer.js +2 -1
- package/apps/app-companion/src/components/companion/CompanionAppView.d.ts.map +1 -1
- package/apps/app-companion/src/components/companion/CompanionAppView.js +2 -1
- package/apps/app-companion/src/components/companion/CompanionView.d.ts.map +1 -1
- package/apps/app-companion/src/components/companion/CompanionView.js +2 -1
- package/apps/app-companion/src/components/companion/EmotePicker.d.ts.map +1 -1
- package/apps/app-companion/src/components/companion/EmotePicker.js +1 -1
- package/apps/app-companion/src/components/companion/scene-overlay-bridge.d.ts.map +1 -1
- package/apps/app-companion/src/components/companion/scene-overlay-bridge.js +2 -1
- package/apps/app-companion/src/index.d.ts +3 -3
- package/apps/app-companion/src/index.d.ts.map +1 -1
- package/apps/app-companion/src/index.js +3 -3
- package/apps/app-elizamaker/src/drop-service.d.ts +2 -2
- package/apps/app-elizamaker/src/drop-service.d.ts.map +1 -1
- package/apps/app-elizamaker/src/twitter-verify.d.ts +2 -2
- package/apps/app-elizamaker/src/twitter-verify.d.ts.map +1 -1
- package/apps/app-lifeops/src/api/client-lifeops.d.ts +1 -1
- package/apps/app-lifeops/src/api/client-lifeops.d.ts.map +1 -1
- package/apps/app-lifeops/src/contracts/index.d.ts +1 -1
- package/apps/app-lifeops/src/contracts/index.d.ts.map +1 -1
- package/apps/app-lifeops/src/contracts/index.js +1 -1
- package/apps/app-lifeops/src/inbox/message-fetcher.d.ts.map +1 -1
- package/apps/app-lifeops/src/inbox/message-fetcher.js +4 -2
- package/apps/app-lifeops/src/lifeops/google-managed-client.d.ts.map +1 -1
- package/apps/app-lifeops/src/lifeops/google-managed-client.js +4 -3
- package/apps/app-lifeops/src/lifeops/paypal-managed-client.d.ts.map +1 -1
- package/apps/app-lifeops/src/lifeops/paypal-managed-client.js +4 -3
- package/apps/app-lifeops/src/lifeops/plaid-managed-client.d.ts.map +1 -1
- package/apps/app-lifeops/src/lifeops/plaid-managed-client.js +4 -3
- package/apps/app-lifeops/src/lifeops/repository.d.ts +12 -1
- package/apps/app-lifeops/src/lifeops/repository.d.ts.map +1 -1
- package/apps/app-lifeops/src/lifeops/repository.js +135 -0
- package/apps/app-lifeops/src/lifeops/schedule-sync-client.js +1 -1
- package/apps/app-lifeops/src/lifeops/schema.d.ts +4587 -3791
- package/apps/app-lifeops/src/lifeops/schema.d.ts.map +1 -1
- package/apps/app-lifeops/src/lifeops/schema.js +30 -0
- package/apps/app-lifeops/src/lifeops/service-mixin-inbox.d.ts +2 -0
- package/apps/app-lifeops/src/lifeops/service-mixin-inbox.d.ts.map +1 -1
- package/apps/app-lifeops/src/lifeops/service-mixin-inbox.js +103 -13
- package/apps/app-lifeops/src/routes/cloud-features-routes.d.ts.map +1 -1
- package/apps/app-lifeops/src/routes/cloud-features-routes.js +2 -1
- package/apps/app-lifeops/src/routes/travel-provider-relay-routes.d.ts.map +1 -1
- package/apps/app-lifeops/src/routes/travel-provider-relay-routes.js +2 -1
- package/package.json +1 -1
- package/packages/agent/src/actions/grounded-action-reply.d.ts.map +1 -1
- package/packages/agent/src/actions/grounded-action-reply.js +1 -1
- package/packages/agent/src/actions/index.d.ts +1 -0
- package/packages/agent/src/actions/index.d.ts.map +1 -1
- package/packages/agent/src/actions/index.js +1 -0
- package/packages/agent/src/actions/scratchpad.d.ts +7 -0
- package/packages/agent/src/actions/scratchpad.d.ts.map +1 -0
- package/packages/agent/src/actions/scratchpad.js +394 -0
- package/packages/agent/src/actions/settings-actions.js +1 -1
- package/packages/agent/src/actions/terminal.d.ts.map +1 -1
- package/packages/agent/src/actions/terminal.js +10 -2
- package/packages/agent/src/api/apps-routes.d.ts.map +1 -1
- package/packages/agent/src/api/apps-routes.js +171 -0
- package/packages/agent/src/api/binance-skill-helpers.d.ts.map +1 -1
- package/packages/agent/src/api/chat-routes.d.ts +3 -0
- package/packages/agent/src/api/chat-routes.d.ts.map +1 -1
- package/packages/agent/src/api/chat-routes.js +33 -14
- package/packages/agent/src/api/conversation-routes.js +2 -2
- package/packages/agent/src/api/misc-routes.d.ts.map +1 -1
- package/packages/agent/src/api/misc-routes.js +2 -2
- package/packages/agent/src/api/permissions-routes.js +1 -1
- package/packages/agent/src/api/plugin-routes.d.ts.map +1 -1
- package/packages/agent/src/api/plugin-routes.js +7 -1
- package/packages/agent/src/api/provider-switch-config.js +1 -1
- package/packages/agent/src/api/registry-service.d.ts +1 -1
- package/packages/agent/src/api/registry-service.d.ts.map +1 -1
- package/packages/agent/src/api/server-auth.d.ts.map +1 -1
- package/packages/agent/src/api/server-auth.js +119 -1
- package/packages/agent/src/api/server-helpers-auth.d.ts.map +1 -1
- package/packages/agent/src/api/server-helpers-auth.js +119 -1
- package/packages/agent/src/api/server-helpers-swarm.d.ts +1 -1
- package/packages/agent/src/api/server-helpers-swarm.d.ts.map +1 -1
- package/packages/agent/src/api/server-helpers.js +1 -1
- package/packages/agent/src/api/server-types.d.ts +2 -2
- package/packages/agent/src/api/server-types.d.ts.map +1 -1
- package/packages/agent/src/api/server.d.ts.map +1 -1
- package/packages/agent/src/api/server.js +5 -4
- package/packages/agent/src/api/training-backend-check.d.ts +1 -1
- package/packages/agent/src/api/training-backend-check.d.ts.map +1 -1
- package/packages/agent/src/api/training-backend-check.js +1 -1
- package/packages/agent/src/api/training-routes.d.ts +1 -1
- package/packages/agent/src/api/training-routes.d.ts.map +1 -1
- package/packages/agent/src/api/training-routes.js +1 -1
- package/packages/agent/src/api/training-service-like.d.ts +1 -1
- package/packages/agent/src/api/training-service-like.d.ts.map +1 -1
- package/packages/agent/src/api/trajectory-routes.d.ts +1 -1
- package/packages/agent/src/api/trajectory-routes.d.ts.map +1 -1
- package/packages/agent/src/api/trajectory-routes.js +1 -1
- package/packages/agent/src/api/wallet-capability.js +1 -1
- package/packages/agent/src/api/wallet-evm-balance.js +1 -1
- package/packages/agent/src/api/wallet.d.ts +1 -1
- package/packages/agent/src/api/wallet.d.ts.map +1 -1
- package/packages/agent/src/api/wallet.js +2 -2
- package/packages/agent/src/awareness/index.d.ts +2 -0
- package/packages/agent/src/awareness/index.d.ts.map +1 -0
- package/packages/agent/src/awareness/index.js +1 -0
- package/packages/agent/src/config/config.d.ts.map +1 -1
- package/packages/agent/src/config/config.js +2 -0
- package/packages/agent/src/config/index.d.ts +1 -0
- package/packages/agent/src/config/index.d.ts.map +1 -1
- package/packages/agent/src/config/index.js +1 -0
- package/packages/agent/src/config/model-metadata.d.ts +20 -0
- package/packages/agent/src/config/model-metadata.d.ts.map +1 -0
- package/packages/agent/src/config/model-metadata.js +133 -0
- package/packages/agent/src/config/zod-schema.core.d.ts +28 -28
- package/packages/agent/src/config/zod-schema.core.d.ts.map +1 -1
- package/packages/agent/src/config/zod-schema.core.js +16 -9
- package/packages/agent/src/config/zod-schema.d.ts +10 -10
- package/packages/agent/src/index.d.ts +6 -11
- package/packages/agent/src/index.d.ts.map +1 -1
- package/packages/agent/src/index.js +8 -10
- package/packages/agent/src/providers/media-provider.js +1 -1
- package/packages/agent/src/runtime/custom-actions.d.ts.map +1 -1
- package/packages/agent/src/runtime/custom-actions.js +1 -1
- package/packages/agent/src/runtime/eliza-plugin.d.ts.map +1 -1
- package/packages/agent/src/runtime/eliza-plugin.js +6 -0
- package/packages/agent/src/runtime/eliza.d.ts.map +1 -1
- package/packages/agent/src/runtime/eliza.js +7 -7
- package/packages/agent/src/runtime/prompt-optimization.d.ts +24 -1
- package/packages/agent/src/runtime/prompt-optimization.d.ts.map +1 -1
- package/packages/agent/src/runtime/prompt-optimization.js +292 -27
- package/packages/agent/src/runtime/trajectory-internals.d.ts +1 -0
- package/packages/agent/src/runtime/trajectory-internals.d.ts.map +1 -1
- package/packages/agent/src/runtime/trajectory-storage.d.ts.map +1 -1
- package/packages/agent/src/runtime/trajectory-storage.js +3 -0
- package/packages/agent/src/services/index.d.ts +4 -4
- package/packages/agent/src/services/index.d.ts.map +1 -1
- package/packages/agent/src/services/index.js +2 -2
- package/packages/agent/src/services/registry-client-app-meta.d.ts.map +1 -1
- package/packages/agent/src/services/registry-client-app-meta.js +0 -61
- package/packages/agent/src/services/skill-marketplace.d.ts.map +1 -1
- package/packages/app-core/src/App.js +1 -1
- package/packages/app-core/src/api/auth.js +1 -1
- package/packages/app-core/src/api/client-agent.d.ts +1 -2
- package/packages/app-core/src/api/client-agent.d.ts.map +1 -1
- package/packages/app-core/src/api/client-chat.d.ts +10 -1
- package/packages/app-core/src/api/client-chat.d.ts.map +1 -1
- package/packages/app-core/src/api/client-chat.js +33 -0
- package/packages/app-core/src/api/client-skills.d.ts.map +1 -1
- package/packages/app-core/src/api/client-types-chat.d.ts +1 -0
- package/packages/app-core/src/api/client-types-chat.d.ts.map +1 -1
- package/packages/app-core/src/api/client-types-config.d.ts +2 -2
- package/packages/app-core/src/api/client-types-config.d.ts.map +1 -1
- package/packages/app-core/src/api/client-wallet.d.ts +2 -4
- package/packages/app-core/src/api/client-wallet.d.ts.map +1 -1
- package/packages/app-core/src/api/client.d.ts +3 -4
- package/packages/app-core/src/api/client.d.ts.map +1 -1
- package/packages/app-core/src/api/client.js +1 -1
- package/packages/app-core/src/api/compat-route-shared.d.ts +1 -1
- package/packages/app-core/src/api/compat-route-shared.d.ts.map +1 -1
- package/packages/app-core/src/api/compat-route-shared.js +117 -1
- package/packages/app-core/src/api/server-cloud-tts.js +1 -1
- package/packages/app-core/src/api/trusted-local-request.d.ts +4 -0
- package/packages/app-core/src/api/trusted-local-request.d.ts.map +1 -0
- package/packages/app-core/src/api/trusted-local-request.js +176 -0
- package/packages/app-core/src/autonomy/index.d.ts.map +1 -1
- package/packages/app-core/src/autonomy/index.js +3 -1
- package/packages/app-core/src/components/auth/LoginView.d.ts +3 -23
- package/packages/app-core/src/components/auth/LoginView.d.ts.map +1 -1
- package/packages/app-core/src/components/auth/LoginView.js +43 -33
- package/packages/app-core/src/components/chat/AppsSection.d.ts.map +1 -1
- package/packages/app-core/src/components/chat/AppsSection.js +61 -6
- package/packages/app-core/src/components/chat/MessageContent.d.ts.map +1 -1
- package/packages/app-core/src/components/chat/MessageContent.js +26 -3
- package/packages/app-core/src/components/chat/message-choice-parser.d.ts +20 -0
- package/packages/app-core/src/components/chat/message-choice-parser.d.ts.map +1 -0
- package/packages/app-core/src/components/chat/message-choice-parser.js +53 -0
- package/packages/app-core/src/components/chat/widgets/ChoiceWidget.d.ts +24 -0
- package/packages/app-core/src/components/chat/widgets/ChoiceWidget.d.ts.map +1 -0
- package/packages/app-core/src/components/chat/widgets/ChoiceWidget.js +38 -0
- package/packages/app-core/src/components/connectors/ConnectorSetupPanel.js +1 -1
- package/packages/app-core/src/components/custom-actions/CustomActionEditor.d.ts.map +1 -1
- package/packages/app-core/src/components/custom-actions/CustomActionsPanel.d.ts.map +1 -1
- package/packages/app-core/src/components/custom-actions/CustomActionsView.d.ts.map +1 -1
- package/packages/app-core/src/components/custom-actions/custom-action-form.d.ts.map +1 -1
- package/packages/app-core/src/components/pages/BrowserWorkspaceView.js +1 -1
- package/packages/app-core/src/components/pages/KnowledgeView.d.ts.map +1 -1
- package/packages/app-core/src/components/pages/KnowledgeView.js +11 -1
- package/packages/app-core/src/components/pages/PluginConfigForm.d.ts.map +1 -1
- package/packages/app-core/src/components/pages/PluginConfigForm.js +1 -1
- package/packages/app-core/src/components/pages/ScratchpadView.d.ts +2 -0
- package/packages/app-core/src/components/pages/ScratchpadView.d.ts.map +1 -0
- package/packages/app-core/src/components/pages/ScratchpadView.js +364 -0
- package/packages/app-core/src/components/pages/SettingsView.d.ts.map +1 -1
- package/packages/app-core/src/components/pages/SettingsView.js +29 -5
- package/packages/app-core/src/components/pages/VectorBrowserView.d.ts.map +1 -1
- package/packages/app-core/src/components/pages/VectorBrowserView.js +1 -1
- package/packages/app-core/src/components/pages/config-page-sections.d.ts +1 -1
- package/packages/app-core/src/components/pages/config-page-sections.d.ts.map +1 -1
- package/packages/app-core/src/components/pages/config-page-sections.js +1 -1
- package/packages/app-core/src/components/pages/plugin-list-utils.d.ts +1 -1
- package/packages/app-core/src/components/pages/plugin-list-utils.d.ts.map +1 -1
- package/packages/app-core/src/components/pages/useBrowserWorkspaceWalletBridge.d.ts +1 -1
- package/packages/app-core/src/components/pages/useBrowserWorkspaceWalletBridge.d.ts.map +1 -1
- package/packages/app-core/src/components/pages/useBrowserWorkspaceWalletBridge.js +1 -1
- package/packages/app-core/src/components/settings/ApiKeyConfig.js +1 -1
- package/packages/app-core/src/components/settings/AppearanceSettingsSection.d.ts.map +1 -1
- package/packages/app-core/src/components/settings/AppearanceSettingsSection.js +1 -1
- package/packages/app-core/src/components/settings/AppsManagementSection.d.ts +12 -0
- package/packages/app-core/src/components/settings/AppsManagementSection.d.ts.map +1 -0
- package/packages/app-core/src/components/settings/AppsManagementSection.js +285 -0
- package/packages/app-core/src/components/settings/PermissionsSection.js +1 -1
- package/packages/app-core/src/components/settings/ProviderSwitcher.d.ts.map +1 -1
- package/packages/app-core/src/components/settings/ProviderSwitcher.js +2 -2
- package/packages/app-core/src/components/settings/SecuritySettingsSection.d.ts.map +1 -1
- package/packages/app-core/src/components/settings/SecuritySettingsSection.js +150 -33
- package/packages/app-core/src/components/settings/cloud-model-schema.d.ts +1 -1
- package/packages/app-core/src/components/settings/cloud-model-schema.d.ts.map +1 -1
- package/packages/app-core/src/components/shell/Header.d.ts.map +1 -1
- package/packages/app-core/src/components/shell/Header.js +28 -1
- package/packages/app-core/src/components/steward/injected.d.ts.map +1 -1
- package/packages/app-core/src/components/steward/injected.js +1 -1
- package/packages/app-core/src/components/training/injected.d.ts.map +1 -1
- package/packages/app-core/src/components/training/injected.js +1 -1
- package/packages/app-core/src/config/boot-config-store.d.ts +1 -1
- package/packages/app-core/src/config/boot-config-store.d.ts.map +1 -1
- package/packages/app-core/src/content-packs/bundled-packs.d.ts.map +1 -1
- package/packages/app-core/src/hooks/index.d.ts +0 -2
- package/packages/app-core/src/hooks/index.d.ts.map +1 -1
- package/packages/app-core/src/hooks/index.js +0 -2
- package/packages/app-core/src/hooks/useAuthStatus.d.ts +5 -0
- package/packages/app-core/src/hooks/useAuthStatus.d.ts.map +1 -1
- package/packages/app-core/src/hooks/useAuthStatus.js +41 -18
- package/packages/app-core/src/hooks/useSignalPairing.d.ts +1 -1
- package/packages/app-core/src/hooks/useSignalPairing.d.ts.map +1 -1
- package/packages/app-core/src/hooks/useWhatsAppPairing.d.ts +1 -1
- package/packages/app-core/src/hooks/useWhatsAppPairing.d.ts.map +1 -1
- package/packages/app-core/src/i18n/locales/en.json +0 -1
- package/packages/app-core/src/i18n/locales/es.json +0 -1
- package/packages/app-core/src/i18n/locales/ko.json +0 -1
- package/packages/app-core/src/i18n/locales/pt.json +0 -1
- package/packages/app-core/src/i18n/locales/tl.json +0 -1
- package/packages/app-core/src/i18n/locales/vi.json +0 -1
- package/packages/app-core/src/i18n/locales/zh-CN.json +0 -1
- package/packages/app-core/src/index.d.ts +0 -1
- package/packages/app-core/src/index.d.ts.map +1 -1
- package/packages/app-core/src/index.js +0 -1
- package/packages/app-core/src/runtime/channel-plugin-map.d.ts.map +1 -1
- package/packages/app-core/src/runtime/channel-plugin-map.js +1 -1
- package/packages/app-core/src/runtime/plugin-manager-guard.d.ts.map +1 -1
- package/packages/app-core/src/runtime/plugin-manager-guard.js +1 -1
- package/packages/app-core/src/services/plugin-installer.d.ts.map +1 -1
- package/packages/app-core/src/services/plugin-installer.js +1 -8
- package/packages/app-core/src/state/index.d.ts +0 -1
- package/packages/app-core/src/state/index.d.ts.map +1 -1
- package/packages/app-core/src/state/index.js +0 -1
- package/packages/app-core/src/state/startup-phase-restore.d.ts.map +1 -1
- package/packages/app-core/src/state/startup-phase-restore.js +1 -1
- package/packages/app-core/src/state/useOnboardingState.js +2 -2
- package/packages/app-core/src/state/usePluginsSkillsState.d.ts +4 -4
- package/packages/app-core/src/types/index.d.ts +1 -1
- package/packages/app-core/src/types/index.d.ts.map +1 -1
- package/packages/shared/src/contracts/index.d.ts +1 -0
- package/packages/shared/src/contracts/index.d.ts.map +1 -1
- package/packages/shared/src/contracts/index.js +1 -0
- package/packages/shared/src/contracts/scratchpad.d.ts +136 -0
- package/packages/shared/src/contracts/scratchpad.d.ts.map +1 -0
- package/packages/shared/src/contracts/scratchpad.js +90 -0
- package/packages/shared/src/index.d.ts +13 -13
- package/packages/shared/src/index.d.ts.map +1 -1
- package/packages/shared/src/index.js +19 -19
- package/packages/shared/src/spoken-text.js +1 -1
- package/packages/typescript/src/features/advanced-capabilities/evaluators/factExtractor.d.ts.map +1 -1
- package/packages/typescript/src/features/advanced-capabilities/evaluators/factExtractor.js +12 -6
- package/packages/typescript/src/generated/action-docs.d.ts +25 -0
- package/packages/typescript/src/generated/action-docs.d.ts.map +1 -1
- package/packages/typescript/src/generated/action-docs.js +51 -0
- package/packages/typescript/src/services/message.d.ts.map +1 -1
- package/packages/typescript/src/services/message.js +1 -3
- package/packages/typescript/src/types/tools.d.ts.map +1 -1
- package/packages/typescript/src/types/tools.js +7 -3
- package/apps/app-lifeops/src/action.d.ts +0 -3
- package/apps/app-lifeops/src/action.d.ts.map +0 -1
- package/apps/app-lifeops/src/action.js +0 -351
- package/apps/app-lifeops/src/actions/activity-report.d.ts +0 -13
- package/apps/app-lifeops/src/actions/activity-report.d.ts.map +0 -1
- package/apps/app-lifeops/src/actions/activity-report.js +0 -313
- package/apps/app-lifeops/src/actions/app-blocker.d.ts +0 -7
- package/apps/app-lifeops/src/actions/app-blocker.d.ts.map +0 -1
- package/apps/app-lifeops/src/actions/app-blocker.js +0 -454
- package/apps/app-lifeops/src/actions/approval.d.ts +0 -21
- package/apps/app-lifeops/src/actions/approval.d.ts.map +0 -1
- package/apps/app-lifeops/src/actions/approval.js +0 -342
- package/apps/app-lifeops/src/actions/autofill.d.ts +0 -35
- package/apps/app-lifeops/src/actions/autofill.d.ts.map +0 -1
- package/apps/app-lifeops/src/actions/autofill.js +0 -475
- package/apps/app-lifeops/src/actions/book-travel-executor.d.ts +0 -9
- package/apps/app-lifeops/src/actions/book-travel-executor.d.ts.map +0 -1
- package/apps/app-lifeops/src/actions/book-travel-executor.js +0 -65
- package/apps/app-lifeops/src/actions/book-travel.d.ts +0 -5
- package/apps/app-lifeops/src/actions/book-travel.d.ts.map +0 -1
- package/apps/app-lifeops/src/actions/book-travel.js +0 -491
- package/apps/app-lifeops/src/actions/calendar.d.ts +0 -19
- package/apps/app-lifeops/src/actions/calendar.d.ts.map +0 -1
- package/apps/app-lifeops/src/actions/calendar.js +0 -3189
- package/apps/app-lifeops/src/actions/calendly.d.ts +0 -3
- package/apps/app-lifeops/src/actions/calendly.d.ts.map +0 -1
- package/apps/app-lifeops/src/actions/calendly.js +0 -285
- package/apps/app-lifeops/src/actions/chat-thread-control.d.ts +0 -3
- package/apps/app-lifeops/src/actions/chat-thread-control.d.ts.map +0 -1
- package/apps/app-lifeops/src/actions/chat-thread-control.js +0 -260
- package/apps/app-lifeops/src/actions/checkin.d.ts +0 -8
- package/apps/app-lifeops/src/actions/checkin.d.ts.map +0 -1
- package/apps/app-lifeops/src/actions/checkin.js +0 -230
- package/apps/app-lifeops/src/actions/computer-use.d.ts +0 -14
- package/apps/app-lifeops/src/actions/computer-use.d.ts.map +0 -1
- package/apps/app-lifeops/src/actions/computer-use.js +0 -365
- package/apps/app-lifeops/src/actions/cross-channel-send.d.ts +0 -34
- package/apps/app-lifeops/src/actions/cross-channel-send.d.ts.map +0 -1
- package/apps/app-lifeops/src/actions/cross-channel-send.js +0 -964
- package/apps/app-lifeops/src/actions/device-bus.d.ts +0 -19
- package/apps/app-lifeops/src/actions/device-bus.d.ts.map +0 -1
- package/apps/app-lifeops/src/actions/device-bus.js +0 -386
- package/apps/app-lifeops/src/actions/dossier.d.ts +0 -5
- package/apps/app-lifeops/src/actions/dossier.d.ts.map +0 -1
- package/apps/app-lifeops/src/actions/dossier.js +0 -227
- package/apps/app-lifeops/src/actions/email-unsubscribe.d.ts +0 -5
- package/apps/app-lifeops/src/actions/email-unsubscribe.d.ts.map +0 -1
- package/apps/app-lifeops/src/actions/email-unsubscribe.js +0 -172
- package/apps/app-lifeops/src/actions/gmail.d.ts +0 -57
- package/apps/app-lifeops/src/actions/gmail.d.ts.map +0 -1
- package/apps/app-lifeops/src/actions/gmail.js +0 -2540
- package/apps/app-lifeops/src/actions/health.d.ts +0 -9
- package/apps/app-lifeops/src/actions/health.d.ts.map +0 -1
- package/apps/app-lifeops/src/actions/health.js +0 -398
- package/apps/app-lifeops/src/actions/inbox.d.ts +0 -5
- package/apps/app-lifeops/src/actions/inbox.d.ts.map +0 -1
- package/apps/app-lifeops/src/actions/inbox.js +0 -1244
- package/apps/app-lifeops/src/actions/intent-sync.d.ts +0 -5
- package/apps/app-lifeops/src/actions/intent-sync.d.ts.map +0 -1
- package/apps/app-lifeops/src/actions/intent-sync.js +0 -326
- package/apps/app-lifeops/src/actions/life-goal-extractor.d.ts +0 -69
- package/apps/app-lifeops/src/actions/life-goal-extractor.d.ts.map +0 -1
- package/apps/app-lifeops/src/actions/life-goal-extractor.js +0 -420
- package/apps/app-lifeops/src/actions/life-param-extractor.d.ts +0 -78
- package/apps/app-lifeops/src/actions/life-param-extractor.d.ts.map +0 -1
- package/apps/app-lifeops/src/actions/life-param-extractor.js +0 -431
- package/apps/app-lifeops/src/actions/life-recent-context.d.ts +0 -9
- package/apps/app-lifeops/src/actions/life-recent-context.d.ts.map +0 -1
- package/apps/app-lifeops/src/actions/life-recent-context.js +0 -78
- package/apps/app-lifeops/src/actions/life-update-extractor.d.ts +0 -27
- package/apps/app-lifeops/src/actions/life-update-extractor.d.ts.map +0 -1
- package/apps/app-lifeops/src/actions/life-update-extractor.js +0 -195
- package/apps/app-lifeops/src/actions/life.d.ts +0 -5
- package/apps/app-lifeops/src/actions/life.d.ts.map +0 -1
- package/apps/app-lifeops/src/actions/life.extractor.d.ts +0 -18
- package/apps/app-lifeops/src/actions/life.extractor.d.ts.map +0 -1
- package/apps/app-lifeops/src/actions/life.extractor.js +0 -363
- package/apps/app-lifeops/src/actions/life.js +0 -3247
- package/apps/app-lifeops/src/actions/lifeops-connector.d.ts +0 -5
- package/apps/app-lifeops/src/actions/lifeops-connector.d.ts.map +0 -1
- package/apps/app-lifeops/src/actions/lifeops-connector.js +0 -683
- package/apps/app-lifeops/src/actions/lifeops-extraction-config.d.ts +0 -16
- package/apps/app-lifeops/src/actions/lifeops-extraction-config.d.ts.map +0 -1
- package/apps/app-lifeops/src/actions/lifeops-extraction-config.js +0 -25
- package/apps/app-lifeops/src/actions/lifeops-google-helpers.d.ts +0 -64
- package/apps/app-lifeops/src/actions/lifeops-google-helpers.d.ts.map +0 -1
- package/apps/app-lifeops/src/actions/lifeops-google-helpers.js +0 -671
- package/apps/app-lifeops/src/actions/lifeops-mutate.d.ts +0 -5
- package/apps/app-lifeops/src/actions/lifeops-mutate.d.ts.map +0 -1
- package/apps/app-lifeops/src/actions/lifeops-mutate.js +0 -769
- package/apps/app-lifeops/src/actions/list-remote-sessions.d.ts +0 -6
- package/apps/app-lifeops/src/actions/list-remote-sessions.d.ts.map +0 -1
- package/apps/app-lifeops/src/actions/list-remote-sessions.js +0 -45
- package/apps/app-lifeops/src/actions/non-actionable-request.d.ts +0 -17
- package/apps/app-lifeops/src/actions/non-actionable-request.d.ts.map +0 -1
- package/apps/app-lifeops/src/actions/non-actionable-request.js +0 -25
- package/apps/app-lifeops/src/actions/owner-app-block.d.ts +0 -12
- package/apps/app-lifeops/src/actions/owner-app-block.d.ts.map +0 -1
- package/apps/app-lifeops/src/actions/owner-app-block.js +0 -144
- package/apps/app-lifeops/src/actions/owner-calendar.d.ts +0 -15
- package/apps/app-lifeops/src/actions/owner-calendar.d.ts.map +0 -1
- package/apps/app-lifeops/src/actions/owner-calendar.js +0 -762
- package/apps/app-lifeops/src/actions/owner-inbox.d.ts +0 -5
- package/apps/app-lifeops/src/actions/owner-inbox.d.ts.map +0 -1
- package/apps/app-lifeops/src/actions/owner-inbox.js +0 -662
- package/apps/app-lifeops/src/actions/owner-remote-desktop.d.ts +0 -12
- package/apps/app-lifeops/src/actions/owner-remote-desktop.d.ts.map +0 -1
- package/apps/app-lifeops/src/actions/owner-remote-desktop.js +0 -173
- package/apps/app-lifeops/src/actions/owner-schedule.d.ts +0 -3
- package/apps/app-lifeops/src/actions/owner-schedule.d.ts.map +0 -1
- package/apps/app-lifeops/src/actions/owner-schedule.js +0 -174
- package/apps/app-lifeops/src/actions/owner-screen-time.d.ts +0 -10
- package/apps/app-lifeops/src/actions/owner-screen-time.d.ts.map +0 -1
- package/apps/app-lifeops/src/actions/owner-screen-time.js +0 -213
- package/apps/app-lifeops/src/actions/owner-website-block.d.ts +0 -12
- package/apps/app-lifeops/src/actions/owner-website-block.d.ts.map +0 -1
- package/apps/app-lifeops/src/actions/owner-website-block.js +0 -424
- package/apps/app-lifeops/src/actions/password-manager.d.ts +0 -5
- package/apps/app-lifeops/src/actions/password-manager.d.ts.map +0 -1
- package/apps/app-lifeops/src/actions/password-manager.js +0 -217
- package/apps/app-lifeops/src/actions/payments.d.ts +0 -5
- package/apps/app-lifeops/src/actions/payments.d.ts.map +0 -1
- package/apps/app-lifeops/src/actions/payments.js +0 -236
- package/apps/app-lifeops/src/actions/relationships.d.ts +0 -12
- package/apps/app-lifeops/src/actions/relationships.d.ts.map +0 -1
- package/apps/app-lifeops/src/actions/relationships.js +0 -880
- package/apps/app-lifeops/src/actions/remote-desktop.d.ts +0 -5
- package/apps/app-lifeops/src/actions/remote-desktop.d.ts.map +0 -1
- package/apps/app-lifeops/src/actions/remote-desktop.js +0 -248
- package/apps/app-lifeops/src/actions/revoke-remote-session.d.ts +0 -6
- package/apps/app-lifeops/src/actions/revoke-remote-session.d.ts.map +0 -1
- package/apps/app-lifeops/src/actions/revoke-remote-session.js +0 -73
- package/apps/app-lifeops/src/actions/schedule-x-dm-reply.d.ts +0 -3
- package/apps/app-lifeops/src/actions/schedule-x-dm-reply.d.ts.map +0 -1
- package/apps/app-lifeops/src/actions/schedule-x-dm-reply.js +0 -134
- package/apps/app-lifeops/src/actions/scheduled-trigger-task.d.ts +0 -19
- package/apps/app-lifeops/src/actions/scheduled-trigger-task.d.ts.map +0 -1
- package/apps/app-lifeops/src/actions/scheduled-trigger-task.js +0 -82
- package/apps/app-lifeops/src/actions/scheduling.d.ts +0 -70
- package/apps/app-lifeops/src/actions/scheduling.d.ts.map +0 -1
- package/apps/app-lifeops/src/actions/scheduling.js +0 -1078
- package/apps/app-lifeops/src/actions/screen-time.d.ts +0 -8
- package/apps/app-lifeops/src/actions/screen-time.d.ts.map +0 -1
- package/apps/app-lifeops/src/actions/screen-time.js +0 -249
- package/apps/app-lifeops/src/actions/search-across-channels.d.ts +0 -13
- package/apps/app-lifeops/src/actions/search-across-channels.d.ts.map +0 -1
- package/apps/app-lifeops/src/actions/search-across-channels.js +0 -338
- package/apps/app-lifeops/src/actions/start-remote-session.d.ts +0 -14
- package/apps/app-lifeops/src/actions/start-remote-session.d.ts.map +0 -1
- package/apps/app-lifeops/src/actions/start-remote-session.js +0 -139
- package/apps/app-lifeops/src/actions/subscriptions.d.ts +0 -5
- package/apps/app-lifeops/src/actions/subscriptions.d.ts.map +0 -1
- package/apps/app-lifeops/src/actions/subscriptions.js +0 -404
- package/apps/app-lifeops/src/actions/timezone-normalization.d.ts +0 -4
- package/apps/app-lifeops/src/actions/timezone-normalization.d.ts.map +0 -1
- package/apps/app-lifeops/src/actions/timezone-normalization.js +0 -159
- package/apps/app-lifeops/src/actions/twilio-call.d.ts +0 -20
- package/apps/app-lifeops/src/actions/twilio-call.d.ts.map +0 -1
- package/apps/app-lifeops/src/actions/twilio-call.js +0 -853
- package/apps/app-lifeops/src/actions/update-owner-profile.d.ts +0 -5
- package/apps/app-lifeops/src/actions/update-owner-profile.d.ts.map +0 -1
- package/apps/app-lifeops/src/actions/update-owner-profile.js +0 -181
- package/apps/app-lifeops/src/actions/x-read.d.ts +0 -5
- package/apps/app-lifeops/src/actions/x-read.d.ts.map +0 -1
- package/apps/app-lifeops/src/actions/x-read.js +0 -561
- package/apps/app-lifeops/src/activity-profile/activity-tracker-service.d.ts +0 -36
- package/apps/app-lifeops/src/activity-profile/activity-tracker-service.d.ts.map +0 -1
- package/apps/app-lifeops/src/activity-profile/activity-tracker-service.js +0 -160
- package/apps/app-lifeops/src/activity-profile/analyzer.d.ts +0 -23
- package/apps/app-lifeops/src/activity-profile/analyzer.d.ts.map +0 -1
- package/apps/app-lifeops/src/activity-profile/analyzer.js +0 -555
- package/apps/app-lifeops/src/activity-profile/presence-signal-bridge-service.d.ts +0 -14
- package/apps/app-lifeops/src/activity-profile/presence-signal-bridge-service.d.ts.map +0 -1
- package/apps/app-lifeops/src/activity-profile/presence-signal-bridge-service.js +0 -133
- package/apps/app-lifeops/src/activity-profile/proactive-planner.d.ts +0 -71
- package/apps/app-lifeops/src/activity-profile/proactive-planner.d.ts.map +0 -1
- package/apps/app-lifeops/src/activity-profile/proactive-planner.js +0 -567
- package/apps/app-lifeops/src/activity-profile/proactive-worker.d.ts +0 -32
- package/apps/app-lifeops/src/activity-profile/proactive-worker.d.ts.map +0 -1
- package/apps/app-lifeops/src/activity-profile/proactive-worker.js +0 -676
- package/apps/app-lifeops/src/activity-profile/service.d.ts +0 -11
- package/apps/app-lifeops/src/activity-profile/service.d.ts.map +0 -1
- package/apps/app-lifeops/src/activity-profile/service.js +0 -246
- package/apps/app-lifeops/src/app-blocker/access.d.ts +0 -8
- package/apps/app-lifeops/src/app-blocker/access.d.ts.map +0 -1
- package/apps/app-lifeops/src/app-blocker/access.js +0 -35
- package/apps/app-lifeops/src/app-blocker/engine.d.ts +0 -10
- package/apps/app-lifeops/src/app-blocker/engine.d.ts.map +0 -1
- package/apps/app-lifeops/src/app-blocker/engine.js +0 -43
- package/apps/app-lifeops/src/components/AppBlockerSettingsCard.d.ts +0 -3
- package/apps/app-lifeops/src/components/AppBlockerSettingsCard.d.ts.map +0 -1
- package/apps/app-lifeops/src/components/AppBlockerSettingsCard.js +0 -189
- package/apps/app-lifeops/src/components/BrowserBridgeSetupPanel.d.ts +0 -2
- package/apps/app-lifeops/src/components/BrowserBridgeSetupPanel.d.ts.map +0 -1
- package/apps/app-lifeops/src/components/BrowserBridgeSetupPanel.js +0 -1065
- package/apps/app-lifeops/src/components/BrowserBridgeStatusChip.d.ts +0 -7
- package/apps/app-lifeops/src/components/BrowserBridgeStatusChip.d.ts.map +0 -1
- package/apps/app-lifeops/src/components/BrowserBridgeStatusChip.js +0 -74
- package/apps/app-lifeops/src/components/DataSourcesStrip.d.ts +0 -14
- package/apps/app-lifeops/src/components/DataSourcesStrip.d.ts.map +0 -1
- package/apps/app-lifeops/src/components/DataSourcesStrip.js +0 -36
- package/apps/app-lifeops/src/components/EventEditorDrawer.d.ts +0 -23
- package/apps/app-lifeops/src/components/EventEditorDrawer.d.ts.map +0 -1
- package/apps/app-lifeops/src/components/EventEditorDrawer.js +0 -514
- package/apps/app-lifeops/src/components/LifeOpsActivitySignalsEffect.d.ts +0 -2
- package/apps/app-lifeops/src/components/LifeOpsActivitySignalsEffect.d.ts.map +0 -1
- package/apps/app-lifeops/src/components/LifeOpsActivitySignalsEffect.js +0 -10
- package/apps/app-lifeops/src/components/LifeOpsCalendarSection.d.ts +0 -15
- package/apps/app-lifeops/src/components/LifeOpsCalendarSection.d.ts.map +0 -1
- package/apps/app-lifeops/src/components/LifeOpsCalendarSection.js +0 -515
- package/apps/app-lifeops/src/components/LifeOpsChatAdapter.d.ts +0 -34
- package/apps/app-lifeops/src/components/LifeOpsChatAdapter.d.ts.map +0 -1
- package/apps/app-lifeops/src/components/LifeOpsChatAdapter.js +0 -175
- package/apps/app-lifeops/src/components/LifeOpsFeatureTogglesSection.d.ts +0 -2
- package/apps/app-lifeops/src/components/LifeOpsFeatureTogglesSection.d.ts.map +0 -1
- package/apps/app-lifeops/src/components/LifeOpsFeatureTogglesSection.js +0 -99
- package/apps/app-lifeops/src/components/LifeOpsHabitVisuals.d.ts +0 -37
- package/apps/app-lifeops/src/components/LifeOpsHabitVisuals.d.ts.map +0 -1
- package/apps/app-lifeops/src/components/LifeOpsHabitVisuals.js +0 -88
- package/apps/app-lifeops/src/components/LifeOpsInboxSection.d.ts +0 -13
- package/apps/app-lifeops/src/components/LifeOpsInboxSection.d.ts.map +0 -1
- package/apps/app-lifeops/src/components/LifeOpsInboxSection.js +0 -490
- package/apps/app-lifeops/src/components/LifeOpsLinkBankButton.d.ts +0 -12
- package/apps/app-lifeops/src/components/LifeOpsLinkBankButton.d.ts.map +0 -1
- package/apps/app-lifeops/src/components/LifeOpsLinkBankButton.js +0 -92
- package/apps/app-lifeops/src/components/LifeOpsLinkPaypalButton.d.ts +0 -12
- package/apps/app-lifeops/src/components/LifeOpsLinkPaypalButton.d.ts.map +0 -1
- package/apps/app-lifeops/src/components/LifeOpsLinkPaypalButton.js +0 -160
- package/apps/app-lifeops/src/components/LifeOpsMoneySection.d.ts +0 -3
- package/apps/app-lifeops/src/components/LifeOpsMoneySection.d.ts.map +0 -1
- package/apps/app-lifeops/src/components/LifeOpsMoneySection.js +0 -373
- package/apps/app-lifeops/src/components/LifeOpsNavRail.d.ts +0 -9
- package/apps/app-lifeops/src/components/LifeOpsNavRail.d.ts.map +0 -1
- package/apps/app-lifeops/src/components/LifeOpsNavRail.js +0 -93
- package/apps/app-lifeops/src/components/LifeOpsOperationalPanels.d.ts +0 -4
- package/apps/app-lifeops/src/components/LifeOpsOperationalPanels.d.ts.map +0 -1
- package/apps/app-lifeops/src/components/LifeOpsOperationalPanels.js +0 -274
- package/apps/app-lifeops/src/components/LifeOpsOverviewSection.d.ts +0 -7
- package/apps/app-lifeops/src/components/LifeOpsOverviewSection.d.ts.map +0 -1
- package/apps/app-lifeops/src/components/LifeOpsOverviewSection.js +0 -670
- package/apps/app-lifeops/src/components/LifeOpsPageSections.d.ts +0 -42
- package/apps/app-lifeops/src/components/LifeOpsPageSections.d.ts.map +0 -1
- package/apps/app-lifeops/src/components/LifeOpsPageSections.js +0 -166
- package/apps/app-lifeops/src/components/LifeOpsPageView.d.ts +0 -2
- package/apps/app-lifeops/src/components/LifeOpsPageView.d.ts.map +0 -1
- package/apps/app-lifeops/src/components/LifeOpsPageView.js +0 -565
- package/apps/app-lifeops/src/components/LifeOpsRemindersSection.d.ts +0 -2
- package/apps/app-lifeops/src/components/LifeOpsRemindersSection.d.ts.map +0 -1
- package/apps/app-lifeops/src/components/LifeOpsRemindersSection.js +0 -749
- package/apps/app-lifeops/src/components/LifeOpsResizableSidebar.d.ts +0 -27
- package/apps/app-lifeops/src/components/LifeOpsResizableSidebar.d.ts.map +0 -1
- package/apps/app-lifeops/src/components/LifeOpsResizableSidebar.js +0 -106
- package/apps/app-lifeops/src/components/LifeOpsScreenTimeSection.d.ts +0 -2
- package/apps/app-lifeops/src/components/LifeOpsScreenTimeSection.d.ts.map +0 -1
- package/apps/app-lifeops/src/components/LifeOpsScreenTimeSection.js +0 -373
- package/apps/app-lifeops/src/components/LifeOpsSectionContent.d.ts +0 -10
- package/apps/app-lifeops/src/components/LifeOpsSectionContent.d.ts.map +0 -1
- package/apps/app-lifeops/src/components/LifeOpsSectionContent.js +0 -30
- package/apps/app-lifeops/src/components/LifeOpsSelectionContext.d.ts +0 -21
- package/apps/app-lifeops/src/components/LifeOpsSelectionContext.d.ts.map +0 -1
- package/apps/app-lifeops/src/components/LifeOpsSelectionContext.js +0 -30
- package/apps/app-lifeops/src/components/LifeOpsSettingsSection.d.ts +0 -20
- package/apps/app-lifeops/src/components/LifeOpsSettingsSection.d.ts.map +0 -1
- package/apps/app-lifeops/src/components/LifeOpsSettingsSection.js +0 -597
- package/apps/app-lifeops/src/components/LifeOpsSetupGate.d.ts +0 -13
- package/apps/app-lifeops/src/components/LifeOpsSetupGate.d.ts.map +0 -1
- package/apps/app-lifeops/src/components/LifeOpsSetupGate.js +0 -134
- package/apps/app-lifeops/src/components/LifeOpsSleepSection.d.ts +0 -10
- package/apps/app-lifeops/src/components/LifeOpsSleepSection.d.ts.map +0 -1
- package/apps/app-lifeops/src/components/LifeOpsSleepSection.js +0 -425
- package/apps/app-lifeops/src/components/LifeOpsWorkspaceShell.d.ts +0 -11
- package/apps/app-lifeops/src/components/LifeOpsWorkspaceShell.d.ts.map +0 -1
- package/apps/app-lifeops/src/components/LifeOpsWorkspaceShell.js +0 -49
- package/apps/app-lifeops/src/components/LifeOpsWorkspaceView.d.ts +0 -2
- package/apps/app-lifeops/src/components/LifeOpsWorkspaceView.d.ts.map +0 -1
- package/apps/app-lifeops/src/components/LifeOpsWorkspaceView.js +0 -1041
- package/apps/app-lifeops/src/components/MessagingConnectorCards.d.ts +0 -7
- package/apps/app-lifeops/src/components/MessagingConnectorCards.d.ts.map +0 -1
- package/apps/app-lifeops/src/components/MessagingConnectorCards.js +0 -643
- package/apps/app-lifeops/src/components/MissingSourceCard.d.ts +0 -9
- package/apps/app-lifeops/src/components/MissingSourceCard.d.ts.map +0 -1
- package/apps/app-lifeops/src/components/MissingSourceCard.js +0 -5
- package/apps/app-lifeops/src/components/MobileSignalsSetupCard.d.ts +0 -2
- package/apps/app-lifeops/src/components/MobileSignalsSetupCard.d.ts.map +0 -1
- package/apps/app-lifeops/src/components/MobileSignalsSetupCard.js +0 -162
- package/apps/app-lifeops/src/components/SleepInspectionPanel.d.ts +0 -8
- package/apps/app-lifeops/src/components/SleepInspectionPanel.d.ts.map +0 -1
- package/apps/app-lifeops/src/components/SleepInspectionPanel.js +0 -59
- package/apps/app-lifeops/src/components/WebsiteBlockerSettingsCard.d.ts +0 -3
- package/apps/app-lifeops/src/components/WebsiteBlockerSettingsCard.d.ts.map +0 -1
- package/apps/app-lifeops/src/components/WebsiteBlockerSettingsCard.js +0 -75
- package/apps/app-lifeops/src/components/WhatsAppQrOverlay.d.ts +0 -8
- package/apps/app-lifeops/src/components/WhatsAppQrOverlay.d.ts.map +0 -1
- package/apps/app-lifeops/src/components/WhatsAppQrOverlay.js +0 -48
- package/apps/app-lifeops/src/components/lifeops-labels.d.ts +0 -2
- package/apps/app-lifeops/src/components/lifeops-labels.d.ts.map +0 -1
- package/apps/app-lifeops/src/components/lifeops-labels.js +0 -5
- package/apps/app-lifeops/src/events/index.d.ts +0 -34
- package/apps/app-lifeops/src/events/index.d.ts.map +0 -1
- package/apps/app-lifeops/src/events/index.js +0 -23
- package/apps/app-lifeops/src/followup/actions/listOverdueFollowups.d.ts +0 -3
- package/apps/app-lifeops/src/followup/actions/listOverdueFollowups.d.ts.map +0 -1
- package/apps/app-lifeops/src/followup/actions/listOverdueFollowups.js +0 -48
- package/apps/app-lifeops/src/followup/actions/markFollowupDone.d.ts +0 -3
- package/apps/app-lifeops/src/followup/actions/markFollowupDone.d.ts.map +0 -1
- package/apps/app-lifeops/src/followup/actions/markFollowupDone.js +0 -173
- package/apps/app-lifeops/src/followup/actions/setFollowupThreshold.d.ts +0 -3
- package/apps/app-lifeops/src/followup/actions/setFollowupThreshold.d.ts.map +0 -1
- package/apps/app-lifeops/src/followup/actions/setFollowupThreshold.js +0 -172
- package/apps/app-lifeops/src/followup/followup-tracker.d.ts +0 -82
- package/apps/app-lifeops/src/followup/followup-tracker.d.ts.map +0 -1
- package/apps/app-lifeops/src/followup/followup-tracker.js +0 -279
- package/apps/app-lifeops/src/followup/index.d.ts +0 -5
- package/apps/app-lifeops/src/followup/index.d.ts.map +0 -1
- package/apps/app-lifeops/src/followup/index.js +0 -4
- package/apps/app-lifeops/src/hooks/useCalendarWeek.d.ts +0 -28
- package/apps/app-lifeops/src/hooks/useCalendarWeek.d.ts.map +0 -1
- package/apps/app-lifeops/src/hooks/useCalendarWeek.js +0 -93
- package/apps/app-lifeops/src/hooks/useDiscordConnector.d.ts +0 -14
- package/apps/app-lifeops/src/hooks/useDiscordConnector.d.ts.map +0 -1
- package/apps/app-lifeops/src/hooks/useDiscordConnector.js +0 -126
- package/apps/app-lifeops/src/hooks/useGoogleLifeOpsConnector.d.ts +0 -29
- package/apps/app-lifeops/src/hooks/useGoogleLifeOpsConnector.d.ts.map +0 -1
- package/apps/app-lifeops/src/hooks/useGoogleLifeOpsConnector.js +0 -481
- package/apps/app-lifeops/src/hooks/useIMessageConnector.d.ts +0 -10
- package/apps/app-lifeops/src/hooks/useIMessageConnector.d.ts.map +0 -1
- package/apps/app-lifeops/src/hooks/useIMessageConnector.js +0 -50
- package/apps/app-lifeops/src/hooks/useInbox.d.ts +0 -34
- package/apps/app-lifeops/src/hooks/useInbox.d.ts.map +0 -1
- package/apps/app-lifeops/src/hooks/useInbox.js +0 -98
- package/apps/app-lifeops/src/hooks/useLifeOpsActivitySignals.d.ts +0 -2
- package/apps/app-lifeops/src/hooks/useLifeOpsActivitySignals.d.ts.map +0 -1
- package/apps/app-lifeops/src/hooks/useLifeOpsActivitySignals.js +0 -382
- package/apps/app-lifeops/src/hooks/useLifeOpsAppState.d.ts +0 -21
- package/apps/app-lifeops/src/hooks/useLifeOpsAppState.d.ts.map +0 -1
- package/apps/app-lifeops/src/hooks/useLifeOpsAppState.js +0 -83
- package/apps/app-lifeops/src/hooks/useLifeOpsCapabilitiesStatus.d.ts +0 -8
- package/apps/app-lifeops/src/hooks/useLifeOpsCapabilitiesStatus.d.ts.map +0 -1
- package/apps/app-lifeops/src/hooks/useLifeOpsCapabilitiesStatus.js +0 -60
- package/apps/app-lifeops/src/hooks/useLifeOpsScheduleInspection.d.ts +0 -18
- package/apps/app-lifeops/src/hooks/useLifeOpsScheduleInspection.d.ts.map +0 -1
- package/apps/app-lifeops/src/hooks/useLifeOpsScheduleInspection.js +0 -66
- package/apps/app-lifeops/src/hooks/useLifeOpsScheduleState.d.ts +0 -14
- package/apps/app-lifeops/src/hooks/useLifeOpsScheduleState.d.ts.map +0 -1
- package/apps/app-lifeops/src/hooks/useLifeOpsScheduleState.js +0 -79
- package/apps/app-lifeops/src/hooks/useLifeOpsSection.d.ts +0 -18
- package/apps/app-lifeops/src/hooks/useLifeOpsSection.d.ts.map +0 -1
- package/apps/app-lifeops/src/hooks/useLifeOpsSection.js +0 -78
- package/apps/app-lifeops/src/hooks/useLifeOpsXConnector.d.ts +0 -14
- package/apps/app-lifeops/src/hooks/useLifeOpsXConnector.d.ts.map +0 -1
- package/apps/app-lifeops/src/hooks/useLifeOpsXConnector.js +0 -160
- package/apps/app-lifeops/src/hooks/useSignalConnector.d.ts +0 -16
- package/apps/app-lifeops/src/hooks/useSignalConnector.d.ts.map +0 -1
- package/apps/app-lifeops/src/hooks/useSignalConnector.js +0 -198
- package/apps/app-lifeops/src/hooks/useTelegramConnector.d.ts +0 -21
- package/apps/app-lifeops/src/hooks/useTelegramConnector.d.ts.map +0 -1
- package/apps/app-lifeops/src/hooks/useTelegramConnector.js +0 -177
- package/apps/app-lifeops/src/hooks/useWhatsAppConnector.d.ts +0 -8
- package/apps/app-lifeops/src/hooks/useWhatsAppConnector.d.ts.map +0 -1
- package/apps/app-lifeops/src/hooks/useWhatsAppConnector.js +0 -58
- package/apps/app-lifeops/src/hooks/useWhatsAppPairing.d.ts +0 -12
- package/apps/app-lifeops/src/hooks/useWhatsAppPairing.d.ts.map +0 -1
- package/apps/app-lifeops/src/hooks/useWhatsAppPairing.js +0 -152
- package/apps/app-lifeops/src/inbox/config.d.ts +0 -7
- package/apps/app-lifeops/src/inbox/config.d.ts.map +0 -1
- package/apps/app-lifeops/src/inbox/config.js +0 -67
- package/apps/app-lifeops/src/inbox/reflection.d.ts +0 -40
- package/apps/app-lifeops/src/inbox/reflection.d.ts.map +0 -1
- package/apps/app-lifeops/src/inbox/reflection.js +0 -115
- package/apps/app-lifeops/src/inbox/repository.d.ts +0 -52
- package/apps/app-lifeops/src/inbox/repository.d.ts.map +0 -1
- package/apps/app-lifeops/src/inbox/repository.js +0 -262
- package/apps/app-lifeops/src/inbox/triage-classifier.d.ts +0 -15
- package/apps/app-lifeops/src/inbox/triage-classifier.d.ts.map +0 -1
- package/apps/app-lifeops/src/inbox/triage-classifier.js +0 -179
- package/apps/app-lifeops/src/index.d.ts +0 -20
- package/apps/app-lifeops/src/index.d.ts.map +0 -1
- package/apps/app-lifeops/src/index.js +0 -18
- package/apps/app-lifeops/src/lifeops/approval-queue.d.ts +0 -24
- package/apps/app-lifeops/src/lifeops/approval-queue.d.ts.map +0 -1
- package/apps/app-lifeops/src/lifeops/approval-queue.js +0 -500
- package/apps/app-lifeops/src/lifeops/approval-queue.types.d.ts +0 -166
- package/apps/app-lifeops/src/lifeops/approval-queue.types.d.ts.map +0 -1
- package/apps/app-lifeops/src/lifeops/approval-queue.types.js +0 -22
- package/apps/app-lifeops/src/lifeops/autofill-whitelist.d.ts +0 -15
- package/apps/app-lifeops/src/lifeops/autofill-whitelist.d.ts.map +0 -1
- package/apps/app-lifeops/src/lifeops/autofill-whitelist.js +0 -116
- package/apps/app-lifeops/src/lifeops/background-planner-dispatch.d.ts +0 -60
- package/apps/app-lifeops/src/lifeops/background-planner-dispatch.d.ts.map +0 -1
- package/apps/app-lifeops/src/lifeops/background-planner-dispatch.js +0 -134
- package/apps/app-lifeops/src/lifeops/background-planner.d.ts +0 -141
- package/apps/app-lifeops/src/lifeops/background-planner.d.ts.map +0 -1
- package/apps/app-lifeops/src/lifeops/background-planner.js +0 -377
- package/apps/app-lifeops/src/lifeops/calendly-client.d.ts +0 -61
- package/apps/app-lifeops/src/lifeops/calendly-client.d.ts.map +0 -1
- package/apps/app-lifeops/src/lifeops/calendly-client.js +0 -234
- package/apps/app-lifeops/src/lifeops/checkin/schedule-resolver.d.ts +0 -14
- package/apps/app-lifeops/src/lifeops/checkin/schedule-resolver.d.ts.map +0 -1
- package/apps/app-lifeops/src/lifeops/checkin/schedule-resolver.js +0 -27
- package/apps/app-lifeops/src/lifeops/cross-channel-search.d.ts +0 -88
- package/apps/app-lifeops/src/lifeops/cross-channel-search.d.ts.map +0 -1
- package/apps/app-lifeops/src/lifeops/cross-channel-search.js +0 -446
- package/apps/app-lifeops/src/lifeops/intent-sync.d.ts +0 -59
- package/apps/app-lifeops/src/lifeops/intent-sync.d.ts.map +0 -1
- package/apps/app-lifeops/src/lifeops/intent-sync.js +0 -305
- package/apps/app-lifeops/src/lifeops/notifications-push.d.ts +0 -37
- package/apps/app-lifeops/src/lifeops/notifications-push.d.ts.map +0 -1
- package/apps/app-lifeops/src/lifeops/notifications-push.js +0 -92
- package/apps/app-lifeops/src/lifeops/password-manager-bridge.d.ts +0 -50
- package/apps/app-lifeops/src/lifeops/password-manager-bridge.d.ts.map +0 -1
- package/apps/app-lifeops/src/lifeops/password-manager-bridge.js +0 -448
- package/apps/app-lifeops/src/lifeops/remote-desktop.d.ts +0 -38
- package/apps/app-lifeops/src/lifeops/remote-desktop.d.ts.map +0 -1
- package/apps/app-lifeops/src/lifeops/remote-desktop.js +0 -372
- package/apps/app-lifeops/src/lifeops/runtime.d.ts +0 -11
- package/apps/app-lifeops/src/lifeops/runtime.d.ts.map +0 -1
- package/apps/app-lifeops/src/lifeops/runtime.js +0 -57
- package/apps/app-lifeops/src/lifeops/screen-context.d.ts +0 -52
- package/apps/app-lifeops/src/lifeops/screen-context.d.ts.map +0 -1
- package/apps/app-lifeops/src/lifeops/screen-context.js +0 -349
- package/apps/app-lifeops/src/lifeops-route.d.ts +0 -74
- package/apps/app-lifeops/src/lifeops-route.d.ts.map +0 -1
- package/apps/app-lifeops/src/lifeops-route.js +0 -204
- package/apps/app-lifeops/src/platform/index.d.ts +0 -2
- package/apps/app-lifeops/src/platform/index.d.ts.map +0 -1
- package/apps/app-lifeops/src/platform/index.js +0 -1
- package/apps/app-lifeops/src/platform/lifeops-github.d.ts +0 -15
- package/apps/app-lifeops/src/platform/lifeops-github.d.ts.map +0 -1
- package/apps/app-lifeops/src/platform/lifeops-github.js +0 -135
- package/apps/app-lifeops/src/plugin.d.ts +0 -33
- package/apps/app-lifeops/src/plugin.d.ts.map +0 -1
- package/apps/app-lifeops/src/plugin.js +0 -316
- package/apps/app-lifeops/src/provider.d.ts +0 -4
- package/apps/app-lifeops/src/provider.d.ts.map +0 -1
- package/apps/app-lifeops/src/provider.js +0 -77
- package/apps/app-lifeops/src/providers/activity-profile.d.ts +0 -3
- package/apps/app-lifeops/src/providers/activity-profile.d.ts.map +0 -1
- package/apps/app-lifeops/src/providers/activity-profile.js +0 -140
- package/apps/app-lifeops/src/providers/app-blocker.d.ts +0 -3
- package/apps/app-lifeops/src/providers/app-blocker.d.ts.map +0 -1
- package/apps/app-lifeops/src/providers/app-blocker.js +0 -86
- package/apps/app-lifeops/src/providers/cross-channel-context.d.ts +0 -29
- package/apps/app-lifeops/src/providers/cross-channel-context.d.ts.map +0 -1
- package/apps/app-lifeops/src/providers/cross-channel-context.js +0 -182
- package/apps/app-lifeops/src/providers/inbox-triage.d.ts +0 -3
- package/apps/app-lifeops/src/providers/inbox-triage.d.ts.map +0 -1
- package/apps/app-lifeops/src/providers/inbox-triage.js +0 -90
- package/apps/app-lifeops/src/providers/lifeops.d.ts +0 -3
- package/apps/app-lifeops/src/providers/lifeops.d.ts.map +0 -1
- package/apps/app-lifeops/src/providers/lifeops.js +0 -197
- package/apps/app-lifeops/src/remote/pairing-code.d.ts +0 -39
- package/apps/app-lifeops/src/remote/pairing-code.d.ts.map +0 -1
- package/apps/app-lifeops/src/remote/pairing-code.js +0 -76
- package/apps/app-lifeops/src/remote/remote-session-service.d.ts +0 -107
- package/apps/app-lifeops/src/remote/remote-session-service.d.ts.map +0 -1
- package/apps/app-lifeops/src/remote/remote-session-service.js +0 -253
- package/apps/app-lifeops/src/service.d.ts +0 -32
- package/apps/app-lifeops/src/service.d.ts.map +0 -1
- package/apps/app-lifeops/src/service.js +0 -67
- package/apps/app-lifeops/src/travel-time/calendar-create.d.ts +0 -17
- package/apps/app-lifeops/src/travel-time/calendar-create.d.ts.map +0 -1
- package/apps/app-lifeops/src/travel-time/calendar-create.js +0 -21
- package/apps/app-lifeops/src/travel-time/service.d.ts +0 -60
- package/apps/app-lifeops/src/travel-time/service.d.ts.map +0 -1
- package/apps/app-lifeops/src/travel-time/service.js +0 -142
- package/apps/app-lifeops/src/utils/lifeops-url.d.ts +0 -5
- package/apps/app-lifeops/src/utils/lifeops-url.d.ts.map +0 -1
- package/apps/app-lifeops/src/utils/lifeops-url.js +0 -35
- package/apps/app-lifeops/src/website-blocker/chat-integration/actions/blockUntilTaskComplete.d.ts +0 -3
- package/apps/app-lifeops/src/website-blocker/chat-integration/actions/blockUntilTaskComplete.d.ts.map +0 -1
- package/apps/app-lifeops/src/website-blocker/chat-integration/actions/blockUntilTaskComplete.js +0 -246
- package/apps/app-lifeops/src/website-blocker/chat-integration/actions/listActiveBlocks.d.ts +0 -3
- package/apps/app-lifeops/src/website-blocker/chat-integration/actions/listActiveBlocks.d.ts.map +0 -1
- package/apps/app-lifeops/src/website-blocker/chat-integration/actions/listActiveBlocks.js +0 -83
- package/apps/app-lifeops/src/website-blocker/chat-integration/actions/releaseBlock.d.ts +0 -3
- package/apps/app-lifeops/src/website-blocker/chat-integration/actions/releaseBlock.d.ts.map +0 -1
- package/apps/app-lifeops/src/website-blocker/chat-integration/actions/releaseBlock.js +0 -98
- package/apps/app-lifeops/src/website-blocker/chat-integration/block-rule-reconciler.d.ts +0 -7
- package/apps/app-lifeops/src/website-blocker/chat-integration/block-rule-reconciler.d.ts.map +0 -1
- package/apps/app-lifeops/src/website-blocker/chat-integration/block-rule-reconciler.js +0 -111
- package/apps/app-lifeops/src/website-blocker/chat-integration/block-rule-schema.d.ts +0 -39
- package/apps/app-lifeops/src/website-blocker/chat-integration/block-rule-schema.d.ts.map +0 -1
- package/apps/app-lifeops/src/website-blocker/chat-integration/block-rule-schema.js +0 -123
- package/apps/app-lifeops/src/website-blocker/chat-integration/block-rule-service.d.ts +0 -21
- package/apps/app-lifeops/src/website-blocker/chat-integration/block-rule-service.d.ts.map +0 -1
- package/apps/app-lifeops/src/website-blocker/chat-integration/block-rule-service.js +0 -258
- package/apps/app-lifeops/src/website-blocker/chat-integration/index.d.ts +0 -8
- package/apps/app-lifeops/src/website-blocker/chat-integration/index.d.ts.map +0 -1
- package/apps/app-lifeops/src/website-blocker/chat-integration/index.js +0 -6
- package/packages/app-core/src/api/client-lifeops.d.ts +0 -35
- package/packages/app-core/src/api/client-lifeops.d.ts.map +0 -1
- package/packages/app-core/src/api/client-lifeops.js +0 -114
- package/packages/app-core/src/hooks/useGoogleLifeOpsConnector.d.ts +0 -20
- package/packages/app-core/src/hooks/useGoogleLifeOpsConnector.d.ts.map +0 -1
- package/packages/app-core/src/hooks/useGoogleLifeOpsConnector.js +0 -69
- package/packages/app-core/src/hooks/useLifeOpsAppState.d.ts +0 -21
- package/packages/app-core/src/hooks/useLifeOpsAppState.d.ts.map +0 -1
- package/packages/app-core/src/hooks/useLifeOpsAppState.js +0 -81
- package/packages/app-core/src/services/steward-sidecar.d.ts +0 -6
- package/packages/app-core/src/services/steward-sidecar.d.ts.map +0 -1
- package/packages/app-core/src/services/steward-sidecar.js +0 -5
|
@@ -1,3247 +0,0 @@
|
|
|
1
|
-
import { ModelType, parseJSONObjectFromText } from "@elizaos/core";
|
|
2
|
-
import { getRecentMessagesData } from "@elizaos/shared";
|
|
3
|
-
import { buildNativeAppleReminderMetadata, } from "../lifeops/apple-reminders.js";
|
|
4
|
-
import { resolveDefaultTimeZone, resolveDefaultWindowPolicy, } from "../lifeops/defaults.js";
|
|
5
|
-
import { LifeOpsService, LifeOpsServiceError } from "../lifeops/service.js";
|
|
6
|
-
import { addDaysToLocalDate, buildUtcDateFromLocalParts, getZonedDateParts, } from "../lifeops/time.js";
|
|
7
|
-
import { gmailAction } from "./gmail.js";
|
|
8
|
-
import { renderGroundedActionReply, } from "@elizaos/agent";
|
|
9
|
-
import { extractLifeOperationWithLlm, } from "./life.extractor.js";
|
|
10
|
-
import { extractGoalCreatePlanWithLlm, extractGoalUpdatePlanWithLlm, mergeGoalMetadataWithGrounding, } from "./life-goal-extractor.js";
|
|
11
|
-
import { extractReminderIntensityWithLlm, extractTaskCreatePlanWithLlm, } from "./life-param-extractor.js";
|
|
12
|
-
import { recentConversationTexts } from "./life-recent-context.js";
|
|
13
|
-
import { extractUpdateFieldsWithLlm } from "./life-update-extractor.js";
|
|
14
|
-
import { calendarReadUnavailableMessage, dayRange, detailArray, detailBoolean, detailNumber, detailObject, detailString, formatCalendarFeed, formatNextEventContext, formatOverviewForQuery, getGoogleCapabilityStatus, hasLifeOpsAccess, INTERNAL_URL, messageText, toActionData, weekRange, } from "./lifeops-google-helpers.js";
|
|
15
|
-
import { looksLikeCodingTaskRequest } from "./non-actionable-request.js";
|
|
16
|
-
import { normalizeExplicitTimeZoneToken } from "./timezone-normalization.js";
|
|
17
|
-
const ACTION_TO_OPERATION = {
|
|
18
|
-
create: "create_definition",
|
|
19
|
-
create_goal: "create_goal",
|
|
20
|
-
update: "update_definition",
|
|
21
|
-
update_goal: "update_goal",
|
|
22
|
-
delete: "delete_definition",
|
|
23
|
-
delete_goal: "delete_goal",
|
|
24
|
-
complete: "complete_occurrence",
|
|
25
|
-
skip: "skip_occurrence",
|
|
26
|
-
snooze: "snooze_occurrence",
|
|
27
|
-
review: "review_goal",
|
|
28
|
-
phone: "capture_phone",
|
|
29
|
-
escalation: "configure_escalation",
|
|
30
|
-
reminder_preference: "set_reminder_preference",
|
|
31
|
-
calendar: "query_calendar_today",
|
|
32
|
-
next_event: "query_calendar_next",
|
|
33
|
-
email: "query_email",
|
|
34
|
-
overview: "query_overview",
|
|
35
|
-
};
|
|
36
|
-
const GENERIC_DERIVED_TITLE_RE = /^(?:new\s+)?(?:habit|routine|task|goal|life goal|thing|item|something|anything|stuff|plan|reminder|todo|to do|achieve|achieve a|achieve an)$/i;
|
|
37
|
-
/** Maximum age (ms) for a deferred draft before it expires. */
|
|
38
|
-
const DRAFT_EXPIRY_MS = 5 * 60 * 1000; // 5 minutes
|
|
39
|
-
/** Maximum conversation turns before a deferred draft expires. */
|
|
40
|
-
const DRAFT_MAX_TURNS = 3;
|
|
41
|
-
function normalizeLifeTimeZoneToken(value) {
|
|
42
|
-
return normalizeExplicitTimeZoneToken(value);
|
|
43
|
-
}
|
|
44
|
-
async function resolveLifeOperationPlan(args) {
|
|
45
|
-
const { runtime, message, state, intent, explicitOperation } = args;
|
|
46
|
-
if (explicitOperation) {
|
|
47
|
-
return {
|
|
48
|
-
operation: explicitOperation,
|
|
49
|
-
confidence: 1,
|
|
50
|
-
missing: [],
|
|
51
|
-
shouldAct: true,
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
const extracted = await extractLifeOperationWithLlm({
|
|
55
|
-
runtime,
|
|
56
|
-
message,
|
|
57
|
-
state,
|
|
58
|
-
intent,
|
|
59
|
-
});
|
|
60
|
-
if (!extracted.shouldAct || !extracted.operation) {
|
|
61
|
-
return {
|
|
62
|
-
operation: extracted.operation,
|
|
63
|
-
confidence: extracted.confidence,
|
|
64
|
-
missing: extracted.missing,
|
|
65
|
-
shouldAct: false,
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
return {
|
|
69
|
-
operation: extracted.operation,
|
|
70
|
-
confidence: extracted.confidence,
|
|
71
|
-
missing: extracted.missing,
|
|
72
|
-
shouldAct: true,
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
function shouldForceLifeCreateExecution(args) {
|
|
76
|
-
if (args.operation !== "create_definition") {
|
|
77
|
-
return false;
|
|
78
|
-
}
|
|
79
|
-
const blockingFields = args.missing.filter((field) => field !== "title" && field !== "schedule");
|
|
80
|
-
if (blockingFields.length > 0) {
|
|
81
|
-
return false;
|
|
82
|
-
}
|
|
83
|
-
if (typeof args.title === "string" && args.title.trim().length > 0) {
|
|
84
|
-
return true;
|
|
85
|
-
}
|
|
86
|
-
if (normalizeCadenceDetail(detailObject(args.details, "cadence"))) {
|
|
87
|
-
return true;
|
|
88
|
-
}
|
|
89
|
-
return false;
|
|
90
|
-
}
|
|
91
|
-
// ── Helpers ───────────────────────────────────────────
|
|
92
|
-
function requestedOwnership(domain) {
|
|
93
|
-
if (domain === "agent_ops") {
|
|
94
|
-
return { domain: "agent_ops", subjectType: "agent" };
|
|
95
|
-
}
|
|
96
|
-
return { domain: "user_lifeops", subjectType: "owner" };
|
|
97
|
-
}
|
|
98
|
-
function normalizeIntentText(value) {
|
|
99
|
-
return normalizeLifeInputText(value).toLowerCase();
|
|
100
|
-
}
|
|
101
|
-
function normalizeLifeInputText(value) {
|
|
102
|
-
return value
|
|
103
|
-
.replace(/[\u00a0\u1680\u2000-\u200b\u202f\u205f\u3000]/g, " ")
|
|
104
|
-
.replace(/\s+/g, " ")
|
|
105
|
-
.trim();
|
|
106
|
-
}
|
|
107
|
-
function normalizeTitle(value) {
|
|
108
|
-
return normalizeIntentText(value);
|
|
109
|
-
}
|
|
110
|
-
function matchByTitle(entries, targetTitle) {
|
|
111
|
-
const normalized = normalizeTitle(targetTitle);
|
|
112
|
-
return (entries.find((e) => normalizeTitle(e.definition?.title ?? e.goal?.title ?? "") ===
|
|
113
|
-
normalized) ??
|
|
114
|
-
entries.find((e) => normalizeTitle(e.definition?.title ?? e.goal?.title ?? "").includes(normalized)) ??
|
|
115
|
-
null);
|
|
116
|
-
}
|
|
117
|
-
function coerceDeferredLifeDraft(value) {
|
|
118
|
-
if (!value || typeof value !== "object") {
|
|
119
|
-
return null;
|
|
120
|
-
}
|
|
121
|
-
const record = value;
|
|
122
|
-
const operation = record.operation;
|
|
123
|
-
const intent = typeof record.intent === "string" ? record.intent.trim() : "";
|
|
124
|
-
const request = record.request && typeof record.request === "object"
|
|
125
|
-
? record.request
|
|
126
|
-
: null;
|
|
127
|
-
const createdAt = typeof record.createdAt === "number" && Number.isFinite(record.createdAt)
|
|
128
|
-
? record.createdAt
|
|
129
|
-
: undefined;
|
|
130
|
-
if (!request || !intent) {
|
|
131
|
-
return null;
|
|
132
|
-
}
|
|
133
|
-
const title = typeof request.title === "string" ? request.title.trim() : "";
|
|
134
|
-
if (!title) {
|
|
135
|
-
return null;
|
|
136
|
-
}
|
|
137
|
-
if (operation === "create_definition") {
|
|
138
|
-
const kind = typeof request.kind === "string"
|
|
139
|
-
? request.kind
|
|
140
|
-
: null;
|
|
141
|
-
const cadence = request.cadence;
|
|
142
|
-
if (!kind || !cadence) {
|
|
143
|
-
return null;
|
|
144
|
-
}
|
|
145
|
-
return {
|
|
146
|
-
createdAt,
|
|
147
|
-
intent,
|
|
148
|
-
operation,
|
|
149
|
-
request: {
|
|
150
|
-
cadence,
|
|
151
|
-
description: typeof request.description === "string"
|
|
152
|
-
? request.description
|
|
153
|
-
: undefined,
|
|
154
|
-
goalRef: typeof request.goalRef === "string" ? request.goalRef : undefined,
|
|
155
|
-
kind,
|
|
156
|
-
priority: typeof request.priority === "number" ? request.priority : undefined,
|
|
157
|
-
progressionRule: request.progressionRule,
|
|
158
|
-
reminderPlan: request.reminderPlan,
|
|
159
|
-
timezone: typeof request.timezone === "string" ? request.timezone : undefined,
|
|
160
|
-
title,
|
|
161
|
-
metadata: request.metadata && typeof request.metadata === "object"
|
|
162
|
-
? request.metadata
|
|
163
|
-
: undefined,
|
|
164
|
-
windowPolicy: request.windowPolicy,
|
|
165
|
-
websiteAccess: request.websiteAccess,
|
|
166
|
-
},
|
|
167
|
-
};
|
|
168
|
-
}
|
|
169
|
-
if (operation === "create_goal") {
|
|
170
|
-
return {
|
|
171
|
-
createdAt,
|
|
172
|
-
intent,
|
|
173
|
-
operation,
|
|
174
|
-
request: {
|
|
175
|
-
cadence: request.cadence,
|
|
176
|
-
description: typeof request.description === "string"
|
|
177
|
-
? request.description
|
|
178
|
-
: undefined,
|
|
179
|
-
metadata: request.metadata && typeof request.metadata === "object"
|
|
180
|
-
? request.metadata
|
|
181
|
-
: undefined,
|
|
182
|
-
successCriteria: request.successCriteria,
|
|
183
|
-
supportStrategy: request.supportStrategy,
|
|
184
|
-
title,
|
|
185
|
-
},
|
|
186
|
-
};
|
|
187
|
-
}
|
|
188
|
-
return null;
|
|
189
|
-
}
|
|
190
|
-
function stateActionResults(state) {
|
|
191
|
-
if (!state || typeof state !== "object") {
|
|
192
|
-
return [];
|
|
193
|
-
}
|
|
194
|
-
const stateRecord = state;
|
|
195
|
-
const data = stateRecord.data && typeof stateRecord.data === "object"
|
|
196
|
-
? stateRecord.data
|
|
197
|
-
: undefined;
|
|
198
|
-
const providerResults = data?.providers && typeof data.providers === "object"
|
|
199
|
-
? data.providers
|
|
200
|
-
: undefined;
|
|
201
|
-
const providerActionState = providerResults?.ACTION_STATE &&
|
|
202
|
-
typeof providerResults.ACTION_STATE === "object"
|
|
203
|
-
? providerResults.ACTION_STATE
|
|
204
|
-
: undefined;
|
|
205
|
-
const providerActionStateData = providerActionState?.data && typeof providerActionState.data === "object"
|
|
206
|
-
? providerActionState.data
|
|
207
|
-
: undefined;
|
|
208
|
-
const providerRecentMessages = providerResults?.RECENT_MESSAGES &&
|
|
209
|
-
typeof providerResults.RECENT_MESSAGES === "object"
|
|
210
|
-
? providerResults.RECENT_MESSAGES
|
|
211
|
-
: undefined;
|
|
212
|
-
const providerRecentMessagesData = providerRecentMessages?.data &&
|
|
213
|
-
typeof providerRecentMessages.data === "object"
|
|
214
|
-
? providerRecentMessages.data
|
|
215
|
-
: undefined;
|
|
216
|
-
const candidates = [
|
|
217
|
-
data?.actionResults,
|
|
218
|
-
providerActionStateData?.actionResults,
|
|
219
|
-
providerActionStateData?.recentActionMemories,
|
|
220
|
-
providerRecentMessagesData?.actionResults,
|
|
221
|
-
].filter(Array.isArray);
|
|
222
|
-
if (candidates.length === 0) {
|
|
223
|
-
return [];
|
|
224
|
-
}
|
|
225
|
-
return candidates.flatMap((entries) => entries.flatMap((entry) => {
|
|
226
|
-
if (!entry || typeof entry !== "object") {
|
|
227
|
-
return [];
|
|
228
|
-
}
|
|
229
|
-
if ("content" in entry) {
|
|
230
|
-
const content = entry.content &&
|
|
231
|
-
typeof entry.content === "object"
|
|
232
|
-
? entry
|
|
233
|
-
.content
|
|
234
|
-
: null;
|
|
235
|
-
if (!content) {
|
|
236
|
-
return [];
|
|
237
|
-
}
|
|
238
|
-
const contentData = content.data && typeof content.data === "object"
|
|
239
|
-
? { ...content.data }
|
|
240
|
-
: {};
|
|
241
|
-
if (typeof content.actionName === "string" &&
|
|
242
|
-
typeof contentData.actionName !== "string") {
|
|
243
|
-
contentData.actionName = content.actionName;
|
|
244
|
-
}
|
|
245
|
-
return [
|
|
246
|
-
{
|
|
247
|
-
success: content.actionStatus !== "failed",
|
|
248
|
-
text: typeof content.text === "string" ? content.text : undefined,
|
|
249
|
-
data: contentData,
|
|
250
|
-
error: typeof content.error === "string" ? content.error : undefined,
|
|
251
|
-
},
|
|
252
|
-
];
|
|
253
|
-
}
|
|
254
|
-
return [entry];
|
|
255
|
-
}));
|
|
256
|
-
}
|
|
257
|
-
function stateMessageDrafts(state) {
|
|
258
|
-
if (!state || typeof state !== "object") {
|
|
259
|
-
return [];
|
|
260
|
-
}
|
|
261
|
-
const drafts = [];
|
|
262
|
-
for (const item of getRecentMessagesData(state)) {
|
|
263
|
-
const content = item.content;
|
|
264
|
-
if (!content || typeof content !== "object") {
|
|
265
|
-
continue;
|
|
266
|
-
}
|
|
267
|
-
const contentRecord = content;
|
|
268
|
-
const candidate = coerceDeferredLifeDraft(contentRecord.lifeDraft) ??
|
|
269
|
-
coerceDeferredLifeDraft(contentRecord.data && typeof contentRecord.data === "object"
|
|
270
|
-
? contentRecord.data.lifeDraft
|
|
271
|
-
: undefined);
|
|
272
|
-
if (candidate) {
|
|
273
|
-
drafts.push(candidate);
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
return drafts;
|
|
277
|
-
}
|
|
278
|
-
function stateRecentMessageEntries(state) {
|
|
279
|
-
if (!state || typeof state !== "object") {
|
|
280
|
-
return [];
|
|
281
|
-
}
|
|
282
|
-
return getRecentMessagesData(state);
|
|
283
|
-
}
|
|
284
|
-
function isDeferredLifeDraftMessageEntry(item) {
|
|
285
|
-
const content = item.content && typeof item.content === "object"
|
|
286
|
-
? item.content
|
|
287
|
-
: null;
|
|
288
|
-
if (!content) {
|
|
289
|
-
return false;
|
|
290
|
-
}
|
|
291
|
-
return Boolean(coerceDeferredLifeDraft(content.lifeDraft) ??
|
|
292
|
-
coerceDeferredLifeDraft(content.data && typeof content.data === "object"
|
|
293
|
-
? content.data.lifeDraft
|
|
294
|
-
: undefined));
|
|
295
|
-
}
|
|
296
|
-
function countTurnsSinceLatestDeferredLifeDraft(state) {
|
|
297
|
-
const entries = stateRecentMessageEntries(state);
|
|
298
|
-
if (entries.length === 0) {
|
|
299
|
-
return undefined;
|
|
300
|
-
}
|
|
301
|
-
let latestDraftIndex = -1;
|
|
302
|
-
for (let index = entries.length - 1; index >= 0; index--) {
|
|
303
|
-
const entry = entries[index];
|
|
304
|
-
if (entry && isDeferredLifeDraftMessageEntry(entry)) {
|
|
305
|
-
latestDraftIndex = index;
|
|
306
|
-
break;
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
if (latestDraftIndex < 0) {
|
|
310
|
-
return undefined;
|
|
311
|
-
}
|
|
312
|
-
let turns = 0;
|
|
313
|
-
for (const entry of entries.slice(latestDraftIndex + 1)) {
|
|
314
|
-
const content = entry.content && typeof entry.content === "object"
|
|
315
|
-
? entry.content
|
|
316
|
-
: null;
|
|
317
|
-
if (!content || isDeferredLifeDraftMessageEntry(entry)) {
|
|
318
|
-
continue;
|
|
319
|
-
}
|
|
320
|
-
if (typeof content.text === "string" && content.text.trim().length > 0) {
|
|
321
|
-
turns++;
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
return turns;
|
|
325
|
-
}
|
|
326
|
-
function latestDeferredLifeDraft(state) {
|
|
327
|
-
for (const result of [...stateActionResults(state)].reverse()) {
|
|
328
|
-
const resultData = result.data && typeof result.data === "object"
|
|
329
|
-
? result.data
|
|
330
|
-
: null;
|
|
331
|
-
const completedCreate = result.success &&
|
|
332
|
-
resultData &&
|
|
333
|
-
!coerceDeferredLifeDraft(resultData.lifeDraft) &&
|
|
334
|
-
((resultData.definition && typeof resultData.definition === "object") ||
|
|
335
|
-
(resultData.goal && typeof resultData.goal === "object"));
|
|
336
|
-
if (completedCreate) {
|
|
337
|
-
return null;
|
|
338
|
-
}
|
|
339
|
-
const candidate = coerceDeferredLifeDraft(result.data?.lifeDraft);
|
|
340
|
-
if (candidate) {
|
|
341
|
-
return candidate;
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
const messageDrafts = stateMessageDrafts(state);
|
|
345
|
-
return messageDrafts.at(-1) ?? null;
|
|
346
|
-
}
|
|
347
|
-
function deferredLifeDraftExpiryReason(args) {
|
|
348
|
-
if (!args.draft) {
|
|
349
|
-
return null;
|
|
350
|
-
}
|
|
351
|
-
if (args.draft.createdAt) {
|
|
352
|
-
const ageMs = Date.now() - args.draft.createdAt;
|
|
353
|
-
if (ageMs >= DRAFT_EXPIRY_MS) {
|
|
354
|
-
return "age";
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
if (typeof args.turnsSinceDraft === "number" &&
|
|
358
|
-
args.turnsSinceDraft >= DRAFT_MAX_TURNS) {
|
|
359
|
-
return "turns";
|
|
360
|
-
}
|
|
361
|
-
return null;
|
|
362
|
-
}
|
|
363
|
-
async function extractDeferredLifeDraftFollowupWithLlm(args) {
|
|
364
|
-
if (typeof args.runtime.useModel !== "function") {
|
|
365
|
-
return null;
|
|
366
|
-
}
|
|
367
|
-
const recentConversation = await recentConversationTexts({
|
|
368
|
-
runtime: args.runtime,
|
|
369
|
-
message: args.message,
|
|
370
|
-
state: args.state,
|
|
371
|
-
limit: 12,
|
|
372
|
-
});
|
|
373
|
-
const prompt = [
|
|
374
|
-
"Decide how the assistant should interpret the user's follow-up to a previewed LifeOps draft that has not been saved yet.",
|
|
375
|
-
"Use the current message, the draft summary, and recent conversation.",
|
|
376
|
-
"The user may speak in any language.",
|
|
377
|
-
"",
|
|
378
|
-
"Return ONLY valid JSON with exactly this shape:",
|
|
379
|
-
'{"mode":"confirm"|"edit"|"cancel"|"none"}',
|
|
380
|
-
"",
|
|
381
|
-
"Choose confirm when the user clearly approves saving the current draft now.",
|
|
382
|
-
"Choose edit when the user wants to change the draft or continue specifying it before saving.",
|
|
383
|
-
"Choose cancel when the user says not to save it, never mind, not yet, hold off, or equivalent.",
|
|
384
|
-
"Choose none when the follow-up is unrelated or too ambiguous to attach to the draft.",
|
|
385
|
-
"",
|
|
386
|
-
"Previewed draft:",
|
|
387
|
-
stringifyDeferredLifeDraftForPrompt(args.draft),
|
|
388
|
-
"",
|
|
389
|
-
`Current user message: ${JSON.stringify(args.currentText)}`,
|
|
390
|
-
`Recent conversation: ${JSON.stringify(recentConversation.join("\n"))}`,
|
|
391
|
-
].join("\n");
|
|
392
|
-
try {
|
|
393
|
-
const result = await args.runtime.useModel(ModelType.TEXT_LARGE, {
|
|
394
|
-
prompt,
|
|
395
|
-
});
|
|
396
|
-
const raw = typeof result === "string" ? result : "";
|
|
397
|
-
const parsed = parseJSONObjectFromText(raw);
|
|
398
|
-
const mode = parsed && typeof parsed.mode === "string"
|
|
399
|
-
? parsed.mode.trim().toLowerCase()
|
|
400
|
-
: "";
|
|
401
|
-
switch (mode) {
|
|
402
|
-
case "confirm":
|
|
403
|
-
case "edit":
|
|
404
|
-
case "cancel":
|
|
405
|
-
return mode;
|
|
406
|
-
default:
|
|
407
|
-
return null;
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
catch {
|
|
411
|
-
return null;
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
function stringifyDeferredLifeDraftForPrompt(draft) {
|
|
415
|
-
if (draft.operation === "create_definition") {
|
|
416
|
-
return JSON.stringify({
|
|
417
|
-
operation: draft.operation,
|
|
418
|
-
title: draft.request.title,
|
|
419
|
-
kind: draft.request.kind,
|
|
420
|
-
cadence: draft.request.cadence,
|
|
421
|
-
timezone: draft.request.timezone ?? null,
|
|
422
|
-
description: draft.request.description ?? null,
|
|
423
|
-
});
|
|
424
|
-
}
|
|
425
|
-
return JSON.stringify({
|
|
426
|
-
operation: draft.operation,
|
|
427
|
-
title: draft.request.title,
|
|
428
|
-
cadence: draft.request.cadence ?? null,
|
|
429
|
-
description: draft.request.description ?? null,
|
|
430
|
-
});
|
|
431
|
-
}
|
|
432
|
-
function resolveDeferredLifeDraftReuseMode(args) {
|
|
433
|
-
if (!args.draft) {
|
|
434
|
-
return null;
|
|
435
|
-
}
|
|
436
|
-
if (deferredLifeDraftExpiryReason(args)) {
|
|
437
|
-
return null;
|
|
438
|
-
}
|
|
439
|
-
if (detailBoolean(args.details, "confirmed") === true) {
|
|
440
|
-
return "confirm";
|
|
441
|
-
}
|
|
442
|
-
if (args.explicitAction &&
|
|
443
|
-
ACTION_TO_OPERATION[args.explicitAction] !== args.draft.operation) {
|
|
444
|
-
return null;
|
|
445
|
-
}
|
|
446
|
-
if (args.llmMode === "confirm" || args.llmMode === "edit") {
|
|
447
|
-
return args.llmMode;
|
|
448
|
-
}
|
|
449
|
-
return null;
|
|
450
|
-
}
|
|
451
|
-
async function resolveGoal(service, target, domain) {
|
|
452
|
-
if (!target)
|
|
453
|
-
return null;
|
|
454
|
-
const goals = (await service.listGoals()).filter((e) => domain ? e.goal.domain === domain : true);
|
|
455
|
-
return goals.find((e) => e.goal.id === target) ?? matchByTitle(goals, target);
|
|
456
|
-
}
|
|
457
|
-
async function resolveDefinition(service, target, domain) {
|
|
458
|
-
if (!target)
|
|
459
|
-
return null;
|
|
460
|
-
const defs = (await service.listDefinitions()).filter((e) => domain ? e.definition.domain === domain : true);
|
|
461
|
-
return (defs.find((e) => e.definition.id === target) ?? matchByTitle(defs, target));
|
|
462
|
-
}
|
|
463
|
-
function tokenizeTitle(value) {
|
|
464
|
-
return normalizeTitle(value)
|
|
465
|
-
.split(" ")
|
|
466
|
-
.filter((token) => token.length >= 3);
|
|
467
|
-
}
|
|
468
|
-
async function resolveDefinitionFromIntent(service, target, intent, domain) {
|
|
469
|
-
const direct = await resolveDefinition(service, target, domain);
|
|
470
|
-
if (direct) {
|
|
471
|
-
return direct;
|
|
472
|
-
}
|
|
473
|
-
const defs = (await service.listDefinitions()).filter((entry) => domain ? entry.definition.domain === domain : true);
|
|
474
|
-
const intentTokens = new Set(tokenizeTitle(intent));
|
|
475
|
-
let best = null;
|
|
476
|
-
let bestScore = 0;
|
|
477
|
-
let tied = false;
|
|
478
|
-
for (const entry of defs) {
|
|
479
|
-
const title = normalizeTitle(entry.definition.title);
|
|
480
|
-
if (title.length > 0 && normalizeTitle(intent).includes(title)) {
|
|
481
|
-
return entry;
|
|
482
|
-
}
|
|
483
|
-
const overlap = tokenizeTitle(entry.definition.title).filter((token) => intentTokens.has(token)).length;
|
|
484
|
-
if (overlap === 0) {
|
|
485
|
-
continue;
|
|
486
|
-
}
|
|
487
|
-
if (overlap > bestScore) {
|
|
488
|
-
best = entry;
|
|
489
|
-
bestScore = overlap;
|
|
490
|
-
tied = false;
|
|
491
|
-
continue;
|
|
492
|
-
}
|
|
493
|
-
if (overlap === bestScore) {
|
|
494
|
-
tied = true;
|
|
495
|
-
}
|
|
496
|
-
}
|
|
497
|
-
return bestScore > 0 && !tied ? best : null;
|
|
498
|
-
}
|
|
499
|
-
function formatOccurrenceDisambiguationLabel(occurrence) {
|
|
500
|
-
const hints = [];
|
|
501
|
-
if (typeof occurrence.windowName === "string" &&
|
|
502
|
-
occurrence.windowName.trim()) {
|
|
503
|
-
hints.push(occurrence.windowName.trim());
|
|
504
|
-
}
|
|
505
|
-
if (occurrence.dueAt) {
|
|
506
|
-
const dueAt = new Date(occurrence.dueAt);
|
|
507
|
-
if (!Number.isNaN(dueAt.getTime())) {
|
|
508
|
-
hints.push(dueAt.toLocaleString(undefined, {
|
|
509
|
-
month: "short",
|
|
510
|
-
day: "numeric",
|
|
511
|
-
hour: "numeric",
|
|
512
|
-
minute: "2-digit",
|
|
513
|
-
}));
|
|
514
|
-
}
|
|
515
|
-
}
|
|
516
|
-
return hints.length > 0
|
|
517
|
-
? `${occurrence.title} (${hints.join(", ")})`
|
|
518
|
-
: occurrence.title;
|
|
519
|
-
}
|
|
520
|
-
function narrowOccurrenceCandidates(matches) {
|
|
521
|
-
const actionableMatches = matches.filter((occurrence) => occurrence.state === "visible" || occurrence.state === "snoozed");
|
|
522
|
-
return actionableMatches.length > 0 ? actionableMatches : matches;
|
|
523
|
-
}
|
|
524
|
-
async function resolveOccurrence(service, target, domain) {
|
|
525
|
-
if (!target)
|
|
526
|
-
return { match: null, ambiguousCandidates: [] };
|
|
527
|
-
const overview = await service.getOverview();
|
|
528
|
-
const all = [
|
|
529
|
-
...overview.owner.occurrences,
|
|
530
|
-
...overview.agentOps.occurrences,
|
|
531
|
-
].filter((o) => (domain ? o.domain === domain : true));
|
|
532
|
-
const normalized = normalizeTitle(target);
|
|
533
|
-
// Exact ID match
|
|
534
|
-
const byId = all.find((o) => o.id === target);
|
|
535
|
-
if (byId)
|
|
536
|
-
return { match: byId, ambiguousCandidates: [] };
|
|
537
|
-
// Exact normalized-title match
|
|
538
|
-
const exactMatches = all.filter((o) => normalizeTitle(o.title) === normalized);
|
|
539
|
-
if (exactMatches.length === 1) {
|
|
540
|
-
return { match: exactMatches.at(0) ?? null, ambiguousCandidates: [] };
|
|
541
|
-
}
|
|
542
|
-
if (exactMatches.length > 1) {
|
|
543
|
-
const narrowedMatches = narrowOccurrenceCandidates(exactMatches);
|
|
544
|
-
if (narrowedMatches.length === 1) {
|
|
545
|
-
return { match: narrowedMatches.at(0) ?? null, ambiguousCandidates: [] };
|
|
546
|
-
}
|
|
547
|
-
return {
|
|
548
|
-
match: null,
|
|
549
|
-
ambiguousCandidates: narrowedMatches.map(formatOccurrenceDisambiguationLabel),
|
|
550
|
-
};
|
|
551
|
-
}
|
|
552
|
-
// Substring matches — disambiguate when multiple
|
|
553
|
-
const substringMatches = all.filter((o) => normalizeTitle(o.title).includes(normalized));
|
|
554
|
-
if (substringMatches.length === 1) {
|
|
555
|
-
return { match: substringMatches.at(0) ?? null, ambiguousCandidates: [] };
|
|
556
|
-
}
|
|
557
|
-
if (substringMatches.length > 1) {
|
|
558
|
-
const narrowedSubstringMatches = narrowOccurrenceCandidates(substringMatches);
|
|
559
|
-
if (narrowedSubstringMatches.length === 1) {
|
|
560
|
-
return {
|
|
561
|
-
match: narrowedSubstringMatches.at(0) ?? null,
|
|
562
|
-
ambiguousCandidates: [],
|
|
563
|
-
};
|
|
564
|
-
}
|
|
565
|
-
// Prefer startsWith over generic includes
|
|
566
|
-
const startsWithMatches = narrowedSubstringMatches.filter((o) => normalizeTitle(o.title).startsWith(normalized));
|
|
567
|
-
if (startsWithMatches.length === 1) {
|
|
568
|
-
return { match: startsWithMatches.at(0) ?? null, ambiguousCandidates: [] };
|
|
569
|
-
}
|
|
570
|
-
if (startsWithMatches.length > 1) {
|
|
571
|
-
return {
|
|
572
|
-
match: null,
|
|
573
|
-
ambiguousCandidates: startsWithMatches.map(formatOccurrenceDisambiguationLabel),
|
|
574
|
-
};
|
|
575
|
-
}
|
|
576
|
-
// Still ambiguous — return candidates for the caller to list
|
|
577
|
-
return {
|
|
578
|
-
match: null,
|
|
579
|
-
ambiguousCandidates: narrowedSubstringMatches.map(formatOccurrenceDisambiguationLabel),
|
|
580
|
-
};
|
|
581
|
-
}
|
|
582
|
-
const targetTokens = normalized.split(/\s+/).filter(Boolean);
|
|
583
|
-
if (targetTokens.length > 1) {
|
|
584
|
-
const tokenSetMatches = all.filter((occurrence) => {
|
|
585
|
-
const occurrenceTokens = new Set(normalizeTitle(occurrence.title).split(/\s+/).filter(Boolean));
|
|
586
|
-
return targetTokens.every((token) => occurrenceTokens.has(token));
|
|
587
|
-
});
|
|
588
|
-
if (tokenSetMatches.length === 1) {
|
|
589
|
-
return { match: tokenSetMatches.at(0) ?? null, ambiguousCandidates: [] };
|
|
590
|
-
}
|
|
591
|
-
if (tokenSetMatches.length > 1) {
|
|
592
|
-
const narrowedTokenSetMatches = narrowOccurrenceCandidates(tokenSetMatches);
|
|
593
|
-
if (narrowedTokenSetMatches.length === 1) {
|
|
594
|
-
return {
|
|
595
|
-
match: narrowedTokenSetMatches.at(0) ?? null,
|
|
596
|
-
ambiguousCandidates: [],
|
|
597
|
-
};
|
|
598
|
-
}
|
|
599
|
-
return {
|
|
600
|
-
match: null,
|
|
601
|
-
ambiguousCandidates: narrowedTokenSetMatches.map(formatOccurrenceDisambiguationLabel),
|
|
602
|
-
};
|
|
603
|
-
}
|
|
604
|
-
}
|
|
605
|
-
return { match: null, ambiguousCandidates: [] };
|
|
606
|
-
}
|
|
607
|
-
function deriveOccurrenceTargetFromIntent(intent, operation) {
|
|
608
|
-
const normalized = normalizeLifeInputText(intent);
|
|
609
|
-
if (!normalized) {
|
|
610
|
-
return null;
|
|
611
|
-
}
|
|
612
|
-
let candidate = normalized;
|
|
613
|
-
if (operation === "snooze_occurrence") {
|
|
614
|
-
candidate = candidate
|
|
615
|
-
.replace(/^(?:please\s+)?(?:snooze|postpone|push\b.*\bback|remind me later about)\s+/i, "")
|
|
616
|
-
.replace(/\bfor\s+\d+\s*(?:minutes?|hours?)\b.*$/i, "")
|
|
617
|
-
.replace(/\b(?:until|til)\b.+$/i, "")
|
|
618
|
-
.trim();
|
|
619
|
-
}
|
|
620
|
-
else if (operation === "skip_occurrence") {
|
|
621
|
-
candidate = candidate
|
|
622
|
-
.replace(/^(?:please\s+)?(?:skip|pass on)\s+/i, "")
|
|
623
|
-
.replace(/\b(?:today|tonight|for now)\b.*$/i, "")
|
|
624
|
-
.trim();
|
|
625
|
-
}
|
|
626
|
-
else if (operation === "complete_occurrence") {
|
|
627
|
-
candidate = candidate
|
|
628
|
-
.replace(/^(?:please\s+)?(?:mark\s+|i(?:'ve| have)?\s+|just\s+)?(?:done|completed|finished|did)\s+/i, "")
|
|
629
|
-
.replace(/\b(?:done|complete|completed|finished)\b.*$/i, "")
|
|
630
|
-
.trim();
|
|
631
|
-
}
|
|
632
|
-
return candidate.length > 0 ? candidate : null;
|
|
633
|
-
}
|
|
634
|
-
async function resolveOccurrenceWithIntentFallback(args) {
|
|
635
|
-
const direct = await resolveOccurrence(args.service, args.target, args.domain);
|
|
636
|
-
if (direct.match || direct.ambiguousCandidates.length > 0) {
|
|
637
|
-
return direct;
|
|
638
|
-
}
|
|
639
|
-
const fallbackTarget = deriveOccurrenceTargetFromIntent(args.intent, args.operation);
|
|
640
|
-
if (!fallbackTarget ||
|
|
641
|
-
(args.target &&
|
|
642
|
-
normalizeTitle(fallbackTarget) === normalizeTitle(args.target))) {
|
|
643
|
-
return direct;
|
|
644
|
-
}
|
|
645
|
-
return resolveOccurrence(args.service, fallbackTarget, args.domain);
|
|
646
|
-
}
|
|
647
|
-
function summarizeCadence(cadence) {
|
|
648
|
-
const cadenceWindows = Array.isArray(cadence.windows)
|
|
649
|
-
? (cadence.windows ?? []).filter((windowName) => typeof windowName === "string" && windowName.trim().length > 0)
|
|
650
|
-
: [];
|
|
651
|
-
switch (cadence.kind) {
|
|
652
|
-
case "once": {
|
|
653
|
-
const dueAt = new Date(cadence.dueAt);
|
|
654
|
-
if (Number.isNaN(dueAt.getTime())) {
|
|
655
|
-
return "once";
|
|
656
|
-
}
|
|
657
|
-
return `once on ${dueAt.toLocaleString(undefined, {
|
|
658
|
-
month: "short",
|
|
659
|
-
day: "numeric",
|
|
660
|
-
hour: "numeric",
|
|
661
|
-
minute: "2-digit",
|
|
662
|
-
timeZone: resolveDefaultTimeZone(),
|
|
663
|
-
})}`;
|
|
664
|
-
}
|
|
665
|
-
case "daily":
|
|
666
|
-
return cadenceWindows.length > 0
|
|
667
|
-
? `every day in ${cadenceWindows.join(", ")}`
|
|
668
|
-
: "every day";
|
|
669
|
-
case "times_per_day":
|
|
670
|
-
return cadence.slots
|
|
671
|
-
.map((slot) => slot.label?.trim() || `${slot.minuteOfDay}`)
|
|
672
|
-
.filter(Boolean)
|
|
673
|
-
.join(" and ");
|
|
674
|
-
case "interval":
|
|
675
|
-
return cadenceWindows.length > 0
|
|
676
|
-
? `every ${cadence.everyMinutes} minutes in ${cadenceWindows.join(", ")}`
|
|
677
|
-
: `every ${cadence.everyMinutes} minutes`;
|
|
678
|
-
case "weekly":
|
|
679
|
-
return `weekly on ${cadence.weekdays
|
|
680
|
-
.map((weekday) => [
|
|
681
|
-
"Sunday",
|
|
682
|
-
"Monday",
|
|
683
|
-
"Tuesday",
|
|
684
|
-
"Wednesday",
|
|
685
|
-
"Thursday",
|
|
686
|
-
"Friday",
|
|
687
|
-
"Saturday",
|
|
688
|
-
][weekday] ?? String(weekday))
|
|
689
|
-
.join(", ")}`;
|
|
690
|
-
}
|
|
691
|
-
}
|
|
692
|
-
function buildRuleBasedLifeReply(args) {
|
|
693
|
-
const context = args.context ?? {};
|
|
694
|
-
const updated = context.updated && typeof context.updated === "object"
|
|
695
|
-
? context.updated
|
|
696
|
-
: null;
|
|
697
|
-
const created = context.created && typeof context.created === "object"
|
|
698
|
-
? context.created
|
|
699
|
-
: null;
|
|
700
|
-
const title = (typeof updated?.title === "string" ? updated.title : null) ??
|
|
701
|
-
(typeof created?.title === "string" ? created.title : null) ??
|
|
702
|
-
(typeof context.title === "string" ? context.title : null) ??
|
|
703
|
-
null;
|
|
704
|
-
// Time-phrase nuance ("mornings now", "7pm now", etc.) is rendered by the
|
|
705
|
-
// LLM in renderGroundedActionReply via the additionalRules contract. The
|
|
706
|
-
// rule-based fallback intentionally only carries the title — never tries
|
|
707
|
-
// to parse English-only time phrases out of the intent.
|
|
708
|
-
switch (args.scenario) {
|
|
709
|
-
case "updated_definition":
|
|
710
|
-
if (title) {
|
|
711
|
-
return `${title} is updated.`;
|
|
712
|
-
}
|
|
713
|
-
break;
|
|
714
|
-
case "deleted_definition":
|
|
715
|
-
if (title) {
|
|
716
|
-
return `${title} is off your list.`;
|
|
717
|
-
}
|
|
718
|
-
break;
|
|
719
|
-
case "deleted_goal":
|
|
720
|
-
if (title) {
|
|
721
|
-
return `${title} is off your goals list.`;
|
|
722
|
-
}
|
|
723
|
-
break;
|
|
724
|
-
case "completed_occurrence":
|
|
725
|
-
if (title) {
|
|
726
|
-
return `Marked ${title} done.`;
|
|
727
|
-
}
|
|
728
|
-
break;
|
|
729
|
-
case "skipped_occurrence":
|
|
730
|
-
if (title) {
|
|
731
|
-
return `Okay, skipping ${title} for now.`;
|
|
732
|
-
}
|
|
733
|
-
break;
|
|
734
|
-
case "snoozed_occurrence":
|
|
735
|
-
if (title) {
|
|
736
|
-
return `Okay, I'll bring ${title} back a bit later.`;
|
|
737
|
-
}
|
|
738
|
-
break;
|
|
739
|
-
default:
|
|
740
|
-
break;
|
|
741
|
-
}
|
|
742
|
-
return args.fallback;
|
|
743
|
-
}
|
|
744
|
-
async function renderLifeActionReply(args) {
|
|
745
|
-
const { runtime, message, state, intent, scenario, fallback, context } = args;
|
|
746
|
-
const naturalFallback = buildRuleBasedLifeReply({
|
|
747
|
-
scenario,
|
|
748
|
-
intent,
|
|
749
|
-
fallback,
|
|
750
|
-
context,
|
|
751
|
-
});
|
|
752
|
-
return renderGroundedActionReply({
|
|
753
|
-
runtime,
|
|
754
|
-
message,
|
|
755
|
-
state,
|
|
756
|
-
intent,
|
|
757
|
-
domain: "lifeops",
|
|
758
|
-
scenario,
|
|
759
|
-
fallback: naturalFallback,
|
|
760
|
-
context,
|
|
761
|
-
preferCharacterVoice: true,
|
|
762
|
-
additionalRules: [
|
|
763
|
-
"Mirror the user's phrasing for time and date when possible.",
|
|
764
|
-
"Prefer phrases like tomorrow morning, every night, 7 am, or the user's own wording over robotic schedule language.",
|
|
765
|
-
"Never surface raw ISO timestamps unless the user used raw ISO timestamps.",
|
|
766
|
-
"If this is a preview, make clear it is not saved yet and the user can confirm or change it naturally.",
|
|
767
|
-
"If this is reply-only, do not pretend you saved or changed anything.",
|
|
768
|
-
],
|
|
769
|
-
});
|
|
770
|
-
}
|
|
771
|
-
function buildLifeClarificationFallback(args) {
|
|
772
|
-
const missing = new Set(args.missing);
|
|
773
|
-
if (args.operation === "create_goal") {
|
|
774
|
-
return "What do you want the goal to be?";
|
|
775
|
-
}
|
|
776
|
-
if (missing.has("title") && missing.has("schedule")) {
|
|
777
|
-
return "What do you want the todo to be, and when should it happen?";
|
|
778
|
-
}
|
|
779
|
-
if (missing.has("title")) {
|
|
780
|
-
return "What do you want it to be?";
|
|
781
|
-
}
|
|
782
|
-
if (missing.has("schedule")) {
|
|
783
|
-
return "When should it happen?";
|
|
784
|
-
}
|
|
785
|
-
return "Tell me a bit more about what you want to set up.";
|
|
786
|
-
}
|
|
787
|
-
function buildLifeServiceErrorFallback(error, intent) {
|
|
788
|
-
const normalized = error.message.toLowerCase();
|
|
789
|
-
if (normalized.includes("utc 'z' suffix") ||
|
|
790
|
-
normalized.includes("local datetime without 'z'") ||
|
|
791
|
-
normalized.includes("time didn't parse") ||
|
|
792
|
-
normalized.includes("invalid dueat") ||
|
|
793
|
-
normalized.includes("cadence.dueat")) {
|
|
794
|
-
return `I couldn't pin down the reminder time from "${intent}". Tell me the time again in plain language, like "Friday at 8 pm Pacific."`;
|
|
795
|
-
}
|
|
796
|
-
if (normalized.includes("when windowpreset is not provided") ||
|
|
797
|
-
normalized.includes("startat is required")) {
|
|
798
|
-
return "I still need the time for that reminder. Tell me when it should happen.";
|
|
799
|
-
}
|
|
800
|
-
if (error.status === 429 || normalized.includes("rate limit")) {
|
|
801
|
-
return "LifeOps is rate-limited right now. Try again in a bit.";
|
|
802
|
-
}
|
|
803
|
-
return "I couldn't finish that LifeOps change yet. Tell me the task and timing again, and I'll try it a different way.";
|
|
804
|
-
}
|
|
805
|
-
// ── Calendar/email formatters ─────────────────────────
|
|
806
|
-
const DEFAULT_WINDOW_SLOT_TIMES = {
|
|
807
|
-
morning: {
|
|
808
|
-
minuteOfDay: 8 * 60,
|
|
809
|
-
durationMinutes: 45,
|
|
810
|
-
label: "Morning",
|
|
811
|
-
},
|
|
812
|
-
afternoon: {
|
|
813
|
-
minuteOfDay: 13 * 60,
|
|
814
|
-
durationMinutes: 45,
|
|
815
|
-
label: "Afternoon",
|
|
816
|
-
},
|
|
817
|
-
evening: {
|
|
818
|
-
minuteOfDay: 18 * 60,
|
|
819
|
-
durationMinutes: 45,
|
|
820
|
-
label: "Evening",
|
|
821
|
-
},
|
|
822
|
-
night: {
|
|
823
|
-
minuteOfDay: 21 * 60,
|
|
824
|
-
durationMinutes: 45,
|
|
825
|
-
label: "Night",
|
|
826
|
-
},
|
|
827
|
-
};
|
|
828
|
-
function buildSlotsFromWindows(windows) {
|
|
829
|
-
return windows.map((window, index) => {
|
|
830
|
-
const preset = DEFAULT_WINDOW_SLOT_TIMES[window];
|
|
831
|
-
return {
|
|
832
|
-
key: windows.indexOf(window) === index ? window : `${window}-${index + 1}`,
|
|
833
|
-
label: preset.label,
|
|
834
|
-
minuteOfDay: preset.minuteOfDay,
|
|
835
|
-
durationMinutes: preset.durationMinutes,
|
|
836
|
-
};
|
|
837
|
-
});
|
|
838
|
-
}
|
|
839
|
-
function buildDistributedDailySlots(count) {
|
|
840
|
-
const normalizedCount = Math.max(1, Math.min(6, count));
|
|
841
|
-
let minutes;
|
|
842
|
-
switch (normalizedCount) {
|
|
843
|
-
case 1:
|
|
844
|
-
minutes = [9 * 60];
|
|
845
|
-
break;
|
|
846
|
-
case 2:
|
|
847
|
-
minutes = [8 * 60, 21 * 60];
|
|
848
|
-
break;
|
|
849
|
-
case 3:
|
|
850
|
-
minutes = [8 * 60, 13 * 60, 20 * 60];
|
|
851
|
-
break;
|
|
852
|
-
case 4:
|
|
853
|
-
minutes = [8 * 60, 12 * 60, 16 * 60, 20 * 60];
|
|
854
|
-
break;
|
|
855
|
-
case 5:
|
|
856
|
-
minutes = [8 * 60, 11 * 60, 14 * 60, 17 * 60, 20 * 60];
|
|
857
|
-
break;
|
|
858
|
-
default:
|
|
859
|
-
minutes = [8 * 60, 10 * 60, 12 * 60, 14 * 60, 17 * 60, 20 * 60];
|
|
860
|
-
break;
|
|
861
|
-
}
|
|
862
|
-
return minutes.map((minuteOfDay, index) => ({
|
|
863
|
-
key: `slot-${index + 1}`,
|
|
864
|
-
label: `Time ${index + 1}`,
|
|
865
|
-
minuteOfDay,
|
|
866
|
-
durationMinutes: 45,
|
|
867
|
-
}));
|
|
868
|
-
}
|
|
869
|
-
function inferWindowFromMinuteOfDay(minuteOfDay) {
|
|
870
|
-
if (minuteOfDay < 12 * 60) {
|
|
871
|
-
return "morning";
|
|
872
|
-
}
|
|
873
|
-
if (minuteOfDay < 17 * 60) {
|
|
874
|
-
return "afternoon";
|
|
875
|
-
}
|
|
876
|
-
if (minuteOfDay < 21 * 60) {
|
|
877
|
-
return "evening";
|
|
878
|
-
}
|
|
879
|
-
return "night";
|
|
880
|
-
}
|
|
881
|
-
function buildSingleDailySlot(minuteOfDay, durationMinutes = 45) {
|
|
882
|
-
return {
|
|
883
|
-
key: `time-${minuteOfDay}`,
|
|
884
|
-
label: formatMinuteOfDayLabel(minuteOfDay),
|
|
885
|
-
minuteOfDay,
|
|
886
|
-
durationMinutes,
|
|
887
|
-
};
|
|
888
|
-
}
|
|
889
|
-
function buildCustomTimeWindowPolicy(minuteOfDay, timeZone) {
|
|
890
|
-
const basePolicy = resolveDefaultWindowPolicy(timeZone);
|
|
891
|
-
return {
|
|
892
|
-
timezone: basePolicy.timezone,
|
|
893
|
-
windows: [
|
|
894
|
-
...basePolicy.windows,
|
|
895
|
-
{
|
|
896
|
-
name: "custom",
|
|
897
|
-
label: formatMinuteOfDayLabel(minuteOfDay),
|
|
898
|
-
startMinute: minuteOfDay,
|
|
899
|
-
endMinute: Math.min(minuteOfDay + 1, 24 * 60),
|
|
900
|
-
},
|
|
901
|
-
],
|
|
902
|
-
};
|
|
903
|
-
}
|
|
904
|
-
function formatMinuteOfDayLabel(minuteOfDay) {
|
|
905
|
-
const hour24 = Math.floor(minuteOfDay / 60);
|
|
906
|
-
const minute = minuteOfDay % 60;
|
|
907
|
-
const meridiem = hour24 >= 12 ? "pm" : "am";
|
|
908
|
-
const hour12 = hour24 % 12 === 0 ? 12 : hour24 % 12;
|
|
909
|
-
return minute === 0
|
|
910
|
-
? `${hour12}${meridiem}`
|
|
911
|
-
: `${hour12}:${String(minute).padStart(2, "0")}${meridiem}`;
|
|
912
|
-
}
|
|
913
|
-
function parseClockToken(token) {
|
|
914
|
-
const normalized = token.trim().toLowerCase();
|
|
915
|
-
if (normalized === "noon") {
|
|
916
|
-
return 12 * 60;
|
|
917
|
-
}
|
|
918
|
-
if (normalized === "midnight") {
|
|
919
|
-
return 0;
|
|
920
|
-
}
|
|
921
|
-
const match = normalized.match(/^(\d{1,2})(?::(\d{2}))?\s*(am|pm)$/);
|
|
922
|
-
if (!match) {
|
|
923
|
-
return null;
|
|
924
|
-
}
|
|
925
|
-
const hour = Number(match[1]);
|
|
926
|
-
const minute = Number(match[2] ?? "0");
|
|
927
|
-
if (!Number.isFinite(hour) || !Number.isFinite(minute) || minute >= 60) {
|
|
928
|
-
return null;
|
|
929
|
-
}
|
|
930
|
-
if (hour < 1 || hour > 12) {
|
|
931
|
-
return null;
|
|
932
|
-
}
|
|
933
|
-
const meridiem = match[3];
|
|
934
|
-
const normalizedHour = meridiem === "am" ? hour % 12 : hour % 12 === 0 ? 12 : (hour % 12) + 12;
|
|
935
|
-
return normalizedHour * 60 + minute;
|
|
936
|
-
}
|
|
937
|
-
function parseTimeOfDayToken(token) {
|
|
938
|
-
const normalized = normalizeLifeInputText(token).toLowerCase();
|
|
939
|
-
const hhmmMatch = normalized.match(/^(\d{1,2}):(\d{2})$/);
|
|
940
|
-
if (hhmmMatch) {
|
|
941
|
-
const hour = Number(hhmmMatch[1]);
|
|
942
|
-
const minute = Number(hhmmMatch[2]);
|
|
943
|
-
if (Number.isFinite(hour) &&
|
|
944
|
-
Number.isFinite(minute) &&
|
|
945
|
-
hour >= 0 &&
|
|
946
|
-
hour <= 23 &&
|
|
947
|
-
minute >= 0 &&
|
|
948
|
-
minute < 60) {
|
|
949
|
-
return hour * 60 + minute;
|
|
950
|
-
}
|
|
951
|
-
}
|
|
952
|
-
return parseClockToken(normalized);
|
|
953
|
-
}
|
|
954
|
-
function buildOneOffDueAtFromMinuteOfDay(args) {
|
|
955
|
-
const now = args.now ?? new Date();
|
|
956
|
-
const timeZone = args.timeZone ?? resolveDefaultTimeZone();
|
|
957
|
-
const nowParts = getZonedDateParts(now, timeZone);
|
|
958
|
-
let localDate = {
|
|
959
|
-
year: nowParts.year,
|
|
960
|
-
month: nowParts.month,
|
|
961
|
-
day: nowParts.day,
|
|
962
|
-
};
|
|
963
|
-
const buildCandidate = () => buildUtcDateFromLocalParts(timeZone, {
|
|
964
|
-
...localDate,
|
|
965
|
-
hour: Math.floor(args.minuteOfDay / 60),
|
|
966
|
-
minute: args.minuteOfDay % 60,
|
|
967
|
-
second: 0,
|
|
968
|
-
});
|
|
969
|
-
let candidate = buildCandidate();
|
|
970
|
-
if (candidate.getTime() <= now.getTime()) {
|
|
971
|
-
localDate = addDaysToLocalDate(localDate, 1);
|
|
972
|
-
candidate = buildCandidate();
|
|
973
|
-
}
|
|
974
|
-
return candidate.toISOString();
|
|
975
|
-
}
|
|
976
|
-
function mergeMetadataRecords(...records) {
|
|
977
|
-
const merged = Object.assign({}, ...records.filter((record) => record != null && Object.keys(record).length > 0));
|
|
978
|
-
return Object.keys(merged).length > 0 ? merged : undefined;
|
|
979
|
-
}
|
|
980
|
-
function extractExplicitDailySlots(intent) {
|
|
981
|
-
const tokens = [
|
|
982
|
-
...intent.matchAll(/\b(\d{1,2}(?::\d{2})?\s*(?:am|pm)|noon|midnight)\b/gi),
|
|
983
|
-
]
|
|
984
|
-
.map((match) => match[1])
|
|
985
|
-
.filter((token) => typeof token === "string" && token.length > 0);
|
|
986
|
-
const seen = new Set();
|
|
987
|
-
const slots = [];
|
|
988
|
-
for (const [index, token] of tokens.entries()) {
|
|
989
|
-
const minuteOfDay = parseClockToken(token);
|
|
990
|
-
if (minuteOfDay === null || seen.has(minuteOfDay)) {
|
|
991
|
-
continue;
|
|
992
|
-
}
|
|
993
|
-
seen.add(minuteOfDay);
|
|
994
|
-
slots.push({
|
|
995
|
-
key: `clock-${index + 1}`,
|
|
996
|
-
label: token.trim(),
|
|
997
|
-
minuteOfDay,
|
|
998
|
-
durationMinutes: 45,
|
|
999
|
-
});
|
|
1000
|
-
}
|
|
1001
|
-
return slots.sort((left, right) => left.minuteOfDay - right.minuteOfDay);
|
|
1002
|
-
}
|
|
1003
|
-
function normalizeLifeWindows(value) {
|
|
1004
|
-
const values = Array.isArray(value) ? value : value == null ? [] : [value];
|
|
1005
|
-
const normalized = values.flatMap((entry) => {
|
|
1006
|
-
if (typeof entry !== "string") {
|
|
1007
|
-
return [];
|
|
1008
|
-
}
|
|
1009
|
-
const lower = normalizeLifeInputText(entry).toLowerCase();
|
|
1010
|
-
if (lower === "morning")
|
|
1011
|
-
return ["morning"];
|
|
1012
|
-
if (lower === "afternoon")
|
|
1013
|
-
return ["afternoon"];
|
|
1014
|
-
if (lower === "evening")
|
|
1015
|
-
return ["evening"];
|
|
1016
|
-
if (lower === "night")
|
|
1017
|
-
return ["night"];
|
|
1018
|
-
return [];
|
|
1019
|
-
});
|
|
1020
|
-
return [...new Set(normalized)];
|
|
1021
|
-
}
|
|
1022
|
-
function normalizeCadenceDetail(value) {
|
|
1023
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
1024
|
-
return undefined;
|
|
1025
|
-
}
|
|
1026
|
-
const record = value;
|
|
1027
|
-
const cadenceKind = typeof record.kind === "string"
|
|
1028
|
-
? normalizeLifeInputText(record.kind).toLowerCase()
|
|
1029
|
-
: typeof record.type === "string"
|
|
1030
|
-
? normalizeLifeInputText(record.type).toLowerCase()
|
|
1031
|
-
: "";
|
|
1032
|
-
if (!cadenceKind) {
|
|
1033
|
-
return undefined;
|
|
1034
|
-
}
|
|
1035
|
-
if (cadenceKind === "once" && typeof record.dueAt === "string") {
|
|
1036
|
-
return {
|
|
1037
|
-
kind: "once",
|
|
1038
|
-
dueAt: record.dueAt,
|
|
1039
|
-
};
|
|
1040
|
-
}
|
|
1041
|
-
if (cadenceKind === "interval") {
|
|
1042
|
-
const everyMinutes = typeof record.everyMinutes === "number"
|
|
1043
|
-
? record.everyMinutes
|
|
1044
|
-
: typeof record.everyMinutes === "string"
|
|
1045
|
-
? Number(record.everyMinutes)
|
|
1046
|
-
: typeof record.minutes === "number"
|
|
1047
|
-
? record.minutes
|
|
1048
|
-
: typeof record.minutes === "string"
|
|
1049
|
-
? Number(record.minutes)
|
|
1050
|
-
: NaN;
|
|
1051
|
-
if (Number.isFinite(everyMinutes) && everyMinutes > 0) {
|
|
1052
|
-
return {
|
|
1053
|
-
kind: "interval",
|
|
1054
|
-
everyMinutes,
|
|
1055
|
-
windows: normalizeLifeWindows(record.windows),
|
|
1056
|
-
};
|
|
1057
|
-
}
|
|
1058
|
-
return undefined;
|
|
1059
|
-
}
|
|
1060
|
-
if (cadenceKind === "weekly") {
|
|
1061
|
-
const weekdays = Array.isArray(record.weekdays)
|
|
1062
|
-
? record.weekdays
|
|
1063
|
-
.map((entry) => typeof entry === "number"
|
|
1064
|
-
? entry
|
|
1065
|
-
: typeof entry === "string"
|
|
1066
|
-
? Number(entry)
|
|
1067
|
-
: NaN)
|
|
1068
|
-
.filter((entry) => Number.isFinite(entry))
|
|
1069
|
-
: [];
|
|
1070
|
-
if (weekdays.length > 0) {
|
|
1071
|
-
return {
|
|
1072
|
-
kind: "weekly",
|
|
1073
|
-
weekdays,
|
|
1074
|
-
windows: normalizeLifeWindows(record.windows),
|
|
1075
|
-
};
|
|
1076
|
-
}
|
|
1077
|
-
return undefined;
|
|
1078
|
-
}
|
|
1079
|
-
const explicitTimes = Array.isArray(record.times)
|
|
1080
|
-
? record.times
|
|
1081
|
-
.map((entry) => typeof entry === "string" ? parseTimeOfDayToken(entry) : null)
|
|
1082
|
-
.filter((entry) => entry !== null)
|
|
1083
|
-
: [];
|
|
1084
|
-
if (explicitTimes.length > 0) {
|
|
1085
|
-
return {
|
|
1086
|
-
kind: "times_per_day",
|
|
1087
|
-
slots: explicitTimes.map((minuteOfDay, index) => ({
|
|
1088
|
-
key: `time-${index + 1}`,
|
|
1089
|
-
label: formatMinuteOfDayLabel(minuteOfDay),
|
|
1090
|
-
minuteOfDay,
|
|
1091
|
-
durationMinutes: 45,
|
|
1092
|
-
})),
|
|
1093
|
-
visibilityLeadMinutes: 90,
|
|
1094
|
-
visibilityLagMinutes: 180,
|
|
1095
|
-
};
|
|
1096
|
-
}
|
|
1097
|
-
if (cadenceKind === "times_per_day") {
|
|
1098
|
-
if (Array.isArray(record.slots)) {
|
|
1099
|
-
const slots = record.slots
|
|
1100
|
-
.map((entry, index) => {
|
|
1101
|
-
if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
|
|
1102
|
-
return null;
|
|
1103
|
-
}
|
|
1104
|
-
const slot = entry;
|
|
1105
|
-
const minuteOfDay = typeof slot.minuteOfDay === "number"
|
|
1106
|
-
? slot.minuteOfDay
|
|
1107
|
-
: typeof slot.minuteOfDay === "string"
|
|
1108
|
-
? Number(slot.minuteOfDay)
|
|
1109
|
-
: null;
|
|
1110
|
-
if (minuteOfDay === null || !Number.isFinite(minuteOfDay)) {
|
|
1111
|
-
return null;
|
|
1112
|
-
}
|
|
1113
|
-
return {
|
|
1114
|
-
key: typeof slot.key === "string" && slot.key.trim().length > 0
|
|
1115
|
-
? slot.key
|
|
1116
|
-
: `slot-${index + 1}`,
|
|
1117
|
-
label: typeof slot.label === "string" && slot.label.trim().length > 0
|
|
1118
|
-
? slot.label
|
|
1119
|
-
: formatMinuteOfDayLabel(minuteOfDay),
|
|
1120
|
-
minuteOfDay,
|
|
1121
|
-
durationMinutes: typeof slot.durationMinutes === "number" &&
|
|
1122
|
-
Number.isFinite(slot.durationMinutes) &&
|
|
1123
|
-
slot.durationMinutes > 0
|
|
1124
|
-
? slot.durationMinutes
|
|
1125
|
-
: 45,
|
|
1126
|
-
};
|
|
1127
|
-
})
|
|
1128
|
-
.filter((entry) => entry !== null);
|
|
1129
|
-
if (slots.length > 0) {
|
|
1130
|
-
return {
|
|
1131
|
-
kind: "times_per_day",
|
|
1132
|
-
slots,
|
|
1133
|
-
visibilityLeadMinutes: typeof record.visibilityLeadMinutes === "number"
|
|
1134
|
-
? record.visibilityLeadMinutes
|
|
1135
|
-
: 90,
|
|
1136
|
-
visibilityLagMinutes: typeof record.visibilityLagMinutes === "number"
|
|
1137
|
-
? record.visibilityLagMinutes
|
|
1138
|
-
: 180,
|
|
1139
|
-
};
|
|
1140
|
-
}
|
|
1141
|
-
}
|
|
1142
|
-
const count = typeof record.count === "number"
|
|
1143
|
-
? record.count
|
|
1144
|
-
: typeof record.count === "string"
|
|
1145
|
-
? Number(record.count)
|
|
1146
|
-
: NaN;
|
|
1147
|
-
if (Number.isFinite(count) && count > 0) {
|
|
1148
|
-
return {
|
|
1149
|
-
kind: "times_per_day",
|
|
1150
|
-
slots: buildDistributedDailySlots(count),
|
|
1151
|
-
visibilityLeadMinutes: 90,
|
|
1152
|
-
visibilityLagMinutes: 180,
|
|
1153
|
-
};
|
|
1154
|
-
}
|
|
1155
|
-
}
|
|
1156
|
-
if (cadenceKind === "daily") {
|
|
1157
|
-
const windows = normalizeLifeWindows(record.windows ?? record.window);
|
|
1158
|
-
if (windows.length > 0) {
|
|
1159
|
-
return {
|
|
1160
|
-
kind: "daily",
|
|
1161
|
-
windows,
|
|
1162
|
-
};
|
|
1163
|
-
}
|
|
1164
|
-
return {
|
|
1165
|
-
kind: "daily",
|
|
1166
|
-
windows: ["morning"],
|
|
1167
|
-
};
|
|
1168
|
-
}
|
|
1169
|
-
return undefined;
|
|
1170
|
-
}
|
|
1171
|
-
/**
|
|
1172
|
-
* Convert LLM-extracted params into a typed LifeOpsCadence.
|
|
1173
|
-
* Returns null when the LLM output is insufficient to construct a
|
|
1174
|
-
* valid cadence, letting the caller fall back to regex-derived values.
|
|
1175
|
-
*/
|
|
1176
|
-
function buildCadenceFromLlmParams(params, context) {
|
|
1177
|
-
const kind = params.cadenceKind;
|
|
1178
|
-
if (!kind)
|
|
1179
|
-
return null;
|
|
1180
|
-
const effectiveTimeZone = context?.timeZone;
|
|
1181
|
-
const timeOfDayMinute = typeof params.timeOfDay === "string"
|
|
1182
|
-
? parseTimeOfDayToken(params.timeOfDay)
|
|
1183
|
-
: null;
|
|
1184
|
-
const explicitSlots = typeof context?.intent === "string"
|
|
1185
|
-
? extractExplicitDailySlots(context.intent)
|
|
1186
|
-
: [];
|
|
1187
|
-
const slotDuration = typeof params.durationMinutes === "number" && params.durationMinutes > 0
|
|
1188
|
-
? params.durationMinutes
|
|
1189
|
-
: 45;
|
|
1190
|
-
const windows = (params.windows ?? []).filter((w) => w === "morning" || w === "afternoon" || w === "evening" || w === "night");
|
|
1191
|
-
const effectiveWindows = windows.length > 0
|
|
1192
|
-
? windows
|
|
1193
|
-
: timeOfDayMinute !== null
|
|
1194
|
-
? [inferWindowFromMinuteOfDay(timeOfDayMinute)]
|
|
1195
|
-
: ["morning"];
|
|
1196
|
-
if (kind === "once") {
|
|
1197
|
-
if (timeOfDayMinute !== null) {
|
|
1198
|
-
return {
|
|
1199
|
-
cadence: {
|
|
1200
|
-
kind: "once",
|
|
1201
|
-
dueAt: buildOneOffDueAtFromMinuteOfDay({
|
|
1202
|
-
minuteOfDay: timeOfDayMinute,
|
|
1203
|
-
now: context?.now,
|
|
1204
|
-
timeZone: effectiveTimeZone,
|
|
1205
|
-
}),
|
|
1206
|
-
},
|
|
1207
|
-
};
|
|
1208
|
-
}
|
|
1209
|
-
return { cadence: { kind: "once", dueAt: new Date().toISOString() } };
|
|
1210
|
-
}
|
|
1211
|
-
if (kind === "daily") {
|
|
1212
|
-
if (explicitSlots.length >= 2) {
|
|
1213
|
-
return {
|
|
1214
|
-
cadence: {
|
|
1215
|
-
kind: "times_per_day",
|
|
1216
|
-
slots: explicitSlots.map((slot) => ({
|
|
1217
|
-
...slot,
|
|
1218
|
-
durationMinutes: slot.durationMinutes ?? slotDuration,
|
|
1219
|
-
})),
|
|
1220
|
-
visibilityLeadMinutes: 90,
|
|
1221
|
-
visibilityLagMinutes: 180,
|
|
1222
|
-
},
|
|
1223
|
-
};
|
|
1224
|
-
}
|
|
1225
|
-
if (timeOfDayMinute !== null) {
|
|
1226
|
-
return {
|
|
1227
|
-
cadence: {
|
|
1228
|
-
kind: "times_per_day",
|
|
1229
|
-
slots: [buildSingleDailySlot(timeOfDayMinute, slotDuration)],
|
|
1230
|
-
visibilityLeadMinutes: 90,
|
|
1231
|
-
visibilityLagMinutes: 180,
|
|
1232
|
-
},
|
|
1233
|
-
};
|
|
1234
|
-
}
|
|
1235
|
-
if (effectiveWindows.length >= 2) {
|
|
1236
|
-
return {
|
|
1237
|
-
cadence: {
|
|
1238
|
-
kind: "times_per_day",
|
|
1239
|
-
slots: buildSlotsFromWindows(effectiveWindows),
|
|
1240
|
-
visibilityLeadMinutes: 90,
|
|
1241
|
-
visibilityLagMinutes: 180,
|
|
1242
|
-
},
|
|
1243
|
-
};
|
|
1244
|
-
}
|
|
1245
|
-
return { cadence: { kind: "daily", windows: effectiveWindows } };
|
|
1246
|
-
}
|
|
1247
|
-
if (kind === "weekly") {
|
|
1248
|
-
const weekdays = params.weekdays;
|
|
1249
|
-
if (!weekdays || weekdays.length === 0)
|
|
1250
|
-
return null;
|
|
1251
|
-
if (timeOfDayMinute !== null) {
|
|
1252
|
-
return {
|
|
1253
|
-
cadence: { kind: "weekly", weekdays, windows: ["custom"] },
|
|
1254
|
-
windowPolicy: buildCustomTimeWindowPolicy(timeOfDayMinute, effectiveTimeZone ?? resolveDefaultTimeZone()),
|
|
1255
|
-
};
|
|
1256
|
-
}
|
|
1257
|
-
return { cadence: { kind: "weekly", weekdays, windows: effectiveWindows } };
|
|
1258
|
-
}
|
|
1259
|
-
if (kind === "interval") {
|
|
1260
|
-
const everyMinutes = params.everyMinutes;
|
|
1261
|
-
if (!everyMinutes || everyMinutes <= 0)
|
|
1262
|
-
return null;
|
|
1263
|
-
return {
|
|
1264
|
-
cadence: {
|
|
1265
|
-
kind: "interval",
|
|
1266
|
-
everyMinutes,
|
|
1267
|
-
windows: effectiveWindows,
|
|
1268
|
-
startMinuteOfDay: timeOfDayMinute ?? undefined,
|
|
1269
|
-
durationMinutes: typeof params.durationMinutes === "number" &&
|
|
1270
|
-
params.durationMinutes > 0
|
|
1271
|
-
? params.durationMinutes
|
|
1272
|
-
: undefined,
|
|
1273
|
-
},
|
|
1274
|
-
};
|
|
1275
|
-
}
|
|
1276
|
-
if (kind === "times_per_day") {
|
|
1277
|
-
if (explicitSlots.length >= 2) {
|
|
1278
|
-
return {
|
|
1279
|
-
cadence: {
|
|
1280
|
-
kind: "times_per_day",
|
|
1281
|
-
slots: explicitSlots.map((slot) => ({
|
|
1282
|
-
...slot,
|
|
1283
|
-
durationMinutes: slot.durationMinutes ?? slotDuration,
|
|
1284
|
-
})),
|
|
1285
|
-
visibilityLeadMinutes: 90,
|
|
1286
|
-
visibilityLagMinutes: 180,
|
|
1287
|
-
},
|
|
1288
|
-
};
|
|
1289
|
-
}
|
|
1290
|
-
if (timeOfDayMinute !== null) {
|
|
1291
|
-
return {
|
|
1292
|
-
cadence: {
|
|
1293
|
-
kind: "times_per_day",
|
|
1294
|
-
slots: [buildSingleDailySlot(timeOfDayMinute, slotDuration)],
|
|
1295
|
-
visibilityLeadMinutes: 90,
|
|
1296
|
-
visibilityLagMinutes: 180,
|
|
1297
|
-
},
|
|
1298
|
-
};
|
|
1299
|
-
}
|
|
1300
|
-
const count = params.timesPerDay;
|
|
1301
|
-
if (!count || count <= 0)
|
|
1302
|
-
return null;
|
|
1303
|
-
return {
|
|
1304
|
-
cadence: {
|
|
1305
|
-
kind: "times_per_day",
|
|
1306
|
-
slots: buildDistributedDailySlots(count).map((slot) => ({
|
|
1307
|
-
...slot,
|
|
1308
|
-
durationMinutes: slotDuration,
|
|
1309
|
-
})),
|
|
1310
|
-
visibilityLeadMinutes: 90,
|
|
1311
|
-
visibilityLagMinutes: 180,
|
|
1312
|
-
},
|
|
1313
|
-
};
|
|
1314
|
-
}
|
|
1315
|
-
return null;
|
|
1316
|
-
}
|
|
1317
|
-
function buildCadenceFromUpdateFields(args) {
|
|
1318
|
-
const { currentCadence, currentWindowPolicy, timeZone, update } = args;
|
|
1319
|
-
const kind = (update.cadenceKind ??
|
|
1320
|
-
currentCadence.kind);
|
|
1321
|
-
const requestedWindows = normalizeLifeWindows(update.windows ?? []);
|
|
1322
|
-
const timeOfDayMinute = typeof update.timeOfDay === "string"
|
|
1323
|
-
? parseTimeOfDayToken(update.timeOfDay)
|
|
1324
|
-
: null;
|
|
1325
|
-
if (kind === "interval") {
|
|
1326
|
-
const everyMinutes = update.everyMinutes ??
|
|
1327
|
-
(currentCadence.kind === "interval" ? currentCadence.everyMinutes : null);
|
|
1328
|
-
if (!everyMinutes || everyMinutes <= 0) {
|
|
1329
|
-
return null;
|
|
1330
|
-
}
|
|
1331
|
-
const windows = requestedWindows.length > 0
|
|
1332
|
-
? requestedWindows
|
|
1333
|
-
: currentCadence.kind === "interval" &&
|
|
1334
|
-
currentCadence.windows.length > 0
|
|
1335
|
-
? normalizeLifeWindows(currentCadence.windows)
|
|
1336
|
-
: timeOfDayMinute !== null
|
|
1337
|
-
? [inferWindowFromMinuteOfDay(timeOfDayMinute)]
|
|
1338
|
-
: ["morning"];
|
|
1339
|
-
return {
|
|
1340
|
-
cadence: {
|
|
1341
|
-
kind: "interval",
|
|
1342
|
-
everyMinutes,
|
|
1343
|
-
windows,
|
|
1344
|
-
startMinuteOfDay: timeOfDayMinute ??
|
|
1345
|
-
(currentCadence.kind === "interval"
|
|
1346
|
-
? currentCadence.startMinuteOfDay
|
|
1347
|
-
: undefined),
|
|
1348
|
-
maxOccurrencesPerDay: currentCadence.kind === "interval"
|
|
1349
|
-
? currentCadence.maxOccurrencesPerDay
|
|
1350
|
-
: undefined,
|
|
1351
|
-
durationMinutes: currentCadence.kind === "interval"
|
|
1352
|
-
? currentCadence.durationMinutes
|
|
1353
|
-
: undefined,
|
|
1354
|
-
visibilityLeadMinutes: currentCadence.kind === "interval"
|
|
1355
|
-
? currentCadence.visibilityLeadMinutes
|
|
1356
|
-
: undefined,
|
|
1357
|
-
visibilityLagMinutes: currentCadence.kind === "interval"
|
|
1358
|
-
? currentCadence.visibilityLagMinutes
|
|
1359
|
-
: undefined,
|
|
1360
|
-
},
|
|
1361
|
-
};
|
|
1362
|
-
}
|
|
1363
|
-
if (kind === "weekly") {
|
|
1364
|
-
const weekdays = update.weekdays ??
|
|
1365
|
-
(currentCadence.kind === "weekly" ? currentCadence.weekdays : null);
|
|
1366
|
-
if (!weekdays || weekdays.length === 0) {
|
|
1367
|
-
return null;
|
|
1368
|
-
}
|
|
1369
|
-
if (timeOfDayMinute !== null) {
|
|
1370
|
-
return {
|
|
1371
|
-
cadence: {
|
|
1372
|
-
kind: "weekly",
|
|
1373
|
-
weekdays,
|
|
1374
|
-
windows: ["custom"],
|
|
1375
|
-
visibilityLeadMinutes: currentCadence.kind === "weekly"
|
|
1376
|
-
? currentCadence.visibilityLeadMinutes
|
|
1377
|
-
: undefined,
|
|
1378
|
-
visibilityLagMinutes: currentCadence.kind === "weekly"
|
|
1379
|
-
? currentCadence.visibilityLagMinutes
|
|
1380
|
-
: undefined,
|
|
1381
|
-
},
|
|
1382
|
-
windowPolicy: buildCustomTimeWindowPolicy(timeOfDayMinute, timeZone),
|
|
1383
|
-
};
|
|
1384
|
-
}
|
|
1385
|
-
return {
|
|
1386
|
-
cadence: {
|
|
1387
|
-
kind: "weekly",
|
|
1388
|
-
weekdays,
|
|
1389
|
-
windows: requestedWindows.length > 0
|
|
1390
|
-
? requestedWindows
|
|
1391
|
-
: currentCadence.kind === "weekly" &&
|
|
1392
|
-
currentCadence.windows.length > 0
|
|
1393
|
-
? currentCadence.windows
|
|
1394
|
-
: ["morning"],
|
|
1395
|
-
visibilityLeadMinutes: currentCadence.kind === "weekly"
|
|
1396
|
-
? currentCadence.visibilityLeadMinutes
|
|
1397
|
-
: undefined,
|
|
1398
|
-
visibilityLagMinutes: currentCadence.kind === "weekly"
|
|
1399
|
-
? currentCadence.visibilityLagMinutes
|
|
1400
|
-
: undefined,
|
|
1401
|
-
},
|
|
1402
|
-
windowPolicy: currentWindowPolicy.windows.some((window) => (requestedWindows.length > 0
|
|
1403
|
-
? requestedWindows
|
|
1404
|
-
: ["morning"]).includes(window.name))
|
|
1405
|
-
? undefined
|
|
1406
|
-
: resolveDefaultWindowPolicy(timeZone),
|
|
1407
|
-
};
|
|
1408
|
-
}
|
|
1409
|
-
if (kind === "daily") {
|
|
1410
|
-
if (timeOfDayMinute !== null) {
|
|
1411
|
-
return {
|
|
1412
|
-
cadence: {
|
|
1413
|
-
kind: "times_per_day",
|
|
1414
|
-
slots: [buildSingleDailySlot(timeOfDayMinute)],
|
|
1415
|
-
visibilityLeadMinutes: 90,
|
|
1416
|
-
visibilityLagMinutes: 180,
|
|
1417
|
-
},
|
|
1418
|
-
};
|
|
1419
|
-
}
|
|
1420
|
-
return {
|
|
1421
|
-
cadence: {
|
|
1422
|
-
kind: "daily",
|
|
1423
|
-
windows: requestedWindows.length > 0
|
|
1424
|
-
? requestedWindows
|
|
1425
|
-
: currentCadence.kind === "daily" &&
|
|
1426
|
-
currentCadence.windows.length > 0
|
|
1427
|
-
? currentCadence.windows
|
|
1428
|
-
: ["morning"],
|
|
1429
|
-
visibilityLeadMinutes: currentCadence.kind === "daily"
|
|
1430
|
-
? currentCadence.visibilityLeadMinutes
|
|
1431
|
-
: undefined,
|
|
1432
|
-
visibilityLagMinutes: currentCadence.kind === "daily"
|
|
1433
|
-
? currentCadence.visibilityLagMinutes
|
|
1434
|
-
: undefined,
|
|
1435
|
-
},
|
|
1436
|
-
};
|
|
1437
|
-
}
|
|
1438
|
-
if (kind === "times_per_day") {
|
|
1439
|
-
if (timeOfDayMinute !== null) {
|
|
1440
|
-
return {
|
|
1441
|
-
cadence: {
|
|
1442
|
-
kind: "times_per_day",
|
|
1443
|
-
slots: [buildSingleDailySlot(timeOfDayMinute)],
|
|
1444
|
-
visibilityLeadMinutes: 90,
|
|
1445
|
-
visibilityLagMinutes: 180,
|
|
1446
|
-
},
|
|
1447
|
-
};
|
|
1448
|
-
}
|
|
1449
|
-
if (requestedWindows.length > 0) {
|
|
1450
|
-
return {
|
|
1451
|
-
cadence: {
|
|
1452
|
-
kind: "times_per_day",
|
|
1453
|
-
slots: buildSlotsFromWindows(requestedWindows),
|
|
1454
|
-
visibilityLeadMinutes: 90,
|
|
1455
|
-
visibilityLagMinutes: 180,
|
|
1456
|
-
},
|
|
1457
|
-
};
|
|
1458
|
-
}
|
|
1459
|
-
return currentCadence.kind === "times_per_day"
|
|
1460
|
-
? { cadence: currentCadence }
|
|
1461
|
-
: null;
|
|
1462
|
-
}
|
|
1463
|
-
return currentCadence.kind === "once" ? { cadence: currentCadence } : null;
|
|
1464
|
-
}
|
|
1465
|
-
function hasDefinitionUpdateChanges(request) {
|
|
1466
|
-
return (request.title != null ||
|
|
1467
|
-
request.cadence != null ||
|
|
1468
|
-
request.priority != null ||
|
|
1469
|
-
request.description != null ||
|
|
1470
|
-
request.windowPolicy != null ||
|
|
1471
|
-
request.reminderPlan != null);
|
|
1472
|
-
}
|
|
1473
|
-
function buildDefaultReminderPlan(label) {
|
|
1474
|
-
return {
|
|
1475
|
-
steps: [{ channel: "in_app", offsetMinutes: 0, label }],
|
|
1476
|
-
};
|
|
1477
|
-
}
|
|
1478
|
-
function scoreDefinitionTitleQuality(value) {
|
|
1479
|
-
const normalized = normalizeTitle(value ?? "");
|
|
1480
|
-
if (!normalized) {
|
|
1481
|
-
return Number.NEGATIVE_INFINITY;
|
|
1482
|
-
}
|
|
1483
|
-
let score = normalized.split(/\s+/).filter(Boolean).length;
|
|
1484
|
-
if (/\b\d+\b/.test(normalized)) {
|
|
1485
|
-
score += 6;
|
|
1486
|
-
}
|
|
1487
|
-
if (/[+&]/.test(value ?? "") || /\band\b/.test(normalized)) {
|
|
1488
|
-
score += 4;
|
|
1489
|
-
}
|
|
1490
|
-
if (/^(?:do|work out|workout|habit|routine|task|todo|reminder|alarm)\b/.test(normalized)) {
|
|
1491
|
-
score -= 5;
|
|
1492
|
-
}
|
|
1493
|
-
if (GENERIC_DERIVED_TITLE_RE.test(normalized)) {
|
|
1494
|
-
score -= 6;
|
|
1495
|
-
}
|
|
1496
|
-
return score;
|
|
1497
|
-
}
|
|
1498
|
-
function shouldAdoptPlannerTitle(args) {
|
|
1499
|
-
const plannerTitle = args.plannerTitle?.trim();
|
|
1500
|
-
if (!plannerTitle) {
|
|
1501
|
-
return false;
|
|
1502
|
-
}
|
|
1503
|
-
const currentTitle = args.currentTitle?.trim();
|
|
1504
|
-
if (!currentTitle) {
|
|
1505
|
-
return true;
|
|
1506
|
-
}
|
|
1507
|
-
if (normalizeTitle(currentTitle) === normalizeTitle(plannerTitle)) {
|
|
1508
|
-
return false;
|
|
1509
|
-
}
|
|
1510
|
-
return (scoreDefinitionTitleQuality(plannerTitle) >
|
|
1511
|
-
scoreDefinitionTitleQuality(currentTitle));
|
|
1512
|
-
}
|
|
1513
|
-
function shouldAdoptPlannerCadence(args) {
|
|
1514
|
-
const { currentCadence, plannerCadence } = args;
|
|
1515
|
-
if (!currentCadence) {
|
|
1516
|
-
return true;
|
|
1517
|
-
}
|
|
1518
|
-
if (currentCadence.kind === "times_per_day") {
|
|
1519
|
-
return ((plannerCadence.kind === "times_per_day" &&
|
|
1520
|
-
plannerCadence.slots.length >= currentCadence.slots.length) ||
|
|
1521
|
-
(plannerCadence.kind === "once" && currentCadence.slots.length === 1));
|
|
1522
|
-
}
|
|
1523
|
-
if (currentCadence.kind === "weekly") {
|
|
1524
|
-
return (plannerCadence.kind === "weekly" &&
|
|
1525
|
-
plannerCadence.weekdays.length >= currentCadence.weekdays.length &&
|
|
1526
|
-
(currentCadence.windows.includes("custom")
|
|
1527
|
-
? plannerCadence.windows.includes("custom")
|
|
1528
|
-
: plannerCadence.windows.length >= currentCadence.windows.length));
|
|
1529
|
-
}
|
|
1530
|
-
if (currentCadence.kind === "interval") {
|
|
1531
|
-
return plannerCadence.kind === "interval";
|
|
1532
|
-
}
|
|
1533
|
-
if (currentCadence.kind === "once") {
|
|
1534
|
-
return plannerCadence.kind === "once";
|
|
1535
|
-
}
|
|
1536
|
-
if (currentCadence.kind === "daily") {
|
|
1537
|
-
return (plannerCadence.kind === "times_per_day" ||
|
|
1538
|
-
(plannerCadence.kind === "daily" &&
|
|
1539
|
-
plannerCadence.windows.length >= currentCadence.windows.length));
|
|
1540
|
-
}
|
|
1541
|
-
return true;
|
|
1542
|
-
}
|
|
1543
|
-
function shouldRequireLifeCreateConfirmation(args) {
|
|
1544
|
-
if (args.messageSource === "autonomy") {
|
|
1545
|
-
return false;
|
|
1546
|
-
}
|
|
1547
|
-
if (args.requestKind && args.cadence?.kind === "once") {
|
|
1548
|
-
return false;
|
|
1549
|
-
}
|
|
1550
|
-
return !args.confirmed;
|
|
1551
|
-
}
|
|
1552
|
-
function describeReminderIntensity(intensity) {
|
|
1553
|
-
switch (intensity) {
|
|
1554
|
-
case "minimal":
|
|
1555
|
-
return "minimal";
|
|
1556
|
-
case "normal":
|
|
1557
|
-
return "normal";
|
|
1558
|
-
case "persistent":
|
|
1559
|
-
return "persistent";
|
|
1560
|
-
case "high_priority_only":
|
|
1561
|
-
return "high priority only";
|
|
1562
|
-
}
|
|
1563
|
-
return "normal";
|
|
1564
|
-
}
|
|
1565
|
-
function formatGoalExperienceLoopSummary(experienceLoop) {
|
|
1566
|
-
if (!experienceLoop || !experienceLoop.summary) {
|
|
1567
|
-
return null;
|
|
1568
|
-
}
|
|
1569
|
-
const similarGoalTitle = experienceLoop.similarGoals?.[0]?.title?.trim();
|
|
1570
|
-
const carryForwardTitle = experienceLoop.suggestedCarryForward?.[0]?.title?.trim();
|
|
1571
|
-
const parts = [experienceLoop.summary.trim()];
|
|
1572
|
-
if (similarGoalTitle) {
|
|
1573
|
-
parts.push(`Closest match: "${similarGoalTitle}".`);
|
|
1574
|
-
}
|
|
1575
|
-
if (carryForwardTitle) {
|
|
1576
|
-
parts.push(`Carry forward "${carryForwardTitle}" if it still fits.`);
|
|
1577
|
-
}
|
|
1578
|
-
return parts.join(" ");
|
|
1579
|
-
}
|
|
1580
|
-
function formatWeeklyGoalReview(args) {
|
|
1581
|
-
const parts = [
|
|
1582
|
-
`Weekly goal review: ${args.summary.totalGoals} active ${args.summary.totalGoals === 1 ? "goal" : "goals"}, ${args.summary.onTrackCount} on track, ${args.summary.atRiskCount} at risk, ${args.summary.needsAttentionCount} needing attention.`,
|
|
1583
|
-
];
|
|
1584
|
-
if (args.atRisk.length > 0) {
|
|
1585
|
-
parts.push(`Drifting: ${args.atRisk.slice(0, 3).map((review) => review.goal.title).join(", ")}.`);
|
|
1586
|
-
}
|
|
1587
|
-
if (args.needsAttention.length > 0) {
|
|
1588
|
-
parts.push(`Needs attention: ${args.needsAttention
|
|
1589
|
-
.slice(0, 3)
|
|
1590
|
-
.map((review) => review.goal.title)
|
|
1591
|
-
.join(", ")}.`);
|
|
1592
|
-
}
|
|
1593
|
-
if (args.onTrack.length > 0) {
|
|
1594
|
-
parts.push(`On track: ${args.onTrack
|
|
1595
|
-
.slice(0, 3)
|
|
1596
|
-
.map((review) => review.goal.title)
|
|
1597
|
-
.join(", ")}.`);
|
|
1598
|
-
}
|
|
1599
|
-
return parts.join(" ");
|
|
1600
|
-
}
|
|
1601
|
-
// ── Main action ───────────────────────────────────────
|
|
1602
|
-
export const lifeAction = {
|
|
1603
|
-
name: "LIFE",
|
|
1604
|
-
// CREATE_TASK and COMPLETE_TASK must NOT appear in similes: they are
|
|
1605
|
-
// the orchestrator's primary aliases, and the collision routes coding
|
|
1606
|
-
// prompts ("fix this bug") here by name match. LifeOps intent is still
|
|
1607
|
-
// covered by the todo/habit/goal/reminder similes plus description.
|
|
1608
|
-
similes: [
|
|
1609
|
-
"MANAGE_LIFEOPS",
|
|
1610
|
-
"QUERY_LIFEOPS",
|
|
1611
|
-
"CREATE_TODO",
|
|
1612
|
-
"ADD_TODO",
|
|
1613
|
-
"LIST_TODOS",
|
|
1614
|
-
"TODO_LIST",
|
|
1615
|
-
"COMPLETE_TODO",
|
|
1616
|
-
"CREATE_HABIT",
|
|
1617
|
-
"CREATE_GOAL",
|
|
1618
|
-
"LIFE_CREATE_DEFINITION",
|
|
1619
|
-
"TRACK_HABIT",
|
|
1620
|
-
"SET_ALARM",
|
|
1621
|
-
"SET_REMINDER",
|
|
1622
|
-
"SNOOZE_REMINDER",
|
|
1623
|
-
"SET_REMINDER_INTENSITY",
|
|
1624
|
-
],
|
|
1625
|
-
description: "Manage the user's personal routines, habits, goals, reminders, alarms, and escalation settings through LifeOps. " +
|
|
1626
|
-
"USE this action for: creating, editing, or deleting tasks, habits, routines, and goals; " +
|
|
1627
|
-
"todo and goal requests like 'add a todo: pick up dry cleaning tomorrow', 'remember to call mom on Sunday', 'what's on my todo list today?', or 'set a goal to save $5,000 by the end of the year'; " +
|
|
1628
|
-
"setting one-off alarms or wake-up reminders like 'set an alarm for 7am' or 'wake me up at 7'; " +
|
|
1629
|
-
"helping the user actually set up follow-through when they say things like 'help me brush my teeth every day', 'i keep forgetting x', or 'help me actually do it'; " +
|
|
1630
|
-
"using LifeOps defaults for common routines when the user gives a natural window instead of an exact clock, like water reminders, stretch breaks, weekday-after-lunch Invisalign checks, twice-weekly shave reminders, or brushing when they wake up and before bed; " +
|
|
1631
|
-
"marking items as complete, skipping, or snoozing them; reviewing goal progress, weekly goal review, and carry-forward lessons from similar completed goals; " +
|
|
1632
|
-
"setting up phone/SMS escalation channels; adjusting reminder frequency or intensity; " +
|
|
1633
|
-
"querying an overview of active LifeOps items. " +
|
|
1634
|
-
"These are executable LifeOps items, not profile facts or bio updates. " +
|
|
1635
|
-
"ALWAYS use LIFE for dynamic status questions like 'what's still left for today', 'what do i still need to do today', or 'anything else in my LifeOps list', even when the conversation already mentioned tasks, because their status may have changed after a completion, snooze, or reminder. " +
|
|
1636
|
-
"Use LIFE for reminder/escalation policies about the owner's own follow-through, such as 'if I still haven't answered about those three events, bump me again with context instead of starting over,' when the request is about reminding the owner rather than modifying the calendar itself. " +
|
|
1637
|
-
"Do not fall back to REPLY, UPDATE_ENTITY, or UPDATE_OWNER_PROFILE when the user is asking to create or inspect a todo, habit, goal, reminder, or alarm. " +
|
|
1638
|
-
"DO NOT use this action for generic coaching or advice questions like 'any tips on setting better goals?' unless the user is also asking you to create, update, review, or track a concrete goal, task, reminder, or routine. " +
|
|
1639
|
-
"DO NOT use this action for person-specific follow-ups like 'remind me to follow up with David next week about the project' — use OWNER_RELATIONSHIP instead. " +
|
|
1640
|
-
"DO NOT use this action for Gmail inbox triage, email search, drafting or sending emails — use OWNER_INBOX with channel=gmail instead. " +
|
|
1641
|
-
"DO NOT use this action for daily briefs, unread summaries, drafts awaiting sign-off, or cross-channel inbox review — use OWNER_INBOX instead. " +
|
|
1642
|
-
"DO NOT use this action for calendar lookups, scheduling meetings, availability, Calendly, or travel itineraries — use OWNER_CALENDAR instead. " +
|
|
1643
|
-
"DO NOT use this action for multi-device push ladders or device-wide reminder delivery — use PUBLISH_DEVICE_INTENT instead. " +
|
|
1644
|
-
"DO NOT use this action for pre-event asset checklists, questions like 'what slides, bio, title, or portal assets do I still owe before the event', document-signing workflows, collecting updated ID copies, or cancellation-fee warning/escalation policies — use OWNER_INBOX, PUBLISH_DEVICE_INTENT, OWNER_CALENDAR, or LIFEOPS_COMPUTER_USE instead. " +
|
|
1645
|
-
"DO NOT use this action for browser/portal/file workflows on the owner's machine — use LIFEOPS_COMPUTER_USE instead. " +
|
|
1646
|
-
"This action provides the final grounded reply; do not pair it with a speculative REPLY action or fall back to advice-only chat when the user wants real LifeOps follow-through.",
|
|
1647
|
-
descriptionCompressed: "LifeOps: manage habits, goals, reminders, alarms, escalation. Create/edit/complete/snooze items. Query active status.",
|
|
1648
|
-
suppressPostActionContinuation: true,
|
|
1649
|
-
validate: async (runtime, message) => {
|
|
1650
|
-
// Coding prompts share LifeOps verbs ("make", "create", "add") so
|
|
1651
|
-
// the action selector can still pick LIFE. Decline here to let
|
|
1652
|
-
// plugin-agent-orchestrator's CREATE_TASK take the route.
|
|
1653
|
-
if (looksLikeCodingTaskRequest(messageText(message))) {
|
|
1654
|
-
return false;
|
|
1655
|
-
}
|
|
1656
|
-
return hasLifeOpsAccess(runtime, message);
|
|
1657
|
-
},
|
|
1658
|
-
handler: async (runtime, message, state, options) => {
|
|
1659
|
-
if (!(await hasLifeOpsAccess(runtime, message))) {
|
|
1660
|
-
const fallback = "Life management is restricted to the owner, explicitly granted users, and the agent.";
|
|
1661
|
-
return {
|
|
1662
|
-
success: false,
|
|
1663
|
-
text: await renderLifeActionReply({
|
|
1664
|
-
runtime,
|
|
1665
|
-
message,
|
|
1666
|
-
state,
|
|
1667
|
-
intent: normalizeLifeInputText(messageText(message)),
|
|
1668
|
-
scenario: "reply_only",
|
|
1669
|
-
fallback,
|
|
1670
|
-
context: {
|
|
1671
|
-
reason: "access_restricted",
|
|
1672
|
-
},
|
|
1673
|
-
}),
|
|
1674
|
-
};
|
|
1675
|
-
}
|
|
1676
|
-
const rawParams = options?.parameters;
|
|
1677
|
-
const params = rawParams ?? {};
|
|
1678
|
-
const currentText = normalizeLifeInputText(messageText(message));
|
|
1679
|
-
const details = params.details;
|
|
1680
|
-
const deferredDraft = latestDeferredLifeDraft(state);
|
|
1681
|
-
const turnsSinceDraft = deferredDraft != null
|
|
1682
|
-
? (countTurnsSinceLatestDeferredLifeDraft(state) ?? 0) + 1
|
|
1683
|
-
: undefined;
|
|
1684
|
-
const deferredDraftFollowupMode = deferredDraft
|
|
1685
|
-
? await extractDeferredLifeDraftFollowupWithLlm({
|
|
1686
|
-
runtime,
|
|
1687
|
-
message,
|
|
1688
|
-
state,
|
|
1689
|
-
currentText,
|
|
1690
|
-
draft: deferredDraft,
|
|
1691
|
-
})
|
|
1692
|
-
: null;
|
|
1693
|
-
const draftExpiryReason = deferredLifeDraftExpiryReason({
|
|
1694
|
-
draft: deferredDraft,
|
|
1695
|
-
turnsSinceDraft,
|
|
1696
|
-
});
|
|
1697
|
-
if (draftExpiryReason && deferredDraftFollowupMode === "confirm") {
|
|
1698
|
-
const fallback = "That LifeOps draft expired. Please restate it and I'll preview it again.";
|
|
1699
|
-
return {
|
|
1700
|
-
success: false,
|
|
1701
|
-
text: await renderLifeActionReply({
|
|
1702
|
-
runtime,
|
|
1703
|
-
message,
|
|
1704
|
-
state,
|
|
1705
|
-
intent: currentText,
|
|
1706
|
-
scenario: "reply_only",
|
|
1707
|
-
fallback,
|
|
1708
|
-
context: {
|
|
1709
|
-
reason: "draft_expired",
|
|
1710
|
-
},
|
|
1711
|
-
}),
|
|
1712
|
-
};
|
|
1713
|
-
}
|
|
1714
|
-
if (deferredDraftFollowupMode === "cancel") {
|
|
1715
|
-
const fallback = "Okay, I won't save it yet.";
|
|
1716
|
-
return {
|
|
1717
|
-
success: true,
|
|
1718
|
-
text: await renderLifeActionReply({
|
|
1719
|
-
runtime,
|
|
1720
|
-
message,
|
|
1721
|
-
state,
|
|
1722
|
-
intent: currentText,
|
|
1723
|
-
scenario: "reply_only",
|
|
1724
|
-
fallback,
|
|
1725
|
-
context: {
|
|
1726
|
-
reason: "draft_cancelled",
|
|
1727
|
-
draft: deferredDraft
|
|
1728
|
-
? {
|
|
1729
|
-
operation: deferredDraft.operation,
|
|
1730
|
-
title: deferredDraft.request.title,
|
|
1731
|
-
}
|
|
1732
|
-
: null,
|
|
1733
|
-
},
|
|
1734
|
-
}),
|
|
1735
|
-
data: {
|
|
1736
|
-
actionName: "LIFE",
|
|
1737
|
-
noop: true,
|
|
1738
|
-
},
|
|
1739
|
-
};
|
|
1740
|
-
}
|
|
1741
|
-
const deferredDraftReuseMode = resolveDeferredLifeDraftReuseMode({
|
|
1742
|
-
details,
|
|
1743
|
-
draft: deferredDraft,
|
|
1744
|
-
explicitAction: params.action,
|
|
1745
|
-
llmMode: deferredDraftFollowupMode,
|
|
1746
|
-
turnsSinceDraft,
|
|
1747
|
-
});
|
|
1748
|
-
const reuseDeferredDraft = deferredDraftReuseMode !== null;
|
|
1749
|
-
const intent = reuseDeferredDraft
|
|
1750
|
-
? deferredDraftReuseMode === "confirm"
|
|
1751
|
-
? normalizeLifeInputText(deferredDraft?.intent ?? "")
|
|
1752
|
-
: normalizeLifeInputText(params.intent?.trim() ?? currentText)
|
|
1753
|
-
: normalizeLifeInputText(params.intent?.trim() ?? currentText);
|
|
1754
|
-
if (!intent) {
|
|
1755
|
-
const fallback = "Tell me what you want me to do.";
|
|
1756
|
-
return {
|
|
1757
|
-
success: false,
|
|
1758
|
-
text: await renderLifeActionReply({
|
|
1759
|
-
runtime,
|
|
1760
|
-
message,
|
|
1761
|
-
state,
|
|
1762
|
-
intent: currentText,
|
|
1763
|
-
scenario: "reply_only",
|
|
1764
|
-
fallback,
|
|
1765
|
-
context: {
|
|
1766
|
-
reason: "missing_intent",
|
|
1767
|
-
},
|
|
1768
|
-
}),
|
|
1769
|
-
};
|
|
1770
|
-
}
|
|
1771
|
-
const explicitOperation = params.action
|
|
1772
|
-
? ACTION_TO_OPERATION[params.action]
|
|
1773
|
-
: undefined;
|
|
1774
|
-
const operationPlan = reuseDeferredDraft && deferredDraft
|
|
1775
|
-
? {
|
|
1776
|
-
confidence: 1,
|
|
1777
|
-
missing: [],
|
|
1778
|
-
operation: deferredDraft.operation,
|
|
1779
|
-
shouldAct: true,
|
|
1780
|
-
}
|
|
1781
|
-
: await resolveLifeOperationPlan({
|
|
1782
|
-
runtime,
|
|
1783
|
-
message,
|
|
1784
|
-
state,
|
|
1785
|
-
intent,
|
|
1786
|
-
explicitOperation,
|
|
1787
|
-
});
|
|
1788
|
-
const forceCreateExecution = shouldForceLifeCreateExecution({
|
|
1789
|
-
intent,
|
|
1790
|
-
missing: operationPlan.missing,
|
|
1791
|
-
operation: operationPlan.operation,
|
|
1792
|
-
details,
|
|
1793
|
-
title: params.title,
|
|
1794
|
-
});
|
|
1795
|
-
if (!operationPlan.shouldAct && !forceCreateExecution) {
|
|
1796
|
-
const fallback = buildLifeClarificationFallback({
|
|
1797
|
-
missing: operationPlan.missing,
|
|
1798
|
-
operation: operationPlan.operation,
|
|
1799
|
-
});
|
|
1800
|
-
return {
|
|
1801
|
-
success: true,
|
|
1802
|
-
text: await renderLifeActionReply({
|
|
1803
|
-
runtime,
|
|
1804
|
-
message,
|
|
1805
|
-
state,
|
|
1806
|
-
intent,
|
|
1807
|
-
scenario: operationPlan.operation === "create_goal"
|
|
1808
|
-
? "clarify_create_goal"
|
|
1809
|
-
: "clarify_create_definition",
|
|
1810
|
-
fallback,
|
|
1811
|
-
context: {
|
|
1812
|
-
missing: operationPlan.missing,
|
|
1813
|
-
operation: operationPlan.operation,
|
|
1814
|
-
},
|
|
1815
|
-
}),
|
|
1816
|
-
data: {
|
|
1817
|
-
actionName: "LIFE",
|
|
1818
|
-
noop: true,
|
|
1819
|
-
suggestedOperation: operationPlan.operation,
|
|
1820
|
-
},
|
|
1821
|
-
};
|
|
1822
|
-
}
|
|
1823
|
-
const operation = forceCreateExecution
|
|
1824
|
-
? "create_definition"
|
|
1825
|
-
: operationPlan.operation;
|
|
1826
|
-
if (!operation) {
|
|
1827
|
-
const fallback = "Tell me what LifeOps action you want me to take.";
|
|
1828
|
-
return {
|
|
1829
|
-
success: true,
|
|
1830
|
-
text: await renderLifeActionReply({
|
|
1831
|
-
runtime,
|
|
1832
|
-
message,
|
|
1833
|
-
state,
|
|
1834
|
-
intent,
|
|
1835
|
-
scenario: "reply_only",
|
|
1836
|
-
fallback,
|
|
1837
|
-
context: {
|
|
1838
|
-
reason: "missing_operation_after_extraction",
|
|
1839
|
-
},
|
|
1840
|
-
}),
|
|
1841
|
-
data: {
|
|
1842
|
-
actionName: "LIFE",
|
|
1843
|
-
noop: true,
|
|
1844
|
-
},
|
|
1845
|
-
};
|
|
1846
|
-
}
|
|
1847
|
-
const service = new LifeOpsService(runtime);
|
|
1848
|
-
const domain = detailString(details, "domain");
|
|
1849
|
-
const ownership = requestedOwnership(domain);
|
|
1850
|
-
const chatText = intent;
|
|
1851
|
-
const targetName = params.target ?? params.title;
|
|
1852
|
-
const createConfirmed = deferredDraftReuseMode === "confirm" ||
|
|
1853
|
-
detailBoolean(details, "confirmed") === true;
|
|
1854
|
-
try {
|
|
1855
|
-
const createDefinition = async () => {
|
|
1856
|
-
const deferredDefinitionDraft = reuseDeferredDraft && deferredDraft?.operation === "create_definition"
|
|
1857
|
-
? deferredDraft
|
|
1858
|
-
: null;
|
|
1859
|
-
const editingDeferredDefinitionDraft = deferredDraftReuseMode === "edit" &&
|
|
1860
|
-
deferredDefinitionDraft?.operation === "create_definition";
|
|
1861
|
-
const explicitCadenceDetail = normalizeCadenceDetail(detailObject(details, "cadence"));
|
|
1862
|
-
const fallbackTitle = deferredDefinitionDraft?.request.title ?? null;
|
|
1863
|
-
let title = editingDeferredDefinitionDraft
|
|
1864
|
-
? (params.title ?? fallbackTitle)
|
|
1865
|
-
: (fallbackTitle ?? params.title ?? null);
|
|
1866
|
-
const fallbackCadence = deferredDefinitionDraft?.request.cadence;
|
|
1867
|
-
let cadence = editingDeferredDefinitionDraft
|
|
1868
|
-
? (explicitCadenceDetail ?? fallbackCadence ?? undefined)
|
|
1869
|
-
: (fallbackCadence ?? explicitCadenceDetail ?? undefined);
|
|
1870
|
-
let windowPolicy = editingDeferredDefinitionDraft
|
|
1871
|
-
? (detailObject(details, "windowPolicy") ?? deferredDefinitionDraft?.request.windowPolicy)
|
|
1872
|
-
: (deferredDefinitionDraft?.request.windowPolicy ??
|
|
1873
|
-
detailObject(details, "windowPolicy"));
|
|
1874
|
-
const explicitPriority = detailNumber(details, "priority");
|
|
1875
|
-
const explicitDescription = detailString(details, "description");
|
|
1876
|
-
const explicitMetadata = detailObject(details, "metadata");
|
|
1877
|
-
// Track whether cadence/title came from explicit high-confidence
|
|
1878
|
-
// sources so the planner only fills genuine gaps.
|
|
1879
|
-
const hadExplicitCadence = Boolean((editingDeferredDefinitionDraft
|
|
1880
|
-
? (explicitCadenceDetail ??
|
|
1881
|
-
deferredDefinitionDraft?.request.cadence)
|
|
1882
|
-
: deferredDefinitionDraft?.request.cadence) ??
|
|
1883
|
-
explicitCadenceDetail);
|
|
1884
|
-
const hadExplicitTitle = Boolean((editingDeferredDefinitionDraft
|
|
1885
|
-
? params.title
|
|
1886
|
-
: deferredDefinitionDraft?.request.title) ?? params.title);
|
|
1887
|
-
// ── LLM parameter enhancement (fills gaps) ────────
|
|
1888
|
-
// Skip when reusing a confirmed deferred draft — the user already
|
|
1889
|
-
// approved those values.
|
|
1890
|
-
let llmPlan = null;
|
|
1891
|
-
let llmDescription;
|
|
1892
|
-
let llmPriority;
|
|
1893
|
-
let llmRequestKind = null;
|
|
1894
|
-
if (!deferredDefinitionDraft || editingDeferredDefinitionDraft) {
|
|
1895
|
-
llmPlan = await extractTaskCreatePlanWithLlm({
|
|
1896
|
-
runtime,
|
|
1897
|
-
intent,
|
|
1898
|
-
state: state ?? undefined,
|
|
1899
|
-
message: message ?? undefined,
|
|
1900
|
-
});
|
|
1901
|
-
const shouldHonorPlannerResponse = llmPlan?.mode === "respond" &&
|
|
1902
|
-
Boolean(llmPlan.response) &&
|
|
1903
|
-
!editingDeferredDefinitionDraft &&
|
|
1904
|
-
!params.title &&
|
|
1905
|
-
!explicitCadenceDetail &&
|
|
1906
|
-
!detailString(details, "description") &&
|
|
1907
|
-
!detailString(details, "goalId") &&
|
|
1908
|
-
!detailString(details, "goalTitle") &&
|
|
1909
|
-
!detailString(details, "kind");
|
|
1910
|
-
if (shouldHonorPlannerResponse && llmPlan?.response) {
|
|
1911
|
-
return {
|
|
1912
|
-
success: true,
|
|
1913
|
-
text: llmPlan.response,
|
|
1914
|
-
};
|
|
1915
|
-
}
|
|
1916
|
-
if (llmPlan) {
|
|
1917
|
-
llmRequestKind = llmPlan.requestKind;
|
|
1918
|
-
if (!hadExplicitTitle &&
|
|
1919
|
-
shouldAdoptPlannerTitle({
|
|
1920
|
-
currentTitle: title,
|
|
1921
|
-
plannerTitle: llmPlan.title,
|
|
1922
|
-
})) {
|
|
1923
|
-
title = llmPlan.title;
|
|
1924
|
-
}
|
|
1925
|
-
if ((editingDeferredDefinitionDraft || !hadExplicitCadence) &&
|
|
1926
|
-
llmPlan.cadenceKind) {
|
|
1927
|
-
const llmCadenceTimeZone = normalizeLifeTimeZoneToken(detailString(details, "timeZone") ??
|
|
1928
|
-
llmPlan.timeZone ??
|
|
1929
|
-
deferredDefinitionDraft?.request.timezone ??
|
|
1930
|
-
windowPolicy?.timezone);
|
|
1931
|
-
const llmCadence = buildCadenceFromLlmParams(llmPlan, {
|
|
1932
|
-
intent,
|
|
1933
|
-
timeZone: llmCadenceTimeZone ?? undefined,
|
|
1934
|
-
});
|
|
1935
|
-
if (llmCadence &&
|
|
1936
|
-
shouldAdoptPlannerCadence({
|
|
1937
|
-
currentCadence: cadence,
|
|
1938
|
-
plannerCadence: llmCadence.cadence,
|
|
1939
|
-
})) {
|
|
1940
|
-
cadence = llmCadence.cadence;
|
|
1941
|
-
windowPolicy = llmCadence.windowPolicy ?? windowPolicy;
|
|
1942
|
-
}
|
|
1943
|
-
}
|
|
1944
|
-
if (!explicitDescription && llmPlan.description) {
|
|
1945
|
-
llmDescription = llmPlan.description;
|
|
1946
|
-
}
|
|
1947
|
-
if (explicitPriority === undefined && llmPlan.priority) {
|
|
1948
|
-
llmPriority = llmPlan.priority;
|
|
1949
|
-
}
|
|
1950
|
-
}
|
|
1951
|
-
}
|
|
1952
|
-
const resolvedTimeZone = normalizeLifeTimeZoneToken(detailString(details, "timeZone") ??
|
|
1953
|
-
llmPlan?.timeZone ??
|
|
1954
|
-
deferredDefinitionDraft?.request.timezone ??
|
|
1955
|
-
windowPolicy?.timezone);
|
|
1956
|
-
const timedRequestKind = llmRequestKind;
|
|
1957
|
-
const nativeAppleMetadata = timedRequestKind && cadence?.kind === "once"
|
|
1958
|
-
? buildNativeAppleReminderMetadata({
|
|
1959
|
-
kind: timedRequestKind,
|
|
1960
|
-
source: "llm",
|
|
1961
|
-
})
|
|
1962
|
-
: undefined;
|
|
1963
|
-
const definitionMetadata = editingDeferredDefinitionDraft
|
|
1964
|
-
? mergeMetadataRecords(deferredDefinitionDraft?.request.metadata, mergeMetadataRecords(explicitMetadata, nativeAppleMetadata))
|
|
1965
|
-
: (deferredDefinitionDraft?.request.metadata ??
|
|
1966
|
-
mergeMetadataRecords(explicitMetadata, nativeAppleMetadata));
|
|
1967
|
-
if (!title) {
|
|
1968
|
-
const fallback = "What should I call it?";
|
|
1969
|
-
return {
|
|
1970
|
-
success: false,
|
|
1971
|
-
text: await renderLifeActionReply({
|
|
1972
|
-
runtime,
|
|
1973
|
-
message,
|
|
1974
|
-
state,
|
|
1975
|
-
intent,
|
|
1976
|
-
scenario: "clarify_create_definition",
|
|
1977
|
-
fallback,
|
|
1978
|
-
context: {
|
|
1979
|
-
missing: ["title"],
|
|
1980
|
-
operation: "create_definition",
|
|
1981
|
-
},
|
|
1982
|
-
}),
|
|
1983
|
-
};
|
|
1984
|
-
}
|
|
1985
|
-
if (!cadence) {
|
|
1986
|
-
const fallback = "When should it happen?";
|
|
1987
|
-
return {
|
|
1988
|
-
success: false,
|
|
1989
|
-
text: await renderLifeActionReply({
|
|
1990
|
-
runtime,
|
|
1991
|
-
message,
|
|
1992
|
-
state,
|
|
1993
|
-
intent,
|
|
1994
|
-
scenario: "clarify_create_definition",
|
|
1995
|
-
fallback,
|
|
1996
|
-
context: {
|
|
1997
|
-
missing: ["schedule"],
|
|
1998
|
-
operation: "create_definition",
|
|
1999
|
-
},
|
|
2000
|
-
}),
|
|
2001
|
-
};
|
|
2002
|
-
}
|
|
2003
|
-
const kind = (editingDeferredDefinitionDraft
|
|
2004
|
-
? detailString(details, "kind")
|
|
2005
|
-
: deferredDefinitionDraft?.request.kind) ??
|
|
2006
|
-
detailString(details, "kind") ??
|
|
2007
|
-
"habit";
|
|
2008
|
-
const definitionDraft = {
|
|
2009
|
-
intent,
|
|
2010
|
-
operation: "create_definition",
|
|
2011
|
-
createdAt: editingDeferredDefinitionDraft
|
|
2012
|
-
? Date.now()
|
|
2013
|
-
: (deferredDefinitionDraft?.createdAt ?? Date.now()),
|
|
2014
|
-
request: {
|
|
2015
|
-
cadence,
|
|
2016
|
-
description: explicitDescription ??
|
|
2017
|
-
llmDescription ??
|
|
2018
|
-
(editingDeferredDefinitionDraft
|
|
2019
|
-
? deferredDefinitionDraft?.request.description
|
|
2020
|
-
: undefined),
|
|
2021
|
-
goalRef: detailString(details, "goalId") ??
|
|
2022
|
-
detailString(details, "goalTitle") ??
|
|
2023
|
-
deferredDefinitionDraft?.request.goalRef ??
|
|
2024
|
-
undefined,
|
|
2025
|
-
kind,
|
|
2026
|
-
priority: explicitPriority ??
|
|
2027
|
-
llmPriority ??
|
|
2028
|
-
deferredDefinitionDraft?.request.priority,
|
|
2029
|
-
progressionRule: detailObject(details, "progressionRule") ??
|
|
2030
|
-
deferredDefinitionDraft?.request.progressionRule,
|
|
2031
|
-
reminderPlan: detailObject(details, "reminderPlan") ??
|
|
2032
|
-
deferredDefinitionDraft?.request.reminderPlan ??
|
|
2033
|
-
buildDefaultReminderPlan(`${title} reminder`),
|
|
2034
|
-
timezone: normalizeLifeTimeZoneToken(llmPlan?.timeZone) ??
|
|
2035
|
-
normalizeLifeTimeZoneToken(resolvedTimeZone ?? deferredDefinitionDraft?.request.timezone) ??
|
|
2036
|
-
resolvedTimeZone ??
|
|
2037
|
-
deferredDefinitionDraft?.request.timezone,
|
|
2038
|
-
title,
|
|
2039
|
-
metadata: definitionMetadata,
|
|
2040
|
-
windowPolicy,
|
|
2041
|
-
websiteAccess: detailObject(details, "websiteAccess") ?? deferredDefinitionDraft?.request.websiteAccess,
|
|
2042
|
-
},
|
|
2043
|
-
};
|
|
2044
|
-
if (shouldRequireLifeCreateConfirmation({
|
|
2045
|
-
confirmed: createConfirmed,
|
|
2046
|
-
messageSource: typeof message.content?.source === "string"
|
|
2047
|
-
? message.content.source
|
|
2048
|
-
: undefined,
|
|
2049
|
-
requestKind: timedRequestKind,
|
|
2050
|
-
cadence: definitionDraft.request.cadence,
|
|
2051
|
-
})) {
|
|
2052
|
-
const fallback = `I can save this as a ${definitionDraft.request.kind} named "${definitionDraft.request.title}" that happens ${summarizeCadence(definitionDraft.request.cadence)}. Confirm and I'll save it, or tell me what to change.`;
|
|
2053
|
-
return {
|
|
2054
|
-
success: true,
|
|
2055
|
-
text: await renderLifeActionReply({
|
|
2056
|
-
runtime,
|
|
2057
|
-
message,
|
|
2058
|
-
state,
|
|
2059
|
-
intent,
|
|
2060
|
-
scenario: "preview_definition",
|
|
2061
|
-
fallback,
|
|
2062
|
-
context: {
|
|
2063
|
-
draft: definitionDraft.request,
|
|
2064
|
-
requestKind: timedRequestKind,
|
|
2065
|
-
},
|
|
2066
|
-
}),
|
|
2067
|
-
data: {
|
|
2068
|
-
actionName: "LIFE",
|
|
2069
|
-
deferred: true,
|
|
2070
|
-
lifeDraft: definitionDraft,
|
|
2071
|
-
preview: {
|
|
2072
|
-
cadence: definitionDraft.request.cadence,
|
|
2073
|
-
kind: definitionDraft.request.kind,
|
|
2074
|
-
title: definitionDraft.request.title,
|
|
2075
|
-
},
|
|
2076
|
-
},
|
|
2077
|
-
};
|
|
2078
|
-
}
|
|
2079
|
-
const resolvedGoal = definitionDraft.request.goalRef
|
|
2080
|
-
? await resolveGoal(service, definitionDraft.request.goalRef, domain)
|
|
2081
|
-
: null;
|
|
2082
|
-
const created = await service.createDefinition({
|
|
2083
|
-
ownership,
|
|
2084
|
-
kind: definitionDraft.request.kind,
|
|
2085
|
-
title: definitionDraft.request.title,
|
|
2086
|
-
description: definitionDraft.request.description,
|
|
2087
|
-
originalIntent: definitionDraft.intent || definitionDraft.request.title,
|
|
2088
|
-
cadence: definitionDraft.request.cadence,
|
|
2089
|
-
timezone: normalizeLifeTimeZoneToken(definitionDraft.request.timezone) ??
|
|
2090
|
-
definitionDraft.request.timezone,
|
|
2091
|
-
priority: definitionDraft.request.priority,
|
|
2092
|
-
windowPolicy: definitionDraft.request.windowPolicy,
|
|
2093
|
-
progressionRule: definitionDraft.request.progressionRule,
|
|
2094
|
-
reminderPlan: definitionDraft.request.reminderPlan,
|
|
2095
|
-
metadata: definitionDraft.request.metadata,
|
|
2096
|
-
websiteAccess: definitionDraft.request.websiteAccess,
|
|
2097
|
-
goalId: resolvedGoal?.goal.id ?? null,
|
|
2098
|
-
source: "chat",
|
|
2099
|
-
});
|
|
2100
|
-
const fallback = `Saved "${created.definition.title}" as ${summarizeCadence(created.definition.cadence)}.`;
|
|
2101
|
-
return {
|
|
2102
|
-
success: true,
|
|
2103
|
-
text: await renderLifeActionReply({
|
|
2104
|
-
runtime,
|
|
2105
|
-
message,
|
|
2106
|
-
state,
|
|
2107
|
-
intent,
|
|
2108
|
-
scenario: "saved_definition",
|
|
2109
|
-
fallback,
|
|
2110
|
-
context: {
|
|
2111
|
-
created: {
|
|
2112
|
-
title: created.definition.title,
|
|
2113
|
-
cadence: created.definition.cadence,
|
|
2114
|
-
},
|
|
2115
|
-
requestKind: timedRequestKind,
|
|
2116
|
-
},
|
|
2117
|
-
}),
|
|
2118
|
-
data: toActionData(created),
|
|
2119
|
-
};
|
|
2120
|
-
};
|
|
2121
|
-
// ── Queries ─────────────────────────────────────
|
|
2122
|
-
if (operation === "query_calendar_today" ||
|
|
2123
|
-
operation === "query_calendar_next") {
|
|
2124
|
-
const google = await getGoogleCapabilityStatus(service);
|
|
2125
|
-
if (!google.hasCalendarRead) {
|
|
2126
|
-
return {
|
|
2127
|
-
success: false,
|
|
2128
|
-
text: calendarReadUnavailableMessage(google),
|
|
2129
|
-
};
|
|
2130
|
-
}
|
|
2131
|
-
if (operation === "query_calendar_next") {
|
|
2132
|
-
const ctx = await service.getNextCalendarEventContext(INTERNAL_URL);
|
|
2133
|
-
return {
|
|
2134
|
-
success: true,
|
|
2135
|
-
text: formatNextEventContext(ctx),
|
|
2136
|
-
data: toActionData(ctx),
|
|
2137
|
-
};
|
|
2138
|
-
}
|
|
2139
|
-
// The planner extracts the time window as a structured `when` param
|
|
2140
|
-
// ("today" | "tomorrow" | "this_week"), so we never re-parse the
|
|
2141
|
-
// free-form `intent` string at runtime. Default to "today" when the
|
|
2142
|
-
// caller omits it.
|
|
2143
|
-
const whenRaw = detailString(details, "when")?.toLowerCase().trim();
|
|
2144
|
-
const when = whenRaw === "tomorrow"
|
|
2145
|
-
? "tomorrow"
|
|
2146
|
-
: whenRaw === "this_week" || whenRaw === "this week" || whenRaw === "week"
|
|
2147
|
-
? "this_week"
|
|
2148
|
-
: "today";
|
|
2149
|
-
const range = when === "tomorrow"
|
|
2150
|
-
? dayRange(1)
|
|
2151
|
-
: when === "this_week"
|
|
2152
|
-
? weekRange()
|
|
2153
|
-
: dayRange(0);
|
|
2154
|
-
const label = when === "tomorrow"
|
|
2155
|
-
? "tomorrow"
|
|
2156
|
-
: when === "this_week"
|
|
2157
|
-
? "this week"
|
|
2158
|
-
: "today";
|
|
2159
|
-
const feed = await service.getCalendarFeed(INTERNAL_URL, {
|
|
2160
|
-
includeHiddenCalendars: true,
|
|
2161
|
-
timeMin: range.timeMin,
|
|
2162
|
-
timeMax: range.timeMax,
|
|
2163
|
-
});
|
|
2164
|
-
return {
|
|
2165
|
-
success: true,
|
|
2166
|
-
text: formatCalendarFeed(feed, label),
|
|
2167
|
-
data: toActionData(feed),
|
|
2168
|
-
};
|
|
2169
|
-
}
|
|
2170
|
-
if (operation === "query_email") {
|
|
2171
|
-
const limit = detailNumber(details, "limit") ?? 10;
|
|
2172
|
-
return ((await gmailAction.handler?.(runtime, message, state, {
|
|
2173
|
-
parameters: {
|
|
2174
|
-
subaction: "triage",
|
|
2175
|
-
intent,
|
|
2176
|
-
details: {
|
|
2177
|
-
...details,
|
|
2178
|
-
maxResults: limit,
|
|
2179
|
-
},
|
|
2180
|
-
},
|
|
2181
|
-
})) ?? {
|
|
2182
|
-
success: false,
|
|
2183
|
-
text: "I couldn't route that Gmail request yet.",
|
|
2184
|
-
});
|
|
2185
|
-
}
|
|
2186
|
-
if (operation === "query_overview") {
|
|
2187
|
-
const overview = await service.getOverview();
|
|
2188
|
-
const userQuery = messageText(message) || intent || "overview";
|
|
2189
|
-
const fallback = formatOverviewForQuery(overview, userQuery);
|
|
2190
|
-
return {
|
|
2191
|
-
success: true,
|
|
2192
|
-
text: await renderLifeActionReply({
|
|
2193
|
-
runtime,
|
|
2194
|
-
message,
|
|
2195
|
-
state,
|
|
2196
|
-
intent: userQuery,
|
|
2197
|
-
scenario: "overview",
|
|
2198
|
-
fallback,
|
|
2199
|
-
context: {
|
|
2200
|
-
summary: overview.owner.summary,
|
|
2201
|
-
occurrenceTitles: overview.owner.occurrences
|
|
2202
|
-
.slice(0, 6)
|
|
2203
|
-
.map((occurrence) => occurrence.title),
|
|
2204
|
-
goalTitles: overview.owner.goals
|
|
2205
|
-
.slice(0, 3)
|
|
2206
|
-
.map((goal) => goal.title),
|
|
2207
|
-
},
|
|
2208
|
-
}),
|
|
2209
|
-
data: toActionData(overview),
|
|
2210
|
-
};
|
|
2211
|
-
}
|
|
2212
|
-
// ── Mutations ───────────────────────────────────
|
|
2213
|
-
if (operation === "create_definition") {
|
|
2214
|
-
return await createDefinition();
|
|
2215
|
-
}
|
|
2216
|
-
if (operation === "create_goal") {
|
|
2217
|
-
const deferredGoalDraft = reuseDeferredDraft && deferredDraft?.operation === "create_goal"
|
|
2218
|
-
? deferredDraft
|
|
2219
|
-
: null;
|
|
2220
|
-
const editingDeferredGoalDraft = deferredDraftReuseMode === "edit" &&
|
|
2221
|
-
deferredGoalDraft?.operation === "create_goal";
|
|
2222
|
-
const explicitDescription = detailString(details, "description");
|
|
2223
|
-
const explicitCadence = normalizeCadenceDetail(detailObject(details, "cadence"));
|
|
2224
|
-
const explicitSuccessCriteria = detailObject(details, "successCriteria");
|
|
2225
|
-
const explicitSupportStrategy = detailObject(details, "supportStrategy");
|
|
2226
|
-
const explicitMetadata = detailObject(details, "metadata");
|
|
2227
|
-
let title = editingDeferredGoalDraft
|
|
2228
|
-
? (params.title ?? deferredGoalDraft?.request.title ?? null)
|
|
2229
|
-
: (deferredGoalDraft?.request.title ?? params.title ?? null);
|
|
2230
|
-
let description = editingDeferredGoalDraft
|
|
2231
|
-
? (explicitDescription ?? deferredGoalDraft?.request.description)
|
|
2232
|
-
: (deferredGoalDraft?.request.description ?? explicitDescription);
|
|
2233
|
-
let cadence = editingDeferredGoalDraft
|
|
2234
|
-
? (explicitCadence ?? deferredGoalDraft?.request.cadence)
|
|
2235
|
-
: (deferredGoalDraft?.request.cadence ?? explicitCadence);
|
|
2236
|
-
let successCriteria = editingDeferredGoalDraft
|
|
2237
|
-
? (explicitSuccessCriteria ??
|
|
2238
|
-
deferredGoalDraft?.request.successCriteria)
|
|
2239
|
-
: (deferredGoalDraft?.request.successCriteria ??
|
|
2240
|
-
explicitSuccessCriteria);
|
|
2241
|
-
let supportStrategy = editingDeferredGoalDraft
|
|
2242
|
-
? (explicitSupportStrategy ??
|
|
2243
|
-
deferredGoalDraft?.request.supportStrategy)
|
|
2244
|
-
: (deferredGoalDraft?.request.supportStrategy ??
|
|
2245
|
-
explicitSupportStrategy);
|
|
2246
|
-
let goalMetadata = editingDeferredGoalDraft
|
|
2247
|
-
? (explicitMetadata ?? deferredGoalDraft?.request.metadata)
|
|
2248
|
-
: (deferredGoalDraft?.request.metadata ?? explicitMetadata);
|
|
2249
|
-
let evaluationSummary = null;
|
|
2250
|
-
const hasExplicitGroundedGoal = Boolean(title) &&
|
|
2251
|
-
(createConfirmed ||
|
|
2252
|
-
(Boolean(successCriteria) && Boolean(supportStrategy)));
|
|
2253
|
-
if ((!deferredGoalDraft || editingDeferredGoalDraft) &&
|
|
2254
|
-
!hasExplicitGroundedGoal) {
|
|
2255
|
-
const llmPlan = await extractGoalCreatePlanWithLlm({
|
|
2256
|
-
runtime,
|
|
2257
|
-
intent,
|
|
2258
|
-
state: state ?? undefined,
|
|
2259
|
-
message: message ?? undefined,
|
|
2260
|
-
});
|
|
2261
|
-
if (!title && llmPlan.title) {
|
|
2262
|
-
title = llmPlan.title;
|
|
2263
|
-
}
|
|
2264
|
-
if (!description && llmPlan.description) {
|
|
2265
|
-
description = llmPlan.description;
|
|
2266
|
-
}
|
|
2267
|
-
if (!cadence && llmPlan.cadence) {
|
|
2268
|
-
cadence = llmPlan.cadence;
|
|
2269
|
-
}
|
|
2270
|
-
if (!successCriteria && llmPlan.successCriteria) {
|
|
2271
|
-
successCriteria = llmPlan.successCriteria;
|
|
2272
|
-
}
|
|
2273
|
-
if (!supportStrategy && llmPlan.supportStrategy) {
|
|
2274
|
-
supportStrategy = llmPlan.supportStrategy;
|
|
2275
|
-
}
|
|
2276
|
-
evaluationSummary = llmPlan.evaluationSummary;
|
|
2277
|
-
if (llmPlan.groundingState === "grounded" &&
|
|
2278
|
-
llmPlan.successCriteria &&
|
|
2279
|
-
title) {
|
|
2280
|
-
goalMetadata = mergeGoalMetadataWithGrounding({
|
|
2281
|
-
metadata: {
|
|
2282
|
-
...(goalMetadata ?? {}),
|
|
2283
|
-
source: "chat",
|
|
2284
|
-
originalIntent: intent,
|
|
2285
|
-
},
|
|
2286
|
-
nowIso: new Date().toISOString(),
|
|
2287
|
-
plan: llmPlan,
|
|
2288
|
-
});
|
|
2289
|
-
}
|
|
2290
|
-
if (llmPlan.groundingState !== "grounded" ||
|
|
2291
|
-
!title ||
|
|
2292
|
-
!successCriteria ||
|
|
2293
|
-
!supportStrategy) {
|
|
2294
|
-
// A clarification request is a successful outcome from the
|
|
2295
|
-
// agent's point of view — the agent chose to ask instead of
|
|
2296
|
-
// invent an ungrounded goal. Callers rely on `success: true +
|
|
2297
|
-
// data.noop: true` to distinguish a deliberate clarify from a
|
|
2298
|
-
// handler error.
|
|
2299
|
-
return {
|
|
2300
|
-
success: true,
|
|
2301
|
-
text: llmPlan.response ??
|
|
2302
|
-
"What would count as success for that goal, and over what time window?",
|
|
2303
|
-
values: {
|
|
2304
|
-
success: true,
|
|
2305
|
-
error: "NOOP_GOAL_UNGROUNDED",
|
|
2306
|
-
noop: true,
|
|
2307
|
-
suggestedOperation: "create_goal",
|
|
2308
|
-
},
|
|
2309
|
-
data: {
|
|
2310
|
-
actionName: "LIFE",
|
|
2311
|
-
noop: true,
|
|
2312
|
-
error: "NOOP_GOAL_UNGROUNDED",
|
|
2313
|
-
suggestedOperation: "create_goal",
|
|
2314
|
-
},
|
|
2315
|
-
};
|
|
2316
|
-
}
|
|
2317
|
-
}
|
|
2318
|
-
if (!title)
|
|
2319
|
-
return {
|
|
2320
|
-
success: false,
|
|
2321
|
-
text: await renderLifeActionReply({
|
|
2322
|
-
runtime,
|
|
2323
|
-
message,
|
|
2324
|
-
state,
|
|
2325
|
-
intent,
|
|
2326
|
-
scenario: "clarify_create_goal",
|
|
2327
|
-
fallback: "What are you trying to achieve?",
|
|
2328
|
-
context: {
|
|
2329
|
-
missing: ["title"],
|
|
2330
|
-
operation: "create_goal",
|
|
2331
|
-
},
|
|
2332
|
-
}),
|
|
2333
|
-
};
|
|
2334
|
-
const goalDraft = deferredGoalDraft ?? {
|
|
2335
|
-
intent,
|
|
2336
|
-
operation: "create_goal",
|
|
2337
|
-
createdAt: Date.now(),
|
|
2338
|
-
request: {
|
|
2339
|
-
cadence,
|
|
2340
|
-
description,
|
|
2341
|
-
metadata: goalMetadata,
|
|
2342
|
-
successCriteria,
|
|
2343
|
-
supportStrategy,
|
|
2344
|
-
title,
|
|
2345
|
-
},
|
|
2346
|
-
};
|
|
2347
|
-
const experienceLoop = await service.buildGoalExperienceLoop({
|
|
2348
|
-
title: goalDraft.request.title,
|
|
2349
|
-
description: goalDraft.request.description,
|
|
2350
|
-
successCriteria: goalDraft.request.successCriteria ??
|
|
2351
|
-
null,
|
|
2352
|
-
});
|
|
2353
|
-
if (shouldRequireLifeCreateConfirmation({
|
|
2354
|
-
confirmed: createConfirmed,
|
|
2355
|
-
messageSource: typeof message.content?.source === "string"
|
|
2356
|
-
? message.content.source
|
|
2357
|
-
: undefined,
|
|
2358
|
-
})) {
|
|
2359
|
-
const fallbackParts = [
|
|
2360
|
-
evaluationSummary
|
|
2361
|
-
? `I can save "${goalDraft.request.title}" as a goal. Success looks like this: ${evaluationSummary} Confirm and I'll save it, or tell me what to change.`
|
|
2362
|
-
: `I can save this goal as "${goalDraft.request.title}". Confirm and I'll save it, or tell me what to change.`,
|
|
2363
|
-
];
|
|
2364
|
-
const experienceSummary = formatGoalExperienceLoopSummary(experienceLoop);
|
|
2365
|
-
if (experienceSummary) {
|
|
2366
|
-
fallbackParts.push(experienceSummary);
|
|
2367
|
-
}
|
|
2368
|
-
return {
|
|
2369
|
-
success: true,
|
|
2370
|
-
text: await renderLifeActionReply({
|
|
2371
|
-
runtime,
|
|
2372
|
-
message,
|
|
2373
|
-
state,
|
|
2374
|
-
intent,
|
|
2375
|
-
scenario: "preview_goal",
|
|
2376
|
-
fallback: fallbackParts.join(" "),
|
|
2377
|
-
context: {
|
|
2378
|
-
draft: goalDraft.request,
|
|
2379
|
-
groundingSummary: evaluationSummary,
|
|
2380
|
-
experienceLoop,
|
|
2381
|
-
},
|
|
2382
|
-
}),
|
|
2383
|
-
data: {
|
|
2384
|
-
actionName: "LIFE",
|
|
2385
|
-
deferred: true,
|
|
2386
|
-
lifeDraft: goalDraft,
|
|
2387
|
-
experienceLoop,
|
|
2388
|
-
preview: {
|
|
2389
|
-
title: goalDraft.request.title,
|
|
2390
|
-
},
|
|
2391
|
-
},
|
|
2392
|
-
};
|
|
2393
|
-
}
|
|
2394
|
-
const created = await service.createGoal({
|
|
2395
|
-
ownership,
|
|
2396
|
-
title: goalDraft.request.title,
|
|
2397
|
-
description: goalDraft.request.description,
|
|
2398
|
-
cadence: goalDraft.request.cadence,
|
|
2399
|
-
supportStrategy: goalDraft.request.supportStrategy,
|
|
2400
|
-
successCriteria: goalDraft.request.successCriteria,
|
|
2401
|
-
metadata: {
|
|
2402
|
-
...(goalDraft.request.metadata ?? {}),
|
|
2403
|
-
source: "chat",
|
|
2404
|
-
originalIntent: goalDraft.intent || goalDraft.request.title,
|
|
2405
|
-
},
|
|
2406
|
-
});
|
|
2407
|
-
const createdExperienceLoop = await service.buildGoalExperienceLoop({
|
|
2408
|
-
goalId: created.goal.id,
|
|
2409
|
-
title: created.goal.title,
|
|
2410
|
-
description: created.goal.description,
|
|
2411
|
-
successCriteria: created.goal.successCriteria ??
|
|
2412
|
-
null,
|
|
2413
|
-
});
|
|
2414
|
-
const experienceSummary = formatGoalExperienceLoopSummary(createdExperienceLoop);
|
|
2415
|
-
const fallback = experienceSummary
|
|
2416
|
-
? `Saved goal "${created.goal.title}". ${experienceSummary}`
|
|
2417
|
-
: `Saved goal "${created.goal.title}".`;
|
|
2418
|
-
return {
|
|
2419
|
-
success: true,
|
|
2420
|
-
text: await renderLifeActionReply({
|
|
2421
|
-
runtime,
|
|
2422
|
-
message,
|
|
2423
|
-
state,
|
|
2424
|
-
intent,
|
|
2425
|
-
scenario: "saved_goal",
|
|
2426
|
-
fallback,
|
|
2427
|
-
context: {
|
|
2428
|
-
created: {
|
|
2429
|
-
title: created.goal.title,
|
|
2430
|
-
cadence: created.goal.cadence,
|
|
2431
|
-
},
|
|
2432
|
-
experienceLoop: createdExperienceLoop,
|
|
2433
|
-
},
|
|
2434
|
-
}),
|
|
2435
|
-
data: toActionData({
|
|
2436
|
-
...created,
|
|
2437
|
-
experienceLoop: createdExperienceLoop,
|
|
2438
|
-
}),
|
|
2439
|
-
};
|
|
2440
|
-
}
|
|
2441
|
-
if (operation === "update_definition") {
|
|
2442
|
-
const target = await resolveDefinition(service, targetName, domain);
|
|
2443
|
-
if (!target)
|
|
2444
|
-
return {
|
|
2445
|
-
success: false,
|
|
2446
|
-
text: "I could not find that item to update.",
|
|
2447
|
-
};
|
|
2448
|
-
const request = {
|
|
2449
|
-
ownership,
|
|
2450
|
-
title: params.title !== target.definition.title ? params.title : undefined,
|
|
2451
|
-
description: detailString(details, "description"),
|
|
2452
|
-
cadence: normalizeCadenceDetail(detailObject(details, "cadence")),
|
|
2453
|
-
priority: detailNumber(details, "priority"),
|
|
2454
|
-
windowPolicy: detailObject(details, "windowPolicy"),
|
|
2455
|
-
reminderPlan: detailObject(details, "reminderPlan"),
|
|
2456
|
-
};
|
|
2457
|
-
// If no explicit changes from structured details, try LLM extraction
|
|
2458
|
-
const hasExplicitChanges = hasDefinitionUpdateChanges(request);
|
|
2459
|
-
if (!hasExplicitChanges && intent) {
|
|
2460
|
-
const llmFields = await extractUpdateFieldsWithLlm({
|
|
2461
|
-
runtime,
|
|
2462
|
-
intent,
|
|
2463
|
-
currentTitle: target.definition.title,
|
|
2464
|
-
currentCadenceKind: target.definition.cadence.kind,
|
|
2465
|
-
currentWindows: target.definition.windowPolicy?.windows?.map((w) => w.name) ?? [],
|
|
2466
|
-
});
|
|
2467
|
-
if (llmFields) {
|
|
2468
|
-
if (llmFields.title)
|
|
2469
|
-
request.title = llmFields.title;
|
|
2470
|
-
if (llmFields.priority)
|
|
2471
|
-
request.priority = llmFields.priority;
|
|
2472
|
-
if (llmFields.description)
|
|
2473
|
-
request.description = llmFields.description;
|
|
2474
|
-
if (llmFields.cadenceKind ||
|
|
2475
|
-
llmFields.windows ||
|
|
2476
|
-
llmFields.weekdays ||
|
|
2477
|
-
llmFields.everyMinutes ||
|
|
2478
|
-
llmFields.timeOfDay) {
|
|
2479
|
-
const built = buildCadenceFromUpdateFields({
|
|
2480
|
-
currentCadence: target.definition.cadence,
|
|
2481
|
-
currentWindowPolicy: target.definition.windowPolicy,
|
|
2482
|
-
timeZone: target.definition.timezone,
|
|
2483
|
-
update: llmFields,
|
|
2484
|
-
});
|
|
2485
|
-
if (built) {
|
|
2486
|
-
request.cadence = built.cadence;
|
|
2487
|
-
request.windowPolicy = built.windowPolicy;
|
|
2488
|
-
}
|
|
2489
|
-
}
|
|
2490
|
-
}
|
|
2491
|
-
}
|
|
2492
|
-
if (!hasDefinitionUpdateChanges(request)) {
|
|
2493
|
-
return {
|
|
2494
|
-
success: false,
|
|
2495
|
-
text: `Tell me what to change about "${target.definition.title}" and I'll update it.`,
|
|
2496
|
-
};
|
|
2497
|
-
}
|
|
2498
|
-
const updated = await service.updateDefinition(target.definition.id, request);
|
|
2499
|
-
const fallback = `Updated "${updated.definition.title}".`;
|
|
2500
|
-
return {
|
|
2501
|
-
success: true,
|
|
2502
|
-
text: await renderLifeActionReply({
|
|
2503
|
-
runtime,
|
|
2504
|
-
message,
|
|
2505
|
-
state,
|
|
2506
|
-
intent,
|
|
2507
|
-
scenario: "updated_definition",
|
|
2508
|
-
fallback,
|
|
2509
|
-
context: {
|
|
2510
|
-
previousTitle: target.definition.title,
|
|
2511
|
-
updated: {
|
|
2512
|
-
title: updated.definition.title,
|
|
2513
|
-
},
|
|
2514
|
-
},
|
|
2515
|
-
}),
|
|
2516
|
-
data: toActionData(updated),
|
|
2517
|
-
};
|
|
2518
|
-
}
|
|
2519
|
-
if (operation === "update_goal") {
|
|
2520
|
-
const target = await resolveGoal(service, targetName, domain);
|
|
2521
|
-
if (!target)
|
|
2522
|
-
return {
|
|
2523
|
-
success: false,
|
|
2524
|
-
text: "I could not find that goal to update.",
|
|
2525
|
-
};
|
|
2526
|
-
const request = {
|
|
2527
|
-
ownership,
|
|
2528
|
-
title: params.title !== target.goal.title ? params.title : undefined,
|
|
2529
|
-
description: detailString(details, "description"),
|
|
2530
|
-
cadence: normalizeCadenceDetail(detailObject(details, "cadence")),
|
|
2531
|
-
supportStrategy: detailObject(details, "supportStrategy"),
|
|
2532
|
-
successCriteria: detailObject(details, "successCriteria"),
|
|
2533
|
-
};
|
|
2534
|
-
const hasExplicitGoalChanges = request.title !== undefined ||
|
|
2535
|
-
request.description !== undefined ||
|
|
2536
|
-
request.cadence !== undefined ||
|
|
2537
|
-
request.supportStrategy !== undefined ||
|
|
2538
|
-
request.successCriteria !== undefined;
|
|
2539
|
-
if (!hasExplicitGoalChanges) {
|
|
2540
|
-
const llmPlan = await extractGoalUpdatePlanWithLlm({
|
|
2541
|
-
runtime,
|
|
2542
|
-
currentGoal: target.goal,
|
|
2543
|
-
intent,
|
|
2544
|
-
state: state ?? undefined,
|
|
2545
|
-
message: message ?? undefined,
|
|
2546
|
-
});
|
|
2547
|
-
if (llmPlan.mode === "respond") {
|
|
2548
|
-
return {
|
|
2549
|
-
success: true,
|
|
2550
|
-
text: llmPlan.response ??
|
|
2551
|
-
`Tell me what to change about "${target.goal.title}" and I'll update it.`,
|
|
2552
|
-
data: {
|
|
2553
|
-
actionName: "LIFE",
|
|
2554
|
-
noop: true,
|
|
2555
|
-
suggestedOperation: "update_goal",
|
|
2556
|
-
},
|
|
2557
|
-
};
|
|
2558
|
-
}
|
|
2559
|
-
if (llmPlan.title)
|
|
2560
|
-
request.title = llmPlan.title;
|
|
2561
|
-
if (llmPlan.description)
|
|
2562
|
-
request.description = llmPlan.description;
|
|
2563
|
-
if (llmPlan.cadence)
|
|
2564
|
-
request.cadence = llmPlan.cadence;
|
|
2565
|
-
if (llmPlan.supportStrategy)
|
|
2566
|
-
request.supportStrategy = llmPlan.supportStrategy;
|
|
2567
|
-
if (llmPlan.successCriteria)
|
|
2568
|
-
request.successCriteria = llmPlan.successCriteria;
|
|
2569
|
-
if (llmPlan.groundingState) {
|
|
2570
|
-
request.metadata = mergeGoalMetadataWithGrounding({
|
|
2571
|
-
metadata: target.goal.metadata,
|
|
2572
|
-
nowIso: new Date().toISOString(),
|
|
2573
|
-
plan: {
|
|
2574
|
-
cadence: llmPlan.cadence,
|
|
2575
|
-
confidence: llmPlan.confidence,
|
|
2576
|
-
evaluationSummary: llmPlan.evaluationSummary,
|
|
2577
|
-
groundingState: llmPlan.groundingState,
|
|
2578
|
-
missingCriticalFields: llmPlan.missingCriticalFields,
|
|
2579
|
-
successCriteria: llmPlan.successCriteria ?? target.goal.successCriteria,
|
|
2580
|
-
targetDomain: llmPlan.targetDomain,
|
|
2581
|
-
},
|
|
2582
|
-
});
|
|
2583
|
-
}
|
|
2584
|
-
}
|
|
2585
|
-
if (request.title === undefined &&
|
|
2586
|
-
request.description === undefined &&
|
|
2587
|
-
request.cadence === undefined &&
|
|
2588
|
-
request.supportStrategy === undefined &&
|
|
2589
|
-
request.successCriteria === undefined &&
|
|
2590
|
-
request.metadata === undefined) {
|
|
2591
|
-
return {
|
|
2592
|
-
success: false,
|
|
2593
|
-
text: `Tell me what to change about "${target.goal.title}" and I'll update it.`,
|
|
2594
|
-
};
|
|
2595
|
-
}
|
|
2596
|
-
const updated = await service.updateGoal(target.goal.id, request);
|
|
2597
|
-
const fallback = `Updated goal "${updated.goal.title}".`;
|
|
2598
|
-
return {
|
|
2599
|
-
success: true,
|
|
2600
|
-
text: await renderLifeActionReply({
|
|
2601
|
-
runtime,
|
|
2602
|
-
message,
|
|
2603
|
-
state,
|
|
2604
|
-
intent,
|
|
2605
|
-
scenario: "updated_goal",
|
|
2606
|
-
fallback,
|
|
2607
|
-
context: {
|
|
2608
|
-
previousTitle: target.goal.title,
|
|
2609
|
-
updated: {
|
|
2610
|
-
title: updated.goal.title,
|
|
2611
|
-
},
|
|
2612
|
-
},
|
|
2613
|
-
}),
|
|
2614
|
-
data: toActionData(updated),
|
|
2615
|
-
};
|
|
2616
|
-
}
|
|
2617
|
-
if (operation === "delete_definition") {
|
|
2618
|
-
const target = await resolveDefinition(service, targetName, domain);
|
|
2619
|
-
if (!target)
|
|
2620
|
-
return {
|
|
2621
|
-
success: false,
|
|
2622
|
-
text: "I could not find that item to delete.",
|
|
2623
|
-
};
|
|
2624
|
-
await service.deleteDefinition(target.definition.id);
|
|
2625
|
-
const fallback = `Deleted "${target.definition.title}" and its occurrences.`;
|
|
2626
|
-
return {
|
|
2627
|
-
success: true,
|
|
2628
|
-
text: await renderLifeActionReply({
|
|
2629
|
-
runtime,
|
|
2630
|
-
message,
|
|
2631
|
-
state,
|
|
2632
|
-
intent,
|
|
2633
|
-
scenario: "deleted_definition",
|
|
2634
|
-
fallback,
|
|
2635
|
-
context: {
|
|
2636
|
-
deleted: {
|
|
2637
|
-
title: target.definition.title,
|
|
2638
|
-
},
|
|
2639
|
-
},
|
|
2640
|
-
}),
|
|
2641
|
-
};
|
|
2642
|
-
}
|
|
2643
|
-
if (operation === "delete_goal") {
|
|
2644
|
-
const target = await resolveGoal(service, targetName, domain);
|
|
2645
|
-
if (!target)
|
|
2646
|
-
return {
|
|
2647
|
-
success: false,
|
|
2648
|
-
text: "I could not find that goal to delete.",
|
|
2649
|
-
};
|
|
2650
|
-
await service.deleteGoal(target.goal.id);
|
|
2651
|
-
const fallback = `Deleted goal "${target.goal.title}".`;
|
|
2652
|
-
return {
|
|
2653
|
-
success: true,
|
|
2654
|
-
text: await renderLifeActionReply({
|
|
2655
|
-
runtime,
|
|
2656
|
-
message,
|
|
2657
|
-
state,
|
|
2658
|
-
intent,
|
|
2659
|
-
scenario: "deleted_goal",
|
|
2660
|
-
fallback,
|
|
2661
|
-
context: {
|
|
2662
|
-
deleted: {
|
|
2663
|
-
title: target.goal.title,
|
|
2664
|
-
},
|
|
2665
|
-
},
|
|
2666
|
-
}),
|
|
2667
|
-
};
|
|
2668
|
-
}
|
|
2669
|
-
if (operation === "complete_occurrence") {
|
|
2670
|
-
const { match: target, ambiguousCandidates } = await resolveOccurrenceWithIntentFallback({
|
|
2671
|
-
service,
|
|
2672
|
-
target: targetName,
|
|
2673
|
-
domain,
|
|
2674
|
-
intent,
|
|
2675
|
-
operation,
|
|
2676
|
-
});
|
|
2677
|
-
if (!target) {
|
|
2678
|
-
if (ambiguousCandidates.length > 0) {
|
|
2679
|
-
return {
|
|
2680
|
-
success: false,
|
|
2681
|
-
text: `Multiple items match — which one?\n${ambiguousCandidates.map((t) => ` - ${t}`).join("\n")}`,
|
|
2682
|
-
};
|
|
2683
|
-
}
|
|
2684
|
-
return {
|
|
2685
|
-
success: false,
|
|
2686
|
-
text: "I could not find that active item to complete.",
|
|
2687
|
-
};
|
|
2688
|
-
}
|
|
2689
|
-
const completed = await service.completeOccurrence(target.id, {
|
|
2690
|
-
note: detailString(details, "note"),
|
|
2691
|
-
});
|
|
2692
|
-
const fallback = `Marked "${completed.title}" done.`;
|
|
2693
|
-
return {
|
|
2694
|
-
success: true,
|
|
2695
|
-
text: await renderLifeActionReply({
|
|
2696
|
-
runtime,
|
|
2697
|
-
message,
|
|
2698
|
-
state,
|
|
2699
|
-
intent,
|
|
2700
|
-
scenario: "completed_occurrence",
|
|
2701
|
-
fallback,
|
|
2702
|
-
context: {
|
|
2703
|
-
completed: {
|
|
2704
|
-
title: completed.title,
|
|
2705
|
-
},
|
|
2706
|
-
note: detailString(details, "note"),
|
|
2707
|
-
},
|
|
2708
|
-
}),
|
|
2709
|
-
data: toActionData(completed),
|
|
2710
|
-
};
|
|
2711
|
-
}
|
|
2712
|
-
if (operation === "skip_occurrence") {
|
|
2713
|
-
const { match: target, ambiguousCandidates } = await resolveOccurrenceWithIntentFallback({
|
|
2714
|
-
service,
|
|
2715
|
-
target: targetName,
|
|
2716
|
-
domain,
|
|
2717
|
-
intent,
|
|
2718
|
-
operation,
|
|
2719
|
-
});
|
|
2720
|
-
if (!target) {
|
|
2721
|
-
if (ambiguousCandidates.length > 0) {
|
|
2722
|
-
return {
|
|
2723
|
-
success: false,
|
|
2724
|
-
text: `Multiple items match — which one?\n${ambiguousCandidates.map((t) => ` - ${t}`).join("\n")}`,
|
|
2725
|
-
};
|
|
2726
|
-
}
|
|
2727
|
-
return {
|
|
2728
|
-
success: false,
|
|
2729
|
-
text: "I could not find that active item to skip.",
|
|
2730
|
-
};
|
|
2731
|
-
}
|
|
2732
|
-
const skipped = await service.skipOccurrence(target.id);
|
|
2733
|
-
const fallback = `Skipped "${skipped.title}".`;
|
|
2734
|
-
return {
|
|
2735
|
-
success: true,
|
|
2736
|
-
text: await renderLifeActionReply({
|
|
2737
|
-
runtime,
|
|
2738
|
-
message,
|
|
2739
|
-
state,
|
|
2740
|
-
intent,
|
|
2741
|
-
scenario: "skipped_occurrence",
|
|
2742
|
-
fallback,
|
|
2743
|
-
context: {
|
|
2744
|
-
skipped: {
|
|
2745
|
-
title: skipped.title,
|
|
2746
|
-
},
|
|
2747
|
-
},
|
|
2748
|
-
}),
|
|
2749
|
-
data: toActionData(skipped),
|
|
2750
|
-
};
|
|
2751
|
-
}
|
|
2752
|
-
if (operation === "snooze_occurrence") {
|
|
2753
|
-
const { match: target, ambiguousCandidates } = await resolveOccurrenceWithIntentFallback({
|
|
2754
|
-
service,
|
|
2755
|
-
target: targetName,
|
|
2756
|
-
domain,
|
|
2757
|
-
intent,
|
|
2758
|
-
operation,
|
|
2759
|
-
});
|
|
2760
|
-
if (!target) {
|
|
2761
|
-
if (ambiguousCandidates.length > 0) {
|
|
2762
|
-
return {
|
|
2763
|
-
success: false,
|
|
2764
|
-
text: `Multiple items match — which one?\n${ambiguousCandidates.map((t) => ` - ${t}`).join("\n")}`,
|
|
2765
|
-
};
|
|
2766
|
-
}
|
|
2767
|
-
return {
|
|
2768
|
-
success: false,
|
|
2769
|
-
text: "I could not find that active item to snooze.",
|
|
2770
|
-
};
|
|
2771
|
-
}
|
|
2772
|
-
const preset = detailString(details, "preset");
|
|
2773
|
-
const minutes = detailNumber(details, "minutes");
|
|
2774
|
-
const snoozed = await service.snoozeOccurrence(target.id, {
|
|
2775
|
-
preset,
|
|
2776
|
-
minutes,
|
|
2777
|
-
});
|
|
2778
|
-
const fallback = `Snoozed "${snoozed.title}".`;
|
|
2779
|
-
return {
|
|
2780
|
-
success: true,
|
|
2781
|
-
text: await renderLifeActionReply({
|
|
2782
|
-
runtime,
|
|
2783
|
-
message,
|
|
2784
|
-
state,
|
|
2785
|
-
intent,
|
|
2786
|
-
scenario: "snoozed_occurrence",
|
|
2787
|
-
fallback,
|
|
2788
|
-
context: {
|
|
2789
|
-
snoozed: {
|
|
2790
|
-
title: snoozed.title,
|
|
2791
|
-
},
|
|
2792
|
-
preset: preset ?? null,
|
|
2793
|
-
minutes: minutes ?? null,
|
|
2794
|
-
},
|
|
2795
|
-
}),
|
|
2796
|
-
data: toActionData(snoozed),
|
|
2797
|
-
};
|
|
2798
|
-
}
|
|
2799
|
-
if (operation === "review_goal") {
|
|
2800
|
-
const target = await resolveGoal(service, targetName, domain);
|
|
2801
|
-
if (!target) {
|
|
2802
|
-
const weeklyReview = await service.reviewGoalsForWeek();
|
|
2803
|
-
if (weeklyReview.summary.totalGoals === 0) {
|
|
2804
|
-
return {
|
|
2805
|
-
success: false,
|
|
2806
|
-
text: "I could not find any active goals to review.",
|
|
2807
|
-
};
|
|
2808
|
-
}
|
|
2809
|
-
const fallback = formatWeeklyGoalReview(weeklyReview);
|
|
2810
|
-
return {
|
|
2811
|
-
success: true,
|
|
2812
|
-
text: await renderLifeActionReply({
|
|
2813
|
-
runtime,
|
|
2814
|
-
message,
|
|
2815
|
-
state,
|
|
2816
|
-
intent,
|
|
2817
|
-
scenario: "weekly_goal_review",
|
|
2818
|
-
fallback,
|
|
2819
|
-
context: {
|
|
2820
|
-
summary: weeklyReview.summary,
|
|
2821
|
-
atRiskTitles: weeklyReview.atRisk
|
|
2822
|
-
.slice(0, 3)
|
|
2823
|
-
.map((review) => review.goal.title),
|
|
2824
|
-
needsAttentionTitles: weeklyReview.needsAttention
|
|
2825
|
-
.slice(0, 3)
|
|
2826
|
-
.map((review) => review.goal.title),
|
|
2827
|
-
onTrackTitles: weeklyReview.onTrack
|
|
2828
|
-
.slice(0, 3)
|
|
2829
|
-
.map((review) => review.goal.title),
|
|
2830
|
-
},
|
|
2831
|
-
}),
|
|
2832
|
-
data: toActionData(weeklyReview),
|
|
2833
|
-
};
|
|
2834
|
-
}
|
|
2835
|
-
const review = await service.reviewGoal(target.goal.id);
|
|
2836
|
-
return {
|
|
2837
|
-
success: true,
|
|
2838
|
-
text: review.summary.explanation,
|
|
2839
|
-
data: toActionData(review),
|
|
2840
|
-
};
|
|
2841
|
-
}
|
|
2842
|
-
if (operation === "set_reminder_preference") {
|
|
2843
|
-
const reminderIntensityPlan = await extractReminderIntensityWithLlm({
|
|
2844
|
-
runtime,
|
|
2845
|
-
intent,
|
|
2846
|
-
});
|
|
2847
|
-
if (reminderIntensityPlan.intensity === "unknown") {
|
|
2848
|
-
return {
|
|
2849
|
-
success: false,
|
|
2850
|
-
text: "I need to know whether you want reminders minimal, normal, persistent, or high priority only.",
|
|
2851
|
-
};
|
|
2852
|
-
}
|
|
2853
|
-
const intensity = reminderIntensityPlan.intensity;
|
|
2854
|
-
const target = await resolveDefinitionFromIntent(service, targetName, intent, domain);
|
|
2855
|
-
const request = {
|
|
2856
|
-
intensity,
|
|
2857
|
-
definitionId: target?.definition.id ?? null,
|
|
2858
|
-
note: chatText || intent,
|
|
2859
|
-
};
|
|
2860
|
-
const preference = await service.setReminderPreference(request);
|
|
2861
|
-
if (target) {
|
|
2862
|
-
const fallback = intensity === "high_priority_only"
|
|
2863
|
-
? `Reminder intensity for "${target.definition.title}" is now high priority only.`
|
|
2864
|
-
: `Reminder intensity for "${target.definition.title}" is now ${describeReminderIntensity(preference.effective.intensity)}.`;
|
|
2865
|
-
return {
|
|
2866
|
-
success: true,
|
|
2867
|
-
text: await renderLifeActionReply({
|
|
2868
|
-
runtime,
|
|
2869
|
-
message,
|
|
2870
|
-
state,
|
|
2871
|
-
intent,
|
|
2872
|
-
scenario: "set_reminder_preference",
|
|
2873
|
-
fallback,
|
|
2874
|
-
context: {
|
|
2875
|
-
scope: "definition",
|
|
2876
|
-
targetTitle: target.definition.title,
|
|
2877
|
-
intensity: preference.effective.intensity,
|
|
2878
|
-
},
|
|
2879
|
-
}),
|
|
2880
|
-
data: toActionData(preference),
|
|
2881
|
-
};
|
|
2882
|
-
}
|
|
2883
|
-
const fallback = intensity === "high_priority_only"
|
|
2884
|
-
? "Global LifeOps reminders are now high priority only."
|
|
2885
|
-
: `Global LifeOps reminders are now ${describeReminderIntensity(preference.effective.intensity)}.`;
|
|
2886
|
-
return {
|
|
2887
|
-
success: true,
|
|
2888
|
-
text: await renderLifeActionReply({
|
|
2889
|
-
runtime,
|
|
2890
|
-
message,
|
|
2891
|
-
state,
|
|
2892
|
-
intent,
|
|
2893
|
-
scenario: "set_reminder_preference",
|
|
2894
|
-
fallback,
|
|
2895
|
-
context: {
|
|
2896
|
-
scope: "global",
|
|
2897
|
-
intensity: preference.effective.intensity,
|
|
2898
|
-
},
|
|
2899
|
-
}),
|
|
2900
|
-
data: toActionData(preference),
|
|
2901
|
-
};
|
|
2902
|
-
}
|
|
2903
|
-
if (operation === "capture_phone") {
|
|
2904
|
-
const phoneNumber = detailString(details, "phoneNumber") ?? params.title;
|
|
2905
|
-
if (!phoneNumber)
|
|
2906
|
-
return {
|
|
2907
|
-
success: false,
|
|
2908
|
-
text: "I need a phone number to set up SMS or voice contact.",
|
|
2909
|
-
};
|
|
2910
|
-
const allowSms = detailBoolean(details, "allowSms") ?? true;
|
|
2911
|
-
const allowVoice = detailBoolean(details, "allowVoice") ?? false;
|
|
2912
|
-
const result = await service.capturePhoneConsent({
|
|
2913
|
-
phoneNumber,
|
|
2914
|
-
consentGiven: true,
|
|
2915
|
-
allowSms,
|
|
2916
|
-
allowVoice,
|
|
2917
|
-
privacyClass: "private",
|
|
2918
|
-
});
|
|
2919
|
-
const channels = [];
|
|
2920
|
-
if (allowSms)
|
|
2921
|
-
channels.push("SMS");
|
|
2922
|
-
if (allowVoice)
|
|
2923
|
-
channels.push("voice calls");
|
|
2924
|
-
const fallback = `Phone number ${result.phoneNumber} saved. Enabled for: ${channels.join(" and ") || "reminders"}.`;
|
|
2925
|
-
return {
|
|
2926
|
-
success: true,
|
|
2927
|
-
text: await renderLifeActionReply({
|
|
2928
|
-
runtime,
|
|
2929
|
-
message,
|
|
2930
|
-
state,
|
|
2931
|
-
intent,
|
|
2932
|
-
scenario: "captured_phone",
|
|
2933
|
-
fallback,
|
|
2934
|
-
context: {
|
|
2935
|
-
phoneNumber: result.phoneNumber,
|
|
2936
|
-
channels,
|
|
2937
|
-
},
|
|
2938
|
-
}),
|
|
2939
|
-
data: toActionData(result),
|
|
2940
|
-
};
|
|
2941
|
-
}
|
|
2942
|
-
if (operation === "configure_escalation") {
|
|
2943
|
-
const target = await resolveDefinition(service, targetName, domain);
|
|
2944
|
-
if (!target)
|
|
2945
|
-
return {
|
|
2946
|
-
success: false,
|
|
2947
|
-
text: "I could not find that item to configure its reminders.",
|
|
2948
|
-
};
|
|
2949
|
-
const rawSteps = detailArray(details, "steps") ??
|
|
2950
|
-
detailArray(details, "escalationSteps");
|
|
2951
|
-
const steps = rawSteps
|
|
2952
|
-
? rawSteps
|
|
2953
|
-
.filter((s) => typeof s === "object" && s !== null)
|
|
2954
|
-
.map((s) => ({
|
|
2955
|
-
channel: String(s.channel ?? "in_app"),
|
|
2956
|
-
offsetMinutes: typeof s.offsetMinutes === "number" ? s.offsetMinutes : 0,
|
|
2957
|
-
label: typeof s.label === "string"
|
|
2958
|
-
? s.label
|
|
2959
|
-
: String(s.channel ?? "reminder"),
|
|
2960
|
-
}))
|
|
2961
|
-
: [{ channel: "in_app", offsetMinutes: 0, label: "In-app reminder" }];
|
|
2962
|
-
const updated = await service.updateDefinition(target.definition.id, {
|
|
2963
|
-
ownership,
|
|
2964
|
-
reminderPlan: { steps },
|
|
2965
|
-
});
|
|
2966
|
-
const summary = steps
|
|
2967
|
-
.map((s) => `${s.channel} at +${s.offsetMinutes}m`)
|
|
2968
|
-
.join(", ");
|
|
2969
|
-
const fallback = `Updated reminder plan for "${updated.definition.title}": ${summary}.`;
|
|
2970
|
-
return {
|
|
2971
|
-
success: true,
|
|
2972
|
-
text: await renderLifeActionReply({
|
|
2973
|
-
runtime,
|
|
2974
|
-
message,
|
|
2975
|
-
state,
|
|
2976
|
-
intent,
|
|
2977
|
-
scenario: "configured_escalation",
|
|
2978
|
-
fallback,
|
|
2979
|
-
context: {
|
|
2980
|
-
targetTitle: updated.definition.title,
|
|
2981
|
-
steps,
|
|
2982
|
-
},
|
|
2983
|
-
}),
|
|
2984
|
-
data: toActionData(updated),
|
|
2985
|
-
};
|
|
2986
|
-
}
|
|
2987
|
-
return {
|
|
2988
|
-
success: false,
|
|
2989
|
-
text: "I didn't understand that life management request.",
|
|
2990
|
-
};
|
|
2991
|
-
}
|
|
2992
|
-
catch (err) {
|
|
2993
|
-
if (err instanceof LifeOpsServiceError) {
|
|
2994
|
-
const fallback = buildLifeServiceErrorFallback(err, intent);
|
|
2995
|
-
return {
|
|
2996
|
-
success: false,
|
|
2997
|
-
text: await renderLifeActionReply({
|
|
2998
|
-
runtime,
|
|
2999
|
-
message,
|
|
3000
|
-
state,
|
|
3001
|
-
intent,
|
|
3002
|
-
scenario: "service_error",
|
|
3003
|
-
fallback,
|
|
3004
|
-
context: {
|
|
3005
|
-
status: err.status,
|
|
3006
|
-
operation,
|
|
3007
|
-
},
|
|
3008
|
-
}),
|
|
3009
|
-
};
|
|
3010
|
-
}
|
|
3011
|
-
throw err;
|
|
3012
|
-
}
|
|
3013
|
-
},
|
|
3014
|
-
parameters: [
|
|
3015
|
-
{
|
|
3016
|
-
name: "action",
|
|
3017
|
-
description: "What kind of life operation to perform.",
|
|
3018
|
-
required: false,
|
|
3019
|
-
schema: {
|
|
3020
|
-
type: "string",
|
|
3021
|
-
enum: [
|
|
3022
|
-
"create",
|
|
3023
|
-
"create_goal",
|
|
3024
|
-
"update",
|
|
3025
|
-
"update_goal",
|
|
3026
|
-
"delete",
|
|
3027
|
-
"delete_goal",
|
|
3028
|
-
"complete",
|
|
3029
|
-
"skip",
|
|
3030
|
-
"snooze",
|
|
3031
|
-
"review",
|
|
3032
|
-
"phone",
|
|
3033
|
-
"escalation",
|
|
3034
|
-
"reminder_preference",
|
|
3035
|
-
"calendar",
|
|
3036
|
-
"next_event",
|
|
3037
|
-
"email",
|
|
3038
|
-
"overview",
|
|
3039
|
-
],
|
|
3040
|
-
},
|
|
3041
|
-
},
|
|
3042
|
-
{
|
|
3043
|
-
name: "intent",
|
|
3044
|
-
description: 'Natural language description of what to do. Examples: "create a daily brushing habit for morning and night", "snooze brushing for 30 minutes", "what\'s on my calendar today".',
|
|
3045
|
-
required: false,
|
|
3046
|
-
schema: { type: "string" },
|
|
3047
|
-
},
|
|
3048
|
-
{
|
|
3049
|
-
name: "title",
|
|
3050
|
-
description: "Name for a new item, or the name of an existing item to act on.",
|
|
3051
|
-
required: false,
|
|
3052
|
-
schema: { type: "string" },
|
|
3053
|
-
},
|
|
3054
|
-
{
|
|
3055
|
-
name: "target",
|
|
3056
|
-
description: "Name or ID of an existing item when different from title (e.g., when renaming).",
|
|
3057
|
-
required: false,
|
|
3058
|
-
schema: { type: "string" },
|
|
3059
|
-
},
|
|
3060
|
-
{
|
|
3061
|
-
name: "details",
|
|
3062
|
-
description: "Structured data when needed. May include: cadence (schedule object), kind (task/habit/routine), description, priority, progressionRule, reminderPlan, confirmed (boolean when the user explicitly approves a previewed create), preset (snooze preset like 15m/30m/1h/tonight/tomorrow_morning), minutes (snooze minutes), phoneNumber, allowSms, allowVoice, steps (escalation steps array), goalId, goalTitle, supportStrategy, successCriteria, note, limit, domain (user_lifeops/agent_ops), or reminder preference targeting.",
|
|
3063
|
-
required: false,
|
|
3064
|
-
schema: { type: "object" },
|
|
3065
|
-
},
|
|
3066
|
-
],
|
|
3067
|
-
examples: [
|
|
3068
|
-
[
|
|
3069
|
-
{
|
|
3070
|
-
name: "{{name1}}",
|
|
3071
|
-
content: {
|
|
3072
|
-
text: "add a todo: pick up dry cleaning tomorrow",
|
|
3073
|
-
},
|
|
3074
|
-
},
|
|
3075
|
-
{
|
|
3076
|
-
name: "{{agentName}}",
|
|
3077
|
-
content: {
|
|
3078
|
-
text: 'I can save "Pick up dry cleaning" for tomorrow. Confirm and I\'ll save it.',
|
|
3079
|
-
actions: ["LIFE"],
|
|
3080
|
-
},
|
|
3081
|
-
},
|
|
3082
|
-
],
|
|
3083
|
-
[
|
|
3084
|
-
{
|
|
3085
|
-
name: "{{name1}}",
|
|
3086
|
-
content: {
|
|
3087
|
-
text: "what's on my todo list today?",
|
|
3088
|
-
},
|
|
3089
|
-
},
|
|
3090
|
-
{
|
|
3091
|
-
name: "{{agentName}}",
|
|
3092
|
-
content: {
|
|
3093
|
-
text: "You have 2 LifeOps items due today: pick up dry cleaning and call mom.",
|
|
3094
|
-
actions: ["LIFE"],
|
|
3095
|
-
},
|
|
3096
|
-
},
|
|
3097
|
-
],
|
|
3098
|
-
[
|
|
3099
|
-
{
|
|
3100
|
-
name: "{{name1}}",
|
|
3101
|
-
content: {
|
|
3102
|
-
text: "set a goal to save $5,000 by the end of the year",
|
|
3103
|
-
},
|
|
3104
|
-
},
|
|
3105
|
-
{
|
|
3106
|
-
name: "{{agentName}}",
|
|
3107
|
-
content: {
|
|
3108
|
-
text: 'I can save this goal as "Save $5,000 by the end of the year". Confirm and I\'ll save it, or tell me what to change.',
|
|
3109
|
-
actions: ["LIFE"],
|
|
3110
|
-
},
|
|
3111
|
-
},
|
|
3112
|
-
],
|
|
3113
|
-
[
|
|
3114
|
-
{
|
|
3115
|
-
name: "{{name1}}",
|
|
3116
|
-
content: {
|
|
3117
|
-
text: "help me remember to drink water",
|
|
3118
|
-
},
|
|
3119
|
-
},
|
|
3120
|
-
{
|
|
3121
|
-
name: "{{agentName}}",
|
|
3122
|
-
content: {
|
|
3123
|
-
text: 'I can set up a "Drink water" habit with a reasonable daytime default cadence. Confirm and I\'ll save it.',
|
|
3124
|
-
actions: ["LIFE"],
|
|
3125
|
-
},
|
|
3126
|
-
},
|
|
3127
|
-
],
|
|
3128
|
-
[
|
|
3129
|
-
{
|
|
3130
|
-
name: "{{name1}}",
|
|
3131
|
-
content: {
|
|
3132
|
-
text: "help me remember to stretch during the day",
|
|
3133
|
-
},
|
|
3134
|
-
},
|
|
3135
|
-
{
|
|
3136
|
-
name: "{{agentName}}",
|
|
3137
|
-
content: {
|
|
3138
|
-
text: 'I can set up a "Stretch" habit with daytime stretch-break defaults. Confirm and I\'ll save it.',
|
|
3139
|
-
actions: ["LIFE"],
|
|
3140
|
-
},
|
|
3141
|
-
},
|
|
3142
|
-
],
|
|
3143
|
-
[
|
|
3144
|
-
{
|
|
3145
|
-
name: "{{name1}}",
|
|
3146
|
-
content: {
|
|
3147
|
-
text: "please remind me about my Invisalign on weekdays after lunch",
|
|
3148
|
-
},
|
|
3149
|
-
},
|
|
3150
|
-
{
|
|
3151
|
-
name: "{{agentName}}",
|
|
3152
|
-
content: {
|
|
3153
|
-
text: "I can set up a weekday-after-lunch Invisalign habit. Confirm and I'll save it.",
|
|
3154
|
-
actions: ["LIFE"],
|
|
3155
|
-
},
|
|
3156
|
-
},
|
|
3157
|
-
],
|
|
3158
|
-
[
|
|
3159
|
-
{
|
|
3160
|
-
name: "{{name1}}",
|
|
3161
|
-
content: {
|
|
3162
|
-
text: "recuérdame cepillarme los dientes por la mañana y por la noche",
|
|
3163
|
-
},
|
|
3164
|
-
},
|
|
3165
|
-
{
|
|
3166
|
-
name: "{{agentName}}",
|
|
3167
|
-
content: {
|
|
3168
|
-
text: 'Puedo guardar el hábito "Brush teeth" para la mañana y la noche. Confirma y lo guardo.',
|
|
3169
|
-
actions: ["LIFE"],
|
|
3170
|
-
},
|
|
3171
|
-
},
|
|
3172
|
-
],
|
|
3173
|
-
[
|
|
3174
|
-
{
|
|
3175
|
-
name: "{{name1}}",
|
|
3176
|
-
content: {
|
|
3177
|
-
text: "help me brush my teeth at 8 am and 9 pm every day",
|
|
3178
|
-
},
|
|
3179
|
-
},
|
|
3180
|
-
{
|
|
3181
|
-
name: "{{agentName}}",
|
|
3182
|
-
content: {
|
|
3183
|
-
text: 'I can set up a habit named "Brush teeth" for 8 am and 9 pm daily. Confirm and I\'ll save it.',
|
|
3184
|
-
actions: ["LIFE"],
|
|
3185
|
-
},
|
|
3186
|
-
},
|
|
3187
|
-
],
|
|
3188
|
-
[
|
|
3189
|
-
{
|
|
3190
|
-
name: "{{name1}}",
|
|
3191
|
-
content: {
|
|
3192
|
-
text: "Please remind me to shave twice a week.",
|
|
3193
|
-
},
|
|
3194
|
-
},
|
|
3195
|
-
{
|
|
3196
|
-
name: "{{agentName}}",
|
|
3197
|
-
content: {
|
|
3198
|
-
text: 'I can set up a "Shave" habit with a twice-weekly default cadence. Confirm and I\'ll save it.',
|
|
3199
|
-
actions: ["LIFE"],
|
|
3200
|
-
},
|
|
3201
|
-
},
|
|
3202
|
-
],
|
|
3203
|
-
[
|
|
3204
|
-
{
|
|
3205
|
-
name: "{{name1}}",
|
|
3206
|
-
content: {
|
|
3207
|
-
text: "what life ops tasks are still left for today?",
|
|
3208
|
-
},
|
|
3209
|
-
},
|
|
3210
|
-
{
|
|
3211
|
-
name: "{{agentName}}",
|
|
3212
|
-
content: {
|
|
3213
|
-
text: "You have 2 LifeOps tasks left for today: call mom and pay rent.",
|
|
3214
|
-
actions: ["LIFE"],
|
|
3215
|
-
},
|
|
3216
|
-
},
|
|
3217
|
-
{
|
|
3218
|
-
name: "{{name1}}",
|
|
3219
|
-
content: {
|
|
3220
|
-
text: "anything else in my life ops list i need to get done today?",
|
|
3221
|
-
},
|
|
3222
|
-
},
|
|
3223
|
-
{
|
|
3224
|
-
name: "{{agentName}}",
|
|
3225
|
-
content: {
|
|
3226
|
-
text: "You have 1 LifeOps task left for today: pay rent.",
|
|
3227
|
-
actions: ["LIFE"],
|
|
3228
|
-
},
|
|
3229
|
-
},
|
|
3230
|
-
],
|
|
3231
|
-
[
|
|
3232
|
-
{
|
|
3233
|
-
name: "{{name1}}",
|
|
3234
|
-
content: {
|
|
3235
|
-
text: "remind me less about brush teeth",
|
|
3236
|
-
},
|
|
3237
|
-
},
|
|
3238
|
-
{
|
|
3239
|
-
name: "{{agentName}}",
|
|
3240
|
-
content: {
|
|
3241
|
-
text: 'Reminder intensity for "Brush teeth" is now minimal.',
|
|
3242
|
-
actions: ["LIFE"],
|
|
3243
|
-
},
|
|
3244
|
-
},
|
|
3245
|
-
],
|
|
3246
|
-
],
|
|
3247
|
-
};
|