neoagent 3.2.1-beta.1 → 3.2.1-beta.11
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/extensions/chrome-browser/background.mjs +318 -88
- package/extensions/chrome-browser/http.mjs +136 -0
- package/extensions/chrome-browser/protocol.mjs +654 -90
- package/flutter_app/lib/main_chat.dart +118 -739
- package/flutter_app/lib/main_controller.dart +157 -24
- package/flutter_app/lib/main_integrations.dart +607 -8
- package/flutter_app/lib/main_models.dart +7 -2
- package/flutter_app/lib/main_operations.dart +334 -370
- package/flutter_app/lib/main_security.dart +266 -112
- package/flutter_app/lib/main_settings.dart +342 -3
- package/flutter_app/lib/main_shared.dart +14 -11
- package/flutter_app/lib/src/backend_client.dart +97 -0
- package/flutter_app/lib/src/desktop_companion_actions.dart +185 -31
- package/flutter_app/lib/src/desktop_companion_io.dart +319 -86
- package/flutter_app/windows/runner/flutter_window.cpp +143 -32
- package/landing/index.html +3 -1
- package/lib/manager.js +106 -89
- package/lib/schema_migrations.js +115 -13
- package/package.json +30 -15
- package/runtime/paths.js +49 -5
- package/server/db/database.js +2 -2
- package/server/guest-agent.cli.package.json +13 -0
- package/server/guest_agent.js +85 -40
- package/server/http/middleware.js +24 -0
- package/server/http/routes.js +12 -6
- package/server/public/.last_build_id +1 -1
- package/server/public/assets/fonts/MaterialIcons-Regular.otf +0 -0
- package/server/public/flutter_bootstrap.js +2 -2
- package/server/public/main.dart.js +81930 -80509
- package/server/routes/admin.js +1 -1
- package/server/routes/android.js +30 -34
- package/server/routes/behavior.js +80 -0
- package/server/routes/browser.js +23 -15
- package/server/routes/desktop.js +18 -1
- package/server/routes/integrations.js +107 -1
- package/server/routes/memory.js +1 -0
- package/server/routes/settings.js +20 -5
- package/server/routes/social_reach.js +12 -3
- package/server/routes/social_video.js +4 -0
- package/server/services/agents/manager.js +1 -1
- package/server/services/ai/capabilityHealth.js +62 -96
- package/server/services/ai/compaction.js +7 -2
- package/server/services/ai/history.js +45 -6
- package/server/services/ai/integrated_tools/http_request.js +8 -0
- package/server/services/ai/loop/agent_engine_core.js +452 -176
- package/server/services/ai/loop/blank_recovery.js +5 -4
- package/server/services/ai/loop/callbacks.js +1 -0
- package/server/services/ai/loop/completion_judge.js +291 -8
- package/server/services/ai/loop/conversation_loop.js +515 -342
- package/server/services/ai/loop/messaging_delivery.js +176 -57
- package/server/services/ai/loop/model_call_guard.js +91 -0
- package/server/services/ai/loop/model_io.js +20 -45
- package/server/services/ai/loop/progress_classification.js +2 -0
- package/server/services/ai/loop/tool_dispatch.js +19 -8
- package/server/services/ai/loopPolicy.js +48 -21
- package/server/services/ai/messagingFallback.js +17 -17
- package/server/services/ai/model_discovery.js +227 -0
- package/server/services/ai/model_failure_cache.js +108 -0
- package/server/services/ai/model_identity.js +71 -0
- package/server/services/ai/models.js +68 -163
- package/server/services/ai/providerRetry.js +17 -59
- package/server/services/ai/provider_selector.js +166 -0
- package/server/services/ai/providers/anthropic.js +2 -2
- package/server/services/ai/providers/claudeCode.js +21 -33
- package/server/services/ai/providers/githubCopilot.js +41 -20
- package/server/services/ai/providers/google.js +135 -97
- package/server/services/ai/providers/grok.js +4 -3
- package/server/services/ai/providers/grokOauth.js +19 -27
- package/server/services/ai/providers/nvidia.js +10 -5
- package/server/services/ai/providers/ollama.js +111 -84
- package/server/services/ai/providers/ollama_stream.js +142 -0
- package/server/services/ai/providers/openai.js +39 -5
- package/server/services/ai/providers/openaiCodex.js +11 -4
- package/server/services/ai/providers/openrouter.js +29 -7
- package/server/services/ai/providers/provider_error.js +36 -0
- package/server/services/ai/settings.js +26 -2
- package/server/services/ai/systemPrompt.js +32 -123
- package/server/services/ai/taskAnalysis.js +104 -11
- package/server/services/ai/toolEvidence.js +256 -29
- package/server/services/ai/tools.js +248 -117
- package/server/services/android/controller.js +770 -237
- package/server/services/android/process.js +140 -0
- package/server/services/android/sdk_download.js +143 -0
- package/server/services/android/uia.js +6 -5
- package/server/services/artifacts/store.js +24 -0
- package/server/services/behavior/config.js +251 -0
- package/server/services/behavior/defaults.js +68 -0
- package/server/services/behavior/delivery.js +176 -0
- package/server/services/behavior/index.js +43 -0
- package/server/services/behavior/model_client.js +35 -0
- package/server/services/behavior/modules/agent_identity.js +37 -0
- package/server/services/behavior/modules/channel_style.js +28 -0
- package/server/services/behavior/modules/index.js +29 -0
- package/server/services/behavior/modules/norms.js +101 -0
- package/server/services/behavior/modules/persona.js +48 -0
- package/server/services/behavior/modules/persona_prompt.js +33 -0
- package/server/services/behavior/modules/social_memory.js +86 -0
- package/server/services/behavior/modules/social_observability.js +94 -0
- package/server/services/behavior/modules/social_signals.js +41 -0
- package/server/services/behavior/modules/theory_of_mind.js +110 -0
- package/server/services/behavior/modules/turn_taking.js +237 -0
- package/server/services/behavior/pipeline.js +285 -0
- package/server/services/behavior/registry.js +78 -0
- package/server/services/behavior/signals.js +107 -0
- package/server/services/behavior/state.js +99 -0
- package/server/services/behavior/system_prompt.js +75 -0
- package/server/services/browser/controller.js +843 -385
- package/server/services/browser/extension/gateway.js +40 -16
- package/server/services/browser/extension/protocol.js +15 -1
- package/server/services/browser/extension/provider.js +71 -47
- package/server/services/browser/extension/registry.js +155 -34
- package/server/services/cli/executor.js +62 -9
- package/server/services/credentials/bitwarden_cli.js +322 -0
- package/server/services/credentials/broker.js +594 -0
- package/server/services/desktop/gateway.js +41 -4
- package/server/services/desktop/protocol.js +3 -0
- package/server/services/desktop/provider.js +39 -42
- package/server/services/desktop/registry.js +137 -52
- package/server/services/integrations/bitwarden/constants.js +14 -0
- package/server/services/integrations/bitwarden/provider.js +197 -0
- package/server/services/integrations/bitwarden/snapshot.js +65 -0
- package/server/services/integrations/figma/provider.js +78 -12
- package/server/services/integrations/github/common.js +11 -6
- package/server/services/integrations/github/provider.js +52 -53
- package/server/services/integrations/google/provider.js +55 -19
- package/server/services/integrations/home_assistant/network.js +17 -20
- package/server/services/integrations/home_assistant/provider.js +7 -5
- package/server/services/integrations/home_assistant/tools.js +17 -5
- package/server/services/integrations/http.js +51 -0
- package/server/services/integrations/manager.js +159 -53
- package/server/services/integrations/microsoft/provider.js +80 -13
- package/server/services/integrations/neoarchive/provider.js +55 -29
- package/server/services/integrations/neorecall/client.js +17 -10
- package/server/services/integrations/neorecall/provider.js +20 -11
- package/server/services/integrations/notion/provider.js +16 -13
- package/server/services/integrations/oauth_provider.js +115 -51
- package/server/services/integrations/registry.js +2 -0
- package/server/services/integrations/slack/provider.js +98 -9
- package/server/services/integrations/spotify/provider.js +67 -71
- package/server/services/integrations/trello/provider.js +21 -7
- package/server/services/integrations/weather/provider.js +18 -12
- package/server/services/integrations/whatsapp/provider.js +76 -16
- package/server/services/manager.js +110 -1
- package/server/services/memory/embedding_index.js +20 -8
- package/server/services/memory/embeddings.js +151 -90
- package/server/services/memory/ingestion.js +50 -9
- package/server/services/memory/ingestion_documents.js +13 -3
- package/server/services/memory/manager.js +66 -52
- package/server/services/messaging/access_policy.js +10 -6
- package/server/services/messaging/automation.js +240 -34
- package/server/services/messaging/discord.js +11 -1
- package/server/services/messaging/formatting_guides.js +5 -4
- package/server/services/messaging/http_platforms.js +37 -16
- package/server/services/messaging/inbound_queue.js +143 -28
- package/server/services/messaging/inbound_store.js +257 -0
- package/server/services/messaging/manager.js +344 -51
- package/server/services/messaging/telegram.js +10 -1
- package/server/services/messaging/typing_keepalive.js +5 -2
- package/server/services/messaging/whatsapp.js +33 -14
- package/server/services/network/http.js +210 -0
- package/server/services/network/safe_request.js +307 -0
- package/server/services/runtime/backends/local-vm.js +227 -67
- package/server/services/runtime/docker-vm-manager.js +9 -0
- package/server/services/runtime/guest_bootstrap.js +30 -4
- package/server/services/runtime/guest_image.js +43 -12
- package/server/services/runtime/manager.js +77 -23
- package/server/services/runtime/validation.js +7 -6
- package/server/services/security/tool_categories.js +6 -0
- package/server/services/social_reach/channels/github.js +10 -4
- package/server/services/social_reach/channels/reddit.js +4 -4
- package/server/services/social_reach/channels/rss.js +2 -2
- package/server/services/social_reach/channels/social_video.js +13 -8
- package/server/services/social_reach/channels/v2ex.js +21 -8
- package/server/services/social_reach/channels/x.js +2 -2
- package/server/services/social_reach/channels/xueqiu.js +5 -5
- package/server/services/social_reach/service.js +9 -6
- package/server/services/social_reach/utils.js +65 -14
- package/server/services/social_video/captions.js +2 -2
- package/server/services/social_video/service.js +343 -68
- package/server/services/tasks/integration_runtime.js +18 -8
- package/server/services/tasks/runtime.js +39 -4
- package/server/services/voice/agentBridge.js +17 -4
- package/server/services/voice/bufferedLiveRelayAdapter.js +5 -0
- package/server/services/voice/liveSession.js +31 -0
- package/server/services/voice/message.js +1 -1
- package/server/services/voice/openaiSpeech.js +33 -8
- package/server/services/voice/providers.js +233 -151
- package/server/services/voice/runtime.js +2 -2
- package/server/services/voice/runtimeManager.js +118 -20
- package/server/services/voice/turnRunner.js +6 -0
- package/server/services/wearable/firmware_manifest.js +51 -13
- package/server/services/wearable/service.js +1 -0
- package/server/utils/abort.js +96 -0
- package/server/utils/cloud-security.js +110 -3
- package/server/utils/files.js +31 -0
- package/server/utils/image_payload.js +95 -0
- package/server/utils/logger.js +19 -0
- package/server/utils/retry.js +107 -0
package/server/routes/admin.js
CHANGED
|
@@ -1025,7 +1025,7 @@ router.put('/api/config/rate-limits', requireAdminAuth, express.json(), (req, re
|
|
|
1025
1025
|
router.get('/api/models', requireAdminAuth, async (req, res) => {
|
|
1026
1026
|
const { getSupportedModels } = require('../services/ai/models');
|
|
1027
1027
|
try {
|
|
1028
|
-
const models = await getSupportedModels(null, null);
|
|
1028
|
+
const models = await getSupportedModels(null, null, { signal: req.signal });
|
|
1029
1029
|
const disabledStr = process.env.NEOAGENT_DISABLED_MODELS || '';
|
|
1030
1030
|
const disabledModels = disabledStr ? disabledStr.split(',').map(s => s.trim()).filter(Boolean) : [];
|
|
1031
1031
|
res.json({ models, disabledModels });
|
package/server/routes/android.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
1
3
|
const express = require('express');
|
|
2
4
|
const fs = require('fs');
|
|
3
5
|
const path = require('path');
|
|
@@ -6,8 +8,7 @@ const router = express.Router();
|
|
|
6
8
|
const { DATA_DIR } = require('../../runtime/paths');
|
|
7
9
|
const { requireAuth } = require('../middleware/auth');
|
|
8
10
|
const { sanitizeError } = require('../utils/security');
|
|
9
|
-
const {
|
|
10
|
-
const { getRuntimeValidation } = require('../services/runtime/validation');
|
|
11
|
+
const { validateAndroidIntentUrl } = require('../utils/cloud-security');
|
|
11
12
|
|
|
12
13
|
router.use(requireAuth);
|
|
13
14
|
|
|
@@ -52,18 +53,6 @@ async function getAndroidController(req) {
|
|
|
52
53
|
throw new Error('Android controller is unavailable.');
|
|
53
54
|
}
|
|
54
55
|
|
|
55
|
-
function getAndroidStatusSnapshot(req) {
|
|
56
|
-
const runtimeValidation = getRuntimeValidation(req.app?.locals?.runtimeManager);
|
|
57
|
-
const ready = Boolean(runtimeValidation?.ready);
|
|
58
|
-
return {
|
|
59
|
-
bootstrapped: false,
|
|
60
|
-
canBootstrap: ready,
|
|
61
|
-
devices: [],
|
|
62
|
-
lastStartError: ready ? null : (runtimeValidation?.issues?.[0] || 'VM runtime is not ready.'),
|
|
63
|
-
runtimeReady: ready,
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
|
|
67
56
|
function handleAndroidAction(action) {
|
|
68
57
|
return async (req, res) => {
|
|
69
58
|
try {
|
|
@@ -79,45 +68,49 @@ function handleAndroidAction(action) {
|
|
|
79
68
|
router.get('/status', async (req, res) => {
|
|
80
69
|
try {
|
|
81
70
|
const controller = await getAndroidController(req);
|
|
82
|
-
res.json(await controller.getStatus(
|
|
71
|
+
res.json(await controller.getStatus({ signal: req.signal }));
|
|
83
72
|
} catch (err) {
|
|
84
73
|
res.status(500).json({ error: sanitizeError(err) });
|
|
85
74
|
}
|
|
86
75
|
});
|
|
87
76
|
|
|
88
77
|
router.post('/start', handleAndroidAction((controller, req) =>
|
|
89
|
-
controller.requestStartEmulator(req.body || {})));
|
|
78
|
+
controller.requestStartEmulator({ ...(req.body || {}), signal: req.signal })));
|
|
90
79
|
|
|
91
|
-
router.post('/stop', handleAndroidAction((controller) => controller.stopEmulator()));
|
|
80
|
+
router.post('/stop', handleAndroidAction((controller, req) => controller.stopEmulator({ signal: req.signal })));
|
|
92
81
|
|
|
93
|
-
router.get('/devices', handleAndroidAction(async (controller) => ({
|
|
94
|
-
devices: await controller.listDevices(),
|
|
82
|
+
router.get('/devices', handleAndroidAction(async (controller, req) => ({
|
|
83
|
+
devices: await controller.listDevices({ signal: req.signal }),
|
|
95
84
|
})));
|
|
96
85
|
|
|
97
86
|
router.post('/screenshot', handleAndroidAction((controller, req) =>
|
|
98
|
-
controller.screenshot(req.body || {})));
|
|
87
|
+
controller.screenshot({ ...(req.body || {}), signal: req.signal })));
|
|
99
88
|
|
|
100
89
|
router.post('/observe', handleAndroidAction((controller, req) =>
|
|
101
|
-
controller.observe(req.body || {})));
|
|
90
|
+
controller.observe({ ...(req.body || {}), signal: req.signal })));
|
|
102
91
|
|
|
103
92
|
router.post('/ui-dump', handleAndroidAction((controller, req) =>
|
|
104
|
-
controller.dumpUi(req.body || {})));
|
|
93
|
+
controller.dumpUi({ ...(req.body || {}), signal: req.signal })));
|
|
105
94
|
|
|
106
95
|
router.get('/apps', handleAndroidAction((controller, req) =>
|
|
107
|
-
controller.listApps({ includeSystem: req.query.includeSystem === 'true' })));
|
|
96
|
+
controller.listApps({ includeSystem: req.query.includeSystem === 'true', signal: req.signal })));
|
|
108
97
|
|
|
109
98
|
router.post('/open-app', handleAndroidAction((controller, req) =>
|
|
110
|
-
controller.openApp(req.body || {})));
|
|
99
|
+
controller.openApp({ ...(req.body || {}), signal: req.signal })));
|
|
111
100
|
|
|
112
101
|
router.post('/open-intent', async (req, res) => {
|
|
113
102
|
try {
|
|
114
103
|
const body = req.body || {};
|
|
115
104
|
const intentUrl = body.data || body.url || body.uri;
|
|
116
|
-
if (
|
|
105
|
+
if (
|
|
106
|
+
intentUrl
|
|
107
|
+
&& typeof intentUrl === 'string'
|
|
108
|
+
&& !(await validateAndroidIntentUrl(intentUrl, { signal: req.signal })).allowed
|
|
109
|
+
) {
|
|
117
110
|
return res.status(403).json({ error: 'This URL is not permitted.' });
|
|
118
111
|
}
|
|
119
112
|
const controller = await getAndroidController(req);
|
|
120
|
-
const result = await controller.openIntent(body);
|
|
113
|
+
const result = await controller.openIntent({ ...body, signal: req.signal });
|
|
121
114
|
res.json(result);
|
|
122
115
|
} catch (err) {
|
|
123
116
|
res.status(500).json({ error: sanitizeError(err) });
|
|
@@ -125,22 +118,22 @@ router.post('/open-intent', async (req, res) => {
|
|
|
125
118
|
});
|
|
126
119
|
|
|
127
120
|
router.post('/tap', handleAndroidAction((controller, req) =>
|
|
128
|
-
controller.tap(req.body || {})));
|
|
121
|
+
controller.tap({ ...(req.body || {}), signal: req.signal })));
|
|
129
122
|
|
|
130
123
|
router.post('/long-press', handleAndroidAction((controller, req) =>
|
|
131
|
-
controller.longPress(req.body || {})));
|
|
124
|
+
controller.longPress({ ...(req.body || {}), signal: req.signal })));
|
|
132
125
|
|
|
133
126
|
router.post('/type', handleAndroidAction((controller, req) =>
|
|
134
|
-
controller.type(req.body || {})));
|
|
127
|
+
controller.type({ ...(req.body || {}), signal: req.signal })));
|
|
135
128
|
|
|
136
129
|
router.post('/swipe', handleAndroidAction((controller, req) =>
|
|
137
|
-
controller.swipe(req.body || {})));
|
|
130
|
+
controller.swipe({ ...(req.body || {}), signal: req.signal })));
|
|
138
131
|
|
|
139
132
|
router.post('/press-key', handleAndroidAction((controller, req) =>
|
|
140
|
-
controller.pressKey(req.body || {})));
|
|
133
|
+
controller.pressKey({ ...(req.body || {}), signal: req.signal })));
|
|
141
134
|
|
|
142
135
|
router.post('/wait-for', handleAndroidAction((controller, req) =>
|
|
143
|
-
controller.waitFor(req.body || {})));
|
|
136
|
+
controller.waitFor({ ...(req.body || {}), signal: req.signal })));
|
|
144
137
|
|
|
145
138
|
router.post('/install-apk', (req, res) => {
|
|
146
139
|
androidApkUpload.single('apk')(req, res, async (uploadError) => {
|
|
@@ -162,7 +155,7 @@ router.post('/install-apk', (req, res) => {
|
|
|
162
155
|
|
|
163
156
|
try {
|
|
164
157
|
const controller = await getAndroidController(req);
|
|
165
|
-
const result = await controller.installApk({ apkPath: uploadedApkPath });
|
|
158
|
+
const result = await controller.installApk({ apkPath: uploadedApkPath, signal: req.signal });
|
|
166
159
|
res.json({
|
|
167
160
|
...result,
|
|
168
161
|
filename: req.file.originalname,
|
|
@@ -176,6 +169,9 @@ router.post('/install-apk', (req, res) => {
|
|
|
176
169
|
});
|
|
177
170
|
});
|
|
178
171
|
|
|
179
|
-
router.post('/shell', handleAndroidAction((controller, req) => controller.shell(
|
|
172
|
+
router.post('/shell', handleAndroidAction((controller, req) => controller.shell({
|
|
173
|
+
...(req.body || {}),
|
|
174
|
+
signal: req.signal,
|
|
175
|
+
})));
|
|
180
176
|
|
|
181
177
|
module.exports = router;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const express = require('express');
|
|
4
|
+
const { requireAuth } = require('../middleware/auth');
|
|
5
|
+
const {
|
|
6
|
+
MODULE_IDS,
|
|
7
|
+
cloneDefaults,
|
|
8
|
+
getBehaviorConfig,
|
|
9
|
+
setBehaviorConfig,
|
|
10
|
+
resolveBehaviorConfig,
|
|
11
|
+
} = require('../services/behavior');
|
|
12
|
+
const {
|
|
13
|
+
getAgentIdFromRequest,
|
|
14
|
+
resolveAgentId,
|
|
15
|
+
} = require('../services/agents/manager');
|
|
16
|
+
const { invalidateSystemPromptCache } = require('../services/ai/systemPrompt');
|
|
17
|
+
|
|
18
|
+
const router = express.Router();
|
|
19
|
+
router.use(requireAuth);
|
|
20
|
+
|
|
21
|
+
function requestAgentId(req) {
|
|
22
|
+
return resolveAgentId(req.session.userId, getAgentIdFromRequest(req));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
router.get('/', (req, res) => {
|
|
26
|
+
const userId = req.session.userId;
|
|
27
|
+
const agentId = requestAgentId(req);
|
|
28
|
+
res.json({
|
|
29
|
+
agentId,
|
|
30
|
+
modules: MODULE_IDS,
|
|
31
|
+
defaults: cloneDefaults(),
|
|
32
|
+
config: getBehaviorConfig(userId, agentId),
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
router.put('/', (req, res) => {
|
|
37
|
+
if (!req.body?.config || typeof req.body.config !== 'object' || Array.isArray(req.body.config)) {
|
|
38
|
+
return res.status(400).json({ error: 'config must be an object' });
|
|
39
|
+
}
|
|
40
|
+
const userId = req.session.userId;
|
|
41
|
+
const agentId = requestAgentId(req);
|
|
42
|
+
const config = setBehaviorConfig(userId, agentId, req.body.config);
|
|
43
|
+
invalidateSystemPromptCache(userId, agentId);
|
|
44
|
+
return res.json({ agentId, config });
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
router.get('/effective', (req, res) => {
|
|
48
|
+
const userId = req.session.userId;
|
|
49
|
+
const agentId = requestAgentId(req);
|
|
50
|
+
const platform = String(req.query.platform || '').trim();
|
|
51
|
+
const chatId = String(req.query.chatId || '').trim();
|
|
52
|
+
if (!platform || !chatId) {
|
|
53
|
+
return res.status(400).json({ error: 'platform and chatId are required' });
|
|
54
|
+
}
|
|
55
|
+
return res.json({
|
|
56
|
+
agentId,
|
|
57
|
+
config: resolveBehaviorConfig(userId, agentId, {
|
|
58
|
+
platform,
|
|
59
|
+
chatId,
|
|
60
|
+
isGroup: req.query.isGroup !== 'false',
|
|
61
|
+
}),
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
router.get('/diagnostics', (req, res) => {
|
|
66
|
+
const userId = req.session.userId;
|
|
67
|
+
const agentId = requestAgentId(req);
|
|
68
|
+
const platform = String(req.query.platform || '').trim();
|
|
69
|
+
const chatId = String(req.query.chatId || '').trim();
|
|
70
|
+
if (!platform || !chatId) {
|
|
71
|
+
return res.status(400).json({ error: 'platform and chatId are required' });
|
|
72
|
+
}
|
|
73
|
+
const pipeline = req.app?.locals?.behaviorPipeline;
|
|
74
|
+
if (!pipeline?.getDiagnostics) {
|
|
75
|
+
return res.status(503).json({ error: 'Behavior runtime is not initialized' });
|
|
76
|
+
}
|
|
77
|
+
return res.json(pipeline.getDiagnostics(userId, agentId, platform, chatId));
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
module.exports = router;
|
package/server/routes/browser.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
1
3
|
const express = require('express');
|
|
2
4
|
const router = express.Router();
|
|
3
5
|
const { requireAuth } = require('../middleware/auth');
|
|
4
6
|
const { sanitizeError } = require('../utils/security');
|
|
5
|
-
const {
|
|
7
|
+
const { validateCloudUrlWithDns } = require('../utils/cloud-security');
|
|
6
8
|
const { getRuntimeValidation } = require('../services/runtime/validation');
|
|
7
9
|
|
|
8
10
|
router.use(requireAuth);
|
|
@@ -11,7 +13,9 @@ async function getBrowserController(req) {
|
|
|
11
13
|
const runtimeManager = req.app?.locals?.runtimeManager;
|
|
12
14
|
if (runtimeManager && typeof runtimeManager.getBrowserProviderForUser === 'function') {
|
|
13
15
|
const start = Date.now();
|
|
14
|
-
const runtimeController = await runtimeManager.getBrowserProviderForUser(req.session?.userId
|
|
16
|
+
const runtimeController = await runtimeManager.getBrowserProviderForUser(req.session?.userId, {
|
|
17
|
+
signal: req.signal,
|
|
18
|
+
});
|
|
15
19
|
const duration = Date.now() - start;
|
|
16
20
|
if (duration > 1000) {
|
|
17
21
|
console.log(`[HTTP] Browser controller acquired for user ${req.session?.userId} in ${duration}ms`);
|
|
@@ -73,7 +77,7 @@ router.get('/cookies', async (req, res) => {
|
|
|
73
77
|
if (typeof bc.getCookies !== 'function') {
|
|
74
78
|
return res.status(501).json({ error: 'Cookie export is unavailable for this browser provider.' });
|
|
75
79
|
}
|
|
76
|
-
const result = await bc.getCookies();
|
|
80
|
+
const result = await bc.getCookies({ signal: req.signal });
|
|
77
81
|
res.json(result);
|
|
78
82
|
} catch (err) {
|
|
79
83
|
res.status(500).json({ error: sanitizeError(err) });
|
|
@@ -84,7 +88,7 @@ router.get('/cookies', async (req, res) => {
|
|
|
84
88
|
router.post('/launch', async (req, res) => {
|
|
85
89
|
try {
|
|
86
90
|
const bc = await getBrowserController(req);
|
|
87
|
-
await bc.launch(req.body || {});
|
|
91
|
+
await bc.launch({ ...(req.body || {}), signal: req.signal });
|
|
88
92
|
res.json({ success: true });
|
|
89
93
|
} catch (err) {
|
|
90
94
|
res.status(500).json({ error: sanitizeError(err) });
|
|
@@ -97,12 +101,12 @@ router.post('/navigate', async (req, res) => {
|
|
|
97
101
|
const { url, waitFor } = req.body;
|
|
98
102
|
if (!url) return res.status(400).json({ error: 'url required' });
|
|
99
103
|
|
|
100
|
-
const
|
|
101
|
-
|
|
102
|
-
if (bc.providerType === 'vm' && !validateCloudUrl(url).allowed) {
|
|
104
|
+
const urlValidation = await validateCloudUrlWithDns(url, { signal: req.signal });
|
|
105
|
+
if (!urlValidation.allowed) {
|
|
103
106
|
return res.status(403).json({ error: 'This URL is not permitted.' });
|
|
104
107
|
}
|
|
105
108
|
|
|
109
|
+
const bc = await getBrowserController(req);
|
|
106
110
|
const result = await bc.navigate(url, {
|
|
107
111
|
waitUntil: waitFor || req.body?.waitUntil || 'domcontentloaded',
|
|
108
112
|
waitFor,
|
|
@@ -110,6 +114,7 @@ router.post('/navigate', async (req, res) => {
|
|
|
110
114
|
fullPage: req.body?.fullPage === true,
|
|
111
115
|
referrerMode: req.body?.referrerMode,
|
|
112
116
|
challengeRetry: req.body?.challengeRetry,
|
|
117
|
+
signal: req.signal,
|
|
113
118
|
});
|
|
114
119
|
res.json(result);
|
|
115
120
|
} catch (err) {
|
|
@@ -121,7 +126,7 @@ router.post('/navigate', async (req, res) => {
|
|
|
121
126
|
router.post('/screenshot', async (req, res) => {
|
|
122
127
|
try {
|
|
123
128
|
const bc = await getBrowserController(req);
|
|
124
|
-
const result = await bc.screenshot(req.body || {});
|
|
129
|
+
const result = await bc.screenshot({ ...(req.body || {}), signal: req.signal });
|
|
125
130
|
res.json(result);
|
|
126
131
|
} catch (err) {
|
|
127
132
|
res.status(500).json({ error: sanitizeError(err) });
|
|
@@ -133,7 +138,7 @@ router.post('/click', async (req, res) => {
|
|
|
133
138
|
try {
|
|
134
139
|
const { selector, text } = req.body;
|
|
135
140
|
const bc = await getBrowserController(req);
|
|
136
|
-
const result = await bc.click(selector, text, req.body?.screenshot !== false);
|
|
141
|
+
const result = await bc.click(selector, text, req.body?.screenshot !== false, { signal: req.signal });
|
|
137
142
|
res.json(result);
|
|
138
143
|
} catch (err) {
|
|
139
144
|
res.status(500).json({ error: sanitizeError(err) });
|
|
@@ -147,7 +152,7 @@ router.post('/click-point', async (req, res) => {
|
|
|
147
152
|
return res.status(400).json({ error: 'x and y required' });
|
|
148
153
|
}
|
|
149
154
|
const bc = await getBrowserController(req);
|
|
150
|
-
const result = await bc.clickPoint(x, y, req.body?.screenshot !== false);
|
|
155
|
+
const result = await bc.clickPoint(x, y, req.body?.screenshot !== false, { signal: req.signal });
|
|
151
156
|
res.json(result);
|
|
152
157
|
} catch (err) {
|
|
153
158
|
res.status(500).json({ error: sanitizeError(err) });
|
|
@@ -161,7 +166,7 @@ router.post('/mouse-move', async (req, res) => {
|
|
|
161
166
|
return res.status(400).json({ error: 'x and y required' });
|
|
162
167
|
}
|
|
163
168
|
const bc = await getBrowserController(req);
|
|
164
|
-
const result = await bc.hoverPoint(x, y, req.body || {});
|
|
169
|
+
const result = await bc.hoverPoint(x, y, { ...(req.body || {}), signal: req.signal });
|
|
165
170
|
res.json(result);
|
|
166
171
|
} catch (err) {
|
|
167
172
|
res.status(500).json({ error: sanitizeError(err) });
|
|
@@ -179,6 +184,7 @@ router.post('/fill', async (req, res) => {
|
|
|
179
184
|
clear: req.body?.clear !== false,
|
|
180
185
|
pressEnter: req.body?.pressEnter === true,
|
|
181
186
|
screenshot: req.body?.screenshot !== false,
|
|
187
|
+
signal: req.signal,
|
|
182
188
|
});
|
|
183
189
|
res.json(result);
|
|
184
190
|
} catch (err) {
|
|
@@ -193,6 +199,7 @@ router.post('/type-text', async (req, res) => {
|
|
|
193
199
|
const result = await bc.typeText(String(text || ''), {
|
|
194
200
|
pressEnter: req.body?.pressEnter === true,
|
|
195
201
|
screenshot: req.body?.screenshot !== false,
|
|
202
|
+
signal: req.signal,
|
|
196
203
|
});
|
|
197
204
|
res.json(result);
|
|
198
205
|
} catch (err) {
|
|
@@ -205,7 +212,7 @@ router.post('/press-key', async (req, res) => {
|
|
|
205
212
|
const { key } = req.body || {};
|
|
206
213
|
if (!key) return res.status(400).json({ error: 'key required' });
|
|
207
214
|
const bc = await getBrowserController(req);
|
|
208
|
-
const result = await bc.pressKey(key, req.body?.screenshot !== false);
|
|
215
|
+
const result = await bc.pressKey(key, req.body?.screenshot !== false, { signal: req.signal });
|
|
209
216
|
res.json(result);
|
|
210
217
|
} catch (err) {
|
|
211
218
|
res.status(500).json({ error: sanitizeError(err) });
|
|
@@ -219,6 +226,7 @@ router.post('/scroll', async (req, res) => {
|
|
|
219
226
|
req.body?.deltaX ?? 0,
|
|
220
227
|
req.body?.deltaY ?? 0,
|
|
221
228
|
req.body?.screenshot !== false,
|
|
229
|
+
{ signal: req.signal },
|
|
222
230
|
);
|
|
223
231
|
res.json(result);
|
|
224
232
|
} catch (err) {
|
|
@@ -230,7 +238,7 @@ router.post('/scroll', async (req, res) => {
|
|
|
230
238
|
router.post('/extract', async (req, res) => {
|
|
231
239
|
try {
|
|
232
240
|
const bc = await getBrowserController(req);
|
|
233
|
-
const result = await bc.extractContent(req.body || {});
|
|
241
|
+
const result = await bc.extractContent({ ...(req.body || {}), signal: req.signal });
|
|
234
242
|
res.json(result);
|
|
235
243
|
} catch (err) {
|
|
236
244
|
res.status(500).json({ error: sanitizeError(err) });
|
|
@@ -252,7 +260,7 @@ router.post('/execute', async (req, res) => {
|
|
|
252
260
|
}
|
|
253
261
|
|
|
254
262
|
const bc = await getBrowserController(req);
|
|
255
|
-
const result = await bc.executeJS(code);
|
|
263
|
+
const result = await bc.executeJS(code, { signal: req.signal });
|
|
256
264
|
res.json({ result });
|
|
257
265
|
} catch (err) {
|
|
258
266
|
res.status(500).json({ error: sanitizeError(err) });
|
|
@@ -263,7 +271,7 @@ router.post('/execute', async (req, res) => {
|
|
|
263
271
|
router.post('/close', async (req, res) => {
|
|
264
272
|
try {
|
|
265
273
|
const bc = await getBrowserController(req);
|
|
266
|
-
await bc.closeBrowser();
|
|
274
|
+
await bc.closeBrowser({ signal: req.signal });
|
|
267
275
|
res.json({ success: true });
|
|
268
276
|
} catch (err) {
|
|
269
277
|
res.status(500).json({ error: sanitizeError(err) });
|
package/server/routes/desktop.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
1
3
|
const express = require('express');
|
|
2
4
|
const router = express.Router();
|
|
3
5
|
const { requireAuth } = require('../middleware/auth');
|
|
@@ -144,6 +146,7 @@ router.post('/screenshot', (req, res) =>
|
|
|
144
146
|
handleDesktopAction(req, res, (provider, request) => provider.screenshot({
|
|
145
147
|
...(request.body || {}),
|
|
146
148
|
deviceId: parseDeviceId(request.body?.deviceId),
|
|
149
|
+
signal: request.signal,
|
|
147
150
|
})));
|
|
148
151
|
|
|
149
152
|
router.post('/observe', (req, res) =>
|
|
@@ -151,6 +154,7 @@ router.post('/observe', (req, res) =>
|
|
|
151
154
|
...(request.body || {}),
|
|
152
155
|
deviceId: parseDeviceId(request.body?.deviceId),
|
|
153
156
|
includeTree: parseOptionalBoolean(request.body?.includeTree, false),
|
|
157
|
+
signal: request.signal,
|
|
154
158
|
})));
|
|
155
159
|
|
|
156
160
|
router.post('/click', (req, res) =>
|
|
@@ -160,6 +164,7 @@ router.post('/click', (req, res) =>
|
|
|
160
164
|
{
|
|
161
165
|
...(request.body || {}),
|
|
162
166
|
deviceId: parseDeviceId(request.body?.deviceId),
|
|
167
|
+
signal: request.signal,
|
|
163
168
|
},
|
|
164
169
|
)));
|
|
165
170
|
|
|
@@ -170,6 +175,7 @@ router.post('/mouse-move', (req, res) =>
|
|
|
170
175
|
{
|
|
171
176
|
...(request.body || {}),
|
|
172
177
|
deviceId: parseDeviceId(request.body?.deviceId),
|
|
178
|
+
signal: request.signal,
|
|
173
179
|
},
|
|
174
180
|
)));
|
|
175
181
|
|
|
@@ -182,6 +188,7 @@ router.post('/drag', (req, res) =>
|
|
|
182
188
|
x2: parseFiniteNumber(request.body?.x2, 'x2', { min: -100000, max: 100000 }),
|
|
183
189
|
y2: parseFiniteNumber(request.body?.y2, 'y2', { min: -100000, max: 100000 }),
|
|
184
190
|
durationMs: Math.round(parseFiniteNumber(request.body?.durationMs ?? 280, 'durationMs', { min: 20, max: 5000 })),
|
|
191
|
+
signal: request.signal,
|
|
185
192
|
})));
|
|
186
193
|
|
|
187
194
|
router.post('/scroll', (req, res) =>
|
|
@@ -190,6 +197,7 @@ router.post('/scroll', (req, res) =>
|
|
|
190
197
|
deviceId: parseDeviceId(request.body?.deviceId),
|
|
191
198
|
deltaX: Math.round(parseFiniteNumber(request.body?.deltaX ?? 0, 'deltaX', { min: -5000, max: 5000 })),
|
|
192
199
|
deltaY: Math.round(parseFiniteNumber(request.body?.deltaY ?? 0, 'deltaY', { min: -5000, max: 5000 })),
|
|
200
|
+
signal: request.signal,
|
|
193
201
|
})));
|
|
194
202
|
|
|
195
203
|
router.post('/type-text', (req, res) =>
|
|
@@ -199,6 +207,7 @@ router.post('/type-text', (req, res) =>
|
|
|
199
207
|
...(request.body || {}),
|
|
200
208
|
deviceId: parseDeviceId(request.body?.deviceId),
|
|
201
209
|
pressEnter: parseOptionalBoolean(request.body?.pressEnter, false),
|
|
210
|
+
signal: request.signal,
|
|
202
211
|
},
|
|
203
212
|
)));
|
|
204
213
|
|
|
@@ -208,6 +217,7 @@ router.post('/press-key', (req, res) =>
|
|
|
208
217
|
{
|
|
209
218
|
...(request.body || {}),
|
|
210
219
|
deviceId: parseDeviceId(request.body?.deviceId),
|
|
220
|
+
signal: request.signal,
|
|
211
221
|
},
|
|
212
222
|
)));
|
|
213
223
|
|
|
@@ -216,11 +226,15 @@ router.post('/launch-app', (req, res) =>
|
|
|
216
226
|
...(request.body || {}),
|
|
217
227
|
deviceId: parseDeviceId(request.body?.deviceId),
|
|
218
228
|
app: parseRequiredString(request.body?.app, 'app', MAX_APP_LENGTH),
|
|
229
|
+
signal: request.signal,
|
|
219
230
|
})));
|
|
220
231
|
|
|
221
232
|
router.get('/displays', (req, res) =>
|
|
222
233
|
handleDesktopAction(req, res, (provider, request) =>
|
|
223
|
-
provider.listDisplays(
|
|
234
|
+
provider.listDisplays({
|
|
235
|
+
...parseTypedDisplayQuery(request.query),
|
|
236
|
+
signal: request.signal,
|
|
237
|
+
})));
|
|
224
238
|
|
|
225
239
|
router.post('/select-display', (req, res) =>
|
|
226
240
|
handleDesktopAction(req, res, (provider, request) => provider.selectDisplay(
|
|
@@ -228,6 +242,7 @@ router.post('/select-display', (req, res) =>
|
|
|
228
242
|
{
|
|
229
243
|
...(request.body || {}),
|
|
230
244
|
deviceId: parseDeviceId(request.body?.deviceId),
|
|
245
|
+
signal: request.signal,
|
|
231
246
|
},
|
|
232
247
|
)));
|
|
233
248
|
|
|
@@ -239,12 +254,14 @@ router.post('/pause-device', (req, res) =>
|
|
|
239
254
|
handleDesktopAction(req, res, (provider, request) => provider.pauseDevice(
|
|
240
255
|
parseRequiredString(request.body?.deviceId, 'deviceId', 256),
|
|
241
256
|
parseOptionalBoolean(request.body?.paused, true),
|
|
257
|
+
{ signal: request.signal },
|
|
242
258
|
)));
|
|
243
259
|
|
|
244
260
|
router.post('/tree', (req, res) =>
|
|
245
261
|
handleDesktopAction(req, res, (provider, request) => provider.getAccessibilityTree({
|
|
246
262
|
...(request.body || {}),
|
|
247
263
|
deviceId: parseDeviceId(request.body?.deviceId),
|
|
264
|
+
signal: request.signal,
|
|
248
265
|
})));
|
|
249
266
|
|
|
250
267
|
module.exports = router;
|
|
@@ -17,6 +17,14 @@ function getAuthProviderManager(req) {
|
|
|
17
17
|
return req.app?.locals?.authProviderManager;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
function getCredentialScope(req) {
|
|
21
|
+
const userId = Number(req.session.userId);
|
|
22
|
+
return {
|
|
23
|
+
userId,
|
|
24
|
+
agentId: resolveAgentId(userId, getAgentIdFromRequest(req)),
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
20
28
|
function escapeHtml(value) {
|
|
21
29
|
return String(value || '')
|
|
22
30
|
.replace(/&/g, '&')
|
|
@@ -101,7 +109,7 @@ router.get('/oauth/callback', async (req, res) => {
|
|
|
101
109
|
if (!manager) {
|
|
102
110
|
throw new Error('Official integration manager is not available on app.locals.integrationManager.');
|
|
103
111
|
}
|
|
104
|
-
const result = await manager.finishOAuth(state, code);
|
|
112
|
+
const result = await manager.finishOAuth(state, code, { signal: req.signal });
|
|
105
113
|
const payload = JSON.stringify({
|
|
106
114
|
type: 'integration_oauth_success',
|
|
107
115
|
provider: result.provider,
|
|
@@ -144,6 +152,100 @@ router.get('/oauth/callback', async (req, res) => {
|
|
|
144
152
|
|
|
145
153
|
router.use(requireAuth);
|
|
146
154
|
|
|
155
|
+
router.post('/bitwarden/unlock', async (req, res) => {
|
|
156
|
+
try {
|
|
157
|
+
const cli = req.app?.locals?.bitwardenCli;
|
|
158
|
+
if (!cli) throw new Error('Bitwarden credential service is unavailable.');
|
|
159
|
+
const scope = getCredentialScope(req);
|
|
160
|
+
const status = await cli.unlock(
|
|
161
|
+
scope.userId,
|
|
162
|
+
scope.agentId,
|
|
163
|
+
req.body?.masterPassword,
|
|
164
|
+
req.body?.idleTimeoutMinutes,
|
|
165
|
+
{ signal: req.signal },
|
|
166
|
+
);
|
|
167
|
+
res.json(status);
|
|
168
|
+
} catch (err) {
|
|
169
|
+
res.status(400).json({ error: sanitizeError(err), code: err.code || null });
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
router.post('/bitwarden/lock', async (req, res) => {
|
|
174
|
+
try {
|
|
175
|
+
const cli = req.app?.locals?.bitwardenCli;
|
|
176
|
+
if (!cli) throw new Error('Bitwarden credential service is unavailable.');
|
|
177
|
+
const scope = getCredentialScope(req);
|
|
178
|
+
res.json(await cli.lock(scope.userId, scope.agentId));
|
|
179
|
+
} catch (err) {
|
|
180
|
+
res.status(400).json({ error: sanitizeError(err), code: err.code || null });
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
router.get('/bitwarden/items', async (req, res) => {
|
|
185
|
+
try {
|
|
186
|
+
const broker = req.app?.locals?.credentialBroker;
|
|
187
|
+
if (!broker) throw new Error('Credential broker is unavailable.');
|
|
188
|
+
const scope = getCredentialScope(req);
|
|
189
|
+
res.json({ items: await broker.listVaultItems(scope.userId, scope.agentId, { signal: req.signal }) });
|
|
190
|
+
} catch (err) {
|
|
191
|
+
res.status(400).json({ error: sanitizeError(err), code: err.code || null });
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
router.get('/bitwarden/bindings', (req, res) => {
|
|
196
|
+
try {
|
|
197
|
+
const broker = req.app?.locals?.credentialBroker;
|
|
198
|
+
if (!broker) throw new Error('Credential broker is unavailable.');
|
|
199
|
+
const scope = getCredentialScope(req);
|
|
200
|
+
res.json({ bindings: broker.listBindings(scope.userId, scope.agentId) });
|
|
201
|
+
} catch (err) {
|
|
202
|
+
res.status(400).json({ error: sanitizeError(err), code: err.code || null });
|
|
203
|
+
}
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
router.post('/bitwarden/bindings', async (req, res) => {
|
|
207
|
+
try {
|
|
208
|
+
const broker = req.app?.locals?.credentialBroker;
|
|
209
|
+
if (!broker) throw new Error('Credential broker is unavailable.');
|
|
210
|
+
const scope = getCredentialScope(req);
|
|
211
|
+
const binding = await broker.createBinding(scope.userId, scope.agentId, req.body, {
|
|
212
|
+
signal: req.signal,
|
|
213
|
+
});
|
|
214
|
+
res.status(201).json({ binding });
|
|
215
|
+
} catch (err) {
|
|
216
|
+
res.status(400).json({ error: sanitizeError(err), code: err.code || null });
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
router.put('/bitwarden/bindings/:bindingId', async (req, res) => {
|
|
221
|
+
try {
|
|
222
|
+
const broker = req.app?.locals?.credentialBroker;
|
|
223
|
+
if (!broker) throw new Error('Credential broker is unavailable.');
|
|
224
|
+
const scope = getCredentialScope(req);
|
|
225
|
+
const binding = await broker.updateBinding(
|
|
226
|
+
scope.userId,
|
|
227
|
+
scope.agentId,
|
|
228
|
+
req.params.bindingId,
|
|
229
|
+
req.body,
|
|
230
|
+
{ signal: req.signal },
|
|
231
|
+
);
|
|
232
|
+
res.json({ binding });
|
|
233
|
+
} catch (err) {
|
|
234
|
+
res.status(400).json({ error: sanitizeError(err), code: err.code || null });
|
|
235
|
+
}
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
router.delete('/bitwarden/bindings/:bindingId', (req, res) => {
|
|
239
|
+
try {
|
|
240
|
+
const broker = req.app?.locals?.credentialBroker;
|
|
241
|
+
if (!broker) throw new Error('Credential broker is unavailable.');
|
|
242
|
+
const scope = getCredentialScope(req);
|
|
243
|
+
res.json(broker.deleteBinding(scope.userId, scope.agentId, req.params.bindingId));
|
|
244
|
+
} catch (err) {
|
|
245
|
+
res.status(400).json({ error: sanitizeError(err), code: err.code || null });
|
|
246
|
+
}
|
|
247
|
+
});
|
|
248
|
+
|
|
147
249
|
router.get('/qr-image', async (req, res) => {
|
|
148
250
|
try {
|
|
149
251
|
const data = String(req.query.data || '').trim();
|
|
@@ -320,6 +422,7 @@ router.post('/:provider/connect', async (req, res) => {
|
|
|
320
422
|
{
|
|
321
423
|
appKey: req.body?.appId,
|
|
322
424
|
agentId: resolveAgentId(req.session.userId, getAgentIdFromRequest(req)),
|
|
425
|
+
signal: req.signal,
|
|
323
426
|
},
|
|
324
427
|
);
|
|
325
428
|
res.json(result);
|
|
@@ -340,6 +443,7 @@ router.post('/:provider/disconnect', async (req, res) => {
|
|
|
340
443
|
{
|
|
341
444
|
connectionId: req.body?.connectionId,
|
|
342
445
|
agentId: resolveAgentId(req.session.userId, getAgentIdFromRequest(req)),
|
|
446
|
+
signal: req.signal,
|
|
343
447
|
},
|
|
344
448
|
);
|
|
345
449
|
res.json(result);
|
|
@@ -429,6 +533,7 @@ router.put('/:provider/config', async (req, res) => {
|
|
|
429
533
|
userId: req.session.userId,
|
|
430
534
|
agentId: resolveAgentId(req.session.userId, getAgentIdFromRequest(req)),
|
|
431
535
|
config: req.body?.config || req.body || {},
|
|
536
|
+
signal: req.signal,
|
|
432
537
|
});
|
|
433
538
|
res.json({
|
|
434
539
|
provider: provider.key,
|
|
@@ -458,6 +563,7 @@ router.delete('/:provider/config', async (req, res) => {
|
|
|
458
563
|
await provider.clearUserConfig({
|
|
459
564
|
userId: req.session.userId,
|
|
460
565
|
agentId: resolveAgentId(req.session.userId, getAgentIdFromRequest(req)),
|
|
566
|
+
signal: req.signal,
|
|
461
567
|
});
|
|
462
568
|
res.json({
|
|
463
569
|
provider: provider.key,
|
package/server/routes/memory.js
CHANGED
|
@@ -198,6 +198,7 @@ router.post('/ingestion/documents', async (req, res) => {
|
|
|
198
198
|
connectionId: req.body.connectionId,
|
|
199
199
|
sourceAccount: req.body.sourceAccount,
|
|
200
200
|
metadata: normalizeMetadata(req.body.metadata),
|
|
201
|
+
signal: req.signal,
|
|
201
202
|
});
|
|
202
203
|
res.json(result);
|
|
203
204
|
} catch (err) {
|