@lobu/gateway 3.0.7 → 3.0.9
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/api/platform.d.ts.map +1 -1
- package/dist/api/platform.js +1 -0
- package/dist/api/platform.js.map +1 -1
- package/dist/auth/bedrock/models.d.ts +13 -0
- package/dist/auth/bedrock/models.d.ts.map +1 -0
- package/dist/auth/bedrock/models.js +75 -0
- package/dist/auth/bedrock/models.js.map +1 -0
- package/dist/auth/bedrock/provider-module.d.ts +17 -0
- package/dist/auth/bedrock/provider-module.d.ts.map +1 -0
- package/dist/auth/bedrock/provider-module.js +80 -0
- package/dist/auth/bedrock/provider-module.js.map +1 -0
- package/dist/auth/external/device-code-client.d.ts +2 -0
- package/dist/auth/external/device-code-client.d.ts.map +1 -1
- package/dist/auth/external/device-code-client.js +12 -4
- package/dist/auth/external/device-code-client.js.map +1 -1
- package/dist/auth/mcp/config-service.d.ts +3 -4
- package/dist/auth/mcp/config-service.d.ts.map +1 -1
- package/dist/auth/mcp/config-service.js +40 -12
- package/dist/auth/mcp/config-service.js.map +1 -1
- package/dist/auth/mcp/proxy.d.ts +1 -3
- package/dist/auth/mcp/proxy.d.ts.map +1 -1
- package/dist/auth/mcp/proxy.js.map +1 -1
- package/dist/cli/gateway.d.ts.map +1 -1
- package/dist/cli/gateway.js +12 -5
- package/dist/cli/gateway.js.map +1 -1
- package/dist/cli/index.js +2 -2
- package/dist/cli/index.js.map +1 -1
- package/dist/connections/interaction-bridge.d.ts.map +1 -1
- package/dist/connections/interaction-bridge.js +57 -15
- package/dist/connections/interaction-bridge.js.map +1 -1
- package/dist/connections/message-handler-bridge.d.ts.map +1 -1
- package/dist/connections/message-handler-bridge.js +44 -26
- package/dist/connections/message-handler-bridge.js.map +1 -1
- package/dist/gateway/index.d.ts.map +1 -1
- package/dist/gateway/index.js +1 -3
- package/dist/gateway/index.js.map +1 -1
- package/dist/orchestration/base-deployment-manager.js +7 -7
- package/dist/orchestration/base-deployment-manager.js.map +1 -1
- package/dist/platform/unified-thread-consumer.d.ts.map +1 -1
- package/dist/platform/unified-thread-consumer.js +38 -34
- package/dist/platform/unified-thread-consumer.js.map +1 -1
- package/dist/routes/internal/device-auth.d.ts +7 -0
- package/dist/routes/internal/device-auth.d.ts.map +1 -1
- package/dist/routes/internal/device-auth.js +101 -48
- package/dist/routes/internal/device-auth.js.map +1 -1
- package/dist/routes/public/cli-auth.d.ts.map +1 -1
- package/dist/routes/public/cli-auth.js +10 -0
- package/dist/routes/public/cli-auth.js.map +1 -1
- package/dist/services/bedrock-anthropic-service.d.ts +87 -0
- package/dist/services/bedrock-anthropic-service.d.ts.map +1 -0
- package/dist/services/bedrock-anthropic-service.js +453 -0
- package/dist/services/bedrock-anthropic-service.js.map +1 -0
- package/dist/services/bedrock-model-catalog.d.ts +28 -0
- package/dist/services/bedrock-model-catalog.d.ts.map +1 -0
- package/dist/services/bedrock-model-catalog.js +160 -0
- package/dist/services/bedrock-model-catalog.js.map +1 -0
- package/dist/services/bedrock-openai-service.d.ts +119 -0
- package/dist/services/bedrock-openai-service.d.ts.map +1 -0
- package/dist/services/bedrock-openai-service.js +412 -0
- package/dist/services/bedrock-openai-service.js.map +1 -0
- package/dist/services/core-services.d.ts +3 -0
- package/dist/services/core-services.d.ts.map +1 -1
- package/dist/services/core-services.js +13 -0
- package/dist/services/core-services.js.map +1 -1
- package/dist/services/system-config-resolver.d.ts.map +1 -1
- package/dist/services/system-config-resolver.js +0 -2
- package/dist/services/system-config-resolver.js.map +1 -1
- package/package.json +12 -10
- package/src/__tests__/bedrock-model-catalog.test.ts +40 -0
- package/src/__tests__/bedrock-openai-service.test.ts +157 -0
- package/src/__tests__/bedrock-provider-module.test.ts +56 -0
- package/src/__tests__/mcp-config-service.test.ts +1 -1
- package/src/__tests__/mcp-proxy.test.ts +1 -3
- package/src/auth/bedrock/provider-module.ts +110 -0
- package/src/auth/external/device-code-client.ts +14 -4
- package/src/auth/mcp/config-service.ts +49 -21
- package/src/auth/mcp/proxy.ts +1 -3
- package/src/cli/gateway.ts +8 -0
- package/src/cli/index.ts +2 -2
- package/src/connections/message-handler-bridge.ts +76 -51
- package/src/gateway/index.ts +1 -3
- package/src/orchestration/base-deployment-manager.ts +7 -7
- package/src/platform/unified-thread-consumer.ts +49 -42
- package/src/routes/internal/device-auth.ts +137 -51
- package/src/routes/public/cli-auth.ts +13 -0
- package/src/services/bedrock-model-catalog.ts +217 -0
- package/src/services/bedrock-openai-service.ts +658 -0
- package/src/services/core-services.ts +19 -0
- package/src/services/system-config-resolver.ts +0 -1
- package/tsconfig.tsbuildinfo +1 -0
|
@@ -10,6 +10,8 @@ export interface DeviceCodeClientConfig {
|
|
|
10
10
|
tokenUrl: string;
|
|
11
11
|
deviceAuthorizationUrl: string;
|
|
12
12
|
scope: string;
|
|
13
|
+
/** RFC 8707 resource indicator included in token requests. */
|
|
14
|
+
resource?: string;
|
|
13
15
|
tokenEndpointAuthMethod?:
|
|
14
16
|
| "none"
|
|
15
17
|
| "client_secret_post"
|
|
@@ -68,10 +70,14 @@ export class GenericDeviceCodeClient extends BaseOAuth2Client {
|
|
|
68
70
|
}
|
|
69
71
|
|
|
70
72
|
async requestDeviceCode(): Promise<DeviceAuthorizationStartResult> {
|
|
71
|
-
const
|
|
73
|
+
const params: Record<string, string> = {
|
|
72
74
|
client_id: this.config.clientId,
|
|
73
75
|
scope: this.config.scope,
|
|
74
|
-
}
|
|
76
|
+
};
|
|
77
|
+
if (this.config.resource) {
|
|
78
|
+
params.resource = this.config.resource;
|
|
79
|
+
}
|
|
80
|
+
const { headers, body } = this.buildAuthenticatedFormBody(params);
|
|
75
81
|
|
|
76
82
|
const response = await fetch(this.config.deviceAuthorizationUrl, {
|
|
77
83
|
method: "POST",
|
|
@@ -103,11 +109,15 @@ export class GenericDeviceCodeClient extends BaseOAuth2Client {
|
|
|
103
109
|
deviceAuthId: string,
|
|
104
110
|
intervalSeconds?: number
|
|
105
111
|
): Promise<DeviceAuthorizationPollResult> {
|
|
106
|
-
const
|
|
112
|
+
const params: Record<string, string> = {
|
|
107
113
|
grant_type: DEVICE_CODE_GRANT_TYPE,
|
|
108
114
|
device_code: deviceAuthId,
|
|
109
115
|
client_id: this.config.clientId,
|
|
110
|
-
}
|
|
116
|
+
};
|
|
117
|
+
if (this.config.resource) {
|
|
118
|
+
params.resource = this.config.resource;
|
|
119
|
+
}
|
|
120
|
+
const { headers, body } = this.buildAuthenticatedFormBody(params);
|
|
111
121
|
|
|
112
122
|
const response = await fetch(this.config.tokenUrl, {
|
|
113
123
|
method: "POST",
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
type McpOAuthConfig,
|
|
3
|
+
createLogger,
|
|
4
|
+
verifyWorkerToken,
|
|
5
|
+
} from "@lobu/core";
|
|
2
6
|
import type { SystemConfigResolver } from "../../services/system-config-resolver";
|
|
3
7
|
import type { AgentSettingsStore } from "../settings/agent-settings-store";
|
|
4
8
|
|
|
@@ -10,14 +14,12 @@ interface McpInput {
|
|
|
10
14
|
description: string;
|
|
11
15
|
}
|
|
12
16
|
|
|
13
|
-
interface HttpMcpServerConfig {
|
|
17
|
+
export interface HttpMcpServerConfig {
|
|
14
18
|
id: string;
|
|
15
19
|
upstreamUrl: string;
|
|
16
|
-
oauth?:
|
|
20
|
+
oauth?: McpOAuthConfig;
|
|
17
21
|
inputs?: McpInput[];
|
|
18
22
|
headers?: Record<string, string>;
|
|
19
|
-
loginUrl?: string;
|
|
20
|
-
resource?: string;
|
|
21
23
|
}
|
|
22
24
|
|
|
23
25
|
interface WorkerMcpConfig {
|
|
@@ -182,9 +184,7 @@ export class McpConfigService {
|
|
|
182
184
|
const statuses: McpStatus[] = [];
|
|
183
185
|
|
|
184
186
|
for (const [id, httpServer] of httpServers) {
|
|
185
|
-
const
|
|
186
|
-
const hasLoginUrl = !!httpServer.loginUrl;
|
|
187
|
-
const requiresAuth = hasOAuth || hasLoginUrl;
|
|
187
|
+
const requiresAuth = !!httpServer.oauth;
|
|
188
188
|
const requiresInput = !!(
|
|
189
189
|
httpServer.inputs && httpServer.inputs.length > 0
|
|
190
190
|
);
|
|
@@ -280,6 +280,45 @@ export class McpConfigService {
|
|
|
280
280
|
}
|
|
281
281
|
}
|
|
282
282
|
|
|
283
|
+
/**
|
|
284
|
+
* Parse and validate an oauth config from raw MCP server config.
|
|
285
|
+
* Handles backward compat: migrates top-level `resource` into `oauth.resource`,
|
|
286
|
+
* and treats `loginUrl` presence as `oauth: {}` (requiresAuth flag).
|
|
287
|
+
*/
|
|
288
|
+
function parseOAuthConfig(raw: any): McpOAuthConfig | undefined {
|
|
289
|
+
const hasLoginUrl = typeof raw.loginUrl === "string";
|
|
290
|
+
const hasOAuth = raw.oauth && typeof raw.oauth === "object";
|
|
291
|
+
|
|
292
|
+
if (!hasOAuth && !hasLoginUrl && typeof raw.resource !== "string") {
|
|
293
|
+
return undefined;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
const config: McpOAuthConfig = {};
|
|
297
|
+
|
|
298
|
+
if (hasOAuth) {
|
|
299
|
+
const obj = raw.oauth;
|
|
300
|
+
if (typeof obj.authUrl === "string") config.authUrl = obj.authUrl;
|
|
301
|
+
if (typeof obj.tokenUrl === "string") config.tokenUrl = obj.tokenUrl;
|
|
302
|
+
if (typeof obj.clientId === "string") config.clientId = obj.clientId;
|
|
303
|
+
if (typeof obj.clientSecret === "string")
|
|
304
|
+
config.clientSecret = obj.clientSecret;
|
|
305
|
+
if (Array.isArray(obj.scopes))
|
|
306
|
+
config.scopes = obj.scopes.filter((s: unknown) => typeof s === "string");
|
|
307
|
+
if (typeof obj.deviceAuthorizationUrl === "string")
|
|
308
|
+
config.deviceAuthorizationUrl = obj.deviceAuthorizationUrl;
|
|
309
|
+
if (typeof obj.registrationUrl === "string")
|
|
310
|
+
config.registrationUrl = obj.registrationUrl;
|
|
311
|
+
if (typeof obj.resource === "string") config.resource = obj.resource;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// Migrate top-level resource into oauth.resource (backward compat)
|
|
315
|
+
if (typeof raw.resource === "string" && !config.resource) {
|
|
316
|
+
config.resource = raw.resource;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
return config;
|
|
320
|
+
}
|
|
321
|
+
|
|
283
322
|
function normalizeConfig(config: { mcpServers: Record<string, any> }) {
|
|
284
323
|
const rawServers: Record<string, any> = {};
|
|
285
324
|
const httpServers = new Map<string, HttpMcpServerConfig>();
|
|
@@ -296,10 +335,7 @@ function normalizeConfig(config: { mcpServers: Record<string, any> }) {
|
|
|
296
335
|
httpServers.set(id, {
|
|
297
336
|
id,
|
|
298
337
|
upstreamUrl: cloned.url,
|
|
299
|
-
oauth:
|
|
300
|
-
cloned.oauth && typeof cloned.oauth === "object"
|
|
301
|
-
? cloned.oauth
|
|
302
|
-
: undefined,
|
|
338
|
+
oauth: parseOAuthConfig(cloned),
|
|
303
339
|
inputs: Array.isArray(cloned.inputs)
|
|
304
340
|
? cloned.inputs.filter(
|
|
305
341
|
(input: any) =>
|
|
@@ -312,10 +348,6 @@ function normalizeConfig(config: { mcpServers: Record<string, any> }) {
|
|
|
312
348
|
cloned.headers && typeof cloned.headers === "object"
|
|
313
349
|
? cloned.headers
|
|
314
350
|
: undefined,
|
|
315
|
-
loginUrl:
|
|
316
|
-
typeof cloned.loginUrl === "string" ? cloned.loginUrl : undefined,
|
|
317
|
-
resource:
|
|
318
|
-
typeof cloned.resource === "string" ? cloned.resource : undefined,
|
|
319
351
|
});
|
|
320
352
|
}
|
|
321
353
|
}
|
|
@@ -343,10 +375,7 @@ function toHttpServerConfig(
|
|
|
343
375
|
return {
|
|
344
376
|
id,
|
|
345
377
|
upstreamUrl: cloned.url,
|
|
346
|
-
oauth:
|
|
347
|
-
cloned.oauth && typeof cloned.oauth === "object"
|
|
348
|
-
? cloned.oauth
|
|
349
|
-
: undefined,
|
|
378
|
+
oauth: parseOAuthConfig(cloned),
|
|
350
379
|
inputs: Array.isArray(cloned.inputs)
|
|
351
380
|
? cloned.inputs.filter(
|
|
352
381
|
(input: any) =>
|
|
@@ -357,7 +386,6 @@ function toHttpServerConfig(
|
|
|
357
386
|
cloned.headers && typeof cloned.headers === "object"
|
|
358
387
|
? cloned.headers
|
|
359
388
|
: undefined,
|
|
360
|
-
loginUrl: typeof cloned.loginUrl === "string" ? cloned.loginUrl : undefined,
|
|
361
389
|
};
|
|
362
390
|
}
|
|
363
391
|
|
package/src/auth/mcp/proxy.ts
CHANGED
|
@@ -85,11 +85,9 @@ interface JsonRpcResponse {
|
|
|
85
85
|
interface HttpMcpServerConfig {
|
|
86
86
|
id: string;
|
|
87
87
|
upstreamUrl: string;
|
|
88
|
-
oauth?:
|
|
88
|
+
oauth?: import("@lobu/core").McpOAuthConfig;
|
|
89
89
|
inputs?: unknown[];
|
|
90
90
|
headers?: Record<string, string>;
|
|
91
|
-
loginUrl?: string;
|
|
92
|
-
resource?: string;
|
|
93
91
|
}
|
|
94
92
|
|
|
95
93
|
interface McpConfigSource {
|
package/src/cli/gateway.ts
CHANGED
|
@@ -136,6 +136,14 @@ export function createGatewayApp(
|
|
|
136
136
|
logger.debug("Secret proxy enabled at :8080/api/proxy");
|
|
137
137
|
}
|
|
138
138
|
|
|
139
|
+
if (coreServices) {
|
|
140
|
+
const bedrockOpenAIService = coreServices.getBedrockOpenAIService?.();
|
|
141
|
+
if (bedrockOpenAIService) {
|
|
142
|
+
app.route("/api/bedrock", bedrockOpenAIService.getApp());
|
|
143
|
+
logger.debug("Bedrock routes enabled at :8080/api/bedrock/*");
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
139
147
|
// Worker Gateway routes (Hono)
|
|
140
148
|
if (workerGateway) {
|
|
141
149
|
app.route("/worker", workerGateway.getApp());
|
package/src/cli/index.ts
CHANGED
|
@@ -34,8 +34,8 @@ async function main() {
|
|
|
34
34
|
initTracing({
|
|
35
35
|
serviceName: "lobu-gateway",
|
|
36
36
|
serviceVersion: process.env.npm_package_version || "2.0.0",
|
|
37
|
-
|
|
38
|
-
enabled: !!process.env.
|
|
37
|
+
otlpEndpoint: process.env.OTEL_EXPORTER_OTLP_ENDPOINT,
|
|
38
|
+
enabled: !!process.env.OTEL_EXPORTER_OTLP_ENDPOINT,
|
|
39
39
|
});
|
|
40
40
|
|
|
41
41
|
const config = buildGatewayConfig();
|
|
@@ -4,7 +4,12 @@
|
|
|
4
4
|
* settings links, allowlist, audio transcription, etc.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
createLogger,
|
|
9
|
+
createRootSpan,
|
|
10
|
+
flushTracing,
|
|
11
|
+
generateTraceId,
|
|
12
|
+
} from "@lobu/core";
|
|
8
13
|
import type Redis from "ioredis";
|
|
9
14
|
import type { CommandDispatcher } from "../commands/command-dispatcher";
|
|
10
15
|
import { createChatReply } from "../commands/command-reply-adapters";
|
|
@@ -290,62 +295,82 @@ class MessageHandlerBridge {
|
|
|
290
295
|
const traceId = generateTraceId(messageId);
|
|
291
296
|
const agentSettingsStore = this.services.getAgentSettingsStore();
|
|
292
297
|
|
|
293
|
-
//
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
}
|
|
298
|
+
// Create root span for distributed tracing
|
|
299
|
+
const { span: rootSpan, traceparent } = createRootSpan("message_received", {
|
|
300
|
+
"lobu.agent_id": agentId,
|
|
301
|
+
"lobu.message_id": messageId,
|
|
302
|
+
"lobu.platform": platform,
|
|
303
|
+
"lobu.connection_id": this.connection.id,
|
|
304
|
+
});
|
|
300
305
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
{
|
|
304
|
-
|
|
305
|
-
|
|
306
|
+
try {
|
|
307
|
+
// Check if agent has any provider credentials before enqueuing
|
|
308
|
+
if (!(await hasConfiguredProvider(agentId, agentSettingsStore))) {
|
|
309
|
+
await thread.post(
|
|
310
|
+
"No AI provider is configured yet. Provider setup is not available in the end-user chat flow yet. Ask an admin to connect a provider for the base agent."
|
|
311
|
+
);
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
306
314
|
|
|
307
|
-
|
|
308
|
-
platform,
|
|
309
|
-
userId,
|
|
310
|
-
botId: platform,
|
|
311
|
-
conversationId: isGroup ? messageId : channelId,
|
|
312
|
-
teamId: isGroup ? channelId : platform,
|
|
313
|
-
agentId,
|
|
314
|
-
messageId,
|
|
315
|
-
messageText,
|
|
316
|
-
channelId,
|
|
317
|
-
platformMetadata: {
|
|
318
|
-
traceId,
|
|
315
|
+
const agentOptions = await resolveAgentOptions(
|
|
319
316
|
agentId,
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
senderDisplayName: message.author?.fullName,
|
|
324
|
-
isGroup,
|
|
325
|
-
connectionId: this.connection.id,
|
|
326
|
-
responseChannel: channelId,
|
|
327
|
-
responseId: messageId,
|
|
328
|
-
responseThreadId: thread.id,
|
|
329
|
-
conversationHistory:
|
|
330
|
-
conversationHistory.length > 0 ? conversationHistory : undefined,
|
|
331
|
-
...(sessionReset && { sessionReset: true }),
|
|
332
|
-
},
|
|
333
|
-
agentOptions,
|
|
334
|
-
});
|
|
317
|
+
{},
|
|
318
|
+
agentSettingsStore
|
|
319
|
+
);
|
|
335
320
|
|
|
336
|
-
|
|
337
|
-
|
|
321
|
+
const payload = buildMessagePayload({
|
|
322
|
+
platform,
|
|
323
|
+
userId,
|
|
324
|
+
botId: platform,
|
|
325
|
+
conversationId: isGroup ? messageId : channelId,
|
|
326
|
+
teamId: isGroup ? channelId : platform,
|
|
327
|
+
agentId,
|
|
328
|
+
messageId,
|
|
329
|
+
messageText,
|
|
330
|
+
channelId,
|
|
331
|
+
platformMetadata: {
|
|
332
|
+
traceId,
|
|
333
|
+
traceparent: traceparent || undefined,
|
|
334
|
+
agentId,
|
|
335
|
+
chatId: channelId,
|
|
336
|
+
senderId: userId,
|
|
337
|
+
senderUsername: message.author?.userName,
|
|
338
|
+
senderDisplayName: message.author?.fullName,
|
|
339
|
+
isGroup,
|
|
340
|
+
connectionId: this.connection.id,
|
|
341
|
+
responseChannel: channelId,
|
|
342
|
+
responseId: messageId,
|
|
343
|
+
responseThreadId: thread.id,
|
|
344
|
+
conversationHistory:
|
|
345
|
+
conversationHistory.length > 0 ? conversationHistory : undefined,
|
|
346
|
+
...(sessionReset && { sessionReset: true }),
|
|
347
|
+
},
|
|
348
|
+
agentOptions,
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
const queueProducer = this.services.getQueueProducer();
|
|
352
|
+
await queueProducer.enqueueMessage(payload);
|
|
338
353
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
354
|
+
logger.info(
|
|
355
|
+
{
|
|
356
|
+
traceId,
|
|
357
|
+
traceparent,
|
|
358
|
+
messageId,
|
|
359
|
+
agentId,
|
|
360
|
+
connectionId: this.connection.id,
|
|
361
|
+
},
|
|
362
|
+
"Message enqueued via Chat SDK bridge"
|
|
363
|
+
);
|
|
343
364
|
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
365
|
+
// Show typing indicator
|
|
366
|
+
try {
|
|
367
|
+
await thread.startTyping?.("Processing...");
|
|
368
|
+
} catch {
|
|
369
|
+
// best effort
|
|
370
|
+
}
|
|
371
|
+
} finally {
|
|
372
|
+
rootSpan?.end();
|
|
373
|
+
void flushTracing();
|
|
349
374
|
}
|
|
350
375
|
}
|
|
351
376
|
|
package/src/gateway/index.ts
CHANGED
|
@@ -662,9 +662,7 @@ export class WorkerGateway {
|
|
|
662
662
|
if (primaryProvider) {
|
|
663
663
|
result.credentialEnvVarName = primaryProvider.getCredentialEnvVarName();
|
|
664
664
|
const upstream = primaryProvider.getUpstreamConfig?.();
|
|
665
|
-
|
|
666
|
-
result.defaultProvider = upstream.slug;
|
|
667
|
-
}
|
|
665
|
+
result.defaultProvider = upstream?.slug || primaryProvider.providerId;
|
|
668
666
|
}
|
|
669
667
|
|
|
670
668
|
if (agentModel) {
|
|
@@ -480,15 +480,15 @@ export abstract class BaseDeploymentManager {
|
|
|
480
480
|
envVars.TRACE_ID = traceId;
|
|
481
481
|
}
|
|
482
482
|
|
|
483
|
-
// Add
|
|
484
|
-
const
|
|
485
|
-
if (
|
|
486
|
-
envVars.
|
|
483
|
+
// Add OTLP endpoint for distributed tracing
|
|
484
|
+
const otlpEndpoint = process.env.OTEL_EXPORTER_OTLP_ENDPOINT;
|
|
485
|
+
if (otlpEndpoint) {
|
|
486
|
+
envVars.OTEL_EXPORTER_OTLP_ENDPOINT = otlpEndpoint;
|
|
487
487
|
try {
|
|
488
|
-
const
|
|
489
|
-
envVars.NO_PROXY = `${envVars.NO_PROXY},${
|
|
488
|
+
const otlpUrl = new URL(otlpEndpoint);
|
|
489
|
+
envVars.NO_PROXY = `${envVars.NO_PROXY},${otlpUrl.hostname}`;
|
|
490
490
|
} catch {
|
|
491
|
-
envVars.NO_PROXY = `${envVars.NO_PROXY},
|
|
491
|
+
envVars.NO_PROXY = `${envVars.NO_PROXY},tempo`;
|
|
492
492
|
}
|
|
493
493
|
}
|
|
494
494
|
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* via the PlatformRegistry, eliminating duplicate queue filtering logic.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { createLogger } from "@lobu/core";
|
|
7
|
+
import { createChildSpan, createLogger, flushTracing } from "@lobu/core";
|
|
8
8
|
import type { ChatResponseBridge } from "../connections/chat-response-bridge";
|
|
9
9
|
import type {
|
|
10
10
|
IMessageQueue,
|
|
@@ -77,61 +77,68 @@ export class UnifiedThreadResponseConsumer {
|
|
|
77
77
|
return;
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
//
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
80
|
+
// Create child span for response processing (linked to original trace)
|
|
81
|
+
const traceparent = data.platformMetadata?.traceparent as
|
|
82
|
+
| string
|
|
83
|
+
| undefined;
|
|
84
|
+
const span = createChildSpan("response_delivery", traceparent, {
|
|
85
|
+
"lobu.message_id": data.messageId,
|
|
86
|
+
"lobu.user_id": data.userId,
|
|
87
|
+
"lobu.platform": data.platform || data.teamId || "unknown",
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
try {
|
|
91
|
+
// Check if this response belongs to a Chat SDK connection — handle before legacy routing
|
|
92
|
+
if (this.chatResponseBridge?.canHandle(data)) {
|
|
93
|
+
const sessionKey = `${data.userId}:${data.originalMessageId || data.messageId}`;
|
|
84
94
|
await this.routeToRenderer(this.chatResponseBridge, data, sessionKey);
|
|
85
|
-
|
|
86
|
-
logger.error("Error processing Chat SDK response:", error);
|
|
87
|
-
throw error;
|
|
95
|
+
return;
|
|
88
96
|
}
|
|
89
|
-
return;
|
|
90
|
-
}
|
|
91
97
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
98
|
+
// Use platform field, fall back to teamId
|
|
99
|
+
const platformName = data.platform || data.teamId;
|
|
100
|
+
if (!platformName) {
|
|
101
|
+
logger.warn(
|
|
102
|
+
`Missing platform in thread response for message ${data.messageId}, skipping`
|
|
103
|
+
);
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
100
106
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
107
|
+
// Get platform adapter from registry
|
|
108
|
+
const platform = this.platformRegistry.get(platformName);
|
|
109
|
+
if (!platform) {
|
|
110
|
+
logger.warn(
|
|
111
|
+
`No platform adapter registered for: ${platformName}, skipping message ${data.messageId}`
|
|
112
|
+
);
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
109
115
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
116
|
+
// Get renderer from platform
|
|
117
|
+
const renderer = platform.getResponseRenderer?.();
|
|
118
|
+
if (!renderer) {
|
|
119
|
+
logger.warn(
|
|
120
|
+
`Platform ${platformName} does not provide a response renderer, skipping message ${data.messageId}`
|
|
121
|
+
);
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
118
124
|
|
|
119
|
-
|
|
120
|
-
|
|
125
|
+
// Create session key for tracking
|
|
126
|
+
const sessionKey = `${data.userId}:${data.originalMessageId || data.messageId}`;
|
|
121
127
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
128
|
+
logger.info(
|
|
129
|
+
`Processing thread response for platform=${platformName}, message=${data.messageId}, session=${sessionKey}`
|
|
130
|
+
);
|
|
125
131
|
|
|
126
|
-
try {
|
|
127
132
|
await this.routeToRenderer(renderer, data, sessionKey);
|
|
128
133
|
} catch (error) {
|
|
129
134
|
logger.error(
|
|
130
|
-
`Error processing thread response for ${
|
|
135
|
+
`Error processing thread response for message ${data.messageId}:`,
|
|
131
136
|
error
|
|
132
137
|
);
|
|
133
|
-
// Let queue handle retry logic
|
|
134
138
|
throw error;
|
|
139
|
+
} finally {
|
|
140
|
+
span?.end();
|
|
141
|
+
void flushTracing();
|
|
135
142
|
}
|
|
136
143
|
}
|
|
137
144
|
|