feat: communication spine — gateway, TUI, Discord (#61)
Co-authored-by: Jason Woltje <jason@diversecanvas.com> Co-committed-by: Jason Woltje <jason@diversecanvas.com>
This commit was merged in pull request #61.
This commit is contained in:
75
apps/gateway/src/chat/chat.controller.ts
Normal file
75
apps/gateway/src/chat/chat.controller.ts
Normal file
@@ -0,0 +1,75 @@
|
||||
import { Controller, Post, Body, Logger, HttpException, HttpStatus } from '@nestjs/common';
|
||||
import type { AgentSessionEvent } from '@mariozechner/pi-coding-agent';
|
||||
import { AgentService } from '../agent/agent.service.js';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
|
||||
interface ChatRequest {
|
||||
conversationId?: string;
|
||||
content: string;
|
||||
}
|
||||
|
||||
interface ChatResponse {
|
||||
conversationId: string;
|
||||
text: string;
|
||||
}
|
||||
|
||||
@Controller('api/chat')
|
||||
export class ChatController {
|
||||
private readonly logger = new Logger(ChatController.name);
|
||||
|
||||
constructor(private readonly agentService: AgentService) {}
|
||||
|
||||
@Post()
|
||||
async chat(@Body() body: ChatRequest): Promise<ChatResponse> {
|
||||
const conversationId = body.conversationId ?? uuid();
|
||||
|
||||
try {
|
||||
let agentSession = this.agentService.getSession(conversationId);
|
||||
if (!agentSession) {
|
||||
agentSession = await this.agentService.createSession(conversationId);
|
||||
}
|
||||
} catch (err) {
|
||||
this.logger.error(
|
||||
`Session creation failed for conversation=${conversationId}`,
|
||||
err instanceof Error ? err.stack : String(err),
|
||||
);
|
||||
throw new HttpException('Agent session unavailable', HttpStatus.SERVICE_UNAVAILABLE);
|
||||
}
|
||||
|
||||
let responseText = '';
|
||||
|
||||
const done = new Promise<void>((resolve, reject) => {
|
||||
const timer = setTimeout(() => {
|
||||
cleanup();
|
||||
this.logger.error(`Agent response timed out after 120s for conversation=${conversationId}`);
|
||||
reject(new Error('Agent response timed out'));
|
||||
}, 120_000);
|
||||
|
||||
const cleanup = this.agentService.onEvent(conversationId, (event: AgentSessionEvent) => {
|
||||
if (event.type === 'message_update' && event.assistantMessageEvent.type === 'text_delta') {
|
||||
responseText += event.assistantMessageEvent.delta;
|
||||
}
|
||||
if (event.type === 'agent_end') {
|
||||
clearTimeout(timer);
|
||||
cleanup();
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
try {
|
||||
await this.agentService.prompt(conversationId, body.content);
|
||||
await done;
|
||||
} catch (err) {
|
||||
if (err instanceof HttpException) throw err;
|
||||
const message = err instanceof Error ? err.message : String(err);
|
||||
if (message.includes('timed out')) {
|
||||
throw new HttpException('Agent response timed out', HttpStatus.GATEWAY_TIMEOUT);
|
||||
}
|
||||
this.logger.error(`Chat prompt failed for conversation=${conversationId}`, String(err));
|
||||
throw new HttpException('Agent processing failed', HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
return { conversationId, text: responseText };
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user