@inkeep/agents-work-apps 0.53.13 → 0.54.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.
@@ -1,7 +1,7 @@
1
- import * as hono0 from "hono";
1
+ import * as hono1 from "hono";
2
2
 
3
3
  //#region src/github/mcp/auth.d.ts
4
- declare const githubMcpAuth: () => hono0.MiddlewareHandler<{
4
+ declare const githubMcpAuth: () => hono1.MiddlewareHandler<{
5
5
  Variables: {
6
6
  toolId: string;
7
7
  };
@@ -1,11 +1,11 @@
1
1
  import { Hono } from "hono";
2
- import * as hono_types5 from "hono/types";
2
+ import * as hono_types3 from "hono/types";
3
3
 
4
4
  //#region src/github/mcp/index.d.ts
5
5
  declare const app: Hono<{
6
6
  Variables: {
7
7
  toolId: string;
8
8
  };
9
- }, hono_types5.BlankSchema, "/">;
9
+ }, hono_types3.BlankSchema, "/">;
10
10
  //#endregion
11
11
  export { app as default };
@@ -76,8 +76,8 @@ declare const ChangedFileSchema: z.ZodObject<{
76
76
  path: z.ZodString;
77
77
  status: z.ZodEnum<{
78
78
  added: "added";
79
- modified: "modified";
80
79
  removed: "removed";
80
+ modified: "modified";
81
81
  renamed: "renamed";
82
82
  copied: "copied";
83
83
  changed: "changed";
@@ -1,7 +1,7 @@
1
1
  import { Hono } from "hono";
2
- import * as hono_types3 from "hono/types";
2
+ import * as hono_types4 from "hono/types";
3
3
 
4
4
  //#region src/github/routes/tokenExchange.d.ts
5
- declare const app: Hono<hono_types3.BlankEnv, hono_types3.BlankSchema, "/">;
5
+ declare const app: Hono<hono_types4.BlankEnv, hono_types4.BlankSchema, "/">;
6
6
  //#endregion
7
7
  export { app as default };
@@ -1,7 +1,7 @@
1
1
  import { DispatchOptions, SlackEventDispatchResult, dispatchSlackEvent } from "./dispatcher.js";
2
2
  import { ManageAppVariables, WorkAppsVariables } from "./types.js";
3
- import { DefaultAgentConfig, SlackWorkspaceConnection, WorkspaceInstallData, clearWorkspaceConnectionCache, computeWorkspaceConnectionId, createConnectSession, deleteWorkspaceInstallation, findWorkspaceConnectionByTeamId, getConnectionAccessToken, getSlackIntegrationId, getSlackNango, getWorkspaceDefaultAgentFromNango, listWorkspaceInstallations, setWorkspaceDefaultAgent, storeWorkspaceInstallation, updateConnectionMetadata } from "./services/nango.js";
4
- import { getChannelAgentConfig, getWorkspaceDefaultAgent } from "./services/events/utils.js";
3
+ import { DefaultAgentConfig, SlackWorkspaceConnection, WorkspaceInstallData, clearWorkspaceConnectionCache, computeWorkspaceConnectionId, createConnectSession, deleteWorkspaceInstallation, findWorkspaceConnectionByTeamId, getConnectionAccessToken, getSlackIntegrationId, getSlackNango, getWorkspaceDefaultAgent, getWorkspaceDefaultAgentFromNango, listWorkspaceInstallations, setWorkspaceDefaultAgent, storeWorkspaceInstallation, updateConnectionMetadata } from "./services/nango.js";
4
+ import { getChannelAgentConfig } from "./services/events/utils.js";
5
5
  import "./services/events/index.js";
6
6
  import { getBotTokenForTeam, setBotTokenForTeam } from "./services/workspace-tokens.js";
7
7
  import "./routes/oauth.js";
@@ -1,5 +1,5 @@
1
- import { clearWorkspaceConnectionCache, computeWorkspaceConnectionId, createConnectSession, deleteWorkspaceInstallation, findWorkspaceConnectionByTeamId, getConnectionAccessToken, getSlackIntegrationId, getSlackNango, getWorkspaceDefaultAgentFromNango, listWorkspaceInstallations, setWorkspaceDefaultAgent, storeWorkspaceInstallation, updateConnectionMetadata } from "./services/nango.js";
2
- import { getChannelAgentConfig, getWorkspaceDefaultAgent } from "./services/events/utils.js";
1
+ import { clearWorkspaceConnectionCache, computeWorkspaceConnectionId, createConnectSession, deleteWorkspaceInstallation, findWorkspaceConnectionByTeamId, getConnectionAccessToken, getSlackIntegrationId, getSlackNango, getWorkspaceDefaultAgent, getWorkspaceDefaultAgentFromNango, listWorkspaceInstallations, setWorkspaceDefaultAgent, storeWorkspaceInstallation, updateConnectionMetadata } from "./services/nango.js";
2
+ import { getChannelAgentConfig } from "./services/events/utils.js";
3
3
  import "./services/events/index.js";
4
4
  import { getBotTokenForTeam, setBotTokenForTeam } from "./services/workspace-tokens.js";
5
5
  import { dispatchSlackEvent } from "./dispatcher.js";
@@ -1,11 +1,12 @@
1
1
  import { getLogger } from "../../logger.js";
2
2
  import runDbClient_default from "../../db/runDbClient.js";
3
- import { clearWorkspaceConnectionCache, computeWorkspaceConnectionId, deleteWorkspaceInstallation, findWorkspaceConnectionByTeamId, getWorkspaceDefaultAgentFromNango, listWorkspaceInstallations, setWorkspaceDefaultAgent } from "../services/nango.js";
3
+ import { clearWorkspaceConnectionCache, computeWorkspaceConnectionId, deleteWorkspaceInstallation, findWorkspaceConnectionByTeamId, listWorkspaceInstallations, setWorkspaceDefaultAgent } from "../services/nango.js";
4
+ import { lookupAgentName } from "../services/agent-resolution.js";
4
5
  import { getBotMemberChannels, getSlackChannels, getSlackClient, revokeSlackToken } from "../services/client.js";
5
6
  import "../services/index.js";
6
7
  import { requireChannelMemberOrAdmin, requireWorkspaceAdmin } from "../middleware/permissions.js";
7
8
  import { OpenAPIHono, z } from "@hono/zod-openapi";
8
- import { deleteAllWorkAppSlackChannelAgentConfigsByTeam, deleteAllWorkAppSlackUserMappingsByTeam, deleteWorkAppSlackChannelAgentConfig, deleteWorkAppSlackWorkspaceByNangoConnectionId, findWorkAppSlackChannelAgentConfig, findWorkAppSlackWorkspaceByTeamId, listWorkAppSlackChannelAgentConfigsByTeam, listWorkAppSlackUserMappingsByTeam, updateWorkAppSlackWorkspace, upsertWorkAppSlackChannelAgentConfig } from "@inkeep/agents-core";
9
+ import { WorkAppSlackAgentConfigRequestSchema, deleteAllWorkAppSlackChannelAgentConfigsByTeam, deleteAllWorkAppSlackUserMappingsByTeam, deleteWorkAppSlackChannelAgentConfig, deleteWorkAppSlackWorkspaceByNangoConnectionId, findWorkAppSlackChannelAgentConfig, findWorkAppSlackWorkspaceByTeamId, listWorkAppSlackChannelAgentConfigsByTeam, listWorkAppSlackUserMappingsByTeam, updateWorkAppSlackWorkspace, upsertWorkAppSlackChannelAgentConfig } from "@inkeep/agents-core";
9
10
  import { createProtectedRoute, inheritedWorkAppsAuth } from "@inkeep/agents-core/middleware";
10
11
 
11
12
  //#region src/slack/routes/workspaces.ts
@@ -40,14 +41,8 @@ function verifyTenantOwnership(c, workspaceTenantId) {
40
41
  return sessionTenantId === workspaceTenantId;
41
42
  }
42
43
  const app = new OpenAPIHono();
43
- const ChannelAgentConfigSchema = z.object({
44
- projectId: z.string(),
45
- agentId: z.string(),
46
- agentName: z.string().optional(),
47
- projectName: z.string().optional(),
48
- grantAccessToMembers: z.boolean().optional()
49
- });
50
- const WorkspaceSettingsSchema = z.object({ defaultAgent: ChannelAgentConfigSchema.optional() });
44
+ const WorkspaceSettingsResponseSchema = z.object({ defaultAgent: WorkAppSlackAgentConfigRequestSchema.optional() });
45
+ const WorkspaceSettingsRequestSchema = z.object({ defaultAgent: WorkAppSlackAgentConfigRequestSchema.optional() });
51
46
  const JoinFromWorkspaceSettingsSchema = z.object({ shouldAllowJoinFromWorkspace: z.boolean() });
52
47
  app.openapi(createProtectedRoute({
53
48
  method: "get",
@@ -75,27 +70,38 @@ app.openapi(createProtectedRoute({
75
70
  } }
76
71
  }), async (c) => {
77
72
  try {
78
- const allWorkspaces = await listWorkspaceInstallations();
79
73
  const sessionTenantId = c.get("tenantId");
80
74
  if (!sessionTenantId) {
81
75
  logger.warn({}, "No tenantId in session context — cannot list workspaces");
82
76
  return c.json({ workspaces: [] });
83
77
  }
84
- const workspaces = allWorkspaces.filter((w) => w.tenantId === sessionTenantId);
78
+ const workspaces = await listWorkspaceInstallations(sessionTenantId);
85
79
  logger.info({
86
80
  count: workspaces.length,
87
- totalCount: allWorkspaces.length,
88
81
  tenantId: sessionTenantId
89
82
  }, "Listed workspace installations");
90
- return c.json({ workspaces: workspaces.map((w) => ({
91
- connectionId: w.connectionId,
92
- teamId: w.teamId,
93
- teamName: w.teamName,
94
- teamDomain: w.teamDomain,
95
- tenantId: w.tenantId,
96
- hasDefaultAgent: !!w.defaultAgent,
97
- defaultAgentName: w.defaultAgent?.agentName
98
- })) });
83
+ const workspacesWithNames = await Promise.all(workspaces.map(async (w) => {
84
+ let defaultAgentName;
85
+ if (w.defaultAgent?.agentId && w.defaultAgent.projectId) try {
86
+ defaultAgentName = await lookupAgentName(w.tenantId, w.defaultAgent.projectId, w.defaultAgent.agentId, { skipCache: true });
87
+ } catch {
88
+ logger.warn({
89
+ tenantId: w.tenantId,
90
+ teamId: w.teamId,
91
+ projectId: w.defaultAgent.projectId,
92
+ agentId: w.defaultAgent.agentId
93
+ }, "Failed to resolve default agent name for workspace listing");
94
+ }
95
+ return {
96
+ connectionId: w.connectionId,
97
+ teamId: w.teamId,
98
+ teamName: w.teamName,
99
+ tenantId: w.tenantId,
100
+ hasDefaultAgent: !!w.defaultAgent,
101
+ defaultAgentName: defaultAgentName || w.defaultAgent?.agentId
102
+ };
103
+ }));
104
+ return c.json({ workspaces: workspacesWithNames });
99
105
  } catch (error) {
100
106
  logger.error({ error }, "Failed to list workspaces");
101
107
  return c.json({ workspaces: [] });
@@ -122,7 +128,7 @@ app.openapi(createProtectedRoute({
122
128
  teamName: z.string().optional(),
123
129
  tenantId: z.string(),
124
130
  connectionId: z.string(),
125
- defaultAgent: ChannelAgentConfigSchema.optional()
131
+ defaultAgent: WorkAppSlackAgentConfigRequestSchema.optional()
126
132
  }) } }
127
133
  },
128
134
  404: { description: "Workspace not found" }
@@ -131,19 +137,16 @@ app.openapi(createProtectedRoute({
131
137
  const { teamId } = c.req.valid("param");
132
138
  const workspace = await findWorkspaceConnectionByTeamId(teamId);
133
139
  if (!workspace || !verifyTenantOwnership(c, workspace.tenantId)) return c.json({ error: "Workspace not found" }, 404);
134
- let defaultAgent;
135
- const nangoDefault = await getWorkspaceDefaultAgentFromNango(teamId);
136
- if (nangoDefault) defaultAgent = {
137
- projectId: nangoDefault.projectId,
138
- agentId: nangoDefault.agentId,
139
- agentName: nangoDefault.agentName
140
- };
141
140
  return c.json({
142
141
  teamId: workspace.teamId,
143
142
  teamName: workspace.teamName,
144
143
  tenantId: workspace.tenantId,
145
144
  connectionId: workspace.connectionId,
146
- defaultAgent
145
+ defaultAgent: workspace.defaultAgent ? {
146
+ projectId: workspace.defaultAgent.projectId,
147
+ agentId: workspace.defaultAgent.agentId,
148
+ grantAccessToMembers: workspace.defaultAgent.grantAccessToMembers
149
+ } : void 0
147
150
  });
148
151
  });
149
152
  app.openapi(createProtectedRoute({
@@ -161,7 +164,7 @@ app.openapi(createProtectedRoute({
161
164
  request: { params: z.object({ teamId: z.string() }) },
162
165
  responses: { 200: {
163
166
  description: "Workspace settings",
164
- content: { "application/json": { schema: WorkspaceSettingsSchema } }
167
+ content: { "application/json": { schema: WorkspaceSettingsResponseSchema } }
165
168
  } }
166
169
  }), async (c) => {
167
170
  const { teamId } = c.req.valid("param");
@@ -170,15 +173,11 @@ app.openapi(createProtectedRoute({
170
173
  logger.warn({ teamId }, "Workspace not found or tenant mismatch");
171
174
  return c.json({ defaultAgent: void 0 });
172
175
  }
173
- let defaultAgent;
174
- const nangoDefault = await getWorkspaceDefaultAgentFromNango(teamId);
175
- if (nangoDefault) defaultAgent = {
176
- projectId: nangoDefault.projectId,
177
- agentId: nangoDefault.agentId,
178
- agentName: nangoDefault.agentName,
179
- projectName: nangoDefault.projectName
180
- };
181
- return c.json({ defaultAgent });
176
+ return c.json({ defaultAgent: workspace.defaultAgent ? {
177
+ projectId: workspace.defaultAgent.projectId,
178
+ agentId: workspace.defaultAgent.agentId,
179
+ grantAccessToMembers: workspace.defaultAgent.grantAccessToMembers
180
+ } : void 0 });
182
181
  });
183
182
  app.openapi(createProtectedRoute({
184
183
  method: "put",
@@ -194,31 +193,46 @@ app.openapi(createProtectedRoute({
194
193
  permission: requireWorkspaceAdmin(),
195
194
  request: {
196
195
  params: z.object({ teamId: z.string() }),
197
- body: { content: { "application/json": { schema: WorkspaceSettingsSchema } } }
196
+ body: { content: { "application/json": { schema: WorkspaceSettingsRequestSchema } } }
198
197
  },
199
198
  responses: {
200
199
  200: {
201
200
  description: "Settings updated",
202
201
  content: { "application/json": { schema: z.object({ success: z.boolean() }) } }
203
202
  },
204
- 500: {
205
- description: "Failed to update settings",
206
- content: { "application/json": { schema: z.object({ success: z.boolean() }) } }
207
- }
203
+ 400: { description: "Agent not found" },
204
+ 500: { description: "Failed to update settings" }
208
205
  }
209
206
  }), async (c) => {
210
207
  const { teamId } = c.req.valid("param");
211
208
  const body = c.req.valid("json");
212
209
  if (body.defaultAgent) {
210
+ const workspace = await findWorkspaceConnectionByTeamId(teamId);
211
+ if (!workspace) return c.json({ success: false }, 500);
212
+ let agentName;
213
+ try {
214
+ agentName = await lookupAgentName(workspace.tenantId, body.defaultAgent.projectId, body.defaultAgent.agentId, {
215
+ skipCache: true,
216
+ throwOnError: true
217
+ });
218
+ } catch (error) {
219
+ logger.error({
220
+ error,
221
+ teamId,
222
+ projectId: body.defaultAgent.projectId,
223
+ agentId: body.defaultAgent.agentId
224
+ }, "Agent lookup failed during workspace default validation");
225
+ return c.json({ error: "Unable to validate agent — please try again" }, 503);
226
+ }
227
+ if (!agentName) return c.json({ error: `Agent '${body.defaultAgent.agentId}' not found in project '${body.defaultAgent.projectId}'` }, 400);
213
228
  if (!await setWorkspaceDefaultAgent(teamId, body.defaultAgent)) {
214
- logger.warn({ teamId }, "Failed to persist workspace settings to Nango");
229
+ logger.warn({ teamId }, "Failed to persist workspace settings");
215
230
  return c.json({ success: false }, 500);
216
231
  }
217
232
  logger.info({
218
233
  teamId,
219
- agentId: body.defaultAgent.agentId,
220
- agentName: body.defaultAgent.agentName
221
- }, "Saved workspace default agent to Nango");
234
+ agentId: body.defaultAgent.agentId
235
+ }, "Saved workspace default agent");
222
236
  } else {
223
237
  await setWorkspaceDefaultAgent(teamId, null);
224
238
  logger.info({ teamId }, "Cleared workspace default agent");
@@ -409,7 +423,7 @@ app.openapi(createProtectedRoute({
409
423
  isShared: z.boolean(),
410
424
  memberCount: z.number().optional(),
411
425
  hasAgentConfig: z.boolean(),
412
- agentConfig: ChannelAgentConfigSchema.optional()
426
+ agentConfig: WorkAppSlackAgentConfigRequestSchema.optional()
413
427
  })),
414
428
  nextCursor: z.string().optional()
415
429
  }) } }
@@ -447,7 +461,6 @@ app.openapi(createProtectedRoute({
447
461
  agentConfig: config ? {
448
462
  projectId: config.projectId,
449
463
  agentId: config.agentId,
450
- agentName: config.agentName || void 0,
451
464
  grantAccessToMembers: config.grantAccessToMembers
452
465
  } : void 0
453
466
  };
@@ -484,7 +497,7 @@ app.openapi(createProtectedRoute({
484
497
  description: "Channel settings",
485
498
  content: { "application/json": { schema: z.object({
486
499
  channelId: z.string(),
487
- agentConfig: ChannelAgentConfigSchema.optional()
500
+ agentConfig: WorkAppSlackAgentConfigRequestSchema.optional()
488
501
  }) } }
489
502
  } }
490
503
  }), async (c) => {
@@ -504,7 +517,6 @@ app.openapi(createProtectedRoute({
504
517
  agentConfig: config ? {
505
518
  projectId: config.projectId,
506
519
  agentId: config.agentId,
507
- agentName: config.agentName || void 0,
508
520
  grantAccessToMembers: config.grantAccessToMembers
509
521
  } : void 0
510
522
  });
@@ -527,18 +539,21 @@ app.openapi(createProtectedRoute({
527
539
  channelId: z.string()
528
540
  }),
529
541
  body: { content: { "application/json": { schema: z.object({
530
- agentConfig: ChannelAgentConfigSchema,
542
+ agentConfig: WorkAppSlackAgentConfigRequestSchema,
531
543
  channelName: z.string().optional(),
532
544
  channelType: z.string().optional()
533
545
  }) } } }
534
546
  },
535
- responses: { 200: {
536
- description: "Channel settings updated",
537
- content: { "application/json": { schema: z.object({
538
- success: z.boolean(),
539
- configId: z.string()
540
- }) } }
541
- } }
547
+ responses: {
548
+ 200: {
549
+ description: "Channel settings updated",
550
+ content: { "application/json": { schema: z.object({
551
+ success: z.boolean(),
552
+ configId: z.string()
553
+ }) } }
554
+ },
555
+ 400: { description: "Agent not found" }
556
+ }
542
557
  }), async (c) => {
543
558
  const { teamId, channelId } = c.req.valid("param");
544
559
  const body = c.req.valid("json");
@@ -551,6 +566,23 @@ app.openapi(createProtectedRoute({
551
566
  });
552
567
  }
553
568
  const tenantId = workspace.tenantId;
569
+ let agentName;
570
+ try {
571
+ agentName = await lookupAgentName(tenantId, body.agentConfig.projectId, body.agentConfig.agentId, {
572
+ skipCache: true,
573
+ throwOnError: true
574
+ });
575
+ } catch (error) {
576
+ logger.error({
577
+ error,
578
+ teamId,
579
+ tenantId,
580
+ projectId: body.agentConfig.projectId,
581
+ agentId: body.agentConfig.agentId
582
+ }, "Agent lookup failed during channel config validation");
583
+ return c.json({ error: "Unable to validate agent — please try again" }, 503);
584
+ }
585
+ if (!agentName) return c.json({ error: `Agent '${body.agentConfig.agentId}' not found in project '${body.agentConfig.projectId}'` }, 400);
554
586
  const config = await upsertWorkAppSlackChannelAgentConfig(runDbClient_default)({
555
587
  tenantId,
556
588
  slackTeamId: teamId,
@@ -559,7 +591,6 @@ app.openapi(createProtectedRoute({
559
591
  slackChannelType: body.channelType,
560
592
  projectId: body.agentConfig.projectId,
561
593
  agentId: body.agentConfig.agentId,
562
- agentName: body.agentConfig.agentName,
563
594
  grantAccessToMembers: body.agentConfig.grantAccessToMembers ?? true,
564
595
  enabled: true
565
596
  });
@@ -589,7 +620,7 @@ app.openapi(createProtectedRoute({
589
620
  params: z.object({ teamId: z.string() }),
590
621
  body: { content: { "application/json": { schema: z.object({
591
622
  channelIds: z.array(z.string()).min(1),
592
- agentConfig: ChannelAgentConfigSchema
623
+ agentConfig: WorkAppSlackAgentConfigRequestSchema
593
624
  }) } } }
594
625
  },
595
626
  responses: {
@@ -614,6 +645,23 @@ app.openapi(createProtectedRoute({
614
645
  const workspace = await findWorkspaceConnectionByTeamId(teamId);
615
646
  if (!workspace?.botToken || !verifyTenantOwnership(c, workspace.tenantId)) return c.json({ error: "Workspace not found or no bot token" }, 404);
616
647
  const tenantId = workspace.tenantId;
648
+ let agentName;
649
+ try {
650
+ agentName = await lookupAgentName(tenantId, body.agentConfig.projectId, body.agentConfig.agentId, {
651
+ skipCache: true,
652
+ throwOnError: true
653
+ });
654
+ } catch (error) {
655
+ logger.error({
656
+ error,
657
+ teamId,
658
+ tenantId,
659
+ projectId: body.agentConfig.projectId,
660
+ agentId: body.agentConfig.agentId
661
+ }, "Agent lookup failed during bulk channel config validation");
662
+ return c.json({ error: "Unable to validate agent — please try again" }, 503);
663
+ }
664
+ if (!agentName) return c.json({ error: `Agent '${body.agentConfig.agentId}' not found in project '${body.agentConfig.projectId}'` }, 400);
617
665
  const slackClient = getSlackClient(workspace.botToken);
618
666
  let channels = [];
619
667
  try {
@@ -646,7 +694,6 @@ app.openapi(createProtectedRoute({
646
694
  slackChannelType: "public",
647
695
  projectId: body.agentConfig.projectId,
648
696
  agentId: body.agentConfig.agentId,
649
- agentName: body.agentConfig.agentName,
650
697
  grantAccessToMembers: body.agentConfig.grantAccessToMembers ?? true,
651
698
  enabled: true
652
699
  });
@@ -1,16 +1,18 @@
1
+ import { WorkAppSlackAgentConfigRequest } from "@inkeep/agents-core";
2
+
1
3
  //#region src/slack/services/agent-resolution.d.ts
2
- /**
3
- * Slack Agent Resolution Service
4
- *
5
- * Determines which agent to use for a given Slack interaction.
6
- * Priority: Channel default > Workspace default (all admin-controlled)
7
- */
8
- /** Configuration for a resolved agent */
9
- interface ResolvedAgentConfig {
10
- projectId: string;
11
- projectName?: string;
12
- agentId: string;
4
+
5
+ declare function lookupAgentName(tenantId: string, projectId: string, agentId: string, options?: {
6
+ skipCache?: boolean;
7
+ throwOnError?: boolean;
8
+ }): Promise<string | undefined>;
9
+ declare function lookupProjectName(tenantId: string, projectId: string, options?: {
10
+ skipCache?: boolean;
11
+ }): Promise<string | undefined>;
12
+ /** Configuration for a resolved agent — extends the canonical config with resolution metadata */
13
+ interface ResolvedAgentConfig extends WorkAppSlackAgentConfigRequest {
13
14
  agentName?: string;
15
+ projectName?: string;
14
16
  source: 'channel' | 'workspace' | 'none';
15
17
  grantAccessToMembers: boolean;
16
18
  }
@@ -40,4 +42,4 @@ declare function getAgentConfigSources(params: AgentResolutionParams): Promise<{
40
42
  effective: ResolvedAgentConfig | null;
41
43
  }>;
42
44
  //#endregion
43
- export { AgentResolutionParams, ResolvedAgentConfig, getAgentConfigSources, resolveEffectiveAgent };
45
+ export { AgentResolutionParams, ResolvedAgentConfig, getAgentConfigSources, lookupAgentName, lookupProjectName, resolveEffectiveAgent };
@@ -1,6 +1,6 @@
1
1
  import { getLogger } from "../../logger.js";
2
2
  import runDbClient_default from "../../db/runDbClient.js";
3
- import { getWorkspaceDefaultAgentFromNango } from "./nango.js";
3
+ import { getWorkspaceDefaultAgent } from "./nango.js";
4
4
  import { fetchAgentsForProject, fetchProjectsForTenant } from "./events/utils.js";
5
5
  import { findWorkAppSlackChannelAgentConfig } from "@inkeep/agents-core";
6
6
 
@@ -15,11 +15,13 @@ const logger = getLogger("slack-agent-resolution");
15
15
  const AGENT_NAME_CACHE_TTL_MS = 300 * 1e3;
16
16
  const AGENT_NAME_CACHE_MAX_SIZE = 500;
17
17
  const agentNameCache = /* @__PURE__ */ new Map();
18
- async function lookupAgentName(tenantId, projectId, agentId) {
18
+ async function lookupAgentName(tenantId, projectId, agentId, options) {
19
19
  const cacheKey = `${tenantId}:${projectId}:${agentId}`;
20
- const cached = agentNameCache.get(cacheKey);
21
- if (cached && cached.expiresAt > Date.now()) return cached.name || void 0;
22
- const agents = await fetchAgentsForProject(tenantId, projectId);
20
+ if (!options?.skipCache) {
21
+ const cached = agentNameCache.get(cacheKey);
22
+ if (cached && cached.expiresAt > Date.now()) return cached.name || void 0;
23
+ }
24
+ const agents = await fetchAgentsForProject(tenantId, projectId, { throwOnError: options?.throwOnError });
23
25
  for (const agent of agents) {
24
26
  const key = `${tenantId}:${projectId}:${agent.id}`;
25
27
  agentNameCache.set(key, {
@@ -44,10 +46,12 @@ async function lookupAgentName(tenantId, projectId, agentId) {
44
46
  const PROJECT_NAME_CACHE_TTL_MS = 300 * 1e3;
45
47
  const PROJECT_NAME_CACHE_MAX_SIZE = 200;
46
48
  const projectNameCache = /* @__PURE__ */ new Map();
47
- async function lookupProjectName(tenantId, projectId) {
49
+ async function lookupProjectName(tenantId, projectId, options) {
48
50
  const cacheKey = `${tenantId}:${projectId}`;
49
- const cached = projectNameCache.get(cacheKey);
50
- if (cached && cached.expiresAt > Date.now()) return cached.name || void 0;
51
+ if (!options?.skipCache) {
52
+ const cached = projectNameCache.get(cacheKey);
53
+ if (cached && cached.expiresAt > Date.now()) return cached.name || void 0;
54
+ }
51
55
  const projects = await fetchProjectsForTenant(tenantId);
52
56
  for (const project of projects) {
53
57
  const key = `${tenantId}:${project.id}`;
@@ -96,14 +100,13 @@ async function resolveEffectiveAgent(params) {
96
100
  result = {
97
101
  projectId: channelConfig.projectId,
98
102
  agentId: channelConfig.agentId,
99
- agentName: channelConfig.agentName || void 0,
100
103
  source: "channel",
101
104
  grantAccessToMembers: channelConfig.grantAccessToMembers
102
105
  };
103
106
  }
104
107
  }
105
108
  if (!result) {
106
- const workspaceConfig = await getWorkspaceDefaultAgentFromNango(teamId);
109
+ const workspaceConfig = await getWorkspaceDefaultAgent(teamId);
107
110
  if (workspaceConfig?.agentId && workspaceConfig.projectId) {
108
111
  logger.info({
109
112
  teamId,
@@ -112,25 +115,17 @@ async function resolveEffectiveAgent(params) {
112
115
  }, "Resolved agent from workspace config");
113
116
  result = {
114
117
  projectId: workspaceConfig.projectId,
115
- projectName: workspaceConfig.projectName,
116
118
  agentId: workspaceConfig.agentId,
117
- agentName: workspaceConfig.agentName,
118
119
  source: "workspace",
119
120
  grantAccessToMembers: workspaceConfig.grantAccessToMembers ?? true
120
121
  };
121
122
  }
122
123
  }
123
- if (result && (!result.agentName || result.agentName === result.agentId)) {
124
+ if (result) {
124
125
  const name = await lookupAgentName(tenantId, result.projectId, result.agentId);
125
- if (name) {
126
- result.agentName = name;
127
- logger.debug({
128
- agentId: result.agentId,
129
- agentName: name
130
- }, "Enriched agent config with name from manage API");
131
- }
126
+ if (name) result.agentName = name;
132
127
  }
133
- if (result && !result.projectName) {
128
+ if (result) {
134
129
  const projectName = await lookupProjectName(tenantId, result.projectId);
135
130
  if (projectName) result.projectName = projectName;
136
131
  }
@@ -156,35 +151,29 @@ async function getAgentConfigSources(params) {
156
151
  if (config?.enabled) channelConfig = {
157
152
  projectId: config.projectId,
158
153
  agentId: config.agentId,
159
- agentName: config.agentName || void 0,
160
154
  source: "channel",
161
155
  grantAccessToMembers: config.grantAccessToMembers
162
156
  };
163
157
  }
164
- const wsConfig = await getWorkspaceDefaultAgentFromNango(teamId);
158
+ const wsConfig = await getWorkspaceDefaultAgent(teamId);
165
159
  if (wsConfig?.agentId && wsConfig.projectId) workspaceConfig = {
166
160
  projectId: wsConfig.projectId,
167
- projectName: wsConfig.projectName,
168
161
  agentId: wsConfig.agentId,
169
- agentName: wsConfig.agentName,
170
162
  source: "workspace",
171
163
  grantAccessToMembers: wsConfig.grantAccessToMembers ?? true
172
164
  };
173
- const effective = channelConfig || workspaceConfig;
174
- if (effective && (!effective.agentName || effective.agentName === effective.agentId)) {
175
- const name = await lookupAgentName(tenantId, effective.projectId, effective.agentId);
176
- if (name) effective.agentName = name;
177
- }
178
- if (effective && !effective.projectName) {
179
- const projectName = await lookupProjectName(tenantId, effective.projectId);
180
- if (projectName) effective.projectName = projectName;
181
- }
165
+ const configsToEnrich = [channelConfig, workspaceConfig].filter((c) => c !== null);
166
+ await Promise.all(configsToEnrich.map(async (config) => {
167
+ const [agentName, projectName] = await Promise.all([lookupAgentName(tenantId, config.projectId, config.agentId), lookupProjectName(tenantId, config.projectId)]);
168
+ if (agentName) config.agentName = agentName;
169
+ if (projectName) config.projectName = projectName;
170
+ }));
182
171
  return {
183
172
  channelConfig,
184
173
  workspaceConfig,
185
- effective
174
+ effective: channelConfig || workspaceConfig
186
175
  };
187
176
  }
188
177
 
189
178
  //#endregion
190
- export { getAgentConfigSources, resolveEffectiveAgent };
179
+ export { getAgentConfigSources, lookupAgentName, lookupProjectName, resolveEffectiveAgent };
@@ -1,6 +1,7 @@
1
1
  import { getLogger } from "../../../logger.js";
2
2
  import { findWorkspaceConnectionByTeamId } from "../nango.js";
3
3
  import { classifyError, findCachedUserMapping, formatSlackQuery, generateSlackConversationId, getThreadContext, getUserFriendlyErrorMessage } from "./utils.js";
4
+ import { lookupAgentName } from "../agent-resolution.js";
4
5
  import { SlackStrings } from "../../i18n/strings.js";
5
6
  import { getSlackClient, getSlackUserInfo } from "../client.js";
6
7
  import { SLACK_SPAN_KEYS, SLACK_SPAN_NAMES, setSpanWithError, tracer } from "../../tracer.js";
@@ -53,7 +54,7 @@ async function handleDirectMessage(params) {
53
54
  }
54
55
  span.setAttribute(SLACK_SPAN_KEYS.AGENT_ID, defaultAgent.agentId);
55
56
  span.setAttribute(SLACK_SPAN_KEYS.PROJECT_ID, defaultAgent.projectId);
56
- const agentDisplayName = defaultAgent.agentName || defaultAgent.agentId;
57
+ const agentDisplayName = await lookupAgentName(tenantId, defaultAgent.projectId, defaultAgent.agentId) || defaultAgent.agentId;
57
58
  const [existingLink, userInfo] = await Promise.all([findCachedUserMapping(tenantId, slackUserId, teamId), getSlackUserInfo(slackClient, slackUserId)]);
58
59
  if (!existingLink) {
59
60
  logger.info({
@@ -1,8 +1,8 @@
1
- import { SlackErrorType, checkIfBotThread, classifyError, extractApiErrorMessage, fetchAgentsForProject, fetchProjectsForTenant, findCachedUserMapping, generateSlackConversationId, getChannelAgentConfig, getThreadContext, getUserFriendlyErrorMessage, getWorkspaceDefaultAgent, markdownToMrkdwn, sendResponseUrlMessage } from "./utils.js";
1
+ import { SlackErrorType, checkIfBotThread, classifyError, extractApiErrorMessage, fetchAgentsForProject, fetchProjectsForTenant, findCachedUserMapping, generateSlackConversationId, getChannelAgentConfig, getThreadContext, getUserFriendlyErrorMessage, markdownToMrkdwn, sendResponseUrlMessage } from "./utils.js";
2
2
  import { InlineSelectorMetadata, handleAppMention } from "./app-mention.js";
3
3
  import { handleMessageShortcut, handleOpenAgentSelectorModal, handleToolApproval } from "./block-actions.js";
4
4
  import { handleDirectMessage } from "./direct-message.js";
5
5
  import { StreamResult, streamAgentResponse } from "./streaming.js";
6
6
  import { PublicExecutionParams, executeAgentPublicly } from "./execution.js";
7
7
  import { handleModalSubmission } from "./modal-submission.js";
8
- export { type InlineSelectorMetadata, type PublicExecutionParams, SlackErrorType, type StreamResult, checkIfBotThread, classifyError, executeAgentPublicly, extractApiErrorMessage, fetchAgentsForProject, fetchProjectsForTenant, findCachedUserMapping, generateSlackConversationId, getChannelAgentConfig, getThreadContext, getUserFriendlyErrorMessage, getWorkspaceDefaultAgent, handleAppMention, handleDirectMessage, handleMessageShortcut, handleModalSubmission, handleOpenAgentSelectorModal, handleToolApproval, markdownToMrkdwn, sendResponseUrlMessage, streamAgentResponse };
8
+ export { type InlineSelectorMetadata, type PublicExecutionParams, SlackErrorType, type StreamResult, checkIfBotThread, classifyError, executeAgentPublicly, extractApiErrorMessage, fetchAgentsForProject, fetchProjectsForTenant, findCachedUserMapping, generateSlackConversationId, getChannelAgentConfig, getThreadContext, getUserFriendlyErrorMessage, handleAppMention, handleDirectMessage, handleMessageShortcut, handleModalSubmission, handleOpenAgentSelectorModal, handleToolApproval, markdownToMrkdwn, sendResponseUrlMessage, streamAgentResponse };
@@ -1,4 +1,4 @@
1
- import { SlackErrorType, checkIfBotThread, classifyError, extractApiErrorMessage, fetchAgentsForProject, fetchProjectsForTenant, findCachedUserMapping, generateSlackConversationId, getChannelAgentConfig, getThreadContext, getUserFriendlyErrorMessage, getWorkspaceDefaultAgent, markdownToMrkdwn, sendResponseUrlMessage } from "./utils.js";
1
+ import { SlackErrorType, checkIfBotThread, classifyError, extractApiErrorMessage, fetchAgentsForProject, fetchProjectsForTenant, findCachedUserMapping, generateSlackConversationId, getChannelAgentConfig, getThreadContext, getUserFriendlyErrorMessage, markdownToMrkdwn, sendResponseUrlMessage } from "./utils.js";
2
2
  import { streamAgentResponse } from "./streaming.js";
3
3
  import { executeAgentPublicly } from "./execution.js";
4
4
  import { handleAppMention } from "./app-mention.js";
@@ -6,4 +6,4 @@ import { handleMessageShortcut, handleOpenAgentSelectorModal, handleToolApproval
6
6
  import { handleDirectMessage } from "./direct-message.js";
7
7
  import { handleModalSubmission } from "./modal-submission.js";
8
8
 
9
- export { SlackErrorType, checkIfBotThread, classifyError, executeAgentPublicly, extractApiErrorMessage, fetchAgentsForProject, fetchProjectsForTenant, findCachedUserMapping, generateSlackConversationId, getChannelAgentConfig, getThreadContext, getUserFriendlyErrorMessage, getWorkspaceDefaultAgent, handleAppMention, handleDirectMessage, handleMessageShortcut, handleModalSubmission, handleOpenAgentSelectorModal, handleToolApproval, markdownToMrkdwn, sendResponseUrlMessage, streamAgentResponse };
9
+ export { SlackErrorType, checkIfBotThread, classifyError, executeAgentPublicly, extractApiErrorMessage, fetchAgentsForProject, fetchProjectsForTenant, findCachedUserMapping, generateSlackConversationId, getChannelAgentConfig, getThreadContext, getUserFriendlyErrorMessage, handleAppMention, handleDirectMessage, handleMessageShortcut, handleModalSubmission, handleOpenAgentSelectorModal, handleToolApproval, markdownToMrkdwn, sendResponseUrlMessage, streamAgentResponse };
@@ -1,4 +1,5 @@
1
- import { DefaultAgentConfig, SlackWorkspaceConnection } from "../nango.js";
1
+ import { ResolvedAgentConfig } from "../agent-resolution.js";
2
+ import { SlackWorkspaceConnection } from "../nango.js";
2
3
  import { AgentOption } from "../modals.js";
3
4
 
4
5
  //#region src/slack/services/events/utils.d.ts
@@ -8,12 +9,12 @@ import { AgentOption } from "../modals.js";
8
9
  * Called on every @mention and /inkeep command — caching avoids redundant DB queries.
9
10
  */
10
11
  declare function findCachedUserMapping(tenantId: string, slackUserId: string, teamId: string, clientId?: string): Promise<{
11
- id: string;
12
+ slackUserId: string;
12
13
  createdAt: string;
13
14
  updatedAt: string;
15
+ id: string;
14
16
  tenantId: string;
15
17
  clientId: string;
16
- slackUserId: string;
17
18
  slackTeamId: string;
18
19
  slackEnterpriseId: string | null;
19
20
  inkeepUserId: string;
@@ -69,14 +70,16 @@ type ProjectOption = {
69
70
  name: string;
70
71
  };
71
72
  declare function fetchProjectsForTenant(tenantId: string): Promise<ProjectOption[]>;
72
- declare function fetchAgentsForProject(tenantId: string, projectId: string): Promise<AgentOption[]>;
73
- declare function getWorkspaceDefaultAgent(teamId: string): Promise<DefaultAgentConfig | null>;
74
- declare function getChannelAgentConfig(teamId: string, channelId: string): Promise<DefaultAgentConfig | null>;
73
+ declare function fetchAgentsForProject(tenantId: string, projectId: string, options?: {
74
+ throwOnError?: boolean;
75
+ }): Promise<AgentOption[]>;
76
+ declare function getChannelAgentConfig(teamId: string, channelId: string): Promise<ResolvedAgentConfig | null>;
75
77
  /**
76
78
  * Resolve channel agent config using a pre-resolved workspace connection.
77
79
  * Avoids redundant workspace lookups when the connection is already available.
80
+ * Returns a ResolvedAgentConfig with enriched agent/project names and source metadata.
78
81
  */
79
- declare function resolveChannelAgentConfig(teamId: string, channelId: string, workspace: SlackWorkspaceConnection | null): Promise<DefaultAgentConfig | null>;
82
+ declare function resolveChannelAgentConfig(teamId: string, channelId: string, workspace: SlackWorkspaceConnection | null): Promise<ResolvedAgentConfig | null>;
80
83
  declare function sendResponseUrlMessage(responseUrl: string, message: {
81
84
  text: string;
82
85
  response_type?: 'ephemeral' | 'in_channel';
@@ -191,4 +194,4 @@ interface FormatSlackQueryOptions {
191
194
  }
192
195
  declare function formatSlackQuery(options: FormatSlackQueryOptions): string;
193
196
  //#endregion
194
- export { FormatSlackQueryOptions, ProjectOption, SlackAttachment, SlackErrorType, checkIfBotThread, classifyError, escapeSlackLinkText, escapeSlackMrkdwn, extractApiErrorMessage, fetchAgentsForProject, fetchProjectsForTenant, findCachedUserMapping, formatAttachments, formatChannelContext, formatChannelLabel, formatMessageTimestamp, formatSlackQuery, generateSlackConversationId, getChannelAgentConfig, getThreadContext, getUserFriendlyErrorMessage, getWorkspaceDefaultAgent, markdownToMrkdwn, resolveChannelAgentConfig, sendResponseUrlMessage, timedOp };
197
+ export { FormatSlackQueryOptions, ProjectOption, SlackAttachment, SlackErrorType, checkIfBotThread, classifyError, escapeSlackLinkText, escapeSlackMrkdwn, extractApiErrorMessage, fetchAgentsForProject, fetchProjectsForTenant, findCachedUserMapping, formatAttachments, formatChannelContext, formatChannelLabel, formatMessageTimestamp, formatSlackQuery, generateSlackConversationId, getChannelAgentConfig, getThreadContext, getUserFriendlyErrorMessage, markdownToMrkdwn, resolveChannelAgentConfig, sendResponseUrlMessage, timedOp };
@@ -2,6 +2,7 @@ import { env } from "../../../env.js";
2
2
  import { getLogger } from "../../../logger.js";
3
3
  import runDbClient_default from "../../../db/runDbClient.js";
4
4
  import { findWorkspaceConnectionByTeamId } from "../nango.js";
5
+ import { lookupAgentName, lookupProjectName } from "../agent-resolution.js";
5
6
  import { InternalServices, findWorkAppSlackChannelAgentConfig, findWorkAppSlackUserMapping, generateInternalServiceToken, getInProcessFetch } from "@inkeep/agents-core";
6
7
 
7
8
  //#region src/slack/services/events/utils.ts
@@ -175,7 +176,7 @@ async function fetchProjectsForTenant(tenantId) {
175
176
  clearTimeout(timeout);
176
177
  }
177
178
  }
178
- async function fetchAgentsForProject(tenantId, projectId) {
179
+ async function fetchAgentsForProject(tenantId, projectId, options) {
179
180
  const apiUrl = env.INKEEP_AGENTS_API_URL || "http://localhost:3002";
180
181
  const token = await generateInternalServiceToken({
181
182
  serviceId: InternalServices.INKEEP_AGENTS_MANAGE_API,
@@ -202,6 +203,7 @@ async function fetchAgentsForProject(tenantId, projectId) {
202
203
  projectId,
203
204
  errorBody
204
205
  }, "Failed to fetch agents from API");
206
+ if (options?.throwOnError) throw new Error(`Failed to fetch agents: ${response.status}`);
205
207
  return [];
206
208
  }
207
209
  const result = await response.json();
@@ -222,37 +224,47 @@ async function fetchAgentsForProject(tenantId, projectId) {
222
224
  tenantId,
223
225
  projectId
224
226
  }, "Error fetching agents from API");
227
+ if (options?.throwOnError) throw error;
225
228
  return [];
226
229
  } finally {
227
230
  clearTimeout(timeout);
228
231
  }
229
232
  }
230
- async function getWorkspaceDefaultAgent(teamId) {
231
- const workspace = await findWorkspaceConnectionByTeamId(teamId);
232
- if (workspace?.defaultAgent) {
233
- logger.debug({ teamId }, "Found workspace default agent");
234
- return workspace.defaultAgent;
235
- }
236
- return null;
237
- }
238
233
  async function getChannelAgentConfig(teamId, channelId) {
239
234
  return resolveChannelAgentConfig(teamId, channelId, await findWorkspaceConnectionByTeamId(teamId));
240
235
  }
241
236
  /**
242
237
  * Resolve channel agent config using a pre-resolved workspace connection.
243
238
  * Avoids redundant workspace lookups when the connection is already available.
239
+ * Returns a ResolvedAgentConfig with enriched agent/project names and source metadata.
244
240
  */
245
241
  async function resolveChannelAgentConfig(teamId, channelId, workspace) {
246
242
  const tenantId = workspace?.tenantId;
247
243
  if (!tenantId) return null;
248
244
  const channelConfig = await findWorkAppSlackChannelAgentConfig(runDbClient_default)(tenantId, teamId, channelId);
249
- if (channelConfig?.enabled) return {
250
- projectId: channelConfig.projectId,
251
- agentId: channelConfig.agentId,
252
- agentName: channelConfig.agentName || channelConfig.agentId,
253
- projectName: channelConfig.projectId
254
- };
255
- return workspace?.defaultAgent || null;
245
+ if (channelConfig?.enabled) {
246
+ const [agentName, projectName] = await Promise.all([lookupAgentName(tenantId, channelConfig.projectId, channelConfig.agentId), lookupProjectName(tenantId, channelConfig.projectId)]);
247
+ return {
248
+ projectId: channelConfig.projectId,
249
+ agentId: channelConfig.agentId,
250
+ agentName: agentName || channelConfig.agentId,
251
+ projectName: projectName || channelConfig.projectId,
252
+ source: "channel",
253
+ grantAccessToMembers: channelConfig.grantAccessToMembers
254
+ };
255
+ }
256
+ if (workspace?.defaultAgent) {
257
+ const [agentName, projectName] = await Promise.all([lookupAgentName(tenantId, workspace.defaultAgent.projectId, workspace.defaultAgent.agentId), lookupProjectName(tenantId, workspace.defaultAgent.projectId)]);
258
+ return {
259
+ projectId: workspace.defaultAgent.projectId,
260
+ agentId: workspace.defaultAgent.agentId,
261
+ agentName: agentName || workspace.defaultAgent.agentId,
262
+ projectName: projectName || workspace.defaultAgent.projectId,
263
+ source: "workspace",
264
+ grantAccessToMembers: workspace.defaultAgent.grantAccessToMembers ?? true
265
+ };
266
+ }
267
+ return null;
256
268
  }
257
269
  async function sendResponseUrlMessage(responseUrl, message) {
258
270
  try {
@@ -487,4 +499,4 @@ Respond naturally as if you're joining the conversation to help.`;
487
499
  }
488
500
 
489
501
  //#endregion
490
- export { SlackErrorType, checkIfBotThread, classifyError, escapeSlackLinkText, escapeSlackMrkdwn, extractApiErrorMessage, fetchAgentsForProject, fetchProjectsForTenant, findCachedUserMapping, formatAttachments, formatChannelContext, formatChannelLabel, formatMessageTimestamp, formatSlackQuery, generateSlackConversationId, getChannelAgentConfig, getThreadContext, getUserFriendlyErrorMessage, getWorkspaceDefaultAgent, markdownToMrkdwn, resolveChannelAgentConfig, sendResponseUrlMessage, timedOp };
502
+ export { SlackErrorType, checkIfBotThread, classifyError, escapeSlackLinkText, escapeSlackMrkdwn, extractApiErrorMessage, fetchAgentsForProject, fetchProjectsForTenant, findCachedUserMapping, formatAttachments, formatChannelContext, formatChannelLabel, formatMessageTimestamp, formatSlackQuery, generateSlackConversationId, getChannelAgentConfig, getThreadContext, getUserFriendlyErrorMessage, markdownToMrkdwn, resolveChannelAgentConfig, sendResponseUrlMessage, timedOp };
@@ -1,11 +1,11 @@
1
- import { AgentResolutionParams, ResolvedAgentConfig, getAgentConfigSources, resolveEffectiveAgent } from "./agent-resolution.js";
1
+ import { AgentResolutionParams, ResolvedAgentConfig, getAgentConfigSources, lookupAgentName, lookupProjectName, resolveEffectiveAgent } from "./agent-resolution.js";
2
2
  import { AgentConfigSources, ContextBlockParams, ToolApprovalButtonValue, ToolApprovalButtonValueSchema, buildCitationsBlock, buildDataArtifactBlocks, buildDataComponentBlocks, buildSummaryBreadcrumbBlock, buildToolApprovalBlocks, buildToolApprovalDoneBlocks, buildToolApprovalExpiredBlocks, buildToolOutputErrorBlock, createAlreadyLinkedMessage, createContextBlock, createContextBlockFromText, createCreateInkeepAccountMessage, createErrorMessage, createNotLinkedMessage, createSmartLinkMessage, createStatusMessage, createUnlinkSuccessMessage, createUpdatedHelpMessage } from "./blocks/index.js";
3
3
  import { checkUserIsChannelMember, getBotMemberChannels, getSlackChannelInfo, getSlackChannels, getSlackClient, getSlackTeamInfo, getSlackUserInfo, postMessage, postMessageInThread, revokeSlackToken } from "./client.js";
4
- import { DefaultAgentConfig, SlackWorkspaceConnection, WorkspaceInstallData, clearWorkspaceConnectionCache, computeWorkspaceConnectionId, createConnectSession, deleteWorkspaceInstallation, findWorkspaceConnectionByTeamId, getConnectionAccessToken, getSlackIntegrationId, getSlackNango, getWorkspaceDefaultAgentFromNango, listWorkspaceInstallations, setWorkspaceDefaultAgent, storeWorkspaceInstallation, updateConnectionMetadata } from "./nango.js";
4
+ import { DefaultAgentConfig, SlackWorkspaceConnection, WorkspaceInstallData, clearWorkspaceConnectionCache, computeWorkspaceConnectionId, createConnectSession, deleteWorkspaceInstallation, findWorkspaceConnectionByTeamId, getConnectionAccessToken, getSlackIntegrationId, getSlackNango, getWorkspaceDefaultAgent, getWorkspaceDefaultAgentFromNango, listWorkspaceInstallations, setWorkspaceDefaultAgent, storeWorkspaceInstallation, updateConnectionMetadata } from "./nango.js";
5
5
  import { SlackCommandPayload, SlackCommandResponse } from "./types.js";
6
6
  import { handleAgentPickerCommand, handleCommand, handleHelpCommand, handleLinkCommand, handleQuestionCommand, handleStatusCommand, handleUnlinkCommand } from "./commands/index.js";
7
7
  import { AgentOption, BuildAgentSelectorModalParams, BuildMessageShortcutModalParams, ModalMetadata, buildAgentSelectorModal, buildMessageShortcutModal } from "./modals.js";
8
- import { SlackErrorType, checkIfBotThread, classifyError, extractApiErrorMessage, fetchAgentsForProject, fetchProjectsForTenant, findCachedUserMapping, generateSlackConversationId, getChannelAgentConfig, getThreadContext, getUserFriendlyErrorMessage, getWorkspaceDefaultAgent, markdownToMrkdwn, sendResponseUrlMessage } from "./events/utils.js";
8
+ import { SlackErrorType, checkIfBotThread, classifyError, extractApiErrorMessage, fetchAgentsForProject, fetchProjectsForTenant, findCachedUserMapping, generateSlackConversationId, getChannelAgentConfig, getThreadContext, getUserFriendlyErrorMessage, markdownToMrkdwn, sendResponseUrlMessage } from "./events/utils.js";
9
9
  import { InlineSelectorMetadata, handleAppMention } from "./events/app-mention.js";
10
10
  import { handleMessageShortcut, handleOpenAgentSelectorModal, handleToolApproval } from "./events/block-actions.js";
11
11
  import { handleDirectMessage } from "./events/direct-message.js";
@@ -15,4 +15,4 @@ import { handleModalSubmission } from "./events/modal-submission.js";
15
15
  import "./events/index.js";
16
16
  import { parseSlackCommandBody, parseSlackEventBody, verifySlackRequest } from "./security.js";
17
17
  import { getBotTokenForTeam, setBotTokenForTeam } from "./workspace-tokens.js";
18
- export { AgentConfigSources, AgentOption, AgentResolutionParams, BuildAgentSelectorModalParams, BuildMessageShortcutModalParams, ContextBlockParams, DefaultAgentConfig, InlineSelectorMetadata, ModalMetadata, PublicExecutionParams, ResolvedAgentConfig, SlackCommandPayload, SlackCommandResponse, SlackErrorType, SlackWorkspaceConnection, StreamResult, ToolApprovalButtonValue, ToolApprovalButtonValueSchema, WorkspaceInstallData, buildAgentSelectorModal, buildCitationsBlock, buildDataArtifactBlocks, buildDataComponentBlocks, buildMessageShortcutModal, buildSummaryBreadcrumbBlock, buildToolApprovalBlocks, buildToolApprovalDoneBlocks, buildToolApprovalExpiredBlocks, buildToolOutputErrorBlock, checkIfBotThread, checkUserIsChannelMember, classifyError, clearWorkspaceConnectionCache, computeWorkspaceConnectionId, createAlreadyLinkedMessage, createConnectSession, createContextBlock, createContextBlockFromText, createCreateInkeepAccountMessage, createErrorMessage, createNotLinkedMessage, createSmartLinkMessage, createStatusMessage, createUnlinkSuccessMessage, createUpdatedHelpMessage, deleteWorkspaceInstallation, executeAgentPublicly, extractApiErrorMessage, fetchAgentsForProject, fetchProjectsForTenant, findCachedUserMapping, findWorkspaceConnectionByTeamId, generateSlackConversationId, getAgentConfigSources, getBotMemberChannels, getBotTokenForTeam, getChannelAgentConfig, getConnectionAccessToken, getSlackChannelInfo, getSlackChannels, getSlackClient, getSlackIntegrationId, getSlackNango, getSlackTeamInfo, getSlackUserInfo, getThreadContext, getUserFriendlyErrorMessage, getWorkspaceDefaultAgent, getWorkspaceDefaultAgentFromNango, handleAgentPickerCommand, handleAppMention, handleCommand, handleDirectMessage, handleHelpCommand, handleLinkCommand, handleMessageShortcut, handleModalSubmission, handleOpenAgentSelectorModal, handleQuestionCommand, handleStatusCommand, handleToolApproval, handleUnlinkCommand, listWorkspaceInstallations, markdownToMrkdwn, parseSlackCommandBody, parseSlackEventBody, postMessage, postMessageInThread, resolveEffectiveAgent, revokeSlackToken, sendResponseUrlMessage, setBotTokenForTeam, setWorkspaceDefaultAgent, storeWorkspaceInstallation, streamAgentResponse, updateConnectionMetadata, verifySlackRequest };
18
+ export { AgentConfigSources, AgentOption, AgentResolutionParams, BuildAgentSelectorModalParams, BuildMessageShortcutModalParams, ContextBlockParams, DefaultAgentConfig, InlineSelectorMetadata, ModalMetadata, PublicExecutionParams, ResolvedAgentConfig, SlackCommandPayload, SlackCommandResponse, SlackErrorType, SlackWorkspaceConnection, StreamResult, ToolApprovalButtonValue, ToolApprovalButtonValueSchema, WorkspaceInstallData, buildAgentSelectorModal, buildCitationsBlock, buildDataArtifactBlocks, buildDataComponentBlocks, buildMessageShortcutModal, buildSummaryBreadcrumbBlock, buildToolApprovalBlocks, buildToolApprovalDoneBlocks, buildToolApprovalExpiredBlocks, buildToolOutputErrorBlock, checkIfBotThread, checkUserIsChannelMember, classifyError, clearWorkspaceConnectionCache, computeWorkspaceConnectionId, createAlreadyLinkedMessage, createConnectSession, createContextBlock, createContextBlockFromText, createCreateInkeepAccountMessage, createErrorMessage, createNotLinkedMessage, createSmartLinkMessage, createStatusMessage, createUnlinkSuccessMessage, createUpdatedHelpMessage, deleteWorkspaceInstallation, executeAgentPublicly, extractApiErrorMessage, fetchAgentsForProject, fetchProjectsForTenant, findCachedUserMapping, findWorkspaceConnectionByTeamId, generateSlackConversationId, getAgentConfigSources, getBotMemberChannels, getBotTokenForTeam, getChannelAgentConfig, getConnectionAccessToken, getSlackChannelInfo, getSlackChannels, getSlackClient, getSlackIntegrationId, getSlackNango, getSlackTeamInfo, getSlackUserInfo, getThreadContext, getUserFriendlyErrorMessage, getWorkspaceDefaultAgent, getWorkspaceDefaultAgentFromNango, handleAgentPickerCommand, handleAppMention, handleCommand, handleDirectMessage, handleHelpCommand, handleLinkCommand, handleMessageShortcut, handleModalSubmission, handleOpenAgentSelectorModal, handleQuestionCommand, handleStatusCommand, handleToolApproval, handleUnlinkCommand, listWorkspaceInstallations, lookupAgentName, lookupProjectName, markdownToMrkdwn, parseSlackCommandBody, parseSlackEventBody, postMessage, postMessageInThread, resolveEffectiveAgent, revokeSlackToken, sendResponseUrlMessage, setBotTokenForTeam, setWorkspaceDefaultAgent, storeWorkspaceInstallation, streamAgentResponse, updateConnectionMetadata, verifySlackRequest };
@@ -1,6 +1,6 @@
1
- import { clearWorkspaceConnectionCache, computeWorkspaceConnectionId, createConnectSession, deleteWorkspaceInstallation, findWorkspaceConnectionByTeamId, getConnectionAccessToken, getSlackIntegrationId, getSlackNango, getWorkspaceDefaultAgentFromNango, listWorkspaceInstallations, setWorkspaceDefaultAgent, storeWorkspaceInstallation, updateConnectionMetadata } from "./nango.js";
2
- import { SlackErrorType, checkIfBotThread, classifyError, extractApiErrorMessage, fetchAgentsForProject, fetchProjectsForTenant, findCachedUserMapping, generateSlackConversationId, getChannelAgentConfig, getThreadContext, getUserFriendlyErrorMessage, getWorkspaceDefaultAgent, markdownToMrkdwn, sendResponseUrlMessage } from "./events/utils.js";
3
- import { getAgentConfigSources, resolveEffectiveAgent } from "./agent-resolution.js";
1
+ import { clearWorkspaceConnectionCache, computeWorkspaceConnectionId, createConnectSession, deleteWorkspaceInstallation, findWorkspaceConnectionByTeamId, getConnectionAccessToken, getSlackIntegrationId, getSlackNango, getWorkspaceDefaultAgent, getWorkspaceDefaultAgentFromNango, listWorkspaceInstallations, setWorkspaceDefaultAgent, storeWorkspaceInstallation, updateConnectionMetadata } from "./nango.js";
2
+ import { SlackErrorType, checkIfBotThread, classifyError, extractApiErrorMessage, fetchAgentsForProject, fetchProjectsForTenant, findCachedUserMapping, generateSlackConversationId, getChannelAgentConfig, getThreadContext, getUserFriendlyErrorMessage, markdownToMrkdwn, sendResponseUrlMessage } from "./events/utils.js";
3
+ import { getAgentConfigSources, lookupAgentName, lookupProjectName, resolveEffectiveAgent } from "./agent-resolution.js";
4
4
  import { ToolApprovalButtonValueSchema, buildCitationsBlock, buildDataArtifactBlocks, buildDataComponentBlocks, buildSummaryBreadcrumbBlock, buildToolApprovalBlocks, buildToolApprovalDoneBlocks, buildToolApprovalExpiredBlocks, buildToolOutputErrorBlock, createAlreadyLinkedMessage, createContextBlock, createContextBlockFromText, createCreateInkeepAccountMessage, createErrorMessage, createNotLinkedMessage, createSmartLinkMessage, createStatusMessage, createUnlinkSuccessMessage, createUpdatedHelpMessage } from "./blocks/index.js";
5
5
  import { checkUserIsChannelMember, getBotMemberChannels, getSlackChannelInfo, getSlackChannels, getSlackClient, getSlackTeamInfo, getSlackUserInfo, postMessage, postMessageInThread, revokeSlackToken } from "./client.js";
6
6
  import { streamAgentResponse } from "./events/streaming.js";
@@ -15,4 +15,4 @@ import "./events/index.js";
15
15
  import { parseSlackCommandBody, parseSlackEventBody, verifySlackRequest } from "./security.js";
16
16
  import { getBotTokenForTeam, setBotTokenForTeam } from "./workspace-tokens.js";
17
17
 
18
- export { SlackErrorType, ToolApprovalButtonValueSchema, buildAgentSelectorModal, buildCitationsBlock, buildDataArtifactBlocks, buildDataComponentBlocks, buildMessageShortcutModal, buildSummaryBreadcrumbBlock, buildToolApprovalBlocks, buildToolApprovalDoneBlocks, buildToolApprovalExpiredBlocks, buildToolOutputErrorBlock, checkIfBotThread, checkUserIsChannelMember, classifyError, clearWorkspaceConnectionCache, computeWorkspaceConnectionId, createAlreadyLinkedMessage, createConnectSession, createContextBlock, createContextBlockFromText, createCreateInkeepAccountMessage, createErrorMessage, createNotLinkedMessage, createSmartLinkMessage, createStatusMessage, createUnlinkSuccessMessage, createUpdatedHelpMessage, deleteWorkspaceInstallation, executeAgentPublicly, extractApiErrorMessage, fetchAgentsForProject, fetchProjectsForTenant, findCachedUserMapping, findWorkspaceConnectionByTeamId, generateSlackConversationId, getAgentConfigSources, getBotMemberChannels, getBotTokenForTeam, getChannelAgentConfig, getConnectionAccessToken, getSlackChannelInfo, getSlackChannels, getSlackClient, getSlackIntegrationId, getSlackNango, getSlackTeamInfo, getSlackUserInfo, getThreadContext, getUserFriendlyErrorMessage, getWorkspaceDefaultAgent, getWorkspaceDefaultAgentFromNango, handleAgentPickerCommand, handleAppMention, handleCommand, handleDirectMessage, handleHelpCommand, handleLinkCommand, handleMessageShortcut, handleModalSubmission, handleOpenAgentSelectorModal, handleQuestionCommand, handleStatusCommand, handleToolApproval, handleUnlinkCommand, listWorkspaceInstallations, markdownToMrkdwn, parseSlackCommandBody, parseSlackEventBody, postMessage, postMessageInThread, resolveEffectiveAgent, revokeSlackToken, sendResponseUrlMessage, setBotTokenForTeam, setWorkspaceDefaultAgent, storeWorkspaceInstallation, streamAgentResponse, updateConnectionMetadata, verifySlackRequest };
18
+ export { SlackErrorType, ToolApprovalButtonValueSchema, buildAgentSelectorModal, buildCitationsBlock, buildDataArtifactBlocks, buildDataComponentBlocks, buildMessageShortcutModal, buildSummaryBreadcrumbBlock, buildToolApprovalBlocks, buildToolApprovalDoneBlocks, buildToolApprovalExpiredBlocks, buildToolOutputErrorBlock, checkIfBotThread, checkUserIsChannelMember, classifyError, clearWorkspaceConnectionCache, computeWorkspaceConnectionId, createAlreadyLinkedMessage, createConnectSession, createContextBlock, createContextBlockFromText, createCreateInkeepAccountMessage, createErrorMessage, createNotLinkedMessage, createSmartLinkMessage, createStatusMessage, createUnlinkSuccessMessage, createUpdatedHelpMessage, deleteWorkspaceInstallation, executeAgentPublicly, extractApiErrorMessage, fetchAgentsForProject, fetchProjectsForTenant, findCachedUserMapping, findWorkspaceConnectionByTeamId, generateSlackConversationId, getAgentConfigSources, getBotMemberChannels, getBotTokenForTeam, getChannelAgentConfig, getConnectionAccessToken, getSlackChannelInfo, getSlackChannels, getSlackClient, getSlackIntegrationId, getSlackNango, getSlackTeamInfo, getSlackUserInfo, getThreadContext, getUserFriendlyErrorMessage, getWorkspaceDefaultAgent, getWorkspaceDefaultAgentFromNango, handleAgentPickerCommand, handleAppMention, handleCommand, handleDirectMessage, handleHelpCommand, handleLinkCommand, handleMessageShortcut, handleModalSubmission, handleOpenAgentSelectorModal, handleQuestionCommand, handleStatusCommand, handleToolApproval, handleUnlinkCommand, listWorkspaceInstallations, lookupAgentName, lookupProjectName, markdownToMrkdwn, parseSlackCommandBody, parseSlackEventBody, postMessage, postMessageInThread, resolveEffectiveAgent, revokeSlackToken, sendResponseUrlMessage, setBotTokenForTeam, setWorkspaceDefaultAgent, storeWorkspaceInstallation, streamAgentResponse, updateConnectionMetadata, verifySlackRequest };
@@ -1,5 +1,5 @@
1
1
  import { SlackLinkIntent } from "@inkeep/agents-core";
2
- import * as slack_block_builder7 from "slack-block-builder";
2
+ import * as slack_block_builder0 from "slack-block-builder";
3
3
 
4
4
  //#region src/slack/services/link-prompt.d.ts
5
5
  type LinkPromptResult = {
@@ -22,6 +22,6 @@ interface ResolveLinkActionParams {
22
22
  intent?: SlackLinkIntent;
23
23
  }
24
24
  declare function resolveUnlinkedUserAction(params: ResolveLinkActionParams): Promise<LinkPromptResult>;
25
- declare function buildLinkPromptMessage(result: LinkPromptResult): Readonly<slack_block_builder7.SlackMessageDto>;
25
+ declare function buildLinkPromptMessage(result: LinkPromptResult): Readonly<slack_block_builder0.SlackMessageDto>;
26
26
  //#endregion
27
27
  export { LinkPromptResult, ResolveLinkActionParams, buildLinkPromptMessage, resolveUnlinkedUserAction };
@@ -1,3 +1,4 @@
1
+ import { WorkAppSlackAgentConfigRequest } from "@inkeep/agents-core";
1
2
  import { Nango } from "@nangohq/node";
2
3
 
3
4
  //#region src/slack/services/nango.d.ts
@@ -13,13 +14,7 @@ declare function createConnectSession(params: {
13
14
  sessionToken: string;
14
15
  } | null>;
15
16
  declare function getConnectionAccessToken(connectionId: string): Promise<string | null>;
16
- interface DefaultAgentConfig {
17
- agentId: string;
18
- agentName?: string;
19
- projectId: string;
20
- projectName?: string;
21
- grantAccessToMembers?: boolean;
22
- }
17
+ type DefaultAgentConfig = WorkAppSlackAgentConfigRequest;
23
18
  interface SlackWorkspaceConnection {
24
19
  connectionId: string;
25
20
  teamId: string;
@@ -42,7 +37,9 @@ declare function findWorkspaceConnectionByTeamId(teamId: string): Promise<SlackW
42
37
  declare function clearWorkspaceConnectionCache(teamId?: string): void;
43
38
  declare function updateConnectionMetadata(connectionId: string, metadata: Record<string, string>): Promise<boolean>;
44
39
  declare function setWorkspaceDefaultAgent(teamId: string, defaultAgent: DefaultAgentConfig | null): Promise<boolean>;
45
- declare function getWorkspaceDefaultAgentFromNango(teamId: string): Promise<DefaultAgentConfig | null>;
40
+ declare function getWorkspaceDefaultAgent(teamId: string): Promise<DefaultAgentConfig | null>;
41
+ /** @deprecated Use `getWorkspaceDefaultAgent` instead */
42
+ declare const getWorkspaceDefaultAgentFromNango: typeof getWorkspaceDefaultAgent;
46
43
  /**
47
44
  * Compute a stable, deterministic connection ID for a Slack workspace.
48
45
  * Format: "T:<team_id>" or "E:<enterprise_id>:T:<team_id>" for Enterprise Grid
@@ -78,12 +75,13 @@ declare function storeWorkspaceInstallation(data: WorkspaceInstallData): Promise
78
75
  success: boolean;
79
76
  }>;
80
77
  /**
81
- * List all workspace installations from Nango.
78
+ * List all workspace installations for a tenant.
79
+ * Reads workspace metadata from PostgreSQL and retrieves bot tokens from Nango.
82
80
  */
83
- declare function listWorkspaceInstallations(): Promise<SlackWorkspaceConnection[]>;
81
+ declare function listWorkspaceInstallations(tenantId: string): Promise<SlackWorkspaceConnection[]>;
84
82
  /**
85
83
  * Delete a workspace installation from Nango.
86
84
  */
87
85
  declare function deleteWorkspaceInstallation(connectionId: string): Promise<boolean>;
88
86
  //#endregion
89
- export { DefaultAgentConfig, SlackWorkspaceConnection, WorkspaceInstallData, clearWorkspaceConnectionCache, computeWorkspaceConnectionId, createConnectSession, deleteWorkspaceInstallation, findWorkspaceConnectionByTeamId, getConnectionAccessToken, getSlackIntegrationId, getSlackNango, getWorkspaceDefaultAgentFromNango, listWorkspaceInstallations, setWorkspaceDefaultAgent, storeWorkspaceInstallation, updateConnectionMetadata };
87
+ export { DefaultAgentConfig, SlackWorkspaceConnection, WorkspaceInstallData, clearWorkspaceConnectionCache, computeWorkspaceConnectionId, createConnectSession, deleteWorkspaceInstallation, findWorkspaceConnectionByTeamId, getConnectionAccessToken, getSlackIntegrationId, getSlackNango, getWorkspaceDefaultAgent, getWorkspaceDefaultAgentFromNango, listWorkspaceInstallations, setWorkspaceDefaultAgent, storeWorkspaceInstallation, updateConnectionMetadata };
@@ -2,7 +2,7 @@ import { env } from "../../env.js";
2
2
  import { getLogger } from "../../logger.js";
3
3
  import runDbClient_default from "../../db/runDbClient.js";
4
4
  import { getDevDefaultAgent, isSlackDevMode, loadSlackDevConfig, saveSlackDevConfig } from "./dev-config.js";
5
- import { findWorkAppSlackWorkspaceBySlackTeamId, retryWithBackoff } from "@inkeep/agents-core";
5
+ import { findWorkAppSlackWorkspaceBySlackTeamId, listWorkAppSlackWorkspacesByTenant, retryWithBackoff, updateWorkAppSlackWorkspace } from "@inkeep/agents-core";
6
6
  import { Nango } from "@nangohq/node";
7
7
 
8
8
  //#region src/slack/services/nango.ts
@@ -17,7 +17,6 @@ import { Nango } from "@nangohq/node";
17
17
  * Nango is used ONLY for:
18
18
  * - OAuth token storage and refresh (bot tokens for workspaces)
19
19
  * - OAuth flow management (createConnectSession)
20
- * - Workspace default agent config (stored in connection metadata)
21
20
  *
22
21
  * PERFORMANCE: Workspace lookups use PostgreSQL first (O(1)), with Nango
23
22
  * fallback only when needed for bot token retrieval.
@@ -146,16 +145,19 @@ async function findWorkspaceConnectionByTeamId(teamId) {
146
145
  if (dbWorkspace?.nangoConnectionId) {
147
146
  const botToken = await getConnectionAccessToken(dbWorkspace.nangoConnectionId);
148
147
  if (botToken) {
148
+ const defaultAgent = dbWorkspace.defaultAgentId && dbWorkspace.defaultProjectId ? {
149
+ agentId: dbWorkspace.defaultAgentId,
150
+ projectId: dbWorkspace.defaultProjectId,
151
+ grantAccessToMembers: dbWorkspace.defaultGrantAccessToMembers ?? true
152
+ } : void 0;
149
153
  const connection = {
150
154
  connectionId: dbWorkspace.nangoConnectionId,
151
155
  teamId,
152
156
  teamName: dbWorkspace.slackTeamName || void 0,
153
157
  botToken,
154
158
  tenantId: dbWorkspace.tenantId,
155
- defaultAgent: void 0
159
+ defaultAgent
156
160
  };
157
- const defaultAgentConfig = await getWorkspaceDefaultAgentFromNangoByConnectionId(dbWorkspace.nangoConnectionId);
158
- if (defaultAgentConfig) connection.defaultAgent = defaultAgentConfig;
159
161
  evictWorkspaceCache();
160
162
  workspaceConnectionCache.set(teamId, {
161
163
  connection,
@@ -175,23 +177,6 @@ async function findWorkspaceConnectionByTeamId(teamId) {
175
177
  return findWorkspaceConnectionByTeamIdFromNango(teamId);
176
178
  }
177
179
  }
178
- async function getWorkspaceDefaultAgentFromNangoByConnectionId(connectionId) {
179
- if (isSlackDevMode()) return getDevDefaultAgent(loadSlackDevConfig());
180
- try {
181
- const nango = getSlackNango();
182
- const integrationId = getSlackIntegrationId();
183
- const metadata = (await nango.getConnection(integrationId, connectionId)).metadata;
184
- if (metadata?.default_agent) try {
185
- return JSON.parse(metadata.default_agent);
186
- } catch {
187
- return null;
188
- }
189
- return null;
190
- } catch (error) {
191
- logger.warn({ error }, "Failed to get workspace default agent from Nango");
192
- return null;
193
- }
194
- }
195
180
  /**
196
181
  * Legacy fallback: Find workspace by iterating all Nango connections.
197
182
  * Only used when PostgreSQL lookup fails.
@@ -207,17 +192,13 @@ async function findWorkspaceConnectionByTeamIdFromNango(teamId) {
207
192
  const metadata = fullConn.metadata;
208
193
  const credentials = fullConn;
209
194
  if ((connectionConfig?.["team.id"] || metadata?.slack_team_id) === teamId && credentials.credentials?.access_token) {
210
- let defaultAgent;
211
- if (metadata?.default_agent) try {
212
- defaultAgent = JSON.parse(metadata.default_agent);
213
- } catch {}
214
195
  const connection = {
215
196
  connectionId: conn.connection_id,
216
197
  teamId,
217
198
  teamName: metadata?.slack_team_name,
218
199
  botToken: credentials.credentials.access_token,
219
200
  tenantId: metadata?.tenant_id || metadata?.inkeep_tenant_id || "",
220
- defaultAgent
201
+ defaultAgent: void 0
221
202
  };
222
203
  evictWorkspaceCache();
223
204
  workspaceConnectionCache.set(teamId, {
@@ -276,23 +257,32 @@ async function setWorkspaceDefaultAgent(teamId, defaultAgent) {
276
257
  if (isSlackDevMode()) {
277
258
  const devConfig = loadSlackDevConfig();
278
259
  if (!devConfig) return false;
260
+ const persistedDevAgent = defaultAgent ? {
261
+ agentId: defaultAgent.agentId,
262
+ projectId: defaultAgent.projectId,
263
+ grantAccessToMembers: defaultAgent.grantAccessToMembers
264
+ } : null;
279
265
  devConfig.metadata = {
280
266
  ...devConfig.metadata,
281
- default_agent: defaultAgent ? JSON.stringify(defaultAgent) : ""
267
+ default_agent: persistedDevAgent ? JSON.stringify(persistedDevAgent) : ""
282
268
  };
283
269
  const saved = saveSlackDevConfig(devConfig);
284
270
  if (saved) clearWorkspaceConnectionCache(teamId);
285
271
  return saved;
286
272
  }
287
273
  try {
288
- const workspace = await findWorkspaceConnectionByTeamId(teamId);
289
- if (!workspace) {
290
- logger.warn({ teamId }, "No workspace connection found to set default agent");
274
+ const dbWorkspace = await findWorkAppSlackWorkspaceBySlackTeamId(runDbClient_default)(teamId);
275
+ if (!dbWorkspace) {
276
+ logger.warn({ teamId }, "No workspace found in DB to set default agent");
291
277
  return false;
292
278
  }
293
- const success = await updateConnectionMetadata(workspace.connectionId, { default_agent: defaultAgent ? JSON.stringify(defaultAgent) : "" });
294
- if (success) clearWorkspaceConnectionCache(teamId);
295
- return success;
279
+ const updated = await updateWorkAppSlackWorkspace(runDbClient_default)(dbWorkspace.id, {
280
+ defaultAgentId: defaultAgent?.agentId ?? null,
281
+ defaultProjectId: defaultAgent?.projectId ?? null,
282
+ defaultGrantAccessToMembers: defaultAgent?.grantAccessToMembers ?? null
283
+ });
284
+ if (updated) clearWorkspaceConnectionCache(teamId);
285
+ return !!updated;
296
286
  } catch (error) {
297
287
  logger.error({
298
288
  error,
@@ -301,10 +291,16 @@ async function setWorkspaceDefaultAgent(teamId, defaultAgent) {
301
291
  return false;
302
292
  }
303
293
  }
304
- async function getWorkspaceDefaultAgentFromNango(teamId) {
294
+ async function getWorkspaceDefaultAgent(teamId) {
305
295
  if (isSlackDevMode()) return getDevDefaultAgent(loadSlackDevConfig());
306
296
  try {
307
- return (await findWorkspaceConnectionByTeamId(teamId))?.defaultAgent || null;
297
+ const dbWorkspace = await findWorkAppSlackWorkspaceBySlackTeamId(runDbClient_default)(teamId);
298
+ if (!dbWorkspace?.defaultAgentId || !dbWorkspace.defaultProjectId) return null;
299
+ return {
300
+ agentId: dbWorkspace.defaultAgentId,
301
+ projectId: dbWorkspace.defaultProjectId,
302
+ grantAccessToMembers: dbWorkspace.defaultGrantAccessToMembers ?? true
303
+ };
308
304
  } catch (error) {
309
305
  logger.error({
310
306
  error,
@@ -313,6 +309,8 @@ async function getWorkspaceDefaultAgentFromNango(teamId) {
313
309
  return null;
314
310
  }
315
311
  }
312
+ /** @deprecated Use `getWorkspaceDefaultAgent` instead */
313
+ const getWorkspaceDefaultAgentFromNango = getWorkspaceDefaultAgent;
316
314
  /**
317
315
  * Compute a stable, deterministic connection ID for a Slack workspace.
318
316
  * Format: "T:<team_id>" or "E:<enterprise_id>:T:<team_id>" for Enterprise Grid
@@ -447,9 +445,10 @@ async function storeWorkspaceInstallation(data) {
447
445
  }
448
446
  }
449
447
  /**
450
- * List all workspace installations from Nango.
448
+ * List all workspace installations for a tenant.
449
+ * Reads workspace metadata from PostgreSQL and retrieves bot tokens from Nango.
451
450
  */
452
- async function listWorkspaceInstallations() {
451
+ async function listWorkspaceInstallations(tenantId) {
453
452
  if (isSlackDevMode()) {
454
453
  const devConfig = loadSlackDevConfig();
455
454
  if (!devConfig) return [];
@@ -463,38 +462,31 @@ async function listWorkspaceInstallations() {
463
462
  }];
464
463
  }
465
464
  try {
466
- const nango = getSlackNango();
467
- const integrationId = getSlackIntegrationId();
468
- const connections = await nango.listConnections();
465
+ const dbWorkspaces = await listWorkAppSlackWorkspacesByTenant(runDbClient_default)(tenantId);
469
466
  const workspaces = [];
470
- for (const conn of connections.connections) if (conn.provider_config_key === integrationId) try {
471
- const fullConn = await nango.getConnection(integrationId, conn.connection_id);
472
- const metadata = fullConn.metadata;
473
- const credentials = fullConn;
474
- if (metadata?.connection_type === "workspace" && credentials.credentials?.access_token) {
475
- let defaultAgent;
476
- if (metadata?.default_agent) try {
477
- defaultAgent = JSON.parse(metadata.default_agent);
478
- } catch {}
479
- workspaces.push({
480
- connectionId: conn.connection_id,
481
- teamId: metadata.slack_team_id || "",
482
- teamName: metadata.slack_team_name,
483
- teamDomain: metadata.slack_team_domain || void 0,
484
- botToken: credentials.credentials.access_token,
485
- tenantId: metadata.tenant_id || metadata.inkeep_tenant_id || "",
486
- defaultAgent
487
- });
488
- }
489
- } catch (error) {
490
- logger.warn({
491
- error,
492
- connectionId: conn.connection_id
493
- }, "Failed to get Nango connection during list");
494
- }
467
+ await Promise.all(dbWorkspaces.map(async (ws) => {
468
+ const botToken = await getConnectionAccessToken(ws.nangoConnectionId);
469
+ if (!botToken) return;
470
+ const defaultAgent = ws.defaultAgentId && ws.defaultProjectId ? {
471
+ agentId: ws.defaultAgentId,
472
+ projectId: ws.defaultProjectId,
473
+ grantAccessToMembers: ws.defaultGrantAccessToMembers ?? true
474
+ } : void 0;
475
+ workspaces.push({
476
+ connectionId: ws.nangoConnectionId,
477
+ teamId: ws.slackTeamId,
478
+ teamName: ws.slackTeamName || void 0,
479
+ botToken,
480
+ tenantId: ws.tenantId,
481
+ defaultAgent
482
+ });
483
+ }));
495
484
  return workspaces;
496
485
  } catch (error) {
497
- logger.error({ error }, "Failed to list workspace installations");
486
+ logger.error({
487
+ error,
488
+ tenantId
489
+ }, "Failed to list workspace installations");
498
490
  return [];
499
491
  }
500
492
  }
@@ -534,4 +526,4 @@ async function deleteWorkspaceInstallation(connectionId) {
534
526
  }
535
527
 
536
528
  //#endregion
537
- export { clearWorkspaceConnectionCache, computeWorkspaceConnectionId, createConnectSession, deleteWorkspaceInstallation, findWorkspaceConnectionByTeamId, getConnectionAccessToken, getSlackIntegrationId, getSlackNango, getWorkspaceDefaultAgentFromNango, listWorkspaceInstallations, setWorkspaceDefaultAgent, storeWorkspaceInstallation, updateConnectionMetadata };
529
+ export { clearWorkspaceConnectionCache, computeWorkspaceConnectionId, createConnectSession, deleteWorkspaceInstallation, findWorkspaceConnectionByTeamId, getConnectionAccessToken, getSlackIntegrationId, getSlackNango, getWorkspaceDefaultAgent, getWorkspaceDefaultAgentFromNango, listWorkspaceInstallations, setWorkspaceDefaultAgent, storeWorkspaceInstallation, updateConnectionMetadata };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inkeep/agents-work-apps",
3
- "version": "0.53.13",
3
+ "version": "0.54.0",
4
4
  "description": "First party integrations for Inkeep Agents",
5
5
  "type": "module",
6
6
  "license": "SEE LICENSE IN LICENSE.md",
@@ -33,7 +33,7 @@
33
33
  "jose": "^6.1.0",
34
34
  "minimatch": "^10.2.1",
35
35
  "slack-block-builder": "^2.8.0",
36
- "@inkeep/agents-core": "0.53.13"
36
+ "@inkeep/agents-core": "0.54.0"
37
37
  },
38
38
  "peerDependencies": {
39
39
  "@hono/zod-openapi": "^1.1.5",