@xopcai/xopc 0.0.197 → 0.0.200
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-BwmdJ5pv.js → activity-store-DYVN1hRp.js} +1 -1
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-C5st7lt5.js → agent-avatar-dicebear-eMarz29u.js} +1 -1
- package/dist/gateway/static/root/assets/agents-DeLW-454.js +68 -0
- package/dist/gateway/static/root/assets/{api-BM1hNzjw.js → api-B8mzbAle.js} +1 -1
- package/dist/gateway/static/root/assets/app-management-settings-panel-yfb68wq9.js +1 -0
- package/dist/gateway/static/root/assets/appearance-settings-B8SPknFM.js +1 -0
- package/dist/gateway/static/root/assets/apps-page-Bmor22Ny.js +1 -0
- package/dist/gateway/static/root/assets/{archive-plugin-qL07mwnY.js → archive-plugin-DmYRiOP3.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-CqSobpdi.js → attachment-load-D66JvcPi.js} +1 -1
- package/dist/gateway/static/root/assets/automations-page-Q4e8m11h.js +6 -0
- package/dist/gateway/static/root/assets/{binary-plugins-DBRPyLYE.js → binary-plugins-ChIsZArT.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-6wG1LU7t.js → block-editor-Ck-k_d0Z.js} +4 -4
- package/dist/gateway/static/root/assets/browser-settings-page--uVL73Sb.js +8 -0
- package/dist/gateway/static/root/assets/browser-workflow-inputs-_ndaecsf.js +1 -0
- package/dist/gateway/static/root/assets/{browser-workflows-page-BEu3E0et.js → browser-workflows-page-BC5jm1zL.js} +2 -2
- package/dist/gateway/static/root/assets/button-CSEbl4zT.js +1 -0
- package/dist/gateway/static/root/assets/capabilities-settings-panel-DXpf3QYN.js +7 -0
- package/dist/gateway/static/root/assets/{capability-presets-api-BoOzFotX.js → capability-presets-api-Dy1jZJKs.js} +1 -1
- package/dist/gateway/static/root/assets/capability-presets-settings-panel-NAjCsrTi.js +3 -0
- package/dist/gateway/static/root/assets/{channel-recipient-api-_8IiTxRB.js → channel-recipient-api-D-9qiuio.js} +1 -1
- package/dist/gateway/static/root/assets/channels-settings-CiWUo7jW.js +1 -0
- package/dist/gateway/static/root/assets/channels-status-swr-B4Rbh3bM.js +1 -0
- package/dist/gateway/static/root/assets/connectors-api-5xiCRVUS.js +1 -0
- package/dist/gateway/static/root/assets/connectors-page-DOwlMseU.js +2 -0
- package/dist/gateway/static/root/assets/copy-Dv6d4Dvw.js +1 -0
- package/dist/gateway/static/root/assets/cron-expression-B3PebXKZ.js +2 -0
- package/dist/gateway/static/root/assets/date-picker-C1Vke7Xn.js +1 -0
- package/dist/gateway/static/root/assets/dependency-picker-FrQ0tsBC.js +1 -0
- package/dist/gateway/static/root/assets/{desktop-pet-CsLR4pWB.js → desktop-pet-CPBAzNJi.js} +1 -1
- package/dist/gateway/static/root/assets/desktop-pet-settings-D6s3glDP.js +1 -0
- package/dist/gateway/static/root/assets/directory-picker-path-field-CbNQ7QQS.js +1 -0
- package/dist/gateway/static/root/assets/dist-BPoKqzeH.js +1 -0
- package/dist/gateway/static/root/assets/dist-DY4Af0fY.js +1 -0
- package/dist/gateway/static/root/assets/{extension-debug-page-CD73euAM.js → extension-debug-page-dTK14hUv.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-DAKjpNwd.js → extension-page-Cpdj1Kip.js} +1 -1
- package/dist/gateway/static/root/assets/extension-settings-page-iNHUZGd5.js +1 -0
- package/dist/gateway/static/root/assets/external-link-DjqjBmc3.js +1 -0
- package/dist/gateway/static/root/assets/form-field-width-DJw_jULe.js +1 -0
- package/dist/gateway/static/root/assets/gateway-config-api-SvMvWqMM.js +1 -0
- package/dist/gateway/static/root/assets/gateway-config-swr-jB0hAhWO.js +1 -0
- package/dist/gateway/static/root/assets/gateway-settings-BilR3dGZ.js +1 -0
- package/dist/gateway/static/root/assets/{gateway-startup-retry--2njcDpC.js → gateway-startup-retry-C-fRlHCL.js} +1 -1
- package/dist/gateway/static/root/assets/globe-DSSGFWFn.js +1 -0
- package/dist/gateway/static/root/assets/heartbeat-settings-zK40dcQ5.js +1 -0
- package/dist/gateway/static/root/assets/home-page-NyXy5MLr.js +3 -0
- package/dist/gateway/static/root/assets/index-Bp8I_eX4.css +1 -0
- package/dist/gateway/static/root/assets/index-CCK8zdlS.js +152 -0
- package/dist/gateway/static/root/assets/interaction-BmQogeqz.js +1 -0
- package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-HMhxgOuD.js → keyboard-shortcuts-settings-nKzsroud.js} +1 -1
- package/dist/gateway/static/root/assets/loader-circle-CifKLtgG.js +1 -0
- package/dist/gateway/static/root/assets/local-app-workbench-page-Ds3sPXTh.js +2 -0
- package/dist/gateway/static/root/assets/local-apps-page-DV1s_FYh.js +1 -0
- package/dist/gateway/static/root/assets/{locale-store-Bjvw7jtg.js → locale-store-xULEcFVs.js} +1 -1
- package/dist/gateway/static/root/assets/logs-page-Biz4eA02.js +2 -0
- package/dist/gateway/static/root/assets/management-settings-D7KjYgHu.js +1 -0
- package/dist/gateway/static/root/assets/{markdown-split-DvVBewS4.js → markdown-split-CTYbpkrd.js} +1 -1
- package/dist/gateway/static/root/assets/{media-plugins-YVj7NVzD.js → media-plugins-BXYnaiZ6.js} +1 -1
- package/dist/gateway/static/root/assets/messages-3qRsLZuX.js +3 -0
- package/dist/gateway/static/root/assets/{notes-page-BDzuL2I9.js → notes-page-CWWVXpw5.js} +1 -1
- package/dist/gateway/static/root/assets/notes-workbench-DnBkQihH.js +4 -0
- package/dist/gateway/static/root/assets/page-tabs-BaEQMYm_.js +1 -0
- package/dist/gateway/static/root/assets/popover-select-BzdnTy3h.js +1 -0
- package/dist/gateway/static/root/assets/preview-open-alternatives-pimQAkeI.js +1 -0
- package/dist/gateway/static/root/assets/{product-open-page-Bwx_CQht.js → product-open-page-BoYSS_YR.js} +1 -1
- package/dist/gateway/static/root/assets/project-detail-page-ZO7t1UkB.js +1 -0
- package/dist/gateway/static/root/assets/projects-page-By-vq41g.js +1 -0
- package/dist/gateway/static/root/assets/remote-access-hub-C0C_Y9d0.js +1 -0
- package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-Fe05Nus6.js → runtime-tools-settings-panel-DT8flaX1.js} +4 -4
- package/dist/gateway/static/root/assets/schema-form-DabEP-UI.js +1 -0
- package/dist/gateway/static/root/assets/sessions-page-BNlVwUzV.js +1 -0
- package/dist/gateway/static/root/assets/settings-advanced-gate-CxYBQDaM.js +1 -0
- package/dist/gateway/static/root/assets/settings-form-draft-Dy10ldo8.js +1 -0
- package/dist/gateway/static/root/assets/settings-form-section-DCsfZAtC.js +1 -0
- package/dist/gateway/static/root/assets/{settings-loading-skeleton-BRE_-7Da.js → settings-loading-skeleton-Dac6Yd0T.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-C1zxCpqB.js → settings-page-BDoYoEar.js} +1 -1
- package/dist/gateway/static/root/assets/settings-page-layout-BRQNel6r.js +1 -0
- package/dist/gateway/static/root/assets/settings-shell-dialog-layer-BU3UuiJr.js +1 -0
- package/dist/gateway/static/root/assets/setup-status-panel-DWijJ1rw.js +1 -0
- package/dist/gateway/static/root/assets/share-preview-page-ie9I2_7h.js +2 -0
- package/dist/gateway/static/root/assets/shares-settings-DU9VrJLf.js +1 -0
- package/dist/gateway/static/root/assets/skill-reload-api-C5RaIvoE.js +1 -0
- package/dist/gateway/static/root/assets/skills-page-N0YhaR5S.js +2 -0
- package/dist/gateway/static/root/assets/{skills-page.utils-CYwFWTso.js → skills-page.utils-C639DLXr.js} +1 -1
- package/dist/gateway/static/root/assets/system-settings-panel-CpshpQtC.js +1 -0
- package/dist/gateway/static/root/assets/task-detail-page-DsTocYkK.js +1 -0
- package/dist/gateway/static/root/assets/{theme-store-DtxpMC5S.js → theme-store-CHQRiuCF.js} +1 -1
- package/dist/gateway/static/root/assets/tool-activity-R8V9l6nk.js +1 -0
- package/dist/gateway/static/root/assets/typed-models-lib-q5-Vfqd8.js +1 -0
- package/dist/gateway/static/root/assets/use-autosave-ms6rDy59.js +1 -0
- package/dist/gateway/static/root/assets/user-context-page-BUxIemwy.js +1 -0
- package/dist/gateway/static/root/assets/voice-api-key-field-CObrQWh2.js +1 -0
- package/dist/gateway/static/root/assets/work-discovery-overlay-BBxrnEFt.js +1 -0
- package/dist/gateway/static/root/assets/work-discovery-page-DN3l-HW3.js +1 -0
- package/dist/gateway/static/root/assets/{workflow-run-setup-panel-DqIb1oBB.js → workflow-run-setup-panel-BxXhe3IV.js} +2 -2
- package/dist/gateway/static/root/assets/workflows-page-BCHkjd1i.js +5 -0
- package/dist/gateway/static/root/assets/working-directory-picker-modal-D-IgcHPp.js +1 -0
- package/dist/gateway/static/root/index.html +23 -8
- package/dist/package.js +1 -1
- package/dist/packages/gateway-contract/src/tasks.js +103 -9
- package/dist/src/agent/agent-manager.d.ts +1 -0
- package/dist/src/agent/agent-manager.js +1 -0
- package/dist/src/agent/context/execution-scope.js +3 -1
- package/dist/src/agent/service.js +1 -0
- package/dist/src/agent/service.types.d.ts +1 -0
- package/dist/src/agent/tasks/task-judge-service.d.ts +1 -1
- package/dist/src/agent/tasks/task-judge-service.js +3 -2
- package/dist/src/agent/tools/factory.d.ts +2 -0
- package/dist/src/agent/tools/factory.js +2 -1
- package/dist/src/agent/tools/xopc-use-tool.d.ts +1 -0
- package/dist/src/agent/tools/xopc-use-tool.js +69 -9
- package/dist/src/automations/domain/validation.d.ts +40 -12
- package/dist/src/automations/draft/automation-draft-validator.d.ts +4 -4
- package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
- package/dist/src/config/rules.js +2 -2
- package/dist/src/gateway/hono/app.d.ts +2 -0
- package/dist/src/gateway/hono/app.js +10 -3
- package/dist/src/gateway/hono/middleware/strict-rate-limit.d.ts +4 -0
- package/dist/src/gateway/hono/middleware/strict-rate-limit.js +8 -1
- package/dist/src/gateway/hono/routes/agent-stream.js +2 -74
- package/dist/src/gateway/hono/routes/config-patch/misc.js +2 -1
- package/dist/src/gateway/hono/routes/config.js +9 -0
- package/dist/src/gateway/hono/routes/deps.d.ts +1 -0
- package/dist/src/gateway/hono/routes/projects.js +55 -0
- package/dist/src/gateway/hono/routes/session-input-handler.d.ts +62 -0
- package/dist/src/gateway/hono/routes/session-input-handler.js +82 -0
- package/dist/src/gateway/hono/routes/tasks.js +272 -20
- package/dist/src/gateway/host.d.ts +9 -1
- package/dist/src/gateway/host.js +22 -5
- package/dist/src/gateway/rate-limit/buckets.d.ts +3 -0
- package/dist/src/gateway/rate-limit/buckets.js +12 -0
- package/dist/src/gateway/runtime-config.js +6 -5
- package/dist/src/gateway/security/audit.js +0 -7
- package/dist/src/gateway/server.js +4 -1
- package/dist/src/gateway/service/task-conversation-query-service.d.ts +58 -0
- package/dist/src/gateway/service/task-conversation-query-service.js +84 -0
- package/dist/src/gateway/service.d.ts +11 -0
- package/dist/src/gateway/service.js +75 -38
- package/dist/src/proactive/actions/service.d.ts +2 -0
- package/dist/src/proactive/actions/service.js +80 -0
- package/dist/src/proactive/execution/insight.js +20 -0
- package/dist/src/proactive/execution/repository.js +8 -2
- package/dist/src/proactive/execution/types.d.ts +14 -0
- package/dist/src/proactive/inbox/repository.js +59 -9
- package/dist/src/proactive/inbox/service.d.ts +2 -2
- package/dist/src/proactive/inbox/service.js +7 -2
- package/dist/src/proactive/inbox/types.d.ts +14 -0
- package/dist/src/proactive/inbox/worker.js +2 -0
- package/dist/src/proactive/scenarios/prompt-composer.js +2 -2
- package/dist/src/projects/project-agent.js +1 -1
- package/dist/src/storage/sqlite/migrations/118_task_board_rank.sql +6 -0
- package/dist/src/storage/sqlite/migrations/119_proactive_disposition.sql +13 -0
- package/dist/src/storage/sqlite/migrations/120_task_conversation.sql +112 -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/execution-context.js +8 -4
- package/dist/src/tasks/home-query-service.d.ts +5 -0
- package/dist/src/tasks/home-query-service.js +7 -2
- package/dist/src/tasks/index.d.ts +3 -0
- package/dist/src/tasks/index.js +6 -3
- package/dist/src/tasks/project-monitoring-service.d.ts +9 -0
- package/dist/src/tasks/project-monitoring-service.js +41 -3
- package/dist/src/tasks/project-operating-view-service.d.ts +1 -2
- package/dist/src/tasks/project-operating-view-service.js +26 -23
- package/dist/src/tasks/task-application-service.js +107 -21
- package/dist/src/tasks/task-change-events.d.ts +13 -0
- package/dist/src/tasks/task-change-events.js +29 -0
- package/dist/src/tasks/task-context-assembler.js +9 -4
- package/dist/src/tasks/task-context-repository.d.ts +0 -6
- package/dist/src/tasks/task-context-repository.js +0 -4
- package/dist/src/tasks/task-conversation-repository.d.ts +71 -0
- package/dist/src/tasks/task-conversation-repository.js +194 -0
- package/dist/src/tasks/task-handoff-service.d.ts +31 -0
- package/dist/src/tasks/task-handoff-service.js +143 -0
- package/dist/src/tasks/task-read-model-projector.js +3 -6
- package/dist/src/tasks/task-repository.d.ts +7 -2
- package/dist/src/tasks/task-repository.js +31 -15
- package/dist/src/tasks/task-run-coordinator.js +3 -1
- package/dist/src/tunnel/enable-lan-pairing.js +15 -26
- package/dist/src/tunnel/pair-context.js +1 -1
- package/dist/src/tunnel/pair-url.js +1 -1
- package/dist/src/tunnel/tunnel-qr.d.ts +0 -7
- package/dist/src/tunnel/tunnel-qr.js +2 -19
- package/dist/src/workflows/service/workflow-run-service.js +4 -2
- package/package.json +5 -3
- package/dist/gateway/static/root/assets/agents-Baxfj44y.js +0 -68
- package/dist/gateway/static/root/assets/app-management-settings-panel-S8LhoD6G.js +0 -1
- package/dist/gateway/static/root/assets/appearance-settings-D8Cd5vDP.js +0 -1
- package/dist/gateway/static/root/assets/apps-page-0uCxKyE5.js +0 -1
- package/dist/gateway/static/root/assets/automations-page-XyDat125.js +0 -6
- package/dist/gateway/static/root/assets/browser-settings-page-CrYNMR4w.js +0 -8
- package/dist/gateway/static/root/assets/browser-workflow-inputs-Abil4puY.js +0 -1
- package/dist/gateway/static/root/assets/capabilities-settings-panel-CvMcDhGf.js +0 -7
- package/dist/gateway/static/root/assets/capability-presets-settings-panel-CHJDY-Ih.js +0 -3
- package/dist/gateway/static/root/assets/channels-settings-Ds9BJbcY.js +0 -1
- package/dist/gateway/static/root/assets/channels-status-swr-DPaJSYX_.js +0 -1
- package/dist/gateway/static/root/assets/connectors-api-CgWjgPSI.js +0 -1
- package/dist/gateway/static/root/assets/connectors-page-NUs-Zf7F.js +0 -2
- package/dist/gateway/static/root/assets/cron-expression-ZdDBAoqA.js +0 -2
- package/dist/gateway/static/root/assets/dependency-picker-BGeB1jpn.js +0 -1
- package/dist/gateway/static/root/assets/desktop-pet-settings-CCjT1bdo.js +0 -1
- package/dist/gateway/static/root/assets/directory-picker-path-field-C-Te1QN3.js +0 -1
- package/dist/gateway/static/root/assets/extension-settings-page-BLSNdlgd.js +0 -1
- package/dist/gateway/static/root/assets/gateway-config-api-CQrf0k3D.js +0 -1
- package/dist/gateway/static/root/assets/gateway-settings-CvgH8IJI.js +0 -1
- package/dist/gateway/static/root/assets/heartbeat-settings-SPpnqbjl.js +0 -1
- package/dist/gateway/static/root/assets/home-page-BFoD6047.js +0 -3
- package/dist/gateway/static/root/assets/index-84ys9u-K.js +0 -152
- package/dist/gateway/static/root/assets/index-D-srnucP.css +0 -1
- package/dist/gateway/static/root/assets/local-app-workbench-page-D5uL2_Fd.js +0 -2
- package/dist/gateway/static/root/assets/local-apps-page-DIWkFa3g.js +0 -1
- package/dist/gateway/static/root/assets/logs-page--6v8qq6y.js +0 -2
- package/dist/gateway/static/root/assets/management-settings-DtEuS-kR.js +0 -1
- package/dist/gateway/static/root/assets/messages-DQ5X6cXp.js +0 -3
- package/dist/gateway/static/root/assets/notes-workbench-IdjuNXvH.js +0 -4
- package/dist/gateway/static/root/assets/page-tabs-7bSEWfSX.js +0 -1
- package/dist/gateway/static/root/assets/preview-open-alternatives-tgLbHgcV.js +0 -1
- package/dist/gateway/static/root/assets/project-detail-page-DnJXSuM4.js +0 -1
- package/dist/gateway/static/root/assets/projects-page-DckZKlBI.js +0 -1
- package/dist/gateway/static/root/assets/remote-access-hub-CfbUHBUH.js +0 -1
- package/dist/gateway/static/root/assets/schema-form-CFfyC4CB.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-BCfCh4My.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-Cbi4FvzO.js +0 -1
- package/dist/gateway/static/root/assets/settings-form-section-gEnEYT_3.js +0 -1
- package/dist/gateway/static/root/assets/settings-page-layout-CRpXF_05.js +0 -1
- package/dist/gateway/static/root/assets/setup-status-panel-BcHdpmFf.js +0 -1
- package/dist/gateway/static/root/assets/share-preview-page-DU8L68A5.js +0 -2
- package/dist/gateway/static/root/assets/shares-settings-kjTqH9yY.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-QAGpwzIM.js +0 -1
- package/dist/gateway/static/root/assets/skills-page-lE1-YRdK.js +0 -2
- package/dist/gateway/static/root/assets/system-settings-panel-CVDsiPKn.js +0 -1
- package/dist/gateway/static/root/assets/task-detail-page-DsM13-cy.js +0 -1
- package/dist/gateway/static/root/assets/typed-models-lib-DelyYgoc.js +0 -1
- package/dist/gateway/static/root/assets/use-autosave-C50Mq5yQ.js +0 -1
- package/dist/gateway/static/root/assets/user-context-page-D-VEOt2A.js +0 -1
- package/dist/gateway/static/root/assets/voice-api-key-field-DYfgTe3Y.js +0 -1
- package/dist/gateway/static/root/assets/work-discovery-overlay-DPbujsp3.js +0 -1
- package/dist/gateway/static/root/assets/work-discovery-page-D77opady.js +0 -1
- package/dist/gateway/static/root/assets/workflows-page-B9-PLmlX.js +0 -5
- package/dist/src/gateway/ensure-network-cors.d.ts +0 -3
- package/dist/src/gateway/ensure-network-cors.js +0 -23
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { SessionTimelineItem } from '../../session/transcript-outline.js';
|
|
2
|
+
import { TaskConversationRepository } from '../../tasks/task-conversation-repository.js';
|
|
3
|
+
import type { GatewaySessionsApi } from './sessions-api.js';
|
|
4
|
+
export declare class TaskConversationQueryService {
|
|
5
|
+
#private;
|
|
6
|
+
private readonly sessions;
|
|
7
|
+
private readonly conversations;
|
|
8
|
+
constructor(sessions: Pick<GatewaySessionsApi, 'getMessagePage' | 'getTimeline'>, conversations?: Pick<TaskConversationRepository, 'listSessions'>);
|
|
9
|
+
getMessagePage(taskId: string, options: {
|
|
10
|
+
limit: number;
|
|
11
|
+
offset: number;
|
|
12
|
+
before?: number;
|
|
13
|
+
}): Promise<{
|
|
14
|
+
session: {
|
|
15
|
+
messages: import("../../session/types.js").Message[];
|
|
16
|
+
transcriptSummary?: import("../../session/types.js").SessionTranscriptSummary;
|
|
17
|
+
transcriptRows?: import("../../session/session-context-for-llm.js").TranscriptStoredRow[];
|
|
18
|
+
key: string;
|
|
19
|
+
name?: string;
|
|
20
|
+
status: import("../../session/types.js").SessionStatus;
|
|
21
|
+
tags: string[];
|
|
22
|
+
createdAt: string;
|
|
23
|
+
updatedAt: string;
|
|
24
|
+
lastAccessedAt: string;
|
|
25
|
+
messageCount: number;
|
|
26
|
+
estimatedTokens: number;
|
|
27
|
+
compactedCount: number;
|
|
28
|
+
lastFlushedAt?: string;
|
|
29
|
+
flushCount?: number;
|
|
30
|
+
sourceChannel: string;
|
|
31
|
+
sourceChatId: string;
|
|
32
|
+
customData?: Record<string, unknown>;
|
|
33
|
+
projectId?: string;
|
|
34
|
+
routing?: import("../../session/types.js").SessionRoutingMeta;
|
|
35
|
+
stats?: import("../../session/types.js").SessionStats;
|
|
36
|
+
sessionType: import("../../session/types.js").SessionType;
|
|
37
|
+
hiddenFromSessionList?: boolean;
|
|
38
|
+
parentSessionKey?: string;
|
|
39
|
+
workflowRunId?: string;
|
|
40
|
+
workflowDefinitionId?: string;
|
|
41
|
+
workflowAgentId?: string;
|
|
42
|
+
workflowAgentLabel?: string;
|
|
43
|
+
sessionId?: string;
|
|
44
|
+
cwd?: string;
|
|
45
|
+
sessionStartedAt?: string;
|
|
46
|
+
lastInteractionAt?: string;
|
|
47
|
+
};
|
|
48
|
+
pagination: {
|
|
49
|
+
nextBeforeCursor?: string;
|
|
50
|
+
before?: string;
|
|
51
|
+
total: number;
|
|
52
|
+
limit: number;
|
|
53
|
+
offset: number;
|
|
54
|
+
hasMore: boolean;
|
|
55
|
+
};
|
|
56
|
+
}>;
|
|
57
|
+
getTimeline(taskId: string): Promise<SessionTimelineItem[] | null>;
|
|
58
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { TaskConversationRepository } from "../../tasks/task-conversation-repository.js";
|
|
2
|
+
//#region src/gateway/service/task-conversation-query-service.ts
|
|
3
|
+
var TaskConversationQueryService = class {
|
|
4
|
+
constructor(sessions, conversations = new TaskConversationRepository()) {
|
|
5
|
+
this.sessions = sessions;
|
|
6
|
+
this.conversations = conversations;
|
|
7
|
+
}
|
|
8
|
+
async getMessagePage(taskId, options) {
|
|
9
|
+
const links = this.#executionSessions(taskId);
|
|
10
|
+
if (links.length === 0) return null;
|
|
11
|
+
const probes = await Promise.all(links.map((link) => this.sessions.getMessagePage(link.sessionKey, { limit: 1 })));
|
|
12
|
+
if (probes.some((page) => !page)) return null;
|
|
13
|
+
const pages = probes;
|
|
14
|
+
const total = pages.reduce((sum, page) => sum + page.pagination.total, 0);
|
|
15
|
+
const end = Math.min(total, Math.max(0, options.before ?? total - options.offset));
|
|
16
|
+
const start = Math.max(0, end - options.limit);
|
|
17
|
+
const messages = [];
|
|
18
|
+
let cursor = 0;
|
|
19
|
+
for (let index = 0; index < links.length; index += 1) {
|
|
20
|
+
const sessionTotal = pages[index].pagination.total;
|
|
21
|
+
const localStart = Math.max(0, start - cursor);
|
|
22
|
+
const localEnd = Math.min(sessionTotal, end - cursor);
|
|
23
|
+
if (localStart < localEnd) {
|
|
24
|
+
const page = await this.sessions.getMessagePage(links[index].sessionKey, {
|
|
25
|
+
offset: sessionTotal - localEnd,
|
|
26
|
+
limit: localEnd - localStart
|
|
27
|
+
});
|
|
28
|
+
if (!page) return null;
|
|
29
|
+
messages.push(...page.session.messages);
|
|
30
|
+
}
|
|
31
|
+
cursor += sessionTotal;
|
|
32
|
+
}
|
|
33
|
+
const activeIndex = links.findIndex((link) => link.status === "active");
|
|
34
|
+
return {
|
|
35
|
+
session: {
|
|
36
|
+
...pages[activeIndex >= 0 ? activeIndex : pages.length - 1].session,
|
|
37
|
+
messages
|
|
38
|
+
},
|
|
39
|
+
pagination: {
|
|
40
|
+
total,
|
|
41
|
+
limit: options.limit,
|
|
42
|
+
offset: options.offset,
|
|
43
|
+
hasMore: start > 0,
|
|
44
|
+
...options.before === void 0 ? {} : { before: String(end) },
|
|
45
|
+
...start > 0 ? { nextBeforeCursor: String(start) } : {}
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
async getTimeline(taskId) {
|
|
50
|
+
const links = this.#executionSessions(taskId);
|
|
51
|
+
if (links.length === 0) return null;
|
|
52
|
+
const output = [];
|
|
53
|
+
let displayOffset = 0;
|
|
54
|
+
let turnOffset = 0;
|
|
55
|
+
for (const [index, link] of links.entries()) {
|
|
56
|
+
const [items, page] = await Promise.all([this.sessions.getTimeline(link.sessionKey), this.sessions.getMessagePage(link.sessionKey, { limit: 1 })]);
|
|
57
|
+
if (!items || !page) return null;
|
|
58
|
+
if (index > 0) output.push({
|
|
59
|
+
id: `assignment:${link.id}`,
|
|
60
|
+
kind: "branch",
|
|
61
|
+
title: link.agentId ? `Execution continued by ${link.agentId}` : "Execution continued",
|
|
62
|
+
timestamp: link.startedAt,
|
|
63
|
+
depth: 0,
|
|
64
|
+
turn: turnOffset,
|
|
65
|
+
displayIndex: displayOffset
|
|
66
|
+
});
|
|
67
|
+
output.push(...items.map((item) => ({
|
|
68
|
+
...item,
|
|
69
|
+
id: `${link.id}:${item.id}`,
|
|
70
|
+
turn: item.turn + turnOffset,
|
|
71
|
+
...item.displayIndex === void 0 ? {} : { displayIndex: item.displayIndex + displayOffset }
|
|
72
|
+
})));
|
|
73
|
+
displayOffset += page.pagination.total;
|
|
74
|
+
const highestTurn = items.reduce((max, item) => Math.max(max, item.turn), -1);
|
|
75
|
+
turnOffset += highestTurn + 1;
|
|
76
|
+
}
|
|
77
|
+
return output;
|
|
78
|
+
}
|
|
79
|
+
#executionSessions(taskId) {
|
|
80
|
+
return this.conversations.listSessions(taskId).filter((link) => link.role === "execution").sort((a, b) => a.assignmentEpoch - b.assignmentEpoch || a.startedAt - b.startedAt);
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
//#endregion
|
|
84
|
+
export { TaskConversationQueryService };
|
|
@@ -12,6 +12,7 @@ import { type ResolvedGatewayAuth } from './auth.js';
|
|
|
12
12
|
import { ModelCatalogSyncService } from '../providers/model-catalog-sync-service.js';
|
|
13
13
|
import { ProjectService } from '../projects/index.js';
|
|
14
14
|
import { LocalAppService } from '../local-apps/index.js';
|
|
15
|
+
import { TaskConversationRepository } from '../tasks/task-conversation-repository.js';
|
|
15
16
|
import { type BrowserRecipeService } from '../browser/recipes/index.js';
|
|
16
17
|
import { listInsights, ProactiveEventService, ProactiveInboxService, ProactiveInboxWorker, ProactiveScenarioService, ProactiveTemporalWorker, ProactiveWorker } from '../proactive/index.js';
|
|
17
18
|
import { GatewaySessionsApi } from './service/sessions-api.js';
|
|
@@ -120,6 +121,16 @@ export declare class GatewayService {
|
|
|
120
121
|
private createTaskRunDispatcher;
|
|
121
122
|
private createMobileNotificationService;
|
|
122
123
|
dispatchTaskRuns(): void;
|
|
124
|
+
ensureTaskConversation(taskId: string, options?: {
|
|
125
|
+
runId?: string;
|
|
126
|
+
requestedAgentId?: string;
|
|
127
|
+
}): Promise<{
|
|
128
|
+
sessionKey: string;
|
|
129
|
+
agentId: string;
|
|
130
|
+
created: boolean;
|
|
131
|
+
conversation: ReturnType<TaskConversationRepository['requireState']>;
|
|
132
|
+
}>;
|
|
133
|
+
dispatchTaskEvents(): void;
|
|
123
134
|
runAgent(...args: Parameters<GatewayAgentRunner['runAgent']>): ReturnType<GatewayAgentRunner['runAgent']>;
|
|
124
135
|
submitSessionInput(...args: Parameters<GatewayAgentRunner['submitSessionInput']>): Promise<{
|
|
125
136
|
ok: true;
|
|
@@ -19,19 +19,20 @@ import { loadConfig, saveConfig } from "../config/loader.js";
|
|
|
19
19
|
import { prewarmModelRegistry } from "../providers/model-registry.js";
|
|
20
20
|
import { init_providers, providers_exports } from "../providers/index.js";
|
|
21
21
|
import { TaskRepository } from "../tasks/task-repository.js";
|
|
22
|
+
import { TaskConversationRepository } from "../tasks/task-conversation-repository.js";
|
|
22
23
|
import { disposeAllSessionMcpRuntimes } from "../agent/mcp/bundle-mcp-runtime.js";
|
|
23
24
|
import { resolveEffectiveGatewayPort } from "./host.js";
|
|
24
25
|
import { AutomationService } from "../automations/service/automation-service.js";
|
|
25
26
|
import { onAutomationProductEvent, publishAutomationProductEvent } from "../automations/product-events.js";
|
|
26
27
|
import "../automations/index.js";
|
|
27
28
|
import { ProjectService } from "../projects/project-service.js";
|
|
29
|
+
import { resolveProjectAgentId } from "../projects/project-agent.js";
|
|
28
30
|
import "../projects/index.js";
|
|
29
31
|
import { sanitizeTunnelConfig } from "../tunnel/tunnel-config.js";
|
|
30
32
|
import { wireTunnelEventsToGateway } from "../tunnel/gateway-lifecycle.js";
|
|
31
33
|
import { buckets } from "./rate-limit/buckets.js";
|
|
32
34
|
import { isGatewayStrictSecurityEnabled } from "./rate-limit/env-flags.js";
|
|
33
35
|
import "./rate-limit/index.js";
|
|
34
|
-
import { TaskContextRepository } from "../tasks/task-context-repository.js";
|
|
35
36
|
import { TaskApplicationService } from "../tasks/task-application-service.js";
|
|
36
37
|
import { ProactiveScenarioService } from "../proactive/scenarios/service.js";
|
|
37
38
|
import { TaskOutboxDispatcher } from "../tasks/task-outbox-dispatcher.js";
|
|
@@ -460,6 +461,7 @@ var GatewayService = class {
|
|
|
460
461
|
getNotesService: () => this.notesService,
|
|
461
462
|
getProjectService: () => this.projects,
|
|
462
463
|
getLocalAppService: () => this.localApps,
|
|
464
|
+
dispatchTaskEvents: () => this.dispatchTaskEvents(),
|
|
463
465
|
dispatchTaskRuns: () => this.dispatchTaskRuns(),
|
|
464
466
|
getWorkflowRunService: () => this.createWorkflowRunService(),
|
|
465
467
|
sourceContextResolver: async (binding) => {
|
|
@@ -540,42 +542,10 @@ var GatewayService = class {
|
|
|
540
542
|
if (!this.taskRunDispatcher) this.taskRunDispatcher = new TaskRunDispatcher({
|
|
541
543
|
workerId: "gateway-agent",
|
|
542
544
|
ensureSession: async (taskId, runId, requestedAgentId) => {
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
agentId,
|
|
548
|
-
source: "webchat",
|
|
549
|
-
accountId: "default",
|
|
550
|
-
peerKind: "direct",
|
|
551
|
-
peerId
|
|
552
|
-
});
|
|
553
|
-
if (!await this.sessionIndex.getSessionMetadata(sessionKey)) await this.sessionIndex.saveMessages(sessionKey, [], { metadata: {
|
|
554
|
-
sourceChannel: "webchat",
|
|
555
|
-
sourceChatId: `default:direct:${peerId}`,
|
|
556
|
-
sessionType: "chat",
|
|
557
|
-
routing: {
|
|
558
|
-
agentId,
|
|
559
|
-
source: "webchat",
|
|
560
|
-
accountId: "default",
|
|
561
|
-
peerKind: "direct",
|
|
562
|
-
peerId
|
|
563
|
-
},
|
|
564
|
-
projectId: task.projectId,
|
|
565
|
-
customData: {
|
|
566
|
-
taskId,
|
|
567
|
-
origin: "task",
|
|
568
|
-
triggerKind: "user",
|
|
569
|
-
taskRunId: runId
|
|
570
|
-
}
|
|
571
|
-
} });
|
|
572
|
-
if (task.projectId) this.projects.attachSession(sessionKey, task.projectId);
|
|
573
|
-
new TaskContextRepository().linkSession({
|
|
574
|
-
taskId,
|
|
575
|
-
sessionKey,
|
|
576
|
-
role: "execution"
|
|
577
|
-
});
|
|
578
|
-
return sessionKey;
|
|
545
|
+
return (await this.ensureTaskConversation(taskId, {
|
|
546
|
+
runId,
|
|
547
|
+
requestedAgentId
|
|
548
|
+
})).sessionKey;
|
|
579
549
|
},
|
|
580
550
|
runAgent: async (runId, sessionKey, message) => {
|
|
581
551
|
const stream = this.agentRunner.runAgent(message, "webchat", sessionKey, {
|
|
@@ -593,10 +563,77 @@ var GatewayService = class {
|
|
|
593
563
|
}
|
|
594
564
|
dispatchTaskRuns() {
|
|
595
565
|
new TaskSignalService().tick();
|
|
596
|
-
|
|
566
|
+
this.dispatchTaskEvents();
|
|
597
567
|
this.createTaskRunDispatcher().dispatch();
|
|
598
568
|
this.createWorkflowRunService().dispatchTaskRuns();
|
|
599
569
|
}
|
|
570
|
+
async ensureTaskConversation(taskId, options = {}) {
|
|
571
|
+
const task = new TaskRepository().require(taskId);
|
|
572
|
+
const agentId = resolveProjectAgentId({
|
|
573
|
+
config: this.config,
|
|
574
|
+
projects: this.projects,
|
|
575
|
+
explicitAgentId: options.requestedAgentId ?? task.delegateAgentId,
|
|
576
|
+
projectId: task.projectId
|
|
577
|
+
});
|
|
578
|
+
const conversations = new TaskConversationRepository();
|
|
579
|
+
const active = conversations.getActiveSession(task.id);
|
|
580
|
+
if (active) {
|
|
581
|
+
if (active.agentId && active.agentId !== agentId) throw new Error("Task executor differs from the active conversation");
|
|
582
|
+
const conversation = conversations.activateExecutionSession({
|
|
583
|
+
taskId: task.id,
|
|
584
|
+
sessionKey: active.sessionKey,
|
|
585
|
+
agentId,
|
|
586
|
+
runId: options.runId
|
|
587
|
+
});
|
|
588
|
+
return {
|
|
589
|
+
sessionKey: active.sessionKey,
|
|
590
|
+
agentId,
|
|
591
|
+
created: false,
|
|
592
|
+
conversation
|
|
593
|
+
};
|
|
594
|
+
}
|
|
595
|
+
const peerId = `task-${sanitizeSegment(task.id) || Date.now()}`;
|
|
596
|
+
const sessionKey = buildSessionKey({
|
|
597
|
+
agentId,
|
|
598
|
+
source: "webchat",
|
|
599
|
+
accountId: "default",
|
|
600
|
+
peerKind: "direct",
|
|
601
|
+
peerId
|
|
602
|
+
});
|
|
603
|
+
if (!await this.sessionIndex.getSessionMetadata(sessionKey)) await this.sessionIndex.saveMessages(sessionKey, [], { metadata: {
|
|
604
|
+
sourceChannel: "webchat",
|
|
605
|
+
sourceChatId: `default:direct:${peerId}`,
|
|
606
|
+
sessionType: "chat",
|
|
607
|
+
routing: {
|
|
608
|
+
agentId,
|
|
609
|
+
source: "webchat",
|
|
610
|
+
accountId: "default",
|
|
611
|
+
peerKind: "direct",
|
|
612
|
+
peerId
|
|
613
|
+
},
|
|
614
|
+
projectId: task.projectId,
|
|
615
|
+
customData: {
|
|
616
|
+
origin: "task",
|
|
617
|
+
triggerKind: "user",
|
|
618
|
+
...options.runId ? { taskRunId: options.runId } : {}
|
|
619
|
+
}
|
|
620
|
+
} });
|
|
621
|
+
if (task.projectId) this.projects.attachSession(sessionKey, task.projectId);
|
|
622
|
+
return {
|
|
623
|
+
sessionKey,
|
|
624
|
+
agentId,
|
|
625
|
+
created: true,
|
|
626
|
+
conversation: conversations.activateExecutionSession({
|
|
627
|
+
taskId: task.id,
|
|
628
|
+
sessionKey,
|
|
629
|
+
agentId,
|
|
630
|
+
runId: options.runId
|
|
631
|
+
})
|
|
632
|
+
};
|
|
633
|
+
}
|
|
634
|
+
dispatchTaskEvents() {
|
|
635
|
+
new TaskOutboxDispatcher(publishAutomationProductEvent).drain();
|
|
636
|
+
}
|
|
600
637
|
runAgent(...args) {
|
|
601
638
|
return this.agentRunner.runAgent(...args);
|
|
602
639
|
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { getSqliteDatabase, runSqliteWriteTransaction } from "../../storage/sqlite/transaction.js";
|
|
2
|
+
import { TaskApplicationService } from "../../tasks/task-application-service.js";
|
|
3
|
+
//#region src/proactive/actions/service.ts
|
|
4
|
+
function projectIdFromAggregationKey(value) {
|
|
5
|
+
if (!value.startsWith("project:") || value.length === 8) throw new Error("Proactive action has no project scope");
|
|
6
|
+
return value.slice(8);
|
|
7
|
+
}
|
|
8
|
+
function executeClaimedAction(row, now = /* @__PURE__ */ new Date()) {
|
|
9
|
+
const action = JSON.parse(row.proposed_action_json);
|
|
10
|
+
try {
|
|
11
|
+
if (action.id !== "create_project_task") throw new Error(`Unsupported proactive action: ${action.id}`);
|
|
12
|
+
const result = new TaskApplicationService().create({
|
|
13
|
+
idempotencyKey: `proactive:${row.insight_id}:${action.id}`,
|
|
14
|
+
title: action.input.title,
|
|
15
|
+
projectId: projectIdFromAggregationKey(row.aggregation_key),
|
|
16
|
+
priority: "normal",
|
|
17
|
+
contract: {
|
|
18
|
+
objective: action.input.objective,
|
|
19
|
+
expectedOutputs: [],
|
|
20
|
+
acceptanceCriteria: [],
|
|
21
|
+
constraints: [],
|
|
22
|
+
approvalRequired: [],
|
|
23
|
+
assumptions: [],
|
|
24
|
+
risks: [],
|
|
25
|
+
acceptancePolicy: "manual",
|
|
26
|
+
outputDestinations: []
|
|
27
|
+
},
|
|
28
|
+
dependencies: [],
|
|
29
|
+
context: [],
|
|
30
|
+
authorityGrants: [],
|
|
31
|
+
activation: {
|
|
32
|
+
mode: "capture",
|
|
33
|
+
phase: "backlog"
|
|
34
|
+
}
|
|
35
|
+
}, {
|
|
36
|
+
kind: "system",
|
|
37
|
+
id: "proactive"
|
|
38
|
+
});
|
|
39
|
+
if (!result.ok) throw new Error(`Task creation failed: ${"reason" in result ? result.reason : "unknown"}`);
|
|
40
|
+
getSqliteDatabase().prepare(`UPDATE proactive_insights
|
|
41
|
+
SET action_status = 'completed', action_result_json = ?, action_error = NULL, action_updated_at = ?
|
|
42
|
+
WHERE insight_id = ? AND action_status = 'executing'`).run(JSON.stringify({ taskId: result.model.task.id }), now.toISOString(), row.insight_id);
|
|
43
|
+
} catch (error) {
|
|
44
|
+
getSqliteDatabase().prepare(`UPDATE proactive_insights
|
|
45
|
+
SET action_status = 'failed', action_error = ?, action_updated_at = ?
|
|
46
|
+
WHERE insight_id = ? AND action_status = 'executing'`).run(String(error instanceof Error ? error.message : error).slice(0, 2e3), now.toISOString(), row.insight_id);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function executePendingProactiveActions(now = /* @__PURE__ */ new Date()) {
|
|
50
|
+
const expired = (/* @__PURE__ */ new Date(now.getTime() - 5 * 6e4)).toISOString();
|
|
51
|
+
getSqliteDatabase().prepare(`UPDATE proactive_insights SET action_status = 'pending', action_updated_at = ?
|
|
52
|
+
WHERE action_status = 'executing' AND action_updated_at <= ?`).run(now.toISOString(), expired);
|
|
53
|
+
let executed = 0;
|
|
54
|
+
while (true) {
|
|
55
|
+
const row = runSqliteWriteTransaction((db) => {
|
|
56
|
+
const candidate = db.prepare(`SELECT x.insight_id, b.aggregation_key, x.proposed_action_json
|
|
57
|
+
FROM proactive_insights x
|
|
58
|
+
JOIN proactive_runs r ON r.run_id = x.run_id
|
|
59
|
+
JOIN proactive_signal_batches b ON b.batch_id = r.batch_id
|
|
60
|
+
WHERE x.action_status = 'pending' ORDER BY x.created_at LIMIT 1`).get();
|
|
61
|
+
if (!candidate) return void 0;
|
|
62
|
+
return db.prepare(`UPDATE proactive_insights SET action_status = 'executing', action_updated_at = ?
|
|
63
|
+
WHERE insight_id = ? AND action_status = 'pending'`).run(now.toISOString(), candidate.insight_id).changes === 1 ? candidate : void 0;
|
|
64
|
+
});
|
|
65
|
+
if (!row) return executed;
|
|
66
|
+
executeClaimedAction(row, now);
|
|
67
|
+
executed += 1;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function resolveProactiveActionDecision(inboxItemId, choice, now = /* @__PURE__ */ new Date()) {
|
|
71
|
+
const row = getSqliteDatabase().prepare(`SELECT x.insight_id, x.action_status
|
|
72
|
+
FROM proactive_inbox_items i JOIN proactive_insights x ON x.insight_id = i.insight_id
|
|
73
|
+
WHERE i.inbox_item_id = ?`).get(inboxItemId);
|
|
74
|
+
if (!row || row.action_status !== "approval_required") return;
|
|
75
|
+
getSqliteDatabase().prepare(`UPDATE proactive_insights SET action_status = ?, action_updated_at = ?
|
|
76
|
+
WHERE insight_id = ? AND action_status = 'approval_required'`).run(choice === "approve" ? "pending" : "rejected", now.toISOString(), row.insight_id);
|
|
77
|
+
if (choice === "approve") executePendingProactiveActions(now);
|
|
78
|
+
}
|
|
79
|
+
//#endregion
|
|
80
|
+
export { executePendingProactiveActions, resolveProactiveActionDecision };
|
|
@@ -30,6 +30,23 @@ function parseDecision(value) {
|
|
|
30
30
|
options
|
|
31
31
|
};
|
|
32
32
|
}
|
|
33
|
+
function parseProposedAction(value) {
|
|
34
|
+
if (value == null) return void 0;
|
|
35
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("Insight proposedAction is invalid");
|
|
36
|
+
const row = value;
|
|
37
|
+
if (row.id !== "create_project_task" || row.risk !== "low") throw new Error("Insight proposedAction is not supported");
|
|
38
|
+
if (!row.input || typeof row.input !== "object" || Array.isArray(row.input)) throw new Error("Insight proposedAction input is invalid");
|
|
39
|
+
const input = row.input;
|
|
40
|
+
return {
|
|
41
|
+
id: "create_project_task",
|
|
42
|
+
risk: "low",
|
|
43
|
+
rationale: boundedText(row.rationale, "proposedAction rationale", 600),
|
|
44
|
+
input: {
|
|
45
|
+
title: boundedText(input.title, "proposedAction title", 160),
|
|
46
|
+
objective: boundedText(input.objective, "proposedAction objective", 1200)
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
}
|
|
33
50
|
function parseInsightCandidate(raw, allowedEvidenceIds) {
|
|
34
51
|
let value;
|
|
35
52
|
try {
|
|
@@ -45,6 +62,8 @@ function parseInsightCandidate(raw, allowedEvidenceIds) {
|
|
|
45
62
|
const evidenceIds = [...new Set(row.evidenceIds.map(String))];
|
|
46
63
|
if (evidenceIds.some((id) => !allowedEvidenceIds.has(id))) throw new Error("Insight cites unknown evidence");
|
|
47
64
|
const decision = parseDecision(row.decision);
|
|
65
|
+
const proposedAction = parseProposedAction(row.proposedAction);
|
|
66
|
+
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");
|
|
48
67
|
return {
|
|
49
68
|
title: boundedText(row.title, "title", 160),
|
|
50
69
|
summary: boundedText(row.summary, "summary", 1200),
|
|
@@ -53,6 +72,7 @@ function parseInsightCandidate(raw, allowedEvidenceIds) {
|
|
|
53
72
|
recommendation: boundedText(row.recommendation, "recommendation", 800),
|
|
54
73
|
workDone: boundedText(row.workDone, "workDone", 800),
|
|
55
74
|
...decision ? { decision } : {},
|
|
75
|
+
...proposedAction ? { proposedAction } : {},
|
|
56
76
|
urgency: String(row.urgency),
|
|
57
77
|
confidence: row.confidence,
|
|
58
78
|
evidenceIds
|
|
@@ -96,9 +96,9 @@ function finishRun(input, now = /* @__PURE__ */ new Date()) {
|
|
|
96
96
|
createdAt: nowIso
|
|
97
97
|
};
|
|
98
98
|
db.prepare(`INSERT INTO proactive_insights (insight_id, run_id, subscription_id, scenario_key, title, summary,
|
|
99
|
-
why_now, impact, recommendation, work_done, decision_json, urgency, confidence, value_score,
|
|
99
|
+
why_now, impact, recommendation, work_done, decision_json, proposed_action_json, urgency, confidence, value_score,
|
|
100
100
|
evidence_ids_json, content_fingerprint, created_at)
|
|
101
|
-
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.urgency, insight.confidence, insight.valueScore, JSON.stringify(insight.evidenceIds), fingerprint, insight.createdAt);
|
|
101
|
+
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);
|
|
102
102
|
return insight;
|
|
103
103
|
});
|
|
104
104
|
}
|
|
@@ -124,9 +124,15 @@ function listInsights(limit = 50) {
|
|
|
124
124
|
recommendation: str(row, "recommendation"),
|
|
125
125
|
workDone: str(row, "work_done"),
|
|
126
126
|
...row.decision_json ? { decision: JSON.parse(str(row, "decision_json")) } : {},
|
|
127
|
+
...row.proposed_action_json ? { proposedAction: JSON.parse(str(row, "proposed_action_json")) } : {},
|
|
127
128
|
urgency: str(row, "urgency"),
|
|
128
129
|
confidence: Number(row.confidence),
|
|
129
130
|
valueScore: Number(row.value_score),
|
|
131
|
+
...row.disposition ? { disposition: str(row, "disposition") } : {},
|
|
132
|
+
...row.disposition_reason ? { dispositionReason: str(row, "disposition_reason") } : {},
|
|
133
|
+
...row.action_status ? { actionStatus: str(row, "action_status") } : {},
|
|
134
|
+
...row.action_result_json ? { actionResult: JSON.parse(str(row, "action_result_json")) } : {},
|
|
135
|
+
...row.action_error ? { actionError: str(row, "action_error") } : {},
|
|
130
136
|
evidenceIds: JSON.parse(str(row, "evidence_ids_json")),
|
|
131
137
|
createdAt: str(row, "created_at")
|
|
132
138
|
}));
|
|
@@ -20,6 +20,15 @@ export interface InsightCandidate {
|
|
|
20
20
|
consequence: string;
|
|
21
21
|
}>;
|
|
22
22
|
};
|
|
23
|
+
proposedAction?: {
|
|
24
|
+
id: 'create_project_task';
|
|
25
|
+
risk: 'low';
|
|
26
|
+
rationale: string;
|
|
27
|
+
input: {
|
|
28
|
+
title: string;
|
|
29
|
+
objective: string;
|
|
30
|
+
};
|
|
31
|
+
};
|
|
23
32
|
urgency: 'low' | 'medium' | 'high' | 'critical';
|
|
24
33
|
confidence: number;
|
|
25
34
|
evidenceIds: string[];
|
|
@@ -30,6 +39,11 @@ export interface ProactiveInsight extends InsightCandidate {
|
|
|
30
39
|
subscriptionId: string;
|
|
31
40
|
scenarioKey: string;
|
|
32
41
|
valueScore: number;
|
|
42
|
+
disposition?: 'record_silently' | 'show_in_work' | 'request_approval' | 'auto_execute';
|
|
43
|
+
dispositionReason?: string;
|
|
44
|
+
actionStatus?: 'not_authorized' | 'approval_required' | 'pending' | 'executing' | 'completed' | 'rejected' | 'failed';
|
|
45
|
+
actionResult?: Record<string, unknown>;
|
|
46
|
+
actionError?: string;
|
|
33
47
|
createdAt: string;
|
|
34
48
|
}
|
|
35
49
|
export interface ProactiveAgentExecutor {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { getSqliteDatabase, runSqliteWriteTransaction } from "../../storage/sqlite/transaction.js";
|
|
2
|
+
import { decideProactiveDisposition, nextQuietHoursEnd, proactiveDispositionReason } from "../../tasks/project-monitoring-service.js";
|
|
2
3
|
import { randomUUID } from "node:crypto";
|
|
3
4
|
//#region src/proactive/inbox/repository.ts
|
|
4
5
|
const s = (row, key) => String(row[key]);
|
|
@@ -20,6 +21,12 @@ function itemFromRow(row) {
|
|
|
20
21
|
recommendation: s(row, "recommendation"),
|
|
21
22
|
workDone: s(row, "work_done"),
|
|
22
23
|
...row.decision_json ? { decision: JSON.parse(s(row, "decision_json")) } : {},
|
|
24
|
+
...row.proposed_action_json ? { proposedAction: JSON.parse(s(row, "proposed_action_json")) } : {},
|
|
25
|
+
disposition: s(row, "disposition"),
|
|
26
|
+
dispositionReason: s(row, "disposition_reason"),
|
|
27
|
+
...row.action_status ? { actionStatus: s(row, "action_status") } : {},
|
|
28
|
+
...row.action_result_json ? { actionResult: JSON.parse(s(row, "action_result_json")) } : {},
|
|
29
|
+
...row.action_error ? { actionError: s(row, "action_error") } : {},
|
|
23
30
|
urgency: s(row, "urgency"),
|
|
24
31
|
confidence: Number(row.confidence),
|
|
25
32
|
valueScore: Number(row.value_score),
|
|
@@ -28,27 +35,70 @@ function itemFromRow(row) {
|
|
|
28
35
|
};
|
|
29
36
|
}
|
|
30
37
|
const SELECT_ITEM = `SELECT i.*, x.subscription_id, x.scenario_key, x.title, x.summary, x.why_now, x.impact, x.recommendation,
|
|
31
|
-
x.work_done, x.decision_json, x.
|
|
38
|
+
x.work_done, x.decision_json, x.proposed_action_json, x.disposition, x.disposition_reason,
|
|
39
|
+
x.action_status, x.action_result_json, x.action_error, x.urgency, x.confidence, x.value_score, x.evidence_ids_json FROM proactive_inbox_items i
|
|
32
40
|
JOIN proactive_insights x ON x.insight_id = i.insight_id`;
|
|
33
41
|
function projectInsightsToInbox(now = /* @__PURE__ */ new Date()) {
|
|
34
42
|
return runSqliteWriteTransaction((db) => {
|
|
35
|
-
const missing = db.prepare(`SELECT x.insight_id
|
|
43
|
+
const missing = db.prepare(`SELECT x.insight_id, x.confidence, x.value_score, x.decision_json,
|
|
44
|
+
x.proposed_action_json, b.aggregation_key, p.project_id, p.mode, p.quiet_hours_json,
|
|
45
|
+
p.allowed_actions_json, p.confidence_threshold FROM proactive_insights x
|
|
36
46
|
JOIN proactive_runs r ON r.run_id = x.run_id
|
|
37
47
|
JOIN proactive_signal_batches b ON b.batch_id = r.batch_id
|
|
38
48
|
LEFT JOIN project_monitoring_policies p
|
|
39
49
|
ON b.aggregation_key = 'project:' || p.project_id
|
|
40
|
-
WHERE x.
|
|
41
|
-
|
|
42
|
-
ORDER BY x.created_at`).all();
|
|
50
|
+
WHERE x.disposition IS NULL ORDER BY x.created_at`).all();
|
|
51
|
+
let projected = 0;
|
|
43
52
|
for (const row of missing) {
|
|
44
|
-
const
|
|
53
|
+
const aggregationKey = String(row.aggregation_key);
|
|
54
|
+
const projectId = aggregationKey.startsWith("project:") ? aggregationKey.slice(8) : void 0;
|
|
55
|
+
const policy = projectId ? row.project_id ? {
|
|
56
|
+
projectId,
|
|
57
|
+
mode: String(row.mode),
|
|
58
|
+
...row.quiet_hours_json ? { quietHours: JSON.parse(String(row.quiet_hours_json)) } : {},
|
|
59
|
+
allowedActions: JSON.parse(String(row.allowed_actions_json)),
|
|
60
|
+
confidenceThreshold: Number(row.confidence_threshold),
|
|
61
|
+
scenarios: [],
|
|
62
|
+
configured: true
|
|
63
|
+
} : {
|
|
64
|
+
projectId,
|
|
65
|
+
mode: "observe",
|
|
66
|
+
allowedActions: [],
|
|
67
|
+
confidenceThreshold: .75,
|
|
68
|
+
scenarios: [],
|
|
69
|
+
configured: false
|
|
70
|
+
} : {
|
|
71
|
+
projectId: "",
|
|
72
|
+
mode: "ask_before_action",
|
|
73
|
+
allowedActions: [],
|
|
74
|
+
confidenceThreshold: 0,
|
|
75
|
+
scenarios: [],
|
|
76
|
+
configured: false
|
|
77
|
+
};
|
|
78
|
+
const action = row.proposed_action_json ? JSON.parse(String(row.proposed_action_json)) : void 0;
|
|
79
|
+
const dispositionInput = {
|
|
80
|
+
confidence: Number(row.confidence),
|
|
81
|
+
valueScore: Number(row.value_score),
|
|
82
|
+
risk: action?.risk ?? "low",
|
|
83
|
+
...action ? { actionId: action.id } : {},
|
|
84
|
+
requiresApproval: !action && Boolean(row.decision_json)
|
|
85
|
+
};
|
|
86
|
+
const disposition = action && !projectId ? "show_in_work" : decideProactiveDisposition(policy, dispositionInput);
|
|
87
|
+
const reason = action && !projectId ? "Proposed project action cannot run outside a project scope" : proactiveDispositionReason(policy, dispositionInput, disposition);
|
|
88
|
+
const actionStatus = action ? disposition === "auto_execute" ? "pending" : disposition === "request_approval" ? "approval_required" : disposition === "show_in_work" ? "not_authorized" : null : null;
|
|
45
89
|
const nowIso = now.toISOString();
|
|
90
|
+
db.prepare(`UPDATE proactive_insights SET disposition = ?, disposition_reason = ?, action_status = ?,
|
|
91
|
+
disposition_at = ?, action_updated_at = ? WHERE insight_id = ? AND disposition IS NULL`).run(disposition, reason, actionStatus, nowIso, actionStatus ? nowIso : null, String(row.insight_id));
|
|
92
|
+
if (disposition === "record_silently") continue;
|
|
93
|
+
const id = randomUUID();
|
|
46
94
|
db.prepare(`INSERT INTO proactive_inbox_items (inbox_item_id, insight_id, status, created_at, updated_at)
|
|
47
|
-
VALUES (?, ?, 'unread', ?, ?)`).run(id, row.insight_id, nowIso, nowIso);
|
|
95
|
+
VALUES (?, ?, 'unread', ?, ?)`).run(id, String(row.insight_id), nowIso, nowIso);
|
|
96
|
+
const nextAttemptAt = nextQuietHoursEnd(policy.quietHours, now)?.toISOString() ?? nowIso;
|
|
48
97
|
db.prepare(`INSERT INTO proactive_delivery_outbox (delivery_id, inbox_item_id, status, attempt, next_attempt_at, created_at, updated_at)
|
|
49
|
-
VALUES (?, ?, 'pending', 0, ?, ?, ?)`).run(randomUUID(), id,
|
|
98
|
+
VALUES (?, ?, 'pending', 0, ?, ?, ?)`).run(randomUUID(), id, nextAttemptAt, nowIso, nowIso);
|
|
99
|
+
projected += 1;
|
|
50
100
|
}
|
|
51
|
-
return
|
|
101
|
+
return projected;
|
|
52
102
|
});
|
|
53
103
|
}
|
|
54
104
|
function wakeSnoozedItems(now = /* @__PURE__ */ new Date()) {
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { listInbox, projectInsightsToInbox,
|
|
1
|
+
import { listInbox, projectInsightsToInbox, recordFeedback, wakeSnoozedItems } from './repository.js';
|
|
2
2
|
import type { InboxStatus } from './types.js';
|
|
3
3
|
export declare class ProactiveInboxService {
|
|
4
4
|
list: typeof listInbox;
|
|
5
5
|
project: typeof projectInsightsToInbox;
|
|
6
6
|
wakeSnoozed: typeof wakeSnoozedItems;
|
|
7
|
-
decide: typeof recordDecision;
|
|
8
7
|
feedback: typeof recordFeedback;
|
|
8
|
+
decide(id: string, choice: string, note?: string): import("./types.js").InboxItem;
|
|
9
9
|
instruct(id: string, instruction: string): {
|
|
10
10
|
revisionId: string;
|
|
11
11
|
};
|
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
import { publishInstructionFeedback } from "../scenarios/repository.js";
|
|
2
|
-
import {
|
|
2
|
+
import { resolveProactiveActionDecision } from "../actions/service.js";
|
|
3
|
+
import { getInboxItem, getInboxSubscriptionId, listInbox, projectInsightsToInbox, recordDecision, recordFeedback, transitionInboxItem, wakeSnoozedItems } from "./repository.js";
|
|
3
4
|
//#region src/proactive/inbox/service.ts
|
|
4
5
|
var ProactiveInboxService = class {
|
|
5
6
|
list = listInbox;
|
|
6
7
|
project = projectInsightsToInbox;
|
|
7
8
|
wakeSnoozed = wakeSnoozedItems;
|
|
8
|
-
decide = recordDecision;
|
|
9
9
|
feedback = recordFeedback;
|
|
10
|
+
decide(id, choice, note = "") {
|
|
11
|
+
const item = recordDecision(id, choice, note);
|
|
12
|
+
resolveProactiveActionDecision(id, choice);
|
|
13
|
+
return getInboxItem(id) ?? item;
|
|
14
|
+
}
|
|
10
15
|
instruct(id, instruction) {
|
|
11
16
|
return { revisionId: publishInstructionFeedback({
|
|
12
17
|
subscriptionId: getInboxSubscriptionId(id),
|
|
@@ -23,6 +23,20 @@ export interface InboxItem {
|
|
|
23
23
|
consequence: string;
|
|
24
24
|
}>;
|
|
25
25
|
};
|
|
26
|
+
proposedAction?: {
|
|
27
|
+
id: 'create_project_task';
|
|
28
|
+
risk: 'low';
|
|
29
|
+
rationale: string;
|
|
30
|
+
input: {
|
|
31
|
+
title: string;
|
|
32
|
+
objective: string;
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
disposition: 'show_in_work' | 'request_approval' | 'auto_execute';
|
|
36
|
+
dispositionReason: string;
|
|
37
|
+
actionStatus?: 'not_authorized' | 'approval_required' | 'pending' | 'executing' | 'completed' | 'rejected' | 'failed';
|
|
38
|
+
actionResult?: Record<string, unknown>;
|
|
39
|
+
actionError?: string;
|
|
26
40
|
urgency: 'low' | 'medium' | 'high' | 'critical';
|
|
27
41
|
confidence: number;
|
|
28
42
|
valueScore: number;
|