From e61de49743dba807f513aad5b3ddd26513b92dbc Mon Sep 17 00:00:00 2001
From: Matt Rubens <2600+mrubens@users.noreply.github.com>
Date: Tue, 28 Jul 2026 19:40:10 +0000
Subject: [PATCH 1/4] fix(cloud-agents): quote web follow-ups on GitHub
---
.../server/__tests__/github-message-instructions.test.ts | 6 ++++++
.../cloud-agents/src/server/github-message-instructions.ts | 1 +
2 files changed, 7 insertions(+)
diff --git a/packages/cloud-agents/src/server/__tests__/github-message-instructions.test.ts b/packages/cloud-agents/src/server/__tests__/github-message-instructions.test.ts
index b1fb3fedd..866e6d8d8 100644
--- a/packages/cloud-agents/src/server/__tests__/github-message-instructions.test.ts
+++ b/packages/cloud-agents/src/server/__tests__/github-message-instructions.test.ts
@@ -23,6 +23,12 @@ describe('GitHub message instructions', () => {
expect(instructions).toContain(
'For lightweight clarification, satisfy the `input_needed` milestone on GitHub.',
);
+ expect(instructions).toContain(
+ 'begin the next GitHub reply with a Markdown blockquote of that follow-up',
+ );
+ expect(instructions).toContain('not injected out-of-band context');
+ expect(instructions).toContain('keep it to 280 characters');
+ expect(instructions).toContain('public-reply policy prohibits disclosing');
expect(instructions).toContain('plain GitHub issue');
});
});
diff --git a/packages/cloud-agents/src/server/github-message-instructions.ts b/packages/cloud-agents/src/server/github-message-instructions.ts
index 0e2f1ba96..5ec900e53 100644
--- a/packages/cloud-agents/src/server/github-message-instructions.ts
+++ b/packages/cloud-agents/src/server/github-message-instructions.ts
@@ -9,6 +9,7 @@ export function buildGitHubMessageInstructions(): string {
For that non-actionable mention case, leave one brief GitHub reply on the same conversation surface if a reply is still useful, then conclude with a no-op result.
Do not treat short verification asks such as "is this addressed?" or "did we fix everything from the last round?" as no-op; those are actionable follow-up.
Keep GitHub replies brief, relevant to the request, and free of internal reasoning or raw logs.
+ When answering a follow-up sent from the web UI, begin the next GitHub reply with a Markdown blockquote of that follow-up so other participants can see what the reply addresses. Use the user's message only, not injected out-of-band context; keep it to 280 characters. Omit or summarize any portion that the public-reply policy prohibits disclosing.
If the active workflow already owns a dedicated GitHub comment lifecycle, let that workflow satisfy the relevant communication milestones instead of duplicating generic thread updates.
For lightweight clarification, satisfy the \`input_needed\` milestone on GitHub. Use \`request_user_input\` only when the task needs structured or private input outside the public thread.
From 5957d7ed11d5baf58a445d125e9ff1a42f66b9aa Mon Sep 17 00:00:00 2001
From: Daniel Riccio <57051444+daniel-lxs@users.noreply.github.com>
Date: Tue, 28 Jul 2026 20:02:41 +0000
Subject: [PATCH 2/4] fix: mark web follow-ups in task prompts
---
.../src/trpc/commands/sandbox-session/index.ts | 15 ++++++++++++---
.../commands/sandbox-session/send-prompt.test.ts | 12 ++++++------
.../__tests__/github-message-instructions.test.ts | 1 +
.../src/server/github-message-instructions.ts | 2 +-
4 files changed, 20 insertions(+), 10 deletions(-)
diff --git a/apps/web/src/trpc/commands/sandbox-session/index.ts b/apps/web/src/trpc/commands/sandbox-session/index.ts
index fd3f505bc..e11d560e5 100644
--- a/apps/web/src/trpc/commands/sandbox-session/index.ts
+++ b/apps/web/src/trpc/commands/sandbox-session/index.ts
@@ -72,6 +72,10 @@ function getAuthenticatedPromptUserName(
);
}
+function buildModelVisibleWebPrompt(prompt: string): string {
+ return `\n${prompt}\n`;
+}
+
async function assertSandboxRpcEndpointReachable(sandboxServerUrl: string) {
const controller = new AbortController();
const timeoutId = setTimeout(
@@ -296,11 +300,16 @@ export async function sendSandboxPromptCommand(
],
});
+ const prompt =
+ parsed.source === 'web' && typeof parsed.prompt === 'string'
+ ? buildModelVisibleWebPrompt(parsed.prompt)
+ : parsed.prompt;
+
return await client.commands.sendPrompt.mutate({
prompt:
- outOfBandContext && typeof parsed.prompt === 'string'
- ? withOutOfBandContext(outOfBandContext, parsed.prompt)
- : parsed.prompt,
+ outOfBandContext && typeof prompt === 'string'
+ ? withOutOfBandContext(outOfBandContext, prompt)
+ : prompt,
quoteText: parsed.prompt,
taskTool: parsed.taskTool,
images: parsed.images,
diff --git a/apps/web/src/trpc/commands/sandbox-session/send-prompt.test.ts b/apps/web/src/trpc/commands/sandbox-session/send-prompt.test.ts
index c1607cd26..27297fca4 100644
--- a/apps/web/src/trpc/commands/sandbox-session/send-prompt.test.ts
+++ b/apps/web/src/trpc/commands/sandbox-session/send-prompt.test.ts
@@ -150,7 +150,7 @@ describe('sendSandboxPromptCommand', () => {
expect(mockSendPromptMutate).toHaveBeenCalledWith(
expect.objectContaining({
- prompt: 'keep going',
+ prompt: '\nkeep going\n',
quoteText: 'keep going',
source: 'web',
userName: 'Auth Fallback Name',
@@ -183,7 +183,7 @@ describe('sendSandboxPromptCommand', () => {
expect(mockSendPromptMutate).toHaveBeenCalledWith(
expect.objectContaining({
prompt:
- '\nnotice\n\n\nPlease fix it.',
+ '\nnotice\n\n\n\nPlease fix it.\n',
quoteText: 'Please fix it.',
}),
);
@@ -217,7 +217,7 @@ describe('sendSandboxPromptCommand', () => {
expect(mockSendPromptMutate).toHaveBeenCalledWith(
expect.objectContaining({
- prompt: 'change direction',
+ prompt: '\nchange direction\n',
autoSteerWhenQueued: true,
}),
);
@@ -255,7 +255,7 @@ describe('sendSandboxPromptCommand', () => {
expect(mockSendPromptMutate).toHaveBeenCalledWith(
expect.objectContaining({
- prompt: 'keep going',
+ prompt: '\nkeep going\n',
source: 'web',
userName: 'casey',
}),
@@ -335,7 +335,7 @@ describe('sendSandboxPromptCommand', () => {
expect(updatedRun?.actingUserId).toBe(user.id);
expect(mockSendPromptMutate).toHaveBeenCalledWith(
expect.objectContaining({
- prompt: 'keep going',
+ prompt: '\nkeep going\n',
// Actor handoffs steer so the previous actor's turn does not keep
// running after the credential identity changes.
autoSteerWhenQueued: true,
@@ -370,7 +370,7 @@ describe('sendSandboxPromptCommand', () => {
expect(mockSendPromptMutate).toHaveBeenCalledWith(
expect.objectContaining({
- prompt: 'keep going',
+ prompt: '\nkeep going\n',
autoSteerWhenQueued: undefined,
}),
);
diff --git a/packages/cloud-agents/src/server/__tests__/github-message-instructions.test.ts b/packages/cloud-agents/src/server/__tests__/github-message-instructions.test.ts
index 866e6d8d8..068b5159a 100644
--- a/packages/cloud-agents/src/server/__tests__/github-message-instructions.test.ts
+++ b/packages/cloud-agents/src/server/__tests__/github-message-instructions.test.ts
@@ -26,6 +26,7 @@ describe('GitHub message instructions', () => {
expect(instructions).toContain(
'begin the next GitHub reply with a Markdown blockquote of that follow-up',
);
+ expect(instructions).toContain('');
expect(instructions).toContain('not injected out-of-band context');
expect(instructions).toContain('keep it to 280 characters');
expect(instructions).toContain('public-reply policy prohibits disclosing');
diff --git a/packages/cloud-agents/src/server/github-message-instructions.ts b/packages/cloud-agents/src/server/github-message-instructions.ts
index 5ec900e53..4719bf598 100644
--- a/packages/cloud-agents/src/server/github-message-instructions.ts
+++ b/packages/cloud-agents/src/server/github-message-instructions.ts
@@ -9,7 +9,7 @@ export function buildGitHubMessageInstructions(): string {
For that non-actionable mention case, leave one brief GitHub reply on the same conversation surface if a reply is still useful, then conclude with a no-op result.
Do not treat short verification asks such as "is this addressed?" or "did we fix everything from the last round?" as no-op; those are actionable follow-up.
Keep GitHub replies brief, relevant to the request, and free of internal reasoning or raw logs.
- When answering a follow-up sent from the web UI, begin the next GitHub reply with a Markdown blockquote of that follow-up so other participants can see what the reply addresses. Use the user's message only, not injected out-of-band context; keep it to 280 characters. Omit or summarize any portion that the public-reply policy prohibits disclosing.
+ When answering a , begin the next GitHub reply with a Markdown blockquote of that follow-up so other participants can see what the reply addresses. Use only the message inside that boundary, not injected out-of-band context; keep it to 280 characters. Omit or summarize any portion that the public-reply policy prohibits disclosing.
If the active workflow already owns a dedicated GitHub comment lifecycle, let that workflow satisfy the relevant communication milestones instead of duplicating generic thread updates.
For lightweight clarification, satisfy the \`input_needed\` milestone on GitHub. Use \`request_user_input\` only when the task needs structured or private input outside the public thread.
From dfe9de54620446ae4808dc827f4f6784cfa1c8e2 Mon Sep 17 00:00:00 2001
From: Daniel Riccio <57051444+daniel-lxs@users.noreply.github.com>
Date: Tue, 28 Jul 2026 21:06:14 +0000
Subject: [PATCH 3/4] fix: quote web replies in GitHub comments
---
.../src/handlers/tasks/manageSourceControl.ts | 79 ++++++++++++++++---
.../trpc/commands/sandbox-session/index.ts | 34 +++++---
.../sandbox-session/send-prompt.test.ts | 12 +--
.../github-message-instructions.test.ts | 7 --
.../src/server/github-message-instructions.ts | 1 -
.../src/__tests__/messages.test.ts | 18 +++++
packages/communication/src/messages.ts | 16 ++--
7 files changed, 121 insertions(+), 46 deletions(-)
diff --git a/apps/api/src/handlers/tasks/manageSourceControl.ts b/apps/api/src/handlers/tasks/manageSourceControl.ts
index c7ce752f5..58b7d6a37 100644
--- a/apps/api/src/handlers/tasks/manageSourceControl.ts
+++ b/apps/api/src/handlers/tasks/manageSourceControl.ts
@@ -1,6 +1,11 @@
import type { Context } from 'hono';
import type { ContentfulStatusCode } from 'hono/utils/http-status';
import { z } from 'zod';
+import {
+ clearLatestUserMessageForReplyQuoteIfId,
+ getLatestUserMessageForReplyQuote,
+} from '@roomote/communication/messages';
+import { resolveSourceControlProviderFromPayload } from '@roomote/types';
import {
createOrUpdateSourceControlPullRequestForTaskRun,
@@ -27,6 +32,27 @@ import {
} from '../mcp/proxy-utils';
import { logHandlerError } from '../utils';
+const GITHUB_REPLY_QUOTE_MAX_LENGTH = 280;
+
+function formatGitHubReplyQuote(params: {
+ userName: string;
+ text: string;
+}): string | null {
+ const userName = params.userName.replace(/\s+/g, ' ').trim();
+ const text = params.text.trim();
+
+ if (!userName || !text) {
+ return null;
+ }
+
+ const truncated =
+ text.length <= GITHUB_REPLY_QUOTE_MAX_LENGTH
+ ? text
+ : `${text.slice(0, GITHUB_REPLY_QUOTE_MAX_LENGTH - 3).trimEnd()}...`;
+
+ return `> **${userName}:** ${truncated.replaceAll('\n', '\n> ')}`;
+}
+
/**
* POST /api/mcp/tasks/:taskId/source_control
*
@@ -66,6 +92,35 @@ export async function manageSourceControl(
runId: auth.authContext.runId,
taskId,
});
+ const isGitHubTask =
+ resolveSourceControlProviderFromPayload(taskRun.payload) === 'github';
+ const bodyInput = 'body' in input ? input : null;
+ const shouldQuote =
+ isGitHubTask &&
+ (input.action === 'reply_to_pull_request_comment' ||
+ input.action === 'create_pull_request_comment' ||
+ input.action === 'create_issue_comment') &&
+ typeof bodyInput?.body === 'string';
+ const pendingQuote = shouldQuote
+ ? await getLatestUserMessageForReplyQuote('github', taskRun.id)
+ : null;
+
+ if (pendingQuote && typeof bodyInput?.body === 'string') {
+ const quote = formatGitHubReplyQuote(pendingQuote);
+ if (quote) {
+ bodyInput.body = `${quote}\n\n${bodyInput.body}`;
+ }
+ }
+
+ const clearQuoteAfterSuccess = async () => {
+ if (pendingQuote) {
+ await clearLatestUserMessageForReplyQuoteIfId(
+ 'github',
+ taskRun.id,
+ pendingQuote.id,
+ );
+ }
+ };
switch (input.action) {
case 'create_or_update_pull_request':
@@ -89,21 +144,21 @@ export async function manageSourceControl(
case 'resolve_pull_request_thread':
case 'submit_pull_request_review':
case 'update_pull_request_comment':
- return c.json(
- await writeSourceControlPullRequestForTaskRun({
- taskRun,
- input,
- }),
- );
+ const writeResult = await writeSourceControlPullRequestForTaskRun({
+ taskRun,
+ input,
+ });
+ await clearQuoteAfterSuccess();
+ return c.json(writeResult);
case 'get_issue':
case 'list_issue_comments':
case 'create_issue_comment':
- return c.json(
- await manageSourceControlIssueForTaskRun({
- taskRun,
- input,
- }),
- );
+ const issueResult = await manageSourceControlIssueForTaskRun({
+ taskRun,
+ input,
+ });
+ await clearQuoteAfterSuccess();
+ return c.json(issueResult);
}
} catch (error) {
if (error instanceof z.ZodError) {
diff --git a/apps/web/src/trpc/commands/sandbox-session/index.ts b/apps/web/src/trpc/commands/sandbox-session/index.ts
index e11d560e5..82928fc61 100644
--- a/apps/web/src/trpc/commands/sandbox-session/index.ts
+++ b/apps/web/src/trpc/commands/sandbox-session/index.ts
@@ -5,9 +5,11 @@ import {
getEnvironmentDefinitionIdFromPayload,
isBootingRunStatus,
isExitedRunStatus,
+ resolveSourceControlProviderFromPayload,
taskToolDispatchPayloadSchema,
} from '@roomote/types';
import { createRunToken } from '@roomote/auth';
+import { trackLatestUserMessageForReplyQuote } from '@roomote/communication/messages';
import {
and,
compareAndSetTrustedRunActingUser,
@@ -72,10 +74,6 @@ function getAuthenticatedPromptUserName(
);
}
-function buildModelVisibleWebPrompt(prompt: string): string {
- return `\n${prompt}\n`;
-}
-
async function assertSandboxRpcEndpointReachable(sandboxServerUrl: string) {
const controller = new AbortController();
const timeoutId = setTimeout(
@@ -300,16 +298,11 @@ export async function sendSandboxPromptCommand(
],
});
- const prompt =
- parsed.source === 'web' && typeof parsed.prompt === 'string'
- ? buildModelVisibleWebPrompt(parsed.prompt)
- : parsed.prompt;
-
- return await client.commands.sendPrompt.mutate({
+ const result = await client.commands.sendPrompt.mutate({
prompt:
- outOfBandContext && typeof prompt === 'string'
- ? withOutOfBandContext(outOfBandContext, prompt)
- : prompt,
+ outOfBandContext && typeof parsed.prompt === 'string'
+ ? withOutOfBandContext(outOfBandContext, parsed.prompt)
+ : parsed.prompt,
quoteText: parsed.prompt,
taskTool: parsed.taskTool,
images: parsed.images,
@@ -323,6 +316,21 @@ export async function sendSandboxPromptCommand(
? true
: parsed.autoSteerWhenQueued,
});
+
+ if (
+ parsed.source === 'web' &&
+ typeof parsed.prompt === 'string' &&
+ resolveSourceControlProviderFromPayload(taskRun.payload) === 'github'
+ ) {
+ await trackLatestUserMessageForReplyQuote({
+ provider: 'github',
+ runId: taskRun.id,
+ text: parsed.prompt,
+ userName: getAuthenticatedPromptUserName(auth) ?? 'Someone',
+ });
+ }
+
+ return result;
} catch (error) {
await releaseOutOfBandContext(outOfBandContext);
diff --git a/apps/web/src/trpc/commands/sandbox-session/send-prompt.test.ts b/apps/web/src/trpc/commands/sandbox-session/send-prompt.test.ts
index 27297fca4..c1607cd26 100644
--- a/apps/web/src/trpc/commands/sandbox-session/send-prompt.test.ts
+++ b/apps/web/src/trpc/commands/sandbox-session/send-prompt.test.ts
@@ -150,7 +150,7 @@ describe('sendSandboxPromptCommand', () => {
expect(mockSendPromptMutate).toHaveBeenCalledWith(
expect.objectContaining({
- prompt: '\nkeep going\n',
+ prompt: 'keep going',
quoteText: 'keep going',
source: 'web',
userName: 'Auth Fallback Name',
@@ -183,7 +183,7 @@ describe('sendSandboxPromptCommand', () => {
expect(mockSendPromptMutate).toHaveBeenCalledWith(
expect.objectContaining({
prompt:
- '\nnotice\n\n\n\nPlease fix it.\n',
+ '\nnotice\n\n\nPlease fix it.',
quoteText: 'Please fix it.',
}),
);
@@ -217,7 +217,7 @@ describe('sendSandboxPromptCommand', () => {
expect(mockSendPromptMutate).toHaveBeenCalledWith(
expect.objectContaining({
- prompt: '\nchange direction\n',
+ prompt: 'change direction',
autoSteerWhenQueued: true,
}),
);
@@ -255,7 +255,7 @@ describe('sendSandboxPromptCommand', () => {
expect(mockSendPromptMutate).toHaveBeenCalledWith(
expect.objectContaining({
- prompt: '\nkeep going\n',
+ prompt: 'keep going',
source: 'web',
userName: 'casey',
}),
@@ -335,7 +335,7 @@ describe('sendSandboxPromptCommand', () => {
expect(updatedRun?.actingUserId).toBe(user.id);
expect(mockSendPromptMutate).toHaveBeenCalledWith(
expect.objectContaining({
- prompt: '\nkeep going\n',
+ prompt: 'keep going',
// Actor handoffs steer so the previous actor's turn does not keep
// running after the credential identity changes.
autoSteerWhenQueued: true,
@@ -370,7 +370,7 @@ describe('sendSandboxPromptCommand', () => {
expect(mockSendPromptMutate).toHaveBeenCalledWith(
expect.objectContaining({
- prompt: '\nkeep going\n',
+ prompt: 'keep going',
autoSteerWhenQueued: undefined,
}),
);
diff --git a/packages/cloud-agents/src/server/__tests__/github-message-instructions.test.ts b/packages/cloud-agents/src/server/__tests__/github-message-instructions.test.ts
index 068b5159a..b1fb3fedd 100644
--- a/packages/cloud-agents/src/server/__tests__/github-message-instructions.test.ts
+++ b/packages/cloud-agents/src/server/__tests__/github-message-instructions.test.ts
@@ -23,13 +23,6 @@ describe('GitHub message instructions', () => {
expect(instructions).toContain(
'For lightweight clarification, satisfy the `input_needed` milestone on GitHub.',
);
- expect(instructions).toContain(
- 'begin the next GitHub reply with a Markdown blockquote of that follow-up',
- );
- expect(instructions).toContain('');
- expect(instructions).toContain('not injected out-of-band context');
- expect(instructions).toContain('keep it to 280 characters');
- expect(instructions).toContain('public-reply policy prohibits disclosing');
expect(instructions).toContain('plain GitHub issue');
});
});
diff --git a/packages/cloud-agents/src/server/github-message-instructions.ts b/packages/cloud-agents/src/server/github-message-instructions.ts
index 4719bf598..0e2f1ba96 100644
--- a/packages/cloud-agents/src/server/github-message-instructions.ts
+++ b/packages/cloud-agents/src/server/github-message-instructions.ts
@@ -9,7 +9,6 @@ export function buildGitHubMessageInstructions(): string {
For that non-actionable mention case, leave one brief GitHub reply on the same conversation surface if a reply is still useful, then conclude with a no-op result.
Do not treat short verification asks such as "is this addressed?" or "did we fix everything from the last round?" as no-op; those are actionable follow-up.
Keep GitHub replies brief, relevant to the request, and free of internal reasoning or raw logs.
- When answering a , begin the next GitHub reply with a Markdown blockquote of that follow-up so other participants can see what the reply addresses. Use only the message inside that boundary, not injected out-of-band context; keep it to 280 characters. Omit or summarize any portion that the public-reply policy prohibits disclosing.
If the active workflow already owns a dedicated GitHub comment lifecycle, let that workflow satisfy the relevant communication milestones instead of duplicating generic thread updates.
For lightweight clarification, satisfy the \`input_needed\` milestone on GitHub. Use \`request_user_input\` only when the task needs structured or private input outside the public thread.
diff --git a/packages/communication/src/__tests__/messages.test.ts b/packages/communication/src/__tests__/messages.test.ts
index d7b0d930a..7479dbcbe 100644
--- a/packages/communication/src/__tests__/messages.test.ts
+++ b/packages/communication/src/__tests__/messages.test.ts
@@ -314,6 +314,24 @@ describe('communication message queues', () => {
);
});
+ it('supports GitHub reply quotes without adding GitHub as a chat provider', async () => {
+ await setLatestUserMessageForReplyQuote('github', 44, {
+ text: 'ship it',
+ userName: 'Ada',
+ });
+
+ expect(setMock).toHaveBeenCalledWith(
+ 'github:latest_user_message:44',
+ JSON.stringify({
+ id: 'quote-id-fixed',
+ text: 'ship it',
+ userName: 'Ada',
+ }),
+ 'EX',
+ 30 * 24 * 60 * 60,
+ );
+ });
+
it('reads the latest user message', async () => {
getMock.mockResolvedValueOnce(
JSON.stringify({
diff --git a/packages/communication/src/messages.ts b/packages/communication/src/messages.ts
index f7e746bfe..31ee41131 100644
--- a/packages/communication/src/messages.ts
+++ b/packages/communication/src/messages.ts
@@ -7,6 +7,8 @@ import {
queuedCommunicationMessageSchema,
} from '@roomote/types';
+type ReplyQuoteProvider = CommunicationProvider | 'github';
+
const COMMUNICATION_MESSAGE_TTL_SECONDS = 60 * 60;
const COMMUNICATION_MESSAGE_DEDUPE_TTL_SECONDS = 24 * 60 * 60;
const LATEST_INBOUND_MESSAGE_ID_TTL_SECONDS = 60 * 60 * 24;
@@ -20,7 +22,7 @@ export interface LatestUserMessageForReplyQuote {
}
type TrackLatestUserMessageForReplyQuoteParams = {
- provider: CommunicationProvider;
+ provider: ReplyQuoteProvider;
runId: number;
text: string;
userName: string;
@@ -72,7 +74,7 @@ function getLatestInboundMessageIdKey(
}
function getLatestUserMessageForReplyQuoteKey(
- provider: CommunicationProvider,
+ provider: ReplyQuoteProvider,
runId: number,
): string {
return `${provider}:latest_user_message:${runId}`;
@@ -108,7 +110,7 @@ function parseLatestUserMessageForReplyQuote(
}
function getCommunicationMessageDedupeKey(
- provider: CommunicationProvider,
+ provider: ReplyQuoteProvider,
runId: number,
messageId: string,
): string {
@@ -350,7 +352,7 @@ export async function getLatestInboundMessageId(
* quote it back into the originating chat thread (Discord parity with Slack).
*/
export async function setLatestUserMessageForReplyQuote(
- provider: CommunicationProvider,
+ provider: ReplyQuoteProvider,
runId: number,
message: Omit & { id?: string },
): Promise {
@@ -399,7 +401,7 @@ export async function trackLatestUserMessageForReplyQuote({
}
export async function getLatestUserMessageForReplyQuote(
- provider: CommunicationProvider,
+ provider: ReplyQuoteProvider,
runId: number,
): Promise {
const redis = getRedis();
@@ -410,7 +412,7 @@ export async function getLatestUserMessageForReplyQuote(
}
export async function clearLatestUserMessageForReplyQuote(
- provider: CommunicationProvider,
+ provider: ReplyQuoteProvider,
runId: number,
): Promise {
try {
@@ -430,7 +432,7 @@ export async function clearLatestUserMessageForReplyQuote(
* was quoted on this delivery. Prevents clearing a newer same-text follow-up.
*/
export async function clearLatestUserMessageForReplyQuoteIfId(
- provider: CommunicationProvider,
+ provider: ReplyQuoteProvider,
runId: number,
id: string,
): Promise {
From 6aaff4a0937aa4d7c9216c26295a46ba42dc1df8 Mon Sep 17 00:00:00 2001
From: Daniel Riccio <57051444+daniel-lxs@users.noreply.github.com>
Date: Tue, 28 Jul 2026 21:06:35 +0000
Subject: [PATCH 4/4] fix: scope source control write cases
---
apps/api/src/handlers/tasks/manageSourceControl.ts | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/apps/api/src/handlers/tasks/manageSourceControl.ts b/apps/api/src/handlers/tasks/manageSourceControl.ts
index 58b7d6a37..099a79116 100644
--- a/apps/api/src/handlers/tasks/manageSourceControl.ts
+++ b/apps/api/src/handlers/tasks/manageSourceControl.ts
@@ -143,22 +143,24 @@ export async function manageSourceControl(
case 'create_pull_request_comment':
case 'resolve_pull_request_thread':
case 'submit_pull_request_review':
- case 'update_pull_request_comment':
+ case 'update_pull_request_comment': {
const writeResult = await writeSourceControlPullRequestForTaskRun({
taskRun,
input,
});
await clearQuoteAfterSuccess();
return c.json(writeResult);
+ }
case 'get_issue':
case 'list_issue_comments':
- case 'create_issue_comment':
+ case 'create_issue_comment': {
const issueResult = await manageSourceControlIssueForTaskRun({
taskRun,
input,
});
await clearQuoteAfterSuccess();
return c.json(issueResult);
+ }
}
} catch (error) {
if (error instanceof z.ZodError) {