mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-11-10 01:50:13 +01:00
fix(slack): preserve explicit DM task controls
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
1 parent
78108efc0c
commit
367b6f9b3f
6 files changed
+33
-26
No files matched your search
@@ -58500,7 +58500,7 @@ describeEmbeddedPostgres("chat channel control-plane integration", () => {
|
||||
]);
|
||||
});
|
||||
|
||||
it("binds Slack DM slash controls to the native root returned for the latest task", async () => {
|
||||
it.each(["new", "close"] as const)("binds Slack DM slash controls to the native root returned for the latest task (%s)", async (control) => {
|
||||
const fixture = await seedCompany();
|
||||
const { callbacks, endpoint, runtime, service } =
|
||||
await configuredSlackEndpoint(fixture);
|
||||
@@ -58564,7 +58564,7 @@ describeEmbeddedPostgres("chat channel control-plane integration", () => {
|
||||
threadId: starterThreadId,
|
||||
text: expect.stringMatching(/— todo$/),
|
||||
});
|
||||
await invoke("close");
|
||||
await invoke(control);
|
||||
await expect(service.listConversations(endpoint.id)).resolves.toEqual([
|
||||
expect.objectContaining({
|
||||
externalThreadId: starterThreadId,
|
||||
@@ -58578,9 +58578,21 @@ describeEmbeddedPostgres("chat channel control-plane integration", () => {
|
||||
state: "completed",
|
||||
}),
|
||||
]);
|
||||
expect(
|
||||
await readIssuesByCompanyId(fixture.companyId),
|
||||
).toHaveLength(1);
|
||||
expect(await readIssuesByCompanyId(fixture.companyId)).toHaveLength(1);
|
||||
const providerTime = Date.now();
|
||||
const providerTimestamp = `${Math.floor(providerTime / 1_000)}.${String((providerTime % 1_000) * 1_000).padStart(6, "0")}`;
|
||||
await deliverMessage({
|
||||
callbacks, endpointId: endpoint.id,
|
||||
thread: makeThread({ channelId: "D09SLASHTASK", id: starterThreadId, isDM: true }).thread,
|
||||
message: makeMessage({ id: providerTimestamp, raw: { ts: providerTimestamp }, text: "An explicitly requested new task", userId: "U-DM-SLASH-TASK" }),
|
||||
trigger: "direct_message",
|
||||
});
|
||||
const conversations = await service.listConversations(endpoint.id);
|
||||
expect(conversations).toHaveLength(2);
|
||||
expect(conversations.find(row => row.state === "active")).toMatchObject({
|
||||
externalThreadId: starterThreadId, sessionGeneration: 2,
|
||||
});
|
||||
expect(await readIssuesByCompanyId(fixture.companyId)).toHaveLength(2);
|
||||
});
|
||||
|
||||
it("acknowledges a Slack retry while one durable worker owns the unrecorded command root", async () => {
|
||||
|
||||
@@ -1749,13 +1749,17 @@ export function chatChannelService(db: Db, options: ChatChannelServiceOptions) {
|
||||
let { conversation: existingConversation, issue: existingIssue, latestConversation, isLinear } =
|
||||
await resolveInboundConversationBinding(db, {
|
||||
endpoint, thread,
|
||||
isLinear: () => endpoint.provider === "speko" ? SPEKO_CONVERSATION_IS_LINEAR : surfaceKind !== "native_thread",
|
||||
isLinear: () => endpoint.provider === "speko"
|
||||
? SPEKO_CONVERSATION_IS_LINEAR
|
||||
: surfaceKind !== "native_thread" || (endpoint.provider === "slack" && thread.isDM),
|
||||
lookupConversation: endpoint.provider === "microsoft-teams"
|
||||
? () => conversationForThread(endpoint.id, thread.id)
|
||||
: undefined,
|
||||
conversationIsComplete: endpoint.provider === "imessage-photon"
|
||||
? (conversationId) => photonConversationBindingIsComplete(conversationId, hasCommittedTaskControlCompletion)
|
||||
: undefined,
|
||||
: endpoint.provider === "slack" && thread.isDM && surfaceKind === "native_thread"
|
||||
? async (conversationId, state) => state === "completed" && hasCommittedTaskControlCompletion(conversationId)
|
||||
: undefined,
|
||||
});
|
||||
const telegramControls = endpoint.provider === "telegram"
|
||||
? telegramInboundControls(message.text, surfaceKind)
|
||||
|
||||
@@ -9,7 +9,7 @@ type ConversationBindingInput = {
|
||||
thread: { id: string; channelId: string };
|
||||
isLinear: () => boolean;
|
||||
lookupConversation?: () => Promise<ConversationRow | null>;
|
||||
conversationIsComplete?: (conversationId: string) => Promise<boolean>;
|
||||
conversationIsComplete?: (conversationId: string, state: ConversationRow["state"]) => Promise<boolean>;
|
||||
};
|
||||
|
||||
export async function resolveInboundConversationBinding(
|
||||
@@ -54,7 +54,7 @@ export async function resolveInboundConversationBinding(
|
||||
isLinear &&
|
||||
existingConversation &&
|
||||
(conversationIsComplete
|
||||
? await conversationIsComplete(existingConversation.id)
|
||||
? await conversationIsComplete(existingConversation.id, existingConversation.state)
|
||||
: existingConversation.state === "completed" ||
|
||||
existingIssue?.status === "done" ||
|
||||
existingIssue?.status === "cancelled")
|
||||
|
||||
Reference in new issue
Block a user