@rk0429/agentic-relay 21.2.3 → 22.0.0
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/application/chat/chat-daemon-service.d.ts +81 -0
- package/dist/application/chat/chat-daemon-service.js +382 -0
- package/dist/application/chat/chat-daemon-service.js.map +1 -0
- package/dist/application/chat/chat-inbound-handler.d.ts +35 -0
- package/dist/application/chat/chat-inbound-handler.js +175 -0
- package/dist/application/chat/chat-inbound-handler.js.map +1 -0
- package/dist/application/chat/chat-logging.d.ts +8 -0
- package/dist/application/chat/chat-logging.js +16 -0
- package/dist/application/chat/chat-logging.js.map +1 -0
- package/dist/application/chat/chat-outbound-handler.d.ts +16 -0
- package/dist/application/chat/chat-outbound-handler.js +190 -0
- package/dist/application/chat/chat-outbound-handler.js.map +1 -0
- package/dist/application/chat/chat-question-service.d.ts +37 -0
- package/dist/application/chat/chat-question-service.js +135 -0
- package/dist/application/chat/chat-question-service.js.map +1 -0
- package/dist/application/chat/chat-setup-service.d.ts +27 -0
- package/dist/application/chat/chat-setup-service.js +183 -0
- package/dist/application/chat/chat-setup-service.js.map +1 -0
- package/dist/application/chat/message-queue-manager.d.ts +13 -0
- package/dist/application/chat/message-queue-manager.js +34 -0
- package/dist/application/chat/message-queue-manager.js.map +1 -0
- package/dist/application/routine-status-query-service.d.ts +17 -0
- package/dist/application/routine-status-query-service.js +111 -0
- package/dist/application/routine-status-query-service.js.map +1 -1
- package/dist/bin/relay.d.ts +9 -2
- package/dist/bin/relay.js +296 -18
- package/dist/bin/relay.js.map +1 -1
- package/dist/core/chat-types.d.ts +18 -0
- package/dist/core/chat-types.js +14 -0
- package/dist/core/chat-types.js.map +1 -0
- package/dist/core/types.d.ts +7 -0
- package/dist/domain/chat/message-cleaner.d.ts +11 -0
- package/dist/domain/chat/message-cleaner.js +45 -0
- package/dist/domain/chat/message-cleaner.js.map +1 -0
- package/dist/domain/chat/message-router.d.ts +8 -0
- package/dist/domain/chat/message-router.js +93 -0
- package/dist/domain/chat/message-router.js.map +1 -0
- package/dist/domain/chat/message-splitter.d.ts +3 -0
- package/dist/domain/chat/message-splitter.js +148 -0
- package/dist/domain/chat/message-splitter.js.map +1 -0
- package/dist/domain/chat/platform-connection.d.ts +31 -0
- package/dist/domain/chat/platform-connection.js +67 -0
- package/dist/domain/chat/platform-connection.js.map +1 -0
- package/dist/domain/chat/ports.d.ts +31 -0
- package/dist/domain/chat/ports.js +2 -0
- package/dist/domain/chat/ports.js.map +1 -0
- package/dist/domain/chat/session-bridge.d.ts +41 -0
- package/dist/domain/chat/session-bridge.js +93 -0
- package/dist/domain/chat/session-bridge.js.map +1 -0
- package/dist/domain/chat/types.d.ts +83 -0
- package/dist/domain/chat/types.js +2 -0
- package/dist/domain/chat/types.js.map +1 -0
- package/dist/domain/chat/user-question.d.ts +33 -0
- package/dist/domain/chat/user-question.js +73 -0
- package/dist/domain/chat/user-question.js.map +1 -0
- package/dist/domain/config.d.ts +3 -1
- package/dist/domain/config.js +9 -0
- package/dist/domain/config.js.map +1 -1
- package/dist/domain/routine-loader.d.ts +2 -0
- package/dist/domain/routine-loader.js +3 -0
- package/dist/domain/routine-loader.js.map +1 -1
- package/dist/infrastructure/chat/adapter-factory.d.ts +5 -0
- package/dist/infrastructure/chat/adapter-factory.js +15 -0
- package/dist/infrastructure/chat/adapter-factory.js.map +1 -0
- package/dist/infrastructure/chat/adapters/discord-adapter.d.ts +23 -0
- package/dist/infrastructure/chat/adapters/discord-adapter.js +199 -0
- package/dist/infrastructure/chat/adapters/discord-adapter.js.map +1 -0
- package/dist/infrastructure/chat/adapters/slack-adapter.d.ts +24 -0
- package/dist/infrastructure/chat/adapters/slack-adapter.js +155 -0
- package/dist/infrastructure/chat/adapters/slack-adapter.js.map +1 -0
- package/dist/infrastructure/chat/agent-gateway-impl.d.ts +21 -0
- package/dist/infrastructure/chat/agent-gateway-impl.js +101 -0
- package/dist/infrastructure/chat/agent-gateway-impl.js.map +1 -0
- package/dist/infrastructure/chat/chat-ipc-client.d.ts +33 -0
- package/dist/infrastructure/chat/chat-ipc-client.js +70 -0
- package/dist/infrastructure/chat/chat-ipc-client.js.map +1 -0
- package/dist/infrastructure/chat/chat-ipc-server.d.ts +19 -0
- package/dist/infrastructure/chat/chat-ipc-server.js +125 -0
- package/dist/infrastructure/chat/chat-ipc-server.js.map +1 -0
- package/dist/infrastructure/chat/chat-logger.d.ts +24 -0
- package/dist/infrastructure/chat/chat-logger.js +86 -0
- package/dist/infrastructure/chat/chat-logger.js.map +1 -0
- package/dist/infrastructure/chat/credentials-repository.d.ts +8 -0
- package/dist/infrastructure/chat/credentials-repository.js +84 -0
- package/dist/infrastructure/chat/credentials-repository.js.map +1 -0
- package/dist/infrastructure/chat/session-bridge-repository.d.ts +13 -0
- package/dist/infrastructure/chat/session-bridge-repository.js +120 -0
- package/dist/infrastructure/chat/session-bridge-repository.js.map +1 -0
- package/dist/infrastructure/chat/token-masking.d.ts +3 -0
- package/dist/infrastructure/chat/token-masking.js +22 -0
- package/dist/infrastructure/chat/token-masking.js.map +1 -0
- package/dist/infrastructure/store/relay-store.js +3 -1
- package/dist/infrastructure/store/relay-store.js.map +1 -1
- package/dist/interfaces/cli/chat-cli.d.ts +34 -0
- package/dist/interfaces/cli/chat-cli.js +68 -0
- package/dist/interfaces/cli/chat-cli.js.map +1 -0
- package/dist/interfaces/cli/relay-cli-args.d.ts +16 -1
- package/dist/interfaces/cli/relay-cli-args.js +135 -2
- package/dist/interfaces/cli/relay-cli-args.js.map +1 -1
- package/dist/interfaces/mcp/chat-tools.d.ts +33 -0
- package/dist/interfaces/mcp/chat-tools.js +129 -0
- package/dist/interfaces/mcp/chat-tools.js.map +1 -0
- package/dist/interfaces/mcp/relay-mcp-server.d.ts +2 -0
- package/dist/interfaces/mcp/relay-mcp-server.js +194 -1
- package/dist/interfaces/mcp/relay-mcp-server.js.map +1 -1
- package/package.json +3 -1
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { emitChatLog } from "./chat-logging.js";
|
|
2
|
+
import { MessageRouter } from "../../domain/chat/message-router.js";
|
|
3
|
+
import { SessionBridge, ThreadKey } from "../../domain/chat/session-bridge.js";
|
|
4
|
+
export class ChatInboundHandler {
|
|
5
|
+
deps;
|
|
6
|
+
activeOperations = 0;
|
|
7
|
+
idleWaiters = new Set();
|
|
8
|
+
sessionTimeoutMinutes;
|
|
9
|
+
maxMessageLength;
|
|
10
|
+
logger;
|
|
11
|
+
constructor(deps) {
|
|
12
|
+
this.deps = deps;
|
|
13
|
+
this.sessionTimeoutMinutes = deps.sessionTimeoutMinutes ?? 30;
|
|
14
|
+
this.maxMessageLength = deps.maxMessageLength ?? 10_000;
|
|
15
|
+
this.logger = deps.logger;
|
|
16
|
+
}
|
|
17
|
+
configure(options) {
|
|
18
|
+
if (options.sessionTimeoutMinutes !== undefined) {
|
|
19
|
+
this.sessionTimeoutMinutes = Math.max(1, Math.floor(options.sessionTimeoutMinutes));
|
|
20
|
+
}
|
|
21
|
+
if (options.maxMessageLength !== undefined) {
|
|
22
|
+
this.maxMessageLength = Math.max(1, Math.floor(options.maxMessageLength));
|
|
23
|
+
}
|
|
24
|
+
if (options.messageQueueMaxSize !== undefined) {
|
|
25
|
+
this.deps.messageQueueManager.setMaxBufferedPerThread(options.messageQueueMaxSize);
|
|
26
|
+
}
|
|
27
|
+
if (options.logger !== undefined) {
|
|
28
|
+
this.logger = options.logger;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
async handleInbound(event) {
|
|
32
|
+
const startTime = Date.now();
|
|
33
|
+
const durationMs = () => Date.now() - startTime;
|
|
34
|
+
const incomingKey = new ThreadKey({
|
|
35
|
+
platform: event.platform,
|
|
36
|
+
teamOrGuildId: event.teamOrGuildId,
|
|
37
|
+
channelId: event.channelId,
|
|
38
|
+
threadId: event.threadId,
|
|
39
|
+
});
|
|
40
|
+
const queueKey = incomingKey.toString();
|
|
41
|
+
await this.log("info", "chat inbound received", {
|
|
42
|
+
platform: event.platform,
|
|
43
|
+
threadKey: queueKey,
|
|
44
|
+
teamOrGuildId: event.teamOrGuildId,
|
|
45
|
+
channelId: event.channelId,
|
|
46
|
+
threadId: event.threadId,
|
|
47
|
+
messageId: event.messageId,
|
|
48
|
+
userId: event.userId,
|
|
49
|
+
isDM: event.isDM,
|
|
50
|
+
isMention: event.isMention,
|
|
51
|
+
});
|
|
52
|
+
if (this.deps.messageQueueManager.isProcessing(queueKey)) {
|
|
53
|
+
this.deps.messageQueueManager.enqueue(queueKey, event);
|
|
54
|
+
await this.log("warn", "chat inbound buffered", {
|
|
55
|
+
platform: event.platform,
|
|
56
|
+
threadKey: queueKey,
|
|
57
|
+
messageId: event.messageId,
|
|
58
|
+
durationMs: durationMs(),
|
|
59
|
+
});
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
const intent = MessageRouter.determineIntent(event, (key) => this.deps.sessionBridgeRepository.findByThreadKey(key), (key) => this.deps.questionService.findPendingByThreadKey(key), this.sessionTimeoutMinutes, this.maxMessageLength);
|
|
63
|
+
if (intent.kind === "ignored") {
|
|
64
|
+
await this.log("info", "chat inbound ignored", {
|
|
65
|
+
platform: event.platform,
|
|
66
|
+
reason: intent.reason,
|
|
67
|
+
threadKey: queueKey,
|
|
68
|
+
intent: intent.kind,
|
|
69
|
+
durationMs: durationMs(),
|
|
70
|
+
});
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
this.activeOperations += 1;
|
|
74
|
+
this.deps.messageQueueManager.startProcessing(queueKey);
|
|
75
|
+
const stopIndicator = await this.deps.outboundHandler.beginProcessingIndicator(event);
|
|
76
|
+
try {
|
|
77
|
+
if (intent.kind === "answer_question") {
|
|
78
|
+
await this.deps.questionService.handlePotentialAnswer(event);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
if (intent.kind === "new_session") {
|
|
82
|
+
await this.handleNewSession(event, intent, durationMs);
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
await this.handleContinuation(event, intent, durationMs);
|
|
86
|
+
}
|
|
87
|
+
finally {
|
|
88
|
+
await stopIndicator?.();
|
|
89
|
+
this.deps.messageQueueManager.finishProcessing(queueKey);
|
|
90
|
+
this.activeOperations = Math.max(0, this.activeOperations - 1);
|
|
91
|
+
if (this.activeOperations === 0) {
|
|
92
|
+
for (const resolve of this.idleWaiters) {
|
|
93
|
+
resolve();
|
|
94
|
+
}
|
|
95
|
+
this.idleWaiters.clear();
|
|
96
|
+
}
|
|
97
|
+
for (const buffered of this.deps.messageQueueManager.dequeueAll(queueKey)) {
|
|
98
|
+
await this.handleInbound(buffered);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
async waitForIdle(timeoutMs) {
|
|
103
|
+
if (this.activeOperations === 0) {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
await Promise.race([
|
|
107
|
+
new Promise((resolve) => this.idleWaiters.add(resolve)),
|
|
108
|
+
new Promise((resolve) => setTimeout(resolve, timeoutMs)),
|
|
109
|
+
]);
|
|
110
|
+
}
|
|
111
|
+
async handleNewSession(event, intent, durationMs) {
|
|
112
|
+
const result = await this.deps.agentGateway.startSession(intent.cleanedText, intent.backendSpec);
|
|
113
|
+
const sendResult = await this.deps.outboundHandler.sendResponse(event.platform, {
|
|
114
|
+
channelId: event.channelId,
|
|
115
|
+
threadId: event.threadId,
|
|
116
|
+
userId: event.isDM ? event.userId : undefined,
|
|
117
|
+
messageId: event.messageId,
|
|
118
|
+
}, result.response);
|
|
119
|
+
const bridge = SessionBridge.create(new ThreadKey({
|
|
120
|
+
platform: event.platform,
|
|
121
|
+
teamOrGuildId: sendResult.teamOrGuildId ?? event.teamOrGuildId,
|
|
122
|
+
channelId: sendResult.channelId ?? event.channelId,
|
|
123
|
+
threadId: sendResult.threadId ?? event.threadId,
|
|
124
|
+
}), result.relaySessionId, result.backend);
|
|
125
|
+
bridge.backendSessionId = result.backendSessionId ?? bridge.backendSessionId;
|
|
126
|
+
this.deps.sessionBridgeRepository.save(bridge);
|
|
127
|
+
await this.log("info", "chat session started", {
|
|
128
|
+
platform: event.platform,
|
|
129
|
+
relaySessionId: result.relaySessionId,
|
|
130
|
+
backend: result.backend,
|
|
131
|
+
threadKey: bridge.threadKey.toString(),
|
|
132
|
+
intent: intent.kind,
|
|
133
|
+
durationMs: durationMs(),
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
async handleContinuation(event, intent, durationMs) {
|
|
137
|
+
intent.bridge.startProcessing();
|
|
138
|
+
this.deps.sessionBridgeRepository.save(intent.bridge);
|
|
139
|
+
const result = await this.deps.agentGateway.continueSession(intent.bridge.relaySessionId, intent.cleanedText);
|
|
140
|
+
const sendResult = await this.deps.outboundHandler.sendResponse(event.platform, {
|
|
141
|
+
channelId: intent.bridge.threadKey.channelId,
|
|
142
|
+
threadId: intent.bridge.threadKey.threadId,
|
|
143
|
+
userId: event.isDM ? event.userId : undefined,
|
|
144
|
+
messageId: event.messageId,
|
|
145
|
+
}, result.response);
|
|
146
|
+
const updatedBridge = new SessionBridge({
|
|
147
|
+
threadKey: new ThreadKey({
|
|
148
|
+
platform: event.platform,
|
|
149
|
+
teamOrGuildId: sendResult.teamOrGuildId ?? intent.bridge.threadKey.teamOrGuildId,
|
|
150
|
+
channelId: sendResult.channelId ?? intent.bridge.threadKey.channelId,
|
|
151
|
+
threadId: sendResult.threadId ?? intent.bridge.threadKey.threadId,
|
|
152
|
+
}),
|
|
153
|
+
relaySessionId: result.relaySessionId,
|
|
154
|
+
backendSessionId: result.backendSessionId ?? intent.bridge.backendSessionId,
|
|
155
|
+
backend: result.backend,
|
|
156
|
+
createdAt: intent.bridge.createdAt,
|
|
157
|
+
lastActivityAt: new Date(),
|
|
158
|
+
isProcessing: false,
|
|
159
|
+
});
|
|
160
|
+
updatedBridge.finishProcessing();
|
|
161
|
+
this.deps.sessionBridgeRepository.save(updatedBridge);
|
|
162
|
+
await this.log("info", "chat session continued", {
|
|
163
|
+
platform: event.platform,
|
|
164
|
+
relaySessionId: result.relaySessionId,
|
|
165
|
+
backend: result.backend,
|
|
166
|
+
threadKey: updatedBridge.threadKey.toString(),
|
|
167
|
+
intent: intent.kind,
|
|
168
|
+
durationMs: durationMs(),
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
async log(level, message, metadata) {
|
|
172
|
+
await emitChatLog(this.logger, level, message, metadata);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
//# sourceMappingURL=chat-inbound-handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-inbound-handler.js","sourceRoot":"","sources":["../../../src/application/chat/chat-inbound-handler.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface ChatStructuredLogger {
|
|
2
|
+
info(message: string, metadata?: Record<string, unknown>): Promise<void> | void;
|
|
3
|
+
warn(message: string, metadata?: Record<string, unknown>): Promise<void> | void;
|
|
4
|
+
error(message: string, metadata?: Record<string, unknown>): Promise<void> | void;
|
|
5
|
+
}
|
|
6
|
+
export type ChatLoggerLike = ChatStructuredLogger | ((message: string, metadata?: Record<string, unknown>) => Promise<void> | void);
|
|
7
|
+
export declare const noopChatLogger: ChatStructuredLogger;
|
|
8
|
+
export declare function emitChatLog(logger: ChatLoggerLike | undefined, level: keyof ChatStructuredLogger, message: string, metadata?: Record<string, unknown>): Promise<void>;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export const noopChatLogger = {
|
|
2
|
+
info() { },
|
|
3
|
+
warn() { },
|
|
4
|
+
error() { },
|
|
5
|
+
};
|
|
6
|
+
export async function emitChatLog(logger, level, message, metadata) {
|
|
7
|
+
if (!logger) {
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
if (typeof logger === "function") {
|
|
11
|
+
await Promise.resolve(logger(message, metadata));
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
await Promise.resolve(logger[level](message, metadata));
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=chat-logging.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-logging.js","sourceRoot":"","sources":["../../../src/application/chat/chat-logging.ts"],"names":[],"mappings":"AAUA,MAAM,CAAC,MAAM,cAAc,GAAyB;IAClD,IAAI,KAAU,CAAC;IACf,IAAI,KAAU,CAAC;IACf,KAAK,KAAU,CAAC;CACjB,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,MAAkC,EAClC,KAAiC,EACjC,OAAe,EACf,QAAkC;IAElC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO;IACT,CAAC;IAED,IAAI,OAAO,MAAM,KAAK,UAAU,EAAE,CAAC;QACjC,MAAM,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;QACjD,OAAO;IACT,CAAC;IAED,MAAM,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;AAC1D,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { PlatformType, type ChatChannel } from "../../core/chat-types.js";
|
|
2
|
+
import type { ChatPlatformAdapter } from "../../domain/chat/ports.js";
|
|
3
|
+
import type { ChatTarget, InboundChatEvent, SendResult } from "../../domain/chat/types.js";
|
|
4
|
+
export declare class ChatOutboundHandler {
|
|
5
|
+
private adaptersByPlatform;
|
|
6
|
+
constructor(adapters?: ChatPlatformAdapter[]);
|
|
7
|
+
setAdapters(adapters: ChatPlatformAdapter[]): void;
|
|
8
|
+
sendResponse(platform: PlatformType | undefined, target: Omit<ChatTarget, "platform">, content: string): Promise<SendResult>;
|
|
9
|
+
listChannels(platform?: PlatformType): Promise<ChatChannel[]>;
|
|
10
|
+
beginProcessingIndicator(event: InboundChatEvent): Promise<(() => Promise<void>) | undefined>;
|
|
11
|
+
static markdownToSlackMrkdwn(markdown: string): string;
|
|
12
|
+
static markdownToSlackBlocks(markdown: string): Array<Record<string, unknown>>;
|
|
13
|
+
static markdownToDiscordEmbed(markdown: string): Record<string, unknown> | null;
|
|
14
|
+
private resolveAdapter;
|
|
15
|
+
private buildMessage;
|
|
16
|
+
}
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import { ValidationError } from "../../core/errors.js";
|
|
2
|
+
import { PlatformType } from "../../core/chat-types.js";
|
|
3
|
+
import { MessageSplitter } from "../../domain/chat/message-splitter.js";
|
|
4
|
+
export class ChatOutboundHandler {
|
|
5
|
+
adaptersByPlatform;
|
|
6
|
+
constructor(adapters = []) {
|
|
7
|
+
this.adaptersByPlatform = new Map();
|
|
8
|
+
this.setAdapters(adapters);
|
|
9
|
+
}
|
|
10
|
+
setAdapters(adapters) {
|
|
11
|
+
this.adaptersByPlatform = new Map(adapters.map((adapter) => [adapter.platform, adapter]));
|
|
12
|
+
}
|
|
13
|
+
async sendResponse(platform, target, content) {
|
|
14
|
+
const adapter = this.resolveAdapter(platform);
|
|
15
|
+
const maxLength = adapter.platform === PlatformType.Slack ? 4_000 : 2_000;
|
|
16
|
+
const pieces = MessageSplitter.split(content, maxLength);
|
|
17
|
+
const baseTarget = {
|
|
18
|
+
platform: adapter.platform,
|
|
19
|
+
...target,
|
|
20
|
+
};
|
|
21
|
+
let replyTarget = baseTarget;
|
|
22
|
+
let firstResult;
|
|
23
|
+
for (const piece of pieces) {
|
|
24
|
+
const message = this.buildMessage(adapter.platform, piece);
|
|
25
|
+
const result = await adapter.sendMessage(replyTarget, message);
|
|
26
|
+
firstResult ??= result;
|
|
27
|
+
if (!replyTarget.threadId && result.threadId) {
|
|
28
|
+
replyTarget = {
|
|
29
|
+
...replyTarget,
|
|
30
|
+
channelId: result.channelId ?? replyTarget.channelId,
|
|
31
|
+
threadId: result.threadId,
|
|
32
|
+
messageId: undefined,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return firstResult ?? {
|
|
37
|
+
success: true,
|
|
38
|
+
messageId: "",
|
|
39
|
+
channelId: target.channelId,
|
|
40
|
+
threadId: target.threadId,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
async listChannels(platform) {
|
|
44
|
+
const adapter = this.resolveAdapter(platform);
|
|
45
|
+
return adapter.getChannels();
|
|
46
|
+
}
|
|
47
|
+
async beginProcessingIndicator(event) {
|
|
48
|
+
const adapter = this.adaptersByPlatform.get(event.platform);
|
|
49
|
+
const stopIndicator = await adapter?.beginProcessingIndicator?.(event);
|
|
50
|
+
return typeof stopIndicator === "function" ? stopIndicator : undefined;
|
|
51
|
+
}
|
|
52
|
+
static markdownToSlackMrkdwn(markdown) {
|
|
53
|
+
return markdown
|
|
54
|
+
.replace(/\r\n/g, "\n")
|
|
55
|
+
.replace(/^#\s+(.+)$/gm, (_, title) => `*${title.trim()}*`)
|
|
56
|
+
.replace(/\*\*(.+?)\*\*/g, "*$1*");
|
|
57
|
+
}
|
|
58
|
+
static markdownToSlackBlocks(markdown) {
|
|
59
|
+
const blocks = [];
|
|
60
|
+
const segments = splitMarkdownSegments(markdown);
|
|
61
|
+
for (const segment of segments) {
|
|
62
|
+
const trimmed = segment.trim();
|
|
63
|
+
if (!trimmed) {
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
const headingMatch = trimmed.match(/^#\s+(.+)$/);
|
|
67
|
+
if (headingMatch) {
|
|
68
|
+
blocks.push({
|
|
69
|
+
type: "header",
|
|
70
|
+
text: {
|
|
71
|
+
type: "plain_text",
|
|
72
|
+
text: headingMatch[1].trim().slice(0, 150),
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
blocks.push({
|
|
78
|
+
type: "section",
|
|
79
|
+
text: {
|
|
80
|
+
type: "mrkdwn",
|
|
81
|
+
text: ChatOutboundHandler.markdownToSlackMrkdwn(trimmed).slice(0, 3_000),
|
|
82
|
+
},
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
return blocks;
|
|
86
|
+
}
|
|
87
|
+
static markdownToDiscordEmbed(markdown) {
|
|
88
|
+
const normalized = markdown.trim();
|
|
89
|
+
const headingMatch = normalized.match(/^#\s+(.+?)(?:\n+([\s\S]*))?$/);
|
|
90
|
+
if (!headingMatch && normalized.length < 500) {
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
const title = headingMatch?.[1]?.trim();
|
|
94
|
+
const description = (headingMatch?.[2] ?? normalized).trim();
|
|
95
|
+
return {
|
|
96
|
+
title: title || undefined,
|
|
97
|
+
description: description || normalized,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
resolveAdapter(platform) {
|
|
101
|
+
if (platform) {
|
|
102
|
+
const adapter = this.adaptersByPlatform.get(platform);
|
|
103
|
+
if (!adapter) {
|
|
104
|
+
throw new ValidationError(`Platform "${platform}" is not connected.`, {
|
|
105
|
+
recoveryHint: "Start the chat daemon with credentials for the requested platform.",
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
return adapter;
|
|
109
|
+
}
|
|
110
|
+
const adapters = [...this.adaptersByPlatform.values()];
|
|
111
|
+
if (adapters.length === 1) {
|
|
112
|
+
return adapters[0];
|
|
113
|
+
}
|
|
114
|
+
throw new ValidationError("platform is required when multiple chat platforms are connected.", {
|
|
115
|
+
recoveryHint: "Specify platform: slack or discord.",
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
buildMessage(platform, content) {
|
|
119
|
+
if (platform === PlatformType.Slack) {
|
|
120
|
+
try {
|
|
121
|
+
return {
|
|
122
|
+
content: ChatOutboundHandler.markdownToSlackMrkdwn(content),
|
|
123
|
+
format: "plain_text",
|
|
124
|
+
metadata: {
|
|
125
|
+
blocks: ChatOutboundHandler.markdownToSlackBlocks(content),
|
|
126
|
+
plainText: content,
|
|
127
|
+
},
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
return {
|
|
132
|
+
content: ChatOutboundHandler.markdownToSlackMrkdwn(content),
|
|
133
|
+
format: "plain_text",
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
try {
|
|
138
|
+
const embed = ChatOutboundHandler.markdownToDiscordEmbed(content);
|
|
139
|
+
if (embed) {
|
|
140
|
+
return {
|
|
141
|
+
content,
|
|
142
|
+
format: "markdown",
|
|
143
|
+
metadata: {
|
|
144
|
+
embed,
|
|
145
|
+
plainText: content,
|
|
146
|
+
},
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
// Fall back to plain markdown below.
|
|
152
|
+
}
|
|
153
|
+
return {
|
|
154
|
+
content,
|
|
155
|
+
format: "markdown",
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
function splitMarkdownSegments(markdown) {
|
|
160
|
+
const lines = markdown.replace(/\r\n/g, "\n").split("\n");
|
|
161
|
+
const segments = [];
|
|
162
|
+
const buffer = [];
|
|
163
|
+
let inCodeBlock = false;
|
|
164
|
+
const flush = () => {
|
|
165
|
+
if (buffer.length === 0) {
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
segments.push(buffer.join("\n"));
|
|
169
|
+
buffer.length = 0;
|
|
170
|
+
};
|
|
171
|
+
for (const line of lines) {
|
|
172
|
+
const trimmed = line.trimStart();
|
|
173
|
+
if (trimmed.startsWith("```")) {
|
|
174
|
+
inCodeBlock = !inCodeBlock;
|
|
175
|
+
buffer.push(line);
|
|
176
|
+
if (!inCodeBlock) {
|
|
177
|
+
flush();
|
|
178
|
+
}
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
if (!inCodeBlock && line.trim() === "") {
|
|
182
|
+
flush();
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
buffer.push(line);
|
|
186
|
+
}
|
|
187
|
+
flush();
|
|
188
|
+
return segments;
|
|
189
|
+
}
|
|
190
|
+
//# sourceMappingURL=chat-outbound-handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-outbound-handler.js","sourceRoot":"","sources":["../../../src/application/chat/chat-outbound-handler.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { PlatformType } from "../../core/chat-types.js";
|
|
2
|
+
import type { ChatPlatformAdapter, UserQuestionRepository } from "../../domain/chat/ports.js";
|
|
3
|
+
import { ThreadKey } from "../../domain/chat/session-bridge.js";
|
|
4
|
+
import { UserQuestion } from "../../domain/chat/user-question.js";
|
|
5
|
+
import type { InboundChatEvent } from "../../domain/chat/types.js";
|
|
6
|
+
export interface AskUserResult {
|
|
7
|
+
answered: boolean;
|
|
8
|
+
response?: string;
|
|
9
|
+
user_id?: string;
|
|
10
|
+
timestamp?: string;
|
|
11
|
+
reason?: "timeout";
|
|
12
|
+
}
|
|
13
|
+
export declare class InMemoryUserQuestionRepository implements UserQuestionRepository {
|
|
14
|
+
private readonly questions;
|
|
15
|
+
findPendingByThreadKey(key: ThreadKey): UserQuestion | null;
|
|
16
|
+
save(question: UserQuestion): void;
|
|
17
|
+
}
|
|
18
|
+
export declare class ChatQuestionService {
|
|
19
|
+
private readonly deps;
|
|
20
|
+
private adaptersByPlatform;
|
|
21
|
+
private readonly pendingQuestions;
|
|
22
|
+
private maxMessageLength;
|
|
23
|
+
constructor(deps: {
|
|
24
|
+
userQuestionRepository: UserQuestionRepository;
|
|
25
|
+
adapters?: ChatPlatformAdapter[];
|
|
26
|
+
now?: () => Date;
|
|
27
|
+
questionIdFactory?: () => string;
|
|
28
|
+
});
|
|
29
|
+
setAdapters(adapters: ChatPlatformAdapter[]): void;
|
|
30
|
+
configure(options: {
|
|
31
|
+
maxMessageLength?: number;
|
|
32
|
+
}): void;
|
|
33
|
+
findPendingByThreadKey(key: ThreadKey): UserQuestion | null;
|
|
34
|
+
ask(userId: string, questionText: string, timeoutSeconds?: number, platform?: PlatformType, channel?: string): Promise<AskUserResult>;
|
|
35
|
+
handlePotentialAnswer(event: InboundChatEvent): Promise<boolean>;
|
|
36
|
+
private resolveAdapter;
|
|
37
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { ValidationError } from "../../core/errors.js";
|
|
3
|
+
import { MessageCleaner } from "../../domain/chat/message-cleaner.js";
|
|
4
|
+
import { ThreadKey } from "../../domain/chat/session-bridge.js";
|
|
5
|
+
import { QuestionState, UserQuestion, } from "../../domain/chat/user-question.js";
|
|
6
|
+
export class InMemoryUserQuestionRepository {
|
|
7
|
+
questions = new Map();
|
|
8
|
+
findPendingByThreadKey(key) {
|
|
9
|
+
for (const question of this.questions.values()) {
|
|
10
|
+
if (question.state === QuestionState.Pending &&
|
|
11
|
+
question.replyScope?.equals(key)) {
|
|
12
|
+
return question;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
save(question) {
|
|
18
|
+
this.questions.set(question.questionId, question);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export class ChatQuestionService {
|
|
22
|
+
deps;
|
|
23
|
+
adaptersByPlatform;
|
|
24
|
+
pendingQuestions = new Map();
|
|
25
|
+
maxMessageLength;
|
|
26
|
+
constructor(deps) {
|
|
27
|
+
this.deps = deps;
|
|
28
|
+
this.adaptersByPlatform = new Map();
|
|
29
|
+
this.maxMessageLength = 10_000;
|
|
30
|
+
this.setAdapters(deps.adapters ?? []);
|
|
31
|
+
}
|
|
32
|
+
setAdapters(adapters) {
|
|
33
|
+
this.adaptersByPlatform = new Map(adapters.map((adapter) => [adapter.platform, adapter]));
|
|
34
|
+
}
|
|
35
|
+
configure(options) {
|
|
36
|
+
if (options.maxMessageLength !== undefined) {
|
|
37
|
+
this.maxMessageLength = Math.max(1, Math.floor(options.maxMessageLength));
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
findPendingByThreadKey(key) {
|
|
41
|
+
return this.deps.userQuestionRepository.findPendingByThreadKey(key);
|
|
42
|
+
}
|
|
43
|
+
async ask(userId, questionText, timeoutSeconds = 300, platform, channel) {
|
|
44
|
+
const adapter = this.resolveAdapter(platform);
|
|
45
|
+
const normalizedTimeout = Math.max(1, Math.floor(timeoutSeconds));
|
|
46
|
+
const question = UserQuestion.ask(this.deps.questionIdFactory?.() ?? randomUUID(), userId, questionText, normalizedTimeout);
|
|
47
|
+
this.deps.userQuestionRepository.save(question);
|
|
48
|
+
const sendResult = await adapter.sendMessage({
|
|
49
|
+
platform: adapter.platform,
|
|
50
|
+
userId,
|
|
51
|
+
channelId: channel,
|
|
52
|
+
}, {
|
|
53
|
+
content: questionText,
|
|
54
|
+
format: "markdown",
|
|
55
|
+
});
|
|
56
|
+
const replyChannelId = sendResult.channelId ?? channel;
|
|
57
|
+
if (!replyChannelId) {
|
|
58
|
+
throw new ValidationError("Unable to determine reply channel for chat_ask_user.", {
|
|
59
|
+
recoveryHint: "Ensure the chat adapter returns channelId for sent messages or pass channel explicitly.",
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
question.markSent(new ThreadKey({
|
|
63
|
+
platform: adapter.platform,
|
|
64
|
+
teamOrGuildId: sendResult.teamOrGuildId,
|
|
65
|
+
channelId: replyChannelId,
|
|
66
|
+
threadId: sendResult.threadId,
|
|
67
|
+
}));
|
|
68
|
+
this.deps.userQuestionRepository.save(question);
|
|
69
|
+
return new Promise((resolve) => {
|
|
70
|
+
const timer = setTimeout(() => {
|
|
71
|
+
if (question.state === QuestionState.Pending) {
|
|
72
|
+
question.markTimedOut();
|
|
73
|
+
this.deps.userQuestionRepository.save(question);
|
|
74
|
+
}
|
|
75
|
+
this.pendingQuestions.delete(question.questionId);
|
|
76
|
+
resolve({
|
|
77
|
+
answered: false,
|
|
78
|
+
reason: "timeout",
|
|
79
|
+
});
|
|
80
|
+
}, normalizedTimeout * 1_000);
|
|
81
|
+
this.pendingQuestions.set(question.questionId, {
|
|
82
|
+
question,
|
|
83
|
+
resolve,
|
|
84
|
+
timer,
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
async handlePotentialAnswer(event) {
|
|
89
|
+
const threadKey = new ThreadKey({
|
|
90
|
+
platform: event.platform,
|
|
91
|
+
teamOrGuildId: event.teamOrGuildId,
|
|
92
|
+
channelId: event.channelId,
|
|
93
|
+
threadId: event.threadId,
|
|
94
|
+
});
|
|
95
|
+
const question = this.deps.userQuestionRepository.findPendingByThreadKey(threadKey);
|
|
96
|
+
if (!question) {
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
const pending = this.pendingQuestions.get(question.questionId);
|
|
100
|
+
if (!pending) {
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
const cleaned = MessageCleaner.clean(event.rawText, event.platform, undefined, this.maxMessageLength).cleanedText;
|
|
104
|
+
question.receiveAnswer(cleaned);
|
|
105
|
+
this.deps.userQuestionRepository.save(question);
|
|
106
|
+
clearTimeout(pending.timer);
|
|
107
|
+
this.pendingQuestions.delete(question.questionId);
|
|
108
|
+
pending.resolve({
|
|
109
|
+
answered: true,
|
|
110
|
+
response: cleaned,
|
|
111
|
+
user_id: event.userId,
|
|
112
|
+
timestamp: event.timestamp,
|
|
113
|
+
});
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
resolveAdapter(platform) {
|
|
117
|
+
if (platform) {
|
|
118
|
+
const adapter = this.adaptersByPlatform.get(platform);
|
|
119
|
+
if (!adapter) {
|
|
120
|
+
throw new ValidationError(`Platform "${platform}" is not connected.`, {
|
|
121
|
+
recoveryHint: "Specify a connected platform or start the chat daemon first.",
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
return adapter;
|
|
125
|
+
}
|
|
126
|
+
const adapters = [...this.adaptersByPlatform.values()];
|
|
127
|
+
if (adapters.length === 1) {
|
|
128
|
+
return adapters[0];
|
|
129
|
+
}
|
|
130
|
+
throw new ValidationError("platform is required when multiple chat platforms are connected.", {
|
|
131
|
+
recoveryHint: "Specify platform: slack or discord.",
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=chat-question-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-question-service.js","sourceRoot":"","sources":["../../../src/application/chat/chat-question-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { CredentialsRepository } from "../../domain/chat/ports.js";
|
|
2
|
+
export declare class ChatSetupService {
|
|
3
|
+
private readonly deps;
|
|
4
|
+
constructor(deps: {
|
|
5
|
+
credentialsRepository: CredentialsRepository;
|
|
6
|
+
prompt: (message: string) => Promise<string>;
|
|
7
|
+
confirm: (message: string) => Promise<boolean>;
|
|
8
|
+
openUrl: (url: string) => Promise<void>;
|
|
9
|
+
fetchImpl?: typeof fetch;
|
|
10
|
+
logger?: (message: string) => void;
|
|
11
|
+
});
|
|
12
|
+
setupSlack(): Promise<{
|
|
13
|
+
platform: "slack";
|
|
14
|
+
manifestUrl: string;
|
|
15
|
+
}>;
|
|
16
|
+
setupDiscord(): Promise<{
|
|
17
|
+
platform: "discord";
|
|
18
|
+
inviteUrl: string;
|
|
19
|
+
}>;
|
|
20
|
+
private validateSlackCredentials;
|
|
21
|
+
private validateDiscordCredentials;
|
|
22
|
+
private confirmOverwrite;
|
|
23
|
+
private openWithFallback;
|
|
24
|
+
private fetchJson;
|
|
25
|
+
}
|
|
26
|
+
export declare function buildSlackManifest(): Record<string, unknown>;
|
|
27
|
+
export declare function buildDiscordInviteUrl(applicationId: string): string;
|