neoagent 3.2.1-beta.0 → 3.2.1-beta.10
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/docs/agent-run-lifecycle.md +10 -0
- 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 +111 -20
- package/flutter_app/lib/main_integrations.dart +607 -8
- package/flutter_app/lib/main_models.dart +3 -0
- package/flutter_app/lib/main_operations.dart +334 -321
- package/flutter_app/lib/main_security.dart +266 -112
- package/flutter_app/lib/main_settings.dart +4 -3
- package/flutter_app/lib/main_shared.dart +14 -11
- package/flutter_app/lib/src/backend_client.dart +78 -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 +145 -13
- package/package.json +30 -15
- package/runtime/paths.js +49 -5
- package/server/db/database.js +4 -4
- 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 +11 -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 +73083 -72209
- package/server/routes/admin.js +1 -1
- package/server/routes/agents.js +35 -2
- package/server/routes/android.js +30 -34
- 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 +16 -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 +496 -166
- 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 +121 -5
- package/server/services/ai/loop/conversation_loop.js +620 -340
- package/server/services/ai/loop/lifecycle.js +108 -0
- package/server/services/ai/loop/messaging_delivery.js +129 -57
- package/server/services/ai/loop/model_call_guard.js +91 -0
- package/server/services/ai/loop/model_io.js +48 -56
- package/server/services/ai/loop/progress_classification.js +2 -0
- package/server/services/ai/loop/tool_dispatch.js +28 -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 +4 -4
- 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 +6 -5
- package/server/services/ai/providers/grokOauth.js +19 -27
- package/server/services/ai/providers/nvidia.js +12 -7
- package/server/services/ai/providers/ollama.js +114 -86
- package/server/services/ai/providers/ollama_stream.js +142 -0
- package/server/services/ai/providers/openai.js +41 -7
- package/server/services/ai/providers/openaiCodex.js +13 -4
- package/server/services/ai/providers/openrouter.js +31 -9
- package/server/services/ai/providers/provider_error.js +36 -0
- package/server/services/ai/settings.js +26 -2
- package/server/services/ai/systemPrompt.js +19 -12
- package/server/services/ai/taskAnalysis.js +58 -10
- package/server/services/ai/terminal_reply.js +18 -0
- package/server/services/ai/toolEvidence.js +350 -29
- package/server/services/ai/tools.js +190 -111
- 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/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 +52 -19
- package/server/services/messaging/automation.js +85 -10
- package/server/services/messaging/formatting_guides.js +7 -4
- package/server/services/messaging/http_platforms.js +33 -13
- package/server/services/messaging/inbound_queue.js +78 -24
- package/server/services/messaging/inbound_store.js +224 -0
- package/server/services/messaging/manager.js +326 -51
- package/server/services/messaging/typing_keepalive.js +5 -2
- package/server/services/messaging/whatsapp.js +22 -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 +12 -7
- 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/service.js +160 -50
- 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/retry.js +107 -0
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const { analyzeImageForUser } = require('./imageAnalysis');
|
|
4
|
-
const {
|
|
4
|
+
const { validateCloudUrlWithDns } = require('../../utils/cloud-security');
|
|
5
|
+
const { isAbortError } = require('../../utils/abort');
|
|
6
|
+
const { fetchResponseText } = require('../network/http');
|
|
5
7
|
const db = require('../../db/database');
|
|
6
8
|
const { DATA_DIR } = require('../../../runtime/paths');
|
|
7
9
|
const { isMainAgent } = require('../agents/manager');
|
|
@@ -15,6 +17,7 @@ const {
|
|
|
15
17
|
executeIntegratedTool,
|
|
16
18
|
getIntegratedToolDefinitions,
|
|
17
19
|
} = require('./integrated_tools');
|
|
20
|
+
const { executeHttpRequest } = require('./integrated_tools/http_request');
|
|
18
21
|
|
|
19
22
|
function compactText(text, maxChars = 120) {
|
|
20
23
|
const str = String(text || '').replace(/\s+/g, ' ').trim();
|
|
@@ -34,6 +37,14 @@ function compactToolDefinition(tool, options = {}) {
|
|
|
34
37
|
}
|
|
35
38
|
};
|
|
36
39
|
|
|
40
|
+
// Keep execution-only access metadata on the internal tool definition. The
|
|
41
|
+
// provider adapters serialize only name/description/parameters, so this is
|
|
42
|
+
// never sent as part of an LLM tool schema. The loop uses it to distinguish
|
|
43
|
+
// official-integration reads from writes without hard-coding provider names.
|
|
44
|
+
if (typeof tool.access === 'string' && tool.access.trim()) {
|
|
45
|
+
compact.access = tool.access.trim().toLowerCase();
|
|
46
|
+
}
|
|
47
|
+
|
|
37
48
|
if (options.includeDescriptions) {
|
|
38
49
|
compact.description = compactText(tool.description, 320);
|
|
39
50
|
}
|
|
@@ -464,6 +475,58 @@ function getAvailableTools(app, options = {}) {
|
|
|
464
475
|
required: ['script']
|
|
465
476
|
}
|
|
466
477
|
},
|
|
478
|
+
{
|
|
479
|
+
name: 'credential_fill_browser',
|
|
480
|
+
description: 'Fill a configured credential binding into the current HTTPS login page without revealing the username or password. This enters protected mode; call credential_submit_browser or credential_cancel_browser next.',
|
|
481
|
+
parameters: {
|
|
482
|
+
type: 'object',
|
|
483
|
+
properties: {
|
|
484
|
+
binding_id: { type: 'string', description: 'Opaque browser credential binding ID from the Bitwarden integration summary.' },
|
|
485
|
+
stage: { type: 'string', enum: ['both', 'username', 'password'], description: 'Use username then password in separate protected fills for multi-step sign-in pages; default both.' },
|
|
486
|
+
username_selector: { type: 'string', description: 'CSS selector for the username or email input. Required for both or username stage.' },
|
|
487
|
+
password_selector: { type: 'string', description: 'CSS selector for the password input. Required for both or password stage.' }
|
|
488
|
+
},
|
|
489
|
+
required: ['binding_id']
|
|
490
|
+
}
|
|
491
|
+
},
|
|
492
|
+
{
|
|
493
|
+
name: 'credential_submit_browser',
|
|
494
|
+
description: 'Submit an active protected credential fill. Normal browser capabilities resume after this call.',
|
|
495
|
+
parameters: {
|
|
496
|
+
type: 'object',
|
|
497
|
+
properties: {
|
|
498
|
+
protected_fill_id: { type: 'string', description: 'Opaque protected fill ID returned by credential_fill_browser.' }
|
|
499
|
+
},
|
|
500
|
+
required: ['protected_fill_id']
|
|
501
|
+
}
|
|
502
|
+
},
|
|
503
|
+
{
|
|
504
|
+
name: 'credential_cancel_browser',
|
|
505
|
+
description: 'Clear and cancel an active protected credential fill. Normal browser capabilities resume after this call.',
|
|
506
|
+
parameters: {
|
|
507
|
+
type: 'object',
|
|
508
|
+
properties: {
|
|
509
|
+
protected_fill_id: { type: 'string', description: 'Opaque protected fill ID returned by credential_fill_browser.' }
|
|
510
|
+
},
|
|
511
|
+
required: ['protected_fill_id']
|
|
512
|
+
}
|
|
513
|
+
},
|
|
514
|
+
{
|
|
515
|
+
name: 'credential_http_request',
|
|
516
|
+
description: 'Make an HTTPS request through a configured credential binding. Authentication is injected by the host and never exposed; only the bounded origin, path prefix, and methods are allowed.',
|
|
517
|
+
parameters: {
|
|
518
|
+
type: 'object',
|
|
519
|
+
properties: {
|
|
520
|
+
binding_id: { type: 'string', description: 'Opaque HTTP credential binding ID from the Bitwarden integration summary.' },
|
|
521
|
+
method: { type: 'string', enum: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'] },
|
|
522
|
+
url: { type: 'string', description: 'Full HTTPS URL allowed by the binding.' },
|
|
523
|
+
headers: { type: 'object', description: 'Optional non-authentication request headers.' },
|
|
524
|
+
body: { type: 'string', description: 'Optional request body.' },
|
|
525
|
+
timeout_ms: { type: 'number', description: 'Optional timeout from 1000 to 120000 milliseconds.' }
|
|
526
|
+
},
|
|
527
|
+
required: ['binding_id', 'method', 'url']
|
|
528
|
+
}
|
|
529
|
+
},
|
|
467
530
|
{
|
|
468
531
|
name: 'desktop_list_devices',
|
|
469
532
|
description: 'List logged-in desktop companion devices available for local PC control.',
|
|
@@ -878,7 +941,7 @@ function getAvailableTools(app, options = {}) {
|
|
|
878
941
|
},
|
|
879
942
|
{
|
|
880
943
|
name: 'send_message',
|
|
881
|
-
description: `Send a message on a connected messaging platform. Supports WhatsApp (text/media), Telnyx Voice (phone calls — TTS), Discord, Telegram, Slack, Google Chat, Microsoft Teams, Matrix, Signal, iMessage/BlueBubbles, IRC, Feishu, LINE, Mattermost, Nextcloud Talk, Nostr, Synology Chat, Tlon, Twitch, Zalo, WeChat, WebChat, and configurable webhook bridges. ${buildSendMessageFormattingReference()} For WhatsApp: use media_path to attach files. Use content "[NO RESPONSE]" only when the user explicitly asked for silence/no reply, or when a background task intentionally decides no user-visible update is needed with purpose="no_response". For background task or schedule runs, set purpose to final_result, blocker, or no_response.`,
|
|
944
|
+
description: `Send a final message on a connected messaging platform. Use send_interim_update, not this tool, for an ongoing status reply to the originating chat. Supports WhatsApp (text/media), Telnyx Voice (phone calls — TTS), Discord, Telegram, Slack, Google Chat, Microsoft Teams, Matrix, Signal, iMessage/BlueBubbles, IRC, Feishu, LINE, Mattermost, Nextcloud Talk, Nostr, Synology Chat, Tlon, Twitch, Zalo, WeChat, WebChat, and configurable webhook bridges. ${buildSendMessageFormattingReference()} For WhatsApp: use media_path to attach files. Use content "[NO RESPONSE]" only when the user explicitly asked for silence/no reply, or when a background task intentionally decides no user-visible update is needed with purpose="no_response". For background task or schedule runs, set purpose to final_result, blocker, or no_response.`,
|
|
882
945
|
parameters: {
|
|
883
946
|
type: 'object',
|
|
884
947
|
properties: {
|
|
@@ -1632,7 +1695,8 @@ async function executeTool(toolName, args, context, engine) {
|
|
|
1632
1695
|
taskId,
|
|
1633
1696
|
widgetId,
|
|
1634
1697
|
deliveryState = null,
|
|
1635
|
-
allowMultipleProactiveMessages = false
|
|
1698
|
+
allowMultipleProactiveMessages = false,
|
|
1699
|
+
signal = null,
|
|
1636
1700
|
} = context;
|
|
1637
1701
|
const runtime = () => app?.locals?.runtimeManager || engine.runtimeManager || null;
|
|
1638
1702
|
const bc = async () => {
|
|
@@ -1641,7 +1705,10 @@ async function executeTool(toolName, args, context, engine) {
|
|
|
1641
1705
|
const backend = typeof manager.getActiveBrowserBackend === 'function'
|
|
1642
1706
|
? await Promise.resolve(manager.getActiveBrowserBackend(userId))
|
|
1643
1707
|
: 'vm';
|
|
1644
|
-
return {
|
|
1708
|
+
return {
|
|
1709
|
+
provider: await manager.getBrowserProviderForUser(userId, { signal }),
|
|
1710
|
+
backend,
|
|
1711
|
+
};
|
|
1645
1712
|
}
|
|
1646
1713
|
throw new Error('Browser provider is unavailable. VM runtime is required.');
|
|
1647
1714
|
};
|
|
@@ -1668,11 +1735,18 @@ async function executeTool(toolName, args, context, engine) {
|
|
|
1668
1735
|
const socialVideo = () => app?.locals?.socialVideoService || null;
|
|
1669
1736
|
const socialReach = () => app?.locals?.socialReachService || null;
|
|
1670
1737
|
const widgets = () => app?.locals?.widgetService || null;
|
|
1738
|
+
const credentials = () => app?.locals?.credentialBroker || null;
|
|
1671
1739
|
const artifactStore = app?.locals?.artifactStore || null;
|
|
1672
1740
|
|
|
1673
1741
|
const integrationManager = integrations();
|
|
1674
1742
|
if (integrationManager) {
|
|
1675
|
-
const integrationResult = await integrationManager.executeTool(
|
|
1743
|
+
const integrationResult = await integrationManager.executeTool(
|
|
1744
|
+
userId,
|
|
1745
|
+
toolName,
|
|
1746
|
+
args,
|
|
1747
|
+
agentId,
|
|
1748
|
+
{ signal },
|
|
1749
|
+
);
|
|
1676
1750
|
if (
|
|
1677
1751
|
integrationResult &&
|
|
1678
1752
|
typeof integrationResult === 'object' &&
|
|
@@ -1724,6 +1798,7 @@ async function executeTool(toolName, args, context, engine) {
|
|
|
1724
1798
|
stdinInput: args.stdin_input,
|
|
1725
1799
|
pty: args.pty === true,
|
|
1726
1800
|
inputs: Array.isArray(args.inputs) ? args.inputs : [],
|
|
1801
|
+
signal,
|
|
1727
1802
|
};
|
|
1728
1803
|
if (typeof runtimeManager.executeCliCommand === 'function') {
|
|
1729
1804
|
return await runtimeManager.executeCliCommand(userId, args.command, execOptions);
|
|
@@ -1736,7 +1811,7 @@ async function executeTool(toolName, args, context, engine) {
|
|
|
1736
1811
|
}
|
|
1737
1812
|
|
|
1738
1813
|
case 'browser_navigate': {
|
|
1739
|
-
const urlCheck =
|
|
1814
|
+
const urlCheck = await validateCloudUrlWithDns(args.url, { signal });
|
|
1740
1815
|
if (!urlCheck.allowed) return { error: 'URL is not allowed: blocked scheme or private/internal network address.' };
|
|
1741
1816
|
const { provider, backend } = await bc();
|
|
1742
1817
|
if (!provider) return { error: 'Browser controller not available' };
|
|
@@ -1745,14 +1820,15 @@ async function executeTool(toolName, args, context, engine) {
|
|
|
1745
1820
|
waitFor: args.waitFor,
|
|
1746
1821
|
fullPage: args.fullPage,
|
|
1747
1822
|
referrerMode: args.referrerMode,
|
|
1748
|
-
challengeRetry: args.challengeRetry
|
|
1823
|
+
challengeRetry: args.challengeRetry,
|
|
1824
|
+
signal,
|
|
1749
1825
|
}), backend };
|
|
1750
1826
|
}
|
|
1751
1827
|
|
|
1752
1828
|
case 'browser_click': {
|
|
1753
1829
|
const { provider, backend } = await bc();
|
|
1754
1830
|
if (!provider) return { error: 'Browser controller not available' };
|
|
1755
|
-
return { ...await provider.click(args.selector, args.text, args.screenshot !== false), backend };
|
|
1831
|
+
return { ...await provider.click(args.selector, args.text, args.screenshot !== false, { signal }), backend };
|
|
1756
1832
|
}
|
|
1757
1833
|
|
|
1758
1834
|
case 'browser_type': {
|
|
@@ -1760,20 +1836,21 @@ async function executeTool(toolName, args, context, engine) {
|
|
|
1760
1836
|
if (!provider) return { error: 'Browser controller not available' };
|
|
1761
1837
|
return { ...await provider.type(args.selector, args.text, {
|
|
1762
1838
|
clear: args.clear !== false,
|
|
1763
|
-
pressEnter: args.pressEnter
|
|
1839
|
+
pressEnter: args.pressEnter,
|
|
1840
|
+
signal,
|
|
1764
1841
|
}), backend };
|
|
1765
1842
|
}
|
|
1766
1843
|
|
|
1767
1844
|
case 'browser_extract': {
|
|
1768
1845
|
const { provider, backend } = await bc();
|
|
1769
1846
|
if (!provider) return { error: 'Browser controller not available' };
|
|
1770
|
-
return { ...await provider.extract(args.selector, args.attribute, args.all), backend };
|
|
1847
|
+
return { ...await provider.extract(args.selector, args.attribute, args.all, { signal }), backend };
|
|
1771
1848
|
}
|
|
1772
1849
|
|
|
1773
1850
|
case 'browser_screenshot': {
|
|
1774
1851
|
const { provider, backend } = await bc();
|
|
1775
1852
|
if (!provider) return { error: 'Browser controller not available' };
|
|
1776
|
-
return { ...await provider.screenshot({ fullPage: args.fullPage, selector: args.selector }), backend };
|
|
1853
|
+
return { ...await provider.screenshot({ fullPage: args.fullPage, selector: args.selector, signal }), backend };
|
|
1777
1854
|
}
|
|
1778
1855
|
|
|
1779
1856
|
case 'browser_evaluate': {
|
|
@@ -1781,13 +1858,37 @@ async function executeTool(toolName, args, context, engine) {
|
|
|
1781
1858
|
if (!provider) return { error: 'Browser controller not available' };
|
|
1782
1859
|
const script = args.script ?? args.javascript;
|
|
1783
1860
|
if (!script) return { error: 'browser_evaluate requires a "script" argument' };
|
|
1784
|
-
return { ...await provider.evaluate(script), backend };
|
|
1861
|
+
return { ...await provider.evaluate(script, { signal }), backend };
|
|
1862
|
+
}
|
|
1863
|
+
|
|
1864
|
+
case 'credential_fill_browser': {
|
|
1865
|
+
const broker = credentials();
|
|
1866
|
+
if (!broker) return { error: 'Credential broker is unavailable.' };
|
|
1867
|
+
return broker.fillBrowser(userId, agentId, args, { runId, signal });
|
|
1868
|
+
}
|
|
1869
|
+
|
|
1870
|
+
case 'credential_submit_browser': {
|
|
1871
|
+
const broker = credentials();
|
|
1872
|
+
if (!broker) return { error: 'Credential broker is unavailable.' };
|
|
1873
|
+
return broker.submitProtected(userId, agentId, args.protected_fill_id, { runId, signal });
|
|
1874
|
+
}
|
|
1875
|
+
|
|
1876
|
+
case 'credential_cancel_browser': {
|
|
1877
|
+
const broker = credentials();
|
|
1878
|
+
if (!broker) return { error: 'Credential broker is unavailable.' };
|
|
1879
|
+
return broker.cancelProtected(userId, agentId, args.protected_fill_id, { runId, signal });
|
|
1880
|
+
}
|
|
1881
|
+
|
|
1882
|
+
case 'credential_http_request': {
|
|
1883
|
+
const broker = credentials();
|
|
1884
|
+
if (!broker) return { error: 'Credential broker is unavailable.' };
|
|
1885
|
+
return broker.httpRequest(userId, agentId, args, { runId, signal });
|
|
1785
1886
|
}
|
|
1786
1887
|
|
|
1787
1888
|
case 'android_start_emulator': {
|
|
1788
1889
|
const controller = await ac();
|
|
1789
1890
|
if (!controller) return { error: 'Android controller not available' };
|
|
1790
|
-
return await controller.startEmulator(args || {});
|
|
1891
|
+
return await controller.startEmulator({ ...(args || {}), signal });
|
|
1791
1892
|
}
|
|
1792
1893
|
|
|
1793
1894
|
case 'desktop_list_devices': {
|
|
@@ -1814,6 +1915,7 @@ async function executeTool(toolName, args, context, engine) {
|
|
|
1814
1915
|
return await controller.observe({
|
|
1815
1916
|
deviceId: args.device_id,
|
|
1816
1917
|
includeTree: args.includeTree === true,
|
|
1918
|
+
signal,
|
|
1817
1919
|
});
|
|
1818
1920
|
}
|
|
1819
1921
|
|
|
@@ -1823,6 +1925,7 @@ async function executeTool(toolName, args, context, engine) {
|
|
|
1823
1925
|
return await controller.clickPoint(args.x, args.y, {
|
|
1824
1926
|
deviceId: args.device_id,
|
|
1825
1927
|
button: args.button,
|
|
1928
|
+
signal,
|
|
1826
1929
|
});
|
|
1827
1930
|
}
|
|
1828
1931
|
|
|
@@ -1836,6 +1939,7 @@ async function executeTool(toolName, args, context, engine) {
|
|
|
1836
1939
|
x2: args.x2,
|
|
1837
1940
|
y2: args.y2,
|
|
1838
1941
|
durationMs: args.durationMs,
|
|
1942
|
+
signal,
|
|
1839
1943
|
});
|
|
1840
1944
|
}
|
|
1841
1945
|
|
|
@@ -1846,6 +1950,7 @@ async function executeTool(toolName, args, context, engine) {
|
|
|
1846
1950
|
deviceId: args.device_id,
|
|
1847
1951
|
deltaX: args.deltaX,
|
|
1848
1952
|
deltaY: args.deltaY,
|
|
1953
|
+
signal,
|
|
1849
1954
|
});
|
|
1850
1955
|
}
|
|
1851
1956
|
|
|
@@ -1855,6 +1960,7 @@ async function executeTool(toolName, args, context, engine) {
|
|
|
1855
1960
|
return await controller.typeText(args.text, {
|
|
1856
1961
|
deviceId: args.device_id,
|
|
1857
1962
|
pressEnter: args.pressEnter === true,
|
|
1963
|
+
signal,
|
|
1858
1964
|
});
|
|
1859
1965
|
}
|
|
1860
1966
|
|
|
@@ -1863,6 +1969,7 @@ async function executeTool(toolName, args, context, engine) {
|
|
|
1863
1969
|
if (!controller) return { error: 'Desktop provider not available' };
|
|
1864
1970
|
return await controller.pressKey(args.key, {
|
|
1865
1971
|
deviceId: args.device_id,
|
|
1972
|
+
signal,
|
|
1866
1973
|
});
|
|
1867
1974
|
}
|
|
1868
1975
|
|
|
@@ -1872,6 +1979,7 @@ async function executeTool(toolName, args, context, engine) {
|
|
|
1872
1979
|
return await controller.launchApp({
|
|
1873
1980
|
deviceId: args.device_id,
|
|
1874
1981
|
app: args.app,
|
|
1982
|
+
signal,
|
|
1875
1983
|
});
|
|
1876
1984
|
}
|
|
1877
1985
|
|
|
@@ -1880,112 +1988,111 @@ async function executeTool(toolName, args, context, engine) {
|
|
|
1880
1988
|
if (!controller) return { error: 'Desktop provider not available' };
|
|
1881
1989
|
return await controller.getAccessibilityTree({
|
|
1882
1990
|
deviceId: args.device_id,
|
|
1991
|
+
signal,
|
|
1883
1992
|
});
|
|
1884
1993
|
}
|
|
1885
1994
|
|
|
1886
1995
|
case 'android_stop_emulator': {
|
|
1887
1996
|
const controller = await ac();
|
|
1888
1997
|
if (!controller) return { error: 'Android controller not available' };
|
|
1889
|
-
return await controller.stopEmulator();
|
|
1998
|
+
return await controller.stopEmulator({ signal });
|
|
1890
1999
|
}
|
|
1891
2000
|
|
|
1892
2001
|
case 'android_list_devices': {
|
|
1893
2002
|
const controller = await ac();
|
|
1894
2003
|
if (!controller) return { error: 'Android controller not available' };
|
|
1895
|
-
return { devices: await controller.listDevices() };
|
|
2004
|
+
return { devices: await controller.listDevices({ signal }) };
|
|
1896
2005
|
}
|
|
1897
2006
|
|
|
1898
2007
|
case 'android_open_app': {
|
|
1899
2008
|
const controller = await ac();
|
|
1900
2009
|
if (!controller) return { error: 'Android controller not available' };
|
|
1901
|
-
return await controller.openApp(args || {});
|
|
2010
|
+
return await controller.openApp({ ...(args || {}), signal });
|
|
1902
2011
|
}
|
|
1903
2012
|
|
|
1904
2013
|
case 'android_open_intent': {
|
|
1905
2014
|
const controller = await ac();
|
|
1906
2015
|
if (!controller) return { error: 'Android controller not available' };
|
|
1907
|
-
return await controller.openIntent(args || {});
|
|
2016
|
+
return await controller.openIntent({ ...(args || {}), signal });
|
|
1908
2017
|
}
|
|
1909
2018
|
|
|
1910
2019
|
case 'android_tap': {
|
|
1911
2020
|
const controller = await ac();
|
|
1912
2021
|
if (!controller) return { error: 'Android controller not available' };
|
|
1913
|
-
return await controller.tap(args || {});
|
|
2022
|
+
return await controller.tap({ ...(args || {}), signal });
|
|
1914
2023
|
}
|
|
1915
2024
|
|
|
1916
2025
|
case 'android_long_press': {
|
|
1917
2026
|
const controller = await ac();
|
|
1918
2027
|
if (!controller) return { error: 'Android controller not available' };
|
|
1919
|
-
return await controller.longPress(args || {});
|
|
2028
|
+
return await controller.longPress({ ...(args || {}), signal });
|
|
1920
2029
|
}
|
|
1921
2030
|
|
|
1922
2031
|
case 'android_type': {
|
|
1923
2032
|
const controller = await ac();
|
|
1924
2033
|
if (!controller) return { error: 'Android controller not available' };
|
|
1925
|
-
return await controller.type(args || {});
|
|
2034
|
+
return await controller.type({ ...(args || {}), signal });
|
|
1926
2035
|
}
|
|
1927
2036
|
|
|
1928
2037
|
case 'android_swipe': {
|
|
1929
2038
|
const controller = await ac();
|
|
1930
2039
|
if (!controller) return { error: 'Android controller not available' };
|
|
1931
|
-
return await controller.swipe(args || {});
|
|
2040
|
+
return await controller.swipe({ ...(args || {}), signal });
|
|
1932
2041
|
}
|
|
1933
2042
|
|
|
1934
2043
|
case 'android_press_key': {
|
|
1935
2044
|
const controller = await ac();
|
|
1936
2045
|
if (!controller) return { error: 'Android controller not available' };
|
|
1937
|
-
return await controller.pressKey(args || {});
|
|
2046
|
+
return await controller.pressKey({ ...(args || {}), signal });
|
|
1938
2047
|
}
|
|
1939
2048
|
|
|
1940
2049
|
case 'android_wait_for': {
|
|
1941
2050
|
const controller = await ac();
|
|
1942
2051
|
if (!controller) return { error: 'Android controller not available' };
|
|
1943
|
-
return await controller.waitFor(args || {});
|
|
2052
|
+
return await controller.waitFor({ ...(args || {}), signal });
|
|
1944
2053
|
}
|
|
1945
2054
|
|
|
1946
2055
|
case 'android_observe': {
|
|
1947
2056
|
const controller = await ac();
|
|
1948
2057
|
if (!controller) return { error: 'Android controller not available' };
|
|
1949
|
-
return await controller.observe(args || {});
|
|
2058
|
+
return await controller.observe({ ...(args || {}), signal });
|
|
1950
2059
|
}
|
|
1951
2060
|
|
|
1952
2061
|
case 'android_dump_ui': {
|
|
1953
2062
|
const controller = await ac();
|
|
1954
2063
|
if (!controller) return { error: 'Android controller not available' };
|
|
1955
|
-
return await controller.dumpUi(args || {});
|
|
2064
|
+
return await controller.dumpUi({ ...(args || {}), signal });
|
|
1956
2065
|
}
|
|
1957
2066
|
|
|
1958
2067
|
case 'android_screenshot': {
|
|
1959
2068
|
const controller = await ac();
|
|
1960
2069
|
if (!controller) return { error: 'Android controller not available' };
|
|
1961
|
-
return await controller.screenshot(args || {});
|
|
2070
|
+
return await controller.screenshot({ ...(args || {}), signal });
|
|
1962
2071
|
}
|
|
1963
2072
|
|
|
1964
2073
|
case 'android_list_apps': {
|
|
1965
2074
|
const controller = await ac();
|
|
1966
2075
|
if (!controller) return { error: 'Android controller not available' };
|
|
1967
|
-
return await controller.listApps(args || {});
|
|
2076
|
+
return await controller.listApps({ ...(args || {}), signal });
|
|
1968
2077
|
}
|
|
1969
2078
|
|
|
1970
2079
|
case 'android_install_apk': {
|
|
1971
2080
|
const controller = await ac();
|
|
1972
2081
|
if (!controller) return { error: 'Android controller not available' };
|
|
1973
|
-
return await controller.installApk(args || {});
|
|
2082
|
+
return await controller.installApk({ ...(args || {}), signal });
|
|
1974
2083
|
}
|
|
1975
2084
|
|
|
1976
2085
|
case 'android_shell': {
|
|
1977
2086
|
const controller = await ac();
|
|
1978
2087
|
if (!controller) return { error: 'Android controller not available' };
|
|
1979
|
-
return await controller.shell(args || {});
|
|
2088
|
+
return await controller.shell({ ...(args || {}), signal });
|
|
1980
2089
|
}
|
|
1981
2090
|
|
|
1982
2091
|
case 'web_search': {
|
|
1983
2092
|
const apiKey = process.env.BRAVE_SEARCH_API_KEY;
|
|
1984
2093
|
if (!apiKey) return { error: 'BRAVE_SEARCH_API_KEY is not configured' };
|
|
1985
2094
|
|
|
1986
|
-
const controller = new AbortController();
|
|
1987
2095
|
const timeoutMs = 20000;
|
|
1988
|
-
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
1989
2096
|
|
|
1990
2097
|
try {
|
|
1991
2098
|
const limit = Math.max(1, Math.min(Number(args.count) || 5, 10));
|
|
@@ -2000,15 +2107,20 @@ async function executeTool(toolName, args, context, engine) {
|
|
|
2000
2107
|
if (args.search_lang) params.set('search_lang', String(args.search_lang).toLowerCase());
|
|
2001
2108
|
if (args.freshness) params.set('freshness', args.freshness);
|
|
2002
2109
|
|
|
2003
|
-
const
|
|
2110
|
+
const { response, text } = await fetchResponseText(
|
|
2111
|
+
`https://api.search.brave.com/res/v1/web/search?${params.toString()}`,
|
|
2112
|
+
{
|
|
2004
2113
|
headers: {
|
|
2005
2114
|
Accept: 'application/json',
|
|
2006
2115
|
'X-Subscription-Token': apiKey
|
|
2007
2116
|
},
|
|
2008
|
-
|
|
2009
|
-
|
|
2117
|
+
maxResponseBytes: 2 * 1024 * 1024,
|
|
2118
|
+
serviceName: 'Brave Search',
|
|
2119
|
+
signal,
|
|
2120
|
+
timeoutMs,
|
|
2121
|
+
},
|
|
2122
|
+
);
|
|
2010
2123
|
|
|
2011
|
-
const text = await res.text();
|
|
2012
2124
|
let data = null;
|
|
2013
2125
|
try {
|
|
2014
2126
|
data = JSON.parse(text);
|
|
@@ -2016,9 +2128,9 @@ async function executeTool(toolName, args, context, engine) {
|
|
|
2016
2128
|
data = null;
|
|
2017
2129
|
}
|
|
2018
2130
|
|
|
2019
|
-
if (!
|
|
2131
|
+
if (!response.ok) {
|
|
2020
2132
|
return {
|
|
2021
|
-
error: `Brave Search API request failed with status ${
|
|
2133
|
+
error: `Brave Search API request failed with status ${response.status}`,
|
|
2022
2134
|
details: data || text.slice(0, 1000)
|
|
2023
2135
|
};
|
|
2024
2136
|
}
|
|
@@ -2040,10 +2152,11 @@ async function executeTool(toolName, args, context, engine) {
|
|
|
2040
2152
|
results
|
|
2041
2153
|
};
|
|
2042
2154
|
} catch (err) {
|
|
2043
|
-
if (err
|
|
2155
|
+
if (isAbortError(err, signal)) throw err;
|
|
2156
|
+
if (err.code === 'HTTP_TIMEOUT') {
|
|
2157
|
+
return { error: `Brave Search API request timed out after ${timeoutMs}ms` };
|
|
2158
|
+
}
|
|
2044
2159
|
return { error: err.message };
|
|
2045
|
-
} finally {
|
|
2046
|
-
clearTimeout(timer);
|
|
2047
2160
|
}
|
|
2048
2161
|
}
|
|
2049
2162
|
|
|
@@ -2051,7 +2164,13 @@ async function executeTool(toolName, args, context, engine) {
|
|
|
2051
2164
|
const { MemoryManager } = require('../memory/manager');
|
|
2052
2165
|
const mm = new MemoryManager();
|
|
2053
2166
|
const content = typeof args.content === 'string' ? args.content : args.value;
|
|
2054
|
-
const id = await mm.saveMemory(
|
|
2167
|
+
const id = await mm.saveMemory(
|
|
2168
|
+
userId,
|
|
2169
|
+
content,
|
|
2170
|
+
args.category || 'episodic',
|
|
2171
|
+
args.importance || 5,
|
|
2172
|
+
{ agentId, signal },
|
|
2173
|
+
);
|
|
2055
2174
|
if (!id) {
|
|
2056
2175
|
return {
|
|
2057
2176
|
success: true,
|
|
@@ -2065,7 +2184,12 @@ async function executeTool(toolName, args, context, engine) {
|
|
|
2065
2184
|
case 'memory_recall': {
|
|
2066
2185
|
const { MemoryManager } = require('../memory/manager');
|
|
2067
2186
|
const mm = new MemoryManager();
|
|
2068
|
-
const results = await mm.recallMemory(
|
|
2187
|
+
const results = await mm.recallMemory(
|
|
2188
|
+
userId,
|
|
2189
|
+
args.query,
|
|
2190
|
+
args.limit || 6,
|
|
2191
|
+
{ agentId, signal },
|
|
2192
|
+
);
|
|
2069
2193
|
if (!results.length) return { results: [], message: 'Nothing found' };
|
|
2070
2194
|
return { results };
|
|
2071
2195
|
}
|
|
@@ -2198,6 +2322,7 @@ async function executeTool(toolName, args, context, engine) {
|
|
|
2198
2322
|
includeFrame: args.include_frame !== false,
|
|
2199
2323
|
forceStt: args.force_stt === true,
|
|
2200
2324
|
agentId,
|
|
2325
|
+
signal,
|
|
2201
2326
|
});
|
|
2202
2327
|
}
|
|
2203
2328
|
|
|
@@ -2206,7 +2331,7 @@ async function executeTool(toolName, args, context, engine) {
|
|
|
2206
2331
|
if (!service || typeof service.getStatus !== 'function') {
|
|
2207
2332
|
return { error: 'Social reach service is unavailable.' };
|
|
2208
2333
|
}
|
|
2209
|
-
return await service.getStatus(userId);
|
|
2334
|
+
return await service.getStatus(userId, { signal });
|
|
2210
2335
|
}
|
|
2211
2336
|
|
|
2212
2337
|
case 'social_reach_read': {
|
|
@@ -2214,7 +2339,7 @@ async function executeTool(toolName, args, context, engine) {
|
|
|
2214
2339
|
if (!service || typeof service.read !== 'function') {
|
|
2215
2340
|
return { error: 'Social reach service is unavailable.' };
|
|
2216
2341
|
}
|
|
2217
|
-
return await service.read(userId, args || {});
|
|
2342
|
+
return await service.read(userId, args || {}, { signal });
|
|
2218
2343
|
}
|
|
2219
2344
|
|
|
2220
2345
|
case 'social_reach_search': {
|
|
@@ -2222,7 +2347,7 @@ async function executeTool(toolName, args, context, engine) {
|
|
|
2222
2347
|
if (!service || typeof service.search !== 'function') {
|
|
2223
2348
|
return { error: 'Social reach service is unavailable.' };
|
|
2224
2349
|
}
|
|
2225
|
-
return await service.search(userId, args || {});
|
|
2350
|
+
return await service.search(userId, args || {}, { signal });
|
|
2226
2351
|
}
|
|
2227
2352
|
|
|
2228
2353
|
case 'memory_write': {
|
|
@@ -2305,6 +2430,13 @@ async function executeTool(toolName, args, context, engine) {
|
|
|
2305
2430
|
stripNoResponseMarker: false
|
|
2306
2431
|
});
|
|
2307
2432
|
const suppressReply = normalizedMessage === '[NO RESPONSE]';
|
|
2433
|
+
const originDelivery = isOriginMessagingDelivery({
|
|
2434
|
+
triggerSource,
|
|
2435
|
+
source: context.source,
|
|
2436
|
+
chatId: context.chatId,
|
|
2437
|
+
platform: args.platform,
|
|
2438
|
+
to: args.to,
|
|
2439
|
+
});
|
|
2308
2440
|
if (isProactiveTrigger(triggerSource)) {
|
|
2309
2441
|
const proactiveValidation = validateProactiveSendMessageArgs({
|
|
2310
2442
|
purpose: args.purpose,
|
|
@@ -2360,24 +2492,22 @@ async function executeTool(toolName, args, context, engine) {
|
|
|
2360
2492
|
};
|
|
2361
2493
|
}
|
|
2362
2494
|
|
|
2495
|
+
if (triggerSource === 'messaging' && originDelivery) {
|
|
2496
|
+
await engine?.stopMessagingProgressSupervisor?.(runId);
|
|
2497
|
+
}
|
|
2363
2498
|
const sendResult = await manager.sendMessage(userId, args.platform, args.to, args.content, {
|
|
2364
2499
|
agentId,
|
|
2365
2500
|
mediaPath: args.media_path,
|
|
2366
2501
|
runId,
|
|
2367
|
-
persistConversation: triggerSource === 'schedule' || triggerSource === 'tasks'
|
|
2502
|
+
persistConversation: triggerSource === 'schedule' || triggerSource === 'tasks',
|
|
2503
|
+
signal,
|
|
2368
2504
|
});
|
|
2369
2505
|
// Track that the agent explicitly sent a message during this run
|
|
2370
2506
|
if (
|
|
2371
2507
|
!suppressReply
|
|
2372
2508
|
&& sendResult?.success === true
|
|
2373
2509
|
&& sendResult?.suppressed !== true
|
|
2374
|
-
&&
|
|
2375
|
-
triggerSource,
|
|
2376
|
-
source: context.source,
|
|
2377
|
-
chatId: context.chatId,
|
|
2378
|
-
platform: args.platform,
|
|
2379
|
-
to: args.to,
|
|
2380
|
-
})
|
|
2510
|
+
&& originDelivery
|
|
2381
2511
|
) {
|
|
2382
2512
|
markProactiveMessageSent({ runState, deliveryState, content: normalizedMessage });
|
|
2383
2513
|
if (runState && triggerSource === 'messaging') {
|
|
@@ -2557,66 +2687,14 @@ async function executeTool(toolName, args, context, engine) {
|
|
|
2557
2687
|
}
|
|
2558
2688
|
|
|
2559
2689
|
case 'http_request': {
|
|
2560
|
-
let parsedUrl;
|
|
2561
|
-
try { parsedUrl = new URL(args.url); } catch {
|
|
2562
|
-
return { error: 'Invalid URL' };
|
|
2563
|
-
}
|
|
2564
|
-
const scheme = parsedUrl.protocol.replace(/:$/, '').toLowerCase();
|
|
2565
|
-
if (!['http', 'https'].includes(scheme)) {
|
|
2566
|
-
return { error: 'URL scheme not allowed. Only http and https are permitted.' };
|
|
2567
|
-
}
|
|
2568
|
-
const h = parsedUrl.hostname.toLowerCase().replace(/^\[|\]$/g, '');
|
|
2569
|
-
if (h === 'localhost' || h === '127.0.0.1' || h === '::1' || h.endsWith('.localhost')) {
|
|
2570
|
-
return { error: 'Loopback addresses are not permitted.' };
|
|
2571
|
-
}
|
|
2572
|
-
const allowPrivate = process.env.NEOAGENT_HTTP_ALLOW_PRIVATE !== 'false';
|
|
2573
|
-
if (!allowPrivate && isPrivateHost(parsedUrl.hostname)) {
|
|
2574
|
-
return { error: 'Private/internal network addresses are not permitted.' };
|
|
2575
|
-
}
|
|
2576
|
-
const controller = new AbortController();
|
|
2577
|
-
const timeoutMs = args.timeout_ms || 30000;
|
|
2578
|
-
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
2579
2690
|
try {
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
};
|
|
2585
|
-
if (args.body && ['POST', 'PUT', 'PATCH'].includes(options.method)) {
|
|
2586
|
-
options.body = args.body;
|
|
2587
|
-
if (!options.headers['Content-Type']) {
|
|
2588
|
-
options.headers['Content-Type'] = 'application/json';
|
|
2589
|
-
}
|
|
2590
|
-
}
|
|
2591
|
-
const res = await fetch(args.url, options);
|
|
2592
|
-
const MAX_BODY = 512 * 1024;
|
|
2593
|
-
const reader = res.body.getReader();
|
|
2594
|
-
const chunks = [];
|
|
2595
|
-
let total = 0;
|
|
2596
|
-
let truncated = false;
|
|
2597
|
-
while (true) {
|
|
2598
|
-
const { done, value } = await reader.read();
|
|
2599
|
-
if (done) break;
|
|
2600
|
-
total += value.length;
|
|
2601
|
-
if (total > MAX_BODY) {
|
|
2602
|
-
const take = MAX_BODY - (total - value.length);
|
|
2603
|
-
if (take > 0) chunks.push(value.slice(0, take));
|
|
2604
|
-
truncated = true;
|
|
2605
|
-
break;
|
|
2606
|
-
}
|
|
2607
|
-
chunks.push(value);
|
|
2608
|
-
}
|
|
2609
|
-
const text = Buffer.concat(chunks.map(c => Buffer.from(c))).toString('utf-8');
|
|
2610
|
-
return {
|
|
2611
|
-
status: res.status,
|
|
2612
|
-
headers: Object.fromEntries(res.headers.entries()),
|
|
2613
|
-
body: truncated ? text + '\n...[truncated]' : text,
|
|
2614
|
-
};
|
|
2691
|
+
return await executeHttpRequest(args, {
|
|
2692
|
+
allowPrivate: process.env.NEOAGENT_HTTP_ALLOW_PRIVATE === 'true',
|
|
2693
|
+
signal,
|
|
2694
|
+
});
|
|
2615
2695
|
} catch (err) {
|
|
2616
|
-
if (err
|
|
2696
|
+
if (isAbortError(err, signal)) throw err;
|
|
2617
2697
|
return { error: err.message };
|
|
2618
|
-
} finally {
|
|
2619
|
-
clearTimeout(timer);
|
|
2620
2698
|
}
|
|
2621
2699
|
}
|
|
2622
2700
|
|
|
@@ -2762,7 +2840,8 @@ async function executeTool(toolName, args, context, engine) {
|
|
|
2762
2840
|
const sendResult = await manager.sendMessage(userId, target.platform, target.to, message, {
|
|
2763
2841
|
agentId,
|
|
2764
2842
|
runId,
|
|
2765
|
-
persistConversation: true
|
|
2843
|
+
persistConversation: true,
|
|
2844
|
+
signal,
|
|
2766
2845
|
});
|
|
2767
2846
|
if (taskId && taskConfig && (taskConfig.notifyPlatform !== target.platform || taskConfig.notifyTo !== target.to)) {
|
|
2768
2847
|
taskConfig.notifyPlatform = target.platform;
|