@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
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
//#region src/gateway/ephemeral-clarification-waiter.ts
|
|
2
|
+
/** In-memory waiter exclusively for caller-owned ephemeral runs such as side chat. */
|
|
3
|
+
var EphemeralClarificationWaiter = class {
|
|
4
|
+
pending = /* @__PURE__ */ new Map();
|
|
5
|
+
start(input) {
|
|
6
|
+
const requestId = crypto.randomUUID();
|
|
7
|
+
return new Promise((resolve, reject) => {
|
|
8
|
+
this.pending.set(requestId, {
|
|
9
|
+
runId: input.runId,
|
|
10
|
+
resolve,
|
|
11
|
+
reject,
|
|
12
|
+
beforeResponse: input.beforeResponse
|
|
13
|
+
});
|
|
14
|
+
input.publish({
|
|
15
|
+
type: "clarify_request",
|
|
16
|
+
requestId,
|
|
17
|
+
kind: input.request.kind ?? "input",
|
|
18
|
+
question: input.request.question,
|
|
19
|
+
choices: input.request.choices,
|
|
20
|
+
suggestedAnswer: input.request.suggestedAnswer,
|
|
21
|
+
version: 1,
|
|
22
|
+
createdAt: Date.now()
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
answer(requestId, answer) {
|
|
27
|
+
const pending = this.pending.get(requestId);
|
|
28
|
+
if (!pending || pending.beforeResponse?.() === false) return false;
|
|
29
|
+
this.pending.delete(requestId);
|
|
30
|
+
pending.resolve(answer.trim());
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
cancelForRun(runId) {
|
|
34
|
+
for (const [requestId, pending] of this.pending) {
|
|
35
|
+
if (pending.runId !== runId) continue;
|
|
36
|
+
this.pending.delete(requestId);
|
|
37
|
+
pending.reject(/* @__PURE__ */ new Error("Ephemeral clarification cancelled"));
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
dispose() {
|
|
41
|
+
for (const pending of this.pending.values()) pending.reject(/* @__PURE__ */ new Error("Gateway shutting down"));
|
|
42
|
+
this.pending.clear();
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
//#endregion
|
|
46
|
+
export { EphemeralClarificationWaiter };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { init_paths_state, resolveStateDir } from "../config/paths-state.js";
|
|
2
2
|
import { init_agent_scope, resolveAgentProfileDir } from "../agent/agent-scope.js";
|
|
3
|
-
import { extractProfileAgentId } from "../config/agent-profile.js";
|
|
4
3
|
import { init_paths, resolveConfigPath, resolveSkillsDir } from "../config/paths.js";
|
|
4
|
+
import { extractProfileAgentId } from "../config/agent-profile.js";
|
|
5
5
|
import { isBareProfileMarkdownFileName, resolveProfileMarkdownPathIfBareName } from "../agent/tools/tool-paths.js";
|
|
6
6
|
import { isPathUnderWorkspace, resolveWorkspaceSafePath } from "./workspace-editor-path.js";
|
|
7
7
|
import { basename, isAbsolute, resolve } from "node:path";
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { createLogger } from "../../utils/logger/index.js";
|
|
2
2
|
import { init_logger } from "../../utils/logger.js";
|
|
3
3
|
import { shouldSilence, stripHeartbeatToken } from "../../heartbeat/tokens.js";
|
|
4
|
-
import { appendCronEventLines } from "../../heartbeat/event-prompt.js";
|
|
5
4
|
import { isWithinActiveHours } from "../../heartbeat/active-hours.js";
|
|
6
5
|
import { isHeartbeatContentEmpty } from "../../heartbeat/content-check.js";
|
|
6
|
+
import { appendCronEventLines } from "../../heartbeat/event-prompt.js";
|
|
7
7
|
import { createHeartbeatWake } from "../../heartbeat/wake.js";
|
|
8
8
|
import { resolveHeartbeatMdPath } from "../workspace-heartbeat-path.js";
|
|
9
9
|
import { readFile } from "fs/promises";
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { ContextPlanningConfigSchema, KnowledgeMemoryConfigSchema, UserModelConfigSchema, init_config } from "../../../user-context/config.js";
|
|
2
2
|
import { init_agent_scope, listAgentEntries, normalizeAgentId, resolveDefaultAgentId } from "../../../agent/agent-scope.js";
|
|
3
3
|
import { resolveModelsJsonPath } from "../../../config/paths.js";
|
|
4
|
-
import { buildChannelCatalogForConfig, buildChannelCatalogFromSnapshot, getChannelSetupStatus, init_channel_catalog_service } from "../../../channels/catalog/channel-catalog-service.js";
|
|
5
4
|
import { init_models_json, loadModelsJson } from "../../../config/models-json.js";
|
|
6
5
|
import { CredentialResolver, init_credentials } from "../../../auth/credentials.js";
|
|
6
|
+
import { buildChannelCatalogForConfig, buildChannelCatalogFromSnapshot, getChannelSetupStatus, init_channel_catalog_service } from "../../../channels/catalog/channel-catalog-service.js";
|
|
7
7
|
import { getProviderRegistry, init_plugin_registry } from "../../../providers/plugin-registry.js";
|
|
8
8
|
import { getAllProviders, init_providers, isProviderConfigured } from "../../../providers/index.js";
|
|
9
9
|
import { normalizeConfiguredMcpServers } from "../../../config/mcp-config-normalize.js";
|
|
@@ -122,38 +122,64 @@ function registerAgentStreamRoutes(authenticated, deps) {
|
|
|
122
122
|
payload: result.state
|
|
123
123
|
}, 409);
|
|
124
124
|
});
|
|
125
|
-
authenticated.
|
|
126
|
-
const
|
|
127
|
-
if (!
|
|
128
|
-
ok: false,
|
|
129
|
-
error: {
|
|
130
|
-
code: "BAD_REQUEST",
|
|
131
|
-
message: "Missing requestId"
|
|
132
|
-
}
|
|
133
|
-
}, 400);
|
|
134
|
-
const body = await c.req.json().catch(() => null);
|
|
135
|
-
const skip = body && typeof body === "object" && body.skip === true;
|
|
136
|
-
const rawAnswer = body && typeof body === "object" && typeof body.answer === "string" ? body.answer : "";
|
|
137
|
-
const answer = typeof rawAnswer === "string" ? rawAnswer.trim() : "";
|
|
138
|
-
if (!skip && !answer) return c.json({
|
|
125
|
+
authenticated.get("/api/sessions/:sessionKey/clarification", (c) => {
|
|
126
|
+
const sessionKey = (c.req.param("sessionKey") ?? "").trim();
|
|
127
|
+
if (!sessionKey) return c.json({
|
|
139
128
|
ok: false,
|
|
140
129
|
error: {
|
|
141
130
|
code: "BAD_REQUEST",
|
|
142
|
-
message: "Missing
|
|
131
|
+
message: "Missing sessionKey"
|
|
143
132
|
}
|
|
144
133
|
}, 400);
|
|
145
|
-
|
|
134
|
+
const snapshot = service.getClarificationState(sessionKey);
|
|
135
|
+
if (!snapshot) return c.json({
|
|
146
136
|
ok: false,
|
|
147
137
|
error: {
|
|
148
138
|
code: "NOT_FOUND",
|
|
149
|
-
message: "
|
|
139
|
+
message: "Session not found"
|
|
150
140
|
}
|
|
151
141
|
}, 404);
|
|
152
142
|
return c.json({
|
|
153
143
|
ok: true,
|
|
154
|
-
payload:
|
|
144
|
+
payload: snapshot
|
|
155
145
|
});
|
|
156
146
|
});
|
|
147
|
+
authenticated.post("/api/clarifications/:id/responses", chatRateLimitMiddleware, async (c) => {
|
|
148
|
+
const id = c.req.param("id")?.trim() ?? "";
|
|
149
|
+
const body = await c.req.json().catch(() => null);
|
|
150
|
+
const record = body && typeof body === "object" ? body : {};
|
|
151
|
+
const action = record.action;
|
|
152
|
+
const expectedVersion = record.expectedVersion;
|
|
153
|
+
const idempotencyKey = typeof record.idempotencyKey === "string" ? record.idempotencyKey.trim() : "";
|
|
154
|
+
if (!id || !idempotencyKey || typeof expectedVersion !== "number" || !Number.isInteger(expectedVersion) || action !== "answer" && action !== "agent_decide" && action !== "cancel") return c.json({
|
|
155
|
+
ok: false,
|
|
156
|
+
error: {
|
|
157
|
+
code: "BAD_REQUEST",
|
|
158
|
+
message: "Invalid clarification response"
|
|
159
|
+
}
|
|
160
|
+
}, 400);
|
|
161
|
+
const result = service.resolveClarificationResponse({
|
|
162
|
+
id,
|
|
163
|
+
expectedVersion,
|
|
164
|
+
idempotencyKey,
|
|
165
|
+
action,
|
|
166
|
+
answer: typeof record.answer === "string" ? record.answer : void 0
|
|
167
|
+
});
|
|
168
|
+
if (result.ok === true) return c.json({
|
|
169
|
+
ok: true,
|
|
170
|
+
payload: result
|
|
171
|
+
}, result.queued ? 202 : 200);
|
|
172
|
+
const status = result.code === "NOT_FOUND" ? 404 : result.code === "EXPIRED" ? 410 : result.code === "INVALID" ? 400 : 409;
|
|
173
|
+
const message = result.code === "NOT_FOUND" ? "This clarification is no longer active" : result.code === "EXPIRED" ? "This approval has expired" : result.code === "INVALID" ? "The clarification response is invalid" : "The clarification changed; reload and try again";
|
|
174
|
+
return c.json({
|
|
175
|
+
ok: false,
|
|
176
|
+
error: {
|
|
177
|
+
code: result.code,
|
|
178
|
+
message
|
|
179
|
+
},
|
|
180
|
+
payload: result.clarification
|
|
181
|
+
}, status);
|
|
182
|
+
});
|
|
157
183
|
authenticated.post("/api/send", chatRateLimitMiddleware, async (c) => {
|
|
158
184
|
const body = await c.req.json().catch(() => null);
|
|
159
185
|
const channel = typeof body?.channel === "string" ? body.channel : "";
|
|
@@ -1,9 +1,52 @@
|
|
|
1
1
|
import { decideBrowserApproval, listBrowserApprovals } from "../../../browser/policy/approval-store.js";
|
|
2
|
+
import { createBrowserDriver } from "../../../browser/drivers/create-driver.js";
|
|
3
|
+
import { checkBrowserReadiness } from "../../../browser/readiness.js";
|
|
2
4
|
import { isLoopbackClientIp } from "../../security/loopback.js";
|
|
3
5
|
import { getConnInfo } from "@hono/node-server/conninfo";
|
|
4
6
|
//#region src/gateway/hono/routes/browser.ts
|
|
5
7
|
/** Browser Control status, approvals, and driver diagnostics. */
|
|
6
8
|
const EXTENSION_ENDPOINT = "http://127.0.0.1:19820/";
|
|
9
|
+
async function extensionStatus() {
|
|
10
|
+
const { getExtensionBrowserServerSnapshot } = await import("../../../browser/providers/extension-ws-acquire.js");
|
|
11
|
+
const snapshot = getExtensionBrowserServerSnapshot();
|
|
12
|
+
let running = snapshot.active;
|
|
13
|
+
let socketConnected = false;
|
|
14
|
+
let connected = false;
|
|
15
|
+
let protocolVersion = null;
|
|
16
|
+
let expectedProtocolVersion = null;
|
|
17
|
+
let extensionVersion = null;
|
|
18
|
+
try {
|
|
19
|
+
const payload = await (await fetch(EXTENSION_ENDPOINT, { signal: AbortSignal.timeout(2e3) })).json();
|
|
20
|
+
running ||= payload.ok === true;
|
|
21
|
+
socketConnected = payload.socketConnected ?? payload.connected === true;
|
|
22
|
+
connected = payload.connected === true;
|
|
23
|
+
protocolVersion = typeof payload.protocolVersion === "number" ? payload.protocolVersion : null;
|
|
24
|
+
expectedProtocolVersion = typeof payload.expectedProtocolVersion === "number" ? payload.expectedProtocolVersion : null;
|
|
25
|
+
extensionVersion = typeof payload.extensionVersion === "string" ? payload.extensionVersion : null;
|
|
26
|
+
} catch {}
|
|
27
|
+
const { browserExtDoctor } = await import("../../../browser/providers/browser-ext-install.js");
|
|
28
|
+
const doctor = await browserExtDoctor({ runtimeExtensionVersion: extensionVersion ?? void 0 });
|
|
29
|
+
return {
|
|
30
|
+
running,
|
|
31
|
+
socketConnected,
|
|
32
|
+
connected,
|
|
33
|
+
driverKind: "extension",
|
|
34
|
+
protocolVersion,
|
|
35
|
+
expectedProtocolVersion,
|
|
36
|
+
extensionVersion,
|
|
37
|
+
artifacts: {
|
|
38
|
+
installed: doctor.installed,
|
|
39
|
+
bundledAvailable: doctor.bundledAvailable,
|
|
40
|
+
extensionDir: doctor.extensionDir,
|
|
41
|
+
xopcVersion: doctor.xopcVersion,
|
|
42
|
+
installedVersion: doctor.installedVersion,
|
|
43
|
+
needsRefresh: doctor.needsRefresh,
|
|
44
|
+
needsChromeReload: doctor.needsChromeReload || socketConnected && !connected
|
|
45
|
+
},
|
|
46
|
+
bridgeHeld: snapshot.active,
|
|
47
|
+
refCount: snapshot.refCount
|
|
48
|
+
};
|
|
49
|
+
}
|
|
7
50
|
function isLocalOwnerRequest(c, service) {
|
|
8
51
|
if (service.currentConfig.gateway?.bind === "loopback") return true;
|
|
9
52
|
try {
|
|
@@ -15,37 +58,116 @@ function isLocalOwnerRequest(c, service) {
|
|
|
15
58
|
function registerBrowserRoutes(authenticated, deps) {
|
|
16
59
|
const { service, strictRateLimitMiddleware } = deps;
|
|
17
60
|
authenticated.get("/api/browser/extension-status", async (c) => {
|
|
18
|
-
const { getExtensionBrowserServerSnapshot } = await import("../../../browser/providers/extension-ws-acquire.js");
|
|
19
|
-
const snapshot = getExtensionBrowserServerSnapshot();
|
|
20
|
-
let running = snapshot.active;
|
|
21
|
-
let connected = false;
|
|
22
61
|
try {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
62
|
+
return c.json(await extensionStatus());
|
|
63
|
+
} catch (error) {
|
|
64
|
+
return c.json({
|
|
65
|
+
running: false,
|
|
66
|
+
connected: false,
|
|
67
|
+
driverKind: "extension",
|
|
68
|
+
error: error instanceof Error ? error.message : String(error)
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
authenticated.get("/api/browser/status", async (c) => {
|
|
73
|
+
const config = service.currentConfig.browser;
|
|
74
|
+
if (!config.enabled) return c.json({
|
|
75
|
+
ok: true,
|
|
76
|
+
payload: {
|
|
77
|
+
enabled: false,
|
|
78
|
+
driverKind: config.driver.kind,
|
|
79
|
+
state: "disabled"
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
const readiness = await checkBrowserReadiness(service.currentConfig);
|
|
83
|
+
const driverStatus = config.driver.kind === "extension" ? await extensionStatus().catch((error) => ({ error: error instanceof Error ? error.message : String(error) })) : config.driver.kind === "playwright" ? await import("../../../browser/providers/playwright-doctor.js").then(({ playwrightChromiumDoctor }) => playwrightChromiumDoctor()) : void 0;
|
|
84
|
+
const extensionConnected = config.driver.kind === "extension" ? driverStatus.connected === true : true;
|
|
85
|
+
const extensionProtocolDetail = config.driver.kind === "extension" && "socketConnected" in driverStatus && driverStatus.socketConnected && !driverStatus.connected ? `Chrome extension protocol ${driverStatus.protocolVersion ?? "unknown"} does not match ${driverStatus.expectedProtocolVersion ?? "the gateway"}. Reload the extension in Chrome.` : void 0;
|
|
40
86
|
return c.json({
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
87
|
+
ok: true,
|
|
88
|
+
payload: {
|
|
89
|
+
enabled: true,
|
|
90
|
+
driverKind: config.driver.kind,
|
|
91
|
+
state: !readiness && extensionConnected ? "ready" : "needs_attention",
|
|
92
|
+
reason: readiness?.hint.reason ?? (extensionConnected ? void 0 : "extension_not_connected"),
|
|
93
|
+
detail: readiness?.hint.detail ?? extensionProtocolDetail,
|
|
94
|
+
driverStatus
|
|
95
|
+
}
|
|
47
96
|
});
|
|
48
97
|
});
|
|
98
|
+
authenticated.post("/api/browser/test", strictRateLimitMiddleware, async (c) => {
|
|
99
|
+
if (!isLocalOwnerRequest(c, service)) return c.json({
|
|
100
|
+
ok: false,
|
|
101
|
+
error: "Local owner access required."
|
|
102
|
+
}, 403);
|
|
103
|
+
if (!service.currentConfig.browser.enabled) return c.json({
|
|
104
|
+
ok: false,
|
|
105
|
+
error: "Browser Control is disabled."
|
|
106
|
+
}, 400);
|
|
107
|
+
const startedAt = Date.now();
|
|
108
|
+
let driver;
|
|
109
|
+
try {
|
|
110
|
+
driver = await createBrowserDriver(service.currentConfig.browser);
|
|
111
|
+
await driver.connect();
|
|
112
|
+
return c.json({
|
|
113
|
+
ok: true,
|
|
114
|
+
payload: {
|
|
115
|
+
driverKind: service.currentConfig.browser.driver.kind,
|
|
116
|
+
durationMs: Date.now() - startedAt
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
} catch (error) {
|
|
120
|
+
return c.json({
|
|
121
|
+
ok: false,
|
|
122
|
+
error: error instanceof Error ? error.message : String(error)
|
|
123
|
+
}, 400);
|
|
124
|
+
} finally {
|
|
125
|
+
await driver?.disconnect().catch(() => {});
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
authenticated.post("/api/browser/extension/install", strictRateLimitMiddleware, async (c) => {
|
|
129
|
+
if (!isLocalOwnerRequest(c, service)) return c.json({
|
|
130
|
+
ok: false,
|
|
131
|
+
error: "Local owner access required."
|
|
132
|
+
}, 403);
|
|
133
|
+
const body = await c.req.json().catch(() => ({}));
|
|
134
|
+
try {
|
|
135
|
+
const { browserExtDoctor, ensureBrowserExtensionArtifacts } = await import("../../../browser/providers/browser-ext-install.js");
|
|
136
|
+
const result = await ensureBrowserExtensionArtifacts({ force: body.force === true });
|
|
137
|
+
return c.json({
|
|
138
|
+
ok: true,
|
|
139
|
+
payload: {
|
|
140
|
+
...result,
|
|
141
|
+
doctor: await browserExtDoctor()
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
} catch (error) {
|
|
145
|
+
return c.json({
|
|
146
|
+
ok: false,
|
|
147
|
+
error: error instanceof Error ? error.message : String(error)
|
|
148
|
+
}, 500);
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
authenticated.post("/api/browser/extension/open", strictRateLimitMiddleware, async (c) => {
|
|
152
|
+
if (!isLocalOwnerRequest(c, service)) return c.json({
|
|
153
|
+
ok: false,
|
|
154
|
+
error: "Local owner access required."
|
|
155
|
+
}, 403);
|
|
156
|
+
const body = await c.req.json().catch(() => ({}));
|
|
157
|
+
const action = body.action === "chrome" || body.action === "folder" || body.action === "both" ? body.action : "both";
|
|
158
|
+
try {
|
|
159
|
+
const { openBrowserExtensionInstallUi } = await import("../../../browser/providers/browser-ext-install.js");
|
|
160
|
+
return c.json({
|
|
161
|
+
ok: true,
|
|
162
|
+
payload: await openBrowserExtensionInstallUi({ action })
|
|
163
|
+
});
|
|
164
|
+
} catch (error) {
|
|
165
|
+
return c.json({
|
|
166
|
+
ok: false,
|
|
167
|
+
error: error instanceof Error ? error.message : String(error)
|
|
168
|
+
}, 400);
|
|
169
|
+
}
|
|
170
|
+
});
|
|
49
171
|
authenticated.get("/api/browser/approvals", (c) => {
|
|
50
172
|
if (!isLocalOwnerRequest(c, service)) return c.json({
|
|
51
173
|
ok: false,
|
|
@@ -53,7 +53,7 @@ const AUTHENTICATED_LAZY_ROUTE_BUNDLES = [
|
|
|
53
53
|
},
|
|
54
54
|
{
|
|
55
55
|
id: "browser-install",
|
|
56
|
-
match: (path) => path === "/api/browser/playwright/install/stream",
|
|
56
|
+
match: (path) => path === "/api/browser/playwright/install/stream" || path === "/api/browser/playwright/install/cancel",
|
|
57
57
|
load: async () => {
|
|
58
58
|
const { registerBrowserInstallRoutes } = await import("./browser-install.js");
|
|
59
59
|
return { register: registerBrowserInstallRoutes };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { resolveModelsJsonPath } from "../../../config/paths.js";
|
|
2
1
|
import { init_resolve_config_value, testApiKeyResolution } from "../../../config/resolve-config-value.js";
|
|
2
|
+
import { resolveModelsJsonPath } from "../../../config/paths.js";
|
|
3
3
|
import { init_models_json, loadModelsJson, saveModelsJson, validateModelsConfig } from "../../../config/models-json.js";
|
|
4
4
|
import { getModelCatalogStore, init_model_catalog_store } from "../../../providers/model-catalog-store.js";
|
|
5
5
|
import { getModelRegistry } from "../../../providers/model-registry.js";
|
|
@@ -45,11 +45,15 @@ export declare function submitSessionInput(c: Context, deps: AuthenticatedRouteD
|
|
|
45
45
|
status: import("../../../storage/sqlite/session-input-repository.js").SessionInputStatus;
|
|
46
46
|
content: string;
|
|
47
47
|
taskRunId?: string;
|
|
48
|
-
kind: "message" | "connection_resume";
|
|
48
|
+
kind: "message" | "connection_resume" | "clarification_resume";
|
|
49
49
|
payload?: {
|
|
50
50
|
waitId: string;
|
|
51
51
|
objectiveRevision: number;
|
|
52
52
|
resolution: "continued" | "skipped";
|
|
53
|
+
} | {
|
|
54
|
+
waitId: string;
|
|
55
|
+
objectiveRevision: number;
|
|
56
|
+
resolution: "answered" | "agent_decide" | "cancelled";
|
|
53
57
|
};
|
|
54
58
|
attachments?: import("hono/dist/types/utils/types.js").JSONValue[];
|
|
55
59
|
contextRefs?: {
|
|
@@ -141,11 +145,15 @@ export declare function replaceLatestSessionTurn(c: Context, deps: Authenticated
|
|
|
141
145
|
status: import("../../../storage/sqlite/session-input-repository.js").SessionInputStatus;
|
|
142
146
|
content: string;
|
|
143
147
|
taskRunId?: string;
|
|
144
|
-
kind: "message" | "connection_resume";
|
|
148
|
+
kind: "message" | "connection_resume" | "clarification_resume";
|
|
145
149
|
payload?: {
|
|
146
150
|
waitId: string;
|
|
147
151
|
objectiveRevision: number;
|
|
148
152
|
resolution: "continued" | "skipped";
|
|
153
|
+
} | {
|
|
154
|
+
waitId: string;
|
|
155
|
+
objectiveRevision: number;
|
|
156
|
+
resolution: "answered" | "agent_decide" | "cancelled";
|
|
149
157
|
};
|
|
150
158
|
attachments?: import("hono/dist/types/utils/types.js").JSONValue[];
|
|
151
159
|
contextRefs?: {
|
|
@@ -1,9 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { chooseModelThinking } from "../../../../packages/gateway-contract/src/model-selection.js";
|
|
2
|
+
import { init_providers, resolveModel } from "../../../providers/index.js";
|
|
3
|
+
import { getModelThinking } from "../../../providers/model-thinking.js";
|
|
4
|
+
import { validateWebchatAttachments, validateWebchatContent } from "../../chat-limits.js";
|
|
2
5
|
import { validateSideChatSelections } from "../../side-chat/context-snapshot.js";
|
|
3
6
|
import { SideChatError, parseThinkingLevel } from "../../side-chat/manager.js";
|
|
4
7
|
import "../../side-chat/index.js";
|
|
5
8
|
import { createGatewayRouteLogger, logRouteError } from "../lib/route-logger.js";
|
|
6
9
|
//#region src/gateway/hono/routes/side-chats.ts
|
|
10
|
+
init_providers();
|
|
7
11
|
const CLIENT_HEADER = "x-xopc-client-instance-id";
|
|
8
12
|
const log = createGatewayRouteLogger("SideChats");
|
|
9
13
|
function registerSideChatRoutes(authenticated, deps) {
|
|
@@ -64,9 +68,18 @@ function registerSideChatRoutes(authenticated, deps) {
|
|
|
64
68
|
const body = await c.req.json().catch(() => ({}));
|
|
65
69
|
if (body.modelRef !== void 0 && typeof body.modelRef !== "string") throw new SideChatError("modelRef must be a string", "INVALID_REQUEST");
|
|
66
70
|
const modelRef = typeof body.modelRef === "string" ? body.modelRef : void 0;
|
|
71
|
+
const current = service.sideChats.get(c.req.param("sideChatId"), readClientInstanceId(c, body.clientInstanceId));
|
|
72
|
+
const nextModelRef = modelRef ?? current.config.modelRef;
|
|
73
|
+
let thinking;
|
|
74
|
+
try {
|
|
75
|
+
thinking = getModelThinking(resolveModel(nextModelRef));
|
|
76
|
+
} catch {
|
|
77
|
+
throw new SideChatError(`Model unavailable: ${nextModelRef}`, "INVALID_REQUEST");
|
|
78
|
+
}
|
|
79
|
+
const requestedThinking = parseThinkingLevel(body.thinkingLevel);
|
|
67
80
|
const sideChat = service.sideChats.updateConfig(c.req.param("sideChatId"), readClientInstanceId(c, body.clientInstanceId), {
|
|
68
|
-
modelRef,
|
|
69
|
-
thinkingLevel:
|
|
81
|
+
modelRef: nextModelRef,
|
|
82
|
+
thinkingLevel: chooseModelThinking(thinking, requestedThinking ?? current.config.thinkingLevel)
|
|
70
83
|
});
|
|
71
84
|
return c.json({
|
|
72
85
|
ok: true,
|
|
@@ -101,9 +114,16 @@ function registerSideChatRoutes(authenticated, deps) {
|
|
|
101
114
|
try {
|
|
102
115
|
const body = await c.req.json().catch(() => ({}));
|
|
103
116
|
const content = typeof body.content === "string" ? body.content : "";
|
|
117
|
+
const attachments = Array.isArray(body.attachments) ? body.attachments : void 0;
|
|
104
118
|
const contentError = validateWebchatContent(content);
|
|
105
119
|
if (contentError) throw new SideChatError(contentError, "INVALID_REQUEST");
|
|
106
|
-
const
|
|
120
|
+
const attachmentError = validateWebchatAttachments(attachments);
|
|
121
|
+
if (attachmentError) throw new SideChatError(attachmentError, "INVALID_REQUEST");
|
|
122
|
+
if (!content.trim() && !attachments?.length) throw new SideChatError("content or attachments are required", "INVALID_REQUEST");
|
|
123
|
+
const result = service.sideChatRuns.submit(c.req.param("sideChatId"), readClientInstanceId(c, body.clientInstanceId), {
|
|
124
|
+
content,
|
|
125
|
+
attachments
|
|
126
|
+
});
|
|
107
127
|
return c.json({
|
|
108
128
|
ok: true,
|
|
109
129
|
payload: result
|
|
@@ -57,7 +57,7 @@ function requiredGatewayScope(method, path) {
|
|
|
57
57
|
if (path.startsWith("/api/home") || path.startsWith("/api/inbox")) return methodScope(method, "tasks.read", "tasks.write");
|
|
58
58
|
if (path.startsWith("/api/automations") || path.startsWith("/api/automation-runs")) return methodScope(method, "automations.read", "automations.write");
|
|
59
59
|
if (path.startsWith("/api/workflows")) return methodScope(method, "automations.read", "automations.write");
|
|
60
|
-
if (path.startsWith("/api/voice") || path.startsWith("/api/media") || path.startsWith("/api/
|
|
60
|
+
if (path.startsWith("/api/voice") || path.startsWith("/api/media") || path.startsWith("/api/clarifications")) return "sessions.write";
|
|
61
61
|
if (path.startsWith("/api/commands") || path.startsWith("/api/skills")) return methodScope(method, "agents.read", "gateway.admin");
|
|
62
62
|
if (path.startsWith("/api/workspace") || path.startsWith("/api/files") || path.startsWith("/api/projects") || path.startsWith("/api/notes") || path.startsWith("/api/shares")) return methodScope(method, "workspace.read", "workspace.write");
|
|
63
63
|
return "gateway.admin";
|
|
@@ -1,31 +1,12 @@
|
|
|
1
1
|
import type { TurnOrigin } from '@xopcai/endpoint-tools-protocol';
|
|
2
|
-
|
|
3
|
-
* GatewayAgentRunner — webchat agent invocation and the surrounding control
|
|
4
|
-
* surface (abort, steer, clarify-bridge plumbing, scheduled Task continuations).
|
|
5
|
-
*
|
|
6
|
-
* Was 200 lines of `GatewayService` covering seven concerns that all hung off
|
|
7
|
-
* the same handful of fields (`activeWebchatRunBySession`, `runAbortControllers`,
|
|
8
|
-
* `clarifyBridge`, `runRelay`):
|
|
9
|
-
*
|
|
10
|
-
* - `runAgent(message, channel, chatId, ...)` — wraps {@link runGatewayAgent}
|
|
11
|
-
* - `abortAgentRun(runId)` — POST /api/agent/abort + cleanup
|
|
12
|
-
* - `submitClarifyResponse(requestId, answer)` — UI answers a `clarify` call
|
|
13
|
-
* - `runScheduledWebchatTurn(sk, userTurn)` — background webchat user turn
|
|
14
|
-
* - `drainScheduledWebchatContinuation(sk, msg)` — background Task continuation
|
|
15
|
-
* - `clarifyForSession({ sessionKey, request })` — clarify-bridge dispatch
|
|
16
|
-
* used by `gatewayClarify.requestClarification` in AgentService
|
|
17
|
-
*
|
|
18
|
-
* Owns the two state maps (`activeWebchatRunBySession`, `runAbortControllers`)
|
|
19
|
-
* directly so peer coordinators (sessions-api, marketplace, config) cannot
|
|
20
|
-
* accidentally mutate them.
|
|
21
|
-
*/
|
|
2
|
+
import type { ClarificationResponseAction } from '@xopcai/gateway-contract';
|
|
22
3
|
import type { Config } from '../../config/schema.js';
|
|
23
4
|
import type { MessageBus } from '../../infra/bus/index.js';
|
|
24
5
|
import type { AgentService } from '../../agent/service.js';
|
|
25
6
|
import type { ChannelManager } from '../../channels/manager.js';
|
|
26
7
|
import type { SessionIndex } from '../../session/index.js';
|
|
27
|
-
import type
|
|
28
|
-
import {
|
|
8
|
+
import { type ClarificationStreamEvent } from '../ephemeral-clarification-waiter.js';
|
|
9
|
+
import type { ClarifyRequestPayload, ClarifyRequestResult } from '../../agent/tools/clarify-tool.js';
|
|
29
10
|
import type { UserTurnAttachment, UserTurnInput } from '../user-turn-input.js';
|
|
30
11
|
import type { AgentSourceContext, TurnContextRef } from '../../agent/source-context/types.js';
|
|
31
12
|
import { SessionInputCoordinator, type ReplaceLatestTurnInput, type SubmitSessionInput } from './session-input-coordinator.js';
|
|
@@ -49,11 +30,10 @@ export declare class GatewayAgentRunner {
|
|
|
49
30
|
private readonly runAbortControllers;
|
|
50
31
|
private readonly runCompletions;
|
|
51
32
|
private readonly resolveRunCompletions;
|
|
52
|
-
private readonly
|
|
33
|
+
private readonly ephemeralClarifications;
|
|
53
34
|
/** Maps webchat session key → active `runId` for `clarify` tool routing. */
|
|
54
35
|
private readonly activeWebchatRunBySession;
|
|
55
36
|
private readonly externalStreamBySession;
|
|
56
|
-
private readonly externalClarificationTimeouts;
|
|
57
37
|
private readonly externalClarificationResponses;
|
|
58
38
|
readonly inputs: SessionInputCoordinator;
|
|
59
39
|
private readonly unsubscribeConnectionWait;
|
|
@@ -65,11 +45,8 @@ export declare class GatewayAgentRunner {
|
|
|
65
45
|
sessionKey: string;
|
|
66
46
|
runId: string;
|
|
67
47
|
}>;
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
disposeClarifyBridge(): void;
|
|
71
|
-
registerExternalWebchatRun(sessionKey: string, runId: string, publish: (event: ClarifyStreamEvent) => void, options?: {
|
|
72
|
-
clarificationTimeoutMs?: number | null;
|
|
48
|
+
disposeClarifications(): void;
|
|
49
|
+
registerExternalWebchatRun(sessionKey: string, runId: string, publish: (event: ClarificationStreamEvent) => void, options?: {
|
|
73
50
|
beforeClarificationResponse?: () => boolean;
|
|
74
51
|
}): void;
|
|
75
52
|
unregisterExternalWebchatRun(sessionKey: string, runId: string): void;
|
|
@@ -126,16 +103,26 @@ export declare class GatewayAgentRunner {
|
|
|
126
103
|
aborted: boolean;
|
|
127
104
|
idle: boolean;
|
|
128
105
|
}>;
|
|
129
|
-
|
|
130
|
-
|
|
106
|
+
answerEphemeralClarification(requestId: string, answer: string): boolean;
|
|
107
|
+
getClarificationState(sessionKey: string): import("@xopcai/gateway-contract").ClarificationWaitSnapshot;
|
|
108
|
+
resolveClarificationResponse(input: {
|
|
109
|
+
id: string;
|
|
110
|
+
expectedVersion: number;
|
|
111
|
+
idempotencyKey: string;
|
|
112
|
+
action: ClarificationResponseAction;
|
|
113
|
+
answer?: string;
|
|
114
|
+
}): import("../../storage/sqlite/clarification-wait-repository.js").ResolveClarificationResult;
|
|
115
|
+
getClarificationById(id: string): import("@xopcai/gateway-contract").ClarificationWait;
|
|
116
|
+
answerClarificationChoice(requestId: string, choiceIndex: number, idempotencyKey: string): boolean;
|
|
117
|
+
answerClarificationText(sessionKey: string, answer: string, idempotencyKey: string): boolean;
|
|
131
118
|
/** Same execution path as scheduled continuation, but lets callers observe failures. */
|
|
132
119
|
runScheduledWebchatTurn(sessionKey: string, userTurn: UserTurnInput): Promise<void>;
|
|
133
120
|
runScheduledWebchatContinuation(sessionKey: string, message: string): Promise<void>;
|
|
134
121
|
/** Background drain for extension-initiated webchat turns (`scheduleWebchatContinuation`). */
|
|
135
122
|
drainScheduledWebchatContinuation(sessionKey: string, message: string): Promise<void>;
|
|
136
123
|
/**
|
|
137
|
-
*
|
|
138
|
-
*
|
|
124
|
+
* Persist normal clarification waits and use the lifecycle-bound waiter only
|
|
125
|
+
* for caller-owned ephemeral sessions.
|
|
139
126
|
* Rejects when neither path is available (e.g. CLI without webchat or TG).
|
|
140
127
|
*
|
|
141
128
|
* `publishStreamFor(runId)` is the bridge into AgentService's
|
|
@@ -144,8 +131,10 @@ export declare class GatewayAgentRunner {
|
|
|
144
131
|
*/
|
|
145
132
|
requestClarification(opts: {
|
|
146
133
|
sessionKey: string;
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
134
|
+
runId: string;
|
|
135
|
+
toolCallId: string;
|
|
136
|
+
request: ClarifyRequestPayload;
|
|
137
|
+
publishStreamFor: (runId: string) => (event: ClarificationStreamEvent) => void;
|
|
138
|
+
}): Promise<ClarifyRequestResult>;
|
|
150
139
|
private deliverTelegramClarify;
|
|
151
140
|
}
|