@xopcai/xopc 0.0.252 → 0.0.254
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/dist/background.js +59 -13
- package/dist/browser-ext/dist/content.js +0 -5
- package/dist/browser-ext/manifest.json +2 -1
- package/dist/extensions/telegram/src/inbound-processor.js +2 -2
- package/dist/extensions/telegram/src/plugin.js +3 -2
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/gateway/static/root/assets/{activity-store-w3eq3YpP.js → activity-store-Ci5Rxmi_.js} +1 -1
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-k039rbUz.js → agent-avatar-dicebear-D82jpmFL.js} +1 -1
- package/dist/gateway/static/root/assets/agent-defaults-settings-panel-vul32IsP.js +1 -0
- package/dist/gateway/static/root/assets/{agents-Bmth_bSQ.js → agents-p3kWyz1T.js} +1 -1
- package/dist/gateway/static/root/assets/{api-2joIfbrH.js → api-CXIzQJ2Z.js} +1 -1
- package/dist/gateway/static/root/assets/{app-management-settings-panel-ByJ4kiD0.js → app-management-settings-panel-mhxcQpkQ.js} +1 -1
- package/dist/gateway/static/root/assets/{appearance-settings-BK2Jga-B.js → appearance-settings-BIMwACUF.js} +1 -1
- package/dist/gateway/static/root/assets/apps-page-CJFJKNwS.js +1 -0
- package/dist/gateway/static/root/assets/{archive-plugin-DMDKtYpi.js → archive-plugin-C63Xp_sU.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-B764Ql3Z.js → attachment-load-D12KYOav.js} +1 -1
- package/dist/gateway/static/root/assets/{automations-page-D-sO8CZe.js → automations-page-DXj0o5CY.js} +1 -1
- package/dist/gateway/static/root/assets/automations-workspace-B2wxcpgq.js +6 -0
- package/dist/gateway/static/root/assets/{binary-plugins-fxtzYRpv.js → binary-plugins-Bcv8hun6.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-Bcjtvckh.js → block-editor-C61LqK_-.js} +50 -50
- package/dist/gateway/static/root/assets/{browser-automation-inputs-BSmnusjD.js → browser-automation-inputs-CAclu735.js} +1 -1
- package/dist/gateway/static/root/assets/{browser-automations-page-DC_OQIBk.js → browser-automations-page-BITfKX8L.js} +2 -2
- package/dist/gateway/static/root/assets/browser-settings-page-BMjY8cyv.js +8 -0
- package/dist/gateway/static/root/assets/capabilities-settings-panel-wB3Vgmp3.js +7 -0
- package/dist/gateway/static/root/assets/channels-settings-U5ffzu4r.js +1 -0
- package/dist/gateway/static/root/assets/{channels-status-swr-BuWjIG_a.js → channels-status-swr-Cmbx0E8O.js} +1 -1
- package/dist/gateway/static/root/assets/{chat-terminal-dock-5SevEo_I.js → chat-terminal-dock-CNBgHN9U.js} +1 -1
- package/dist/gateway/static/root/assets/connectors-page-BGaF--m5.js +2 -0
- package/dist/gateway/static/root/assets/{cron-expression-DtsfalBM.js → cron-expression-DCTN4QAG.js} +1 -1
- package/dist/gateway/static/root/assets/{date-picker-tDEQV5TP.js → date-picker-BuEyUxZn.js} +1 -1
- package/dist/gateway/static/root/assets/{dependency-picker-HhNwg0Y2.js → dependency-picker-l6IXzk0C.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-acU4Li-C.js → desktop-pet-cGn_20DO.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-settings-R84AR0Pe.js → desktop-pet-settings-DIfccDKS.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-debug-page-CrLlRkSN.js → extension-debug-page-CTS5RP_D.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-BH5lmZXE.js → extension-page-Dg9YssYH.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-BscjNAd1.js → extension-settings-page-CWZYL8Fi.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-swr-9HidFZUd.js → gateway-config-swr-Chsr5wGH.js} +1 -1
- package/dist/gateway/static/root/assets/gateway-settings-vHI_Que8.js +1 -0
- package/dist/gateway/static/root/assets/{gateway-startup-retry-DRCPXONr.js → gateway-startup-retry-C9ynH6VV.js} +1 -1
- package/dist/gateway/static/root/assets/{heartbeat-settings-K5Zhl2rx.js → heartbeat-settings-WUhSfvob.js} +1 -1
- package/dist/gateway/static/root/assets/home-page-CYjlMzPx.js +1 -0
- package/dist/gateway/static/root/assets/{image-generation-api-CR6Kle8H.js → image-generation-api-D_TsVe7h.js} +1 -1
- package/dist/gateway/static/root/assets/index-BBlJYVxR.js +74 -0
- package/dist/gateway/static/root/assets/index-_I0dD2LN.css +2 -0
- package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-B1QR49-7.js → keyboard-shortcuts-settings-DGBf6YfD.js} +1 -1
- package/dist/gateway/static/root/assets/local-app-workbench-page-CLlIl83V.js +2 -0
- package/dist/gateway/static/root/assets/{local-apps-page-C74It-T8.js → local-apps-page-DGWP_xsQ.js} +1 -1
- package/dist/gateway/static/root/assets/{locale-store-BfZGZKSs.js → locale-store-B2v8mNJw.js} +1 -1
- package/dist/gateway/static/root/assets/logs-page-DuhCigiB.js +2 -0
- package/dist/gateway/static/root/assets/{management-settings-1kNnYL97.js → management-settings-DUAZ-dtt.js} +1 -1
- package/dist/gateway/static/root/assets/markdown-view-DBWu9d_n.js +201 -0
- package/dist/gateway/static/root/assets/{media-plugins-B5c0AoS1.js → media-plugins-CsUjcIBy.js} +1 -1
- package/dist/gateway/static/root/assets/messages-ChSTFZR5.js +3 -0
- package/dist/gateway/static/root/assets/{mobile-pairing-wizard-CsIZqK51.js → mobile-pairing-wizard-Dxu8twiQ.js} +1 -1
- package/dist/gateway/static/root/assets/note-detail-panel-DMdbaTZp.js +5 -0
- package/dist/gateway/static/root/assets/notes-page-xe_vX0nM.js +8 -0
- package/dist/gateway/static/root/assets/{page-tabs-CqJN6Ljz.js → page-tabs-YeJKwV-7.js} +1 -1
- package/dist/gateway/static/root/assets/{preview-open-alternatives-DqRIGxf4.js → preview-open-alternatives-BfJ3jMDG.js} +1 -1
- package/dist/gateway/static/root/assets/{product-open-page-DE2nPE_K.js → product-open-page-B7NRGPox.js} +1 -1
- package/dist/gateway/static/root/assets/project-detail-page-hG7ELibZ.js +1 -0
- package/dist/gateway/static/root/assets/projects-page-C5G2ET4w.js +1 -0
- package/dist/gateway/static/root/assets/{registry-api-Bpy8XX-5.js → registry-api-B9OZUdwC.js} +1 -1
- package/dist/gateway/static/root/assets/{remote-access-hub-Dnd73xWt.js → remote-access-hub-DTO-faxH.js} +1 -1
- package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-Bb4b74-P.js → runtime-tools-settings-panel-uJ8Br3ZL.js} +1 -1
- package/dist/gateway/static/root/assets/{schema-form-DoPU5j3J.js → schema-form-CXwn6up5.js} +1 -1
- package/dist/gateway/static/root/assets/sessions-page-CwzsUCgP.js +1 -0
- package/dist/gateway/static/root/assets/settings-advanced-gate-Djc3EdoO.js +1 -0
- package/dist/gateway/static/root/assets/{settings-form-section-Ci-9WajJ.js → settings-form-section-YVNYsR0U.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-CL_2F95D.js → settings-page-cHqrIdVR.js} +1 -1
- package/dist/gateway/static/root/assets/setup-status-panel-MUAMcZLD.js +1 -0
- package/dist/gateway/static/root/assets/{share-preview-page-XUA3oKQX.js → share-preview-page-DnjSDQru.js} +1 -1
- package/dist/gateway/static/root/assets/shares-settings-C7A0aywX.js +1 -0
- package/dist/gateway/static/root/assets/skill-reload-api-D1xSGJAQ.js +1 -0
- package/dist/gateway/static/root/assets/{skills-page-sXXAZDc9.js → skills-page-DkrGEdiY.js} +1 -1
- package/dist/gateway/static/root/assets/{skills-page.utils-DD79Bl1I.js → skills-page.utils-CqZbiZuK.js} +1 -1
- package/dist/gateway/static/root/assets/{system-settings-panel-BEH64qBV.js → system-settings-panel-Dmw0RfxZ.js} +1 -1
- package/dist/gateway/static/root/assets/task-detail-page-BvZSCLUH.js +1 -0
- package/dist/gateway/static/root/assets/{theme-store-CISSxU1c.js → theme-store-CubltMKm.js} +1 -1
- package/dist/gateway/static/root/assets/{tunnel-api-DrKDhnJm.js → tunnel-api-CiieC6HP.js} +1 -1
- package/dist/gateway/static/root/assets/{use-autosave-CPYePL-Q.js → use-autosave-XQ3SuyB9.js} +1 -1
- package/dist/gateway/static/root/assets/user-model-page-BKJC7tyW.js +2 -0
- package/dist/gateway/static/root/assets/{voice-api-key-field-DKqzrCXx.js → voice-api-key-field-D4QzVgdt.js} +1 -1
- package/dist/gateway/static/root/assets/{voice-config-api-e9xWjwBX.js → voice-config-api-B1ZbyVmF.js} +1 -1
- package/dist/gateway/static/root/assets/{work-discovery-overlay-kTQug6bq.js → work-discovery-overlay-D5Tf8GRZ.js} +1 -1
- package/dist/gateway/static/root/assets/{workflow-run-setup-panel-m9SKj_GT.js → workflow-run-setup-panel-BW9p8Maz.js} +2 -2
- package/dist/gateway/static/root/assets/workflows-page-DuqRodIc.js +5 -0
- package/dist/gateway/static/root/index.html +10 -10
- package/dist/package.js +1 -1
- package/dist/packages/realtime-protocol/src/voice.js +6 -1
- package/dist/src/agent/agent-manager.js +24 -7
- package/dist/src/agent/background-review/run-background-review.js +1 -1
- package/dist/src/agent/embedded/execution-context.d.ts +2 -1
- package/dist/src/agent/embedded/execution-context.js +10 -4
- package/dist/src/agent/embedded/index.d.ts +1 -1
- package/dist/src/agent/embedded/index.js +2 -2
- package/dist/src/agent/embedded/model-runtime.js +1 -1
- package/dist/src/agent/embedded/run-for-session.js +5 -4
- package/dist/src/agent/embedded/run-turn.js +22 -3
- package/dist/src/agent/embedded/types.d.ts +1 -1
- package/dist/src/agent/image/tool-model-config.js +1 -1
- package/dist/src/agent/mcp/oauth/mcp-oauth-store.js +1 -1
- package/dist/src/agent/service/direct-turn-helpers.js +6 -3
- package/dist/src/agent/service/process-direct-streaming.js +6 -3
- package/dist/src/agent/service.d.ts +2 -0
- package/dist/src/agent/service.js +23 -9
- package/dist/src/agent/session/session-inspector.js +1 -1
- package/dist/src/agent/skills/hub-lock.js +1 -1
- package/dist/src/agent/tasks/task-judge-service.js +3 -3
- package/dist/src/agent/tools/browser/tool/browser-use-tool.js +17 -2
- package/dist/src/agent/tools/browser/tool/schemas.d.ts +85 -1
- package/dist/src/agent/tools/browser/tool/schemas.js +212 -5
- package/dist/src/agent/tools/clarify-tool.d.ts +17 -3
- package/dist/src/agent/tools/clarify-tool.js +27 -32
- package/dist/src/agent/tools/cli-clarify.js +23 -8
- package/dist/src/agent/tools/factory.js +14 -4
- package/dist/src/ai-assist/text-assist.js +1 -1
- package/dist/src/auth/credentials.js +2 -2
- package/dist/src/auth/oauth/xopc-cloud.js +1 -1
- package/dist/src/auth/profiles/store.js +1 -1
- package/dist/src/auth/sync-provider-auth.js +2 -2
- package/dist/src/automations/domain/validation.d.ts +4 -4
- package/dist/src/automations/draft/automation-draft-validator.d.ts +1 -1
- package/dist/src/browser/drivers/extension-driver.d.ts +4 -4
- package/dist/src/browser/drivers/extension-driver.js +20 -8
- package/dist/src/browser/drivers/playwright-driver.js +1 -1
- package/dist/src/browser/providers/browser-ext-install.d.ts +3 -0
- package/dist/src/browser/providers/browser-ext-install.js +19 -4
- package/dist/src/browser/providers/extension.d.ts +14 -1
- package/dist/src/browser/providers/extension.js +89 -11
- package/dist/src/browser/providers/playwright-install.js +8 -12
- package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
- package/dist/src/cli/commands/doctor/checks/provider-auth.js +1 -1
- package/dist/src/cli/commands/models.js +1 -1
- package/dist/src/config/index.js +4 -4
- package/dist/src/config/loader.js +2 -2
- package/dist/src/config/models-json.js +1 -1
- package/dist/src/extensions/lockfile.js +1 -1
- package/dist/src/gateway/agents-admin.js +1 -1
- package/dist/src/gateway/chat-stream/mapper.js +5 -1
- package/dist/src/gateway/chat-stream/protocol.d.ts +5 -1
- package/dist/src/gateway/clarify-runtime.d.ts +7 -5
- package/dist/src/gateway/clarify-runtime.js +8 -11
- package/dist/src/gateway/ephemeral-clarification-waiter.d.ts +17 -0
- package/dist/src/gateway/ephemeral-clarification-waiter.js +46 -0
- package/dist/src/gateway/file-path-classifier.js +1 -1
- package/dist/src/gateway/heartbeat/service.js +1 -1
- package/dist/src/gateway/hono/lib/config-payload.js +1 -1
- package/dist/src/gateway/hono/routes/agent-stream.js +44 -18
- package/dist/src/gateway/hono/routes/browser.js +149 -27
- package/dist/src/gateway/hono/routes/lazy-bundles.js +1 -1
- package/dist/src/gateway/hono/routes/models.js +1 -1
- package/dist/src/gateway/hono/routes/session-input-handler.d.ts +10 -2
- package/dist/src/gateway/hono/routes/side-chats.js +24 -4
- package/dist/src/gateway/security/gateway-scopes.js +1 -1
- package/dist/src/gateway/service/agent-runner.d.ts +25 -36
- package/dist/src/gateway/service/agent-runner.js +103 -32
- package/dist/src/gateway/service/config-coordinator.js +1 -1
- package/dist/src/gateway/service/run-gateway-agent.js +5 -2
- package/dist/src/gateway/service/session-input-coordinator.js +4 -1
- package/dist/src/gateway/service/sessions-api.js +1 -1
- package/dist/src/gateway/service.d.ts +4 -2
- package/dist/src/gateway/service.js +36 -20
- package/dist/src/gateway/side-chat/manager.d.ts +2 -1
- package/dist/src/gateway/side-chat/manager.js +5 -4
- package/dist/src/gateway/side-chat/run-service.d.ts +5 -1
- package/dist/src/gateway/side-chat/run-service.js +24 -23
- package/dist/src/gateway/side-chat/types.d.ts +3 -1
- package/dist/src/heartbeat/index.js +1 -1
- package/dist/src/providers/auth-runtime/resolve-auth.js +1 -1
- package/dist/src/providers/index.js +2 -2
- package/dist/src/providers/model-registry.js +1 -1
- package/dist/src/providers/model-thinking.js +57 -20
- package/dist/src/providers/register-runtime-providers.js +1 -1
- package/dist/src/storage/sqlite/clarification-wait-repository.d.ts +41 -0
- package/dist/src/storage/sqlite/clarification-wait-repository.js +418 -0
- package/dist/src/storage/sqlite/index.d.ts +2 -1
- package/dist/src/storage/sqlite/index.js +2 -1
- package/dist/src/storage/sqlite/migrations/154_session_clarification_waits.sql +60 -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/storage/sqlite/session-input-repository.d.ts +11 -6
- package/dist/src/tui/tui-startup-resources.js +1 -1
- package/dist/src/tui/tui.js +1 -1
- package/dist/src/voice/realtime/agentEngine.js +7 -2
- package/dist/src/voice/realtime/runtime.types.d.ts +5 -0
- package/dist/src/work-discovery/service.js +1 -1
- package/dist/src/workflows/service/workflow-run-service.js +1 -1
- package/package.json +3 -3
- package/skills/creative/hatch-pet/SKILL.md +1 -1
- package/dist/gateway/static/root/assets/agent-defaults-settings-panel-D4J4oq8p.js +0 -1
- package/dist/gateway/static/root/assets/apps-page-B3ky7cWU.js +0 -1
- package/dist/gateway/static/root/assets/automations-workspace-Ds5-_-9z.js +0 -6
- package/dist/gateway/static/root/assets/browser-settings-page-C1FojyG6.js +0 -3
- package/dist/gateway/static/root/assets/capabilities-settings-panel-Bs59UCut.js +0 -7
- package/dist/gateway/static/root/assets/channels-settings-CM9vNmoo.js +0 -1
- package/dist/gateway/static/root/assets/connectors-page-BPZ44D-V.js +0 -2
- package/dist/gateway/static/root/assets/gateway-settings-BxLcW6ij.js +0 -1
- package/dist/gateway/static/root/assets/home-page-CZAg9RBv.js +0 -1
- package/dist/gateway/static/root/assets/index-D4Ykja-U.js +0 -72
- package/dist/gateway/static/root/assets/index-zIJ3AXgR.css +0 -2
- package/dist/gateway/static/root/assets/local-app-workbench-page-wicoV-ti.js +0 -2
- package/dist/gateway/static/root/assets/logs-page-xX-7S49A.js +0 -2
- package/dist/gateway/static/root/assets/markdown-view-DjiwT28p.js +0 -201
- package/dist/gateway/static/root/assets/messages-DaIwVWar.js +0 -3
- package/dist/gateway/static/root/assets/note-detail-panel-CfWxopl4.js +0 -5
- package/dist/gateway/static/root/assets/notes-page-CYN-LCHJ.js +0 -8
- package/dist/gateway/static/root/assets/project-detail-page-B5G3LzDq.js +0 -1
- package/dist/gateway/static/root/assets/projects-page-CuVK2mKu.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-XL4LyKZe.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-0ForzDSS.js +0 -1
- package/dist/gateway/static/root/assets/setup-status-panel-DVws6XZc.js +0 -1
- package/dist/gateway/static/root/assets/shares-settings-BwDvcacF.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-BJjrATqE.js +0 -1
- package/dist/gateway/static/root/assets/task-detail-page-0jxMi75O.js +0 -1
- package/dist/gateway/static/root/assets/user-model-page-B6zLDfDl.js +0 -2
- package/dist/gateway/static/root/assets/workflows-page-Bcd1XqP7.js +0 -5
- package/dist/src/gateway/clarify-bridge.d.ts +0 -46
- package/dist/src/gateway/clarify-bridge.js +0 -111
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
import { createLogger } from "../../utils/logger/index.js";
|
|
2
2
|
import { init_logger } from "../../utils/logger.js";
|
|
3
3
|
import { listActiveSessionInputRuns } from "../../storage/sqlite/session-input-repository.js";
|
|
4
|
+
import { createClarificationWait, getClarification, getClarificationSnapshot, resolveClarification, supersedeActiveClarification } from "../../storage/sqlite/clarification-wait-repository.js";
|
|
4
5
|
import { onConnectionWaitChanged } from "../../storage/sqlite/connection-wait-repository.js";
|
|
5
6
|
import "../../storage/sqlite/index.js";
|
|
6
|
-
import {
|
|
7
|
+
import { EphemeralClarificationWaiter } from "../ephemeral-clarification-waiter.js";
|
|
7
8
|
import { runGatewayAgent } from "./run-gateway-agent.js";
|
|
8
9
|
import { fitSourceContextsToBudget } from "../../agent/source-context/budget.js";
|
|
9
10
|
import { SessionInputCoordinator } from "./session-input-coordinator.js";
|
|
10
11
|
import crypto from "node:crypto";
|
|
11
12
|
//#region src/gateway/service/agent-runner.ts
|
|
12
13
|
init_logger();
|
|
14
|
+
/**
|
|
15
|
+
* Owns gateway agent runs, durable clarification coordination, and the
|
|
16
|
+
* lifecycle-bound clarification waiter used by ephemeral side chats.
|
|
17
|
+
*/
|
|
13
18
|
const log = createLogger("Gateway:AgentRunner");
|
|
14
19
|
const MAX_TURN_CONTEXTS = 5;
|
|
15
20
|
var GatewayAgentRunner = class {
|
|
@@ -18,11 +23,10 @@ var GatewayAgentRunner = class {
|
|
|
18
23
|
runAbortControllers = /* @__PURE__ */ new Map();
|
|
19
24
|
runCompletions = /* @__PURE__ */ new Map();
|
|
20
25
|
resolveRunCompletions = /* @__PURE__ */ new Map();
|
|
21
|
-
|
|
26
|
+
ephemeralClarifications = new EphemeralClarificationWaiter();
|
|
22
27
|
/** Maps webchat session key → active `runId` for `clarify` tool routing. */
|
|
23
28
|
activeWebchatRunBySession = /* @__PURE__ */ new Map();
|
|
24
29
|
externalStreamBySession = /* @__PURE__ */ new Map();
|
|
25
|
-
externalClarificationTimeouts = /* @__PURE__ */ new Map();
|
|
26
30
|
externalClarificationResponses = /* @__PURE__ */ new Map();
|
|
27
31
|
inputs;
|
|
28
32
|
unsubscribeConnectionWait;
|
|
@@ -104,30 +108,24 @@ var GatewayAgentRunner = class {
|
|
|
104
108
|
runId
|
|
105
109
|
}));
|
|
106
110
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
}
|
|
110
|
-
/** Called from `GatewayService.stop()` so the bridge gets cleaned up. */
|
|
111
|
-
disposeClarifyBridge() {
|
|
112
|
-
this.clarifyBridge.dispose();
|
|
111
|
+
disposeClarifications() {
|
|
112
|
+
this.ephemeralClarifications.dispose();
|
|
113
113
|
this.unsubscribeConnectionWait();
|
|
114
114
|
}
|
|
115
115
|
registerExternalWebchatRun(sessionKey, runId, publish, options) {
|
|
116
116
|
this.activeWebchatRunBySession.set(sessionKey, runId);
|
|
117
117
|
this.externalStreamBySession.set(sessionKey, publish);
|
|
118
|
-
if (options?.clarificationTimeoutMs !== void 0) this.externalClarificationTimeouts.set(sessionKey, options.clarificationTimeoutMs);
|
|
119
118
|
if (options?.beforeClarificationResponse) this.externalClarificationResponses.set(sessionKey, options.beforeClarificationResponse);
|
|
120
119
|
}
|
|
121
120
|
unregisterExternalWebchatRun(sessionKey, runId) {
|
|
122
121
|
if (this.activeWebchatRunBySession.get(sessionKey) === runId) {
|
|
123
122
|
this.activeWebchatRunBySession.delete(sessionKey);
|
|
124
123
|
this.externalStreamBySession.delete(sessionKey);
|
|
125
|
-
this.externalClarificationTimeouts.delete(sessionKey);
|
|
126
124
|
this.externalClarificationResponses.delete(sessionKey);
|
|
127
125
|
}
|
|
128
126
|
}
|
|
129
127
|
cancelClarificationForRun(runId) {
|
|
130
|
-
this.
|
|
128
|
+
this.ephemeralClarifications.cancelForRun(runId);
|
|
131
129
|
}
|
|
132
130
|
async *runAgent(message, channel, chatId, origin, attachments, thinking, runOptions) {
|
|
133
131
|
const trackedRunId = runOptions?.runId;
|
|
@@ -185,7 +183,7 @@ var GatewayAgentRunner = class {
|
|
|
185
183
|
}
|
|
186
184
|
/** Abort an in-flight webchat agent run. */
|
|
187
185
|
async abortAgentRun(runId) {
|
|
188
|
-
this.
|
|
186
|
+
this.ephemeralClarifications.cancelForRun(runId);
|
|
189
187
|
const keysToMark = [];
|
|
190
188
|
for (const [sk, id] of this.activeWebchatRunBySession) if (id === runId) keysToMark.push(sk);
|
|
191
189
|
const c = this.runAbortControllers.get(runId);
|
|
@@ -194,10 +192,13 @@ var GatewayAgentRunner = class {
|
|
|
194
192
|
idle: true
|
|
195
193
|
};
|
|
196
194
|
const completion = this.runCompletions.get(runId);
|
|
197
|
-
for (const sk of keysToMark)
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
195
|
+
for (const sk of keysToMark) {
|
|
196
|
+
if ((getClarificationSnapshot(sk)?.clarification)?.originRunId === runId) supersedeActiveClarification(sk);
|
|
197
|
+
this.opts.sessionIndex.appendTranscriptContextEntry(sk, {
|
|
198
|
+
text: "Webchat agent run aborted",
|
|
199
|
+
data: { runId }
|
|
200
|
+
}).catch(() => {});
|
|
201
|
+
}
|
|
201
202
|
c.abort();
|
|
202
203
|
const { abortEmbeddedRun } = await import("../../agent/embedded/runs.js");
|
|
203
204
|
await Promise.all(keysToMark.map((sessionKey) => abortEmbeddedRun(sessionKey).catch(() => false)));
|
|
@@ -207,9 +208,45 @@ var GatewayAgentRunner = class {
|
|
|
207
208
|
idle: true
|
|
208
209
|
};
|
|
209
210
|
}
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
211
|
+
answerEphemeralClarification(requestId, answer) {
|
|
212
|
+
return this.ephemeralClarifications.answer(requestId, answer);
|
|
213
|
+
}
|
|
214
|
+
getClarificationState(sessionKey) {
|
|
215
|
+
return getClarificationSnapshot(sessionKey);
|
|
216
|
+
}
|
|
217
|
+
resolveClarificationResponse(input) {
|
|
218
|
+
const result = resolveClarification(input);
|
|
219
|
+
if (result.ok) {
|
|
220
|
+
this.opts.emit("clarification.updated", result.clarification);
|
|
221
|
+
if (result.queued) this.inputs.drain(result.clarification.sessionKey);
|
|
222
|
+
}
|
|
223
|
+
return result;
|
|
224
|
+
}
|
|
225
|
+
getClarificationById(id) {
|
|
226
|
+
return getClarification(id);
|
|
227
|
+
}
|
|
228
|
+
answerClarificationChoice(requestId, choiceIndex, idempotencyKey) {
|
|
229
|
+
const wait = getClarification(requestId);
|
|
230
|
+
const answer = wait?.status === "open" ? wait.choices?.[choiceIndex] : void 0;
|
|
231
|
+
if (!answer) return false;
|
|
232
|
+
return this.resolveClarificationResponse({
|
|
233
|
+
id: wait.id,
|
|
234
|
+
expectedVersion: wait.version,
|
|
235
|
+
idempotencyKey,
|
|
236
|
+
action: "answer",
|
|
237
|
+
answer
|
|
238
|
+
}).ok;
|
|
239
|
+
}
|
|
240
|
+
answerClarificationText(sessionKey, answer, idempotencyKey) {
|
|
241
|
+
const wait = getClarificationSnapshot(sessionKey)?.clarification;
|
|
242
|
+
if (!wait || wait.status !== "open" || !answer.trim()) return false;
|
|
243
|
+
return this.resolveClarificationResponse({
|
|
244
|
+
id: wait.id,
|
|
245
|
+
expectedVersion: wait.version,
|
|
246
|
+
idempotencyKey,
|
|
247
|
+
action: "answer",
|
|
248
|
+
answer
|
|
249
|
+
}).ok;
|
|
213
250
|
}
|
|
214
251
|
/** Same execution path as scheduled continuation, but lets callers observe failures. */
|
|
215
252
|
async runScheduledWebchatTurn(sessionKey, userTurn) {
|
|
@@ -243,8 +280,8 @@ var GatewayAgentRunner = class {
|
|
|
243
280
|
}
|
|
244
281
|
}
|
|
245
282
|
/**
|
|
246
|
-
*
|
|
247
|
-
*
|
|
283
|
+
* Persist normal clarification waits and use the lifecycle-bound waiter only
|
|
284
|
+
* for caller-owned ephemeral sessions.
|
|
248
285
|
* Rejects when neither path is available (e.g. CLI without webchat or TG).
|
|
249
286
|
*
|
|
250
287
|
* `publishStreamFor(runId)` is the bridge into AgentService's
|
|
@@ -253,33 +290,67 @@ var GatewayAgentRunner = class {
|
|
|
253
290
|
*/
|
|
254
291
|
async requestClarification(opts) {
|
|
255
292
|
const { sessionKey, request, publishStreamFor } = opts;
|
|
256
|
-
const runId = this.activeWebchatRunBySession.get(sessionKey);
|
|
293
|
+
const runId = this.activeWebchatRunBySession.get(sessionKey) ?? opts.runId;
|
|
257
294
|
const publishStream = this.externalStreamBySession.get(sessionKey) ?? (runId ? publishStreamFor(runId) : void 0);
|
|
258
295
|
const deliver = ((await this.opts.sessionIndex.getSessionMetadata(sessionKey).catch(() => null))?.routing)?.source === "telegram" ? async (ctx) => {
|
|
259
296
|
await this.deliverTelegramClarify(ctx);
|
|
260
297
|
} : void 0;
|
|
261
|
-
|
|
262
|
-
return this.
|
|
263
|
-
timeoutMs: this.externalClarificationTimeouts.get(sessionKey),
|
|
298
|
+
const persistedSession = getClarificationSnapshot(sessionKey);
|
|
299
|
+
if (!persistedSession && this.externalStreamBySession.has(sessionKey)) return this.ephemeralClarifications.start({
|
|
264
300
|
beforeResponse: this.externalClarificationResponses.get(sessionKey),
|
|
265
|
-
sessionKey,
|
|
266
301
|
runId,
|
|
267
|
-
publishStream,
|
|
268
|
-
request
|
|
269
|
-
|
|
302
|
+
publish: publishStream,
|
|
303
|
+
request
|
|
304
|
+
}).then((answer) => ({
|
|
305
|
+
status: "answered",
|
|
306
|
+
answer
|
|
307
|
+
}));
|
|
308
|
+
if (!persistedSession) return Promise.reject(/* @__PURE__ */ new Error("Clarify requires a persisted session."));
|
|
309
|
+
const wait = createClarificationWait({
|
|
310
|
+
sessionKey,
|
|
311
|
+
runId: opts.runId,
|
|
312
|
+
toolCallId: opts.toolCallId,
|
|
313
|
+
kind: request.kind === "approval" ? "approval" : "input",
|
|
314
|
+
question: request.question,
|
|
315
|
+
choices: request.choices,
|
|
316
|
+
suggestedAnswer: request.suggestedAnswer,
|
|
317
|
+
approvalKey: request.approvalKey
|
|
318
|
+
});
|
|
319
|
+
const event = {
|
|
320
|
+
type: "clarify_request",
|
|
321
|
+
requestId: wait.id,
|
|
322
|
+
kind: wait.kind,
|
|
323
|
+
question: wait.question,
|
|
324
|
+
choices: wait.choices,
|
|
325
|
+
suggestedAnswer: wait.suggestedAnswer,
|
|
326
|
+
expiresAt: wait.expiresAt,
|
|
327
|
+
createdAt: wait.createdAt,
|
|
328
|
+
version: wait.version
|
|
329
|
+
};
|
|
330
|
+
if (this.activeWebchatRunBySession.has(sessionKey)) publishStream?.(event);
|
|
331
|
+
if (deliver) await deliver({
|
|
332
|
+
sessionKey,
|
|
333
|
+
requestId: wait.id,
|
|
334
|
+
request
|
|
270
335
|
});
|
|
336
|
+
return {
|
|
337
|
+
status: "waiting",
|
|
338
|
+
waitId: wait.id,
|
|
339
|
+
expiresAt: wait.expiresAt
|
|
340
|
+
};
|
|
271
341
|
}
|
|
272
342
|
async deliverTelegramClarify(ctx) {
|
|
273
343
|
const routing = (await this.opts.sessionIndex.getSessionMetadata(ctx.sessionKey).catch(() => null))?.routing;
|
|
274
344
|
if (!routing || routing.source !== "telegram") return;
|
|
275
345
|
let body = ctx.request.question;
|
|
276
|
-
if (ctx.request.
|
|
346
|
+
if (ctx.request.suggestedAnswer) body += `\n\nSuggested answer (never selected automatically): ${ctx.request.suggestedAnswer}`;
|
|
347
|
+
body += ctx.request.kind === "approval" ? "\n\nFor safety, this approval expires after 10 minutes." : "\n\nThis question remains available until you answer or cancel the task.";
|
|
277
348
|
const choices = ctx.request.choices;
|
|
278
349
|
const buttonRows = choices && choices.length >= 2 ? choices.map((c, i) => [{
|
|
279
350
|
text: c.length > 64 ? `${c.slice(0, 61)}…` : c,
|
|
280
351
|
callback_data: `clarify:${ctx.requestId}:${i}`
|
|
281
352
|
}]) : void 0;
|
|
282
|
-
|
|
353
|
+
body += buttonRows ? "\n\nReply with your answer, or tap an option below." : "\n\nReply with your answer.";
|
|
283
354
|
await this.opts.getChannelManager().send({
|
|
284
355
|
channel: "telegram",
|
|
285
356
|
chat_id: routing.peerId,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createLogger } from "../../utils/logger/index.js";
|
|
2
2
|
import { init_logger } from "../../utils/logger.js";
|
|
3
|
-
import { loadConfig, saveConfig } from "../../config/loader.js";
|
|
4
3
|
import { getModelRegistry } from "../../providers/model-registry.js";
|
|
4
|
+
import { loadConfig, saveConfig } from "../../config/loader.js";
|
|
5
5
|
import { init_providers } from "../../providers/index.js";
|
|
6
6
|
import { disposeAllSessionMcpRuntimes } from "../../agent/mcp/bundle-mcp-runtime.js";
|
|
7
7
|
import { reloadImageGenerationProviders } from "../../agent/image/generation/provider-registry.js";
|
|
@@ -1,6 +1,7 @@
|
|
|
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 { isClarificationSuspended } from "../../storage/sqlite/clarification-wait-repository.js";
|
|
4
5
|
import { updateInteractionStateFromMessage } from "../../storage/sqlite/interaction-state-repository.js";
|
|
5
6
|
import { getConnectionResumeInput, isConnectionSuspended } from "../../storage/sqlite/connection-wait-repository.js";
|
|
6
7
|
import "../../storage/sqlite/index.js";
|
|
@@ -144,9 +145,11 @@ async function* runGatewayAgent(deps, message, channel, chatId, origin, attachme
|
|
|
144
145
|
for await (const event of eventStream) yield* mapper.map(event);
|
|
145
146
|
})();
|
|
146
147
|
for await (const event of coalesceThinkingDeltas(mappedEvents)) yield* emitAndYield([event]);
|
|
147
|
-
const
|
|
148
|
+
const connectionSuspended = isConnectionSuspended(sessionKey, runId);
|
|
149
|
+
const clarificationSuspended = isClarificationSuspended(sessionKey, runId);
|
|
150
|
+
const suspended = connectionSuspended || clarificationSuspended;
|
|
148
151
|
const endStatus = mergedSignal.aborted ? "cancelled" : suspended ? "suspended" : "success";
|
|
149
|
-
const endSummary = mergedSignal.aborted ? "Interrupted" :
|
|
152
|
+
const endSummary = mergedSignal.aborted ? "Interrupted" : connectionSuspended ? "Waiting for connection" : clarificationSuspended ? "Waiting for user input" : "Message processed successfully";
|
|
150
153
|
taskRunStatus = mergedSignal.aborted ? "cancelled" : "succeeded";
|
|
151
154
|
terminalStatus = endStatus;
|
|
152
155
|
taskRunSummary = endSummary;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createLogger } from "../../utils/logger/index.js";
|
|
2
2
|
import { init_logger } from "../../utils/logger.js";
|
|
3
3
|
import { SessionInstanceChangedError, cancelQueuedSessionInput, claimNextSessionInput, findSessionInput, finishSessionInputRun, getSessionInputById, getSessionInputState, insertSessionInput, mutateQueuedSessionInput, recoverSessionInputState, setSessionInputStatus } from "../../storage/sqlite/session-input-repository.js";
|
|
4
|
+
import { consumeClarificationResume, supersedeActiveClarification } from "../../storage/sqlite/clarification-wait-repository.js";
|
|
4
5
|
import { replaceLatestSessionTurnAndQueueInput, validateLatestSessionTurnTarget } from "../../storage/sqlite/session-turn-replace-repository.js";
|
|
5
6
|
import { cancelConnectionObjective, consumeConnectionResume, invalidateConnectionResumeIntent, publishConnectionWait } from "../../storage/sqlite/connection-wait-repository.js";
|
|
6
7
|
import "../../storage/sqlite/index.js";
|
|
@@ -113,6 +114,7 @@ var SessionInputCoordinator = class {
|
|
|
113
114
|
if (result.ok === false) return result;
|
|
114
115
|
if (!result.idempotent) {
|
|
115
116
|
cancelConnectionObjective(sessionKey);
|
|
117
|
+
supersedeActiveClarification(sessionKey);
|
|
116
118
|
const replacement = {
|
|
117
119
|
role: "user",
|
|
118
120
|
content,
|
|
@@ -187,6 +189,7 @@ var SessionInputCoordinator = class {
|
|
|
187
189
|
targetRunId: canSteer ? runtime.activeRunId : void 0
|
|
188
190
|
});
|
|
189
191
|
invalidateConnectionResumeIntent(sessionKey);
|
|
192
|
+
supersedeActiveClarification(sessionKey);
|
|
190
193
|
if (canSteer) {
|
|
191
194
|
if (!await this.deps.steer(sessionKey, content)) {
|
|
192
195
|
setSessionInputStatus(row.id, "queued", {
|
|
@@ -221,7 +224,7 @@ var SessionInputCoordinator = class {
|
|
|
221
224
|
const runId = crypto.randomUUID();
|
|
222
225
|
const input = claimNextSessionInput(sessionKey, runId);
|
|
223
226
|
if (!input) return;
|
|
224
|
-
if (this.deps.beforeExecute && !await this.deps.beforeExecute(input) || !consumeConnectionResume(input)) {
|
|
227
|
+
if (this.deps.beforeExecute && !await this.deps.beforeExecute(input) || !consumeConnectionResume(input) || !consumeClarificationResume(input)) {
|
|
225
228
|
finishSessionInputRun(sessionKey, runId, "cancelled");
|
|
226
229
|
this.publish(sessionKey);
|
|
227
230
|
continue;
|
|
@@ -4,8 +4,8 @@ import { retireSessionMcpRuntimeForSessionKey } from "../../agent/mcp/bundle-mcp
|
|
|
4
4
|
import "../../agent/mcp/bundle-mcp-tools.js";
|
|
5
5
|
import { buildSessionTimeline } from "../../session/transcript-outline.js";
|
|
6
6
|
import { transcriptRowsToClientHistory } from "../../session/client-history.js";
|
|
7
|
-
import { withModelConfigLock } from "../../session/model-config-lock.js";
|
|
8
7
|
import { collectMediaUrisFromValues, deleteMediaUris } from "../../media/session-references.js";
|
|
8
|
+
import { withModelConfigLock } from "../../session/model-config-lock.js";
|
|
9
9
|
import { getDistinctSessionChatIds } from "./session-chat-ids.js";
|
|
10
10
|
import { performSessionReset } from "../session-reset-service.js";
|
|
11
11
|
import { randomUUID } from "node:crypto";
|
|
@@ -81,7 +81,7 @@ export declare class GatewayService {
|
|
|
81
81
|
private stopRealtimeLogBridge;
|
|
82
82
|
/**
|
|
83
83
|
* Webchat agent invocation surface (`runAgent`, `abortAgentRun`, `steer*`,
|
|
84
|
-
*
|
|
84
|
+
* clarification dispatch). Owns the
|
|
85
85
|
* `activeWebchatRunBySession` + `runAbortControllers` maps.
|
|
86
86
|
*/
|
|
87
87
|
readonly agentRunner: GatewayAgentRunner;
|
|
@@ -168,7 +168,9 @@ export declare class GatewayService {
|
|
|
168
168
|
idle: boolean;
|
|
169
169
|
}>;
|
|
170
170
|
getActiveWebchatRunId(sessionKey: string): string | undefined;
|
|
171
|
-
|
|
171
|
+
answerEphemeralClarification(requestId: string, answer: string): boolean;
|
|
172
|
+
getClarificationState(sessionKey: string): import("@xopcai/gateway-contract/src/clarifications.js").ClarificationWaitSnapshot;
|
|
173
|
+
resolveClarificationResponse(input: Parameters<GatewayAgentRunner['resolveClarificationResponse']>[0]): import("../storage/sqlite/clarification-wait-repository.js").ResolveClarificationResult;
|
|
172
174
|
private initializeExtensionLoader;
|
|
173
175
|
private registerExtensionChannelPlugins;
|
|
174
176
|
/**
|
|
@@ -12,16 +12,16 @@ import { getSessionConfig } from "../storage/sqlite/config-repository.js";
|
|
|
12
12
|
import "../storage/sqlite/index.js";
|
|
13
13
|
import { getAgentDefaultModelRef, init_schema } from "../config/schema.js";
|
|
14
14
|
import { init_agent_scope, listAgentEntries, normalizeAgentId, resolveAgentWorkspaceDir, resolveDefaultAgentId } from "../agent/agent-scope.js";
|
|
15
|
-
import { buildSessionKey, init_session_key, sanitizeSegment } from "../routing/session-key.js";
|
|
16
|
-
import { getDefaultAgentId, init_resolve_route } from "../routing/resolve-route.js";
|
|
17
|
-
import { resolveEffectiveAgentProfileForSession } from "../config/agent-profile.js";
|
|
18
15
|
import { init_paths, resolveConfigPath, resolveExtensionsDir } from "../config/paths.js";
|
|
16
|
+
import { prewarmModelRegistry } from "../providers/model-registry.js";
|
|
19
17
|
import { areExtensionsGloballyDisabled } from "../extensions/discover-extensions.js";
|
|
20
18
|
import { buildExtensionMetadataSnapshot } from "../extensions/extension-metadata-snapshot.js";
|
|
21
19
|
import { buildChannelCatalogForConfig, buildChannelCatalogFromSnapshot, init_channel_catalog_service } from "../channels/catalog/channel-catalog-service.js";
|
|
22
20
|
import { loadConfig, saveConfig } from "../config/loader.js";
|
|
23
|
-
import {
|
|
21
|
+
import { buildSessionKey, init_session_key, sanitizeSegment } from "../routing/session-key.js";
|
|
22
|
+
import { getDefaultAgentId, init_resolve_route } from "../routing/resolve-route.js";
|
|
24
23
|
import { init_providers, providers_exports } from "../providers/index.js";
|
|
24
|
+
import { resolveEffectiveAgentProfileForSession } from "../config/agent-profile.js";
|
|
25
25
|
import { TaskRepository } from "../tasks/task-repository.js";
|
|
26
26
|
import { TaskConversationRepository } from "../tasks/task-conversation-repository.js";
|
|
27
27
|
import { getEmbeddedExecutionSession } from "../agent/embedded/execution-context.js";
|
|
@@ -50,10 +50,16 @@ import "../infra/bus/index.js";
|
|
|
50
50
|
import { AgentService } from "../agent/service.js";
|
|
51
51
|
import { ensureStarterAgentsInitialized } from "../agent/starter-agents.js";
|
|
52
52
|
import { setPairingBroadcastSink } from "../channels/pairing/pairing-events.js";
|
|
53
|
-
import {
|
|
53
|
+
import { registerClarificationChannelRuntime } from "./clarify-runtime.js";
|
|
54
54
|
import { ChannelManager } from "../channels/manager.js";
|
|
55
55
|
import { getWorkspacePath } from "../config/workspace-path-helpers.js";
|
|
56
56
|
import "../config/index.js";
|
|
57
|
+
import { DiscussionService } from "../discussions/service.js";
|
|
58
|
+
import { DiscussionOrganizer } from "../discussions/organizer.js";
|
|
59
|
+
import { DiscussionLiveWorker } from "../discussions/live-worker.js";
|
|
60
|
+
import { DiscussionOrganizerWorker } from "../discussions/organizer-worker.js";
|
|
61
|
+
import { DiscussionSealer } from "../discussions/sealer.js";
|
|
62
|
+
import "../discussions/index.js";
|
|
57
63
|
import { ManagedComposioEventPoller } from "../connectors/composio-managed-events.js";
|
|
58
64
|
import { startConnectedKnowledgeCoordinator } from "../knowledge/coordinator.js";
|
|
59
65
|
import "../knowledge/index.js";
|
|
@@ -61,12 +67,6 @@ import { ConnectionRecoveryService } from "../connectors/connection-recovery-ser
|
|
|
61
67
|
import { startConnectorLearningCoordinator } from "../connectors/learning-coordinator.js";
|
|
62
68
|
import { ConnectedSourceChangePublisher } from "../connectors/source-change-publisher.js";
|
|
63
69
|
import { startConnectorSupervisor } from "../connectors/supervisor.js";
|
|
64
|
-
import { DiscussionService } from "../discussions/service.js";
|
|
65
|
-
import { DiscussionOrganizer } from "../discussions/organizer.js";
|
|
66
|
-
import { DiscussionLiveWorker } from "../discussions/live-worker.js";
|
|
67
|
-
import { DiscussionOrganizerWorker } from "../discussions/organizer-worker.js";
|
|
68
|
-
import { DiscussionSealer } from "../discussions/sealer.js";
|
|
69
|
-
import "../discussions/index.js";
|
|
70
70
|
import { EndpointToolRuntime } from "../endpoint-tools/runtime.js";
|
|
71
71
|
import "../endpoint-tools/index.js";
|
|
72
72
|
import { assertGatewayAuthConfigured, extractToken, resolveGatewayAuth, validateToken } from "./auth.js";
|
|
@@ -97,6 +97,7 @@ import { assertGatewayRuntimeConfig } from "./runtime-config.js";
|
|
|
97
97
|
import { auditGatewayConfig } from "./security/audit.js";
|
|
98
98
|
import { getXopcCloudCatalogCoordinator } from "../providers/xopc-cloud-catalog-coordinator.js";
|
|
99
99
|
import { ModelCatalogSyncService } from "../providers/model-catalog-sync-service.js";
|
|
100
|
+
import { collectMediaUrisFromMessages, deleteMediaUris } from "../media/session-references.js";
|
|
100
101
|
import { runBootstrapMigrationsSync } from "../migrations/runner.js";
|
|
101
102
|
import { NotificationService } from "../notifications/service.js";
|
|
102
103
|
import { LocalAppService } from "../local-apps/service.js";
|
|
@@ -268,7 +269,7 @@ var GatewayService = class {
|
|
|
268
269
|
stopRealtimeLogBridge = null;
|
|
269
270
|
/**
|
|
270
271
|
* Webchat agent invocation surface (`runAgent`, `abortAgentRun`, `steer*`,
|
|
271
|
-
*
|
|
272
|
+
* clarification dispatch). Owns the
|
|
272
273
|
* `activeWebchatRunBySession` + `runAbortControllers` maps.
|
|
273
274
|
*/
|
|
274
275
|
agentRunner;
|
|
@@ -465,8 +466,12 @@ var GatewayService = class {
|
|
|
465
466
|
getParentMetadata: (sessionKey) => this.sessionIndex.getSessionMetadata(sessionKey),
|
|
466
467
|
loadParentMessages: (sessionKey) => this.sessionIndex.getStore().load(sessionKey),
|
|
467
468
|
getDefaultModelRef: (sessionKey) => this.ensureAgentService().getModelForSession(sessionKey),
|
|
469
|
+
getDefaultThinkingLevel: (sessionKey) => this.ensureAgentService().getThinkingLevelForSession(sessionKey),
|
|
468
470
|
getWorkspacePath: (metadata) => metadata.cwd || this.currentWorkspacePath,
|
|
469
|
-
onBeforeDispose: (sideChatId, clientInstanceId
|
|
471
|
+
onBeforeDispose: async (sideChatId, clientInstanceId, messages) => {
|
|
472
|
+
await sideChatRuns?.cancelRun(sideChatId, clientInstanceId);
|
|
473
|
+
await deleteMediaUris(collectMediaUrisFromMessages(messages));
|
|
474
|
+
},
|
|
470
475
|
onExpired: (sideChatId, clientInstanceId, reason) => {
|
|
471
476
|
const topic = `side-chat:${clientInstanceId}:${sideChatId}`;
|
|
472
477
|
this.realtime.broker.publish(topic, "expired", { reason });
|
|
@@ -572,10 +577,12 @@ var GatewayService = class {
|
|
|
572
577
|
}
|
|
573
578
|
return null;
|
|
574
579
|
},
|
|
575
|
-
gatewayClarify: { requestClarification: (
|
|
576
|
-
const executionSessionKey = getEmbeddedExecutionSession() ?? sessionKey;
|
|
580
|
+
gatewayClarify: { requestClarification: (context, request) => {
|
|
581
|
+
const executionSessionKey = getEmbeddedExecutionSession() ?? context.sessionKey;
|
|
577
582
|
return this.agentRunner.requestClarification({
|
|
578
583
|
sessionKey: executionSessionKey,
|
|
584
|
+
runId: context.runId,
|
|
585
|
+
toolCallId: context.toolCallId,
|
|
579
586
|
request,
|
|
580
587
|
publishStreamFor: (_runId) => (event) => {
|
|
581
588
|
this._agentService.turnDispatcher.enqueueWebchatStreamEvent(executionSessionKey, event);
|
|
@@ -776,8 +783,14 @@ var GatewayService = class {
|
|
|
776
783
|
getActiveWebchatRunId(sessionKey) {
|
|
777
784
|
return this.agentRunner.getActiveRunId(sessionKey);
|
|
778
785
|
}
|
|
779
|
-
|
|
780
|
-
return this.agentRunner.
|
|
786
|
+
answerEphemeralClarification(requestId, answer) {
|
|
787
|
+
return this.agentRunner.answerEphemeralClarification(requestId, answer);
|
|
788
|
+
}
|
|
789
|
+
getClarificationState(sessionKey) {
|
|
790
|
+
return this.agentRunner.getClarificationState(sessionKey);
|
|
791
|
+
}
|
|
792
|
+
resolveClarificationResponse(input) {
|
|
793
|
+
return this.agentRunner.resolveClarificationResponse(input);
|
|
781
794
|
}
|
|
782
795
|
initializeExtensionLoader() {
|
|
783
796
|
try {
|
|
@@ -925,7 +938,10 @@ var GatewayService = class {
|
|
|
925
938
|
errorMessage: readiness.error.message
|
|
926
939
|
}, `Initial XOPC Cloud catalog refresh failed: ${readiness.error.message}`);
|
|
927
940
|
}
|
|
928
|
-
|
|
941
|
+
registerClarificationChannelRuntime({
|
|
942
|
+
answerChoice: (requestId, choiceIndex, idempotencyKey) => this.agentRunner.answerClarificationChoice(requestId, choiceIndex, idempotencyKey),
|
|
943
|
+
answerText: (sessionKey, text, idempotencyKey) => this.agentRunner.answerClarificationText(sessionKey, text, idempotencyKey)
|
|
944
|
+
});
|
|
929
945
|
this.ensureAgentService();
|
|
930
946
|
this.agentRunner.recoverSessionInputs();
|
|
931
947
|
this.connectionRecovery.start();
|
|
@@ -1242,9 +1258,9 @@ var GatewayService = class {
|
|
|
1242
1258
|
}
|
|
1243
1259
|
this.browserExtensionProvider = null;
|
|
1244
1260
|
this.browserExtensionBindKey = null;
|
|
1245
|
-
|
|
1261
|
+
registerClarificationChannelRuntime(null);
|
|
1246
1262
|
this.connectionRecovery.stop();
|
|
1247
|
-
this.agentRunner.
|
|
1263
|
+
this.agentRunner.disposeClarifications();
|
|
1248
1264
|
await disposeAllSessionMcpRuntimes().catch((err) => {
|
|
1249
1265
|
log.warn({ err }, "MCP runtime shutdown failed");
|
|
1250
1266
|
});
|
|
@@ -11,13 +11,14 @@ export interface EphemeralSideChatManagerOptions {
|
|
|
11
11
|
getParentMetadata: (sessionKey: string) => Promise<SessionMetadata | null>;
|
|
12
12
|
loadParentMessages: (sessionKey: string) => Promise<AgentMessage[]>;
|
|
13
13
|
getDefaultModelRef: (sessionKey: string) => string;
|
|
14
|
+
getDefaultThinkingLevel?: (sessionKey: string) => ThinkingLevel;
|
|
14
15
|
getWorkspacePath: (metadata: SessionMetadata) => string;
|
|
15
16
|
idleTtlMs?: number;
|
|
16
17
|
maxPerClient?: number;
|
|
17
18
|
maxTotal?: number;
|
|
18
19
|
now?: () => number;
|
|
19
20
|
startSweepTimer?: boolean;
|
|
20
|
-
onBeforeDispose?: (sideChatId: string, clientInstanceId: string) => void | Promise<void>;
|
|
21
|
+
onBeforeDispose?: (sideChatId: string, clientInstanceId: string, messages: AgentMessage[]) => void | Promise<void>;
|
|
21
22
|
onExpired?: (sideChatId: string, clientInstanceId: string, reason: 'idle' | 'waiting') => void;
|
|
22
23
|
}
|
|
23
24
|
export declare class EphemeralSideChatManager {
|
|
@@ -90,7 +90,7 @@ var EphemeralSideChatManager = class {
|
|
|
90
90
|
runtime.captureBaseline();
|
|
91
91
|
const config = {
|
|
92
92
|
modelRef: normalizeOptionalString(input.config?.modelRef) || this.options.getDefaultModelRef(parentSessionKey),
|
|
93
|
-
thinkingLevel: input.config?.thinkingLevel
|
|
93
|
+
thinkingLevel: input.config?.thinkingLevel ?? this.options.getDefaultThinkingLevel?.(parentSessionKey) ?? "medium"
|
|
94
94
|
};
|
|
95
95
|
const entry = {
|
|
96
96
|
id,
|
|
@@ -169,10 +169,11 @@ var EphemeralSideChatManager = class {
|
|
|
169
169
|
}
|
|
170
170
|
if (entry.clientInstanceId !== clientInstanceId) return false;
|
|
171
171
|
entry.status = "closing";
|
|
172
|
+
const messages = entry.runtime.loadConversationMessages();
|
|
172
173
|
this.entries.delete(id);
|
|
173
174
|
const cleanup = (async () => {
|
|
174
175
|
try {
|
|
175
|
-
await this.runBeforeDispose(id, clientInstanceId);
|
|
176
|
+
await this.runBeforeDispose(id, clientInstanceId, messages);
|
|
176
177
|
await evictEmbeddedSessionRunner(entry.runtime.runtimeId, "side_chat_dispose");
|
|
177
178
|
return true;
|
|
178
179
|
} finally {
|
|
@@ -255,9 +256,9 @@ var EphemeralSideChatManager = class {
|
|
|
255
256
|
entry.lastActiveAt = new Date(now).toISOString();
|
|
256
257
|
entry.expiresAt = entry.status === "running" ? null : new Date(now + this.idleTtlMs).toISOString();
|
|
257
258
|
}
|
|
258
|
-
async runBeforeDispose(id, clientInstanceId) {
|
|
259
|
+
async runBeforeDispose(id, clientInstanceId, messages) {
|
|
259
260
|
try {
|
|
260
|
-
await this.options.onBeforeDispose?.(id, clientInstanceId);
|
|
261
|
+
await this.options.onBeforeDispose?.(id, clientInstanceId, messages);
|
|
261
262
|
} catch (err) {
|
|
262
263
|
log.warn({
|
|
263
264
|
err,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { AgentService } from '../../agent/service.js';
|
|
2
2
|
import type { GatewayAgentRunner } from '../service/agent-runner.js';
|
|
3
3
|
import { type EphemeralSideChatManager } from './manager.js';
|
|
4
|
+
import type { UserTurnAttachment } from '../user-turn-input.js';
|
|
4
5
|
export interface SideChatRunServiceOptions {
|
|
5
6
|
manager: EphemeralSideChatManager;
|
|
6
7
|
getAgentService: () => AgentService;
|
|
@@ -12,7 +13,10 @@ export declare class SideChatRunService {
|
|
|
12
13
|
private readonly options;
|
|
13
14
|
private readonly activeBySideChat;
|
|
14
15
|
constructor(options: SideChatRunServiceOptions);
|
|
15
|
-
submit(sideChatId: string, clientInstanceId: string,
|
|
16
|
+
submit(sideChatId: string, clientInstanceId: string, input: {
|
|
17
|
+
content: string;
|
|
18
|
+
attachments?: UserTurnAttachment[];
|
|
19
|
+
}): {
|
|
16
20
|
runId: string;
|
|
17
21
|
};
|
|
18
22
|
abort(sideChatId: string, clientInstanceId: string, runId?: string): Promise<boolean>;
|
|
@@ -12,9 +12,9 @@ var SideChatRunService = class {
|
|
|
12
12
|
constructor(options) {
|
|
13
13
|
this.options = options;
|
|
14
14
|
}
|
|
15
|
-
submit(sideChatId, clientInstanceId,
|
|
16
|
-
const text = content.trim();
|
|
17
|
-
if (!text) throw new SideChatError("content
|
|
15
|
+
submit(sideChatId, clientInstanceId, input) {
|
|
16
|
+
const text = input.content.trim();
|
|
17
|
+
if (!text && !input.attachments?.length) throw new SideChatError("content or attachments are required", "INVALID_REQUEST");
|
|
18
18
|
const sideChat = this.options.manager.get(sideChatId, clientInstanceId);
|
|
19
19
|
if (this.activeBySideChat.has(sideChatId)) throw new SideChatError("A side chat run is already active", "CONFLICT");
|
|
20
20
|
const run = {
|
|
@@ -26,7 +26,10 @@ var SideChatRunService = class {
|
|
|
26
26
|
};
|
|
27
27
|
this.activeBySideChat.set(sideChatId, run);
|
|
28
28
|
this.options.manager.setStatus(sideChatId, clientInstanceId, "running", run.runId);
|
|
29
|
-
this.execute(run,
|
|
29
|
+
this.execute(run, {
|
|
30
|
+
content: text,
|
|
31
|
+
attachments: input.attachments
|
|
32
|
+
}, sideChat.config).catch((err) => {
|
|
30
33
|
log.error({
|
|
31
34
|
err,
|
|
32
35
|
sideChatId,
|
|
@@ -55,11 +58,11 @@ var SideChatRunService = class {
|
|
|
55
58
|
}
|
|
56
59
|
submitClarification(sideChatId, clientInstanceId, requestId, answer) {
|
|
57
60
|
if (this.options.manager.get(sideChatId, clientInstanceId).clarification?.requestId !== requestId) return false;
|
|
58
|
-
const handled = this.options.agentRunner.
|
|
61
|
+
const handled = this.options.agentRunner.answerEphemeralClarification(requestId, answer);
|
|
59
62
|
if (handled) this.options.manager.setStatus(sideChatId, clientInstanceId, "running");
|
|
60
63
|
return handled;
|
|
61
64
|
}
|
|
62
|
-
async execute(run,
|
|
65
|
+
async execute(run, input, config) {
|
|
63
66
|
const topic = `run:${run.runId}`;
|
|
64
67
|
const mapper = new ChatStreamMapper({
|
|
65
68
|
runId: run.runId,
|
|
@@ -73,8 +76,10 @@ var SideChatRunService = class {
|
|
|
73
76
|
if (run.abortController.signal.aborted) return;
|
|
74
77
|
if (event.type === "clarify_request") this.options.manager.waitForInput(run.sideChatId, run.clientInstanceId, {
|
|
75
78
|
requestId: String(event.requestId),
|
|
79
|
+
kind: event.kind === "approval" ? "approval" : "input",
|
|
76
80
|
question: String(event.question),
|
|
77
|
-
choices: Array.isArray(event.choices) ? event.choices.filter((choice) => typeof choice === "string") : void 0
|
|
81
|
+
choices: Array.isArray(event.choices) ? event.choices.filter((choice) => typeof choice === "string") : void 0,
|
|
82
|
+
suggestedAnswer: typeof event.suggestedAnswer === "string" ? event.suggestedAnswer : void 0
|
|
78
83
|
}, event.kind === "approval" ? "waiting-approval" : "waiting-input");
|
|
79
84
|
for (const mapped of mapper.map(event)) publish(mapped);
|
|
80
85
|
};
|
|
@@ -82,28 +87,24 @@ var SideChatRunService = class {
|
|
|
82
87
|
for (const event of mapper.start()) publish(event);
|
|
83
88
|
publishMapped({
|
|
84
89
|
type: "user_message",
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
timestamp: Date.now()
|
|
89
|
-
}
|
|
90
|
+
content: input.content,
|
|
91
|
+
media: input.attachments?.map(({ data: _data, ...attachment }) => attachment),
|
|
92
|
+
timestamp: Date.now()
|
|
90
93
|
});
|
|
91
|
-
this.options.agentRunner.registerExternalWebchatRun(run.executionSessionKey, run.runId, (event) => publishMapped(event), {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
} catch {
|
|
98
|
-
return false;
|
|
99
|
-
}
|
|
94
|
+
this.options.agentRunner.registerExternalWebchatRun(run.executionSessionKey, run.runId, (event) => publishMapped(event), { beforeClarificationResponse: () => {
|
|
95
|
+
try {
|
|
96
|
+
this.options.manager.setStatus(run.sideChatId, run.clientInstanceId, "running");
|
|
97
|
+
return true;
|
|
98
|
+
} catch {
|
|
99
|
+
return false;
|
|
100
100
|
}
|
|
101
|
-
});
|
|
101
|
+
} });
|
|
102
102
|
const result = await this.options.getAgentService().runEphemeralTurn({
|
|
103
103
|
executionSessionKey: run.executionSessionKey,
|
|
104
104
|
parentSessionKey: this.options.manager.get(run.sideChatId, run.clientInstanceId).parentSessionKey,
|
|
105
105
|
runId: run.runId,
|
|
106
|
-
content,
|
|
106
|
+
content: input.content,
|
|
107
|
+
attachments: input.attachments,
|
|
107
108
|
modelRef: config.modelRef,
|
|
108
109
|
thinkingLevel: config.thinkingLevel,
|
|
109
110
|
transcriptRuntime: this.options.manager.getRuntime(run.sideChatId, run.clientInstanceId),
|
|
@@ -39,7 +39,7 @@ export interface SideChatContextSnapshot {
|
|
|
39
39
|
}
|
|
40
40
|
export interface SideChatConfig {
|
|
41
41
|
modelRef: string;
|
|
42
|
-
thinkingLevel
|
|
42
|
+
thinkingLevel: ThinkingLevel;
|
|
43
43
|
}
|
|
44
44
|
export interface SideChatView {
|
|
45
45
|
id: string;
|
|
@@ -54,8 +54,10 @@ export interface SideChatView {
|
|
|
54
54
|
runId?: string;
|
|
55
55
|
clarification?: {
|
|
56
56
|
requestId: string;
|
|
57
|
+
kind: 'input' | 'approval';
|
|
57
58
|
question: string;
|
|
58
59
|
choices?: string[];
|
|
60
|
+
suggestedAnswer?: string;
|
|
59
61
|
};
|
|
60
62
|
messageCount: number;
|
|
61
63
|
context: SideChatContextSnapshot;
|