feat(conversation): integrate ClaudeAgentServiceV2 for consulting workflow
- Switch ConversationService to use ClaudeAgentServiceV2 - Pass consultingState and deviceInfo from conversation to context - Handle state_update chunks and save updated state to database - Move dotenv to dependencies for migration runtime Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
c0a9710943
commit
9f2bdee8d9
|
|
@ -29,6 +29,7 @@
|
||||||
"@nestjs/websockets": "^10.0.0",
|
"@nestjs/websockets": "^10.0.0",
|
||||||
"class-transformer": "^0.5.1",
|
"class-transformer": "^0.5.1",
|
||||||
"class-validator": "^0.14.0",
|
"class-validator": "^0.14.0",
|
||||||
|
"dotenv": "^16.3.0",
|
||||||
"ioredis": "^5.3.0",
|
"ioredis": "^5.3.0",
|
||||||
"kafkajs": "^2.2.4",
|
"kafkajs": "^2.2.4",
|
||||||
"pg": "^8.11.0",
|
"pg": "^8.11.0",
|
||||||
|
|
@ -45,7 +46,6 @@
|
||||||
"@types/node": "^20.10.0",
|
"@types/node": "^20.10.0",
|
||||||
"@types/socket.io": "^3.0.2",
|
"@types/socket.io": "^3.0.2",
|
||||||
"@types/uuid": "^9.0.0",
|
"@types/uuid": "^9.0.0",
|
||||||
"dotenv": "^16.3.0",
|
|
||||||
"jest": "^29.7.0",
|
"jest": "^29.7.0",
|
||||||
"ts-jest": "^29.1.0",
|
"ts-jest": "^29.1.0",
|
||||||
"ts-node": "^10.9.0",
|
"ts-node": "^10.9.0",
|
||||||
|
|
|
||||||
|
|
@ -11,10 +11,10 @@ import {
|
||||||
MessageType,
|
MessageType,
|
||||||
} from '../domain/entities/message.entity';
|
} from '../domain/entities/message.entity';
|
||||||
import {
|
import {
|
||||||
ClaudeAgentService,
|
ClaudeAgentServiceV2,
|
||||||
ConversationContext,
|
ConversationContext,
|
||||||
StreamChunk,
|
StreamChunk,
|
||||||
} from '../infrastructure/claude/claude-agent.service';
|
} from '../infrastructure/claude/claude-agent-v2.service';
|
||||||
|
|
||||||
export interface CreateConversationDto {
|
export interface CreateConversationDto {
|
||||||
userId: string;
|
userId: string;
|
||||||
|
|
@ -45,7 +45,7 @@ export class ConversationService {
|
||||||
private conversationRepo: Repository<ConversationEntity>,
|
private conversationRepo: Repository<ConversationEntity>,
|
||||||
@InjectRepository(MessageEntity)
|
@InjectRepository(MessageEntity)
|
||||||
private messageRepo: Repository<MessageEntity>,
|
private messageRepo: Repository<MessageEntity>,
|
||||||
private claudeAgentService: ClaudeAgentService,
|
private claudeAgentService: ClaudeAgentServiceV2,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -134,7 +134,7 @@ export class ConversationService {
|
||||||
take: 20, // Last 20 messages for context
|
take: 20, // Last 20 messages for context
|
||||||
});
|
});
|
||||||
|
|
||||||
// Build context with support for multimodal messages
|
// Build context with support for multimodal messages and consulting state (V2)
|
||||||
const context: ConversationContext = {
|
const context: ConversationContext = {
|
||||||
userId: dto.userId,
|
userId: dto.userId,
|
||||||
conversationId: dto.conversationId,
|
conversationId: dto.conversationId,
|
||||||
|
|
@ -149,11 +149,15 @@ export class ConversationService {
|
||||||
}
|
}
|
||||||
return msg;
|
return msg;
|
||||||
}),
|
}),
|
||||||
|
// V2: Pass consulting state from conversation (cast through unknown for JSON/Date compatibility)
|
||||||
|
consultingState: conversation.consultingState as unknown as ConversationContext['consultingState'],
|
||||||
|
deviceInfo: conversation.deviceInfo,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Collect full response for saving
|
// Collect full response for saving
|
||||||
let fullResponse = '';
|
let fullResponse = '';
|
||||||
const toolCalls: Array<{ name: string; input: unknown; result: unknown }> = [];
|
const toolCalls: Array<{ name: string; input: unknown; result: unknown }> = [];
|
||||||
|
let updatedState: ConversationContext['consultingState'] | undefined;
|
||||||
|
|
||||||
// Stream response from Claude (with attachments for multimodal support)
|
// Stream response from Claude (with attachments for multimodal support)
|
||||||
for await (const chunk of this.claudeAgentService.sendMessage(
|
for await (const chunk of this.claudeAgentService.sendMessage(
|
||||||
|
|
@ -174,11 +178,27 @@ export class ConversationService {
|
||||||
if (lastToolCall) {
|
if (lastToolCall) {
|
||||||
lastToolCall.result = chunk.toolResult;
|
lastToolCall.result = chunk.toolResult;
|
||||||
}
|
}
|
||||||
|
} else if (chunk.type === 'state_update' && chunk.newState) {
|
||||||
|
// V2: Capture updated consulting state
|
||||||
|
updatedState = chunk.newState;
|
||||||
}
|
}
|
||||||
|
|
||||||
yield chunk;
|
yield chunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// V2: Save updated consulting state to conversation
|
||||||
|
if (updatedState) {
|
||||||
|
// Convert state to JSON-compatible format for database storage
|
||||||
|
const stateForDb = JSON.parse(JSON.stringify(updatedState));
|
||||||
|
await this.conversationRepo.update(conversation.id, {
|
||||||
|
consultingState: stateForDb,
|
||||||
|
consultingStage: updatedState.currentStageId,
|
||||||
|
collectedInfo: stateForDb.collectedInfo,
|
||||||
|
recommendedPrograms: updatedState.assessmentResult?.recommendedPrograms,
|
||||||
|
conversionPath: updatedState.conversionPath,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Save assistant response
|
// Save assistant response
|
||||||
const assistantMessage = this.messageRepo.create({
|
const assistantMessage = this.messageRepo.create({
|
||||||
conversationId: dto.conversationId,
|
conversationId: dto.conversationId,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue