@supen-ai/cli 1.4.0 → 1.4.2
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/README.md +1 -1
- package/daemon/dist/agent-sdk/app-server-stream.js +5 -5
- package/daemon/dist/agent-sdk/app-server-stream.js.map +1 -1
- package/daemon/dist/agent-sdk/drivers/codex-app-server-driver.d.ts +3 -2
- package/daemon/dist/agent-sdk/drivers/codex-app-server-driver.d.ts.map +1 -1
- package/daemon/dist/agent-sdk/drivers/codex-app-server-driver.js +72 -49
- package/daemon/dist/agent-sdk/drivers/codex-app-server-driver.js.map +1 -1
- package/daemon/dist/agent-sdk/drivers/driver.d.ts +8 -8
- package/daemon/dist/agent-sdk/drivers/driver.d.ts.map +1 -1
- package/daemon/dist/agent-sdk/index.d.ts +4 -4
- package/daemon/dist/agent-sdk/index.d.ts.map +1 -1
- package/daemon/dist/agent-sdk/index.js +2 -2
- package/daemon/dist/agent-sdk/index.js.map +1 -1
- package/daemon/dist/agent-sdk/intelligence/contracts.d.ts +2 -2
- package/daemon/dist/agent-sdk/intelligence/contracts.d.ts.map +1 -1
- package/daemon/dist/agent-sdk/memory/subsystem.d.ts +1 -1
- package/daemon/dist/agent-sdk/memory/subsystem.d.ts.map +1 -1
- package/daemon/dist/agent-sdk/{session-events.d.ts → thread-events.d.ts} +18 -18
- package/daemon/dist/agent-sdk/thread-events.d.ts.map +1 -0
- package/daemon/dist/agent-sdk/{session-events.js → thread-events.js} +15 -15
- package/daemon/dist/agent-sdk/thread-events.js.map +1 -0
- package/daemon/dist/agent-sdk/{session-manager.d.ts → thread-manager.d.ts} +9 -9
- package/daemon/dist/agent-sdk/thread-manager.d.ts.map +1 -0
- package/daemon/dist/agent-sdk/{session-manager.js → thread-manager.js} +7 -7
- package/daemon/dist/agent-sdk/thread-manager.js.map +1 -0
- package/daemon/dist/agent-sdk/types.d.ts +18 -18
- package/daemon/dist/agent-sdk/types.d.ts.map +1 -1
- package/daemon/dist/automation-event-listener.js +6 -6
- package/daemon/dist/automation-event-listener.js.map +1 -1
- package/daemon/dist/automation-runner.d.ts +1 -1
- package/daemon/dist/automation-runner.d.ts.map +1 -1
- package/daemon/dist/automation-runner.js +24 -24
- package/daemon/dist/automation-runner.js.map +1 -1
- package/daemon/dist/autonomy/memory-rules.d.ts +2 -2
- package/daemon/dist/autonomy/memory-rules.d.ts.map +1 -1
- package/daemon/dist/autonomy/memory-rules.js +1 -1
- package/daemon/dist/autonomy/memory-rules.js.map +1 -1
- package/daemon/dist/autonomy/session-autonomy.d.ts +4 -4
- package/daemon/dist/autonomy/session-autonomy.d.ts.map +1 -1
- package/daemon/dist/autonomy/session-autonomy.js +5 -5
- package/daemon/dist/autonomy/session-autonomy.js.map +1 -1
- package/daemon/dist/bin/mcp-os.js +1 -1
- package/daemon/dist/bin/mcp-os.js.map +1 -1
- package/daemon/dist/bin/mcp-scheduler.js +1 -1
- package/daemon/dist/bin/mcp-scheduler.js.map +1 -1
- package/daemon/dist/bin/supen-sys.js +1 -1
- package/daemon/dist/bin/supen-sys.js.map +1 -1
- package/daemon/dist/bootstrap/hub-bootstrap.js +1 -1
- package/daemon/dist/bootstrap/hub-bootstrap.js.map +1 -1
- package/daemon/dist/channels/http-routes.d.ts.map +1 -1
- package/daemon/dist/channels/http-routes.js +54 -60
- package/daemon/dist/channels/http-routes.js.map +1 -1
- package/daemon/dist/channels/http.js +2 -2
- package/daemon/dist/channels/http.js.map +1 -1
- package/daemon/dist/channels/index.d.ts +0 -1
- package/daemon/dist/channels/index.d.ts.map +1 -1
- package/daemon/dist/channels/index.js +0 -2
- package/daemon/dist/channels/index.js.map +1 -1
- package/daemon/dist/channels/registry.d.ts +1 -1
- package/daemon/dist/channels/registry.d.ts.map +1 -1
- package/daemon/dist/commands/builtin.d.ts +1 -1
- package/daemon/dist/commands/builtin.d.ts.map +1 -1
- package/daemon/dist/commands/builtin.js +2 -2
- package/daemon/dist/commands/builtin.js.map +1 -1
- package/daemon/dist/commands/catalog.js +3 -3
- package/daemon/dist/commands/catalog.js.map +1 -1
- package/daemon/dist/core/config.d.ts +0 -2
- package/daemon/dist/core/config.d.ts.map +1 -1
- package/daemon/dist/core/config.js +0 -5
- package/daemon/dist/core/config.js.map +1 -1
- package/daemon/dist/core/control-commands.d.ts +3 -3
- package/daemon/dist/core/control-commands.d.ts.map +1 -1
- package/daemon/dist/core/control-commands.js +6 -6
- package/daemon/dist/core/control-commands.js.map +1 -1
- package/daemon/dist/core/control-log.d.ts +4 -4
- package/daemon/dist/core/control-log.d.ts.map +1 -1
- package/daemon/dist/core/control-log.js +12 -12
- package/daemon/dist/core/control-log.js.map +1 -1
- package/daemon/dist/core/cortex.d.ts +4 -4
- package/daemon/dist/core/cortex.d.ts.map +1 -1
- package/daemon/dist/core/cortex.js +98 -117
- package/daemon/dist/core/cortex.js.map +1 -1
- package/daemon/dist/core/dispatcher.d.ts +3 -3
- package/daemon/dist/core/dispatcher.js +18 -18
- package/daemon/dist/core/dispatcher.js.map +1 -1
- package/daemon/dist/core/gateway-protocol.d.ts +0 -1
- package/daemon/dist/core/gateway-protocol.d.ts.map +1 -1
- package/daemon/dist/core/gateway.d.ts +3 -3
- package/daemon/dist/core/gateway.d.ts.map +1 -1
- package/daemon/dist/core/gateway.js +26 -26
- package/daemon/dist/core/gateway.js.map +1 -1
- package/daemon/dist/core/hub-snapshot.d.ts +1 -1
- package/daemon/dist/core/hub-snapshot.d.ts.map +1 -1
- package/daemon/dist/core/hub-snapshot.js +1 -1
- package/daemon/dist/core/hub-snapshot.js.map +1 -1
- package/daemon/dist/core/pairing.d.ts +2 -2
- package/daemon/dist/core/pairing.js +3 -3
- package/daemon/dist/core/pairing.js.map +1 -1
- package/daemon/dist/core/store.d.ts +38 -38
- package/daemon/dist/core/store.d.ts.map +1 -1
- package/daemon/dist/core/store.js +285 -289
- package/daemon/dist/core/store.js.map +1 -1
- package/daemon/dist/core/task-artifacts.d.ts +4 -4
- package/daemon/dist/core/task-artifacts.d.ts.map +1 -1
- package/daemon/dist/core/task-artifacts.js +10 -10
- package/daemon/dist/core/task-artifacts.js.map +1 -1
- package/daemon/dist/core/thread-context.d.ts +76 -0
- package/daemon/dist/core/thread-context.d.ts.map +1 -0
- package/daemon/dist/core/thread-context.js +308 -0
- package/daemon/dist/core/thread-context.js.map +1 -0
- package/daemon/dist/core/types.d.ts +28 -28
- package/daemon/dist/core/types.d.ts.map +1 -1
- package/daemon/dist/core/utils.js +1 -1
- package/daemon/dist/core/utils.js.map +1 -1
- package/daemon/dist/http/router.d.ts +2 -2
- package/daemon/dist/http/router.d.ts.map +1 -1
- package/daemon/dist/http/router.js +5 -5
- package/daemon/dist/http/router.js.map +1 -1
- package/daemon/dist/http/routes/agents.js +3 -3
- package/daemon/dist/http/routes/agents.js.map +1 -1
- package/daemon/dist/http/routes/automations.d.ts +2 -2
- package/daemon/dist/http/routes/automations.d.ts.map +1 -1
- package/daemon/dist/http/routes/automations.js +23 -23
- package/daemon/dist/http/routes/automations.js.map +1 -1
- package/daemon/dist/http/routes/chat-input.d.ts +1 -1
- package/daemon/dist/http/routes/chat-input.d.ts.map +1 -1
- package/daemon/dist/http/routes/chat-input.js +2 -2
- package/daemon/dist/http/routes/chat-input.js.map +1 -1
- package/daemon/dist/http/routes/plugins.d.ts.map +1 -1
- package/daemon/dist/http/routes/plugins.js +6 -74
- package/daemon/dist/http/routes/plugins.js.map +1 -1
- package/daemon/dist/http/routes/rpc.d.ts +3 -3
- package/daemon/dist/http/routes/rpc.d.ts.map +1 -1
- package/daemon/dist/http/routes/rpc.js +93 -92
- package/daemon/dist/http/routes/rpc.js.map +1 -1
- package/daemon/dist/http/routes/system.d.ts +8 -7
- package/daemon/dist/http/routes/system.d.ts.map +1 -1
- package/daemon/dist/http/routes/system.js +225 -111
- package/daemon/dist/http/routes/system.js.map +1 -1
- package/daemon/dist/http/routes/threads.d.ts +11 -0
- package/daemon/dist/http/routes/threads.d.ts.map +1 -0
- package/daemon/dist/http/routes/{sessions.js → threads.js} +158 -158
- package/daemon/dist/http/routes/threads.js.map +1 -0
- package/daemon/dist/http/stream.d.ts +2 -2
- package/daemon/dist/http/stream.d.ts.map +1 -1
- package/daemon/dist/http/stream.js +3 -3
- package/daemon/dist/http/stream.js.map +1 -1
- package/daemon/dist/http/thread-title.d.ts +1 -1
- package/daemon/dist/http/thread-title.d.ts.map +1 -1
- package/daemon/dist/http/thread-title.js +6 -6
- package/daemon/dist/http/thread-title.js.map +1 -1
- package/daemon/dist/http/websocket.d.ts +2 -2
- package/daemon/dist/http/websocket.d.ts.map +1 -1
- package/daemon/dist/http/websocket.js +11 -11
- package/daemon/dist/http/websocket.js.map +1 -1
- package/daemon/dist/index.d.ts +3 -3
- package/daemon/dist/index.d.ts.map +1 -1
- package/daemon/dist/index.js +65 -81
- package/daemon/dist/index.js.map +1 -1
- package/daemon/dist/mcp/aggregate-config.d.ts +1 -1
- package/daemon/dist/mcp/index.js +1 -1
- package/daemon/dist/mcp/index.js.map +1 -1
- package/daemon/dist/mcp/tools.d.ts +1 -1
- package/daemon/dist/mcp/tools.js +1 -1
- package/daemon/dist/plugins/hub.d.ts +2 -8
- package/daemon/dist/plugins/hub.d.ts.map +1 -1
- package/daemon/dist/plugins/hub.js +63 -214
- package/daemon/dist/plugins/hub.js.map +1 -1
- package/daemon/dist/plugins/types.d.ts +10 -0
- package/daemon/dist/plugins/types.d.ts.map +1 -1
- package/daemon/dist/sub-agent.d.ts +3 -3
- package/daemon/dist/sub-agent.d.ts.map +1 -1
- package/daemon/dist/sub-agent.js +8 -8
- package/daemon/dist/sub-agent.js.map +1 -1
- package/daemon/dist/sync/supabase-sync.js +18 -18
- package/daemon/dist/sync/supabase-sync.js.map +1 -1
- package/daemon/dist/task-executor.js +1 -1
- package/daemon/dist/task-executor.js.map +1 -1
- package/daemon/dist/tools/shell.js +1 -1
- package/daemon/dist/tools/shell.js.map +1 -1
- package/daemon/dist/tools/types.d.ts +1 -1
- package/daemon/dist/tools/types.d.ts.map +1 -1
- package/daemon/package.json +1 -1
- package/dist/computer.js +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/daemon/dist/acp-client.d.ts +0 -42
- package/daemon/dist/acp-client.d.ts.map +0 -1
- package/daemon/dist/acp-client.js +0 -149
- package/daemon/dist/acp-client.js.map +0 -1
- package/daemon/dist/acp-types.d.ts +0 -98
- package/daemon/dist/acp-types.d.ts.map +0 -1
- package/daemon/dist/acp-types.js +0 -2
- package/daemon/dist/acp-types.js.map +0 -1
- package/daemon/dist/agent-sdk/session-events.d.ts.map +0 -1
- package/daemon/dist/agent-sdk/session-events.js.map +0 -1
- package/daemon/dist/agent-sdk/session-manager.d.ts.map +0 -1
- package/daemon/dist/agent-sdk/session-manager.js.map +0 -1
- package/daemon/dist/channels/acp.d.ts +0 -23
- package/daemon/dist/channels/acp.d.ts.map +0 -1
- package/daemon/dist/channels/acp.js +0 -915
- package/daemon/dist/channels/acp.js.map +0 -1
- package/daemon/dist/http/routes/sessions.d.ts +0 -11
- package/daemon/dist/http/routes/sessions.d.ts.map +0 -1
- package/daemon/dist/http/routes/sessions.js.map +0 -1
package/daemon/dist/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import { CODEX_TRUSTED_DATA_HOSTS, ASSISTANT_NAME, SUPEN_HOME, POLL_INTERVAL, TR
|
|
|
4
4
|
import './channels/index.js';
|
|
5
5
|
import { SkillHub } from './skills/hub.js';
|
|
6
6
|
import { getChannelFactory, getRegisteredChannelNames, } from './channels/registry.js';
|
|
7
|
-
import {
|
|
7
|
+
import { ensureThread, getAllChats, getAllRegisteredProjects, getAllThreads, getMessagesSince, getNewMessages, getRouterState, getThreadForAgent, initStore, cleanupStaleThreads, cleanupStaleAutomationExecutions, touchAutomationRun, updateThreadStatus, setRegisteredProject, setRouterState, storeChatMetadata, storeMessage, storeThreadUiEvent, resolveFromChatJid, } from './core/store.js';
|
|
8
8
|
import { logger } from './core/logger.js';
|
|
9
9
|
import { readEnrollmentState, verifyEnrollmentToken, } from './core/enrollment.js';
|
|
10
10
|
import { routeOutbound, routeOutboundFile, routeSetTyping, routeEditMessage, } from './router.js';
|
|
@@ -23,6 +23,7 @@ import { listCommands, resolveCommandInput } from './commands/catalog.js';
|
|
|
23
23
|
import { findLatestInterruptIndex, trimMessagesAfterInterrupt, } from './core/interrupts.js';
|
|
24
24
|
import { isSupabaseConfigured, pullFromSupabase, scheduleSupabasePush, startPeriodicSupabasePush, } from './sync/supabase-sync.js';
|
|
25
25
|
import { appendStreamChunk, createStreamState, } from './core/streaming.js';
|
|
26
|
+
import { attachThreadContextToChunk, readThreadContext, } from './core/thread-context.js';
|
|
26
27
|
const DEFAULT_AUTOMATION_TASK_TIMEOUT_MS = 12 * 60 * 1000;
|
|
27
28
|
function automationTaskTimeoutMs() {
|
|
28
29
|
const raw = process.env.SUPEN_AUTOMATION_TASK_TIMEOUT_MS;
|
|
@@ -33,40 +34,23 @@ function automationTaskTimeoutMs() {
|
|
|
33
34
|
return DEFAULT_AUTOMATION_TASK_TIMEOUT_MS;
|
|
34
35
|
return parsed;
|
|
35
36
|
}
|
|
36
|
-
import { appendThreadEvent } from './core/thread-event-log.js';
|
|
37
37
|
import { parseProgressEvent, formatProgressText, progressKeyFromEvent } from './core/progress.js';
|
|
38
38
|
import { buildAssistantOutputExcerpt, buildObservableToolDetail, buildProgressDetail, buildTaskContextExcerpt, canonicalAutomationLogFields, classifyObservableLogEvent, excerptText, } from './core/observable-logging.js';
|
|
39
39
|
// Global state
|
|
40
40
|
let registeredProjects = {};
|
|
41
|
-
const
|
|
41
|
+
const threads = {}; // folder -> threadId
|
|
42
42
|
const lastAgentTimestamp = {}; // chatJid -> iso
|
|
43
43
|
const channels = [];
|
|
44
44
|
const activeDaemons = new Map();
|
|
45
45
|
export function captureCodexStreamPayload(input) {
|
|
46
|
-
let
|
|
46
|
+
let payload = input.payload;
|
|
47
47
|
try {
|
|
48
|
-
|
|
49
|
-
threadId: input.threadId,
|
|
50
|
-
runtimeThreadId: input.runtimeThreadId || input.threadId,
|
|
51
|
-
source: 'codex-app-server',
|
|
52
|
-
eventType: typeof input.payload.type === 'string'
|
|
53
|
-
? input.payload.type
|
|
54
|
-
: typeof input.payload.method === 'string'
|
|
55
|
-
? input.payload.method
|
|
56
|
-
: 'codex-event',
|
|
57
|
-
rawPayload: input.payload,
|
|
58
|
-
});
|
|
59
|
-
sequence = event.sequence;
|
|
48
|
+
payload = attachThreadContextToChunk(input.payload, readThreadContext({ threadId: input.threadId }));
|
|
60
49
|
}
|
|
61
50
|
catch (error) {
|
|
62
|
-
logger.
|
|
63
|
-
err: error,
|
|
64
|
-
agentId: input.agentId,
|
|
65
|
-
threadId: input.threadId,
|
|
66
|
-
runtimeThreadId: input.runtimeThreadId || input.threadId,
|
|
67
|
-
}, 'Failed to capture Codex stream payload');
|
|
51
|
+
logger.debug({ err: error, agentId: input.agentId, threadId: input.threadId }, 'Skipped Codex stream context attachment');
|
|
68
52
|
}
|
|
69
|
-
broadcastToThread(input.threadId,
|
|
53
|
+
broadcastToThread(input.threadId, payload);
|
|
70
54
|
}
|
|
71
55
|
function appServerChunk(method, params = {}) {
|
|
72
56
|
return {
|
|
@@ -124,24 +108,24 @@ const activeAgentLocks = new Map();
|
|
|
124
108
|
// Pending-run flags: if a second message arrives while the lock is held,
|
|
125
109
|
// set the flag so the run drains immediately after the current one finishes.
|
|
126
110
|
const pendingRuns = new Set();
|
|
127
|
-
function
|
|
128
|
-
const
|
|
129
|
-
const chatJid =
|
|
111
|
+
function requestThreadStop(agentId, threadId, actor = 'unknown') {
|
|
112
|
+
const thread = getThreadForAgent(agentId, threadId);
|
|
113
|
+
const chatJid = thread?.source_ref?.trim() || `web:${agentId}:${threadId}`;
|
|
130
114
|
const daemon = activeDaemons.get(chatJid);
|
|
131
115
|
if (!daemon) {
|
|
132
116
|
return {
|
|
133
117
|
ok: false,
|
|
134
|
-
code: '
|
|
135
|
-
message: `Task "${
|
|
118
|
+
code: 'thread_not_running',
|
|
119
|
+
message: `Task "${threadId}" is not currently running.`,
|
|
136
120
|
chatJid,
|
|
137
121
|
};
|
|
138
122
|
}
|
|
139
|
-
logger.info({ agentId,
|
|
123
|
+
logger.info({ agentId, threadId, chatJid, actor }, 'Stop requested for active thread');
|
|
140
124
|
daemon.interrupt();
|
|
141
125
|
return {
|
|
142
126
|
ok: true,
|
|
143
127
|
code: 'stop_requested',
|
|
144
|
-
message: `Stop requested for
|
|
128
|
+
message: `Stop requested for thread "${threadId}".`,
|
|
145
129
|
chatJid,
|
|
146
130
|
};
|
|
147
131
|
}
|
|
@@ -195,7 +179,7 @@ async function runAndDrain(chatJid) {
|
|
|
195
179
|
}
|
|
196
180
|
}
|
|
197
181
|
}
|
|
198
|
-
export function
|
|
182
|
+
export function resolveThreadChannel(chatJid, existingChannel) {
|
|
199
183
|
if (chatJid.startsWith('dc:'))
|
|
200
184
|
return 'discord';
|
|
201
185
|
if (chatJid.startsWith('web:'))
|
|
@@ -211,14 +195,14 @@ export function resolveSessionChannel(chatJid, existingChannel) {
|
|
|
211
195
|
}
|
|
212
196
|
return existingChannel || chatJid.split(':')[0] || 'unknown';
|
|
213
197
|
}
|
|
214
|
-
export function
|
|
198
|
+
export function resolveStoredThreadChannel(chatJid) {
|
|
215
199
|
const resolved = resolveFromChatJid(chatJid);
|
|
216
200
|
if (!resolved)
|
|
217
201
|
return undefined;
|
|
218
|
-
return
|
|
202
|
+
return getThreadForAgent(resolved.agentId, resolved.threadId)?.channel;
|
|
219
203
|
}
|
|
220
204
|
export function resolveRoutingChannel(chatJid) {
|
|
221
|
-
return
|
|
205
|
+
return resolveThreadChannel(chatJid, resolveStoredThreadChannel(chatJid));
|
|
222
206
|
}
|
|
223
207
|
async function processMessages(chatJid) {
|
|
224
208
|
let group = registeredProjects[chatJid];
|
|
@@ -233,32 +217,32 @@ async function processMessages(chatJid) {
|
|
|
233
217
|
isMain: false,
|
|
234
218
|
};
|
|
235
219
|
}
|
|
236
|
-
// Resolve or create a
|
|
237
|
-
// IMPORTANT: always resolve agentId +
|
|
238
|
-
// chatJid itself as
|
|
220
|
+
// Resolve or create a thread for this chat so directories exist.
|
|
221
|
+
// IMPORTANT: always resolve agentId + threadId from the JID — never use
|
|
222
|
+
// chatJid itself as thread_id, or the full JID gets stored and re-prefixed
|
|
239
223
|
// on every subsequent call, making the key grow indefinitely.
|
|
240
224
|
let agentId = group.agent_id || group.folder;
|
|
241
|
-
let
|
|
225
|
+
let threadId;
|
|
242
226
|
const resolved = resolveFromChatJid(chatJid);
|
|
243
227
|
if (resolved) {
|
|
244
228
|
agentId = resolved.agentId;
|
|
245
|
-
|
|
229
|
+
threadId = resolved.threadId;
|
|
246
230
|
}
|
|
247
231
|
else {
|
|
248
232
|
// Fallback for unrecognised JID formats: split on ':' and use last segment
|
|
249
233
|
const parts = chatJid.split(':');
|
|
250
|
-
|
|
234
|
+
threadId = parts.length >= 2 ? parts.slice(1).join(':') : chatJid;
|
|
251
235
|
if (agentId === 'unknown' && parts.length >= 2) {
|
|
252
236
|
agentId = parts[1];
|
|
253
237
|
}
|
|
254
238
|
}
|
|
255
|
-
const
|
|
256
|
-
const channel =
|
|
257
|
-
?
|
|
239
|
+
const existingThread = getThreadForAgent(agentId, threadId);
|
|
240
|
+
const channel = existingThread
|
|
241
|
+
? resolveThreadChannel(chatJid, existingThread.channel)
|
|
258
242
|
: resolveRoutingChannel(chatJid);
|
|
259
|
-
const
|
|
243
|
+
const thread = ensureThread({
|
|
260
244
|
agent_id: agentId,
|
|
261
|
-
|
|
245
|
+
thread_id: threadId,
|
|
262
246
|
channel,
|
|
263
247
|
agent_name: group.name,
|
|
264
248
|
source_ref: chatJid,
|
|
@@ -354,7 +338,7 @@ async function processMessages(chatJid) {
|
|
|
354
338
|
const portableBuiltinReply = await executePortableBuiltinCommand(resolvedSlashCommand.text, {
|
|
355
339
|
channel: routingChannel,
|
|
356
340
|
agentId,
|
|
357
|
-
|
|
341
|
+
threadId,
|
|
358
342
|
actor: latestMsg?.sender || chatJid,
|
|
359
343
|
isAdmin: isAdminActor(latestMsg?.sender || chatJid),
|
|
360
344
|
});
|
|
@@ -375,7 +359,7 @@ async function processMessages(chatJid) {
|
|
|
375
359
|
}
|
|
376
360
|
// Check if we have a valid workspace for this group
|
|
377
361
|
// (group is guaranteed to be set now because of our fallback logic at the top)
|
|
378
|
-
const workspace =
|
|
362
|
+
const workspace = thread.task_workspace_folder || getFactoryPath(group);
|
|
379
363
|
const hasWorkspace = fs.existsSync(workspace);
|
|
380
364
|
logger.info({ chatJid, workspace, hasWorkspace }, 'processMessages: workspace check');
|
|
381
365
|
const automationMessage = [...runnableMessages]
|
|
@@ -571,16 +555,16 @@ async function processMessages(chatJid) {
|
|
|
571
555
|
latestMsg?.id ||
|
|
572
556
|
taskId;
|
|
573
557
|
const streamState = createStreamState(`${chatJid}:${turnId}`);
|
|
574
|
-
const
|
|
575
|
-
const mirroredThreadId =
|
|
576
|
-
const shouldMirrorTaskThread = Boolean(mirroredThreadId) && (chatJid.startsWith('task:') ||
|
|
558
|
+
const isAdoptedCodexAppServerThread = chatJid.startsWith('web:') && thread.backend_driver_id === 'codex-app-server';
|
|
559
|
+
const mirroredThreadId = isAdoptedCodexAppServerThread ? thread.thread_id : taskId;
|
|
560
|
+
const shouldMirrorTaskThread = Boolean(mirroredThreadId) && (chatJid.startsWith('task:') || isAdoptedCodexAppServerThread);
|
|
577
561
|
const mirrorTaskThreadChunk = (payload) => {
|
|
578
562
|
if (!shouldMirrorTaskThread)
|
|
579
563
|
return;
|
|
580
564
|
captureCodexStreamPayload({
|
|
581
565
|
agentId,
|
|
582
566
|
threadId: mirroredThreadId,
|
|
583
|
-
runtimeThreadId:
|
|
567
|
+
runtimeThreadId: thread.thread_id,
|
|
584
568
|
payload,
|
|
585
569
|
});
|
|
586
570
|
};
|
|
@@ -683,7 +667,7 @@ async function processMessages(chatJid) {
|
|
|
683
667
|
try {
|
|
684
668
|
await completeAutomationRun({
|
|
685
669
|
sendMessage: (jid, notification) => sendFn(jid, notification),
|
|
686
|
-
|
|
670
|
+
ensureNotificationThreadExists,
|
|
687
671
|
}, automationMessage, chatJid, outcome, detail);
|
|
688
672
|
}
|
|
689
673
|
catch (completeError) {
|
|
@@ -697,7 +681,7 @@ async function processMessages(chatJid) {
|
|
|
697
681
|
if (useGatewayChannelReplyLifecycle) {
|
|
698
682
|
await ensureChannelReplyHandle('Thinking...');
|
|
699
683
|
}
|
|
700
|
-
// Get MCP manager for this
|
|
684
|
+
// Get MCP manager for this thread
|
|
701
685
|
let mcpManager;
|
|
702
686
|
try {
|
|
703
687
|
mcpManager = await getMcpManager();
|
|
@@ -705,7 +689,7 @@ async function processMessages(chatJid) {
|
|
|
705
689
|
catch (err) {
|
|
706
690
|
logger.warn({ err }, 'Failed to get MCP manager, continuing without MCP');
|
|
707
691
|
}
|
|
708
|
-
const daemon = new AgentCortex(agentId, { ...
|
|
692
|
+
const daemon = new AgentCortex(agentId, { ...thread, task_id: taskId }.thread_id, {
|
|
709
693
|
mcpManager,
|
|
710
694
|
onStateChange: async (state) => {
|
|
711
695
|
const eventData = {
|
|
@@ -726,7 +710,7 @@ async function processMessages(chatJid) {
|
|
|
726
710
|
? 'idle'
|
|
727
711
|
: 'active';
|
|
728
712
|
mirrorTaskThreadChunk(appServerChunk('thread/status/changed', {
|
|
729
|
-
threadId:
|
|
713
|
+
threadId: thread.thread_id,
|
|
730
714
|
status: { type: statusType },
|
|
731
715
|
}));
|
|
732
716
|
}
|
|
@@ -826,11 +810,11 @@ async function processMessages(chatJid) {
|
|
|
826
810
|
id: streamState.streamId,
|
|
827
811
|
});
|
|
828
812
|
mirrorTaskThreadChunk(appServerChunk('turn/completed', {
|
|
829
|
-
threadId:
|
|
813
|
+
threadId: thread.thread_id,
|
|
830
814
|
turnId,
|
|
831
815
|
turn: { id: turnId, status: 'completed' },
|
|
832
816
|
}));
|
|
833
|
-
|
|
817
|
+
updateThreadStatus(agentId, threadId, 'idle');
|
|
834
818
|
}
|
|
835
819
|
// Finalize streaming: emit stream_end so consumers
|
|
836
820
|
// know the streaming phase is complete.
|
|
@@ -972,12 +956,12 @@ async function processMessages(chatJid) {
|
|
|
972
956
|
id: streamState.streamId,
|
|
973
957
|
});
|
|
974
958
|
mirrorTaskThreadChunk(appServerChunk('turn/failed', {
|
|
975
|
-
threadId:
|
|
959
|
+
threadId: thread.thread_id,
|
|
976
960
|
turnId,
|
|
977
961
|
turn: { id: turnId, status: 'failed' },
|
|
978
962
|
error: { message: error?.message || text },
|
|
979
963
|
}));
|
|
980
|
-
|
|
964
|
+
updateThreadStatus(agentId, threadId, 'error');
|
|
981
965
|
}
|
|
982
966
|
if (!isAutomationMessage && chatJid.startsWith('web:') && streamState.nextSeq > 1) {
|
|
983
967
|
broadcastToChat(chatJid, {
|
|
@@ -1026,13 +1010,13 @@ async function processMessages(chatJid) {
|
|
|
1026
1010
|
activeDaemons.set(chatJid, daemon);
|
|
1027
1011
|
try {
|
|
1028
1012
|
if (shouldMirrorTaskThread) {
|
|
1029
|
-
|
|
1013
|
+
updateThreadStatus(agentId, threadId, 'running');
|
|
1030
1014
|
mirrorTaskThreadChunk({
|
|
1031
1015
|
type: 'start',
|
|
1032
1016
|
messageId: streamState.streamId,
|
|
1033
1017
|
});
|
|
1034
1018
|
mirrorTaskThreadChunk(appServerChunk('turn/started', {
|
|
1035
|
-
threadId:
|
|
1019
|
+
threadId: thread.thread_id,
|
|
1036
1020
|
turnId,
|
|
1037
1021
|
turn: { id: turnId, status: 'running' },
|
|
1038
1022
|
}));
|
|
@@ -1112,8 +1096,8 @@ async function processMessages(chatJid) {
|
|
|
1112
1096
|
const parsedPayload = JSON.parse(payload);
|
|
1113
1097
|
captureCodexStreamPayload({
|
|
1114
1098
|
agentId,
|
|
1115
|
-
threadId:
|
|
1116
|
-
runtimeThreadId:
|
|
1099
|
+
threadId: threadId,
|
|
1100
|
+
runtimeThreadId: thread.thread_id,
|
|
1117
1101
|
payload: parsedPayload,
|
|
1118
1102
|
});
|
|
1119
1103
|
broadcastToChat(chatJid, parsedPayload);
|
|
@@ -1131,8 +1115,8 @@ async function processMessages(chatJid) {
|
|
|
1131
1115
|
const parsedPayload = JSON.parse(payload);
|
|
1132
1116
|
captureCodexStreamPayload({
|
|
1133
1117
|
agentId,
|
|
1134
|
-
threadId:
|
|
1135
|
-
runtimeThreadId:
|
|
1118
|
+
threadId: threadId,
|
|
1119
|
+
runtimeThreadId: thread.thread_id,
|
|
1136
1120
|
payload: parsedPayload,
|
|
1137
1121
|
});
|
|
1138
1122
|
broadcastToChat(chatJid, parsedPayload);
|
|
@@ -1145,7 +1129,7 @@ async function processMessages(chatJid) {
|
|
|
1145
1129
|
// Mark stream dispatch completion after all chunks are broadcast to
|
|
1146
1130
|
// active web clients. `/chat` waits on this marker before closing
|
|
1147
1131
|
// the SSE response to avoid cutting off trailing streamed chunks.
|
|
1148
|
-
|
|
1132
|
+
storeThreadUiEvent(agentId, threadId, {
|
|
1149
1133
|
id: `${taskId}:stream-dispatched:${Date.now()}`,
|
|
1150
1134
|
timestamp: new Date().toISOString(),
|
|
1151
1135
|
task_id: taskId,
|
|
@@ -1300,11 +1284,11 @@ function loadState() {
|
|
|
1300
1284
|
registeredProjects[jid] = group;
|
|
1301
1285
|
}
|
|
1302
1286
|
logger.info({ count: Object.keys(registeredProjects).length }, 'Groups loaded');
|
|
1303
|
-
const
|
|
1304
|
-
for (const sess of
|
|
1305
|
-
|
|
1287
|
+
const dbThreads = getAllThreads();
|
|
1288
|
+
for (const sess of dbThreads) {
|
|
1289
|
+
threads[sess.agent_id] = sess.thread_id;
|
|
1306
1290
|
}
|
|
1307
|
-
logger.info({ count: Object.keys(
|
|
1291
|
+
logger.info({ count: Object.keys(threads).length }, 'Threads loaded');
|
|
1308
1292
|
for (const jid of Object.keys(registeredProjects)) {
|
|
1309
1293
|
const timestamp = getRouterState(jid);
|
|
1310
1294
|
if (timestamp) {
|
|
@@ -1327,13 +1311,13 @@ function recoverPendingMessages() {
|
|
|
1327
1311
|
}
|
|
1328
1312
|
let sendFn;
|
|
1329
1313
|
let createChannelFn;
|
|
1330
|
-
function
|
|
1314
|
+
function ensureNotificationThreadExists(targetJid, fallbackAgentId) {
|
|
1331
1315
|
const resolved = resolveFromChatJid(targetJid);
|
|
1332
1316
|
if (!resolved)
|
|
1333
1317
|
return;
|
|
1334
|
-
|
|
1318
|
+
ensureThread({
|
|
1335
1319
|
agent_id: resolved.agentId || fallbackAgentId || 'unknown',
|
|
1336
|
-
|
|
1320
|
+
thread_id: resolved.threadId,
|
|
1337
1321
|
channel: targetJid.startsWith('web:') ? 'http' : targetJid.split(':')[0] || 'unknown',
|
|
1338
1322
|
source_ref: targetJid,
|
|
1339
1323
|
});
|
|
@@ -1348,18 +1332,18 @@ async function main() {
|
|
|
1348
1332
|
const productName = process.env.SUPEN_PRODUCT_NAME || 'Supen';
|
|
1349
1333
|
logger.info(`${productName} Daemon starting`);
|
|
1350
1334
|
initStore();
|
|
1351
|
-
|
|
1335
|
+
cleanupStaleThreads();
|
|
1352
1336
|
cleanupStaleAutomationExecutions();
|
|
1353
1337
|
logger.info('Database initialized');
|
|
1354
|
-
// Ensure default agent and
|
|
1355
|
-
|
|
1338
|
+
// Ensure default agent and thread exist
|
|
1339
|
+
ensureThread({
|
|
1356
1340
|
agent_id: 'supen-agent',
|
|
1357
|
-
|
|
1341
|
+
thread_id: 'supen-thread',
|
|
1358
1342
|
channel: 'web',
|
|
1359
1343
|
agent_name: 'Supen Agent',
|
|
1360
1344
|
space_id: process.env.SUPEN_SPACE_ID || 'local',
|
|
1361
1345
|
});
|
|
1362
|
-
logger.info('Default agent and
|
|
1346
|
+
logger.info('Default agent and thread ensured');
|
|
1363
1347
|
if (isSupabaseConfigured()) {
|
|
1364
1348
|
await pullFromSupabase();
|
|
1365
1349
|
startPeriodicSupabasePush();
|
|
@@ -1400,7 +1384,7 @@ async function main() {
|
|
|
1400
1384
|
});
|
|
1401
1385
|
}
|
|
1402
1386
|
},
|
|
1403
|
-
|
|
1387
|
+
onThreadStop: (agentId, threadId, actor) => requestThreadStop(agentId, threadId, actor),
|
|
1404
1388
|
onChatMetadata: (chatJid, timestamp, name, channel, isGroup) => handleChatMetadata(chatJid, timestamp, name, channel, isGroup),
|
|
1405
1389
|
registeredProjects: () => registeredProjects,
|
|
1406
1390
|
onGroupRegistered: (jid, group) => registerProject(jid, group),
|
|
@@ -1463,8 +1447,8 @@ async function main() {
|
|
|
1463
1447
|
sendFn = async (jid, text, options) => {
|
|
1464
1448
|
const messageId = options?.message_id || `bot-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;
|
|
1465
1449
|
if (!jid.startsWith('task:')) {
|
|
1466
|
-
// Check if this is a gateway
|
|
1467
|
-
// regular gateway
|
|
1450
|
+
// Check if this is a gateway thread - use gateway's routing which handles both
|
|
1451
|
+
// regular gateway threads and channel-based threads (via sendReplyForChat)
|
|
1468
1452
|
const gw = getGatewayInstance();
|
|
1469
1453
|
if (jid.startsWith('gateway:') && gw) {
|
|
1470
1454
|
await gw.sendReplyForChat(jid, text, options?.message_id, options?.trace_id);
|