* Build user-scoped tools for a voice call, matching the web chat tool set. * This gives voice Addie the same capabilities as chat Addie.
( userId: string, threadId: string, )
| 201 | * This gives voice Addie the same capabilities as chat Addie. |
| 202 | */ |
| 203 | async function buildVoiceRequestTools( |
| 204 | userId: string, |
| 205 | threadId: string, |
| 206 | ): Promise<{ requestTools: RequestTools; requestContext: string; memberContext: MemberContext | null }> { |
| 207 | let memberContext: MemberContext | null = null; |
| 208 | try { |
| 209 | memberContext = await getWebMemberContext(userId); |
| 210 | } catch (error) { |
| 211 | logger.warn({ error, userId }, "Tavus: Failed to get member context"); |
| 212 | } |
| 213 | |
| 214 | // Format member context for system prompt |
| 215 | const contextSections: string[] = []; |
| 216 | if (memberContext) { |
| 217 | const memberContextText = formatMemberContextForPrompt(memberContext, 'web'); |
| 218 | if (memberContextText) contextSections.push(memberContextText); |
| 219 | } |
| 220 | |
| 221 | // Resolve linked Slack identity early — needed by escalation, collaboration, and committee tools |
| 222 | const linkedSlackUserId = memberContext?.slack_user?.slack_user_id; |
| 223 | |
| 224 | // Build per-request tools (mirrors addie-chat.ts prepareRequestWithMemberTools) |
| 225 | const allTools = [...MEMBER_TOOLS, ...SI_HOST_TOOLS, ...ADCP_TOOLS, ...ESCALATION_TOOLS, ...BILLING_TOOLS]; |
| 226 | const combinedHandlers = new Map([ |
| 227 | ...createMemberToolHandlers(memberContext), |
| 228 | ...createSiHostToolHandlers(() => memberContext, () => threadId), |
| 229 | ...createAdcpToolHandlers(memberContext), |
| 230 | ...createEscalationToolHandlers(memberContext, linkedSlackUserId, threadId), |
| 231 | ...createBillingToolHandlers(memberContext), |
| 232 | ]); |
| 233 | |
| 234 | // Schema tools |
| 235 | allTools.push(...SCHEMA_TOOLS); |
| 236 | for (const [name, handler] of createSchemaToolHandlers()) { |
| 237 | combinedHandlers.set(name, handler); |
| 238 | } |
| 239 | |
| 240 | // Property tools |
| 241 | allTools.push(...PROPERTY_TOOLS); |
| 242 | for (const [name, handler] of createPropertyToolHandlers()) { |
| 243 | combinedHandlers.set(name, handler); |
| 244 | } |
| 245 | |
| 246 | // Permission-gated tools |
| 247 | const workingGroupDb = new WorkingGroupDatabase(); |
| 248 | const [userIsAdmin, ledGroups] = await Promise.all([ |
| 249 | isWebUserAAOAdmin(userId), |
| 250 | workingGroupDb.getCommitteesLedByUser(userId), |
| 251 | ]); |
| 252 | |
| 253 | // Event tools: readonly for all users, admin tools for admins only |
| 254 | const eventHandlers = createEventToolHandlers(memberContext); |
| 255 | allTools.push(...EVENT_READONLY_TOOLS); |
| 256 | for (const tool of EVENT_READONLY_TOOLS) { |
| 257 | const handler = eventHandlers.get(tool.name); |
| 258 | if (handler) combinedHandlers.set(tool.name, handler); |
| 259 | } |
| 260 |
no test coverage detected