@inkeep/agents-work-apps 0.53.13 → 0.55.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/github/mcp/index.d.ts +2 -2
- package/dist/github/mcp/schemas.d.ts +1 -1
- package/dist/github/routes/setup.d.ts +2 -2
- package/dist/slack/index.d.ts +2 -2
- package/dist/slack/index.js +2 -2
- package/dist/slack/routes/workspaces.js +112 -65
- package/dist/slack/services/agent-resolution.d.ts +14 -12
- package/dist/slack/services/agent-resolution.js +25 -36
- package/dist/slack/services/events/direct-message.js +2 -1
- package/dist/slack/services/events/index.d.ts +2 -2
- package/dist/slack/services/events/index.js +2 -2
- package/dist/slack/services/events/utils.d.ts +11 -8
- package/dist/slack/services/events/utils.js +29 -17
- package/dist/slack/services/index.d.ts +4 -4
- package/dist/slack/services/index.js +4 -4
- package/dist/slack/services/link-prompt.d.ts +2 -2
- package/dist/slack/services/nango.d.ts +9 -11
- package/dist/slack/services/nango.js +60 -68
- package/package.json +2 -2
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { Hono } from "hono";
|
|
2
|
-
import * as
|
|
2
|
+
import * as hono_types7 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
|
-
},
|
|
9
|
+
}, hono_types7.BlankSchema, "/">;
|
|
10
10
|
//#endregion
|
|
11
11
|
export { app as default };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Hono } from "hono";
|
|
2
|
-
import * as
|
|
2
|
+
import * as hono_types5 from "hono/types";
|
|
3
3
|
|
|
4
4
|
//#region src/github/routes/setup.d.ts
|
|
5
|
-
declare const app: Hono<
|
|
5
|
+
declare const app: Hono<hono_types5.BlankEnv, hono_types5.BlankSchema, "/">;
|
|
6
6
|
//#endregion
|
|
7
7
|
export { app as default };
|
package/dist/slack/index.d.ts
CHANGED
|
@@ -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
|
|
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";
|
package/dist/slack/index.js
CHANGED
|
@@ -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
|
|
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,
|
|
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
|
|
44
|
-
|
|
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 =
|
|
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
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
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:
|
|
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:
|
|
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
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
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:
|
|
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
|
-
|
|
205
|
-
|
|
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
|
|
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
|
-
|
|
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:
|
|
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:
|
|
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:
|
|
542
|
+
agentConfig: WorkAppSlackAgentConfigRequestSchema,
|
|
531
543
|
channelName: z.string().optional(),
|
|
532
544
|
channelType: z.string().optional()
|
|
533
545
|
}) } } }
|
|
534
546
|
},
|
|
535
|
-
responses: {
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
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:
|
|
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
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
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 {
|
|
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
|
-
|
|
21
|
-
|
|
22
|
-
|
|
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
|
-
|
|
50
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
174
|
-
|
|
175
|
-
const
|
|
176
|
-
if (
|
|
177
|
-
|
|
178
|
-
|
|
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.
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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 {
|
|
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
|
-
|
|
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
|
|
73
|
-
|
|
74
|
-
|
|
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<
|
|
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,
|
|
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)
|
|
250
|
-
projectId
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
|
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<
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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:
|
|
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
|
|
289
|
-
if (!
|
|
290
|
-
logger.warn({ teamId }, "No workspace
|
|
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
|
|
294
|
-
|
|
295
|
-
|
|
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
|
|
294
|
+
async function getWorkspaceDefaultAgent(teamId) {
|
|
305
295
|
if (isSlackDevMode()) return getDevDefaultAgent(loadSlackDevConfig());
|
|
306
296
|
try {
|
|
307
|
-
|
|
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
|
|
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
|
|
467
|
-
const integrationId = getSlackIntegrationId();
|
|
468
|
-
const connections = await nango.listConnections();
|
|
465
|
+
const dbWorkspaces = await listWorkAppSlackWorkspacesByTenant(runDbClient_default)(tenantId);
|
|
469
466
|
const workspaces = [];
|
|
470
|
-
|
|
471
|
-
const
|
|
472
|
-
|
|
473
|
-
const
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
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({
|
|
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.
|
|
3
|
+
"version": "0.55.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.
|
|
36
|
+
"@inkeep/agents-core": "0.55.0"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
39
|
"@hono/zod-openapi": "^1.1.5",
|