fix: reply in user's thread and prevent git credential hangs

Pass thread name through Add-ons response wrapper so bot replies stay
in the user's thread instead of posting top-level messages. Add
GIT_TERMINAL_PROMPT=0 to Dockerfile to prevent git from hanging on
credential prompts, which was blocking all requests under concurrency=1.
This commit is contained in:
Adam Weidman
2026-02-12 17:36:58 -05:00
parent 60b01761b8
commit 03ef280120
5 changed files with 20 additions and 5 deletions

View File

@@ -22,6 +22,9 @@ USER node
ENV CODER_AGENT_WORKSPACE_PATH=/workspace
ENV CODER_AGENT_PORT=8080
ENV NODE_ENV=production
# Prevent git from prompting for credentials interactively — fails fast instead of hanging
ENV GIT_TERMINAL_PROMPT=0
ENV CODER_AGENT_HOST=0.0.0.0
EXPOSE 8080

View File

@@ -162,7 +162,7 @@ export class ChatBridgeHandler {
this.sessionStore.updateTaskId(threadName, newTaskId);
const threadKey = message.thread.threadKey || threadName;
return renderResponse(response, threadKey);
return renderResponse(response, threadKey, threadName);
} catch (error) {
const errorMsg =
error instanceof Error ? error.message : 'Unknown error';
@@ -205,7 +205,7 @@ export class ChatBridgeHandler {
// Convert A2A response to Chat format
const threadKey = message.thread.threadKey || threadName;
return renderResponse(response, threadKey);
return renderResponse(response, threadKey, threadName);
} catch (error) {
const errorMsg = error instanceof Error ? error.message : 'Unknown error';
logger.error(`[ChatBridge] Error handling message: ${errorMsg}`, error);

View File

@@ -71,6 +71,7 @@ export function extractToolApprovals(
export function renderResponse(
response: A2AResponse,
threadKey?: string,
threadName?: string,
): ChatResponse {
const parts = extractAllParts(response);
const textContent = extractTextFromParts(parts);
@@ -145,8 +146,10 @@ export function renderResponse(
chatResponse.cardsV2 = cards;
}
if (threadKey) {
chatResponse.thread = { threadKey };
if (threadKey || threadName) {
chatResponse.thread = {};
if (threadKey) chatResponse.thread.threadKey = threadKey;
if (threadName) chatResponse.thread.name = threadName;
}
// Ensure we always return something

View File

@@ -253,6 +253,15 @@ function wrapAddOnsResponse(response: ChatResponse): Record<string, unknown> {
if (response.cardsV2) {
message['cardsV2'] = response.cardsV2;
}
// Include thread info so the reply goes to the user's thread
// instead of appearing as a top-level message
if (response.thread) {
const thread: Record<string, string> = {};
if (response.thread.name) thread['name'] = response.thread.name;
if (response.thread.threadKey)
thread['threadKey'] = response.thread.threadKey;
message['thread'] = thread;
}
// For action responses (like CARD_CLICKED acknowledgments), use updateMessageAction
if (response.actionResponse?.type === 'UPDATE_MESSAGE') {

View File

@@ -121,7 +121,7 @@ export interface ChatOnClick {
export interface ChatResponse {
text?: string;
cardsV2?: ChatCardV2[];
thread?: { threadKey: string };
thread?: { threadKey?: string; name?: string };
actionResponse?: {
type: 'NEW_MESSAGE' | 'UPDATE_MESSAGE' | 'REQUEST_CONFIG';
};