@xopcai/xopc 0.0.268 → 0.0.270
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/dist/browser-ext/manifest.json +1 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/gateway/static/root/assets/{activity-store-Bhyy6ENz.js → activity-store-D_0FmdRj.js} +1 -1
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-B9WObxjr.js → agent-avatar-dicebear-IZvEXak_.js} +1 -1
- package/dist/gateway/static/root/assets/agent-defaults-settings-panel-CE3ygr3l.js +1 -0
- package/dist/gateway/static/root/assets/{agents-BJuTIRPD.js → agents-DzG2qw-c.js} +1 -1
- package/dist/gateway/static/root/assets/{api-B2y7ZjZk.js → api-O3TTQ4qN.js} +1 -1
- package/dist/gateway/static/root/assets/{app-management-settings-panel-Bbn9mDfL.js → app-management-settings-panel-Cqqsbzri.js} +1 -1
- package/dist/gateway/static/root/assets/{appearance-settings-Deo5EsIc.js → appearance-settings-DaJyf32s.js} +1 -1
- package/dist/gateway/static/root/assets/{apps-page-Cz4d7ErX.js → apps-page-B4lX6yoT.js} +1 -1
- package/dist/gateway/static/root/assets/{archive-plugin-CxJTU8MU.js → archive-plugin-kDPnDTJI.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-C71Cukgp.js → attachment-load-CJ3VceKS.js} +1 -1
- package/dist/gateway/static/root/assets/{automations-page-_J7UZ55Q.js → automations-page-JwMtU8XB.js} +1 -1
- package/dist/gateway/static/root/assets/automations-workspace-BiNBewg0.js +6 -0
- package/dist/gateway/static/root/assets/{binary-plugins-CX8fC8Zt.js → binary-plugins-DzyZXLBX.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-Ci9fjoQL.js → block-editor-kTt3gYIJ.js} +3 -3
- package/dist/gateway/static/root/assets/{browser-automation-inputs-s5I78Iko.js → browser-automation-inputs-BKohPYR4.js} +1 -1
- package/dist/gateway/static/root/assets/{browser-automations-page-rDSx0ozx.js → browser-automations-page-ktQfFPk-.js} +1 -1
- package/dist/gateway/static/root/assets/{browser-settings-page-B9RA6x4x.js → browser-settings-page-Dgdt5uVL.js} +3 -3
- package/dist/gateway/static/root/assets/capabilities-settings-panel-BpDW-R9f.js +7 -0
- package/dist/gateway/static/root/assets/{channels-settings-CEhVLJNa.js → channels-settings-DU4EQnR0.js} +1 -1
- package/dist/gateway/static/root/assets/{channels-status-swr-_OsWr_vS.js → channels-status-swr-DrqzYmDr.js} +1 -1
- package/dist/gateway/static/root/assets/{chat-terminal-dock-DMSl8KxS.js → chat-terminal-dock-CIFGGLGa.js} +2 -2
- package/dist/gateway/static/root/assets/connectors-page-CfJqy284.js +2 -0
- package/dist/gateway/static/root/assets/{cron-expression-BByq6Uh8.js → cron-expression-BNwbnrEb.js} +1 -1
- package/dist/gateway/static/root/assets/{date-picker-m6JZCUEW.js → date-picker-DKyirU4K.js} +1 -1
- package/dist/gateway/static/root/assets/{dependency-picker-CwCAjbaJ.js → dependency-picker-D3vNIjRI.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-DSmeEREd.js → desktop-pet-fQwRb_3p.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-settings-MfKceMoe.js → desktop-pet-settings-DfOJ-GvT.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-debug-page-CwvWy26h.js → extension-debug-page-Cn53jB5-.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-DLrbVBHM.js → extension-page-IDpLCxpC.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-BI6C4PM-.js → extension-settings-page-B1dds2bP.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-swr-OObCK8jM.js → gateway-config-swr-B7dcmP7Q.js} +1 -1
- package/dist/gateway/static/root/assets/gateway-settings-pp9jN0wl.js +1 -0
- package/dist/gateway/static/root/assets/{gateway-startup-retry-D_TxKN_A.js → gateway-startup-retry-JGhGMhVZ.js} +1 -1
- package/dist/gateway/static/root/assets/{heartbeat-settings-CUl832Tb.js → heartbeat-settings-B8_zTyev.js} +1 -1
- package/dist/gateway/static/root/assets/home-page-g1KdAdLb.js +1 -0
- package/dist/gateway/static/root/assets/{image-generation-api-fPU9yGsw.js → image-generation-api-BJLX7Qrh.js} +1 -1
- package/dist/gateway/static/root/assets/index-1zRt56Zt.css +2 -0
- package/dist/gateway/static/root/assets/{index-wKE8Q2FX.js → index-OMnem2nr.js} +47 -47
- package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-r4DCS19O.js → keyboard-shortcuts-settings-CBvMTFFx.js} +1 -1
- package/dist/gateway/static/root/assets/{local-app-workbench-page-qwLuir8A.js → local-app-workbench-page-bj75v2ZE.js} +2 -2
- package/dist/gateway/static/root/assets/{local-apps-page-DkfCRLUh.js → local-apps-page-APCMNDvU.js} +1 -1
- package/dist/gateway/static/root/assets/{locale-store-DFQX9kTl.js → locale-store-BThkG0W5.js} +1 -1
- package/dist/gateway/static/root/assets/logs-page-BX7n39zV.js +2 -0
- package/dist/gateway/static/root/assets/{management-settings-Cfx4ATTa.js → management-settings-CM62j8ZX.js} +1 -1
- package/dist/gateway/static/root/assets/{markdown-view-D-5jHRWg.js → markdown-view-BwjpJVPs.js} +1 -1
- package/dist/gateway/static/root/assets/{media-plugins-DOLjWd3y.js → media-plugins-C10byeaa.js} +1 -1
- package/dist/gateway/static/root/assets/{messages-Dj8QuS6e.js → messages-D0V_bgRP.js} +2 -2
- package/dist/gateway/static/root/assets/{mobile-pairing-wizard-BGW9joAb.js → mobile-pairing-wizard-BCWfwVx3.js} +1 -1
- package/dist/gateway/static/root/assets/note-detail-panel-koOqb0gX.js +5 -0
- package/dist/gateway/static/root/assets/notes-page-BH54rY3B.js +8 -0
- package/dist/gateway/static/root/assets/{page-tabs-_SGXMT2O.js → page-tabs-qQ36zncF.js} +1 -1
- package/dist/gateway/static/root/assets/{preview-open-alternatives-lVetfCWk.js → preview-open-alternatives-BiAJvvCo.js} +1 -1
- package/dist/gateway/static/root/assets/proactive-card-CcNBqHoH.js +1 -0
- package/dist/gateway/static/root/assets/proactive-page-C3K61jve.js +1 -0
- package/dist/gateway/static/root/assets/{product-open-page-CIGLPFm7.js → product-open-page-CunnDP4w.js} +1 -1
- package/dist/gateway/static/root/assets/project-detail-page-SL2g8MZY.js +1 -0
- package/dist/gateway/static/root/assets/projects-page-BtxazT5J.js +1 -0
- package/dist/gateway/static/root/assets/{registry-api-CsZLatKo.js → registry-api-0JSegbNl.js} +1 -1
- package/dist/gateway/static/root/assets/remote-access-hub-BSb7b67A.js +1 -0
- package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-BDqVrUEj.js → runtime-tools-settings-panel-bu_mwBTr.js} +1 -1
- package/dist/gateway/static/root/assets/{schema-form-8RQgFJJO.js → schema-form-BE0sgZyz.js} +1 -1
- package/dist/gateway/static/root/assets/sessions-page-ljcS2KVz.js +1 -0
- package/dist/gateway/static/root/assets/settings-advanced-gate-CR9Y9LQm.js +1 -0
- package/dist/gateway/static/root/assets/{settings-form-section-j4UjGM-f.js → settings-form-section-CBo517lV.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-lMi50B_s.js → settings-page-DBPimx93.js} +1 -1
- package/dist/gateway/static/root/assets/{setup-status-panel-Dx4Fy3rU.js → setup-status-panel-J3AnooPW.js} +1 -1
- package/dist/gateway/static/root/assets/{share-preview-page-aSyKRH5y.js → share-preview-page-DdV75VTe.js} +1 -1
- package/dist/gateway/static/root/assets/shares-settings-AAm4Iwcp.js +1 -0
- package/dist/gateway/static/root/assets/skill-reload-api-pRCjP5sm.js +1 -0
- package/dist/gateway/static/root/assets/{skills-page-C2_CAvxW.js → skills-page-Cn_-nvRo.js} +1 -1
- package/dist/gateway/static/root/assets/{skills-page.utils-B00e4Q30.js → skills-page.utils-CfVAc_lu.js} +1 -1
- package/dist/gateway/static/root/assets/{system-settings-panel-CulAkrsV.js → system-settings-panel-B-pzalp-.js} +1 -1
- package/dist/gateway/static/root/assets/task-detail-page-CmrLy3PO.js +1 -0
- package/dist/gateway/static/root/assets/{theme-store-zRT6vaZc.js → theme-store-1wryLgBQ.js} +1 -1
- package/dist/gateway/static/root/assets/{tunnel-api-C01xgCWR.js → tunnel-api-Cgpnm2fL.js} +1 -1
- package/dist/gateway/static/root/assets/{use-autosave-DfSJ3c2p.js → use-autosave-N_lm4FdD.js} +1 -1
- package/dist/gateway/static/root/assets/user-model-page-u3QLDX6L.js +2 -0
- package/dist/gateway/static/root/assets/{voice-api-key-field-9v-miN8o.js → voice-api-key-field-DMsyVfri.js} +1 -1
- package/dist/gateway/static/root/assets/{voice-config-api-DpJEu2RQ.js → voice-config-api-QWVmiAp3.js} +1 -1
- package/dist/gateway/static/root/assets/{work-discovery-overlay-CREYgh-1.js → work-discovery-overlay-BC0vAxp1.js} +1 -1
- package/dist/gateway/static/root/assets/workflow-run-setup-panel-Cz9jQIlP.js +3 -0
- package/dist/gateway/static/root/assets/workflows-page-DA6OOK6X.js +6 -0
- package/dist/gateway/static/root/index.html +10 -10
- package/dist/gateway/static/root/notification-sw.js +15 -0
- package/dist/package.js +1 -1
- package/dist/packages/gateway-contract/src/notifications.js +15 -1
- package/dist/packages/gateway-contract/src/proactive.js +120 -0
- package/dist/packages/realtime-protocol/src/voice.js +2 -1
- package/dist/src/agent/tool-manuals/xopc-use.d.ts +1 -1
- package/dist/src/agent/tool-manuals/xopc-use.js +19 -1
- package/dist/src/agent/tools/factory.js +1 -0
- package/dist/src/agent/tools/xopc-use-tool.d.ts +3 -2
- package/dist/src/agent/tools/xopc-use-tool.js +48 -4
- package/dist/src/agent/workflow/subagent-runner.d.ts +1 -0
- package/dist/src/agent/workflow/subagent-runner.js +2 -2
- package/dist/src/browser/automations/schema.d.ts +1 -1
- package/dist/src/browser/automations/service.d.ts +1 -1
- package/dist/src/cli/bin.js +2 -2
- package/dist/src/cli/commands/agent.js +2 -2
- package/dist/src/cli/commands/auth.js +1 -1
- package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
- package/dist/src/cli/commands/extension-dev.js +1 -1
- package/dist/src/cli/commands/extension-marketplace.js +1 -1
- package/dist/src/cli/commands/extension.js +1 -1
- package/dist/src/cli/commands/gateway/lifecycle.js +1 -1
- package/dist/src/cli/commands/gateway-ssh-tunnel.js +1 -1
- package/dist/src/cli/commands/models.js +2 -2
- package/dist/src/cli/commands/onboard.js +1 -1
- package/dist/src/cli/commands/platform.js +1 -1
- package/dist/src/cli/commands/profile.js +1 -1
- package/dist/src/cli/commands/tunnel.js +1 -1
- package/dist/src/cli/commands/update.js +1 -1
- package/dist/src/cli/extension-cli-register.js +1 -1
- package/dist/src/config/index.js +1 -1
- package/dist/src/connectors/connected-source-normalizers.js +3 -0
- package/dist/src/gateway/hono/routes/index.js +0 -2
- package/dist/src/gateway/hono/routes/lazy-bundles.js +12 -0
- package/dist/src/gateway/hono/routes/proactive-control.d.ts +3 -0
- package/dist/src/gateway/hono/routes/proactive-control.js +168 -0
- package/dist/src/gateway/hono/routes/proactive.d.ts +1 -1
- package/dist/src/gateway/hono/routes/proactive.js +12 -5
- package/dist/src/gateway/hono/routes/voice.js +1 -1
- package/dist/src/gateway/run-loop.js +1 -1
- package/dist/src/gateway/security/gateway-scopes.js +5 -0
- package/dist/src/gateway/server.js +1 -1
- package/dist/src/gateway/service.d.ts +0 -1
- package/dist/src/gateway/service.js +21 -23
- package/dist/src/notifications/planner.js +4 -3
- package/dist/src/notifications/proactive-channel.d.ts +8 -0
- package/dist/src/notifications/proactive-channel.js +57 -0
- package/dist/src/notifications/proactive-policy.d.ts +3 -0
- package/dist/src/notifications/proactive-policy.js +32 -0
- package/dist/src/notifications/service.d.ts +78 -0
- package/dist/src/notifications/service.js +71 -13
- package/dist/src/notifications/store.d.ts +2 -0
- package/dist/src/notifications/store.js +8 -1
- package/dist/src/notifications/web-push.d.ts +19 -0
- package/dist/src/notifications/web-push.js +182 -0
- package/dist/src/proactive/actions/service.js +12 -2
- package/dist/src/proactive/execution/agent-executor.d.ts +5 -0
- package/dist/src/proactive/execution/agent-executor.js +21 -0
- package/dist/src/proactive/execution/authorization.d.ts +5 -0
- package/dist/src/proactive/execution/authorization.js +61 -0
- package/dist/src/proactive/execution/context.d.ts +4 -0
- package/dist/src/proactive/execution/context.js +51 -14
- package/dist/src/proactive/execution/insight.d.ts +7 -0
- package/dist/src/proactive/execution/insight.js +36 -3
- package/dist/src/proactive/execution/repository.d.ts +2 -0
- package/dist/src/proactive/execution/repository.js +53 -9
- package/dist/src/proactive/execution/types.d.ts +7 -0
- package/dist/src/proactive/execution/worker.js +43 -7
- package/dist/src/proactive/experience.d.ts +69 -0
- package/dist/src/proactive/experience.js +90 -0
- package/dist/src/proactive/follow-ups.d.ts +123 -0
- package/dist/src/proactive/follow-ups.js +169 -0
- package/dist/src/proactive/inbox/cards.d.ts +21 -0
- package/dist/src/proactive/inbox/cards.js +266 -0
- package/dist/src/proactive/inbox/delivery.d.ts +6 -0
- package/dist/src/proactive/inbox/delivery.js +54 -0
- package/dist/src/proactive/inbox/digest.d.ts +8 -0
- package/dist/src/proactive/inbox/digest.js +112 -0
- package/dist/src/proactive/inbox/lifecycle.d.ts +4 -0
- package/dist/src/proactive/inbox/lifecycle.js +61 -0
- package/dist/src/proactive/inbox/notification-policy.d.ts +1 -0
- package/dist/src/proactive/inbox/notification-policy.js +22 -0
- package/dist/src/proactive/inbox/repository.d.ts +1 -0
- package/dist/src/proactive/inbox/repository.js +75 -12
- package/dist/src/proactive/inbox/types.d.ts +11 -1
- package/dist/src/proactive/inbox/worker.js +9 -3
- package/dist/src/proactive/index.js +2 -2
- package/dist/src/proactive/mail-thread.d.ts +13 -0
- package/dist/src/proactive/mail-thread.js +54 -0
- package/dist/src/proactive/maintenance.js +7 -0
- package/dist/src/proactive/metrics.d.ts +10 -0
- package/dist/src/proactive/metrics.js +27 -0
- package/dist/src/proactive/policy/presence.d.ts +2 -0
- package/dist/src/proactive/policy/presence.js +27 -0
- package/dist/src/proactive/policy/service.d.ts +51 -0
- package/dist/src/proactive/policy/service.js +120 -0
- package/dist/src/proactive/routing/matcher.js +3 -2
- package/dist/src/proactive/scenarios/control.d.ts +87 -0
- package/dist/src/proactive/scenarios/control.js +108 -0
- package/dist/src/proactive/scenarios/preview.d.ts +13 -0
- package/dist/src/proactive/scenarios/preview.js +81 -0
- package/dist/src/proactive/scenarios/prompt-composer.js +4 -2
- package/dist/src/proactive/scenarios/repository.js +5 -1
- package/dist/src/proactive/service.js +1 -1
- package/dist/src/proactive/temporal/schedule.d.ts +3 -0
- package/dist/src/proactive/temporal/schedule.js +67 -0
- package/dist/src/proactive/temporal/worker.d.ts +1 -0
- package/dist/src/proactive/temporal/worker.js +24 -6
- package/dist/src/storage/sqlite/migrations/159_proactive_controls.sql +68 -0
- package/dist/src/storage/sqlite/migrations/160_proactive_web_push.sql +27 -0
- package/dist/src/storage/sqlite/migrations/161_proactive_delivery_and_lifecycle.sql +51 -0
- package/dist/src/storage/sqlite/migrations/162_proactive_product.sql +7 -0
- package/dist/src/storage/sqlite/migrations/163_proactive_follow_ups.sql +29 -0
- package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
- package/dist/src/storage/sqlite/migrations/runner.js +3 -3
- package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
- package/dist/src/storage/sqlite/schema.js +1 -1
- package/dist/src/tasks/home-query-service.js +1 -1
- package/dist/src/tasks/index.js +4 -4
- package/dist/src/voice/dashscope/streaming-stt-session.js +1 -0
- package/dist/src/voice/dashscope/streaming-tts-stream.d.ts +1 -0
- package/dist/src/voice/dashscope/streaming-tts-stream.js +8 -0
- package/dist/src/voice/realtime/agentBroker.js +1 -1
- package/dist/src/voice/realtime/agentEngine.js +1 -1
- package/dist/src/voice/realtime/pcm-output-gain.d.ts +2 -0
- package/dist/src/voice/realtime/pcm-output-gain.js +16 -0
- package/dist/src/voice/realtime/runtime.d.ts +2 -1
- package/dist/src/voice/realtime/runtime.js +25 -7
- package/dist/src/workflows/domain/run.d.ts +1 -0
- package/dist/src/workflows/index.js +2 -2
- package/dist/src/workflows/service/workflow-run-service.d.ts +3 -0
- package/dist/src/workflows/service/workflow-run-service.js +27 -6
- package/dist/src/workflows/service/workflow-run-service.types.d.ts +1 -0
- package/package.json +7 -5
- package/dist/gateway/static/root/assets/agent-defaults-settings-panel-J1YFNG26.js +0 -1
- package/dist/gateway/static/root/assets/automations-workspace-Bn8nwUOL.js +0 -6
- package/dist/gateway/static/root/assets/capabilities-settings-panel-C1GUih8m.js +0 -7
- package/dist/gateway/static/root/assets/connectors-page-IQAQDSmO.js +0 -2
- package/dist/gateway/static/root/assets/gateway-settings-B3H7Vfbh.js +0 -1
- package/dist/gateway/static/root/assets/home-page-CT4JL2jm.js +0 -1
- package/dist/gateway/static/root/assets/index-CRJrO4GI.css +0 -2
- package/dist/gateway/static/root/assets/logs-page-DrNaaPWc.js +0 -2
- package/dist/gateway/static/root/assets/note-detail-panel-Dbj5OvXE.js +0 -5
- package/dist/gateway/static/root/assets/notes-page-5hRB3WXc.js +0 -8
- package/dist/gateway/static/root/assets/project-detail-page-CblWLA8k.js +0 -1
- package/dist/gateway/static/root/assets/projects-page-CGk-kzqs.js +0 -1
- package/dist/gateway/static/root/assets/remote-access-hub-Du8PweyU.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-BFm94dJC.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-C0H-cToA.js +0 -1
- package/dist/gateway/static/root/assets/shares-settings-CqF9s0pl.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-BBL_ZUSC.js +0 -1
- package/dist/gateway/static/root/assets/task-detail-page-D1FmRFIn.js +0 -1
- package/dist/gateway/static/root/assets/user-model-page-BGC_5baJ.js +0 -2
- package/dist/gateway/static/root/assets/workflow-run-setup-panel-BfCWdw8F.js +0 -3
- package/dist/gateway/static/root/assets/workflows-page-CvmKQkD0.js +0 -6
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { getSqliteDatabase } from "../../storage/sqlite/transaction.js";
|
|
2
|
-
import { getKnowledgeSourceItem } from "../../storage/sqlite/knowledge-repository.js";
|
|
3
|
-
import { getConnectorSyncPolicyForConnection } from "../../storage/sqlite/connector-sync-policy-repository.js";
|
|
4
2
|
import { getAssertionSlot, listUserAssertions } from "../../user-model/repository.js";
|
|
5
3
|
import "../../user-model/index.js";
|
|
4
|
+
import { authorizedConnectedSource } from "./authorization.js";
|
|
5
|
+
import { authorizedMailThread, requireMailFollowUp } from "../follow-ups.js";
|
|
6
6
|
import { getDiscussionCapture, getLatestDiscussionOrganization } from "../../discussions/repository.js";
|
|
7
7
|
import { wrapExternalContent } from "../../gateway/security/external-content.js";
|
|
8
8
|
//#region src/proactive/execution/context.ts
|
|
@@ -28,15 +28,12 @@ function emptyContext() {
|
|
|
28
28
|
};
|
|
29
29
|
}
|
|
30
30
|
function authorizedConnectedSourceItem(event, scenarioKey) {
|
|
31
|
-
const item =
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
const policy = getConnectorSyncPolicyForConnection(connectionId);
|
|
38
|
-
const scenarioAllowed = !policy?.allowedScenarioKeys.length || policy.allowedScenarioKeys.includes(scenarioKey);
|
|
39
|
-
return policy?.scanEnabled && policy.proactiveEnabled && scenarioAllowed ? item : null;
|
|
31
|
+
const item = authorizedConnectedSource(event.subject_id, event.workspace_id, scenarioKey, event.agent_id);
|
|
32
|
+
if (item && event.type === "connected_source.calendar_window.v1") {
|
|
33
|
+
const payload = JSON.parse(event.payload_json);
|
|
34
|
+
if (payload.meetingStartsAt !== item.occurredAt || payload.contentHash && payload.contentHash !== item.contentHash) return null;
|
|
35
|
+
}
|
|
36
|
+
return item;
|
|
40
37
|
}
|
|
41
38
|
var EventBatchContextProvider = class {
|
|
42
39
|
id = "event_batch";
|
|
@@ -62,11 +59,13 @@ var ConnectedSourceContextProvider = class {
|
|
|
62
59
|
async collect(input) {
|
|
63
60
|
const items = [];
|
|
64
61
|
const snapshotItems = [];
|
|
62
|
+
const seen = /* @__PURE__ */ new Set();
|
|
65
63
|
const evidenceIds = [];
|
|
66
64
|
for (const event of eventRows(input.eventIds)) {
|
|
67
65
|
if (!event.type.startsWith("connected_source.") || event.type.includes("_deleted.")) continue;
|
|
68
66
|
const item = authorizedConnectedSourceItem(event, input.scenarioKey);
|
|
69
|
-
if (!item) continue;
|
|
67
|
+
if (!item || seen.has(item.id)) continue;
|
|
68
|
+
seen.add(item.id);
|
|
70
69
|
const evidenceId = `source-item:${item.id}`;
|
|
71
70
|
const common = {
|
|
72
71
|
evidenceId,
|
|
@@ -334,6 +333,43 @@ var DiscussionContextProvider = class {
|
|
|
334
333
|
};
|
|
335
334
|
}
|
|
336
335
|
};
|
|
336
|
+
var MailFollowUpContextProvider = class {
|
|
337
|
+
id = "follow_up";
|
|
338
|
+
async collect(input) {
|
|
339
|
+
const event = eventRows(input.eventIds).findLast((row) => row.subject_kind === "mail_follow_up");
|
|
340
|
+
if (!event) return emptyContext();
|
|
341
|
+
const follow = requireMailFollowUp(event.workspace_id, event.subject_id);
|
|
342
|
+
const thread = authorizedMailThread(follow);
|
|
343
|
+
if (!thread || follow.status !== "watching") return emptyContext();
|
|
344
|
+
const common = {
|
|
345
|
+
followUpId: follow.id,
|
|
346
|
+
revision: follow.revision,
|
|
347
|
+
fingerprint: thread.fingerprint,
|
|
348
|
+
dueAt: follow.due_at,
|
|
349
|
+
deadlinePassed: Date.parse(follow.due_at) <= Date.now()
|
|
350
|
+
};
|
|
351
|
+
return {
|
|
352
|
+
content: {
|
|
353
|
+
...common,
|
|
354
|
+
instructions: follow.instructions,
|
|
355
|
+
items: thread.items.map((item) => ({
|
|
356
|
+
evidenceId: `source-item:${item.id}`,
|
|
357
|
+
occurredAt: item.occurredAt,
|
|
358
|
+
content: wrapExternalContent(item.normalizedText?.slice(0, 4e3) ?? "", { source: "email" })
|
|
359
|
+
}))
|
|
360
|
+
},
|
|
361
|
+
snapshotContent: {
|
|
362
|
+
...common,
|
|
363
|
+
items: thread.items.map((item) => ({
|
|
364
|
+
sourceItemId: item.id,
|
|
365
|
+
contentHash: item.contentHash,
|
|
366
|
+
occurredAt: item.occurredAt
|
|
367
|
+
}))
|
|
368
|
+
},
|
|
369
|
+
evidenceIds: thread.items.map((item) => `source-item:${item.id}`)
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
};
|
|
337
373
|
var ContextProviderRegistry = class {
|
|
338
374
|
constructor(providers = [
|
|
339
375
|
new EventBatchContextProvider(),
|
|
@@ -343,7 +379,8 @@ var ContextProviderRegistry = class {
|
|
|
343
379
|
new MeetingWorkspaceContextProvider(),
|
|
344
380
|
new ProjectStateContextProvider(),
|
|
345
381
|
new AutomationStateContextProvider(),
|
|
346
|
-
new DiscussionContextProvider()
|
|
382
|
+
new DiscussionContextProvider(),
|
|
383
|
+
new MailFollowUpContextProvider()
|
|
347
384
|
]) {
|
|
348
385
|
this.providers = providers;
|
|
349
386
|
}
|
|
@@ -366,4 +403,4 @@ var ContextProviderRegistry = class {
|
|
|
366
403
|
}
|
|
367
404
|
};
|
|
368
405
|
//#endregion
|
|
369
|
-
export { AutomationStateContextProvider, ConnectedSourceContextProvider, ContextProviderRegistry, DiscussionContextProvider, EventBatchContextProvider, InternalObjectContextProvider, MeetingWorkspaceContextProvider, ProjectStateContextProvider, UserModelContextProvider };
|
|
406
|
+
export { AutomationStateContextProvider, ConnectedSourceContextProvider, ContextProviderRegistry, DiscussionContextProvider, EventBatchContextProvider, InternalObjectContextProvider, MailFollowUpContextProvider, MeetingWorkspaceContextProvider, ProjectStateContextProvider, UserModelContextProvider };
|
|
@@ -5,3 +5,10 @@ export declare function isValuableInsight(candidate: InsightCandidate, policy?:
|
|
|
5
5
|
minConfidence: number;
|
|
6
6
|
minScore: number;
|
|
7
7
|
}): boolean;
|
|
8
|
+
export declare function parseAnalysisResult(raw: string, allowedEvidenceIds: Set<string>): {
|
|
9
|
+
result: 'no_insight';
|
|
10
|
+
reason: string;
|
|
11
|
+
} | {
|
|
12
|
+
result: 'insight';
|
|
13
|
+
candidate: InsightCandidate;
|
|
14
|
+
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ProactiveArtifactSchema } from "../../../packages/gateway-contract/src/proactive.js";
|
|
1
2
|
import { stripCodeFences } from "../../providers/model-response.js";
|
|
2
3
|
//#region src/proactive/execution/insight.ts
|
|
3
4
|
const URGENCY = new Set([
|
|
@@ -57,7 +58,7 @@ function parseInsightCandidate(raw, allowedEvidenceIds) {
|
|
|
57
58
|
if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("Insight must be a JSON object");
|
|
58
59
|
const row = value;
|
|
59
60
|
if (!URGENCY.has(String(row.urgency))) throw new Error("Insight urgency is invalid");
|
|
60
|
-
if (typeof row.confidence !== "number" || row.confidence < 0 || row.confidence > 1) throw new Error("Insight confidence is invalid");
|
|
61
|
+
if (typeof row.confidence !== "number" || !Number.isFinite(row.confidence) || row.confidence < 0 || row.confidence > 1) throw new Error("Insight confidence is invalid");
|
|
61
62
|
if (!Array.isArray(row.evidenceIds) || row.evidenceIds.length === 0 || row.evidenceIds.length > 20) throw new Error("Insight evidenceIds are invalid");
|
|
62
63
|
const evidenceIds = [...new Set(row.evidenceIds.map(String))];
|
|
63
64
|
if (evidenceIds.some((id) => !allowedEvidenceIds.has(id))) throw new Error("Insight cites unknown evidence");
|
|
@@ -65,6 +66,7 @@ function parseInsightCandidate(raw, allowedEvidenceIds) {
|
|
|
65
66
|
const proposedAction = parseProposedAction(row.proposedAction);
|
|
66
67
|
if (proposedAction && (!decision || decision.options.length !== 2 || decision.options[0]?.id !== "approve" || decision.options[1]?.id !== "reject")) throw new Error("Insight proposedAction requires approve and reject decision options");
|
|
67
68
|
return {
|
|
69
|
+
...row.artifact != null ? { artifact: ProactiveArtifactSchema.parse(row.artifact) } : {},
|
|
68
70
|
title: boundedText(row.title, "title", 160),
|
|
69
71
|
summary: boundedText(row.summary, "summary", 1200),
|
|
70
72
|
whyNow: boundedText(row.whyNow, "whyNow", 800),
|
|
@@ -91,7 +93,38 @@ function isValuableInsight(candidate, policy = {
|
|
|
91
93
|
minConfidence: .65,
|
|
92
94
|
minScore: .6
|
|
93
95
|
}) {
|
|
94
|
-
return candidate.confidence >= policy.minConfidence && candidate.urgency !== "low" && scoreInsight(candidate) >= policy.minScore;
|
|
96
|
+
return candidate.confidence >= policy.minConfidence && (candidate.urgency !== "low" || Boolean(candidate.artifact)) && scoreInsight(candidate) >= policy.minScore;
|
|
97
|
+
}
|
|
98
|
+
function parseAnalysisResult(raw, allowedEvidenceIds) {
|
|
99
|
+
let value;
|
|
100
|
+
try {
|
|
101
|
+
value = JSON.parse(stripCodeFences(raw));
|
|
102
|
+
} catch {
|
|
103
|
+
throw new Error("Model output is not valid JSON");
|
|
104
|
+
}
|
|
105
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
106
|
+
const row = value;
|
|
107
|
+
if (row.result === "no_insight") {
|
|
108
|
+
if (![
|
|
109
|
+
"unchanged",
|
|
110
|
+
"routine",
|
|
111
|
+
"insufficient_evidence",
|
|
112
|
+
"duplicate"
|
|
113
|
+
].includes(String(row.reason)) || Object.keys(row).some((key) => key !== "result" && key !== "reason")) throw new Error("Invalid no_insight result");
|
|
114
|
+
return {
|
|
115
|
+
result: "no_insight",
|
|
116
|
+
reason: String(row.reason)
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
if (row.result === "insight") return {
|
|
120
|
+
result: "insight",
|
|
121
|
+
candidate: parseInsightCandidate(JSON.stringify(row.candidate), allowedEvidenceIds)
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
return {
|
|
125
|
+
result: "insight",
|
|
126
|
+
candidate: parseInsightCandidate(raw, allowedEvidenceIds)
|
|
127
|
+
};
|
|
95
128
|
}
|
|
96
129
|
//#endregion
|
|
97
|
-
export { isValuableInsight, parseInsightCandidate, scoreInsight };
|
|
130
|
+
export { isValuableInsight, parseAnalysisResult, parseInsightCandidate, scoreInsight };
|
|
@@ -7,6 +7,7 @@ export interface ClaimedRun {
|
|
|
7
7
|
scenarioVersion: number;
|
|
8
8
|
promptRevisionId?: string;
|
|
9
9
|
attempt: number;
|
|
10
|
+
subscriptionRevision?: number;
|
|
10
11
|
}
|
|
11
12
|
export declare function claimNextRun(owner: string, now?: Date, leaseSeconds?: number): ClaimedRun | null;
|
|
12
13
|
export declare function eventIdsForBatch(batchId: string): string[];
|
|
@@ -18,6 +19,7 @@ export declare function finishRun(input: {
|
|
|
18
19
|
valueScore?: number;
|
|
19
20
|
cooldownSeconds?: number;
|
|
20
21
|
rawOutput: string;
|
|
22
|
+
outcomeReason?: string;
|
|
21
23
|
modelRef?: string;
|
|
22
24
|
}, now?: Date): ProactiveInsight | null;
|
|
23
25
|
export declare function failRun(run: ClaimedRun, error: unknown, retryable: boolean, now?: Date): void;
|
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import { getSqliteDatabase, runSqliteWriteTransaction } from "../../storage/sqlite/transaction.js";
|
|
2
|
+
import { effectiveProactivePolicy } from "../policy/service.js";
|
|
2
3
|
import { createHash, randomUUID } from "node:crypto";
|
|
3
4
|
//#region src/proactive/execution/repository.ts
|
|
4
5
|
const str = (row, key) => String(row[key]);
|
|
5
6
|
function claimNextRun(owner, now = /* @__PURE__ */ new Date(), leaseSeconds = 120) {
|
|
6
7
|
return runSqliteWriteTransaction((db) => {
|
|
7
8
|
const nowIso = now.toISOString();
|
|
9
|
+
for (const row of db.prepare("SELECT run_id, batch_id, subscription_id FROM proactive_runs WHERE status IN ('retryable', 'running')").all()) if (!effectiveProactivePolicy(str(row, "subscription_id"), now).enabled) {
|
|
10
|
+
db.prepare("UPDATE proactive_runs SET status = 'discarded', outcome_reason = 'disabled', updated_at = ? WHERE run_id = ?").run(nowIso, str(row, "run_id"));
|
|
11
|
+
db.prepare("UPDATE proactive_signal_batches SET status = 'ignored', updated_at = ? WHERE batch_id = ?").run(nowIso, str(row, "batch_id"));
|
|
12
|
+
}
|
|
13
|
+
for (const row of db.prepare("SELECT batch_id, subscription_id FROM proactive_signal_batches WHERE status = 'ready'").all()) if (!effectiveProactivePolicy(str(row, "subscription_id"), now).enabled) db.prepare("UPDATE proactive_signal_batches SET status = 'ignored' WHERE batch_id = ?").run(str(row, "batch_id"));
|
|
8
14
|
const dayStart = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate())).toISOString();
|
|
9
15
|
db.prepare(`UPDATE proactive_signal_batches SET status = 'ignored', updated_at = ? WHERE status = 'ready'
|
|
10
16
|
AND subscription_id IN (SELECT subscription_id FROM proactive_scenario_subscriptions WHERE enabled = 0)`).run(nowIso);
|
|
@@ -38,9 +44,14 @@ function claimNextRun(owner, now = /* @__PURE__ */ new Date(), leaseSeconds = 12
|
|
|
38
44
|
WHERE b.status = 'ready' ORDER BY b.ready_at LIMIT 1`).get();
|
|
39
45
|
if (!batch) return null;
|
|
40
46
|
const id = randomUUID();
|
|
47
|
+
const policy = effectiveProactivePolicy(str(batch, "subscription_id"), now);
|
|
41
48
|
db.prepare(`INSERT INTO proactive_runs (run_id, batch_id, subscription_id, scenario_key, scenario_version,
|
|
42
|
-
prompt_revision_id, status, attempt, lease_owner, lease_expires_at, started_at, updated_at)
|
|
43
|
-
VALUES (?, ?, ?, ?, ?, ?, 'running', 1, ?, ?, ?, ?)`).run(id, str(batch, "batch_id"), str(batch, "subscription_id"), str(batch, "scenario_key"), Number(batch.scenario_version), batch.active_prompt_revision_id ? String(batch.active_prompt_revision_id) : null, owner, new Date(now.getTime() + leaseSeconds * 1e3).toISOString(), nowIso, nowIso
|
|
49
|
+
prompt_revision_id, status, attempt, lease_owner, lease_expires_at, started_at, updated_at, policy_revision, subscription_revision, policy_snapshot_json)
|
|
50
|
+
VALUES (?, ?, ?, ?, ?, ?, 'running', 1, ?, ?, ?, ?, ?, ?, ?)`).run(id, str(batch, "batch_id"), str(batch, "subscription_id"), str(batch, "scenario_key"), Number(batch.scenario_version), batch.active_prompt_revision_id ? String(batch.active_prompt_revision_id) : null, owner, new Date(now.getTime() + leaseSeconds * 1e3).toISOString(), nowIso, nowIso, policy.preferences.revision, policy.settings.revision, JSON.stringify({
|
|
51
|
+
level: policy.level,
|
|
52
|
+
delivery: policy.settings.delivery,
|
|
53
|
+
scanIntervalMinutes: policy.scanIntervalMinutes
|
|
54
|
+
}));
|
|
44
55
|
db.prepare("UPDATE proactive_signal_batches SET status = 'processing', updated_at = ? WHERE batch_id = ?").run(nowIso, str(batch, "batch_id"));
|
|
45
56
|
return runFromRow(db.prepare("SELECT * FROM proactive_runs WHERE run_id = ?").get(id));
|
|
46
57
|
});
|
|
@@ -53,6 +64,7 @@ function runFromRow(row) {
|
|
|
53
64
|
scenarioKey: str(row, "scenario_key"),
|
|
54
65
|
scenarioVersion: Number(row.scenario_version),
|
|
55
66
|
attempt: Number(row.attempt),
|
|
67
|
+
subscriptionRevision: Number(row.subscription_revision),
|
|
56
68
|
...row.prompt_revision_id ? { promptRevisionId: str(row, "prompt_revision_id") } : {}
|
|
57
69
|
};
|
|
58
70
|
}
|
|
@@ -77,21 +89,51 @@ function attachSnapshot(runId, snapshotId) {
|
|
|
77
89
|
function finishRun(input, now = /* @__PURE__ */ new Date()) {
|
|
78
90
|
return runSqliteWriteTransaction((db) => {
|
|
79
91
|
const nowIso = now.toISOString();
|
|
92
|
+
const current = db.prepare("SELECT status, attempt FROM proactive_runs WHERE run_id = ?").get(input.run.id);
|
|
93
|
+
if (!current || current.status !== "running" || current.attempt !== input.run.attempt) return null;
|
|
94
|
+
const currentPolicy = effectiveProactivePolicy(input.run.subscriptionId, now);
|
|
95
|
+
if (!currentPolicy.enabled) input = {
|
|
96
|
+
...input,
|
|
97
|
+
candidate: void 0,
|
|
98
|
+
outcomeReason: "disabled"
|
|
99
|
+
};
|
|
100
|
+
else if (input.run.subscriptionRevision !== void 0 && input.run.subscriptionRevision !== currentPolicy.settings.revision) input = {
|
|
101
|
+
...input,
|
|
102
|
+
candidate: void 0,
|
|
103
|
+
outcomeReason: "policy_changed"
|
|
104
|
+
};
|
|
80
105
|
const subjectScope = db.prepare(`SELECT DISTINCT e.subject_kind, e.subject_id
|
|
81
106
|
FROM proactive_batch_events be
|
|
82
107
|
JOIN proactive_events e ON e.event_id = be.event_id
|
|
83
108
|
WHERE be.batch_id = ?
|
|
84
109
|
ORDER BY e.subject_kind, e.subject_id`).all(input.run.batchId).map((row) => `${str(row, "subject_kind")}:${str(row, "subject_id")}`);
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
110
|
+
const snapshot = db.prepare(`SELECT c.content_json FROM proactive_runs r JOIN proactive_context_snapshots c
|
|
111
|
+
ON c.snapshot_id = r.context_snapshot_id WHERE r.run_id = ?`).get(input.run.id);
|
|
112
|
+
const sourceVersions = snapshot ? JSON.parse(snapshot.content_json) : {};
|
|
113
|
+
const fingerprint = input.candidate ? createHash("sha256").update([
|
|
114
|
+
...subjectScope,
|
|
115
|
+
JSON.stringify(input.candidate.artifact ?? null),
|
|
116
|
+
JSON.stringify(sourceVersions.connected_source ?? sourceVersions.project_state ?? sourceVersions.follow_up ?? null),
|
|
117
|
+
...[
|
|
118
|
+
input.candidate.title,
|
|
119
|
+
input.candidate.summary,
|
|
120
|
+
input.candidate.recommendation
|
|
121
|
+
].map((value) => value.trim().toLowerCase().replace(/\s+/g, " "))
|
|
122
|
+
].join("\n")).digest("hex") : void 0;
|
|
90
123
|
const duplicate = fingerprint ? db.prepare(`SELECT 1 FROM proactive_insights
|
|
91
124
|
WHERE subscription_id = ? AND scenario_key = ? AND content_fingerprint = ? AND created_at >= ? LIMIT 1`).get(input.run.subscriptionId, input.run.scenarioKey, fingerprint, (/* @__PURE__ */ new Date(now.getTime() - (input.cooldownSeconds ?? 10080 * 60) * 1e3)).toISOString()) : void 0;
|
|
92
125
|
const valuable = Boolean(input.candidate) && !duplicate;
|
|
126
|
+
const reason = duplicate ? "duplicate" : input.outcomeReason;
|
|
127
|
+
const completed = valuable || [
|
|
128
|
+
"unchanged",
|
|
129
|
+
"routine",
|
|
130
|
+
"insufficient_evidence",
|
|
131
|
+
"duplicate",
|
|
132
|
+
"below_threshold"
|
|
133
|
+
].includes(reason ?? "");
|
|
134
|
+
db.prepare("UPDATE proactive_runs SET outcome_reason = ? WHERE run_id = ?").run(reason ?? null, input.run.id);
|
|
93
135
|
db.prepare(`UPDATE proactive_runs SET status = ?, raw_output = ?, model_ref = ?, lease_owner = NULL,
|
|
94
|
-
lease_expires_at = NULL, completed_at = ?, updated_at = ? WHERE run_id = ?`).run(
|
|
136
|
+
lease_expires_at = NULL, completed_at = ?, updated_at = ? WHERE run_id = ?`).run(completed ? "completed" : "discarded", input.rawOutput.slice(0, 2e4), input.modelRef ?? null, nowIso, nowIso, input.run.id);
|
|
95
137
|
db.prepare(`UPDATE proactive_signal_batches SET status = ?, updated_at = ? WHERE batch_id = ?`).run(valuable ? "processed" : "ignored", nowIso, input.run.batchId);
|
|
96
138
|
if (!input.candidate || duplicate) return null;
|
|
97
139
|
const insight = {
|
|
@@ -107,6 +149,7 @@ function finishRun(input, now = /* @__PURE__ */ new Date()) {
|
|
|
107
149
|
why_now, impact, recommendation, work_done, decision_json, proposed_action_json, urgency, confidence, value_score,
|
|
108
150
|
evidence_ids_json, content_fingerprint, created_at)
|
|
109
151
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(insight.id, insight.runId, insight.subscriptionId, insight.scenarioKey, insight.title, insight.summary, insight.whyNow, insight.impact, insight.recommendation, insight.workDone, insight.decision ? JSON.stringify(insight.decision) : null, insight.proposedAction ? JSON.stringify(insight.proposedAction) : null, insight.urgency, insight.confidence, insight.valueScore, JSON.stringify(insight.evidenceIds), fingerprint, insight.createdAt);
|
|
152
|
+
if (insight.artifact) db.prepare("UPDATE proactive_insights SET artifact_json = ? WHERE insight_id = ?").run(JSON.stringify(insight.artifact), insight.id);
|
|
110
153
|
return insight;
|
|
111
154
|
});
|
|
112
155
|
}
|
|
@@ -115,7 +158,7 @@ function failRun(run, error, retryable, now = /* @__PURE__ */ new Date()) {
|
|
|
115
158
|
const finalRetryable = retryable && run.attempt < 3;
|
|
116
159
|
const nowIso = now.toISOString();
|
|
117
160
|
const nextAttemptAt = finalRetryable ? new Date(now.getTime() + 15e3 * run.attempt).toISOString() : null;
|
|
118
|
-
db.prepare(`UPDATE proactive_runs SET status = ?, error_message = ?, lease_owner = NULL, lease_expires_at = NULL, next_attempt_at = ?, updated_at = ? WHERE run_id = ?`).run(finalRetryable ? "retryable" : "failed", String(error instanceof Error ? error.message : error).slice(0, 2e3), nextAttemptAt, nowIso, run.id);
|
|
161
|
+
if (!db.prepare(`UPDATE proactive_runs SET status = ?, error_message = ?, lease_owner = NULL, lease_expires_at = NULL, next_attempt_at = ?, updated_at = ? WHERE run_id = ? AND status = 'running' AND attempt = ?`).run(finalRetryable ? "retryable" : "failed", String(error instanceof Error ? error.message : error).slice(0, 2e3), nextAttemptAt, nowIso, run.id, run.attempt).changes) return;
|
|
119
162
|
db.prepare(`UPDATE proactive_signal_batches SET status = ?, updated_at = ? WHERE batch_id = ?`).run(finalRetryable ? "failed_retryable" : "failed_permanent", nowIso, run.batchId);
|
|
120
163
|
});
|
|
121
164
|
}
|
|
@@ -131,6 +174,7 @@ function listInsights(limit = 50) {
|
|
|
131
174
|
impact: str(row, "impact"),
|
|
132
175
|
recommendation: str(row, "recommendation"),
|
|
133
176
|
workDone: str(row, "work_done"),
|
|
177
|
+
...row.artifact_json ? { artifact: JSON.parse(str(row, "artifact_json")) } : {},
|
|
134
178
|
...row.decision_json ? { decision: JSON.parse(str(row, "decision_json")) } : {},
|
|
135
179
|
...row.proposed_action_json ? { proposedAction: JSON.parse(str(row, "proposed_action_json")) } : {},
|
|
136
180
|
urgency: str(row, "urgency"),
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ProactiveArtifact } from '@xopcai/gateway-contract';
|
|
1
2
|
export interface ContextSnapshot {
|
|
2
3
|
id: string;
|
|
3
4
|
batchId: string;
|
|
@@ -6,6 +7,7 @@ export interface ContextSnapshot {
|
|
|
6
7
|
createdAt: string;
|
|
7
8
|
}
|
|
8
9
|
export interface InsightCandidate {
|
|
10
|
+
artifact?: ProactiveArtifact;
|
|
9
11
|
title: string;
|
|
10
12
|
summary: string;
|
|
11
13
|
whyNow: string;
|
|
@@ -55,6 +57,11 @@ export interface ProactiveAgentExecutor {
|
|
|
55
57
|
}): Promise<{
|
|
56
58
|
text: string;
|
|
57
59
|
modelRef?: string;
|
|
60
|
+
usage?: {
|
|
61
|
+
inputTokens: number;
|
|
62
|
+
outputTokens: number;
|
|
63
|
+
estimatedCostUsd?: number;
|
|
64
|
+
};
|
|
58
65
|
}>;
|
|
59
66
|
}
|
|
60
67
|
export interface ContextProvider {
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import { createLogger } from "../../utils/logger/index.js";
|
|
2
2
|
import { init_logger } from "../../utils/logger.js";
|
|
3
|
+
import { getSqliteDatabase } from "../../storage/sqlite/transaction.js";
|
|
4
|
+
import { authorizedConnectedSource } from "./authorization.js";
|
|
5
|
+
import { effectiveProactivePolicy } from "../policy/service.js";
|
|
3
6
|
import { getPromptRevision, getScenario } from "../scenarios/repository.js";
|
|
4
7
|
import { composeScenarioPrompt } from "../scenarios/prompt-composer.js";
|
|
5
8
|
import { markReadyBatches } from "../routing/batch-repository.js";
|
|
6
9
|
import { ContextProviderRegistry } from "./context.js";
|
|
7
10
|
import { attachSnapshot, claimNextRun, eventIdsForBatch, failRun, finishRun, saveSnapshot } from "./repository.js";
|
|
8
|
-
import { isValuableInsight,
|
|
11
|
+
import { isValuableInsight, parseAnalysisResult, scoreInsight } from "./insight.js";
|
|
9
12
|
import { randomUUID } from "node:crypto";
|
|
13
|
+
import { isDeepStrictEqual } from "node:util";
|
|
10
14
|
//#region src/proactive/execution/worker.ts
|
|
11
15
|
init_logger();
|
|
12
16
|
const log = createLogger("ProactiveWorker");
|
|
@@ -42,6 +46,14 @@ var ProactiveWorker = class {
|
|
|
42
46
|
try {
|
|
43
47
|
const scenario = getScenario(run.scenarioKey, run.scenarioVersion);
|
|
44
48
|
if (!scenario) throw new Error("Pinned scenario version is unavailable");
|
|
49
|
+
if (!effectiveProactivePolicy(run.subscriptionId).enabled) {
|
|
50
|
+
finishRun({
|
|
51
|
+
run,
|
|
52
|
+
rawOutput: "",
|
|
53
|
+
outcomeReason: "disabled"
|
|
54
|
+
});
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
45
57
|
const revision = run.promptRevisionId ? getPromptRevision(run.promptRevisionId) ?? void 0 : void 0;
|
|
46
58
|
const eventIds = eventIdsForBatch(run.batchId);
|
|
47
59
|
const context = await this.contexts.collect(scenario, {
|
|
@@ -49,6 +61,14 @@ var ProactiveWorker = class {
|
|
|
49
61
|
eventIds,
|
|
50
62
|
subscriptionId: run.subscriptionId
|
|
51
63
|
});
|
|
64
|
+
if (context.evidenceIds.length === 0) {
|
|
65
|
+
finishRun({
|
|
66
|
+
run,
|
|
67
|
+
rawOutput: "",
|
|
68
|
+
outcomeReason: "source_unavailable"
|
|
69
|
+
});
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
52
72
|
const snapshot = saveSnapshot(run.batchId, context.snapshotContent ?? context.content, context.evidenceIds);
|
|
53
73
|
attachSnapshot(run.id, snapshot.id);
|
|
54
74
|
const prompt = composeScenarioPrompt({
|
|
@@ -61,9 +81,24 @@ var ProactiveWorker = class {
|
|
|
61
81
|
userPrompt: prompt.text,
|
|
62
82
|
authorizedContext: context.content
|
|
63
83
|
});
|
|
64
|
-
|
|
65
|
-
const
|
|
66
|
-
|
|
84
|
+
if (output.usage) getSqliteDatabase().prepare("UPDATE proactive_runs SET input_tokens = ?, output_tokens = ?, estimated_cost_usd = ? WHERE run_id = ? AND attempt = ?").run(output.usage.inputTokens, output.usage.outputTokens, output.usage.estimatedCostUsd ?? null, run.id, run.attempt);
|
|
85
|
+
const latestContext = await this.contexts.collect(scenario, {
|
|
86
|
+
batchId: run.batchId,
|
|
87
|
+
eventIds,
|
|
88
|
+
subscriptionId: run.subscriptionId
|
|
89
|
+
});
|
|
90
|
+
const revoked = context.evidenceIds.some((id) => !latestContext.evidenceIds.includes(id));
|
|
91
|
+
const changed = !isDeepStrictEqual(context.snapshotContent ?? context.content, latestContext.snapshotContent ?? latestContext.content);
|
|
92
|
+
const unavailable = context.evidenceIds.some((id) => id.startsWith("source-item:") && !authorizedConnectedSource(id.slice(12), effectiveProactivePolicy(run.subscriptionId).workspaceId, run.scenarioKey));
|
|
93
|
+
const result = revoked || changed ? {
|
|
94
|
+
result: "no_insight",
|
|
95
|
+
reason: unavailable ? "source_unavailable" : "source_changed"
|
|
96
|
+
} : parseAnalysisResult(output.text, new Set(latestContext.evidenceIds));
|
|
97
|
+
const candidate = result.result === "insight" ? result.candidate : void 0;
|
|
98
|
+
if (run.scenarioKey === "communication_follow_up" && (candidate?.decision || candidate?.proposedAction)) throw new Error("Communication preparation must return a draft or update; actions require the conversation confirmation flow");
|
|
99
|
+
const valueScore = candidate ? scoreInsight(candidate) : 0;
|
|
100
|
+
const enabled = effectiveProactivePolicy(run.subscriptionId).enabled;
|
|
101
|
+
const valuable = enabled && candidate && isValuableInsight(candidate, scenario.valuePolicy);
|
|
67
102
|
const insight = finishRun({
|
|
68
103
|
run,
|
|
69
104
|
...valuable ? {
|
|
@@ -71,16 +106,17 @@ var ProactiveWorker = class {
|
|
|
71
106
|
valueScore
|
|
72
107
|
} : {},
|
|
73
108
|
cooldownSeconds: scenario.valuePolicy.cooldownSeconds,
|
|
74
|
-
|
|
109
|
+
outcomeReason: !enabled ? "disabled" : result.result === "no_insight" ? result.reason : valuable ? "insight" : "below_threshold",
|
|
110
|
+
rawOutput: revoked ? "" : output.text,
|
|
75
111
|
modelRef: output.modelRef
|
|
76
112
|
});
|
|
77
|
-
const disposition = insight ? "created" : valuable ? "duplicate_suppressed" : "value_gate_discarded";
|
|
113
|
+
const disposition = insight ? "created" : valuable ? "duplicate_suppressed" : result.result === "no_insight" ? result.reason : "value_gate_discarded";
|
|
78
114
|
log.info({
|
|
79
115
|
runId: run.id,
|
|
80
116
|
scenarioKey: run.scenarioKey,
|
|
81
117
|
disposition,
|
|
82
118
|
insightId: insight?.id
|
|
83
|
-
}, insight ? "Proactive insight created" : "Proactive
|
|
119
|
+
}, insight ? "Proactive insight created" : "Proactive check completed without a card");
|
|
84
120
|
} catch (error) {
|
|
85
121
|
failRun(run, error, !(error instanceof Error && /Pinned scenario/.test(error.message)));
|
|
86
122
|
log.warn({
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
export declare function startDelegation(workspace: string, value: unknown): {
|
|
2
|
+
effectiveLevel: "off" | "active" | "quiet" | "balanced";
|
|
3
|
+
schedule: Record<string, import("node:sqlite").SQLOutputValue>;
|
|
4
|
+
revision: number;
|
|
5
|
+
level: "off" | "active" | "quiet" | "balanced";
|
|
6
|
+
delivery: "digest" | "inbox" | "important";
|
|
7
|
+
completedAt: string;
|
|
8
|
+
scanIntervalMinutes: number;
|
|
9
|
+
userInstructions: string;
|
|
10
|
+
id: string;
|
|
11
|
+
scenarioKey: string;
|
|
12
|
+
workspaceId: string;
|
|
13
|
+
scopeKind: "workspace" | "project";
|
|
14
|
+
scopeId: string;
|
|
15
|
+
enabled: boolean;
|
|
16
|
+
activePromptRevisionId?: string;
|
|
17
|
+
createdAt: string;
|
|
18
|
+
updatedAt: string;
|
|
19
|
+
};
|
|
20
|
+
/** Queue work in the existing worker; HTTP and conversation requests do not own model runs. */
|
|
21
|
+
export declare function checkDelegation(workspace: string, id: string): {
|
|
22
|
+
status: "queued";
|
|
23
|
+
};
|
|
24
|
+
export declare function delegationOverview(workspace: string): {
|
|
25
|
+
followUps: {
|
|
26
|
+
id: string;
|
|
27
|
+
subscriptionId: string;
|
|
28
|
+
instructions: string;
|
|
29
|
+
dueAt: string;
|
|
30
|
+
status: "completed" | "paused" | "watching";
|
|
31
|
+
revision: number;
|
|
32
|
+
lastCheckedAt: string;
|
|
33
|
+
sessionKey: string;
|
|
34
|
+
sourceAvailable: boolean;
|
|
35
|
+
enabled: boolean;
|
|
36
|
+
subject: string;
|
|
37
|
+
latestMessageAt: string;
|
|
38
|
+
latestDirection: string;
|
|
39
|
+
lastSyncedAt: string;
|
|
40
|
+
syncFailed: boolean;
|
|
41
|
+
}[];
|
|
42
|
+
needsDecision: import("@xopcai/gateway-contract/src/proactive.js").ProactiveCard[];
|
|
43
|
+
prepared: import("@xopcai/gateway-contract/src/proactive.js").ProactiveCard[];
|
|
44
|
+
updates: import("@xopcai/gateway-contract/src/proactive.js").ProactiveCard[];
|
|
45
|
+
delegations: {
|
|
46
|
+
effectiveEnabled: boolean;
|
|
47
|
+
project: Record<string, import("node:sqlite").SQLOutputValue>;
|
|
48
|
+
latestRun: Record<string, import("node:sqlite").SQLOutputValue>;
|
|
49
|
+
pending: boolean;
|
|
50
|
+
effectiveLevel: "off" | "active" | "quiet" | "balanced";
|
|
51
|
+
schedule: Record<string, import("node:sqlite").SQLOutputValue>;
|
|
52
|
+
revision: number;
|
|
53
|
+
level: "off" | "active" | "quiet" | "balanced";
|
|
54
|
+
delivery: "digest" | "inbox" | "important";
|
|
55
|
+
completedAt: string;
|
|
56
|
+
scanIntervalMinutes: number;
|
|
57
|
+
userInstructions: string;
|
|
58
|
+
id: string;
|
|
59
|
+
scenarioKey: string;
|
|
60
|
+
workspaceId: string;
|
|
61
|
+
scopeKind: "workspace" | "project";
|
|
62
|
+
scopeId: string;
|
|
63
|
+
enabled: boolean;
|
|
64
|
+
activePromptRevisionId?: string;
|
|
65
|
+
createdAt: string;
|
|
66
|
+
updatedAt: string;
|
|
67
|
+
}[];
|
|
68
|
+
};
|
|
69
|
+
export declare function completeDeliveredProjects(now?: Date): void;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { getSqliteDatabase, runSqliteWriteTransaction } from "../storage/sqlite/transaction.js";
|
|
2
|
+
import { ProactiveConflict, effectiveProactivePolicy } from "./policy/service.js";
|
|
3
|
+
import { controlledSubscriptions, createControlledSubscription, requireSubscription, updateControlledSubscription } from "./scenarios/control.js";
|
|
4
|
+
import { ProactiveScenarioService } from "./scenarios/service.js";
|
|
5
|
+
import { ProactiveEventService } from "./service.js";
|
|
6
|
+
import { listMailFollowUps } from "./follow-ups.js";
|
|
7
|
+
import { getCard } from "./inbox/cards.js";
|
|
8
|
+
import { scanDueProjects } from "./temporal/schedule.js";
|
|
9
|
+
import { z } from "zod";
|
|
10
|
+
//#region src/proactive/experience.ts
|
|
11
|
+
const DelegateSchema = z.object({
|
|
12
|
+
scenarioKey: z.enum([
|
|
13
|
+
"project_delivery_risk",
|
|
14
|
+
"meeting_preparation",
|
|
15
|
+
"discussion_follow_up"
|
|
16
|
+
]),
|
|
17
|
+
projectId: z.string().min(1).optional(),
|
|
18
|
+
instructions: z.string().trim().min(1).max(12e3)
|
|
19
|
+
}).strict();
|
|
20
|
+
function startDelegation(workspace, value) {
|
|
21
|
+
const input = DelegateSchema.parse(value);
|
|
22
|
+
if (input.scenarioKey === "project_delivery_risk" && !input.projectId) throw new Error("Choose a project");
|
|
23
|
+
if (input.scenarioKey !== "project_delivery_risk" && input.projectId) throw new Error("This service uses workspace sources");
|
|
24
|
+
const subscription = createControlledSubscription(workspace, {
|
|
25
|
+
scenarioKey: input.scenarioKey,
|
|
26
|
+
scopeKind: input.projectId ? "project" : "workspace",
|
|
27
|
+
scopeId: input.projectId ?? workspace,
|
|
28
|
+
userInstructions: input.instructions
|
|
29
|
+
});
|
|
30
|
+
if (input.projectId && effectiveProactivePolicy(subscription.id).enabled) checkDelegation(workspace, subscription.id);
|
|
31
|
+
return subscription;
|
|
32
|
+
}
|
|
33
|
+
/** Queue work in the existing worker; HTTP and conversation requests do not own model runs. */
|
|
34
|
+
function checkDelegation(workspace, id) {
|
|
35
|
+
const sub = requireSubscription(id, workspace);
|
|
36
|
+
if (!effectiveProactivePolicy(id).enabled) throw new Error("Resume this service before checking");
|
|
37
|
+
if (sub.scopeKind !== "project") throw new Error("This service checks when connected sources change");
|
|
38
|
+
return runSqliteWriteTransaction((db) => {
|
|
39
|
+
if (db.prepare("SELECT 1 FROM proactive_signal_batches WHERE subscription_id = ? AND status IN ('collecting', 'ready', 'processing')").get(id)) return { status: "queued" };
|
|
40
|
+
const last = db.prepare("SELECT MAX(started_at) AS at FROM proactive_runs WHERE subscription_id = ?").get(id);
|
|
41
|
+
if (last.at && Date.parse(last.at) > Date.now() - 6e4) throw new ProactiveConflict("A check just finished; try again in a minute");
|
|
42
|
+
db.prepare(`INSERT INTO proactive_schedule_state(subscription_id, next_due_at) VALUES (?, ?)
|
|
43
|
+
ON CONFLICT(subscription_id) DO UPDATE SET next_due_at = excluded.next_due_at, last_fingerprint = NULL`).run(id, (/* @__PURE__ */ new Date()).toISOString());
|
|
44
|
+
scanDueProjects(new ProactiveEventService(() => new ProactiveScenarioService().routes()));
|
|
45
|
+
db.prepare("UPDATE proactive_signal_batches SET ready_at = ?, status = 'ready' WHERE subscription_id = ? AND status = 'collecting'").run((/* @__PURE__ */ new Date()).toISOString(), id);
|
|
46
|
+
return { status: "queued" };
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
function delegationOverview(workspace) {
|
|
50
|
+
const db = getSqliteDatabase();
|
|
51
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
52
|
+
const cards = db.prepare(`SELECT i.inbox_item_id FROM proactive_inbox_items i
|
|
53
|
+
JOIN proactive_insights x USING(insight_id) JOIN proactive_scenario_subscriptions s USING(subscription_id)
|
|
54
|
+
WHERE s.workspace_id = ? AND i.withdrawn_at IS NULL AND i.status IN ('unread', 'read')
|
|
55
|
+
AND (i.expires_at IS NULL OR i.expires_at > ?)
|
|
56
|
+
ORDER BY CASE WHEN x.action_status = 'approval_required' THEN 0 WHEN x.artifact_json IS NOT NULL THEN 1 ELSE 2 END,
|
|
57
|
+
x.value_score DESC, i.updated_at DESC LIMIT 100`).all(workspace, now).map((row) => getCard(row.inbox_item_id, workspace)).filter((card) => !["withdrawn", "expired"].includes(card.status));
|
|
58
|
+
return {
|
|
59
|
+
followUps: listMailFollowUps(workspace),
|
|
60
|
+
needsDecision: cards.filter((card) => card.decision && card.actionStatus !== "completed"),
|
|
61
|
+
prepared: cards.filter((card) => card.artifact && !card.decision),
|
|
62
|
+
updates: cards.filter((card) => !card.artifact && !card.decision),
|
|
63
|
+
delegations: controlledSubscriptions(workspace).map((sub) => ({
|
|
64
|
+
...sub,
|
|
65
|
+
effectiveEnabled: effectiveProactivePolicy(sub.id).enabled,
|
|
66
|
+
project: sub.scopeKind === "project" ? db.prepare("SELECT name, status FROM projects WHERE project_id = ?").get(sub.scopeId) ?? null : null,
|
|
67
|
+
latestRun: db.prepare(`SELECT status, outcome_reason AS reason, completed_at AS completedAt, started_at AS startedAt, error_message AS error
|
|
68
|
+
FROM proactive_runs WHERE subscription_id = ? ORDER BY started_at DESC LIMIT 1`).get(sub.id) ?? null,
|
|
69
|
+
pending: Boolean(db.prepare("SELECT 1 FROM proactive_signal_batches WHERE subscription_id = ? AND status IN ('collecting', 'ready', 'processing')").get(sub.id))
|
|
70
|
+
}))
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
function completeDeliveredProjects(now = /* @__PURE__ */ new Date()) {
|
|
74
|
+
const db = getSqliteDatabase();
|
|
75
|
+
const rows = db.prepare(`SELECT s.subscription_id, s.workspace_id FROM proactive_scenario_subscriptions s
|
|
76
|
+
JOIN projects p ON p.project_id = s.scope_id WHERE s.scope_kind = 'project' AND s.enabled = 1
|
|
77
|
+
AND p.status IN ('completed', 'cancelled', 'archived')`).all();
|
|
78
|
+
for (const row of rows) {
|
|
79
|
+
const current = controlledSubscriptions(row.workspace_id).find((sub) => sub.id === row.subscription_id);
|
|
80
|
+
updateControlledSubscription(row.workspace_id, row.subscription_id, {
|
|
81
|
+
expectedRevision: current.revision,
|
|
82
|
+
enabled: false,
|
|
83
|
+
completedAt: now.toISOString()
|
|
84
|
+
});
|
|
85
|
+
db.prepare(`UPDATE proactive_inbox_items SET status = 'resolved', resolution = 'project_ended', updated_at = ?
|
|
86
|
+
WHERE insight_id IN (SELECT insight_id FROM proactive_insights WHERE subscription_id = ?) AND status <> 'resolved'`).run(now.toISOString(), row.subscription_id);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
//#endregion
|
|
90
|
+
export { checkDelegation, completeDeliveredProjects, delegationOverview, startDelegation };
|