@xopcai/xopc 0.0.160 → 0.0.162
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-hpcNv9MZ.js +1 -0
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-B_27aaZQ.js → agent-avatar-dicebear-Zf9UQEmQ.js} +1 -1
- package/dist/gateway/static/root/assets/agents-DfVkZlHc.js +2 -0
- package/dist/gateway/static/root/assets/{api-BbzB57CJ.js → api-Dnatri09.js} +1 -1
- package/dist/gateway/static/root/assets/{app-management-settings-panel-DfmyWcyh.js → app-management-settings-panel-BBTR9wJP.js} +1 -1
- package/dist/gateway/static/root/assets/{appearance-settings-B2v0c-K-.js → appearance-settings-C2zpLCHD.js} +1 -1
- package/dist/gateway/static/root/assets/apps-page-BMtAa4Ra.js +1 -0
- package/dist/gateway/static/root/assets/{archive-plugin-DL5Lnx0C.js → archive-plugin-9eR_ODY1.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-InuP-ZjQ.js → attachment-load-DPuWYUeX.js} +1 -1
- package/dist/gateway/static/root/assets/{automation-suggestion-card-CahGuh7B.js → automation-suggestion-card-Dw49OJRl.js} +1 -1
- package/dist/gateway/static/root/assets/automations-page-BiSAMYTr.js +6 -0
- package/dist/gateway/static/root/assets/{binary-plugins-CdOTGYVu.js → binary-plugins-BdkJpDFm.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-D6ShK1S-.js → block-editor-CAi7SXYU.js} +47 -47
- package/dist/gateway/static/root/assets/browser-settings-page-DHmaEJS2.js +8 -0
- package/dist/gateway/static/root/assets/browser-workflow-inputs-Dx6wkGz1.js +1 -0
- package/dist/gateway/static/root/assets/browser-workflows-page-Skertc-A.js +3 -0
- package/dist/gateway/static/root/assets/capabilities-settings-panel-B5wSgf4f.js +2 -0
- package/dist/gateway/static/root/assets/{capability-presets-api-BzoLm52Z.js → capability-presets-api-CNFl7dM3.js} +1 -1
- package/dist/gateway/static/root/assets/capability-presets-settings-panel-DyvFZwBj.js +2 -0
- package/dist/gateway/static/root/assets/{channel-recipient-api-DbgydMjl.js → channel-recipient-api-DYQyGDw4.js} +1 -1
- package/dist/gateway/static/root/assets/channels-settings-BBKEqDZn.js +1 -0
- package/dist/gateway/static/root/assets/channels-status-swr-Drk110ve.js +1 -0
- package/dist/gateway/static/root/assets/check-DUBLcKHA.js +1 -0
- package/dist/gateway/static/root/assets/circle-alert-BEjgurr2.js +1 -0
- package/dist/gateway/static/root/assets/cn-JdwAhgNB.js +1 -0
- package/dist/gateway/static/root/assets/{connector-logo-C3bJC9nt.js → connector-logo-Bng6kxYF.js} +1 -1
- package/dist/gateway/static/root/assets/connectors-page-HpgaUDQ1.js +2 -0
- package/dist/gateway/static/root/assets/createLucideIcon-DPHK1VkS.js +1 -0
- package/dist/gateway/static/root/assets/desktop-pet-Bpf6oegd.js +1 -0
- package/dist/gateway/static/root/assets/{desktop-pet-settings-BrHVvbBw.js → desktop-pet-settings-BVUyefSd.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-sprite-CFd1jGLJ.js → desktop-pet-sprite-DTqXSpqf.js} +1 -1
- package/dist/gateway/static/root/assets/{directory-picker-path-field-BPI969w-.js → directory-picker-path-field-DjSZAPz_.js} +1 -1
- package/dist/gateway/static/root/assets/{dreaming-settings-iw6QXD45.js → dreaming-settings-CAZk2AM4.js} +3 -3
- package/dist/gateway/static/root/assets/{extension-debug-page-rCHyhEr6.js → extension-debug-page-C2F6vTTd.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-C4gQsAPt.js → extension-page-AnIt4bn4.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-DB_3eik7.js → extension-settings-page-CLSc6682.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-api-Cdt38iF2.js → gateway-config-api-DLFyZv33.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-settings-DM4BgyGw.js → gateway-settings-DnQAA-qq.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-startup-retry-ChRFNjj_.js → gateway-startup-retry-DbzLyJ3R.js} +1 -1
- package/dist/gateway/static/root/assets/goal-create-dialog-DrnKFC6M.js +1 -0
- package/dist/gateway/static/root/assets/goal-detail-page-Cw1hpJkZ.js +4 -0
- package/dist/gateway/static/root/assets/{goals-config-api-RvljeEm6.js → goals-config-api-REmr3QCr.js} +1 -1
- package/dist/gateway/static/root/assets/goals-page-BDGkTVma.js +2 -0
- package/dist/gateway/static/root/assets/{goals-settings-DMGV4S4L.js → goals-settings-Dz0F3uRO.js} +1 -1
- package/dist/gateway/static/root/assets/{heartbeat-settings-B8r5EXc5.js → heartbeat-settings-CQFY5gYs.js} +1 -1
- package/dist/gateway/static/root/assets/index-C8JkTS6d.js +199 -0
- package/dist/gateway/static/root/assets/index-hmrG55qg.css +1 -0
- package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-1-LYibQ4.js → keyboard-shortcuts-settings-BnOQXU5k.js} +1 -1
- package/dist/gateway/static/root/assets/local-app-workbench-page-Bdef1b7F.js +2 -0
- package/dist/gateway/static/root/assets/{local-apps-page-CC4vtUUI.js → local-apps-page-KsOtWOyM.js} +1 -1
- package/dist/gateway/static/root/assets/{locale-store-CPbGB_6l.js → locale-store-0lpYdNDr.js} +1 -1
- package/dist/gateway/static/root/assets/{logs-page-Bn_taxBV.js → logs-page-CwLPgrWh.js} +3 -3
- package/dist/gateway/static/root/assets/{markdown-split-CprEIf8A.js → markdown-split-D5GRg10r.js} +1 -1
- package/dist/gateway/static/root/assets/{media-plugins-BXt_Sj2O.js → media-plugins-C1ryULGs.js} +1 -1
- package/dist/gateway/static/root/assets/messages-BwQ3WssU.js +5 -0
- package/dist/gateway/static/root/assets/{notes-page-Wf5-eyyM.js → notes-page-CIeZ1_DT.js} +1 -1
- package/dist/gateway/static/root/assets/notes-workbench-Cf06q19x.js +4 -0
- package/dist/gateway/static/root/assets/{page-tabs-dtpK_4Fs.js → page-tabs-Caj1-E_X.js} +1 -1
- package/dist/gateway/static/root/assets/{preview-open-alternatives-DijtEVxG.js → preview-open-alternatives-DKwEce-9.js} +1 -1
- package/dist/gateway/static/root/assets/product-delivery-BTRT9kCS.js +1 -0
- package/dist/gateway/static/root/assets/product-open-page-B90ZskkN.js +1 -0
- package/dist/gateway/static/root/assets/project-detail-page-SHTurM4t.js +1 -0
- package/dist/gateway/static/root/assets/projects-page-BcC2qUAw.js +1 -0
- package/dist/gateway/static/root/assets/remote-access-hub-6vGefBHv.js +1 -0
- package/dist/gateway/static/root/assets/save-bar-controls-BDYt53uQ.js +1 -0
- package/dist/gateway/static/root/assets/{schedule-field-AhJ50NoT.js → schedule-field-Bcdni4Pj.js} +1 -1
- package/dist/gateway/static/root/assets/{schema-form-AuJg2CXU.js → schema-form-D7oCARF7.js} +1 -1
- package/dist/gateway/static/root/assets/sessions-page-C5014a53.js +1 -0
- package/dist/gateway/static/root/assets/settings-advanced-gate-CDY3ZI1K.js +1 -0
- package/dist/gateway/static/root/assets/{settings-collapsible-section-D5ganr_X.js → settings-collapsible-section-6eNF8Jey.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-form-section-Db3cKRsg.js → settings-form-section-CARTHCxH.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-loading-skeleton-D05YKT2x.js → settings-loading-skeleton-DEwYqESe.js} +1 -1
- package/dist/gateway/static/root/assets/settings-page-B6vVdHeQ.js +1 -0
- package/dist/gateway/static/root/assets/{settings-page-layout-Cv_Cu4I5.js → settings-page-layout-D3srt5Bi.js} +1 -1
- package/dist/gateway/static/root/assets/setup-status-panel-z-rF0Hdg.js +1 -0
- package/dist/gateway/static/root/assets/{share-preview-page-CYkZVuse.js → share-preview-page-Ck9SxiXw.js} +1 -1
- package/dist/gateway/static/root/assets/shares-settings-CHZFXE_d.js +1 -0
- package/dist/gateway/static/root/assets/skill-reload-api-B7p2QNXt.js +1 -0
- package/dist/gateway/static/root/assets/skills-page-ncw3tX9P.js +2 -0
- package/dist/gateway/static/root/assets/{system-settings-panel-C1Ng5bXh.js → system-settings-panel-DLBUQSk2.js} +1 -1
- package/dist/gateway/static/root/assets/{theme-store-LMHIDR9n.js → theme-store-C1oaqeD2.js} +1 -1
- package/dist/gateway/static/root/assets/{typed-models-lib-Ch2Bdm_5.js → typed-models-lib-Divbg_C4.js} +1 -1
- package/dist/gateway/static/root/assets/{use-channel-catalog-CZnaMOeL.js → use-channel-catalog-CP9a_rAf.js} +1 -1
- package/dist/gateway/static/root/assets/user-context-page-iYfeSLKI.js +1 -0
- package/dist/gateway/static/root/assets/voice-api-key-field-CrwkicvT.js +1 -0
- package/dist/gateway/static/root/assets/work-discovery-page-BQWxyPg8.js +1 -0
- package/dist/gateway/static/root/assets/work-item-detail-page-50ZzGay5.js +1 -0
- package/dist/gateway/static/root/assets/work-page-DPqEahx7.js +1 -0
- package/dist/gateway/static/root/assets/{workflow-run-setup-panel-BFk8TvTw.js → workflow-run-setup-panel-DbDPYQwB.js} +2 -2
- package/dist/gateway/static/root/assets/workflows-page-C3eIC5HZ.js +11 -0
- package/dist/gateway/static/root/index.html +12 -10
- package/dist/package.js +1 -1
- package/dist/src/agent/agent-manager.d.ts +1 -0
- package/dist/src/agent/agent-manager.js +1 -0
- package/dist/src/agent/client-error-format.js +3 -3
- package/dist/src/agent/outcomes/task-evaluation.d.ts +20 -0
- package/dist/src/agent/outcomes/task-evaluation.js +48 -0
- package/dist/src/agent/outcomes/task-verifier.d.ts +29 -0
- package/dist/src/agent/outcomes/task-verifier.js +71 -0
- package/dist/src/agent/prompt/memory/index.js +1 -1
- package/dist/src/agent/prompt/service-prompt-builder.js +32 -1
- package/dist/src/agent/service.js +1 -0
- package/dist/src/agent/service.types.d.ts +1 -0
- package/dist/src/agent/tools/browser/tool/browser-use-tool.d.ts +1 -7
- package/dist/src/agent/tools/browser/tool/browser-use-tool.js +2 -73
- package/dist/src/agent/tools/browser/tool/schemas.d.ts +1 -13
- package/dist/src/agent/tools/browser/tool/schemas.js +1 -9
- package/dist/src/agent/tools/browser-recipe-tool.d.ts +12 -0
- package/dist/src/agent/tools/browser-recipe-tool.js +113 -0
- package/dist/src/agent/tools/factory.d.ts +2 -0
- package/dist/src/agent/tools/factory.js +2 -0
- package/dist/src/agent/tools/index.d.ts +1 -0
- package/dist/src/agent/tools/index.js +2 -1
- package/dist/src/automations/domain/types.d.ts +13 -0
- package/dist/src/automations/domain/validation.d.ts +44 -24
- package/dist/src/automations/domain/validation.js +27 -18
- package/dist/src/automations/draft/automation-draft-validator.d.ts +6 -1
- package/dist/src/automations/draft/automation-draft-validator.js +1 -0
- package/dist/src/automations/service/action-executor.d.ts +1 -0
- package/dist/src/automations/service/action-executor.js +22 -0
- package/dist/src/browser/index.d.ts +0 -1
- package/dist/src/browser/index.js +1 -2
- package/dist/src/browser/pipeline/runner.d.ts +9 -2
- package/dist/src/browser/pipeline/runner.js +151 -105
- package/dist/src/browser/pipeline/schema.d.ts +21 -15
- package/dist/src/browser/pipeline/schema.js +93 -99
- package/dist/src/browser/recipes/index.d.ts +3 -0
- package/dist/src/browser/recipes/index.js +3 -0
- package/dist/src/browser/recipes/repository.d.ts +13 -0
- package/dist/src/browser/recipes/repository.js +81 -0
- package/dist/src/browser/recipes/runtime-service.d.ts +6 -0
- package/dist/src/browser/recipes/runtime-service.js +30 -0
- package/dist/src/browser/recipes/service.d.ts +36 -0
- package/dist/src/browser/recipes/service.js +186 -0
- package/dist/src/browser/recipes/types.d.ts +36 -0
- package/dist/src/browser/recipes/types.js +1 -0
- package/dist/src/cli/commands/browser-cli-helpers.js +6 -12
- package/dist/src/cli/commands/browser.js +4 -3
- package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
- package/dist/src/config/schema.d.ts +3 -3
- package/dist/src/config/schema.js +21 -21
- package/dist/src/gateway/hono/lib/config-payload.d.ts +1 -1
- package/dist/src/gateway/hono/routes/browser-workflows.d.ts +3 -0
- package/dist/src/gateway/hono/routes/browser-workflows.js +78 -0
- package/dist/src/gateway/hono/routes/home.js +1 -0
- package/dist/src/gateway/hono/routes/index.js +4 -0
- package/dist/src/gateway/hono/routes/interaction-state.d.ts +3 -0
- package/dist/src/gateway/hono/routes/interaction-state.js +45 -0
- package/dist/src/gateway/hono/routes/lazy-bundles.js +8 -0
- package/dist/src/gateway/hono/routes/memory.js +33 -4
- package/dist/src/gateway/hono/routes/task-outcomes.d.ts +3 -0
- package/dist/src/gateway/hono/routes/task-outcomes.js +109 -0
- package/dist/src/gateway/hono/routes/you.d.ts +10 -2
- package/dist/src/gateway/hono/routes/you.js +184 -28
- package/dist/src/gateway/hono/sse.d.ts +2 -0
- package/dist/src/gateway/hono/sse.js +10 -3
- package/dist/src/gateway/run-loop.js +17 -7
- package/dist/src/gateway/server.d.ts +1 -0
- package/dist/src/gateway/server.js +9 -0
- package/dist/src/gateway/service/run-gateway-agent.js +84 -0
- package/dist/src/gateway/service.d.ts +3 -0
- package/dist/src/gateway/service.js +14 -0
- package/dist/src/local-apps/preview-runtime-bridge.d.ts +1 -1
- package/dist/src/local-apps/preview-runtime-bridge.js +14 -11
- package/dist/src/proactive/insight-repository.d.ts +2 -0
- package/dist/src/proactive/insight-repository.js +5 -2
- package/dist/src/proactive/run-processor.js +22 -1
- package/dist/src/proactive/types.d.ts +2 -0
- package/dist/src/proactive/value-score.d.ts +13 -0
- package/dist/src/proactive/value-score.js +30 -0
- package/dist/src/share/share-types.js +5 -5
- package/dist/src/share/site-share-types.d.ts +1 -1
- package/dist/src/share/site-share-types.js +5 -5
- package/dist/src/storage/sqlite/index.d.ts +3 -0
- package/dist/src/storage/sqlite/index.js +4 -1
- package/dist/src/storage/sqlite/interaction-state-repository.d.ts +17 -0
- package/dist/src/storage/sqlite/interaction-state-repository.js +60 -0
- package/dist/src/storage/sqlite/memory-records-repository.js +1 -1
- package/dist/src/storage/sqlite/migrations/053_browser_recipes.sql +45 -0
- package/dist/src/storage/sqlite/migrations/054_task_outcomes.sql +24 -0
- package/dist/src/storage/sqlite/migrations/055_relationship_settings.sql +14 -0
- package/dist/src/storage/sqlite/migrations/056_task_verification.sql +6 -0
- package/dist/src/storage/sqlite/migrations/057_interaction_states.sql +11 -0
- package/dist/src/storage/sqlite/migrations/058_proactive_value.sql +3 -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/relationship-settings-repository.d.ts +17 -0
- package/dist/src/storage/sqlite/relationship-settings-repository.js +64 -0
- package/dist/src/storage/sqlite/schema.js +1 -1
- package/dist/src/storage/sqlite/schema.sql +46 -0
- package/dist/src/storage/sqlite/task-outcome-repository.d.ts +90 -0
- package/dist/src/storage/sqlite/task-outcome-repository.js +138 -0
- package/dist/src/user-context/interaction-state.d.ts +13 -0
- package/dist/src/user-context/interaction-state.js +69 -0
- package/dist/src/user-context/memory-use-audit.d.ts +10 -0
- package/dist/src/user-context/memory-use-audit.js +25 -0
- package/dist/src/user-context/personal-playbook.d.ts +11 -0
- package/dist/src/user-context/personal-playbook.js +41 -0
- package/dist/src/user-context/projection.d.ts +4 -0
- package/dist/src/user-context/projection.js +5 -1
- package/dist/src/user-context/relationship-continuity.d.ts +14 -0
- package/dist/src/user-context/relationship-continuity.js +51 -0
- package/package.json +1 -1
- package/dist/gateway/static/root/assets/action-boundary-settings-panel-CY3sizqC.js +0 -1
- package/dist/gateway/static/root/assets/activity-store-3Cso_2qm.js +0 -1
- package/dist/gateway/static/root/assets/agents-B1l3iii6.js +0 -2
- package/dist/gateway/static/root/assets/apps-page-DaNFLsp0.js +0 -1
- package/dist/gateway/static/root/assets/automations-page-Cd0gMx6p.js +0 -6
- package/dist/gateway/static/root/assets/browser-settings-page-BmUYDL2Z.js +0 -8
- package/dist/gateway/static/root/assets/capability-presets-settings-panel-CE7mrWtS.js +0 -2
- package/dist/gateway/static/root/assets/channels-settings-D1_gcAHK.js +0 -1
- package/dist/gateway/static/root/assets/channels-status-swr-Cqfqv59m.js +0 -1
- package/dist/gateway/static/root/assets/check-BODqo66o.js +0 -1
- package/dist/gateway/static/root/assets/circle-alert-RzVebuX2.js +0 -1
- package/dist/gateway/static/root/assets/cn-BQ_8x0bT.js +0 -1
- package/dist/gateway/static/root/assets/connectors-page-CaLBi6Na.js +0 -2
- package/dist/gateway/static/root/assets/desktop-pet-wacrnJJ1.js +0 -1
- package/dist/gateway/static/root/assets/goal-create-dialog-BQamcEmF.js +0 -1
- package/dist/gateway/static/root/assets/goal-detail-page-DZUQ0Lf1.js +0 -4
- package/dist/gateway/static/root/assets/goals-page-BtxVD27C.js +0 -2
- package/dist/gateway/static/root/assets/index-CHKe7nwC.js +0 -197
- package/dist/gateway/static/root/assets/index-CXhfUIjh.css +0 -1
- package/dist/gateway/static/root/assets/local-app-workbench-page-CTTfyFe3.js +0 -2
- package/dist/gateway/static/root/assets/messages-DDsiqdJS.js +0 -5
- package/dist/gateway/static/root/assets/models-hub-panel-DJReXRP9.js +0 -2
- package/dist/gateway/static/root/assets/notes-workbench-BbdjzYzs.js +0 -4
- package/dist/gateway/static/root/assets/project-detail-page-BwG8SOzI.js +0 -1
- package/dist/gateway/static/root/assets/projects-page-nUlyUtxh.js +0 -1
- package/dist/gateway/static/root/assets/remote-access-hub-rf7bjije.js +0 -1
- package/dist/gateway/static/root/assets/save-bar-controls-qhDisdqY.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-CSoHUe38.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-Db976IEa.js +0 -1
- package/dist/gateway/static/root/assets/settings-page-DYfXmfTx.js +0 -1
- package/dist/gateway/static/root/assets/setup-status-panel-wBWOFpvw.js +0 -1
- package/dist/gateway/static/root/assets/shares-settings-BAMma1-P.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-TWxFFWxM.js +0 -1
- package/dist/gateway/static/root/assets/skills-page-Ca2RA29R.js +0 -2
- package/dist/gateway/static/root/assets/user-context-page-CTumZa0y.js +0 -1
- package/dist/gateway/static/root/assets/voice-api-key-field-DdlMxeqO.js +0 -1
- package/dist/gateway/static/root/assets/work-discovery-page-CcfZhdBi.js +0 -1
- package/dist/gateway/static/root/assets/work-item-detail-page--wxLw1p_.js +0 -1
- package/dist/gateway/static/root/assets/work-page-DyS0XBpV.js +0 -1
- package/dist/gateway/static/root/assets/workflows-page-CVVJd4gy.js +0 -11
- package/dist/src/browser/pipeline/source.d.ts +0 -9
- package/dist/src/browser/pipeline/source.js +0 -77
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { runSqliteWriteTransaction } from "../../../storage/sqlite/transaction.js";
|
|
2
|
+
import { getRelationshipSettings, updateRelationshipSettings } from "../../../storage/sqlite/relationship-settings-repository.js";
|
|
2
3
|
import { deleteMemoryRecord, getMemoryRecord, listMemoryRecords, upsertMemoryRecord } from "../../../storage/sqlite/memory-records-repository.js";
|
|
3
4
|
import { listKnowledgeSourceItems, listKnowledgeSyncRuns } from "../../../storage/sqlite/knowledge-repository.js";
|
|
4
5
|
import { getConnectorConnection, listConnectorConnections } from "../../../storage/sqlite/connector-repository.js";
|
|
@@ -15,6 +16,7 @@ import "../../../goals/index.js";
|
|
|
15
16
|
import { revokeComposioConnection } from "../../../connectors/composio.js";
|
|
16
17
|
import { listConnectorCatalog } from "../../../connectors/catalog.js";
|
|
17
18
|
import { nextMemoryReviewAt, resolveMemoryStability } from "../../../agent/memory/lifecycle.js";
|
|
19
|
+
import { PERSONAL_PLAYBOOK_DISABLED_TAG, PERSONAL_PLAYBOOK_ORDER_PREFIX, PERSONAL_PLAYBOOK_RULE_TAG, patchPersonalPlaybookContextTags, personalPlaybookContext } from "../../../user-context/personal-playbook.js";
|
|
18
20
|
import { listConnectorInstances } from "../../../connectors/instances.js";
|
|
19
21
|
import { uninstallConnector } from "../../../connectors/install.js";
|
|
20
22
|
import { readUserProfileFile, writeUserProfileFile } from "../../agents-admin.js";
|
|
@@ -44,8 +46,13 @@ const PLAYBOOK_IDS = [
|
|
|
44
46
|
"execution",
|
|
45
47
|
"routines"
|
|
46
48
|
];
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
+
const PLAYBOOK_SUPPORT_NEEDS = new Set([
|
|
50
|
+
"listen",
|
|
51
|
+
"clarify",
|
|
52
|
+
"advise",
|
|
53
|
+
"act",
|
|
54
|
+
"unknown"
|
|
55
|
+
]);
|
|
49
56
|
const PROFILE_FIELD_LIMITS = {
|
|
50
57
|
callName: 80,
|
|
51
58
|
pronouns: 80,
|
|
@@ -154,34 +161,57 @@ function parseProfilePatch(body) {
|
|
|
154
161
|
return Object.keys(patch).length > 0 ? { patch } : { error: "No profile fields provided" };
|
|
155
162
|
}
|
|
156
163
|
function playbookForRecord(record) {
|
|
164
|
+
if (!record.tags?.includes("playbook:rule")) return void 0;
|
|
157
165
|
if (record.kind === "preference" || record.kind === "boundary" || record.kind === "tool_preference") return "communication";
|
|
158
166
|
if (record.kind === "task_lesson" || record.kind === "derived_insight") return "execution";
|
|
159
167
|
if (record.kind === "routine") return "routines";
|
|
160
168
|
}
|
|
161
169
|
function playbookRuleOrder(record) {
|
|
162
|
-
const tag = record.tags?.find((value) => value.startsWith(
|
|
163
|
-
const parsed = tag ? Number.parseInt(tag.slice(
|
|
170
|
+
const tag = record.tags?.find((value) => value.startsWith(PERSONAL_PLAYBOOK_ORDER_PREFIX));
|
|
171
|
+
const parsed = tag ? Number.parseInt(tag.slice(PERSONAL_PLAYBOOK_ORDER_PREFIX.length), 10) : NaN;
|
|
164
172
|
return Number.isFinite(parsed) ? parsed : 1e3;
|
|
165
173
|
}
|
|
166
174
|
function patchPlaybookRuleTags(record, patch) {
|
|
167
|
-
let tags = (record.tags ?? []).filter((tag) => !tag.startsWith(
|
|
168
|
-
if (patch.enabled === true) tags = tags.filter((tag) => tag !==
|
|
169
|
-
if (patch.enabled === false) tags.push(
|
|
170
|
-
if (patch.order !== void 0) tags.push(`${
|
|
175
|
+
let tags = (record.tags ?? []).filter((tag) => !tag.startsWith(PERSONAL_PLAYBOOK_ORDER_PREFIX));
|
|
176
|
+
if (patch.enabled === true) tags = tags.filter((tag) => tag !== PERSONAL_PLAYBOOK_DISABLED_TAG);
|
|
177
|
+
if (patch.enabled === false) tags.push(PERSONAL_PLAYBOOK_DISABLED_TAG);
|
|
178
|
+
if (patch.order !== void 0) tags.push(`${PERSONAL_PLAYBOOK_ORDER_PREFIX}${patch.order}`);
|
|
171
179
|
return [...new Set(tags)];
|
|
172
180
|
}
|
|
181
|
+
function parsePlaybookContext(value) {
|
|
182
|
+
if (value === void 0) return { context: {} };
|
|
183
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return { error: "context must be an object" };
|
|
184
|
+
const input = value;
|
|
185
|
+
const context = {};
|
|
186
|
+
if ("channel" in input) {
|
|
187
|
+
if (input.channel !== null && (typeof input.channel !== "string" || !/^[a-z0-9_-]{1,40}$/i.test(input.channel))) return { error: "context.channel is invalid" };
|
|
188
|
+
context.channel = input.channel === null ? void 0 : String(input.channel);
|
|
189
|
+
}
|
|
190
|
+
if ("supportNeed" in input) {
|
|
191
|
+
if (input.supportNeed !== null && !PLAYBOOK_SUPPORT_NEEDS.has(String(input.supportNeed))) return { error: "context.supportNeed is invalid" };
|
|
192
|
+
context.supportNeed = input.supportNeed === null ? void 0 : input.supportNeed;
|
|
193
|
+
}
|
|
194
|
+
return { context };
|
|
195
|
+
}
|
|
173
196
|
function buildPersonalPlaybooks(records) {
|
|
174
197
|
return PLAYBOOK_IDS.map((id) => {
|
|
175
|
-
const rules = records.filter((record) => playbookForRecord(record) === id).sort((left, right) => playbookRuleOrder(left) - playbookRuleOrder(right) || left.updatedAt.localeCompare(right.updatedAt));
|
|
198
|
+
const rules = records.filter((record) => record.status === "active" && playbookForRecord(record) === id).sort((left, right) => playbookRuleOrder(left) - playbookRuleOrder(right) || left.updatedAt.localeCompare(right.updatedAt));
|
|
176
199
|
return {
|
|
177
200
|
id,
|
|
178
|
-
enabled: rules.some((record) => !record.tags?.includes(
|
|
201
|
+
enabled: rules.some((record) => !record.tags?.includes(PERSONAL_PLAYBOOK_DISABLED_TAG)),
|
|
179
202
|
rules: rules.map((record) => ({
|
|
180
203
|
id: record.id,
|
|
181
204
|
statement: record.content,
|
|
182
205
|
origin: record.explicitness,
|
|
183
|
-
enabled: !record.tags?.includes(
|
|
184
|
-
order: playbookRuleOrder(record)
|
|
206
|
+
enabled: !record.tags?.includes(PERSONAL_PLAYBOOK_DISABLED_TAG),
|
|
207
|
+
order: playbookRuleOrder(record),
|
|
208
|
+
context: personalPlaybookContext(record),
|
|
209
|
+
versions: playbookVersionChain(records, record.id).map((version) => ({
|
|
210
|
+
id: version.id,
|
|
211
|
+
statement: version.content,
|
|
212
|
+
updatedAt: version.updatedAt,
|
|
213
|
+
current: version.id === record.id
|
|
214
|
+
}))
|
|
185
215
|
})),
|
|
186
216
|
updatedAt: rules.map((record) => record.updatedAt).sort().at(-1)
|
|
187
217
|
};
|
|
@@ -195,7 +225,7 @@ function buildInsightSuggestions(records) {
|
|
|
195
225
|
id: record.id,
|
|
196
226
|
insight: record.content,
|
|
197
227
|
kind: record.kind,
|
|
198
|
-
action: record.kind === "routine" ? "make_repeatable" : "start_progress",
|
|
228
|
+
action: record.kind === "routine" ? "make_repeatable" : record.kind === "task_lesson" || record.kind === "derived_insight" ? "add_playbook" : "start_progress",
|
|
199
229
|
evidenceCount: record.evidence?.length ?? 0,
|
|
200
230
|
confidence: record.confidence,
|
|
201
231
|
sourceName: record.source.provider ?? "local"
|
|
@@ -216,11 +246,11 @@ function editableRecord(recordId) {
|
|
|
216
246
|
if (!record || !VISIBLE_STATUSES.has(record.status) || !isUserContextRecord(record)) return null;
|
|
217
247
|
return record;
|
|
218
248
|
}
|
|
219
|
-
function
|
|
220
|
-
return
|
|
221
|
-
id: record.id,
|
|
249
|
+
function memoryRecordInput(record) {
|
|
250
|
+
return {
|
|
222
251
|
providerId: record.source.provider ?? "local",
|
|
223
252
|
kind: record.kind,
|
|
253
|
+
userId: record.scope.userId,
|
|
224
254
|
sourceAgentId: record.provenance.sourceAgentId,
|
|
225
255
|
workspaceId: record.scope.workspaceId,
|
|
226
256
|
sessionKey: record.scope.sessionKey,
|
|
@@ -242,8 +272,41 @@ function preserveRecord(record, patch) {
|
|
|
242
272
|
validFrom: record.validFrom,
|
|
243
273
|
validTo: record.validTo,
|
|
244
274
|
supersedesRecordId: record.supersedesRecordId,
|
|
245
|
-
conflictGroupId: record.conflictGroupId
|
|
246
|
-
|
|
275
|
+
conflictGroupId: record.conflictGroupId
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
function preserveRecord(record, patch) {
|
|
279
|
+
return upsertMemoryRecord({
|
|
280
|
+
...memoryRecordInput(record),
|
|
281
|
+
...patch,
|
|
282
|
+
id: record.id
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
function playbookVersionChain(records, recordId) {
|
|
286
|
+
const relatedIds = new Set([recordId]);
|
|
287
|
+
let previousSize = 0;
|
|
288
|
+
while (previousSize !== relatedIds.size) {
|
|
289
|
+
previousSize = relatedIds.size;
|
|
290
|
+
for (const record of records) {
|
|
291
|
+
if (!record.supersedesRecordId) continue;
|
|
292
|
+
if (relatedIds.has(record.id) || relatedIds.has(record.supersedesRecordId)) {
|
|
293
|
+
relatedIds.add(record.id);
|
|
294
|
+
relatedIds.add(record.supersedesRecordId);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
return records.filter((record) => relatedIds.has(record.id) && playbookForRecord(record) !== void 0).sort((left, right) => Date.parse(right.updatedAt) - Date.parse(left.updatedAt));
|
|
299
|
+
}
|
|
300
|
+
function versionPlaybookRule(record, patch) {
|
|
301
|
+
return upsertMemoryRecord({
|
|
302
|
+
...memoryRecordInput(record),
|
|
303
|
+
...patch,
|
|
304
|
+
status: "active",
|
|
305
|
+
supersedesRecordId: record.id,
|
|
306
|
+
source: {
|
|
307
|
+
provider: "local",
|
|
308
|
+
path: "you://playbook/version"
|
|
309
|
+
}
|
|
247
310
|
});
|
|
248
311
|
}
|
|
249
312
|
function registerYouRoutes(authenticated, deps) {
|
|
@@ -291,13 +354,14 @@ function registerYouRoutes(authenticated, deps) {
|
|
|
291
354
|
}),
|
|
292
355
|
conflictGroups: buildConflictGroups(allUserContextRecords),
|
|
293
356
|
insights: buildInsightSuggestions(records),
|
|
294
|
-
playbooks: buildPersonalPlaybooks(
|
|
357
|
+
playbooks: buildPersonalPlaybooks(allUserContextRecords),
|
|
295
358
|
sources,
|
|
296
359
|
sourceRecommendations: buildGoalSourceRecommendations(sourceDefinitions.filter((definition) => definition.capabilities.includes("context") || definition.capabilities.includes("memory_source")), new Set(sourceInstances.map((instance) => instance.connectorId)), activeGoals),
|
|
297
360
|
controls: {
|
|
298
361
|
mode: config.userContext.memory.mode,
|
|
299
362
|
sensitiveWritePolicy: config.userContext.privacy.sensitiveWritePolicy
|
|
300
363
|
},
|
|
364
|
+
relationship: getRelationshipSettings(),
|
|
301
365
|
trust: {
|
|
302
366
|
defaultActionLevel: trustPolicy.defaultActionLevel,
|
|
303
367
|
levels: USER_TRUST_LEVELS,
|
|
@@ -305,6 +369,41 @@ function registerYouRoutes(authenticated, deps) {
|
|
|
305
369
|
}
|
|
306
370
|
});
|
|
307
371
|
});
|
|
372
|
+
authenticated.patch("/api/you/relationship", deps.strictRateLimitMiddleware, async (c) => {
|
|
373
|
+
const body = await c.req.json().catch(() => null);
|
|
374
|
+
if (!body || typeof body !== "object" || Array.isArray(body)) return c.json({ error: "Invalid relationship settings" }, 400);
|
|
375
|
+
const input = body;
|
|
376
|
+
const patch = {};
|
|
377
|
+
if ("supportMode" in input) {
|
|
378
|
+
if (![
|
|
379
|
+
"efficient",
|
|
380
|
+
"coach",
|
|
381
|
+
"companion",
|
|
382
|
+
"auto"
|
|
383
|
+
].includes(String(input.supportMode))) return c.json({ error: "Invalid supportMode" }, 400);
|
|
384
|
+
patch.supportMode = input.supportMode;
|
|
385
|
+
}
|
|
386
|
+
if ("proactiveEnabled" in input) {
|
|
387
|
+
if (typeof input.proactiveEnabled !== "boolean") return c.json({ error: "proactiveEnabled must be boolean" }, 400);
|
|
388
|
+
patch.proactiveEnabled = input.proactiveEnabled;
|
|
389
|
+
}
|
|
390
|
+
for (const field of ["quietStart", "quietEnd"]) {
|
|
391
|
+
if (!(field in input)) continue;
|
|
392
|
+
const value = input[field];
|
|
393
|
+
if (value !== null && (typeof value !== "string" || !/^([01]\d|2[0-3]):[0-5]\d$/.test(value))) return c.json({ error: `${field} must use HH:mm` }, 400);
|
|
394
|
+
patch[field] = value === null ? void 0 : String(value);
|
|
395
|
+
}
|
|
396
|
+
for (const field of ["allowedTopics", "blockedTopics"]) {
|
|
397
|
+
if (!(field in input)) continue;
|
|
398
|
+
if (!Array.isArray(input[field]) || input[field].length > 20 || input[field].some((value) => typeof value !== "string" || !value.trim() || value.length > 80)) return c.json({ error: `${field} must contain up to 20 short topics` }, 400);
|
|
399
|
+
patch[field] = [...new Set(input[field].map((value) => value.trim()))];
|
|
400
|
+
}
|
|
401
|
+
if (Object.keys(patch).length === 0) return c.json({ error: "No relationship settings provided" }, 400);
|
|
402
|
+
return c.json({
|
|
403
|
+
ok: true,
|
|
404
|
+
relationship: updateRelationshipSettings(patch)
|
|
405
|
+
});
|
|
406
|
+
});
|
|
308
407
|
authenticated.get("/api/you/profile", async (c) => {
|
|
309
408
|
return c.json(await readProfileBundle(deps.service.currentConfig));
|
|
310
409
|
});
|
|
@@ -523,7 +622,7 @@ function registerYouRoutes(authenticated, deps) {
|
|
|
523
622
|
limit: 500
|
|
524
623
|
}).filter(isUserContextRecord).filter((record) => playbookForRecord(record) === id);
|
|
525
624
|
runSqliteWriteTransaction(() => {
|
|
526
|
-
for (const record of active)
|
|
625
|
+
for (const record of active) versionPlaybookRule(record, { tags: patchPlaybookRuleTags(record, { enabled }) });
|
|
527
626
|
});
|
|
528
627
|
const current = active.map((record) => ({
|
|
529
628
|
...record,
|
|
@@ -540,6 +639,8 @@ function registerYouRoutes(authenticated, deps) {
|
|
|
540
639
|
const body = await c.req.json().catch(() => ({}));
|
|
541
640
|
const statement = typeof body.statement === "string" ? body.statement.trim() : "";
|
|
542
641
|
if (!statement || statement.length > 5e3) return c.json({ error: "Rule statement is required" }, 400);
|
|
642
|
+
const parsedContext = parsePlaybookContext(body.context);
|
|
643
|
+
if ("error" in parsedContext) return c.json({ error: parsedContext.error }, 400);
|
|
543
644
|
const record = upsertMemoryRecord({
|
|
544
645
|
providerId: "local",
|
|
545
646
|
kind: id === "communication" ? "preference" : id === "execution" ? "task_lesson" : "routine",
|
|
@@ -550,11 +651,11 @@ function registerYouRoutes(authenticated, deps) {
|
|
|
550
651
|
path: "you://playbook"
|
|
551
652
|
},
|
|
552
653
|
confidence: 1,
|
|
553
|
-
tags: [
|
|
654
|
+
tags: patchPersonalPlaybookContextTags([
|
|
554
655
|
"user-understanding",
|
|
555
|
-
|
|
556
|
-
`${
|
|
557
|
-
],
|
|
656
|
+
PERSONAL_PLAYBOOK_RULE_TAG,
|
|
657
|
+
`${PERSONAL_PLAYBOOK_ORDER_PREFIX}${Number.isInteger(body.order) ? body.order : 1e3}`
|
|
658
|
+
], parsedContext.context),
|
|
558
659
|
status: "active",
|
|
559
660
|
sensitivity: "normal",
|
|
560
661
|
explicitness: "explicit",
|
|
@@ -576,12 +677,14 @@ function registerYouRoutes(authenticated, deps) {
|
|
|
576
677
|
if (!content || content.length > 5e3) return c.json({ error: "Rule statement is required" }, 400);
|
|
577
678
|
if (body.enabled !== void 0 && typeof body.enabled !== "boolean") return c.json({ error: "enabled must be boolean" }, 400);
|
|
578
679
|
if (body.order !== void 0 && (!Number.isInteger(body.order) || body.order < 0 || body.order > 1e4)) return c.json({ error: "order must be an integer between 0 and 10000" }, 400);
|
|
579
|
-
const
|
|
680
|
+
const parsedContext = parsePlaybookContext(body.context);
|
|
681
|
+
if ("error" in parsedContext) return c.json({ error: parsedContext.error }, 400);
|
|
682
|
+
const updated = versionPlaybookRule(record, {
|
|
580
683
|
content,
|
|
581
|
-
tags: patchPlaybookRuleTags(record, {
|
|
684
|
+
tags: patchPersonalPlaybookContextTags(patchPlaybookRuleTags(record, {
|
|
582
685
|
enabled: body.enabled,
|
|
583
686
|
order: body.order
|
|
584
|
-
}),
|
|
687
|
+
}), parsedContext.context),
|
|
585
688
|
explicitness: body.statement === void 0 ? record.explicitness : "explicit"
|
|
586
689
|
});
|
|
587
690
|
return c.json({
|
|
@@ -593,9 +696,32 @@ function registerYouRoutes(authenticated, deps) {
|
|
|
593
696
|
const id = c.req.param("id");
|
|
594
697
|
const record = editableRecord(c.req.param("recordId"));
|
|
595
698
|
if (!PLAYBOOK_IDS.includes(id) || !record || playbookForRecord(record) !== id) return c.json({ error: "Playbook rule not found" }, 404);
|
|
596
|
-
|
|
699
|
+
preserveRecord(record, {
|
|
700
|
+
status: "archived",
|
|
701
|
+
validTo: (/* @__PURE__ */ new Date()).toISOString()
|
|
702
|
+
});
|
|
597
703
|
return c.json({ ok: true });
|
|
598
704
|
});
|
|
705
|
+
authenticated.post("/api/you/playbooks/:id/rules/:recordId/rollback", deps.strictRateLimitMiddleware, async (c) => {
|
|
706
|
+
const id = c.req.param("id");
|
|
707
|
+
const current = editableRecord(c.req.param("recordId"));
|
|
708
|
+
if (!PLAYBOOK_IDS.includes(id) || !current || playbookForRecord(current) !== id) return c.json({ error: "Playbook rule not found" }, 404);
|
|
709
|
+
const body = await c.req.json().catch(() => ({}));
|
|
710
|
+
const versionId = typeof body.versionId === "string" ? body.versionId : "";
|
|
711
|
+
const all = listAllUserContextRecords(ALL_MEMORY_STATUSES);
|
|
712
|
+
const target = playbookVersionChain(all, current.id).find((record) => record.id === versionId);
|
|
713
|
+
if (!target || target.id === current.id) return c.json({ error: "Previous version not found" }, 404);
|
|
714
|
+
const rolledBack = versionPlaybookRule(current, {
|
|
715
|
+
content: target.content,
|
|
716
|
+
tags: target.tags,
|
|
717
|
+
evidence: target.evidence,
|
|
718
|
+
explicitness: "explicit"
|
|
719
|
+
});
|
|
720
|
+
return c.json({
|
|
721
|
+
ok: true,
|
|
722
|
+
rule: buildPersonalPlaybooks([...all, rolledBack]).find((playbook) => playbook.id === id)?.rules.find((rule) => rule.id === rolledBack.id)
|
|
723
|
+
});
|
|
724
|
+
});
|
|
599
725
|
authenticated.patch("/api/you/insights/:id", deps.strictRateLimitMiddleware, async (c) => {
|
|
600
726
|
const config = deps.service.currentConfig;
|
|
601
727
|
const existing = editableRecord(c.req.param("id"));
|
|
@@ -622,6 +748,36 @@ function registerYouRoutes(authenticated, deps) {
|
|
|
622
748
|
status: "drafting",
|
|
623
749
|
href: buildRoutineAutomationDraftHref(existing)
|
|
624
750
|
});
|
|
751
|
+
if (existing.kind === "task_lesson" || existing.kind === "derived_insight") {
|
|
752
|
+
upsertMemoryRecord({
|
|
753
|
+
providerId: "local",
|
|
754
|
+
kind: "task_lesson",
|
|
755
|
+
sourceAgentId: selectedAgentId(config),
|
|
756
|
+
content: existing.content,
|
|
757
|
+
source: {
|
|
758
|
+
provider: "local",
|
|
759
|
+
path: "you://insight-proposal"
|
|
760
|
+
},
|
|
761
|
+
confidence: 1,
|
|
762
|
+
tags: [
|
|
763
|
+
"user-understanding",
|
|
764
|
+
PERSONAL_PLAYBOOK_RULE_TAG,
|
|
765
|
+
`${PERSONAL_PLAYBOOK_ORDER_PREFIX}1000`
|
|
766
|
+
],
|
|
767
|
+
status: "active",
|
|
768
|
+
sensitivity: existing.sensitivity,
|
|
769
|
+
explicitness: "explicit",
|
|
770
|
+
durability: "durable",
|
|
771
|
+
importance: existing.importance,
|
|
772
|
+
disclosurePolicy: existing.disclosurePolicy,
|
|
773
|
+
evidence: existing.evidence
|
|
774
|
+
});
|
|
775
|
+
preserveRecord(existing, { tags: [...new Set([...existing.tags ?? [], INSIGHT_ACCEPTED_TAG])] });
|
|
776
|
+
return c.json({
|
|
777
|
+
ok: true,
|
|
778
|
+
status: "saved"
|
|
779
|
+
});
|
|
780
|
+
}
|
|
625
781
|
const title = existing.content.trim().split(/\r?\n/)[0].slice(0, 72);
|
|
626
782
|
const uiLocale = body.uiLocale === "zh" ? "zh" : "en";
|
|
627
783
|
const contractDraft = await draftGoalContract({
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { Context } from 'hono';
|
|
2
2
|
import type { GatewayService } from '../service.js';
|
|
3
|
+
/** Close long-lived gateway event streams before the HTTP server starts draining. */
|
|
4
|
+
export declare function closeAllEventStreams(): void;
|
|
3
5
|
export interface SSEHandlerConfig {
|
|
4
6
|
service: GatewayService;
|
|
5
7
|
maxSseConnections?: number;
|
|
@@ -9,6 +9,10 @@ import { streamSSE } from "hono/streaming";
|
|
|
9
9
|
init_logger();
|
|
10
10
|
const log = createLogger("Gateway:SSE");
|
|
11
11
|
const activeConnections = /* @__PURE__ */ new Map();
|
|
12
|
+
/** Close long-lived gateway event streams before the HTTP server starts draining. */
|
|
13
|
+
function closeAllEventStreams() {
|
|
14
|
+
for (const controller of activeConnections.values()) controller.abort();
|
|
15
|
+
}
|
|
12
16
|
function isValidAgentRequest(body) {
|
|
13
17
|
if (!body || typeof body !== "object") return false;
|
|
14
18
|
const b = body;
|
|
@@ -341,17 +345,20 @@ function createEventsSSEHandler(config) {
|
|
|
341
345
|
}
|
|
342
346
|
}, 3e4);
|
|
343
347
|
await new Promise((resolve) => {
|
|
344
|
-
|
|
348
|
+
const finish = () => {
|
|
345
349
|
aborted = true;
|
|
346
350
|
clearInterval(keepAlive);
|
|
347
351
|
cleanup();
|
|
348
352
|
activeConnections.delete(sessionId);
|
|
349
353
|
log.debug({ sessionId }, "Event stream disconnected");
|
|
350
354
|
resolve();
|
|
351
|
-
}
|
|
355
|
+
};
|
|
356
|
+
stream.onAbort(finish);
|
|
357
|
+
abortController.signal.addEventListener("abort", () => stream.abort(), { once: true });
|
|
358
|
+
if (abortController.signal.aborted) stream.abort();
|
|
352
359
|
});
|
|
353
360
|
});
|
|
354
361
|
};
|
|
355
362
|
}
|
|
356
363
|
//#endregion
|
|
357
|
-
export { createAgentResumeHandler, createAgentSSEHandler, createEventsSSEHandler, createSendHandler };
|
|
364
|
+
export { closeAllEventStreams, createAgentResumeHandler, createAgentSSEHandler, createEventsSSEHandler, createSendHandler };
|
|
@@ -15,7 +15,8 @@ async function runGatewayLoop(opts) {
|
|
|
15
15
|
let lock = await acquireGatewayLock(opts.configPath, { port: opts.port });
|
|
16
16
|
let server = null;
|
|
17
17
|
let shuttingDown = false;
|
|
18
|
-
let
|
|
18
|
+
let forceCloseRequested = false;
|
|
19
|
+
let loopResolver = null;
|
|
19
20
|
const cleanupSignals = () => {
|
|
20
21
|
process.removeListener("SIGTERM", onSigterm);
|
|
21
22
|
process.removeListener("SIGINT", onSigint);
|
|
@@ -51,20 +52,27 @@ async function runGatewayLoop(opts) {
|
|
|
51
52
|
return;
|
|
52
53
|
}
|
|
53
54
|
shuttingDown = false;
|
|
54
|
-
|
|
55
|
+
forceCloseRequested = false;
|
|
56
|
+
loopResolver?.("restart");
|
|
55
57
|
};
|
|
56
58
|
const handleStopAfterClose = async () => {
|
|
57
59
|
await releaseLock();
|
|
58
|
-
|
|
60
|
+
loopResolver?.("stop");
|
|
59
61
|
};
|
|
60
62
|
const DRAIN_TIMEOUT_MS = 3e4;
|
|
61
63
|
const SHUTDOWN_TIMEOUT_MS = 15e3;
|
|
62
64
|
const requestShutdown = (action, signal) => {
|
|
63
|
-
if (shuttingDown)
|
|
65
|
+
if (shuttingDown) {
|
|
66
|
+
if (!forceCloseRequested && (signal === "SIGINT" || signal === "SIGTERM")) {
|
|
67
|
+
forceCloseRequested = true;
|
|
68
|
+
console.warn(`[GatewayRunLoop] Received ${signal} again; force closing connections`);
|
|
69
|
+
server?.forceCloseConnections();
|
|
70
|
+
}
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
64
73
|
shuttingDown = true;
|
|
65
74
|
const isRestart = action === "restart";
|
|
66
75
|
console.log(`[GatewayRunLoop] Received ${signal}; ${isRestart ? "restarting" : "shutting down"}`);
|
|
67
|
-
cleanupSignals();
|
|
68
76
|
const forceExitMs = isRestart ? DRAIN_TIMEOUT_MS + SHUTDOWN_TIMEOUT_MS : SHUTDOWN_TIMEOUT_MS;
|
|
69
77
|
const forceExitTimer = setTimeout(() => {
|
|
70
78
|
console.error("[GatewayRunLoop] Shutdown timed out; force exiting");
|
|
@@ -129,9 +137,11 @@ async function runGatewayLoop(opts) {
|
|
|
129
137
|
exitProcess(1);
|
|
130
138
|
return;
|
|
131
139
|
}
|
|
132
|
-
await new Promise((resolve) => {
|
|
133
|
-
|
|
140
|
+
const action = await new Promise((resolve) => {
|
|
141
|
+
loopResolver = resolve;
|
|
134
142
|
});
|
|
143
|
+
loopResolver = null;
|
|
144
|
+
if (action === "stop") return;
|
|
135
145
|
console.log("[GatewayRunLoop] Restart signal received, restarting gateway...");
|
|
136
146
|
}
|
|
137
147
|
} finally {
|
|
@@ -2,6 +2,7 @@ import { resolveGatewayBindHost, resolveGatewayListenHosts } from "../config/gat
|
|
|
2
2
|
import { ensureXopcCliOnPath } from "../infra/path-env.js";
|
|
3
3
|
import { resolveGatewayListenPlan } from "./listen.js";
|
|
4
4
|
import { GatewayService } from "./service.js";
|
|
5
|
+
import { closeAllEventStreams } from "./hono/sse.js";
|
|
5
6
|
import { handleSiteShareUpgrade } from "../share/site-share-router.js";
|
|
6
7
|
import { createHonoApp } from "./hono/app.js";
|
|
7
8
|
import { serve } from "@hono/node-server";
|
|
@@ -94,6 +95,7 @@ var GatewayServer = class {
|
|
|
94
95
|
}
|
|
95
96
|
async stop() {
|
|
96
97
|
console.log("[GatewayServer] Stopping gateway server...");
|
|
98
|
+
closeAllEventStreams();
|
|
97
99
|
const closeServer = async (server) => {
|
|
98
100
|
if (!server) return;
|
|
99
101
|
const forceClose = setTimeout(() => {
|
|
@@ -113,6 +115,13 @@ var GatewayServer = class {
|
|
|
113
115
|
await this.service.stop();
|
|
114
116
|
console.log("[GatewayServer] Gateway server stopped");
|
|
115
117
|
}
|
|
118
|
+
forceCloseConnections() {
|
|
119
|
+
const close = (server) => {
|
|
120
|
+
server?.closeAllConnections?.();
|
|
121
|
+
};
|
|
122
|
+
close(this.server);
|
|
123
|
+
for (const extra of this.extraServers) close(extra);
|
|
124
|
+
}
|
|
116
125
|
get isRunning() {
|
|
117
126
|
return this.server !== void 0;
|
|
118
127
|
}
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { inboundCorrelationMetadataFromAsyncLogContext, updateAsyncLogContext } from "../../utils/logger/context.js";
|
|
2
2
|
import { createLogger } from "../../utils/logger/index.js";
|
|
3
3
|
import { init_logger } from "../../utils/logger.js";
|
|
4
|
+
import { updateInteractionStateFromMessage } from "../../storage/sqlite/interaction-state-repository.js";
|
|
5
|
+
import { completeTaskOutcome, startTaskOutcome, updateTaskOutcome } from "../../storage/sqlite/task-outcome-repository.js";
|
|
6
|
+
import "../../storage/sqlite/index.js";
|
|
7
|
+
import { init_session_key, parseSessionKey } from "../../routing/session-key.js";
|
|
8
|
+
import { recordExplicitRelationshipFollowUp } from "../../user-context/relationship-continuity.js";
|
|
4
9
|
import { formatAgentRunErrorForClient } from "../../agent/client-error-format.js";
|
|
5
10
|
import { prependEnvelopeTimestamp } from "../../channels/envelope-timestamp.js";
|
|
6
11
|
import { shouldSkipWebchatInboundByAbortCutoff } from "../../session/abort-cutoff.js";
|
|
@@ -11,6 +16,7 @@ import { coalesceThinkingDeltas } from "../chat-stream/thinking-delta-coalescer.
|
|
|
11
16
|
import crypto from "crypto";
|
|
12
17
|
//#region src/gateway/service/run-gateway-agent.ts
|
|
13
18
|
init_logger();
|
|
19
|
+
init_session_key();
|
|
14
20
|
const log = createLogger("Gateway:Service");
|
|
15
21
|
/**
|
|
16
22
|
* @param runOptions.signal — When set (e.g. client disconnect), aborts in-flight generation and persists partial output.
|
|
@@ -24,6 +30,11 @@ async function* runGatewayAgent(deps, message, channel, chatId, attachments, thi
|
|
|
24
30
|
const runId = crypto.randomUUID();
|
|
25
31
|
const { agentService, bus, runRelay, runAbortControllers, activeWebchatRunBySession, sessionIndex: sessionIndexFromDeps, emit } = deps;
|
|
26
32
|
const sessionIndex = sessionIndexFromDeps;
|
|
33
|
+
let taskOutcomeStarted = false;
|
|
34
|
+
let taskOutcomeStatus = "failed";
|
|
35
|
+
let taskOutcomeSummary = "Agent run ended unexpectedly";
|
|
36
|
+
let taskContract;
|
|
37
|
+
const taskEvidence = [];
|
|
27
38
|
let webchatSessionKey;
|
|
28
39
|
let webchatSessionId;
|
|
29
40
|
let webchatStaleSkip = false;
|
|
@@ -40,15 +51,65 @@ async function* runGatewayAgent(deps, message, channel, chatId, attachments, thi
|
|
|
40
51
|
runAbortControllers.set(runId, new AbortController());
|
|
41
52
|
}
|
|
42
53
|
const streamSessionKey = webchatSessionKey ?? chatId;
|
|
54
|
+
if (webchatSessionKey) {
|
|
55
|
+
const parsedSession = parseSessionKey(webchatSessionKey);
|
|
56
|
+
if (!parsedSession) throw new Error("Resolved webchat session key is invalid");
|
|
57
|
+
updateInteractionStateFromMessage({
|
|
58
|
+
sessionKey: webchatSessionKey,
|
|
59
|
+
message
|
|
60
|
+
});
|
|
61
|
+
recordExplicitRelationshipFollowUp({
|
|
62
|
+
sessionKey: webchatSessionKey,
|
|
63
|
+
sourceAgentId: parsedSession.agentId,
|
|
64
|
+
message
|
|
65
|
+
});
|
|
66
|
+
startTaskOutcome({
|
|
67
|
+
runId,
|
|
68
|
+
sessionKey: webchatSessionKey,
|
|
69
|
+
channel,
|
|
70
|
+
objective: message.trim()
|
|
71
|
+
});
|
|
72
|
+
taskOutcomeStarted = true;
|
|
73
|
+
}
|
|
43
74
|
const mapper = new ChatStreamMapper({
|
|
44
75
|
runId,
|
|
45
76
|
sessionKey: streamSessionKey,
|
|
46
77
|
channel
|
|
47
78
|
});
|
|
48
79
|
let registeredActiveWebchatRun = false;
|
|
80
|
+
const addTaskEvidence = (evidence) => {
|
|
81
|
+
if (taskEvidence.some((item) => item.kind === evidence.kind && item.title === evidence.title)) return;
|
|
82
|
+
taskEvidence.push(evidence);
|
|
83
|
+
};
|
|
84
|
+
const captureTaskEvent = (event) => {
|
|
85
|
+
if (event.type === "turn_plan") {
|
|
86
|
+
taskContract = {
|
|
87
|
+
objective: message.trim(),
|
|
88
|
+
deliverables: [],
|
|
89
|
+
acceptanceCriteria: event.payload.plan.map((item) => item.step),
|
|
90
|
+
constraints: [],
|
|
91
|
+
approvalRequired: []
|
|
92
|
+
};
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
if (event.type === "patch_applied") {
|
|
96
|
+
addTaskEvidence({
|
|
97
|
+
kind: "state",
|
|
98
|
+
title: "Changes applied",
|
|
99
|
+
summary: `${event.payload.added} additions and ${event.payload.removed} removals`
|
|
100
|
+
});
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
if (event.type === "command_completed" && event.payload.exitCode === 0 && /(^|\s)(test|vitest|jest|pytest|lint|typecheck|build)(\s|$|:)/i.test(event.payload.command)) addTaskEvidence({
|
|
104
|
+
kind: "test",
|
|
105
|
+
title: event.payload.command.slice(0, 120),
|
|
106
|
+
summary: event.payload.durationMs === void 0 ? "Command completed successfully" : `Command completed successfully in ${event.payload.durationMs} ms`
|
|
107
|
+
});
|
|
108
|
+
};
|
|
49
109
|
const publishStreamEvent = (event) => channel === "webchat" ? runRelay.publish(runId, event) ?? event : event;
|
|
50
110
|
const emitAndYield = function* (events) {
|
|
51
111
|
for (const event of events) {
|
|
112
|
+
if (taskOutcomeStarted) captureTaskEvent(event);
|
|
52
113
|
const relayedEvent = publishStreamEvent(event);
|
|
53
114
|
if (channel === "webchat") emit("agent.stream", {
|
|
54
115
|
sessionKey: streamSessionKey,
|
|
@@ -61,6 +122,8 @@ async function* runGatewayAgent(deps, message, channel, chatId, attachments, thi
|
|
|
61
122
|
try {
|
|
62
123
|
if (channel === "webchat" && webchatSessionKey) {
|
|
63
124
|
if (webchatStaleSkip) {
|
|
125
|
+
taskOutcomeStatus = "cancelled";
|
|
126
|
+
taskOutcomeSummary = "Stale inbound message skipped";
|
|
64
127
|
yield* emitAndYield(mapper.end("cancelled", "Stale inbound after abort (clientCreatedAtMs before cutoff)"));
|
|
65
128
|
runRelay.complete(runId);
|
|
66
129
|
runAbortControllers.delete(runId);
|
|
@@ -97,6 +160,8 @@ async function* runGatewayAgent(deps, message, channel, chatId, attachments, thi
|
|
|
97
160
|
for await (const event of coalesceThinkingDeltas(mappedEvents)) yield* emitAndYield([event]);
|
|
98
161
|
const endStatus = mergedSignal.aborted ? "cancelled" : "success";
|
|
99
162
|
const endSummary = mergedSignal.aborted ? "Interrupted" : "Message processed successfully";
|
|
163
|
+
taskOutcomeStatus = mergedSignal.aborted ? "cancelled" : "succeeded";
|
|
164
|
+
taskOutcomeSummary = endSummary;
|
|
100
165
|
yield* emitAndYield(mapper.end(endStatus, endSummary));
|
|
101
166
|
runRelay.complete(runId);
|
|
102
167
|
try {
|
|
@@ -121,6 +186,8 @@ async function* runGatewayAgent(deps, message, channel, chatId, attachments, thi
|
|
|
121
186
|
channel: "webchat"
|
|
122
187
|
}, `Agent processing failed: ${em}`);
|
|
123
188
|
streamError = em;
|
|
189
|
+
taskOutcomeStatus = "failed";
|
|
190
|
+
taskOutcomeSummary = em;
|
|
124
191
|
const errorContent = formatAgentRunErrorForClient(streamError);
|
|
125
192
|
yield* emitAndYield(mapper.error(errorContent));
|
|
126
193
|
yield* emitAndYield(mapper.end("error", streamError));
|
|
@@ -198,12 +265,16 @@ async function* runGatewayAgent(deps, message, channel, chatId, attachments, thi
|
|
|
198
265
|
payload: { messageId }
|
|
199
266
|
}]);
|
|
200
267
|
yield* emitAndYield(mapper.end("success", "Message processed"));
|
|
268
|
+
taskOutcomeStatus = "succeeded";
|
|
269
|
+
taskOutcomeSummary = "Message processed";
|
|
201
270
|
return {
|
|
202
271
|
status: "ok",
|
|
203
272
|
summary: "Message processed"
|
|
204
273
|
};
|
|
205
274
|
} catch (error) {
|
|
206
275
|
const em = error instanceof Error ? error.message : String(error);
|
|
276
|
+
taskOutcomeStatus = "failed";
|
|
277
|
+
taskOutcomeSummary = em;
|
|
207
278
|
log.error({
|
|
208
279
|
err: error,
|
|
209
280
|
errorMessage: em,
|
|
@@ -213,6 +284,19 @@ async function* runGatewayAgent(deps, message, channel, chatId, attachments, thi
|
|
|
213
284
|
chatId
|
|
214
285
|
}, `Agent run failed: ${em}`);
|
|
215
286
|
throw error;
|
|
287
|
+
} finally {
|
|
288
|
+
if (taskOutcomeStarted) {
|
|
289
|
+
updateTaskOutcome({
|
|
290
|
+
runId,
|
|
291
|
+
...taskContract ? { contract: taskContract } : {},
|
|
292
|
+
evidence: taskEvidence
|
|
293
|
+
});
|
|
294
|
+
completeTaskOutcome({
|
|
295
|
+
runId,
|
|
296
|
+
status: taskOutcomeStatus,
|
|
297
|
+
summary: taskOutcomeSummary
|
|
298
|
+
});
|
|
299
|
+
}
|
|
216
300
|
}
|
|
217
301
|
}
|
|
218
302
|
//#endregion
|
|
@@ -11,6 +11,7 @@ import { AgentRunRelay } from './agent-run-relay.js';
|
|
|
11
11
|
import { type EnqueueGoalRunOptions } from '../goals/index.js';
|
|
12
12
|
import { ProjectService } from '../projects/index.js';
|
|
13
13
|
import { LocalAppService } from '../local-apps/index.js';
|
|
14
|
+
import { type BrowserRecipeService } from '../browser/recipes/index.js';
|
|
14
15
|
import { GatewaySessionsApi } from './service/sessions-api.js';
|
|
15
16
|
import { GatewayMarketplaceService } from './service/marketplace-service.js';
|
|
16
17
|
import { GatewayAgentRunner } from './service/agent-runner.js';
|
|
@@ -26,6 +27,7 @@ export declare class GatewayService {
|
|
|
26
27
|
private _agentService;
|
|
27
28
|
private channelManager;
|
|
28
29
|
private automationService;
|
|
30
|
+
private browserRecipeService;
|
|
29
31
|
private notesService;
|
|
30
32
|
private extensionLoader;
|
|
31
33
|
private extensionMetadataSnapshot;
|
|
@@ -42,6 +44,7 @@ export declare class GatewayService {
|
|
|
42
44
|
private auth;
|
|
43
45
|
private readonly sse;
|
|
44
46
|
getConfig(): Config;
|
|
47
|
+
get browserRecipes(): BrowserRecipeService;
|
|
45
48
|
private stopGatewayUpdateCheck;
|
|
46
49
|
/** When set (e.g. by `GatewayServer`), `triggerGatewayProcessRestart` can stop HTTP then exit. */
|
|
47
50
|
private gatewayShutdownForRestart;
|