@openacp/cli 2026.410.3 → 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-CFMUPzvH.d.ts → channel-bWC2vDOv.d.ts} +49 -6
- package/dist/cli.js +1410 -139
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +294 -25
- package/dist/index.js +448 -73
- package/dist/index.js.map +1 -1
- package/dist/testing.d.ts +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -793,6 +793,8 @@ var init_events = __esm({
|
|
|
793
793
|
TURN_START: "turn:start",
|
|
794
794
|
/** Turn ended (always fires, even on error) — read-only, fire-and-forget. */
|
|
795
795
|
TURN_END: "turn:end",
|
|
796
|
+
/** After a turn completes — full assembled agent text, read-only, fire-and-forget. */
|
|
797
|
+
AGENT_AFTER_TURN: "agent:afterTurn",
|
|
796
798
|
// --- Session lifecycle ---
|
|
797
799
|
/** Before a new session is created — modifiable, can block. */
|
|
798
800
|
SESSION_BEFORE_CREATE: "session:beforeCreate",
|
|
@@ -850,6 +852,8 @@ var init_events = __esm({
|
|
|
850
852
|
MESSAGE_QUEUED: "message:queued",
|
|
851
853
|
/** Fired when a queued message starts processing. */
|
|
852
854
|
MESSAGE_PROCESSING: "message:processing",
|
|
855
|
+
/** Fired when a queued message is rejected (e.g. blocked by middleware). */
|
|
856
|
+
MESSAGE_FAILED: "message:failed",
|
|
853
857
|
// --- System lifecycle ---
|
|
854
858
|
/** Fired after kernel (core + plugin infrastructure) has booted. */
|
|
855
859
|
KERNEL_BOOTED: "kernel:booted",
|
|
@@ -870,7 +874,22 @@ var init_events = __esm({
|
|
|
870
874
|
PLUGIN_UNLOADED: "plugin:unloaded",
|
|
871
875
|
// --- Usage ---
|
|
872
876
|
/** Fired when a token usage record is captured (consumed by usage plugin). */
|
|
873
|
-
USAGE_RECORDED: "usage:recorded"
|
|
877
|
+
USAGE_RECORDED: "usage:recorded",
|
|
878
|
+
// --- Identity lifecycle ---
|
|
879
|
+
/** Fired when a new user+identity record is created. */
|
|
880
|
+
IDENTITY_CREATED: "identity:created",
|
|
881
|
+
/** Fired when user profile fields change. */
|
|
882
|
+
IDENTITY_UPDATED: "identity:updated",
|
|
883
|
+
/** Fired when two identities are linked (same person). */
|
|
884
|
+
IDENTITY_LINKED: "identity:linked",
|
|
885
|
+
/** Fired when an identity is unlinked into a new user. */
|
|
886
|
+
IDENTITY_UNLINKED: "identity:unlinked",
|
|
887
|
+
/** Fired when two user records are merged during a link operation. */
|
|
888
|
+
IDENTITY_USER_MERGED: "identity:userMerged",
|
|
889
|
+
/** Fired when a user's role changes. */
|
|
890
|
+
IDENTITY_ROLE_CHANGED: "identity:roleChanged",
|
|
891
|
+
/** Fired when a user is seen (throttled). */
|
|
892
|
+
IDENTITY_SEEN: "identity:seen"
|
|
874
893
|
};
|
|
875
894
|
SessionEv = {
|
|
876
895
|
/** Agent produced an event (text, tool_call, etc.) during a turn. */
|
|
@@ -2829,14 +2848,20 @@ var init_api_client = __esm({
|
|
|
2829
2848
|
});
|
|
2830
2849
|
|
|
2831
2850
|
// src/plugins/notifications/notification.ts
|
|
2832
|
-
var
|
|
2851
|
+
var NotificationService;
|
|
2833
2852
|
var init_notification = __esm({
|
|
2834
2853
|
"src/plugins/notifications/notification.ts"() {
|
|
2835
2854
|
"use strict";
|
|
2836
|
-
|
|
2855
|
+
NotificationService = class {
|
|
2837
2856
|
constructor(adapters) {
|
|
2838
2857
|
this.adapters = adapters;
|
|
2839
2858
|
}
|
|
2859
|
+
identityResolver;
|
|
2860
|
+
/** Inject identity resolver for user-targeted notifications. */
|
|
2861
|
+
setIdentityResolver(resolver) {
|
|
2862
|
+
this.identityResolver = resolver;
|
|
2863
|
+
}
|
|
2864
|
+
// --- Legacy API (backward compat with NotificationManager) ---
|
|
2840
2865
|
/**
|
|
2841
2866
|
* Send a notification to a specific channel adapter.
|
|
2842
2867
|
*
|
|
@@ -2865,6 +2890,62 @@ var init_notification = __esm({
|
|
|
2865
2890
|
}
|
|
2866
2891
|
}
|
|
2867
2892
|
}
|
|
2893
|
+
// --- New user-targeted API ---
|
|
2894
|
+
/**
|
|
2895
|
+
* Send a notification to a user across all their linked platforms.
|
|
2896
|
+
* Fire-and-forget — never throws, swallows all errors.
|
|
2897
|
+
*/
|
|
2898
|
+
async notifyUser(target, message, options) {
|
|
2899
|
+
try {
|
|
2900
|
+
await this._resolveAndDeliver(target, message, options);
|
|
2901
|
+
} catch {
|
|
2902
|
+
}
|
|
2903
|
+
}
|
|
2904
|
+
async _resolveAndDeliver(target, message, options) {
|
|
2905
|
+
if ("channelId" in target && "platformId" in target) {
|
|
2906
|
+
const adapter = this.adapters.get(target.channelId);
|
|
2907
|
+
if (!adapter?.sendUserNotification) return;
|
|
2908
|
+
await adapter.sendUserNotification(target.platformId, message, {
|
|
2909
|
+
via: options?.via,
|
|
2910
|
+
topicId: options?.topicId,
|
|
2911
|
+
sessionId: options?.sessionId
|
|
2912
|
+
});
|
|
2913
|
+
return;
|
|
2914
|
+
}
|
|
2915
|
+
if (!this.identityResolver) return;
|
|
2916
|
+
let identities = [];
|
|
2917
|
+
if ("identityId" in target) {
|
|
2918
|
+
const identity = await this.identityResolver.getIdentity(target.identityId);
|
|
2919
|
+
if (!identity) return;
|
|
2920
|
+
const user = await this.identityResolver.getUser(identity.userId);
|
|
2921
|
+
if (!user) return;
|
|
2922
|
+
identities = await this.identityResolver.getIdentitiesFor(user.userId);
|
|
2923
|
+
} else if ("userId" in target) {
|
|
2924
|
+
identities = await this.identityResolver.getIdentitiesFor(target.userId);
|
|
2925
|
+
}
|
|
2926
|
+
if (options?.onlyPlatforms) {
|
|
2927
|
+
identities = identities.filter((i) => options.onlyPlatforms.includes(i.source));
|
|
2928
|
+
}
|
|
2929
|
+
if (options?.excludePlatforms) {
|
|
2930
|
+
identities = identities.filter((i) => !options.excludePlatforms.includes(i.source));
|
|
2931
|
+
}
|
|
2932
|
+
for (const identity of identities) {
|
|
2933
|
+
const adapter = this.adapters.get(identity.source);
|
|
2934
|
+
if (!adapter?.sendUserNotification) continue;
|
|
2935
|
+
try {
|
|
2936
|
+
await adapter.sendUserNotification(identity.platformId, message, {
|
|
2937
|
+
via: options?.via,
|
|
2938
|
+
topicId: options?.topicId,
|
|
2939
|
+
sessionId: options?.sessionId,
|
|
2940
|
+
platformMention: {
|
|
2941
|
+
platformUsername: identity.platformUsername,
|
|
2942
|
+
platformId: identity.platformId
|
|
2943
|
+
}
|
|
2944
|
+
});
|
|
2945
|
+
} catch {
|
|
2946
|
+
}
|
|
2947
|
+
}
|
|
2948
|
+
}
|
|
2868
2949
|
};
|
|
2869
2950
|
}
|
|
2870
2951
|
});
|
|
@@ -3356,9 +3437,16 @@ async function createApiServer(options) {
|
|
|
3356
3437
|
});
|
|
3357
3438
|
const authPreHandler = createAuthPreHandler(options.getSecret, options.getJwtSecret, options.tokenStore);
|
|
3358
3439
|
app.decorateRequest("auth", null, []);
|
|
3440
|
+
let booted = false;
|
|
3441
|
+
app.addHook("onReady", async () => {
|
|
3442
|
+
booted = true;
|
|
3443
|
+
});
|
|
3359
3444
|
return {
|
|
3360
3445
|
app,
|
|
3361
3446
|
registerPlugin(prefix, plugin, opts) {
|
|
3447
|
+
if (booted) {
|
|
3448
|
+
return;
|
|
3449
|
+
}
|
|
3362
3450
|
const wrappedPlugin = async (pluginApp, pluginOpts) => {
|
|
3363
3451
|
if (opts?.auth !== false) {
|
|
3364
3452
|
pluginApp.addHook("onRequest", authPreHandler);
|
|
@@ -3452,7 +3540,8 @@ var init_sse_manager = __esm({
|
|
|
3452
3540
|
BusEvent.PERMISSION_REQUEST,
|
|
3453
3541
|
BusEvent.PERMISSION_RESOLVED,
|
|
3454
3542
|
BusEvent.MESSAGE_QUEUED,
|
|
3455
|
-
BusEvent.MESSAGE_PROCESSING
|
|
3543
|
+
BusEvent.MESSAGE_PROCESSING,
|
|
3544
|
+
BusEvent.MESSAGE_FAILED
|
|
3456
3545
|
];
|
|
3457
3546
|
for (const eventName of events) {
|
|
3458
3547
|
const handler = (data) => {
|
|
@@ -3534,7 +3623,8 @@ data: ${JSON.stringify(data)}
|
|
|
3534
3623
|
BusEvent.PERMISSION_RESOLVED,
|
|
3535
3624
|
BusEvent.SESSION_UPDATED,
|
|
3536
3625
|
BusEvent.MESSAGE_QUEUED,
|
|
3537
|
-
BusEvent.MESSAGE_PROCESSING
|
|
3626
|
+
BusEvent.MESSAGE_PROCESSING,
|
|
3627
|
+
BusEvent.MESSAGE_FAILED
|
|
3538
3628
|
];
|
|
3539
3629
|
for (const res of this.sseConnections) {
|
|
3540
3630
|
const filter = res.sessionFilter;
|
|
@@ -10024,7 +10114,11 @@ var init_adapter = __esm({
|
|
|
10024
10114
|
}
|
|
10025
10115
|
return prev(method, payload, signal);
|
|
10026
10116
|
});
|
|
10027
|
-
|
|
10117
|
+
const onCommandsReady = ({ commands }) => {
|
|
10118
|
+
this.core.eventBus.off(BusEvent.SYSTEM_COMMANDS_READY, onCommandsReady);
|
|
10119
|
+
this.syncCommandsWithRetry(commands);
|
|
10120
|
+
};
|
|
10121
|
+
this.core.eventBus.on(BusEvent.SYSTEM_COMMANDS_READY, onCommandsReady);
|
|
10028
10122
|
this.bot.use((ctx, next) => {
|
|
10029
10123
|
const chatId = ctx.chat?.id ?? ctx.callbackQuery?.message?.chat?.id;
|
|
10030
10124
|
if (chatId !== this.telegramConfig.chatId) return;
|
|
@@ -10148,10 +10242,19 @@ var init_adapter = __esm({
|
|
|
10148
10242
|
});
|
|
10149
10243
|
} catch {
|
|
10150
10244
|
}
|
|
10151
|
-
} else if (response.type === "text" || response.type === "error") {
|
|
10152
|
-
|
|
10245
|
+
} else if (response.type === "text" || response.type === "error" || response.type === "adaptive") {
|
|
10246
|
+
let text3;
|
|
10247
|
+
let parseMode;
|
|
10248
|
+
if (response.type === "adaptive") {
|
|
10249
|
+
const variant = response.variants?.["telegram"];
|
|
10250
|
+
text3 = variant?.text ?? response.fallback;
|
|
10251
|
+
parseMode = variant?.parse_mode;
|
|
10252
|
+
} else {
|
|
10253
|
+
text3 = response.type === "text" ? response.text : `\u274C ${response.message}`;
|
|
10254
|
+
parseMode = "Markdown";
|
|
10255
|
+
}
|
|
10153
10256
|
try {
|
|
10154
|
-
await ctx.editMessageText(text3, { parse_mode:
|
|
10257
|
+
await ctx.editMessageText(text3, { ...parseMode && { parse_mode: parseMode } });
|
|
10155
10258
|
} catch {
|
|
10156
10259
|
}
|
|
10157
10260
|
}
|
|
@@ -10241,12 +10344,16 @@ ${p}` : p;
|
|
|
10241
10344
|
throw new Error("unreachable");
|
|
10242
10345
|
}
|
|
10243
10346
|
/**
|
|
10244
|
-
*
|
|
10245
|
-
*
|
|
10347
|
+
* Sync Telegram autocomplete commands after all plugins are ready.
|
|
10348
|
+
* Merges STATIC_COMMANDS (hardcoded system commands) with plugin commands
|
|
10349
|
+
* from the registry, deduplicating by command name. Non-critical.
|
|
10246
10350
|
*/
|
|
10247
|
-
|
|
10351
|
+
syncCommandsWithRetry(registryCommands) {
|
|
10352
|
+
const staticNames = new Set(STATIC_COMMANDS.map((c2) => c2.command));
|
|
10353
|
+
const pluginCommands = registryCommands.filter((c2) => c2.category === "plugin" && !staticNames.has(c2.name) && /^[a-z0-9_]+$/.test(c2.name)).map((c2) => ({ command: c2.name, description: c2.description.slice(0, 256) }));
|
|
10354
|
+
const allCommands = [...STATIC_COMMANDS, ...pluginCommands].slice(0, 100);
|
|
10248
10355
|
this.retryWithBackoff(
|
|
10249
|
-
() => this.bot.api.setMyCommands(
|
|
10356
|
+
() => this.bot.api.setMyCommands(allCommands, {
|
|
10250
10357
|
scope: { type: "chat", chat_id: this.telegramConfig.chatId }
|
|
10251
10358
|
}),
|
|
10252
10359
|
"setMyCommands"
|
|
@@ -10433,6 +10540,15 @@ OpenACP will automatically retry until this is resolved.`;
|
|
|
10433
10540
|
message_thread_id: topicId
|
|
10434
10541
|
});
|
|
10435
10542
|
break;
|
|
10543
|
+
case "adaptive": {
|
|
10544
|
+
const variant = response.variants?.["telegram"];
|
|
10545
|
+
const text3 = variant?.text ?? response.fallback;
|
|
10546
|
+
await this.bot.api.sendMessage(chatId, text3, {
|
|
10547
|
+
message_thread_id: topicId,
|
|
10548
|
+
...variant?.parse_mode && { parse_mode: variant.parse_mode }
|
|
10549
|
+
});
|
|
10550
|
+
break;
|
|
10551
|
+
}
|
|
10436
10552
|
case "error":
|
|
10437
10553
|
await this.bot.api.sendMessage(
|
|
10438
10554
|
chatId,
|
|
@@ -10541,12 +10657,25 @@ ${lines.join("\n")}`;
|
|
|
10541
10657
|
}
|
|
10542
10658
|
ctx.replyWithChatAction("typing").catch(() => {
|
|
10543
10659
|
});
|
|
10544
|
-
|
|
10545
|
-
|
|
10546
|
-
|
|
10547
|
-
|
|
10548
|
-
|
|
10549
|
-
|
|
10660
|
+
const fromName = [ctx.from.first_name, ctx.from.last_name].filter(Boolean).join(" ") || void 0;
|
|
10661
|
+
this.core.handleMessage(
|
|
10662
|
+
{
|
|
10663
|
+
channelId: "telegram",
|
|
10664
|
+
threadId: String(threadId),
|
|
10665
|
+
userId: String(ctx.from.id),
|
|
10666
|
+
text: forwardText
|
|
10667
|
+
},
|
|
10668
|
+
// Inject structured channel user info into TurnMeta so plugins can identify
|
|
10669
|
+
// the sender by name without adapter-specific fields on IncomingMessage.
|
|
10670
|
+
{
|
|
10671
|
+
channelUser: {
|
|
10672
|
+
channelId: "telegram",
|
|
10673
|
+
userId: String(ctx.from.id),
|
|
10674
|
+
displayName: fromName,
|
|
10675
|
+
username: ctx.from.username
|
|
10676
|
+
}
|
|
10677
|
+
}
|
|
10678
|
+
).catch((err) => log36.error({ err }, "handleMessage error"));
|
|
10550
10679
|
});
|
|
10551
10680
|
this.bot.on("message:photo", async (ctx) => {
|
|
10552
10681
|
const threadId = ctx.message.message_thread_id;
|
|
@@ -11259,6 +11388,8 @@ var ChannelAdapter = class {
|
|
|
11259
11388
|
}
|
|
11260
11389
|
async archiveSessionTopic(_sessionId) {
|
|
11261
11390
|
}
|
|
11391
|
+
async sendUserNotification(_platformId, _message, _options) {
|
|
11392
|
+
}
|
|
11262
11393
|
};
|
|
11263
11394
|
|
|
11264
11395
|
// src/core/utils/streams.ts
|
|
@@ -12714,16 +12845,16 @@ var PromptQueue = class {
|
|
|
12714
12845
|
* immediately. Otherwise, it's buffered and the returned promise resolves
|
|
12715
12846
|
* only after the prompt finishes processing.
|
|
12716
12847
|
*/
|
|
12717
|
-
async enqueue(text3, attachments, routing, turnId) {
|
|
12848
|
+
async enqueue(text3, userPrompt, attachments, routing, turnId, meta) {
|
|
12718
12849
|
if (this.processing) {
|
|
12719
12850
|
return new Promise((resolve7) => {
|
|
12720
|
-
this.queue.push({ text: text3, attachments, routing, turnId, resolve: resolve7 });
|
|
12851
|
+
this.queue.push({ text: text3, userPrompt, attachments, routing, turnId, meta, resolve: resolve7 });
|
|
12721
12852
|
});
|
|
12722
12853
|
}
|
|
12723
|
-
await this.process(text3, attachments, routing, turnId);
|
|
12854
|
+
await this.process(text3, userPrompt, attachments, routing, turnId, meta);
|
|
12724
12855
|
}
|
|
12725
12856
|
/** Run a single prompt through the processor, then drain the next queued item. */
|
|
12726
|
-
async process(text3, attachments, routing, turnId) {
|
|
12857
|
+
async process(text3, userPrompt, attachments, routing, turnId, meta) {
|
|
12727
12858
|
this.processing = true;
|
|
12728
12859
|
this.abortController = new AbortController();
|
|
12729
12860
|
const { signal } = this.abortController;
|
|
@@ -12733,7 +12864,7 @@ var PromptQueue = class {
|
|
|
12733
12864
|
});
|
|
12734
12865
|
try {
|
|
12735
12866
|
await Promise.race([
|
|
12736
|
-
this.processor(text3, attachments, routing, turnId),
|
|
12867
|
+
this.processor(text3, userPrompt, attachments, routing, turnId, meta),
|
|
12737
12868
|
new Promise((_, reject) => {
|
|
12738
12869
|
signal.addEventListener("abort", () => reject(new Error("Prompt aborted")), { once: true });
|
|
12739
12870
|
})
|
|
@@ -12754,7 +12885,7 @@ var PromptQueue = class {
|
|
|
12754
12885
|
drainNext() {
|
|
12755
12886
|
const next = this.queue.shift();
|
|
12756
12887
|
if (next) {
|
|
12757
|
-
this.process(next.text, next.attachments, next.routing, next.turnId).then(next.resolve);
|
|
12888
|
+
this.process(next.text, next.userPrompt, next.attachments, next.routing, next.turnId, next.meta).then(next.resolve);
|
|
12758
12889
|
}
|
|
12759
12890
|
}
|
|
12760
12891
|
/**
|
|
@@ -12776,6 +12907,13 @@ var PromptQueue = class {
|
|
|
12776
12907
|
get isProcessing() {
|
|
12777
12908
|
return this.processing;
|
|
12778
12909
|
}
|
|
12910
|
+
/** Snapshot of queued (not yet processing) items — used for queue inspection by callers. */
|
|
12911
|
+
get pendingItems() {
|
|
12912
|
+
return this.queue.map((item) => ({
|
|
12913
|
+
userPrompt: item.userPrompt,
|
|
12914
|
+
turnId: item.turnId
|
|
12915
|
+
}));
|
|
12916
|
+
}
|
|
12779
12917
|
};
|
|
12780
12918
|
|
|
12781
12919
|
// src/core/sessions/permission-gate.ts
|
|
@@ -12857,17 +12995,31 @@ import * as fs8 from "fs";
|
|
|
12857
12995
|
|
|
12858
12996
|
// src/core/sessions/turn-context.ts
|
|
12859
12997
|
import { nanoid } from "nanoid";
|
|
12860
|
-
function
|
|
12998
|
+
function extractSender(meta) {
|
|
12999
|
+
const identity = meta?.identity;
|
|
13000
|
+
if (!identity || !identity.userId || !identity.identityId) return null;
|
|
12861
13001
|
return {
|
|
12862
|
-
|
|
12863
|
-
|
|
12864
|
-
|
|
13002
|
+
userId: identity.userId,
|
|
13003
|
+
identityId: identity.identityId,
|
|
13004
|
+
displayName: identity.displayName,
|
|
13005
|
+
username: identity.username
|
|
12865
13006
|
};
|
|
12866
13007
|
}
|
|
12867
13008
|
function getEffectiveTarget(ctx) {
|
|
12868
13009
|
if (ctx.responseAdapterId === null) return null;
|
|
12869
13010
|
return ctx.responseAdapterId ?? ctx.sourceAdapterId;
|
|
12870
13011
|
}
|
|
13012
|
+
function createTurnContext(sourceAdapterId, responseAdapterId, turnId, userPrompt, finalPrompt, attachments, meta) {
|
|
13013
|
+
return {
|
|
13014
|
+
turnId: turnId ?? nanoid(8),
|
|
13015
|
+
sourceAdapterId,
|
|
13016
|
+
responseAdapterId,
|
|
13017
|
+
userPrompt,
|
|
13018
|
+
finalPrompt,
|
|
13019
|
+
attachments,
|
|
13020
|
+
meta
|
|
13021
|
+
};
|
|
13022
|
+
}
|
|
12871
13023
|
var SYSTEM_EVENT_TYPES = /* @__PURE__ */ new Set([
|
|
12872
13024
|
"session_end",
|
|
12873
13025
|
"system_message",
|
|
@@ -12962,7 +13114,7 @@ var Session = class extends TypedEmitter {
|
|
|
12962
13114
|
this.log = createSessionLogger(this.id, moduleLog);
|
|
12963
13115
|
this.log.info({ agentName: this.agentName }, "Session created");
|
|
12964
13116
|
this.queue = new PromptQueue(
|
|
12965
|
-
(text3, attachments, routing, turnId) => this.processPrompt(text3, attachments, routing, turnId),
|
|
13117
|
+
(text3, userPrompt, attachments, routing, turnId, meta) => this.processPrompt(text3, userPrompt, attachments, routing, turnId, meta),
|
|
12966
13118
|
(err) => {
|
|
12967
13119
|
this.log.error({ err }, "Prompt execution failed");
|
|
12968
13120
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -13042,6 +13194,10 @@ var Session = class extends TypedEmitter {
|
|
|
13042
13194
|
get promptRunning() {
|
|
13043
13195
|
return this.queue.isProcessing;
|
|
13044
13196
|
}
|
|
13197
|
+
/** Snapshot of queued (not yet processing) items — for inspection by API consumers. */
|
|
13198
|
+
get queueItems() {
|
|
13199
|
+
return this.queue.pendingItems;
|
|
13200
|
+
}
|
|
13045
13201
|
// --- Context Injection ---
|
|
13046
13202
|
/** Store context markdown to be prepended to the next prompt (used for session resume with history). */
|
|
13047
13203
|
setContext(markdown) {
|
|
@@ -13061,24 +13217,31 @@ var Session = class extends TypedEmitter {
|
|
|
13061
13217
|
* then adds it to the PromptQueue. Returns a turnId that callers can use to correlate
|
|
13062
13218
|
* queued/processing events before the prompt actually runs.
|
|
13063
13219
|
*/
|
|
13064
|
-
async enqueuePrompt(text3, attachments, routing, externalTurnId) {
|
|
13220
|
+
async enqueuePrompt(text3, attachments, routing, externalTurnId, meta) {
|
|
13065
13221
|
const turnId = externalTurnId ?? nanoid2(8);
|
|
13222
|
+
const turnMeta = meta ?? { turnId };
|
|
13223
|
+
const userPrompt = text3;
|
|
13066
13224
|
if (this.middlewareChain) {
|
|
13067
|
-
const payload = { text: text3, attachments, sessionId: this.id, sourceAdapterId: routing?.sourceAdapterId };
|
|
13225
|
+
const payload = { text: text3, attachments, sessionId: this.id, sourceAdapterId: routing?.sourceAdapterId, meta: turnMeta };
|
|
13068
13226
|
const result = await this.middlewareChain.execute(Hook.AGENT_BEFORE_PROMPT, payload, async (p) => p);
|
|
13069
|
-
if (!result)
|
|
13227
|
+
if (!result) throw new Error("PROMPT_BLOCKED");
|
|
13070
13228
|
text3 = result.text;
|
|
13071
13229
|
attachments = result.attachments;
|
|
13072
13230
|
}
|
|
13073
|
-
await this.queue.enqueue(text3, attachments, routing, turnId);
|
|
13231
|
+
await this.queue.enqueue(text3, userPrompt, attachments, routing, turnId, turnMeta);
|
|
13074
13232
|
return turnId;
|
|
13075
13233
|
}
|
|
13076
|
-
async processPrompt(text3, attachments, routing, turnId) {
|
|
13234
|
+
async processPrompt(text3, userPrompt, attachments, routing, turnId, meta) {
|
|
13077
13235
|
if (this._status === "finished") return;
|
|
13078
13236
|
this.activeTurnContext = createTurnContext(
|
|
13079
13237
|
routing?.sourceAdapterId ?? this.channelId,
|
|
13080
13238
|
routing?.responseAdapterId,
|
|
13081
|
-
turnId
|
|
13239
|
+
turnId,
|
|
13240
|
+
userPrompt,
|
|
13241
|
+
text3,
|
|
13242
|
+
// finalPrompt (after middleware transformations)
|
|
13243
|
+
attachments,
|
|
13244
|
+
meta
|
|
13082
13245
|
);
|
|
13083
13246
|
this.emit(SessionEv.TURN_STARTED, this.activeTurnContext);
|
|
13084
13247
|
this.promptCount++;
|
|
@@ -13113,6 +13276,13 @@ ${text3}`;
|
|
|
13113
13276
|
if (accumulatorListener) {
|
|
13114
13277
|
this.on(SessionEv.AGENT_EVENT, accumulatorListener);
|
|
13115
13278
|
}
|
|
13279
|
+
const turnTextBuffer = [];
|
|
13280
|
+
const turnTextListener = (event) => {
|
|
13281
|
+
if (event.type === "text" && typeof event.content === "string") {
|
|
13282
|
+
turnTextBuffer.push(event.content);
|
|
13283
|
+
}
|
|
13284
|
+
};
|
|
13285
|
+
this.on(SessionEv.AGENT_EVENT, turnTextListener);
|
|
13116
13286
|
const mw = this.middlewareChain;
|
|
13117
13287
|
const afterEventListener = mw ? (event) => {
|
|
13118
13288
|
mw.execute(Hook.AGENT_AFTER_EVENT, { sessionId: this.id, event, outgoingMessage: { type: "text", text: "" } }, async (e) => e).catch(() => {
|
|
@@ -13122,7 +13292,16 @@ ${text3}`;
|
|
|
13122
13292
|
this.agentInstance.on(SessionEv.AGENT_EVENT, afterEventListener);
|
|
13123
13293
|
}
|
|
13124
13294
|
if (this.middlewareChain) {
|
|
13125
|
-
this.middlewareChain.execute(Hook.TURN_START, {
|
|
13295
|
+
this.middlewareChain.execute(Hook.TURN_START, {
|
|
13296
|
+
sessionId: this.id,
|
|
13297
|
+
promptText: processed.text,
|
|
13298
|
+
promptNumber: this.promptCount,
|
|
13299
|
+
turnId: this.activeTurnContext?.turnId ?? turnId ?? "",
|
|
13300
|
+
meta,
|
|
13301
|
+
userPrompt: this.activeTurnContext?.userPrompt,
|
|
13302
|
+
sourceAdapterId: this.activeTurnContext?.sourceAdapterId,
|
|
13303
|
+
responseAdapterId: this.activeTurnContext?.responseAdapterId
|
|
13304
|
+
}, async (p) => p).catch(() => {
|
|
13126
13305
|
});
|
|
13127
13306
|
}
|
|
13128
13307
|
let stopReason = "end_turn";
|
|
@@ -13148,8 +13327,20 @@ ${text3}`;
|
|
|
13148
13327
|
if (afterEventListener) {
|
|
13149
13328
|
this.agentInstance.off(SessionEv.AGENT_EVENT, afterEventListener);
|
|
13150
13329
|
}
|
|
13330
|
+
this.off(SessionEv.AGENT_EVENT, turnTextListener);
|
|
13331
|
+
const finalTurnId = this.activeTurnContext?.turnId ?? turnId ?? "";
|
|
13151
13332
|
if (this.middlewareChain) {
|
|
13152
|
-
this.middlewareChain.execute(Hook.TURN_END, { sessionId: this.id, stopReason, durationMs: Date.now() - promptStart }, async (p) => p).catch(() => {
|
|
13333
|
+
this.middlewareChain.execute(Hook.TURN_END, { sessionId: this.id, stopReason, durationMs: Date.now() - promptStart, turnId: finalTurnId, meta }, async (p) => p).catch(() => {
|
|
13334
|
+
});
|
|
13335
|
+
}
|
|
13336
|
+
if (this.middlewareChain) {
|
|
13337
|
+
this.middlewareChain.execute(Hook.AGENT_AFTER_TURN, {
|
|
13338
|
+
sessionId: this.id,
|
|
13339
|
+
turnId: finalTurnId,
|
|
13340
|
+
fullText: turnTextBuffer.join(""),
|
|
13341
|
+
stopReason,
|
|
13342
|
+
meta
|
|
13343
|
+
}, async (p) => p).catch(() => {
|
|
13153
13344
|
});
|
|
13154
13345
|
}
|
|
13155
13346
|
this.activeTurnContext = null;
|
|
@@ -14279,7 +14470,7 @@ var SessionBridge = class {
|
|
|
14279
14470
|
if (this.shouldForward(event)) {
|
|
14280
14471
|
this.dispatchAgentEvent(event);
|
|
14281
14472
|
} else {
|
|
14282
|
-
this.deps.eventBus?.emit(BusEvent.AGENT_EVENT, { sessionId: this.session.id, event });
|
|
14473
|
+
this.deps.eventBus?.emit(BusEvent.AGENT_EVENT, { sessionId: this.session.id, turnId: "", event });
|
|
14283
14474
|
}
|
|
14284
14475
|
});
|
|
14285
14476
|
if (!this.session.agentInstance.onPermissionRequest || this.session.agentInstance.onPermissionRequest.__bridgeId === void 0) {
|
|
@@ -14332,14 +14523,16 @@ var SessionBridge = class {
|
|
|
14332
14523
|
this.deps.sessionManager.patchRecord(this.session.id, { currentPromptCount: count });
|
|
14333
14524
|
});
|
|
14334
14525
|
this.listen(this.session, SessionEv.TURN_STARTED, (ctx) => {
|
|
14335
|
-
|
|
14336
|
-
this.
|
|
14337
|
-
|
|
14338
|
-
|
|
14339
|
-
|
|
14340
|
-
|
|
14341
|
-
|
|
14342
|
-
|
|
14526
|
+
this.deps.eventBus?.emit(BusEvent.MESSAGE_PROCESSING, {
|
|
14527
|
+
sessionId: this.session.id,
|
|
14528
|
+
turnId: ctx.turnId,
|
|
14529
|
+
sourceAdapterId: ctx.sourceAdapterId,
|
|
14530
|
+
userPrompt: ctx.userPrompt,
|
|
14531
|
+
finalPrompt: ctx.finalPrompt,
|
|
14532
|
+
attachments: ctx.attachments,
|
|
14533
|
+
sender: extractSender(ctx.meta),
|
|
14534
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
14535
|
+
});
|
|
14343
14536
|
});
|
|
14344
14537
|
if (this.session.latestCommands !== null) {
|
|
14345
14538
|
this.session.emit(SessionEv.AGENT_EVENT, { type: "commands_update", commands: this.session.latestCommands });
|
|
@@ -14505,6 +14698,7 @@ var SessionBridge = class {
|
|
|
14505
14698
|
}
|
|
14506
14699
|
this.deps.eventBus?.emit(BusEvent.AGENT_EVENT, {
|
|
14507
14700
|
sessionId: this.session.id,
|
|
14701
|
+
turnId: this.session.activeTurnContext?.turnId ?? "",
|
|
14508
14702
|
event
|
|
14509
14703
|
});
|
|
14510
14704
|
return outgoing;
|
|
@@ -14631,8 +14825,7 @@ var SessionFactory = class {
|
|
|
14631
14825
|
const payload = {
|
|
14632
14826
|
agentName: params.agentName,
|
|
14633
14827
|
workingDir: params.workingDirectory,
|
|
14634
|
-
userId: "",
|
|
14635
|
-
// userId is not part of SessionCreateParams — resolved upstream
|
|
14828
|
+
userId: params.userId ?? "",
|
|
14636
14829
|
channelId: params.channelId,
|
|
14637
14830
|
threadId: ""
|
|
14638
14831
|
// threadId is assigned after session creation
|
|
@@ -14706,6 +14899,7 @@ var SessionFactory = class {
|
|
|
14706
14899
|
const failedSessionId = createParams.existingSessionId ?? `failed-${Date.now()}`;
|
|
14707
14900
|
this.eventBus.emit(BusEvent.AGENT_EVENT, {
|
|
14708
14901
|
sessionId: failedSessionId,
|
|
14902
|
+
turnId: "",
|
|
14709
14903
|
event: guidance
|
|
14710
14904
|
});
|
|
14711
14905
|
throw err;
|
|
@@ -14734,7 +14928,8 @@ var SessionFactory = class {
|
|
|
14734
14928
|
this.eventBus.emit(BusEvent.SESSION_CREATED, {
|
|
14735
14929
|
sessionId: session.id,
|
|
14736
14930
|
agent: session.agentName,
|
|
14737
|
-
status: session.status
|
|
14931
|
+
status: session.status,
|
|
14932
|
+
userId: createParams.userId
|
|
14738
14933
|
});
|
|
14739
14934
|
}
|
|
14740
14935
|
return session;
|
|
@@ -15254,7 +15449,7 @@ var AgentSwitchHandler = class {
|
|
|
15254
15449
|
message: `Switching from ${fromAgent} to ${toAgent}...`
|
|
15255
15450
|
};
|
|
15256
15451
|
session.emit(SessionEv.AGENT_EVENT, startEvent);
|
|
15257
|
-
eventBus.emit(BusEvent.AGENT_EVENT, { sessionId, event: startEvent });
|
|
15452
|
+
eventBus.emit(BusEvent.AGENT_EVENT, { sessionId, turnId: "", event: startEvent });
|
|
15258
15453
|
eventBus.emit(BusEvent.SESSION_AGENT_SWITCH, {
|
|
15259
15454
|
sessionId,
|
|
15260
15455
|
fromAgent,
|
|
@@ -15317,7 +15512,7 @@ var AgentSwitchHandler = class {
|
|
|
15317
15512
|
message: resumed ? `Switched to ${toAgent} (resumed previous session).` : `Switched to ${toAgent} (new session).`
|
|
15318
15513
|
};
|
|
15319
15514
|
session.emit(SessionEv.AGENT_EVENT, successEvent);
|
|
15320
|
-
eventBus.emit(BusEvent.AGENT_EVENT, { sessionId, event: successEvent });
|
|
15515
|
+
eventBus.emit(BusEvent.AGENT_EVENT, { sessionId, turnId: "", event: successEvent });
|
|
15321
15516
|
eventBus.emit(BusEvent.SESSION_AGENT_SWITCH, {
|
|
15322
15517
|
sessionId,
|
|
15323
15518
|
fromAgent,
|
|
@@ -15332,7 +15527,7 @@ var AgentSwitchHandler = class {
|
|
|
15332
15527
|
message: `Failed to switch to ${toAgent}: ${errorMessage}`
|
|
15333
15528
|
};
|
|
15334
15529
|
session.emit(SessionEv.AGENT_EVENT, failedEvent);
|
|
15335
|
-
eventBus.emit(BusEvent.AGENT_EVENT, { sessionId, event: failedEvent });
|
|
15530
|
+
eventBus.emit(BusEvent.AGENT_EVENT, { sessionId, turnId: "", event: failedEvent });
|
|
15336
15531
|
eventBus.emit(BusEvent.SESSION_AGENT_SWITCH, {
|
|
15337
15532
|
sessionId,
|
|
15338
15533
|
fromAgent,
|
|
@@ -16102,11 +16297,55 @@ var PluginStorageImpl = class {
|
|
|
16102
16297
|
async list() {
|
|
16103
16298
|
return Object.keys(this.readKv());
|
|
16104
16299
|
}
|
|
16300
|
+
async keys(prefix) {
|
|
16301
|
+
const all = Object.keys(this.readKv());
|
|
16302
|
+
return prefix ? all.filter((k) => k.startsWith(prefix)) : all;
|
|
16303
|
+
}
|
|
16304
|
+
async clear() {
|
|
16305
|
+
this.writeChain = this.writeChain.then(() => {
|
|
16306
|
+
this.writeKv({});
|
|
16307
|
+
});
|
|
16308
|
+
return this.writeChain;
|
|
16309
|
+
}
|
|
16105
16310
|
/** Returns the plugin's data directory, creating it lazily on first access. */
|
|
16106
16311
|
getDataDir() {
|
|
16107
16312
|
fs14.mkdirSync(this.dataDir, { recursive: true });
|
|
16108
16313
|
return this.dataDir;
|
|
16109
16314
|
}
|
|
16315
|
+
/**
|
|
16316
|
+
* Creates a namespaced storage instance scoped to a session.
|
|
16317
|
+
* Keys are prefixed with `session:{sessionId}:` to isolate session data
|
|
16318
|
+
* from global plugin storage in the same backing file.
|
|
16319
|
+
*/
|
|
16320
|
+
forSession(sessionId) {
|
|
16321
|
+
const prefix = `session:${sessionId}:`;
|
|
16322
|
+
return {
|
|
16323
|
+
get: (key) => this.get(`${prefix}${key}`),
|
|
16324
|
+
set: (key, value) => this.set(`${prefix}${key}`, value),
|
|
16325
|
+
delete: (key) => this.delete(`${prefix}${key}`),
|
|
16326
|
+
list: async () => {
|
|
16327
|
+
const all = await this.keys(prefix);
|
|
16328
|
+
return all.map((k) => k.slice(prefix.length));
|
|
16329
|
+
},
|
|
16330
|
+
keys: async (p) => {
|
|
16331
|
+
const full = p ? `${prefix}${p}` : prefix;
|
|
16332
|
+
const all = await this.keys(full);
|
|
16333
|
+
return all.map((k) => k.slice(prefix.length));
|
|
16334
|
+
},
|
|
16335
|
+
clear: async () => {
|
|
16336
|
+
this.writeChain = this.writeChain.then(() => {
|
|
16337
|
+
const data = this.readKv();
|
|
16338
|
+
for (const key of Object.keys(data)) {
|
|
16339
|
+
if (key.startsWith(prefix)) delete data[key];
|
|
16340
|
+
}
|
|
16341
|
+
this.writeKv(data);
|
|
16342
|
+
});
|
|
16343
|
+
return this.writeChain;
|
|
16344
|
+
},
|
|
16345
|
+
getDataDir: () => this.getDataDir(),
|
|
16346
|
+
forSession: (nestedId) => this.forSession(`${sessionId}:${nestedId}`)
|
|
16347
|
+
};
|
|
16348
|
+
}
|
|
16110
16349
|
};
|
|
16111
16350
|
|
|
16112
16351
|
// src/core/plugin/plugin-context.ts
|
|
@@ -16170,9 +16409,52 @@ function createPluginContext(opts) {
|
|
|
16170
16409
|
requirePermission(permissions, "storage:read", "storage.list");
|
|
16171
16410
|
return storageImpl.list();
|
|
16172
16411
|
},
|
|
16412
|
+
async keys(prefix) {
|
|
16413
|
+
requirePermission(permissions, "storage:read", "storage.keys");
|
|
16414
|
+
return storageImpl.keys(prefix);
|
|
16415
|
+
},
|
|
16416
|
+
async clear() {
|
|
16417
|
+
requirePermission(permissions, "storage:write", "storage.clear");
|
|
16418
|
+
return storageImpl.clear();
|
|
16419
|
+
},
|
|
16173
16420
|
getDataDir() {
|
|
16174
16421
|
requirePermission(permissions, "storage:read", "storage.getDataDir");
|
|
16175
16422
|
return storageImpl.getDataDir();
|
|
16423
|
+
},
|
|
16424
|
+
forSession(sessionId) {
|
|
16425
|
+
requirePermission(permissions, "storage:read", "storage.forSession");
|
|
16426
|
+
const scoped = storageImpl.forSession(sessionId);
|
|
16427
|
+
return {
|
|
16428
|
+
get: (key) => {
|
|
16429
|
+
requirePermission(permissions, "storage:read", "storage.get");
|
|
16430
|
+
return scoped.get(key);
|
|
16431
|
+
},
|
|
16432
|
+
set: (key, value) => {
|
|
16433
|
+
requirePermission(permissions, "storage:write", "storage.set");
|
|
16434
|
+
return scoped.set(key, value);
|
|
16435
|
+
},
|
|
16436
|
+
delete: (key) => {
|
|
16437
|
+
requirePermission(permissions, "storage:write", "storage.delete");
|
|
16438
|
+
return scoped.delete(key);
|
|
16439
|
+
},
|
|
16440
|
+
list: () => {
|
|
16441
|
+
requirePermission(permissions, "storage:read", "storage.list");
|
|
16442
|
+
return scoped.list();
|
|
16443
|
+
},
|
|
16444
|
+
keys: (prefix) => {
|
|
16445
|
+
requirePermission(permissions, "storage:read", "storage.keys");
|
|
16446
|
+
return scoped.keys(prefix);
|
|
16447
|
+
},
|
|
16448
|
+
clear: () => {
|
|
16449
|
+
requirePermission(permissions, "storage:write", "storage.clear");
|
|
16450
|
+
return scoped.clear();
|
|
16451
|
+
},
|
|
16452
|
+
getDataDir: () => {
|
|
16453
|
+
requirePermission(permissions, "storage:read", "storage.getDataDir");
|
|
16454
|
+
return scoped.getDataDir();
|
|
16455
|
+
},
|
|
16456
|
+
forSession: (nestedId) => storage.forSession(`${sessionId}:${nestedId}`)
|
|
16457
|
+
};
|
|
16176
16458
|
}
|
|
16177
16459
|
};
|
|
16178
16460
|
const ctx = {
|
|
@@ -16223,6 +16505,26 @@ function createPluginContext(opts) {
|
|
|
16223
16505
|
await router.send(_sessionId, _content);
|
|
16224
16506
|
}
|
|
16225
16507
|
},
|
|
16508
|
+
notify(target, message, options) {
|
|
16509
|
+
requirePermission(permissions, "notifications:send", "notify()");
|
|
16510
|
+
const svc = serviceRegistry.get("notifications");
|
|
16511
|
+
if (svc?.notifyUser) {
|
|
16512
|
+
svc.notifyUser(target, message, options).catch(() => {
|
|
16513
|
+
});
|
|
16514
|
+
}
|
|
16515
|
+
},
|
|
16516
|
+
defineHook(_name) {
|
|
16517
|
+
},
|
|
16518
|
+
async emitHook(name, payload) {
|
|
16519
|
+
const qualifiedName = `plugin:${pluginName}:${name}`;
|
|
16520
|
+
return middlewareChain.execute(qualifiedName, payload, (p) => p);
|
|
16521
|
+
},
|
|
16522
|
+
async getSessionInfo(sessionId) {
|
|
16523
|
+
requirePermission(permissions, "sessions:read", "getSessionInfo()");
|
|
16524
|
+
const sessionMgr = serviceRegistry.get("session-info");
|
|
16525
|
+
if (!sessionMgr) return void 0;
|
|
16526
|
+
return sessionMgr.getSessionInfo(sessionId);
|
|
16527
|
+
},
|
|
16226
16528
|
registerMenuItem(item) {
|
|
16227
16529
|
requirePermission(permissions, "commands:register", "registerMenuItem()");
|
|
16228
16530
|
const menuRegistry = serviceRegistry.get("menu-registry");
|
|
@@ -17272,7 +17574,7 @@ var OpenACPCore = class {
|
|
|
17272
17574
|
*
|
|
17273
17575
|
* If no session is found, the user is told to start one with /new.
|
|
17274
17576
|
*/
|
|
17275
|
-
async handleMessage(message) {
|
|
17577
|
+
async handleMessage(message, initialMeta) {
|
|
17276
17578
|
log16.debug(
|
|
17277
17579
|
{
|
|
17278
17580
|
channelId: message.channelId,
|
|
@@ -17281,10 +17583,12 @@ var OpenACPCore = class {
|
|
|
17281
17583
|
},
|
|
17282
17584
|
"Incoming message"
|
|
17283
17585
|
);
|
|
17586
|
+
const turnId = nanoid3(8);
|
|
17587
|
+
const meta = { turnId, ...initialMeta };
|
|
17284
17588
|
if (this.lifecycleManager?.middlewareChain) {
|
|
17285
17589
|
const result = await this.lifecycleManager.middlewareChain.execute(
|
|
17286
17590
|
Hook.MESSAGE_INCOMING,
|
|
17287
|
-
message,
|
|
17591
|
+
{ ...message, meta },
|
|
17288
17592
|
async (msg) => msg
|
|
17289
17593
|
);
|
|
17290
17594
|
if (!result) return;
|
|
@@ -17319,9 +17623,6 @@ var OpenACPCore = class {
|
|
|
17319
17623
|
}
|
|
17320
17624
|
return;
|
|
17321
17625
|
}
|
|
17322
|
-
this.sessionManager.patchRecord(session.id, {
|
|
17323
|
-
lastActiveAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
17324
|
-
});
|
|
17325
17626
|
let text3 = message.text;
|
|
17326
17627
|
if (this.assistantManager?.isAssistant(session.id)) {
|
|
17327
17628
|
const pending = this.assistantManager.consumePendingSystemPrompt(message.channelId);
|
|
@@ -17334,23 +17635,85 @@ User message:
|
|
|
17334
17635
|
${text3}`;
|
|
17335
17636
|
}
|
|
17336
17637
|
}
|
|
17337
|
-
const
|
|
17338
|
-
|
|
17339
|
-
|
|
17340
|
-
|
|
17341
|
-
|
|
17638
|
+
const enrichedMeta = message.meta ?? meta;
|
|
17639
|
+
await this._dispatchToSession(session, text3, message.attachments, {
|
|
17640
|
+
sourceAdapterId: message.routing?.sourceAdapterId ?? message.channelId,
|
|
17641
|
+
responseAdapterId: message.routing?.responseAdapterId
|
|
17642
|
+
}, turnId, enrichedMeta);
|
|
17643
|
+
}
|
|
17644
|
+
/**
|
|
17645
|
+
* Shared dispatch path for sending a prompt to a session.
|
|
17646
|
+
* Called by both handleMessage (Telegram) and handleMessageInSession (SSE/API)
|
|
17647
|
+
* after their respective middleware/enrichment steps.
|
|
17648
|
+
*/
|
|
17649
|
+
async _dispatchToSession(session, text3, attachments, routing, turnId, meta) {
|
|
17650
|
+
this.sessionManager.patchRecord(session.id, {
|
|
17651
|
+
lastActiveAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
17652
|
+
});
|
|
17653
|
+
this.eventBus.emit(BusEvent.MESSAGE_QUEUED, {
|
|
17654
|
+
sessionId: session.id,
|
|
17655
|
+
turnId,
|
|
17656
|
+
text: text3,
|
|
17657
|
+
sourceAdapterId: routing.sourceAdapterId,
|
|
17658
|
+
attachments,
|
|
17659
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
17660
|
+
queueDepth: session.queueDepth + 1,
|
|
17661
|
+
sender: extractSender(meta)
|
|
17662
|
+
});
|
|
17663
|
+
session.enqueuePrompt(text3, attachments, routing, turnId, meta).catch((err) => {
|
|
17664
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
17665
|
+
log16.warn({ err, sessionId: session.id, turnId, reason }, "enqueuePrompt failed \u2014 emitting message:failed");
|
|
17666
|
+
this.eventBus.emit(BusEvent.MESSAGE_FAILED, {
|
|
17342
17667
|
sessionId: session.id,
|
|
17343
17668
|
turnId,
|
|
17344
|
-
|
|
17345
|
-
sourceAdapterId,
|
|
17346
|
-
attachments: message.attachments,
|
|
17347
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
17348
|
-
queueDepth: session.queueDepth
|
|
17669
|
+
reason
|
|
17349
17670
|
});
|
|
17350
|
-
|
|
17351
|
-
|
|
17352
|
-
|
|
17671
|
+
});
|
|
17672
|
+
}
|
|
17673
|
+
/**
|
|
17674
|
+
* Send a message to a known session, running the full message:incoming → agent:beforePrompt
|
|
17675
|
+
* middleware chain (same as handleMessage) but without the threadId-based session lookup.
|
|
17676
|
+
*
|
|
17677
|
+
* Used by channels that already hold a direct session reference (e.g. SSE adapter, api-server),
|
|
17678
|
+
* where looking up by channelId+threadId is unreliable (API sessions may have no threadId).
|
|
17679
|
+
*
|
|
17680
|
+
* @param session The target session — caller is responsible for validating its status.
|
|
17681
|
+
* @param message Sender context and message content.
|
|
17682
|
+
* @param initialMeta Optional adapter-specific context to seed the TurnMeta bag
|
|
17683
|
+
* (e.g. channelUser with display name/username).
|
|
17684
|
+
* @param options Optional turnId override and response routing.
|
|
17685
|
+
*/
|
|
17686
|
+
async handleMessageInSession(session, message, initialMeta, options) {
|
|
17687
|
+
const turnId = options?.externalTurnId ?? nanoid3(8);
|
|
17688
|
+
const meta = { turnId, ...initialMeta };
|
|
17689
|
+
let text3 = message.text;
|
|
17690
|
+
let { attachments } = message;
|
|
17691
|
+
let enrichedMeta = meta;
|
|
17692
|
+
if (this.lifecycleManager?.middlewareChain) {
|
|
17693
|
+
const payload = {
|
|
17694
|
+
channelId: message.channelId,
|
|
17695
|
+
threadId: session.id,
|
|
17696
|
+
userId: message.userId,
|
|
17697
|
+
text: text3,
|
|
17698
|
+
attachments,
|
|
17699
|
+
meta
|
|
17700
|
+
};
|
|
17701
|
+
const result = await this.lifecycleManager.middlewareChain.execute(
|
|
17702
|
+
Hook.MESSAGE_INCOMING,
|
|
17703
|
+
payload,
|
|
17704
|
+
async (p) => p
|
|
17705
|
+
);
|
|
17706
|
+
if (!result) return { turnId, queueDepth: session.queueDepth };
|
|
17707
|
+
text3 = result.text;
|
|
17708
|
+
attachments = result.attachments;
|
|
17709
|
+
enrichedMeta = result.meta ?? meta;
|
|
17353
17710
|
}
|
|
17711
|
+
const routing = {
|
|
17712
|
+
sourceAdapterId: message.channelId,
|
|
17713
|
+
responseAdapterId: options?.responseAdapterId
|
|
17714
|
+
};
|
|
17715
|
+
await this._dispatchToSession(session, text3, attachments, routing, turnId, enrichedMeta);
|
|
17716
|
+
return { turnId, queueDepth: session.queueDepth };
|
|
17354
17717
|
}
|
|
17355
17718
|
// --- Unified Session Creation Pipeline ---
|
|
17356
17719
|
/**
|
|
@@ -17462,7 +17825,7 @@ ${text3}`;
|
|
|
17462
17825
|
} else if (processedEvent.type === "error") {
|
|
17463
17826
|
session.fail(processedEvent.message);
|
|
17464
17827
|
}
|
|
17465
|
-
this.eventBus.emit(BusEvent.AGENT_EVENT, { sessionId: session.id, event: processedEvent });
|
|
17828
|
+
this.eventBus.emit(BusEvent.AGENT_EVENT, { sessionId: session.id, turnId: session.activeTurnContext?.turnId ?? "", event: processedEvent });
|
|
17466
17829
|
});
|
|
17467
17830
|
session.on(SessionEv.STATUS_CHANGE, (_from, to) => {
|
|
17468
17831
|
this.sessionManager.patchRecord(session.id, {
|
|
@@ -17474,6 +17837,18 @@ ${text3}`;
|
|
|
17474
17837
|
session.on(SessionEv.PROMPT_COUNT_CHANGED, (count) => {
|
|
17475
17838
|
this.sessionManager.patchRecord(session.id, { currentPromptCount: count });
|
|
17476
17839
|
});
|
|
17840
|
+
session.on(SessionEv.TURN_STARTED, (ctx) => {
|
|
17841
|
+
this.eventBus.emit(BusEvent.MESSAGE_PROCESSING, {
|
|
17842
|
+
sessionId: session.id,
|
|
17843
|
+
turnId: ctx.turnId,
|
|
17844
|
+
sourceAdapterId: ctx.sourceAdapterId,
|
|
17845
|
+
userPrompt: ctx.userPrompt,
|
|
17846
|
+
finalPrompt: ctx.finalPrompt,
|
|
17847
|
+
attachments: ctx.attachments,
|
|
17848
|
+
sender: extractSender(ctx.meta),
|
|
17849
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
17850
|
+
});
|
|
17851
|
+
});
|
|
17477
17852
|
}
|
|
17478
17853
|
this.sessionFactory.wireSideEffects(session, {
|
|
17479
17854
|
eventBus: this.eventBus,
|
|
@@ -19792,7 +20167,7 @@ export {
|
|
|
19792
20167
|
MenuRegistry,
|
|
19793
20168
|
MessageTransformer,
|
|
19794
20169
|
MessagingAdapter,
|
|
19795
|
-
NotificationManager,
|
|
20170
|
+
NotificationService as NotificationManager,
|
|
19796
20171
|
OpenACPCore,
|
|
19797
20172
|
OutputModeResolver,
|
|
19798
20173
|
PRODUCT_GUIDE,
|