@openacp/cli 2026.413.1 → 2026.414.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{channel-Dg1nGCYa.d.ts → channel-bWC2vDOv.d.ts} +21 -6
- package/dist/cli.js +210 -107
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +51 -10
- package/dist/index.js +146 -59
- package/dist/index.js.map +1 -1
- package/dist/testing.d.ts +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1870,6 +1870,8 @@ var init_events = __esm({
|
|
|
1870
1870
|
MESSAGE_QUEUED: "message:queued",
|
|
1871
1871
|
/** Fired when a queued message starts processing. */
|
|
1872
1872
|
MESSAGE_PROCESSING: "message:processing",
|
|
1873
|
+
/** Fired when a queued message is rejected (e.g. blocked by middleware). */
|
|
1874
|
+
MESSAGE_FAILED: "message:failed",
|
|
1873
1875
|
// --- System lifecycle ---
|
|
1874
1876
|
/** Fired after kernel (core + plugin infrastructure) has booted. */
|
|
1875
1877
|
KERNEL_BOOTED: "kernel:booted",
|
|
@@ -2031,7 +2033,16 @@ function createSecurityPlugin() {
|
|
|
2031
2033
|
handler: async (payload, next) => {
|
|
2032
2034
|
const access2 = await guard.checkAccess(payload);
|
|
2033
2035
|
if (!access2.allowed) {
|
|
2034
|
-
ctx.log.info(`Access denied: ${access2.reason}`);
|
|
2036
|
+
ctx.log.info(`Access denied for user=${payload.userId} channel=${payload.channelId}: ${access2.reason}`);
|
|
2037
|
+
const adapter = core.adapters?.get?.(payload.channelId);
|
|
2038
|
+
if (adapter?.sendMessage && payload.threadId) {
|
|
2039
|
+
adapter.sendMessage(payload.threadId, {
|
|
2040
|
+
type: "error",
|
|
2041
|
+
message: `Access denied: ${access2.reason ?? "You are not allowed to use this service."}`
|
|
2042
|
+
}).catch((err) => {
|
|
2043
|
+
ctx.log.warn(`Failed to send access-denied message to adapter: ${err}`);
|
|
2044
|
+
});
|
|
2045
|
+
}
|
|
2035
2046
|
return null;
|
|
2036
2047
|
}
|
|
2037
2048
|
return next();
|
|
@@ -2700,23 +2711,30 @@ function createIdentityPlugin() {
|
|
|
2700
2711
|
});
|
|
2701
2712
|
ctx.registerCommand({
|
|
2702
2713
|
name: "whoami",
|
|
2703
|
-
description: "Set your display name
|
|
2704
|
-
usage: "[
|
|
2714
|
+
description: "Set your username and display name",
|
|
2715
|
+
usage: "@username [Display Name]",
|
|
2705
2716
|
category: "plugin",
|
|
2706
2717
|
async handler(args2) {
|
|
2707
|
-
const
|
|
2708
|
-
if (!
|
|
2709
|
-
|
|
2710
|
-
|
|
2718
|
+
const raw = args2.raw.trim();
|
|
2719
|
+
if (!raw) return { type: "error", message: "Usage: /whoami @username [Display Name]" };
|
|
2720
|
+
const tokens = raw.split(/\s+/);
|
|
2721
|
+
const first = tokens[0];
|
|
2722
|
+
const usernameRaw = first.startsWith("@") ? first.slice(1) : first;
|
|
2723
|
+
if (!/^[a-zA-Z0-9_.-]+$/.test(usernameRaw)) {
|
|
2724
|
+
return { type: "error", message: "Invalid username. Only letters, numbers, _ . - allowed." };
|
|
2725
|
+
}
|
|
2726
|
+
const username = usernameRaw;
|
|
2727
|
+
const displayName = tokens.slice(1).join(" ") || void 0;
|
|
2711
2728
|
const identityId = formatIdentityId(args2.channelId, args2.userId);
|
|
2712
2729
|
const user = await service.getUserByIdentity(identityId);
|
|
2713
2730
|
if (!user) {
|
|
2714
|
-
return { type: "error", message: "
|
|
2731
|
+
return { type: "error", message: "Identity not found. Send a message first." };
|
|
2715
2732
|
}
|
|
2716
2733
|
try {
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2734
|
+
await service.updateUser(user.userId, { username, ...displayName && { displayName } });
|
|
2735
|
+
const parts = [`@${username}`];
|
|
2736
|
+
if (displayName) parts.push(`"${displayName}"`);
|
|
2737
|
+
return { type: "text", text: `\u2705 Profile updated: ${parts.join(" ")}` };
|
|
2720
2738
|
} catch (err) {
|
|
2721
2739
|
const message = err instanceof Error ? err.message : String(err);
|
|
2722
2740
|
return { type: "error", message };
|
|
@@ -8987,7 +9005,8 @@ var init_sse_manager = __esm({
|
|
|
8987
9005
|
BusEvent.PERMISSION_REQUEST,
|
|
8988
9006
|
BusEvent.PERMISSION_RESOLVED,
|
|
8989
9007
|
BusEvent.MESSAGE_QUEUED,
|
|
8990
|
-
BusEvent.MESSAGE_PROCESSING
|
|
9008
|
+
BusEvent.MESSAGE_PROCESSING,
|
|
9009
|
+
BusEvent.MESSAGE_FAILED
|
|
8991
9010
|
];
|
|
8992
9011
|
for (const eventName of events) {
|
|
8993
9012
|
const handler = (data) => {
|
|
@@ -9069,7 +9088,8 @@ data: ${JSON.stringify(data)}
|
|
|
9069
9088
|
BusEvent.PERMISSION_RESOLVED,
|
|
9070
9089
|
BusEvent.SESSION_UPDATED,
|
|
9071
9090
|
BusEvent.MESSAGE_QUEUED,
|
|
9072
|
-
BusEvent.MESSAGE_PROCESSING
|
|
9091
|
+
BusEvent.MESSAGE_PROCESSING,
|
|
9092
|
+
BusEvent.MESSAGE_FAILED
|
|
9073
9093
|
];
|
|
9074
9094
|
for (const res of this.sseConnections) {
|
|
9075
9095
|
const filter = res.sessionFilter;
|
|
@@ -9339,7 +9359,6 @@ var sessions_exports = {};
|
|
|
9339
9359
|
__export(sessions_exports, {
|
|
9340
9360
|
sessionRoutes: () => sessionRoutes
|
|
9341
9361
|
});
|
|
9342
|
-
import { nanoid as nanoid3 } from "nanoid";
|
|
9343
9362
|
async function sessionRoutes(app, deps) {
|
|
9344
9363
|
app.get("/", { preHandler: requireScopes("sessions:read") }, async () => {
|
|
9345
9364
|
const summaries = deps.core.sessionManager.listAllSessions();
|
|
@@ -9515,34 +9534,36 @@ async function sessionRoutes(app, deps) {
|
|
|
9515
9534
|
attachments = await resolveAttachments(fileService, sessionId, body.attachments);
|
|
9516
9535
|
}
|
|
9517
9536
|
const sourceAdapterId = body.sourceAdapterId ?? "sse";
|
|
9518
|
-
const turnId = body.turnId ?? nanoid3(8);
|
|
9519
9537
|
const userId = request.auth?.tokenId ?? "api";
|
|
9520
|
-
const
|
|
9521
|
-
|
|
9522
|
-
|
|
9523
|
-
|
|
9524
|
-
|
|
9525
|
-
|
|
9538
|
+
const result = await deps.core.handleMessageInSession(
|
|
9539
|
+
session,
|
|
9540
|
+
{ channelId: sourceAdapterId, userId, text: body.prompt, attachments },
|
|
9541
|
+
{ channelUser: { channelId: "sse", userId } },
|
|
9542
|
+
{ externalTurnId: body.turnId, responseAdapterId: body.responseAdapterId }
|
|
9543
|
+
);
|
|
9544
|
+
if (!result) {
|
|
9545
|
+
throw new AuthError("MESSAGE_BLOCKED", "Message was blocked by a middleware plugin.", 403);
|
|
9546
|
+
}
|
|
9547
|
+
return { ok: true, sessionId, queueDepth: result.queueDepth, turnId: result.turnId };
|
|
9548
|
+
}
|
|
9549
|
+
);
|
|
9550
|
+
app.get(
|
|
9551
|
+
"/:sessionId/queue",
|
|
9552
|
+
{ preHandler: requireScopes("sessions:read") },
|
|
9553
|
+
async (request) => {
|
|
9554
|
+
const { sessionId: rawId } = SessionIdParamSchema.parse(request.params);
|
|
9555
|
+
const sessionId = decodeURIComponent(rawId);
|
|
9556
|
+
const session = await deps.core.getOrResumeSessionById(sessionId);
|
|
9557
|
+
if (!session) {
|
|
9558
|
+
throw new NotFoundError(
|
|
9559
|
+
"SESSION_NOT_FOUND",
|
|
9560
|
+
`Session "${sessionId}" not found`
|
|
9526
9561
|
);
|
|
9527
9562
|
}
|
|
9528
|
-
deps.core.eventBus.emit(BusEvent.MESSAGE_QUEUED, {
|
|
9529
|
-
sessionId,
|
|
9530
|
-
turnId,
|
|
9531
|
-
text: body.prompt,
|
|
9532
|
-
sourceAdapterId,
|
|
9533
|
-
attachments,
|
|
9534
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
9535
|
-
queueDepth: session.queueDepth
|
|
9536
|
-
});
|
|
9537
|
-
await session.enqueuePrompt(body.prompt, attachments, {
|
|
9538
|
-
sourceAdapterId,
|
|
9539
|
-
responseAdapterId: body.responseAdapterId
|
|
9540
|
-
}, turnId, meta);
|
|
9541
9563
|
return {
|
|
9542
|
-
|
|
9543
|
-
|
|
9544
|
-
queueDepth: session.queueDepth
|
|
9545
|
-
turnId
|
|
9564
|
+
pending: session.queueItems,
|
|
9565
|
+
processing: session.promptRunning,
|
|
9566
|
+
queueDepth: session.queueDepth
|
|
9546
9567
|
};
|
|
9547
9568
|
}
|
|
9548
9569
|
);
|
|
@@ -9810,7 +9831,6 @@ var init_sessions2 = __esm({
|
|
|
9810
9831
|
init_error_handler();
|
|
9811
9832
|
init_auth();
|
|
9812
9833
|
init_attachment_utils();
|
|
9813
|
-
init_events();
|
|
9814
9834
|
init_sessions();
|
|
9815
9835
|
}
|
|
9816
9836
|
});
|
|
@@ -12139,14 +12159,13 @@ async function sseRoutes(app, deps) {
|
|
|
12139
12159
|
}
|
|
12140
12160
|
attachments = await resolveAttachments(fileService, sessionId, body.attachments);
|
|
12141
12161
|
}
|
|
12142
|
-
const queueDepth = session.queueDepth + 1;
|
|
12143
12162
|
const userId = request.auth?.tokenId ?? "api";
|
|
12144
|
-
await deps.core.handleMessageInSession(
|
|
12163
|
+
const { turnId, queueDepth } = await deps.core.handleMessageInSession(
|
|
12145
12164
|
session,
|
|
12146
12165
|
{ channelId: "sse", userId, text: body.prompt, attachments },
|
|
12147
12166
|
{ channelUser: { channelId: "sse", userId } }
|
|
12148
12167
|
);
|
|
12149
|
-
return { ok: true, sessionId, queueDepth };
|
|
12168
|
+
return { ok: true, sessionId, queueDepth, turnId };
|
|
12150
12169
|
}
|
|
12151
12170
|
);
|
|
12152
12171
|
app.post(
|
|
@@ -16363,7 +16382,7 @@ var init_commands3 = __esm({
|
|
|
16363
16382
|
|
|
16364
16383
|
// src/plugins/telegram/permissions.ts
|
|
16365
16384
|
import { InlineKeyboard as InlineKeyboard11 } from "grammy";
|
|
16366
|
-
import { nanoid as
|
|
16385
|
+
import { nanoid as nanoid3 } from "nanoid";
|
|
16367
16386
|
var log26, PermissionHandler;
|
|
16368
16387
|
var init_permissions = __esm({
|
|
16369
16388
|
"src/plugins/telegram/permissions.ts"() {
|
|
@@ -16390,7 +16409,7 @@ var init_permissions = __esm({
|
|
|
16390
16409
|
*/
|
|
16391
16410
|
async sendPermissionRequest(session, request) {
|
|
16392
16411
|
const threadId = Number(session.threadId);
|
|
16393
|
-
const callbackKey =
|
|
16412
|
+
const callbackKey = nanoid3(8);
|
|
16394
16413
|
this.pending.set(callbackKey, {
|
|
16395
16414
|
sessionId: session.id,
|
|
16396
16415
|
requestId: request.id,
|
|
@@ -18401,7 +18420,11 @@ var init_adapter2 = __esm({
|
|
|
18401
18420
|
}
|
|
18402
18421
|
return prev(method, payload, signal);
|
|
18403
18422
|
});
|
|
18404
|
-
|
|
18423
|
+
const onCommandsReady = ({ commands }) => {
|
|
18424
|
+
this.core.eventBus.off(BusEvent.SYSTEM_COMMANDS_READY, onCommandsReady);
|
|
18425
|
+
this.syncCommandsWithRetry(commands);
|
|
18426
|
+
};
|
|
18427
|
+
this.core.eventBus.on(BusEvent.SYSTEM_COMMANDS_READY, onCommandsReady);
|
|
18405
18428
|
this.bot.use((ctx, next) => {
|
|
18406
18429
|
const chatId = ctx.chat?.id ?? ctx.callbackQuery?.message?.chat?.id;
|
|
18407
18430
|
if (chatId !== this.telegramConfig.chatId) return;
|
|
@@ -18627,12 +18650,16 @@ ${p2}` : p2;
|
|
|
18627
18650
|
throw new Error("unreachable");
|
|
18628
18651
|
}
|
|
18629
18652
|
/**
|
|
18630
|
-
*
|
|
18631
|
-
*
|
|
18653
|
+
* Sync Telegram autocomplete commands after all plugins are ready.
|
|
18654
|
+
* Merges STATIC_COMMANDS (hardcoded system commands) with plugin commands
|
|
18655
|
+
* from the registry, deduplicating by command name. Non-critical.
|
|
18632
18656
|
*/
|
|
18633
|
-
|
|
18657
|
+
syncCommandsWithRetry(registryCommands) {
|
|
18658
|
+
const staticNames = new Set(STATIC_COMMANDS.map((c3) => c3.command));
|
|
18659
|
+
const pluginCommands = registryCommands.filter((c3) => c3.category === "plugin" && !staticNames.has(c3.name) && /^[a-z0-9_]+$/.test(c3.name)).map((c3) => ({ command: c3.name, description: c3.description.slice(0, 256) }));
|
|
18660
|
+
const allCommands = [...STATIC_COMMANDS, ...pluginCommands].slice(0, 100);
|
|
18634
18661
|
this.retryWithBackoff(
|
|
18635
|
-
() => this.bot.api.setMyCommands(
|
|
18662
|
+
() => this.bot.api.setMyCommands(allCommands, {
|
|
18636
18663
|
scope: { type: "chat", chat_id: this.telegramConfig.chatId }
|
|
18637
18664
|
}),
|
|
18638
18665
|
"setMyCommands"
|
|
@@ -22161,16 +22188,16 @@ var init_prompt_queue = __esm({
|
|
|
22161
22188
|
* immediately. Otherwise, it's buffered and the returned promise resolves
|
|
22162
22189
|
* only after the prompt finishes processing.
|
|
22163
22190
|
*/
|
|
22164
|
-
async enqueue(text5, attachments, routing, turnId, meta) {
|
|
22191
|
+
async enqueue(text5, userPrompt, attachments, routing, turnId, meta) {
|
|
22165
22192
|
if (this.processing) {
|
|
22166
22193
|
return new Promise((resolve9) => {
|
|
22167
|
-
this.queue.push({ text: text5, attachments, routing, turnId, meta, resolve: resolve9 });
|
|
22194
|
+
this.queue.push({ text: text5, userPrompt, attachments, routing, turnId, meta, resolve: resolve9 });
|
|
22168
22195
|
});
|
|
22169
22196
|
}
|
|
22170
|
-
await this.process(text5, attachments, routing, turnId, meta);
|
|
22197
|
+
await this.process(text5, userPrompt, attachments, routing, turnId, meta);
|
|
22171
22198
|
}
|
|
22172
22199
|
/** Run a single prompt through the processor, then drain the next queued item. */
|
|
22173
|
-
async process(text5, attachments, routing, turnId, meta) {
|
|
22200
|
+
async process(text5, userPrompt, attachments, routing, turnId, meta) {
|
|
22174
22201
|
this.processing = true;
|
|
22175
22202
|
this.abortController = new AbortController();
|
|
22176
22203
|
const { signal } = this.abortController;
|
|
@@ -22180,7 +22207,7 @@ var init_prompt_queue = __esm({
|
|
|
22180
22207
|
});
|
|
22181
22208
|
try {
|
|
22182
22209
|
await Promise.race([
|
|
22183
|
-
this.processor(text5, attachments, routing, turnId, meta),
|
|
22210
|
+
this.processor(text5, userPrompt, attachments, routing, turnId, meta),
|
|
22184
22211
|
new Promise((_, reject) => {
|
|
22185
22212
|
signal.addEventListener("abort", () => reject(new Error("Prompt aborted")), { once: true });
|
|
22186
22213
|
})
|
|
@@ -22201,7 +22228,7 @@ var init_prompt_queue = __esm({
|
|
|
22201
22228
|
drainNext() {
|
|
22202
22229
|
const next = this.queue.shift();
|
|
22203
22230
|
if (next) {
|
|
22204
|
-
this.process(next.text, next.attachments, next.routing, next.turnId, next.meta).then(next.resolve);
|
|
22231
|
+
this.process(next.text, next.userPrompt, next.attachments, next.routing, next.turnId, next.meta).then(next.resolve);
|
|
22205
22232
|
}
|
|
22206
22233
|
}
|
|
22207
22234
|
/**
|
|
@@ -22223,6 +22250,13 @@ var init_prompt_queue = __esm({
|
|
|
22223
22250
|
get isProcessing() {
|
|
22224
22251
|
return this.processing;
|
|
22225
22252
|
}
|
|
22253
|
+
/** Snapshot of queued (not yet processing) items — used for queue inspection by callers. */
|
|
22254
|
+
get pendingItems() {
|
|
22255
|
+
return this.queue.map((item) => ({
|
|
22256
|
+
userPrompt: item.userPrompt,
|
|
22257
|
+
turnId: item.turnId
|
|
22258
|
+
}));
|
|
22259
|
+
}
|
|
22226
22260
|
};
|
|
22227
22261
|
}
|
|
22228
22262
|
});
|
|
@@ -22307,18 +22341,32 @@ var init_permission_gate = __esm({
|
|
|
22307
22341
|
});
|
|
22308
22342
|
|
|
22309
22343
|
// src/core/sessions/turn-context.ts
|
|
22310
|
-
import { nanoid as
|
|
22311
|
-
function
|
|
22344
|
+
import { nanoid as nanoid4 } from "nanoid";
|
|
22345
|
+
function extractSender(meta) {
|
|
22346
|
+
const identity = meta?.identity;
|
|
22347
|
+
if (!identity || !identity.userId || !identity.identityId) return null;
|
|
22312
22348
|
return {
|
|
22313
|
-
|
|
22314
|
-
|
|
22315
|
-
|
|
22349
|
+
userId: identity.userId,
|
|
22350
|
+
identityId: identity.identityId,
|
|
22351
|
+
displayName: identity.displayName,
|
|
22352
|
+
username: identity.username
|
|
22316
22353
|
};
|
|
22317
22354
|
}
|
|
22318
22355
|
function getEffectiveTarget(ctx) {
|
|
22319
22356
|
if (ctx.responseAdapterId === null) return null;
|
|
22320
22357
|
return ctx.responseAdapterId ?? ctx.sourceAdapterId;
|
|
22321
22358
|
}
|
|
22359
|
+
function createTurnContext(sourceAdapterId, responseAdapterId, turnId, userPrompt, finalPrompt, attachments, meta) {
|
|
22360
|
+
return {
|
|
22361
|
+
turnId: turnId ?? nanoid4(8),
|
|
22362
|
+
sourceAdapterId,
|
|
22363
|
+
responseAdapterId,
|
|
22364
|
+
userPrompt,
|
|
22365
|
+
finalPrompt,
|
|
22366
|
+
attachments,
|
|
22367
|
+
meta
|
|
22368
|
+
};
|
|
22369
|
+
}
|
|
22322
22370
|
function isSystemEvent(event) {
|
|
22323
22371
|
return SYSTEM_EVENT_TYPES.has(event.type);
|
|
22324
22372
|
}
|
|
@@ -22338,7 +22386,7 @@ var init_turn_context = __esm({
|
|
|
22338
22386
|
});
|
|
22339
22387
|
|
|
22340
22388
|
// src/core/sessions/session.ts
|
|
22341
|
-
import { nanoid as
|
|
22389
|
+
import { nanoid as nanoid5 } from "nanoid";
|
|
22342
22390
|
import * as fs41 from "fs";
|
|
22343
22391
|
var moduleLog, TTS_PROMPT_INSTRUCTION, TTS_BLOCK_REGEX, TTS_MAX_LENGTH, TTS_TIMEOUT_MS, VALID_TRANSITIONS, Session;
|
|
22344
22392
|
var init_session2 = __esm({
|
|
@@ -22418,7 +22466,7 @@ Additionally, include a [TTS]...[/TTS] block with a spoken-friendly summary of y
|
|
|
22418
22466
|
pendingContext = null;
|
|
22419
22467
|
constructor(opts) {
|
|
22420
22468
|
super();
|
|
22421
|
-
this.id = opts.id ||
|
|
22469
|
+
this.id = opts.id || nanoid5(12);
|
|
22422
22470
|
this.channelId = opts.channelId;
|
|
22423
22471
|
this.attachedAdapters = [opts.channelId];
|
|
22424
22472
|
this.agentName = opts.agentName;
|
|
@@ -22430,7 +22478,7 @@ Additionally, include a [TTS]...[/TTS] block with a spoken-friendly summary of y
|
|
|
22430
22478
|
this.log = createSessionLogger(this.id, moduleLog);
|
|
22431
22479
|
this.log.info({ agentName: this.agentName }, "Session created");
|
|
22432
22480
|
this.queue = new PromptQueue(
|
|
22433
|
-
(text5, attachments, routing, turnId, meta) => this.processPrompt(text5, attachments, routing, turnId, meta),
|
|
22481
|
+
(text5, userPrompt, attachments, routing, turnId, meta) => this.processPrompt(text5, userPrompt, attachments, routing, turnId, meta),
|
|
22434
22482
|
(err) => {
|
|
22435
22483
|
this.log.error({ err }, "Prompt execution failed");
|
|
22436
22484
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -22510,6 +22558,10 @@ Additionally, include a [TTS]...[/TTS] block with a spoken-friendly summary of y
|
|
|
22510
22558
|
get promptRunning() {
|
|
22511
22559
|
return this.queue.isProcessing;
|
|
22512
22560
|
}
|
|
22561
|
+
/** Snapshot of queued (not yet processing) items — for inspection by API consumers. */
|
|
22562
|
+
get queueItems() {
|
|
22563
|
+
return this.queue.pendingItems;
|
|
22564
|
+
}
|
|
22513
22565
|
// --- Context Injection ---
|
|
22514
22566
|
/** Store context markdown to be prepended to the next prompt (used for session resume with history). */
|
|
22515
22567
|
setContext(markdown) {
|
|
@@ -22530,24 +22582,30 @@ Additionally, include a [TTS]...[/TTS] block with a spoken-friendly summary of y
|
|
|
22530
22582
|
* queued/processing events before the prompt actually runs.
|
|
22531
22583
|
*/
|
|
22532
22584
|
async enqueuePrompt(text5, attachments, routing, externalTurnId, meta) {
|
|
22533
|
-
const turnId = externalTurnId ??
|
|
22585
|
+
const turnId = externalTurnId ?? nanoid5(8);
|
|
22534
22586
|
const turnMeta = meta ?? { turnId };
|
|
22587
|
+
const userPrompt = text5;
|
|
22535
22588
|
if (this.middlewareChain) {
|
|
22536
22589
|
const payload = { text: text5, attachments, sessionId: this.id, sourceAdapterId: routing?.sourceAdapterId, meta: turnMeta };
|
|
22537
22590
|
const result = await this.middlewareChain.execute(Hook.AGENT_BEFORE_PROMPT, payload, async (p2) => p2);
|
|
22538
|
-
if (!result)
|
|
22591
|
+
if (!result) throw new Error("PROMPT_BLOCKED");
|
|
22539
22592
|
text5 = result.text;
|
|
22540
22593
|
attachments = result.attachments;
|
|
22541
22594
|
}
|
|
22542
|
-
await this.queue.enqueue(text5, attachments, routing, turnId, turnMeta);
|
|
22595
|
+
await this.queue.enqueue(text5, userPrompt, attachments, routing, turnId, turnMeta);
|
|
22543
22596
|
return turnId;
|
|
22544
22597
|
}
|
|
22545
|
-
async processPrompt(text5, attachments, routing, turnId, meta) {
|
|
22598
|
+
async processPrompt(text5, userPrompt, attachments, routing, turnId, meta) {
|
|
22546
22599
|
if (this._status === "finished") return;
|
|
22547
22600
|
this.activeTurnContext = createTurnContext(
|
|
22548
22601
|
routing?.sourceAdapterId ?? this.channelId,
|
|
22549
22602
|
routing?.responseAdapterId,
|
|
22550
|
-
turnId
|
|
22603
|
+
turnId,
|
|
22604
|
+
userPrompt,
|
|
22605
|
+
text5,
|
|
22606
|
+
// finalPrompt (after middleware transformations)
|
|
22607
|
+
attachments,
|
|
22608
|
+
meta
|
|
22551
22609
|
);
|
|
22552
22610
|
this.emit(SessionEv.TURN_STARTED, this.activeTurnContext);
|
|
22553
22611
|
this.promptCount++;
|
|
@@ -22598,7 +22656,16 @@ ${text5}`;
|
|
|
22598
22656
|
this.agentInstance.on(SessionEv.AGENT_EVENT, afterEventListener);
|
|
22599
22657
|
}
|
|
22600
22658
|
if (this.middlewareChain) {
|
|
22601
|
-
this.middlewareChain.execute(Hook.TURN_START, {
|
|
22659
|
+
this.middlewareChain.execute(Hook.TURN_START, {
|
|
22660
|
+
sessionId: this.id,
|
|
22661
|
+
promptText: processed.text,
|
|
22662
|
+
promptNumber: this.promptCount,
|
|
22663
|
+
turnId: this.activeTurnContext?.turnId ?? turnId ?? "",
|
|
22664
|
+
meta,
|
|
22665
|
+
userPrompt: this.activeTurnContext?.userPrompt,
|
|
22666
|
+
sourceAdapterId: this.activeTurnContext?.sourceAdapterId,
|
|
22667
|
+
responseAdapterId: this.activeTurnContext?.responseAdapterId
|
|
22668
|
+
}, async (p2) => p2).catch(() => {
|
|
22602
22669
|
});
|
|
22603
22670
|
}
|
|
22604
22671
|
let stopReason = "end_turn";
|
|
@@ -23269,7 +23336,7 @@ var init_session_bridge = __esm({
|
|
|
23269
23336
|
if (this.shouldForward(event)) {
|
|
23270
23337
|
this.dispatchAgentEvent(event);
|
|
23271
23338
|
} else {
|
|
23272
|
-
this.deps.eventBus?.emit(BusEvent.AGENT_EVENT, { sessionId: this.session.id, event });
|
|
23339
|
+
this.deps.eventBus?.emit(BusEvent.AGENT_EVENT, { sessionId: this.session.id, turnId: "", event });
|
|
23273
23340
|
}
|
|
23274
23341
|
});
|
|
23275
23342
|
if (!this.session.agentInstance.onPermissionRequest || this.session.agentInstance.onPermissionRequest.__bridgeId === void 0) {
|
|
@@ -23322,14 +23389,16 @@ var init_session_bridge = __esm({
|
|
|
23322
23389
|
this.deps.sessionManager.patchRecord(this.session.id, { currentPromptCount: count });
|
|
23323
23390
|
});
|
|
23324
23391
|
this.listen(this.session, SessionEv.TURN_STARTED, (ctx) => {
|
|
23325
|
-
|
|
23326
|
-
this.
|
|
23327
|
-
|
|
23328
|
-
|
|
23329
|
-
|
|
23330
|
-
|
|
23331
|
-
|
|
23332
|
-
|
|
23392
|
+
this.deps.eventBus?.emit(BusEvent.MESSAGE_PROCESSING, {
|
|
23393
|
+
sessionId: this.session.id,
|
|
23394
|
+
turnId: ctx.turnId,
|
|
23395
|
+
sourceAdapterId: ctx.sourceAdapterId,
|
|
23396
|
+
userPrompt: ctx.userPrompt,
|
|
23397
|
+
finalPrompt: ctx.finalPrompt,
|
|
23398
|
+
attachments: ctx.attachments,
|
|
23399
|
+
sender: extractSender(ctx.meta),
|
|
23400
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
23401
|
+
});
|
|
23333
23402
|
});
|
|
23334
23403
|
if (this.session.latestCommands !== null) {
|
|
23335
23404
|
this.session.emit(SessionEv.AGENT_EVENT, { type: "commands_update", commands: this.session.latestCommands });
|
|
@@ -23495,6 +23564,7 @@ var init_session_bridge = __esm({
|
|
|
23495
23564
|
}
|
|
23496
23565
|
this.deps.eventBus?.emit(BusEvent.AGENT_EVENT, {
|
|
23497
23566
|
sessionId: this.session.id,
|
|
23567
|
+
turnId: this.session.activeTurnContext?.turnId ?? "",
|
|
23498
23568
|
event
|
|
23499
23569
|
});
|
|
23500
23570
|
return outgoing;
|
|
@@ -24408,6 +24478,7 @@ var init_session_factory = __esm({
|
|
|
24408
24478
|
const failedSessionId = createParams.existingSessionId ?? `failed-${Date.now()}`;
|
|
24409
24479
|
this.eventBus.emit(BusEvent.AGENT_EVENT, {
|
|
24410
24480
|
sessionId: failedSessionId,
|
|
24481
|
+
turnId: "",
|
|
24411
24482
|
event: guidance
|
|
24412
24483
|
});
|
|
24413
24484
|
throw err;
|
|
@@ -24778,7 +24849,7 @@ var init_agent_switch_handler = __esm({
|
|
|
24778
24849
|
message: `Switching from ${fromAgent} to ${toAgent}...`
|
|
24779
24850
|
};
|
|
24780
24851
|
session.emit(SessionEv.AGENT_EVENT, startEvent);
|
|
24781
|
-
eventBus.emit(BusEvent.AGENT_EVENT, { sessionId, event: startEvent });
|
|
24852
|
+
eventBus.emit(BusEvent.AGENT_EVENT, { sessionId, turnId: "", event: startEvent });
|
|
24782
24853
|
eventBus.emit(BusEvent.SESSION_AGENT_SWITCH, {
|
|
24783
24854
|
sessionId,
|
|
24784
24855
|
fromAgent,
|
|
@@ -24841,7 +24912,7 @@ var init_agent_switch_handler = __esm({
|
|
|
24841
24912
|
message: resumed ? `Switched to ${toAgent} (resumed previous session).` : `Switched to ${toAgent} (new session).`
|
|
24842
24913
|
};
|
|
24843
24914
|
session.emit(SessionEv.AGENT_EVENT, successEvent);
|
|
24844
|
-
eventBus.emit(BusEvent.AGENT_EVENT, { sessionId, event: successEvent });
|
|
24915
|
+
eventBus.emit(BusEvent.AGENT_EVENT, { sessionId, turnId: "", event: successEvent });
|
|
24845
24916
|
eventBus.emit(BusEvent.SESSION_AGENT_SWITCH, {
|
|
24846
24917
|
sessionId,
|
|
24847
24918
|
fromAgent,
|
|
@@ -24856,7 +24927,7 @@ var init_agent_switch_handler = __esm({
|
|
|
24856
24927
|
message: `Failed to switch to ${toAgent}: ${errorMessage}`
|
|
24857
24928
|
};
|
|
24858
24929
|
session.emit(SessionEv.AGENT_EVENT, failedEvent);
|
|
24859
|
-
eventBus.emit(BusEvent.AGENT_EVENT, { sessionId, event: failedEvent });
|
|
24930
|
+
eventBus.emit(BusEvent.AGENT_EVENT, { sessionId, turnId: "", event: failedEvent });
|
|
24860
24931
|
eventBus.emit(BusEvent.SESSION_AGENT_SWITCH, {
|
|
24861
24932
|
sessionId,
|
|
24862
24933
|
fromAgent,
|
|
@@ -26769,7 +26840,7 @@ var init_core_items = __esm({
|
|
|
26769
26840
|
|
|
26770
26841
|
// src/core/core.ts
|
|
26771
26842
|
import path51 from "path";
|
|
26772
|
-
import { nanoid as
|
|
26843
|
+
import { nanoid as nanoid6 } from "nanoid";
|
|
26773
26844
|
var log44, OpenACPCore;
|
|
26774
26845
|
var init_core = __esm({
|
|
26775
26846
|
"src/core/core.ts"() {
|
|
@@ -26795,6 +26866,7 @@ var init_core = __esm({
|
|
|
26795
26866
|
init_error_tracker();
|
|
26796
26867
|
init_log();
|
|
26797
26868
|
init_events();
|
|
26869
|
+
init_turn_context();
|
|
26798
26870
|
log44 = createChildLogger({ module: "core" });
|
|
26799
26871
|
OpenACPCore = class {
|
|
26800
26872
|
configManager;
|
|
@@ -27080,7 +27152,7 @@ var init_core = __esm({
|
|
|
27080
27152
|
},
|
|
27081
27153
|
"Incoming message"
|
|
27082
27154
|
);
|
|
27083
|
-
const turnId =
|
|
27155
|
+
const turnId = nanoid6(8);
|
|
27084
27156
|
const meta = { turnId, ...initialMeta };
|
|
27085
27157
|
if (this.lifecycleManager?.middlewareChain) {
|
|
27086
27158
|
const result = await this.lifecycleManager.middlewareChain.execute(
|
|
@@ -27120,9 +27192,6 @@ var init_core = __esm({
|
|
|
27120
27192
|
}
|
|
27121
27193
|
return;
|
|
27122
27194
|
}
|
|
27123
|
-
this.sessionManager.patchRecord(session.id, {
|
|
27124
|
-
lastActiveAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
27125
|
-
});
|
|
27126
27195
|
let text5 = message.text;
|
|
27127
27196
|
if (this.assistantManager?.isAssistant(session.id)) {
|
|
27128
27197
|
const pending = this.assistantManager.consumePendingSystemPrompt(message.channelId);
|
|
@@ -27135,38 +27204,56 @@ User message:
|
|
|
27135
27204
|
${text5}`;
|
|
27136
27205
|
}
|
|
27137
27206
|
}
|
|
27138
|
-
const sourceAdapterId = message.routing?.sourceAdapterId ?? message.channelId;
|
|
27139
|
-
const routing = sourceAdapterId !== message.routing?.sourceAdapterId ? { ...message.routing, sourceAdapterId } : message.routing;
|
|
27140
27207
|
const enrichedMeta = message.meta ?? meta;
|
|
27141
|
-
|
|
27142
|
-
|
|
27208
|
+
await this._dispatchToSession(session, text5, message.attachments, {
|
|
27209
|
+
sourceAdapterId: message.routing?.sourceAdapterId ?? message.channelId,
|
|
27210
|
+
responseAdapterId: message.routing?.responseAdapterId
|
|
27211
|
+
}, turnId, enrichedMeta);
|
|
27212
|
+
}
|
|
27213
|
+
/**
|
|
27214
|
+
* Shared dispatch path for sending a prompt to a session.
|
|
27215
|
+
* Called by both handleMessage (Telegram) and handleMessageInSession (SSE/API)
|
|
27216
|
+
* after their respective middleware/enrichment steps.
|
|
27217
|
+
*/
|
|
27218
|
+
async _dispatchToSession(session, text5, attachments, routing, turnId, meta) {
|
|
27219
|
+
this.sessionManager.patchRecord(session.id, {
|
|
27220
|
+
lastActiveAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
27221
|
+
});
|
|
27222
|
+
this.eventBus.emit(BusEvent.MESSAGE_QUEUED, {
|
|
27223
|
+
sessionId: session.id,
|
|
27224
|
+
turnId,
|
|
27225
|
+
text: text5,
|
|
27226
|
+
sourceAdapterId: routing.sourceAdapterId,
|
|
27227
|
+
attachments,
|
|
27228
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
27229
|
+
queueDepth: session.queueDepth + 1,
|
|
27230
|
+
sender: extractSender(meta)
|
|
27231
|
+
});
|
|
27232
|
+
session.enqueuePrompt(text5, attachments, routing, turnId, meta).catch((err) => {
|
|
27233
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
27234
|
+
log44.warn({ err, sessionId: session.id, turnId, reason }, "enqueuePrompt failed \u2014 emitting message:failed");
|
|
27235
|
+
this.eventBus.emit(BusEvent.MESSAGE_FAILED, {
|
|
27143
27236
|
sessionId: session.id,
|
|
27144
27237
|
turnId,
|
|
27145
|
-
|
|
27146
|
-
sourceAdapterId,
|
|
27147
|
-
attachments: message.attachments,
|
|
27148
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
27149
|
-
queueDepth: session.queueDepth
|
|
27238
|
+
reason
|
|
27150
27239
|
});
|
|
27151
|
-
|
|
27152
|
-
} else {
|
|
27153
|
-
await session.enqueuePrompt(text5, message.attachments, routing, turnId, enrichedMeta);
|
|
27154
|
-
}
|
|
27240
|
+
});
|
|
27155
27241
|
}
|
|
27156
27242
|
/**
|
|
27157
27243
|
* Send a message to a known session, running the full message:incoming → agent:beforePrompt
|
|
27158
27244
|
* middleware chain (same as handleMessage) but without the threadId-based session lookup.
|
|
27159
27245
|
*
|
|
27160
|
-
* Used by channels that already hold a direct session reference (e.g. SSE adapter),
|
|
27161
|
-
* looking up by channelId+threadId is unreliable (API sessions may have no threadId).
|
|
27246
|
+
* Used by channels that already hold a direct session reference (e.g. SSE adapter, api-server),
|
|
27247
|
+
* where looking up by channelId+threadId is unreliable (API sessions may have no threadId).
|
|
27162
27248
|
*
|
|
27163
27249
|
* @param session The target session — caller is responsible for validating its status.
|
|
27164
27250
|
* @param message Sender context and message content.
|
|
27165
27251
|
* @param initialMeta Optional adapter-specific context to seed the TurnMeta bag
|
|
27166
27252
|
* (e.g. channelUser with display name/username).
|
|
27253
|
+
* @param options Optional turnId override and response routing.
|
|
27167
27254
|
*/
|
|
27168
|
-
async handleMessageInSession(session, message, initialMeta) {
|
|
27169
|
-
const turnId =
|
|
27255
|
+
async handleMessageInSession(session, message, initialMeta, options) {
|
|
27256
|
+
const turnId = options?.externalTurnId ?? nanoid6(8);
|
|
27170
27257
|
const meta = { turnId, ...initialMeta };
|
|
27171
27258
|
let text5 = message.text;
|
|
27172
27259
|
let { attachments } = message;
|
|
@@ -27185,13 +27272,17 @@ ${text5}`;
|
|
|
27185
27272
|
payload,
|
|
27186
27273
|
async (p2) => p2
|
|
27187
27274
|
);
|
|
27188
|
-
if (!result) return;
|
|
27275
|
+
if (!result) return { turnId, queueDepth: session.queueDepth };
|
|
27189
27276
|
text5 = result.text;
|
|
27190
27277
|
attachments = result.attachments;
|
|
27191
27278
|
enrichedMeta = result.meta ?? meta;
|
|
27192
27279
|
}
|
|
27193
|
-
const routing = {
|
|
27194
|
-
|
|
27280
|
+
const routing = {
|
|
27281
|
+
sourceAdapterId: message.channelId,
|
|
27282
|
+
responseAdapterId: options?.responseAdapterId
|
|
27283
|
+
};
|
|
27284
|
+
await this._dispatchToSession(session, text5, attachments, routing, turnId, enrichedMeta);
|
|
27285
|
+
return { turnId, queueDepth: session.queueDepth };
|
|
27195
27286
|
}
|
|
27196
27287
|
// --- Unified Session Creation Pipeline ---
|
|
27197
27288
|
/**
|
|
@@ -27303,7 +27394,7 @@ ${text5}`;
|
|
|
27303
27394
|
} else if (processedEvent.type === "error") {
|
|
27304
27395
|
session.fail(processedEvent.message);
|
|
27305
27396
|
}
|
|
27306
|
-
this.eventBus.emit(BusEvent.AGENT_EVENT, { sessionId: session.id, event: processedEvent });
|
|
27397
|
+
this.eventBus.emit(BusEvent.AGENT_EVENT, { sessionId: session.id, turnId: session.activeTurnContext?.turnId ?? "", event: processedEvent });
|
|
27307
27398
|
});
|
|
27308
27399
|
session.on(SessionEv.STATUS_CHANGE, (_from, to) => {
|
|
27309
27400
|
this.sessionManager.patchRecord(session.id, {
|
|
@@ -27315,6 +27406,18 @@ ${text5}`;
|
|
|
27315
27406
|
session.on(SessionEv.PROMPT_COUNT_CHANGED, (count) => {
|
|
27316
27407
|
this.sessionManager.patchRecord(session.id, { currentPromptCount: count });
|
|
27317
27408
|
});
|
|
27409
|
+
session.on(SessionEv.TURN_STARTED, (ctx) => {
|
|
27410
|
+
this.eventBus.emit(BusEvent.MESSAGE_PROCESSING, {
|
|
27411
|
+
sessionId: session.id,
|
|
27412
|
+
turnId: ctx.turnId,
|
|
27413
|
+
sourceAdapterId: ctx.sourceAdapterId,
|
|
27414
|
+
userPrompt: ctx.userPrompt,
|
|
27415
|
+
finalPrompt: ctx.finalPrompt,
|
|
27416
|
+
attachments: ctx.attachments,
|
|
27417
|
+
sender: extractSender(ctx.meta),
|
|
27418
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
27419
|
+
});
|
|
27420
|
+
});
|
|
27318
27421
|
}
|
|
27319
27422
|
this.sessionFactory.wireSideEffects(session, {
|
|
27320
27423
|
eventBus: this.eventBus,
|