@xopcai/xopc 0.0.196 → 0.0.199
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-B1oxPli_.js → agent-avatar-dicebear-Bt70bZjv.js} +1 -1
- package/dist/gateway/static/root/assets/agents-D19uNmJf.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-B4x7JfL8.js +1 -0
- package/dist/gateway/static/root/assets/appearance-settings-Dwdagf-Q.js +1 -0
- package/dist/gateway/static/root/assets/apps-page-DkTiesxe.js +1 -0
- package/dist/gateway/static/root/assets/{archive-plugin-BdE4Mati.js → archive-plugin-Cv0VXKLm.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-CTzaQcLV.js → attachment-load-CgidKrXn.js} +1 -1
- package/dist/gateway/static/root/assets/automations-page-BR6qMOVr.js +6 -0
- package/dist/gateway/static/root/assets/{binary-plugins-B25zTNxl.js → binary-plugins-DN3CQgIq.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-Cdrf2awF.js → block-editor-BwkSl1F_.js} +46 -46
- package/dist/gateway/static/root/assets/browser-settings-page-CDFQWAxI.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-Wx9FrbK-.js → browser-workflows-page-C_I31wLm.js} +2 -2
- package/dist/gateway/static/root/assets/button-CSEbl4zT.js +1 -0
- package/dist/gateway/static/root/assets/capabilities-settings-panel-D41mssOq.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-BXgCyuu2.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-DV5BhAeu.js +1 -0
- package/dist/gateway/static/root/assets/channels-status-swr-B4Rbh3bM.js +1 -0
- package/dist/gateway/static/root/assets/connectors-api-5FEBYguL.js +1 -0
- package/dist/gateway/static/root/assets/connectors-page-C_qkEN0T.js +2 -0
- package/dist/gateway/static/root/assets/copy-Dv6d4Dvw.js +1 -0
- package/dist/gateway/static/root/assets/cron-expression-SEFx5rnr.js +2 -0
- package/dist/gateway/static/root/assets/date-picker-D4zCUQJL.js +1 -0
- package/dist/gateway/static/root/assets/dependency-picker-DpQAxS2k.js +1 -0
- package/dist/gateway/static/root/assets/{desktop-pet-BOb8sEhN.js → desktop-pet-B_5G3lQl.js} +1 -1
- package/dist/gateway/static/root/assets/desktop-pet-settings-ClEyoUJe.js +1 -0
- package/dist/gateway/static/root/assets/directory-picker-path-field-AsFWmOjG.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-p83TmZFd.js → extension-debug-page-C22Y2o5l.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-DMQ3ovxA.js → extension-page-C61Ikawk.js} +1 -1
- package/dist/gateway/static/root/assets/extension-settings-page-WlWWcDFr.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-ByIOMQdc.js +1 -0
- package/dist/gateway/static/root/assets/gateway-config-swr-jB0hAhWO.js +1 -0
- package/dist/gateway/static/root/assets/gateway-settings-CzzS9A17.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-B4A_CXUL.js +1 -0
- package/dist/gateway/static/root/assets/home-page-FVGYYPWo.js +3 -0
- package/dist/gateway/static/root/assets/index-CGbKTCST.js +152 -0
- package/dist/gateway/static/root/assets/index-CR233S0Q.css +1 -0
- package/dist/gateway/static/root/assets/interaction-BmQogeqz.js +1 -0
- package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-BQb06_jl.js → keyboard-shortcuts-settings-BD_TFz0_.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-BNpkigNb.js +2 -0
- package/dist/gateway/static/root/assets/local-apps-page-BwbUeLfm.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-DXP9OQQt.js +2 -0
- package/dist/gateway/static/root/assets/management-settings-CW2VpqtT.js +1 -0
- package/dist/gateway/static/root/assets/{markdown-split-Db-KrpOQ.js → markdown-split-B1M9KO16.js} +1 -1
- package/dist/gateway/static/root/assets/{media-plugins-CHN66qs0.js → media-plugins-B_QlNdqZ.js} +1 -1
- package/dist/gateway/static/root/assets/messages-3qRsLZuX.js +3 -0
- package/dist/gateway/static/root/assets/{notes-page-CJtKZM0P.js → notes-page-BTbD4GmH.js} +1 -1
- package/dist/gateway/static/root/assets/notes-workbench-JRiq7QDW.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-CeqtArlZ.js +1 -0
- package/dist/gateway/static/root/assets/{product-open-page--RnCc9bb.js → product-open-page-DnalBZZs.js} +1 -1
- package/dist/gateway/static/root/assets/project-detail-page-CjWA13aE.js +1 -0
- package/dist/gateway/static/root/assets/projects-page-jsCkScbG.js +1 -0
- package/dist/gateway/static/root/assets/remote-access-hub-CGPJTEkM.js +1 -0
- package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-Bg1W2__k.js → runtime-tools-settings-panel-cGkBEfg4.js} +4 -4
- package/dist/gateway/static/root/assets/schema-form-CmsrLlxu.js +1 -0
- package/dist/gateway/static/root/assets/sessions-page-BBHzziMd.js +1 -0
- package/dist/gateway/static/root/assets/settings-advanced-gate-2cGg8-9h.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-DUWCbaMJ.js +1 -0
- package/dist/gateway/static/root/assets/{settings-loading-skeleton-BS36Mjzz.js → settings-loading-skeleton-Bvy5rdMY.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-BDSd7F9Y.js → settings-page-cZSAwsRR.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-Cf06b66-.js +1 -0
- package/dist/gateway/static/root/assets/share-preview-page-BzA2NCAH.js +2 -0
- package/dist/gateway/static/root/assets/shares-settings-xlNKydYY.js +1 -0
- package/dist/gateway/static/root/assets/skill-reload-api-C5Xu93c_.js +1 -0
- package/dist/gateway/static/root/assets/skills-page-Bvde7_i5.js +2 -0
- package/dist/gateway/static/root/assets/{skills-page.utils-CnbJncdL.js → skills-page.utils-vXSqHR7g.js} +1 -1
- package/dist/gateway/static/root/assets/system-settings-panel-9cQGOGCK.js +1 -0
- package/dist/gateway/static/root/assets/task-detail-page-Bkno4tTe.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-7XfKULPI.js +1 -0
- package/dist/gateway/static/root/assets/user-context-page-CZ9m9aC_.js +1 -0
- package/dist/gateway/static/root/assets/voice-api-key-field-DXr21v-3.js +1 -0
- package/dist/gateway/static/root/assets/work-discovery-overlay-CeG7g_DZ.js +1 -0
- package/dist/gateway/static/root/assets/work-discovery-page-CQWZD03N.js +1 -0
- package/dist/gateway/static/root/assets/{workflow-run-setup-panel-BEmugHfL.js → workflow-run-setup-panel-DSQQZP9T.js} +2 -2
- package/dist/gateway/static/root/assets/workflows-page-Cs-MXFJ1.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 +54 -2
- package/dist/src/agent/agent-manager.d.ts +1 -0
- package/dist/src/agent/agent-manager.js +1 -0
- package/dist/src/agent/embedded/execution-context.d.ts +2 -0
- package/dist/src/agent/embedded/execution-context.js +11 -0
- package/dist/src/agent/embedded/index.d.ts +3 -1
- package/dist/src/agent/embedded/index.js +5 -3
- package/dist/src/agent/embedded/run-turn.js +15 -9
- package/dist/src/agent/embedded/session-runner.d.ts +6 -11
- package/dist/src/agent/embedded/session-runner.js +25 -36
- package/dist/src/agent/embedded/transcript-runtime.d.ts +35 -0
- package/dist/src/agent/embedded/transcript-runtime.js +66 -0
- package/dist/src/agent/embedded/types.d.ts +3 -1
- package/dist/src/agent/service.d.ts +15 -0
- package/dist/src/agent/service.js +31 -0
- package/dist/src/agent/service.types.d.ts +1 -0
- 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 +56 -6
- package/dist/src/automations/domain/validation.d.ts +40 -0
- package/dist/src/automations/draft/automation-draft-validator.d.ts +4 -1
- package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
- package/dist/src/config/agent-profile.js +1 -1
- package/dist/src/config/rules.js +2 -2
- package/dist/src/gateway/agents-admin.js +1 -1
- 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/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/home.d.ts +1 -1
- package/dist/src/gateway/hono/routes/home.js +2 -2
- package/dist/src/gateway/hono/routes/index.js +2 -0
- package/dist/src/gateway/hono/routes/projects.js +67 -1
- package/dist/src/gateway/hono/routes/side-chats.d.ts +3 -0
- package/dist/src/gateway/hono/routes/side-chats.js +173 -0
- package/dist/src/gateway/hono/routes/tasks.js +112 -19
- 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/agent-runner.d.ts +4 -0
- package/dist/src/gateway/service/agent-runner.js +15 -1
- package/dist/src/gateway/service/run-gateway-agent.js +1 -1
- package/dist/src/gateway/service.d.ts +5 -0
- package/dist/src/gateway/service.js +38 -8
- package/dist/src/gateway/side-chat/context-snapshot.d.ts +11 -0
- package/dist/src/gateway/side-chat/context-snapshot.js +108 -0
- package/dist/src/gateway/side-chat/index.d.ts +5 -0
- package/dist/src/gateway/side-chat/index.js +4 -0
- package/dist/src/gateway/side-chat/manager.d.ts +45 -0
- package/dist/src/gateway/side-chat/manager.js +198 -0
- package/dist/src/gateway/side-chat/run-service.d.ts +22 -0
- package/dist/src/gateway/side-chat/run-service.js +110 -0
- package/dist/src/gateway/side-chat/types.d.ts +61 -0
- package/dist/src/gateway/side-chat/types.js +1 -0
- 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/routing/session-key-utils.d.ts +0 -1
- package/dist/src/routing/session-key-utils.js +1 -6
- package/dist/src/routing/session-key.js +2 -2
- 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/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.d.ts +29 -0
- package/dist/src/tasks/home-query-service.js +291 -7
- package/dist/src/tasks/index.d.ts +1 -0
- package/dist/src/tasks/index.js +5 -4
- 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 +2 -2
- package/dist/src/tasks/project-operating-view-service.js +47 -21
- package/dist/src/tasks/task-application-service.js +99 -6
- 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-read-model-projector.js +2 -1
- package/dist/src/tasks/task-repository.d.ts +7 -0
- package/dist/src/tasks/task-repository.js +29 -6
- 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/package.json +4 -2
- package/dist/gateway/static/root/assets/agents-VoFNMGL3.js +0 -68
- package/dist/gateway/static/root/assets/app-management-settings-panel-vmuJ_Z6i.js +0 -1
- package/dist/gateway/static/root/assets/appearance-settings-BMlEoe-G.js +0 -1
- package/dist/gateway/static/root/assets/apps-page-CsNB6mv_.js +0 -1
- package/dist/gateway/static/root/assets/automations-page-CW1YWgiX.js +0 -6
- package/dist/gateway/static/root/assets/browser-settings-page-BMTmGMM6.js +0 -8
- package/dist/gateway/static/root/assets/browser-workflow-inputs-BsmHy0ks.js +0 -1
- package/dist/gateway/static/root/assets/capabilities-settings-panel-C5l85__e.js +0 -7
- package/dist/gateway/static/root/assets/capability-presets-settings-panel-9T2KXAs1.js +0 -3
- package/dist/gateway/static/root/assets/channels-settings-DquD4BPQ.js +0 -1
- package/dist/gateway/static/root/assets/channels-status-swr-DPaJSYX_.js +0 -1
- package/dist/gateway/static/root/assets/connectors-api-BC-4ftOM.js +0 -1
- package/dist/gateway/static/root/assets/connectors-page-7zUxVHQg.js +0 -2
- package/dist/gateway/static/root/assets/cron-expression-BycQlU8Q.js +0 -2
- package/dist/gateway/static/root/assets/dependency-picker-BvYqHRz0.js +0 -1
- package/dist/gateway/static/root/assets/desktop-pet-settings-DStgPb82.js +0 -1
- package/dist/gateway/static/root/assets/directory-picker-path-field-DUUr9sq0.js +0 -1
- package/dist/gateway/static/root/assets/extension-settings-page-BcSKEU8s.js +0 -1
- package/dist/gateway/static/root/assets/gateway-config-api-C-MmtCc7.js +0 -1
- package/dist/gateway/static/root/assets/gateway-settings-CuaRDWbg.js +0 -1
- package/dist/gateway/static/root/assets/heartbeat-settings-Dm8TrfGa.js +0 -1
- package/dist/gateway/static/root/assets/home-page-BYhDbUvI.js +0 -3
- package/dist/gateway/static/root/assets/index-BzPwnXho.js +0 -150
- package/dist/gateway/static/root/assets/index-CFFYvilx.css +0 -1
- package/dist/gateway/static/root/assets/local-app-workbench-page-CHk4x0kR.js +0 -2
- package/dist/gateway/static/root/assets/local-apps-page-DQtsxjGs.js +0 -1
- package/dist/gateway/static/root/assets/logs-page-CDqIY72S.js +0 -2
- package/dist/gateway/static/root/assets/management-settings-D7itDEHl.js +0 -1
- package/dist/gateway/static/root/assets/messages-DQ5X6cXp.js +0 -3
- package/dist/gateway/static/root/assets/notes-workbench-epHGeKd5.js +0 -4
- package/dist/gateway/static/root/assets/page-tabs-HXweXqYE.js +0 -1
- package/dist/gateway/static/root/assets/preview-open-alternatives-Dob6Oe2l.js +0 -1
- package/dist/gateway/static/root/assets/project-detail-page-BxOD5-zj.js +0 -1
- package/dist/gateway/static/root/assets/projects-page-D-9AhrH5.js +0 -1
- package/dist/gateway/static/root/assets/remote-access-hub-CSUNXLKM.js +0 -1
- package/dist/gateway/static/root/assets/schema-form-BI4rVt3u.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-BxOUBMca.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-DAvTIbgw.js +0 -1
- package/dist/gateway/static/root/assets/settings-form-section-C7rzhi7x.js +0 -1
- package/dist/gateway/static/root/assets/settings-page-layout-CTMmZcwj.js +0 -1
- package/dist/gateway/static/root/assets/setup-status-panel-D1v-2Ci-.js +0 -1
- package/dist/gateway/static/root/assets/share-preview-page-BeCxg6eb.js +0 -2
- package/dist/gateway/static/root/assets/shares-settings-CXL1EldF.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-BxwkKgVw.js +0 -1
- package/dist/gateway/static/root/assets/skills-page-CyfjEM4D.js +0 -2
- package/dist/gateway/static/root/assets/system-settings-panel-CAv0Yk0Y.js +0 -1
- package/dist/gateway/static/root/assets/task-detail-page-DGTVJs_N.js +0 -1
- package/dist/gateway/static/root/assets/typed-models-lib-DomX3Szl.js +0 -1
- package/dist/gateway/static/root/assets/use-autosave-BLc4gfG0.js +0 -1
- package/dist/gateway/static/root/assets/user-context-page-C2kQENTK.js +0 -1
- package/dist/gateway/static/root/assets/voice-api-key-field-BijmpPjb.js +0 -1
- package/dist/gateway/static/root/assets/work-discovery-overlay-D7w2JFFq.js +0 -1
- package/dist/gateway/static/root/assets/work-discovery-page-XtoPgPUS.js +0 -1
- package/dist/gateway/static/root/assets/workflows-page-D_K2xOWq.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,110 @@
|
|
|
1
|
+
import { createLogger } from "../../utils/logger/index.js";
|
|
2
|
+
import { init_logger } from "../../utils/logger.js";
|
|
3
|
+
import { abortEmbeddedRun } from "../../agent/embedded/runs.js";
|
|
4
|
+
import { SideChatError } from "./manager.js";
|
|
5
|
+
import { ChatStreamMapper } from "../chat-stream/mapper.js";
|
|
6
|
+
import { randomUUID } from "node:crypto";
|
|
7
|
+
//#region src/gateway/side-chat/run-service.ts
|
|
8
|
+
init_logger();
|
|
9
|
+
const log = createLogger("Gateway:SideChatRun");
|
|
10
|
+
var SideChatRunService = class {
|
|
11
|
+
activeBySideChat = /* @__PURE__ */ new Map();
|
|
12
|
+
constructor(options) {
|
|
13
|
+
this.options = options;
|
|
14
|
+
}
|
|
15
|
+
submit(sideChatId, clientInstanceId, content) {
|
|
16
|
+
const text = content.trim();
|
|
17
|
+
if (!text) throw new SideChatError("content is required", "INVALID_REQUEST");
|
|
18
|
+
const sideChat = this.options.manager.get(sideChatId, clientInstanceId);
|
|
19
|
+
if (this.activeBySideChat.has(sideChatId)) throw new SideChatError("A side chat run is already active", "CONFLICT");
|
|
20
|
+
const run = {
|
|
21
|
+
sideChatId,
|
|
22
|
+
clientInstanceId,
|
|
23
|
+
executionSessionKey: this.options.manager.getRuntime(sideChatId, clientInstanceId).runtimeId,
|
|
24
|
+
runId: randomUUID(),
|
|
25
|
+
abortController: new AbortController()
|
|
26
|
+
};
|
|
27
|
+
this.activeBySideChat.set(sideChatId, run);
|
|
28
|
+
this.options.manager.setStatus(sideChatId, clientInstanceId, "running");
|
|
29
|
+
this.execute(run, text, sideChat.config).catch((err) => {
|
|
30
|
+
log.error({
|
|
31
|
+
err,
|
|
32
|
+
sideChatId,
|
|
33
|
+
runId: run.runId
|
|
34
|
+
}, "Side chat run cleanup failed");
|
|
35
|
+
});
|
|
36
|
+
return { runId: run.runId };
|
|
37
|
+
}
|
|
38
|
+
async abort(sideChatId, clientInstanceId, runId) {
|
|
39
|
+
this.options.manager.get(sideChatId, clientInstanceId);
|
|
40
|
+
const active = this.activeBySideChat.get(sideChatId);
|
|
41
|
+
if (!active || runId && active.runId !== runId) return false;
|
|
42
|
+
this.options.agentRunner.cancelClarificationForRun(active.runId);
|
|
43
|
+
active.abortController.abort();
|
|
44
|
+
await abortEmbeddedRun(active.executionSessionKey).catch(() => false);
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
async dispose(sideChatId, clientInstanceId) {
|
|
48
|
+
await this.abort(sideChatId, clientInstanceId).catch(() => false);
|
|
49
|
+
return this.options.manager.dispose(sideChatId, clientInstanceId);
|
|
50
|
+
}
|
|
51
|
+
submitClarification(sideChatId, clientInstanceId, requestId, answer) {
|
|
52
|
+
this.options.manager.get(sideChatId, clientInstanceId);
|
|
53
|
+
return this.options.agentRunner.submitClarifyResponse(requestId, answer);
|
|
54
|
+
}
|
|
55
|
+
async execute(run, content, config) {
|
|
56
|
+
const topic = `run:${run.runId}`;
|
|
57
|
+
const mapper = new ChatStreamMapper({
|
|
58
|
+
runId: run.runId,
|
|
59
|
+
sessionKey: run.sideChatId,
|
|
60
|
+
channel: "side-chat"
|
|
61
|
+
});
|
|
62
|
+
const publish = (event) => {
|
|
63
|
+
this.options.publishRealtime(topic, event.type, event);
|
|
64
|
+
};
|
|
65
|
+
const publishMapped = (event) => {
|
|
66
|
+
for (const mapped of mapper.map(event)) publish(mapped);
|
|
67
|
+
};
|
|
68
|
+
try {
|
|
69
|
+
for (const event of mapper.start()) publish(event);
|
|
70
|
+
publishMapped({
|
|
71
|
+
type: "user_message",
|
|
72
|
+
message: {
|
|
73
|
+
role: "user",
|
|
74
|
+
content,
|
|
75
|
+
timestamp: Date.now()
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
this.options.agentRunner.registerExternalWebchatRun(run.executionSessionKey, run.runId, (event) => publishMapped(event));
|
|
79
|
+
const result = await this.options.getAgentService().runEphemeralTurn({
|
|
80
|
+
executionSessionKey: run.executionSessionKey,
|
|
81
|
+
parentSessionKey: this.options.manager.get(run.sideChatId, run.clientInstanceId).parentSessionKey,
|
|
82
|
+
runId: run.runId,
|
|
83
|
+
content,
|
|
84
|
+
modelRef: config.modelRef,
|
|
85
|
+
thinkingLevel: config.thinkingLevel,
|
|
86
|
+
transcriptRuntime: this.options.manager.getRuntime(run.sideChatId, run.clientInstanceId),
|
|
87
|
+
abortSignal: run.abortController.signal,
|
|
88
|
+
onEvent: publishMapped
|
|
89
|
+
});
|
|
90
|
+
const cancelled = run.abortController.signal.aborted;
|
|
91
|
+
const status = cancelled ? "cancelled" : result.ok ? "success" : "error";
|
|
92
|
+
if (!result.ok && result.errorMessage) for (const event of mapper.error(result.errorMessage)) publish(event);
|
|
93
|
+
for (const event of mapper.end(status, cancelled ? "Interrupted" : result.errorMessage)) publish(event);
|
|
94
|
+
} catch (error) {
|
|
95
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
96
|
+
for (const event of mapper.error(message)) publish(event);
|
|
97
|
+
for (const event of mapper.end("error", message)) publish(event);
|
|
98
|
+
} finally {
|
|
99
|
+
this.options.agentRunner.unregisterExternalWebchatRun(run.executionSessionKey, run.runId);
|
|
100
|
+
this.activeBySideChat.delete(run.sideChatId);
|
|
101
|
+
try {
|
|
102
|
+
this.options.manager.getMessages(run.sideChatId, run.clientInstanceId);
|
|
103
|
+
this.options.manager.setStatus(run.sideChatId, run.clientInstanceId, "idle");
|
|
104
|
+
} catch {}
|
|
105
|
+
this.options.completeRealtimeTopic(topic);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
//#endregion
|
|
110
|
+
export { SideChatRunService };
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { ThinkingLevel } from '@earendil-works/pi-agent-core';
|
|
2
|
+
export type SideChatStatus = 'idle' | 'running' | 'waiting-approval' | 'waiting-input' | 'closing';
|
|
3
|
+
export type SideChatSelection = {
|
|
4
|
+
id: string;
|
|
5
|
+
type: 'message';
|
|
6
|
+
messageId: string;
|
|
7
|
+
role: string;
|
|
8
|
+
content: string;
|
|
9
|
+
label?: string;
|
|
10
|
+
} | {
|
|
11
|
+
id: string;
|
|
12
|
+
type: 'text';
|
|
13
|
+
text: string;
|
|
14
|
+
sourceMessageId?: string;
|
|
15
|
+
label?: string;
|
|
16
|
+
} | {
|
|
17
|
+
id: string;
|
|
18
|
+
type: 'file-range';
|
|
19
|
+
path: string;
|
|
20
|
+
startLine: number;
|
|
21
|
+
endLine: number;
|
|
22
|
+
text: string;
|
|
23
|
+
contentHash?: string;
|
|
24
|
+
label?: string;
|
|
25
|
+
} | {
|
|
26
|
+
id: string;
|
|
27
|
+
type: 'diff';
|
|
28
|
+
diff: string;
|
|
29
|
+
path?: string;
|
|
30
|
+
label?: string;
|
|
31
|
+
};
|
|
32
|
+
export interface SideChatContextSnapshot {
|
|
33
|
+
parentSessionKey: string;
|
|
34
|
+
parentSessionId: string;
|
|
35
|
+
parentMessageCount: number;
|
|
36
|
+
createdAt: string;
|
|
37
|
+
selections: SideChatSelection[];
|
|
38
|
+
contentHash: string;
|
|
39
|
+
}
|
|
40
|
+
export interface SideChatConfig {
|
|
41
|
+
modelRef: string;
|
|
42
|
+
thinkingLevel?: ThinkingLevel;
|
|
43
|
+
}
|
|
44
|
+
export interface SideChatView {
|
|
45
|
+
id: string;
|
|
46
|
+
parentSessionKey: string;
|
|
47
|
+
clientInstanceId: string;
|
|
48
|
+
status: SideChatStatus;
|
|
49
|
+
createdAt: string;
|
|
50
|
+
lastActiveAt: string;
|
|
51
|
+
expiresAt: string;
|
|
52
|
+
messageCount: number;
|
|
53
|
+
context: SideChatContextSnapshot;
|
|
54
|
+
config: SideChatConfig;
|
|
55
|
+
}
|
|
56
|
+
export interface CreateSideChatInput {
|
|
57
|
+
parentSessionKey: string;
|
|
58
|
+
clientInstanceId: string;
|
|
59
|
+
selections?: SideChatSelection[];
|
|
60
|
+
config?: Partial<SideChatConfig>;
|
|
61
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -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;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createLogger } from "../../utils/logger/index.js";
|
|
2
2
|
import { init_logger } from "../../utils/logger.js";
|
|
3
|
+
import { executePendingProactiveActions } from "../actions/service.js";
|
|
3
4
|
import { claimDelivery, finishDelivery, projectInsightsToInbox, recoverExpiredDeliveries, wakeSnoozedItems } from "./repository.js";
|
|
4
5
|
//#region src/proactive/inbox/worker.ts
|
|
5
6
|
init_logger();
|
|
@@ -28,6 +29,7 @@ var ProactiveInboxWorker = class {
|
|
|
28
29
|
this.running = true;
|
|
29
30
|
try {
|
|
30
31
|
projectInsightsToInbox();
|
|
32
|
+
executePendingProactiveActions();
|
|
31
33
|
wakeSnoozedItems();
|
|
32
34
|
recoverExpiredDeliveries();
|
|
33
35
|
const claim = claimDelivery();
|
|
@@ -5,8 +5,8 @@ Use only supplied evidence identifiers. Separate observations from inferences.
|
|
|
5
5
|
Do not invent dates, owners, dependencies, impact, or actions.
|
|
6
6
|
Return only the protected output schema.`;
|
|
7
7
|
const OUTPUT_CONTRACT = `Return JSON only with these fields:
|
|
8
|
-
{"title":"...","summary":"...","whyNow":"...","impact":"...","workDone":"What you investigated or ruled out","recommendation":"...","decision":{"question":"The exact user decision","options":[{"id":"stable-id","label":"short choice","consequence":"likely consequence"}]},"urgency":"low|medium|high|critical","confidence":0.0,"evidenceIds":["event-id"]}
|
|
9
|
-
Use decision only when the user must choose; otherwise set decision to null. Provide 2-3 mutually exclusive options. If evidence does not support a timely and actionable insight, return the same shape with urgency "low" and confidence below 0.65. Never add unknown fields.`;
|
|
8
|
+
{"title":"...","summary":"...","whyNow":"...","impact":"...","workDone":"What you investigated or ruled out","recommendation":"...","decision":{"question":"The exact user decision","options":[{"id":"stable-id","label":"short choice","consequence":"likely consequence"}]},"proposedAction":{"id":"create_project_task","risk":"low","rationale":"why this is safe and useful","input":{"title":"...","objective":"..."}},"urgency":"low|medium|high|critical","confidence":0.0,"evidenceIds":["event-id"]}
|
|
9
|
+
Use proposedAction only when the evidence clearly supports creating a follow-up task in the current project; otherwise set it to null. A proposed action must include exactly two decision options in this order: approve, reject. Use decision without proposedAction only when the user must choose; otherwise set decision to null. Provide 2-3 mutually exclusive options. If evidence does not support a timely and actionable insight, return the same shape with urgency "low" and confidence below 0.65. Never add unknown fields.`;
|
|
10
10
|
function composeScenarioPrompt(input) {
|
|
11
11
|
const parts = {
|
|
12
12
|
platformSafety: PLATFORM_SAFETY,
|
|
@@ -14,7 +14,6 @@ export type RawSessionConversationRef = {
|
|
|
14
14
|
};
|
|
15
15
|
/** Parse `agent:{agentId}:{rest}` session keys (OpenClaw canonical form). */
|
|
16
16
|
export declare function parseAgentSessionKey(sessionKey: string | undefined | null): ParsedAgentSessionKey | null;
|
|
17
|
-
export declare function isCronRunSessionKey(sessionKey: string | undefined | null): boolean;
|
|
18
17
|
export declare function isCronSessionKey(sessionKey: string | undefined | null): boolean;
|
|
19
18
|
export declare function isSubagentSessionKey(sessionKey: string | undefined | null): boolean;
|
|
20
19
|
export declare function getSubagentDepth(sessionKey: string | undefined | null): number;
|
|
@@ -16,11 +16,6 @@ function parseAgentSessionKey(sessionKey) {
|
|
|
16
16
|
rest
|
|
17
17
|
};
|
|
18
18
|
}
|
|
19
|
-
function isCronRunSessionKey(sessionKey) {
|
|
20
|
-
const parsed = parseAgentSessionKey(sessionKey);
|
|
21
|
-
if (!parsed) return false;
|
|
22
|
-
return /^cron:[^:]+:run:[^:]+$/.test(parsed.rest);
|
|
23
|
-
}
|
|
24
19
|
function isCronSessionKey(sessionKey) {
|
|
25
20
|
const parsed = parseAgentSessionKey(sessionKey);
|
|
26
21
|
if (!parsed) return false;
|
|
@@ -87,4 +82,4 @@ var init_session_key_utils = __esmMin((() => {
|
|
|
87
82
|
}));
|
|
88
83
|
//#endregion
|
|
89
84
|
init_session_key_utils();
|
|
90
|
-
export { getSubagentDepth, init_session_key_utils, isAcpSessionKey,
|
|
85
|
+
export { getSubagentDepth, init_session_key_utils, isAcpSessionKey, isCronSessionKey, isSubagentSessionKey, parseAgentSessionKey, parseRawSessionConversationRef, parseThreadSessionSuffix, resolveThreadParentSessionKey };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { __esmMin } from "../../_virtual/_rolldown/runtime.js";
|
|
2
2
|
import { DEFAULT_ACCOUNT_ID, normalizeAccountId, normalizeOptionalAccountId } from "./account-id.js";
|
|
3
|
-
import { getSubagentDepth, init_session_key_utils, isAcpSessionKey,
|
|
3
|
+
import { getSubagentDepth, init_session_key_utils, isAcpSessionKey, isCronSessionKey, isSubagentSessionKey, parseAgentSessionKey, parseRawSessionConversationRef, parseThreadSessionSuffix, resolveThreadParentSessionKey } from "./session-key-utils.js";
|
|
4
4
|
import { DEFAULT_AGENT_ID, DEFAULT_MAIN_KEY, assertAgentSessionKey, buildAgentMainSessionKey, buildAgentPeerSessionKey, buildGroupHistoryKey, classifySessionKeyShape, defaultMainSessionKey, init_agent_session_key, isValidAgentId, normalizeAgentId, normalizeMainKey, normalizeSessionKey, resolveAgentIdFromSessionKey, resolveThreadSessionKeys, sanitizeAgentId, scopedHeartbeatWakeOptions, toAgentRequestSessionKey, toAgentStoreSessionKey } from "./agent-session-key.js";
|
|
5
5
|
//#region src/routing/session-key.ts
|
|
6
6
|
function sanitizeSegment(value, options) {
|
|
@@ -188,4 +188,4 @@ var init_session_key = __esmMin((() => {
|
|
|
188
188
|
}));
|
|
189
189
|
//#endregion
|
|
190
190
|
init_session_key();
|
|
191
|
-
export { DEFAULT_ACCOUNT_ID, DEFAULT_AGENT_ID, DEFAULT_MAIN_KEY, assertAgentSessionKey, buildAgentMainSessionKey, buildAgentPeerSessionKey, buildGroupHistoryKey, buildSessionKey, buildSubagentSessionKey, classifySessionKeyShape, defaultMainSessionKey, getParentSessionKey, getSubagentDepth, init_session_key, isAcpSessionKey,
|
|
191
|
+
export { DEFAULT_ACCOUNT_ID, DEFAULT_AGENT_ID, DEFAULT_MAIN_KEY, assertAgentSessionKey, buildAgentMainSessionKey, buildAgentPeerSessionKey, buildGroupHistoryKey, buildSessionKey, buildSubagentSessionKey, classifySessionKeyShape, defaultMainSessionKey, getParentSessionKey, getSubagentDepth, init_session_key, isAcpSessionKey, isCronSessionKey, isSubagentSessionKey, isValidAgentId, isValidSegment, normalizeAccountId, normalizeAgentId, normalizeMainKey, normalizeOptionalAccountId, normalizeSessionKey, parseAgentSessionKey, parseRawSessionConversationRef, parseSessionKey, parseThreadSessionSuffix, resolveAgentIdFromSessionKey, resolveThreadParentSessionKey, resolveThreadSessionKeys, sanitizeAgentId, sanitizeSegment, scopedHeartbeatWakeOptions, toAgentRequestSessionKey, toAgentStoreSessionKey };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
ALTER TABLE proactive_insights ADD COLUMN proposed_action_json TEXT;
|
|
2
|
+
ALTER TABLE proactive_insights ADD COLUMN disposition TEXT
|
|
3
|
+
CHECK (disposition IN ('record_silently', 'show_in_work', 'request_approval', 'auto_execute'));
|
|
4
|
+
ALTER TABLE proactive_insights ADD COLUMN disposition_reason TEXT;
|
|
5
|
+
ALTER TABLE proactive_insights ADD COLUMN action_status TEXT
|
|
6
|
+
CHECK (action_status IN ('not_authorized', 'approval_required', 'pending', 'executing', 'completed', 'rejected', 'failed'));
|
|
7
|
+
ALTER TABLE proactive_insights ADD COLUMN action_result_json TEXT;
|
|
8
|
+
ALTER TABLE proactive_insights ADD COLUMN action_error TEXT;
|
|
9
|
+
ALTER TABLE proactive_insights ADD COLUMN disposition_at TEXT;
|
|
10
|
+
ALTER TABLE proactive_insights ADD COLUMN action_updated_at TEXT;
|
|
11
|
+
|
|
12
|
+
CREATE INDEX idx_proactive_insights_action_status
|
|
13
|
+
ON proactive_insights(action_status, created_at);
|
|
@@ -3,7 +3,7 @@ import type { ApplyMigrationsOptions } from './types.js';
|
|
|
3
3
|
/** Baseline schema version applied from schema.sql on first open. */
|
|
4
4
|
export declare const XOPC_DB_BASELINE_SCHEMA_VERSION = 11;
|
|
5
5
|
/** Latest schema version this release supports (increment when adding migrations). */
|
|
6
|
-
export declare const XOPC_DB_SCHEMA_VERSION =
|
|
6
|
+
export declare const XOPC_DB_SCHEMA_VERSION = 119;
|
|
7
7
|
export declare function resolveMigrationsDir(override?: string): string;
|
|
8
8
|
/**
|
|
9
9
|
* Apply sequential SQL migrations from (currentVersion + 1) through targetVersion.
|
|
@@ -12,7 +12,7 @@ const log = createLogger("Sqlite:Migrations");
|
|
|
12
12
|
/** Baseline schema version applied from schema.sql on first open. */
|
|
13
13
|
const XOPC_DB_BASELINE_SCHEMA_VERSION = 11;
|
|
14
14
|
/** Latest schema version this release supports (increment when adding migrations). */
|
|
15
|
-
const XOPC_DB_SCHEMA_VERSION =
|
|
15
|
+
const XOPC_DB_SCHEMA_VERSION = 119;
|
|
16
16
|
const MODULE_DIR = dirname(fileURLToPath(import.meta.url));
|
|
17
17
|
function backupBeforeTaskCutover(db, databasePath) {
|
|
18
18
|
db.exec("PRAGMA wal_checkpoint(FULL)");
|
|
@@ -57,7 +57,7 @@ function applySingleMigration(db, migration) {
|
|
|
57
57
|
* Each step runs in its own transaction and updates schema_meta on success.
|
|
58
58
|
*/
|
|
59
59
|
function applyPendingMigrations(db, options = {}) {
|
|
60
|
-
const targetVersion = options.targetVersion ??
|
|
60
|
+
const targetVersion = options.targetVersion ?? 119;
|
|
61
61
|
let currentVersion = readSchemaVersion(db);
|
|
62
62
|
if (currentVersion > targetVersion) throw new DatabaseSchemaTooNewError(currentVersion, targetVersion);
|
|
63
63
|
if (currentVersion >= targetVersion) return currentVersion;
|
|
@@ -94,7 +94,7 @@ function applyPendingMigrations(db, options = {}) {
|
|
|
94
94
|
}
|
|
95
95
|
/** Inspect schema version without mutating the database. */
|
|
96
96
|
function inspectSchemaMigrationStatus(db, options = {}) {
|
|
97
|
-
const appVersion = options.targetVersion ??
|
|
97
|
+
const appVersion = options.targetVersion ?? 119;
|
|
98
98
|
const dbVersion = readSchemaVersion(db);
|
|
99
99
|
if (dbVersion > appVersion) return {
|
|
100
100
|
dbVersion,
|