fix(agent): pass sessionId to system prompt for text chat OAuth trigger

Text sessions were not passing sessionId to SystemPromptBuilder, causing
Claude to use the `initiate_dingtalk_binding` custom tool (claude_api only).
When the engine is claude_agent_sdk, this tool does not exist → 404.

Fix: pass session.id as sessionId to systemPromptBuilder.build() in
agent.controller.ts. Claude will now use the wget oauth-trigger endpoint
for ALL session types (text and voice), which works with every engine.

Also: store userId (staffId) as the DingTalk binding ID when resolvable,
falling back to openId. Bot messages deliver senderStaffId which matches
userId, not openId — this prevents the "binding not found" routing failure.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
hailin 2026-03-08 14:20:58 -07:00
parent 3ca3982c28
commit 495407d25b
2 changed files with 15 additions and 3 deletions

View File

@ -256,11 +256,19 @@ export class DingTalkRouterService implements OnModuleInit, OnModuleDestroy {
const instance = await this.instanceRepo.findById(entry.instanceId);
if (!instance) throw new Error('智能体实例不存在');
// Store openId — this matches senderId in incoming bot messages (used for routing)
instance.dingTalkUserId = openId;
// Store userId (staffId) as the binding identifier if resolved — this matches senderStaffId
// in incoming DingTalk bot messages, enabling correct routing.
// Fall back to openId if userId could not be resolved (routing may still work if
// DingTalk delivers openId in senderId for this app type).
const bindingId = userId ?? openId;
instance.dingTalkUserId = bindingId;
await this.instanceRepo.save(instance);
this.logger.log(`OAuth binding saved: instance ${entry.instanceId} → dingTalkUserId(openId)=${openId}`);
this.logger.log(
`OAuth binding saved: instance ${entry.instanceId} → dingTalkUserId=${bindingId} ` +
`(${userId ? 'staffId/userId' : 'openId fallback — staffId not resolved'})`,
);
// Send proactive greeting using userId (staffId). Skip if not resolved.
this.sendGreeting(userId, openId, instance.name).catch((e: Error) =>

View File

@ -146,6 +146,10 @@ export class AgentController {
tenantId,
userId,
userEmail,
// Pass session ID so Claude uses the wget oauth-trigger endpoint (works for ALL engine types).
// The oauth-trigger endpoint emits an oauth_prompt WS event to this session's stream,
// which Flutter's chat page handles the same way as voice sessions.
sessionId: session.id,
});
// Fire-and-forget: run the task stream