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
|
@@ -25,7 +25,7 @@ router.get('/status', async (req, res) => {
|
|
|
25
25
|
if (!service || typeof service.getStatus !== 'function') {
|
|
26
26
|
return res.status(503).json({ error: 'Social reach service is unavailable.' });
|
|
27
27
|
}
|
|
28
|
-
return res.json(await service.getStatus(req.session.userId));
|
|
28
|
+
return res.json(await service.getStatus(req.session.userId, { signal: req.signal }));
|
|
29
29
|
} catch (error) {
|
|
30
30
|
return sendError(res, error);
|
|
31
31
|
}
|
|
@@ -37,7 +37,11 @@ router.post('/read', async (req, res) => {
|
|
|
37
37
|
if (!service || typeof service.read !== 'function') {
|
|
38
38
|
return res.status(503).json({ error: 'Social reach service is unavailable.' });
|
|
39
39
|
}
|
|
40
|
-
return res.json(await service.read(
|
|
40
|
+
return res.json(await service.read(
|
|
41
|
+
req.session.userId,
|
|
42
|
+
req.body || {},
|
|
43
|
+
{ signal: req.signal },
|
|
44
|
+
));
|
|
41
45
|
} catch (error) {
|
|
42
46
|
return sendError(res, error);
|
|
43
47
|
}
|
|
@@ -49,7 +53,11 @@ router.post('/search', async (req, res) => {
|
|
|
49
53
|
if (!service || typeof service.search !== 'function') {
|
|
50
54
|
return res.status(503).json({ error: 'Social reach service is unavailable.' });
|
|
51
55
|
}
|
|
52
|
-
return res.json(await service.search(
|
|
56
|
+
return res.json(await service.search(
|
|
57
|
+
req.session.userId,
|
|
58
|
+
req.body || {},
|
|
59
|
+
{ signal: req.signal },
|
|
60
|
+
));
|
|
53
61
|
} catch (error) {
|
|
54
62
|
return sendError(res, error);
|
|
55
63
|
}
|
|
@@ -67,6 +75,7 @@ router.post('/cookies/import', async (req, res) => {
|
|
|
67
75
|
}
|
|
68
76
|
return res.json(await service.importCookiesFromExtension(req.session.userId, platform, {
|
|
69
77
|
tokenId: req.body?.tokenId || req.body?.token_id || null,
|
|
78
|
+
signal: req.signal,
|
|
70
79
|
}));
|
|
71
80
|
} catch (error) {
|
|
72
81
|
return sendError(res, error);
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
1
3
|
const express = require('express');
|
|
2
4
|
const { requireAuth } = require('../middleware/auth');
|
|
3
5
|
const { getAgentIdFromRequest, resolveAgentId } = require('../services/agents/manager');
|
|
@@ -18,6 +20,7 @@ router.get('/health', async (req, res) => {
|
|
|
18
20
|
}
|
|
19
21
|
const health = await service.getHealthStatus({
|
|
20
22
|
forceRefresh: req.query?.refresh === '1' || req.query?.refresh === 'true',
|
|
23
|
+
signal: req.signal,
|
|
21
24
|
});
|
|
22
25
|
return res.json(health);
|
|
23
26
|
} catch (error) {
|
|
@@ -46,6 +49,7 @@ router.post('/extract', async (req, res) => {
|
|
|
46
49
|
includeFrame: req.body?.include_frame !== false,
|
|
47
50
|
forceStt: req.body?.force_stt === true,
|
|
48
51
|
agentId,
|
|
52
|
+
signal: req.signal,
|
|
49
53
|
});
|
|
50
54
|
|
|
51
55
|
if (result?.setup?.ready === false) {
|
|
@@ -77,7 +77,7 @@ function ensureMainAgent(userId) {
|
|
|
77
77
|
userId,
|
|
78
78
|
MAIN_AGENT_SLUG,
|
|
79
79
|
'Main',
|
|
80
|
-
'Default personal
|
|
80
|
+
'Default personal AI contact and fallback agent.',
|
|
81
81
|
'Handle general requests. Delegate to specialist agents only when their responsibilities clearly match.',
|
|
82
82
|
'',
|
|
83
83
|
);
|
|
@@ -39,6 +39,9 @@ async function getBrowserHealth(userId, app, engine) {
|
|
|
39
39
|
const runtimeSettings = typeof runtimeManager?.getSettings === 'function'
|
|
40
40
|
? runtimeManager.getSettings(userId)
|
|
41
41
|
: null;
|
|
42
|
+
const runtimeSnapshot = typeof runtimeManager?.getCapabilitySnapshot === 'function'
|
|
43
|
+
? runtimeManager.getCapabilitySnapshot(userId)
|
|
44
|
+
: null;
|
|
42
45
|
const extensionStatus = runtimeSettings?.browser_backend === 'extension'
|
|
43
46
|
? app?.locals?.browserExtensionRegistry?.getStatus(userId)
|
|
44
47
|
: null;
|
|
@@ -63,122 +66,81 @@ async function getBrowserHealth(userId, app, engine) {
|
|
|
63
66
|
});
|
|
64
67
|
}
|
|
65
68
|
}
|
|
66
|
-
|
|
67
|
-
let resolutionError = null;
|
|
68
|
-
|
|
69
|
-
if (runtimeManager && typeof runtimeManager.getBrowserProviderForUser === 'function') {
|
|
70
|
-
try {
|
|
71
|
-
controller = await runtimeManager.getBrowserProviderForUser(userId);
|
|
72
|
-
} catch (err) {
|
|
73
|
-
resolutionError = err;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
if (!controller) {
|
|
78
|
-
resolutionError = resolutionError || new Error('Browser provider is unavailable. VM runtime is required.');
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
if (!controller && resolutionError) {
|
|
69
|
+
if (!runtimeManager) {
|
|
82
70
|
return capabilityEntry({
|
|
83
|
-
|
|
84
|
-
healthy: false,
|
|
85
|
-
degraded: true,
|
|
86
|
-
summary: `Browser controller resolution failed: ${resolutionError.message}`,
|
|
87
|
-
details: {
|
|
88
|
-
error: resolutionError.message,
|
|
89
|
-
},
|
|
71
|
+
summary: 'Browser runtime is not available in this environment.',
|
|
90
72
|
});
|
|
91
73
|
}
|
|
92
|
-
let pageInfo = null;
|
|
93
|
-
let launched = false;
|
|
94
|
-
let error = null;
|
|
95
74
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
75
|
+
// Capability reporting runs on every agent turn. It must never resolve a
|
|
76
|
+
// provider because the VM provider performs image builds and container boot.
|
|
77
|
+
// Tool execution remains the authoritative health check and starts/restarts
|
|
78
|
+
// the runtime only when the model actually uses a browser tool.
|
|
79
|
+
const preferredBackend = runtimeSettings?.browser_backend
|
|
80
|
+
|| runtimeSnapshot?.browser?.preferredBackend
|
|
81
|
+
|| 'vm';
|
|
82
|
+
const vmInitialized = runtimeSnapshot?.browser?.vmInitialized === true;
|
|
83
|
+
const extensionConnected = extensionStatus?.connected === true
|
|
84
|
+
|| runtimeSnapshot?.browser?.extensionConnected === true;
|
|
85
|
+
const extensionPreferredButOffline = preferredBackend === 'extension' && !extensionConnected;
|
|
104
86
|
|
|
105
87
|
return capabilityEntry({
|
|
106
|
-
connected:
|
|
88
|
+
connected: vmInitialized || extensionConnected,
|
|
107
89
|
configured: true,
|
|
108
|
-
healthy:
|
|
109
|
-
degraded:
|
|
110
|
-
summary:
|
|
111
|
-
?
|
|
112
|
-
:
|
|
113
|
-
?
|
|
114
|
-
:
|
|
90
|
+
healthy: true,
|
|
91
|
+
degraded: extensionPreferredButOffline,
|
|
92
|
+
summary: extensionPreferredButOffline
|
|
93
|
+
? 'No extension device is active. The VM browser will start on first use.'
|
|
94
|
+
: vmInitialized
|
|
95
|
+
? 'Browser VM session is initialized.'
|
|
96
|
+
: 'Browser runtime is available and will start on first use.',
|
|
115
97
|
details: {
|
|
116
|
-
preferredBackend
|
|
117
|
-
backend:
|
|
118
|
-
|
|
119
|
-
: runtimeSettings?.browser_backend || null,
|
|
120
|
-
extensionConnected: extensionStatus?.connected === true,
|
|
98
|
+
preferredBackend,
|
|
99
|
+
backend: extensionConnected ? 'extension' : 'vm',
|
|
100
|
+
extensionConnected,
|
|
121
101
|
activeTokenCount: Array.isArray(extensionStatus?.tokens)
|
|
122
102
|
? extensionStatus.tokens.filter((token) => token.status === 'active').length
|
|
123
103
|
: 0,
|
|
124
|
-
|
|
125
|
-
pageInfo,
|
|
104
|
+
runtimeInitialized: vmInitialized,
|
|
126
105
|
},
|
|
127
106
|
});
|
|
128
107
|
}
|
|
129
108
|
|
|
130
109
|
async function getAndroidHealth(userId, app, engine) {
|
|
131
110
|
const runtimeManager = app?.locals?.runtimeManager || engine?.runtimeManager || null;
|
|
132
|
-
|
|
133
|
-
let resolutionError = null;
|
|
134
|
-
|
|
135
|
-
if (runtimeManager && typeof runtimeManager.getAndroidProviderForUser === 'function') {
|
|
136
|
-
try {
|
|
137
|
-
controller = await runtimeManager.getAndroidProviderForUser(userId);
|
|
138
|
-
} catch (err) {
|
|
139
|
-
resolutionError = err;
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
if (!controller) {
|
|
144
|
-
resolutionError = resolutionError || new Error('Android provider is unavailable. VM runtime is required.');
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
if (!controller || typeof controller.getStatus !== 'function') {
|
|
111
|
+
if (!runtimeManager) {
|
|
148
112
|
return capabilityEntry({
|
|
149
|
-
|
|
150
|
-
summary: resolutionError
|
|
151
|
-
? `Android controller resolution failed: ${resolutionError.message}`
|
|
152
|
-
: 'Android controller is not available.',
|
|
153
|
-
details: resolutionError ? { error: resolutionError.message } : {},
|
|
113
|
+
summary: 'Android runtime is not available in this environment.',
|
|
154
114
|
});
|
|
155
115
|
}
|
|
156
116
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
117
|
+
// Like browser health, Android health is a snapshot. Creating a controller or
|
|
118
|
+
// running adb here makes unrelated chat turns pay runtime startup/status costs.
|
|
119
|
+
const runtimeSnapshot = typeof runtimeManager.getCapabilitySnapshot === 'function'
|
|
120
|
+
? runtimeManager.getCapabilitySnapshot(userId)
|
|
121
|
+
: null;
|
|
122
|
+
const status = runtimeSnapshot?.android?.status || null;
|
|
123
|
+
const bootstrapped = status?.bootstrapped === true;
|
|
124
|
+
const starting = status?.starting === true;
|
|
125
|
+
const lastStartError = String(status?.lastStartError || '').trim();
|
|
126
|
+
return capabilityEntry({
|
|
127
|
+
connected: bootstrapped,
|
|
128
|
+
configured: true,
|
|
129
|
+
healthy: !lastStartError,
|
|
130
|
+
degraded: Boolean(lastStartError),
|
|
131
|
+
summary: lastStartError
|
|
132
|
+
? `Android tooling reported: ${lastStartError}`
|
|
133
|
+
: bootstrapped
|
|
134
|
+
? 'Android environment is ready.'
|
|
135
|
+
: starting
|
|
136
|
+
? 'Android environment is starting.'
|
|
137
|
+
: 'Android runtime is available and will initialize on first use.',
|
|
138
|
+
details: status || {
|
|
139
|
+
initialized: runtimeSnapshot?.android?.initialized === true,
|
|
140
|
+
bootstrapped: false,
|
|
141
|
+
starting: false,
|
|
142
|
+
},
|
|
143
|
+
});
|
|
182
144
|
}
|
|
183
145
|
|
|
184
146
|
function getMessagingHealth(userId, app, engine, agentId = null) {
|
|
@@ -342,7 +304,9 @@ function getTaskHealth(userId, agentId = null) {
|
|
|
342
304
|
}
|
|
343
305
|
|
|
344
306
|
async function getCapabilityHealth({ userId, agentId = null, app, engine }) {
|
|
345
|
-
const providers = await getProviderHealthCatalog(userId, agentId
|
|
307
|
+
const providers = await getProviderHealthCatalog(userId, agentId, {
|
|
308
|
+
probeLocal: false,
|
|
309
|
+
});
|
|
346
310
|
|
|
347
311
|
return {
|
|
348
312
|
providers,
|
|
@@ -363,6 +327,8 @@ async function getCapabilityHealth({ userId, agentId = null, app, engine }) {
|
|
|
363
327
|
}
|
|
364
328
|
|
|
365
329
|
module.exports = {
|
|
330
|
+
getAndroidHealth,
|
|
331
|
+
getBrowserHealth,
|
|
366
332
|
getCapabilityHealth,
|
|
367
333
|
summarizeCapabilityHealth,
|
|
368
334
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
async function compact(messages, provider, model, contextWindow = null) {
|
|
1
|
+
async function compact(messages, provider, model, contextWindow = null, options = {}) {
|
|
2
2
|
const systemMsg = messages.find(m => m.role === 'system');
|
|
3
3
|
const nonSystem = messages.filter(m => m.role !== 'system');
|
|
4
4
|
const beforeTokens = estimateTokenCount(messages);
|
|
@@ -26,7 +26,11 @@ async function compact(messages, provider, model, contextWindow = null) {
|
|
|
26
26
|
];
|
|
27
27
|
|
|
28
28
|
try {
|
|
29
|
-
const response = await provider.chat(summaryPrompt, [], {
|
|
29
|
+
const response = await provider.chat(summaryPrompt, [], {
|
|
30
|
+
model,
|
|
31
|
+
maxTokens: 1600,
|
|
32
|
+
signal: options.signal,
|
|
33
|
+
});
|
|
30
34
|
const summary = response.content || 'Previous conversation context (summary unavailable).';
|
|
31
35
|
|
|
32
36
|
const compactedMessages = [];
|
|
@@ -44,6 +48,7 @@ async function compact(messages, provider, model, contextWindow = null) {
|
|
|
44
48
|
}
|
|
45
49
|
return compactedMessages;
|
|
46
50
|
} catch (err) {
|
|
51
|
+
if (options.signal?.aborted) throw err;
|
|
47
52
|
console.error('Compaction failed:', err.message);
|
|
48
53
|
const trimmed = [];
|
|
49
54
|
if (systemMsg) trimmed.push(systemMsg);
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
1
3
|
const db = require('../../db/database');
|
|
2
4
|
const { resolveAgentId } = require('../agents/manager');
|
|
5
|
+
const { throwIfAborted } = require('../../utils/abort');
|
|
3
6
|
|
|
4
7
|
const WEB_SUMMARY_KEY = 'web_chat_summary';
|
|
5
8
|
const WEB_SUMMARY_COUNT_KEY = 'web_chat_summary_count';
|
|
@@ -109,13 +112,21 @@ function serializeHistoryForSummary(messages) {
|
|
|
109
112
|
}).join('\n');
|
|
110
113
|
}
|
|
111
114
|
|
|
112
|
-
async function summarizeMessages(
|
|
115
|
+
async function summarizeMessages(
|
|
116
|
+
provider,
|
|
117
|
+
model,
|
|
118
|
+
existingSummary,
|
|
119
|
+
messages,
|
|
120
|
+
label = 'conversation',
|
|
121
|
+
options = {},
|
|
122
|
+
) {
|
|
113
123
|
if (!messages.length) return existingSummary || '';
|
|
124
|
+
throwIfAborted(options.signal, 'Conversation summary refresh aborted.');
|
|
114
125
|
|
|
115
126
|
const prompt = [
|
|
116
127
|
{
|
|
117
128
|
role: 'system',
|
|
118
|
-
content: 'Compress conversation context. Preserve user goals, constraints, preferences, decisions, promised follow-ups, recurring schedules, important facts, tool outcomes, and unresolved issues. Keep concrete details (names, dates, times, statuses) and avoid vague wording. Keep the same personality context. Output plain text only.'
|
|
129
|
+
content: 'Compress conversation context. Preserve user goals, constraints, preferences, decisions, promised follow-ups, recurring schedules, important facts, tool outcomes, and unresolved issues. Keep concrete details (names, dates, times, statuses) and avoid vague wording. Keep the same personality context, including the favorite-contact texting register when relevant. Output plain text only.'
|
|
119
130
|
},
|
|
120
131
|
{
|
|
121
132
|
role: 'user',
|
|
@@ -127,7 +138,12 @@ async function summarizeMessages(provider, model, existingSummary, messages, lab
|
|
|
127
138
|
}
|
|
128
139
|
];
|
|
129
140
|
|
|
130
|
-
const response = await provider.chat(prompt, [], {
|
|
141
|
+
const response = await provider.chat(prompt, [], {
|
|
142
|
+
model,
|
|
143
|
+
maxTokens: 900,
|
|
144
|
+
signal: options.signal,
|
|
145
|
+
});
|
|
146
|
+
throwIfAborted(options.signal, 'Conversation summary refresh aborted.');
|
|
131
147
|
return clampSummary(response.content || existingSummary || '');
|
|
132
148
|
}
|
|
133
149
|
|
|
@@ -183,7 +199,15 @@ async function refreshWebChatSummary(userId, provider, model, recentLimit, force
|
|
|
183
199
|
'SELECT role, content FROM conversation_history WHERE user_id = ? AND agent_id = ? ORDER BY created_at ASC LIMIT ? OFFSET ?'
|
|
184
200
|
).all(userId, agentId, newMessages, count);
|
|
185
201
|
|
|
186
|
-
const nextSummary = clampSummary(await summarizeMessages(
|
|
202
|
+
const nextSummary = clampSummary(await summarizeMessages(
|
|
203
|
+
provider,
|
|
204
|
+
model,
|
|
205
|
+
summary,
|
|
206
|
+
normalizeHistoryRows(rows),
|
|
207
|
+
'web chat',
|
|
208
|
+
options,
|
|
209
|
+
));
|
|
210
|
+
throwIfAborted(options.signal, 'Web chat summary refresh aborted.');
|
|
187
211
|
const upsert = db.prepare(
|
|
188
212
|
'INSERT INTO agent_settings (user_id, agent_id, key, value) VALUES (?, ?, ?, ?) ON CONFLICT(user_id, agent_id, key) DO UPDATE SET value = excluded.value'
|
|
189
213
|
);
|
|
@@ -214,7 +238,14 @@ function getConversationContext(conversationId, recentLimit) {
|
|
|
214
238
|
};
|
|
215
239
|
}
|
|
216
240
|
|
|
217
|
-
async function refreshConversationSummary(
|
|
241
|
+
async function refreshConversationSummary(
|
|
242
|
+
conversationId,
|
|
243
|
+
provider,
|
|
244
|
+
model,
|
|
245
|
+
recentLimit,
|
|
246
|
+
force = false,
|
|
247
|
+
options = {},
|
|
248
|
+
) {
|
|
218
249
|
const convo = db.prepare(
|
|
219
250
|
'SELECT summary, summary_message_count FROM conversations WHERE id = ?'
|
|
220
251
|
).get(conversationId);
|
|
@@ -233,7 +264,15 @@ async function refreshConversationSummary(conversationId, provider, model, recen
|
|
|
233
264
|
'SELECT role, content, tool_calls, tool_call_id, name FROM conversation_messages WHERE conversation_id = ? ORDER BY created_at ASC LIMIT ? OFFSET ?'
|
|
234
265
|
).all(conversationId, newMessages, currentCount);
|
|
235
266
|
|
|
236
|
-
const nextSummary = clampSummary(await summarizeMessages(
|
|
267
|
+
const nextSummary = clampSummary(await summarizeMessages(
|
|
268
|
+
provider,
|
|
269
|
+
model,
|
|
270
|
+
convo.summary || '',
|
|
271
|
+
normalizeHistoryRows(rows),
|
|
272
|
+
'thread',
|
|
273
|
+
options,
|
|
274
|
+
));
|
|
275
|
+
throwIfAborted(options.signal, 'Conversation summary refresh aborted.');
|
|
237
276
|
db.prepare(
|
|
238
277
|
"UPDATE conversations SET summary = ?, summary_message_count = ?, last_summary = datetime('now') WHERE id = ?"
|
|
239
278
|
).run(nextSummary, targetCount, conversationId);
|