@tickernelz/paperclip-pro-server 2026.1012.0 → 2026.1012.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/__tests__/helpers/runner-api-server.d.ts +1 -0
- package/dist/__tests__/helpers/runner-api-server.d.ts.map +1 -1
- package/dist/build-info.json +1 -1
- package/dist/routes/attention.d.ts.map +1 -1
- package/dist/routes/attention.js +12 -1
- package/dist/routes/attention.js.map +1 -1
- package/dist/routes/issues.d.ts.map +1 -1
- package/dist/routes/issues.js +106 -1
- package/dist/routes/issues.js.map +1 -1
- package/dist/routes/openapi.d.ts.map +1 -1
- package/dist/routes/openapi.js +30 -1
- package/dist/routes/openapi.js.map +1 -1
- package/dist/services/agents.d.ts +10 -10
- package/dist/services/chat-completion-delivery.d.ts +5 -0
- package/dist/services/chat-completion-delivery.d.ts.map +1 -1
- package/dist/services/chat-completion-delivery.js +16 -6
- package/dist/services/chat-completion-delivery.js.map +1 -1
- package/dist/services/connectors/slack.d.ts +13 -13
- package/dist/services/issue-thread-interaction-resolution.d.ts.map +1 -1
- package/dist/services/issue-thread-interaction-resolution.js +3 -0
- package/dist/services/issue-thread-interaction-resolution.js.map +1 -1
- package/dist/services/issue-thread-interactions.d.ts +1 -0
- package/dist/services/issue-thread-interactions.d.ts.map +1 -1
- package/dist/services/native-runtime/automatic-completion-reviews.d.ts +1 -0
- package/dist/services/native-runtime/automatic-completion-reviews.d.ts.map +1 -1
- package/dist/services/openwa/admission.d.ts.map +1 -1
- package/dist/services/openwa/admission.js +24 -5
- package/dist/services/openwa/admission.js.map +1 -1
- package/dist/services/openwa/approvals.d.ts +12 -0
- package/dist/services/openwa/approvals.d.ts.map +1 -1
- package/dist/services/openwa/approvals.js +35 -7
- package/dist/services/openwa/approvals.js.map +1 -1
- package/dist/services/openwa/authority.d.ts.map +1 -1
- package/dist/services/openwa/authority.js +1 -0
- package/dist/services/openwa/authority.js.map +1 -1
- package/dist/services/openwa/catalog.d.ts +1 -0
- package/dist/services/openwa/catalog.d.ts.map +1 -1
- package/dist/services/openwa/config-tool.d.ts.map +1 -1
- package/dist/services/openwa/config-tool.js +22 -3
- package/dist/services/openwa/config-tool.js.map +1 -1
- package/dist/services/openwa/guidance.d.ts +2 -0
- package/dist/services/openwa/guidance.d.ts.map +1 -1
- package/dist/services/openwa/guidance.js +27 -5
- package/dist/services/openwa/guidance.js.map +1 -1
- package/dist/services/openwa/owner-report.d.ts +24 -0
- package/dist/services/openwa/owner-report.d.ts.map +1 -0
- package/dist/services/openwa/owner-report.js +97 -0
- package/dist/services/openwa/owner-report.js.map +1 -0
- package/dist/services/openwa/owners.d.ts.map +1 -1
- package/dist/services/openwa/owners.js +4 -0
- package/dist/services/openwa/owners.js.map +1 -1
- package/dist/services/openwa/policy.d.ts +2 -0
- package/dist/services/openwa/policy.d.ts.map +1 -1
- package/dist/services/openwa/policy.js +11 -2
- package/dist/services/openwa/policy.js.map +1 -1
- package/dist/services/openwa/tools.d.ts +1 -0
- package/dist/services/openwa/tools.d.ts.map +1 -1
- package/dist/services/openwa/tools.js +21 -4
- package/dist/services/openwa/tools.js.map +1 -1
- package/dist/services/owner-decision-relay.d.ts +62 -0
- package/dist/services/owner-decision-relay.d.ts.map +1 -0
- package/dist/services/owner-decision-relay.js +433 -0
- package/dist/services/owner-decision-relay.js.map +1 -0
- package/package.json +21 -21
- package/skills/openwa/SKILL.md +51 -3
- package/skills/paperclip/SKILL.md +1 -1
- package/ui-dist/assets/{AgentAvatar-B47RVwPt.js → AgentAvatar-DySHTTwq.js} +1 -1
- package/ui-dist/assets/{Agents.production-CaL_roCY.js → Agents.production-CF5r1j38.js} +2 -2
- package/ui-dist/assets/{BreadcrumbContext-BRKP7-bF.js → BreadcrumbContext-C-JqFdLZ.js} +1 -1
- package/ui-dist/assets/{CompanyActivity.production-B5ko3U6C.js → CompanyActivity.production-BxAfcJub.js} +1 -1
- package/ui-dist/assets/{CompanyExport-D_8Cdnps.js → CompanyExport-CEeoEcyJ.js} +1 -1
- package/ui-dist/assets/{CompanySkills.production-DKpb4vb9.js → CompanySkills.production-DHEEarUk.js} +1 -1
- package/ui-dist/assets/{EmptyState-iwTwakaR.js → EmptyState-fxPFhH-R.js} +1 -1
- package/ui-dist/assets/{MarkdownBody-CbLdPc8E.js → MarkdownBody-CEcIElD-.js} +1 -1
- package/ui-dist/assets/{MarkdownEditor-98mZdmRX.js → MarkdownEditor-B6kwxxZP.js} +1 -1
- package/ui-dist/assets/{OrgChart.production-CpVPwEak.js → OrgChart.production-R4TqTezh.js} +1 -1
- package/ui-dist/assets/{PageSkeleton-Dl_gWB8z.js → PageSkeleton-iVZWoLsF.js} +1 -1
- package/ui-dist/assets/{RoutineDetail.production-CmUbfGto.js → RoutineDetail.production-RCCl99aO.js} +1 -1
- package/ui-dist/assets/{RoutineRunVariablesDialog-DrqOVV5i.js → RoutineRunVariablesDialog-BfaOkOdj.js} +1 -1
- package/ui-dist/assets/{Routines.production-C3-E_ij7.js → Routines.production-i7GS-uxC.js} +1 -1
- package/ui-dist/assets/{StatusIcon-Co-elrfc.js → StatusIcon-DxxLvme9.js} +1 -1
- package/ui-dist/assets/{ToastContext-CYUmn7f8.js → ToastContext-BbzJdb2r.js} +1 -1
- package/ui-dist/assets/{agent-avatar-url-B91C7fqh.js → agent-avatar-url-eBzFMwFS.js} +27 -27
- package/ui-dist/assets/{alert-dialog-CfwPsmAH.js → alert-dialog-Ctnjtpv6.js} +1 -1
- package/ui-dist/assets/{arrow-right-DW0tfmbi.js → arrow-right-DyKWA_SL.js} +1 -1
- package/ui-dist/assets/{badge-B4XIQ7B_.js → badge-CUe24HAP.js} +1 -1
- package/ui-dist/assets/{bot-zBrbL-yH.js → bot-wKcWfYKX.js} +1 -1
- package/ui-dist/assets/{card-79GDCTP3.js → card-GbQ9sLu8.js} +1 -1
- package/ui-dist/assets/{check-x_elx0uL.js → check-VcfFMsHr.js} +1 -1
- package/ui-dist/assets/{checkbox-3gl2Un2H.js → checkbox-Cm-PyDSt.js} +1 -1
- package/ui-dist/assets/{clipboard-_seTAJiP.js → clipboard-CYFyFXxJ.js} +1 -1
- package/ui-dist/assets/{company-members-BXmr5rWO.js → company-members-CSVvQnvh.js} +1 -1
- package/ui-dist/assets/{definition-I91EV37G.js → definition-urW_HpEG.js} +1 -1
- package/ui-dist/assets/{dist-G74v2gk6.js → dist-CfR2_c4p.js} +1 -1
- package/ui-dist/assets/{dist-Bgy8AcEI.js → dist-Dz68ZFqX.js} +1 -1
- package/ui-dist/assets/{dist-D4yyXwCK.js → dist-Z45aKkJm.js} +1 -1
- package/ui-dist/assets/{environments-x0bu3agB.js → environments-Cc8orNVy.js} +1 -1
- package/ui-dist/assets/{external-link-DZQH1MR8.js → external-link-CAutrcht.js} +1 -1
- package/ui-dist/assets/{file-text-DnkFEoqC.js → file-text-Dik8gyob.js} +1 -1
- package/ui-dist/assets/{health-DIsZUg4d.js → health-D_DTw2-J.js} +1 -1
- package/ui-dist/assets/{heartbeats-hynzhqu3.js → heartbeats-BgAe0g2m.js} +1 -1
- package/ui-dist/assets/{index-SsNrNOjw.js → index-st-IN4Gf.js} +139 -139
- package/ui-dist/assets/{input-DW5WzZI0.js → input-BARyUoy0.js} +1 -1
- package/ui-dist/assets/{label-BnuPQCxV.js → label-D4Q0SI3t.js} +1 -1
- package/ui-dist/assets/{mention-chips-DtMro9HO.js → mention-chips-BEoxPZei.js} +1 -1
- package/ui-dist/assets/{rotate-ccw-wat5PoA5.js → rotate-ccw-BT1r8zDE.js} +1 -1
- package/ui-dist/assets/{select-CtJdi3BB.js → select-yD0r8C3i.js} +1 -1
- package/ui-dist/assets/{sheet-5L45GZhN.js → sheet-CAjfRCp9.js} +1 -1
- package/ui-dist/assets/{skeleton-Cea_xEjg.js → skeleton-BFMc3stE.js} +1 -1
- package/ui-dist/assets/{tabs-CVzr4EnB.js → tabs-C1f963Rn.js} +1 -1
- package/ui-dist/assets/{use-adapter-capabilities-BzuoLi4n.js → use-adapter-capabilities-CsKGmy5W.js} +1 -1
- package/ui-dist/assets/{use-copy-action-D1yLO8Yp.js → use-copy-action-B-Azftuv.js} +1 -1
- package/ui-dist/assets/{useHiddenSettings-DuLvvhZD.js → useHiddenSettings-Uo-rfexH.js} +1 -1
- package/ui-dist/index.html +39 -39
- package/ui-dist/sw.js +1 -1
|
@@ -0,0 +1,433 @@
|
|
|
1
|
+
import { and, eq, inArray } from "drizzle-orm";
|
|
2
|
+
import { agents, chatConversations, chatDeliveries, chatEndpoints, heartbeatRuns, issueComments, issueThreadInteractionOwnerRelays, issueThreadInteractions, } from "@tickernelz/paperclip-pro-db";
|
|
3
|
+
import { HttpError, unprocessable } from "../errors.js";
|
|
4
|
+
import { attentionService } from "./attention.js";
|
|
5
|
+
import { boardAuthService } from "./board-auth.js";
|
|
6
|
+
import { openwaOwnerPrincipalOfDeliveries } from "./openwa/approvals.js";
|
|
7
|
+
import { readOpenwaRunContext } from "./openwa/authority.js";
|
|
8
|
+
import { openwaChatKey } from "./openwa/outbound.js";
|
|
9
|
+
import { openwaCurrentOwnerUserId } from "./openwa/owners.js";
|
|
10
|
+
export const OWNER_CONFIRMATION_REQUIRED_CODE = "owner_confirmation_required";
|
|
11
|
+
const OWNER_RELAY_REMEDIATION = "Relay a card answer only from a run the owner's own message started (an owner WhatsApp message, or their board comment), quoting that message's id as ownerMessageRef. Otherwise ask the owner to answer the card in Paperclip.";
|
|
12
|
+
function ownerConfirmationRequired(reason, message) {
|
|
13
|
+
return new HttpError(403, message, { code: OWNER_CONFIRMATION_REQUIRED_CODE, reason, remediation: OWNER_RELAY_REMEDIATION });
|
|
14
|
+
}
|
|
15
|
+
function record(value) {
|
|
16
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
17
|
+
}
|
|
18
|
+
function str(value) {
|
|
19
|
+
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
20
|
+
}
|
|
21
|
+
function strings(value) {
|
|
22
|
+
return Array.isArray(value) ? value.filter((entry) => typeof entry === "string" && entry.trim().length > 0) : [];
|
|
23
|
+
}
|
|
24
|
+
async function whatsappAuthority(db, run, ownerMessageRef) {
|
|
25
|
+
const openwa = readOpenwaRunContext(run.contextSnapshot);
|
|
26
|
+
if (!openwa)
|
|
27
|
+
return null;
|
|
28
|
+
const notOwner = () => ownerConfirmationRequired("not_owner_triggered", "Only a run started by an endpoint owner's own WhatsApp messages can relay their answer to a card");
|
|
29
|
+
if (openwa.triggerClass !== "owner")
|
|
30
|
+
throw notOwner();
|
|
31
|
+
const [endpoint] = await db
|
|
32
|
+
.select({ id: chatEndpoints.id, companyId: chatEndpoints.companyId })
|
|
33
|
+
.from(chatEndpoints)
|
|
34
|
+
.where(and(eq(chatEndpoints.id, openwa.endpointId), eq(chatEndpoints.companyId, run.companyId), eq(chatEndpoints.provider, "openwa")))
|
|
35
|
+
.limit(1);
|
|
36
|
+
const runIssueId = str(run.contextSnapshot?.issueId) ?? str(run.contextSnapshot?.taskId);
|
|
37
|
+
if (!endpoint || !runIssueId)
|
|
38
|
+
throw notOwner();
|
|
39
|
+
const [conversation] = await db
|
|
40
|
+
.select({ id: chatConversations.id })
|
|
41
|
+
.from(chatConversations)
|
|
42
|
+
.where(and(eq(chatConversations.companyId, run.companyId), eq(chatConversations.endpointId, endpoint.id), eq(chatConversations.issueId, runIssueId)))
|
|
43
|
+
.limit(1);
|
|
44
|
+
if (!conversation)
|
|
45
|
+
throw notOwner();
|
|
46
|
+
const principalId = await openwaOwnerPrincipalOfDeliveries(db, {
|
|
47
|
+
companyId: run.companyId,
|
|
48
|
+
endpointId: endpoint.id,
|
|
49
|
+
conversationId: conversation.id,
|
|
50
|
+
chatKey: openwaChatKey(openwa.chatKey),
|
|
51
|
+
deliveryIds: openwa.deliveryIds,
|
|
52
|
+
});
|
|
53
|
+
if (!principalId)
|
|
54
|
+
throw notOwner();
|
|
55
|
+
const deliveries = await db
|
|
56
|
+
.select({ id: chatDeliveries.id, normalizedEvent: chatDeliveries.normalizedEvent, receivedAt: chatDeliveries.receivedAt })
|
|
57
|
+
.from(chatDeliveries)
|
|
58
|
+
.where(and(eq(chatDeliveries.companyId, run.companyId), eq(chatDeliveries.endpointId, endpoint.id), inArray(chatDeliveries.id, openwa.deliveryIds.slice(0, 50))));
|
|
59
|
+
const message = deliveries.find((row) => row.id === ownerMessageRef || str(record(row.normalizedEvent.openwa).waMessageId) === ownerMessageRef);
|
|
60
|
+
if (!message) {
|
|
61
|
+
throw ownerConfirmationRequired("owner_message_not_in_run", "ownerMessageRef must be the id of one of the owner's messages that started this run");
|
|
62
|
+
}
|
|
63
|
+
const owner = await openwaCurrentOwnerUserId(db, endpoint, principalId);
|
|
64
|
+
if (!owner.userId) {
|
|
65
|
+
throw ownerConfirmationRequired("owner_not_linked", "This WhatsApp owner is not linked to a Paperclip user, so their answer cannot be recorded for them");
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
ownerUserId: owner.userId,
|
|
69
|
+
ownerMessageRef,
|
|
70
|
+
ownerText: typeof record(message.normalizedEvent.message).text === "string" ? String(record(message.normalizedEvent.message).text) : "",
|
|
71
|
+
messageAt: message.receivedAt,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
async function commentAuthority(db, run, ownerMessageRef) {
|
|
75
|
+
const wakeCommentIds = new Set([...strings(run.contextSnapshot?.wakeCommentIds), ...strings([run.contextSnapshot?.wakeCommentId])]);
|
|
76
|
+
if (wakeCommentIds.size === 0) {
|
|
77
|
+
throw ownerConfirmationRequired("not_owner_triggered", "Only a run started by a board user's own message can relay their answer to a card");
|
|
78
|
+
}
|
|
79
|
+
if (!wakeCommentIds.has(ownerMessageRef)) {
|
|
80
|
+
throw ownerConfirmationRequired("owner_message_not_in_run", "ownerMessageRef must be the id of the board comment that woke this run");
|
|
81
|
+
}
|
|
82
|
+
const [comment] = await db
|
|
83
|
+
.select({
|
|
84
|
+
authorType: issueComments.authorType,
|
|
85
|
+
authorUserId: issueComments.authorUserId,
|
|
86
|
+
authorAgentId: issueComments.authorAgentId,
|
|
87
|
+
createdByRunId: issueComments.createdByRunId,
|
|
88
|
+
deletedAt: issueComments.deletedAt,
|
|
89
|
+
sourceTrust: issueComments.sourceTrust,
|
|
90
|
+
body: issueComments.body,
|
|
91
|
+
createdAt: issueComments.createdAt,
|
|
92
|
+
})
|
|
93
|
+
.from(issueComments)
|
|
94
|
+
.where(and(eq(issueComments.id, ownerMessageRef), eq(issueComments.companyId, run.companyId)))
|
|
95
|
+
.limit(1);
|
|
96
|
+
if (!comment ||
|
|
97
|
+
comment.deletedAt ||
|
|
98
|
+
comment.authorType !== "user" ||
|
|
99
|
+
!comment.authorUserId ||
|
|
100
|
+
comment.authorAgentId ||
|
|
101
|
+
comment.createdByRunId ||
|
|
102
|
+
comment.sourceTrust?.disposition === "quarantined") {
|
|
103
|
+
throw ownerConfirmationRequired("not_owner_triggered", "The message that woke this run is not a board user's own message");
|
|
104
|
+
}
|
|
105
|
+
return { ownerUserId: comment.authorUserId, ownerMessageRef, ownerText: comment.body, messageAt: comment.createdAt };
|
|
106
|
+
}
|
|
107
|
+
export async function resolveOwnerRelayAuthority(db, input) {
|
|
108
|
+
const [run] = await db
|
|
109
|
+
.select({ id: heartbeatRuns.id, companyId: heartbeatRuns.companyId, agentId: heartbeatRuns.agentId, status: heartbeatRuns.status, contextSnapshot: heartbeatRuns.contextSnapshot })
|
|
110
|
+
.from(heartbeatRuns)
|
|
111
|
+
.where(and(eq(heartbeatRuns.id, input.runId), eq(heartbeatRuns.companyId, input.companyId)))
|
|
112
|
+
.limit(1);
|
|
113
|
+
if (!run || run.agentId !== input.agentId || run.status !== "running") {
|
|
114
|
+
throw ownerConfirmationRequired("run_not_active", "Only the agent's own active run can relay an owner's answer");
|
|
115
|
+
}
|
|
116
|
+
const relayRun = { id: run.id, companyId: run.companyId, contextSnapshot: run.contextSnapshot };
|
|
117
|
+
const whatsapp = await whatsappAuthority(db, relayRun, input.ownerMessageRef);
|
|
118
|
+
const authority = whatsapp ? { channel: "whatsapp", ...whatsapp } : { channel: "paperclip", ...(await commentAuthority(db, relayRun, input.ownerMessageRef)) };
|
|
119
|
+
const access = await boardAuthService(db).resolveBoardAccess(authority.ownerUserId);
|
|
120
|
+
if (!access.user || (!access.isInstanceAdmin && !access.companyIds.includes(input.companyId))) {
|
|
121
|
+
throw ownerConfirmationRequired("owner_not_member", "The owner is not an active board member of this company");
|
|
122
|
+
}
|
|
123
|
+
return authority;
|
|
124
|
+
}
|
|
125
|
+
export function ownerRelayClaimKey(ownerText, card) {
|
|
126
|
+
const text = ownerText.toLowerCase();
|
|
127
|
+
if (text.includes(card.interactionId.toLowerCase()))
|
|
128
|
+
return "interaction:" + card.interactionId.toLowerCase();
|
|
129
|
+
const named = new Set();
|
|
130
|
+
const uuids = text.match(/\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\b/g) ?? [];
|
|
131
|
+
for (const id of uuids)
|
|
132
|
+
named.add("interaction:" + id);
|
|
133
|
+
const prefix = card.issueIdentifier?.split("-")[0]?.toLowerCase() ?? null;
|
|
134
|
+
if (prefix) {
|
|
135
|
+
const escaped = prefix.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
136
|
+
for (const match of text.matchAll(new RegExp("\\b" + escaped + "-(\\d+)\\b", "g")))
|
|
137
|
+
named.add("issue:" + prefix + "-" + match[1]);
|
|
138
|
+
}
|
|
139
|
+
const issueKey = card.issueIdentifier ? "issue:" + card.issueIdentifier.toLowerCase() : null;
|
|
140
|
+
if (issueKey && named.has(issueKey))
|
|
141
|
+
return issueKey;
|
|
142
|
+
if (named.size > 0) {
|
|
143
|
+
throw ownerConfirmationRequired("card_not_named", "The owner's message names other cards, not this one; relay only the cards it names");
|
|
144
|
+
}
|
|
145
|
+
return "*";
|
|
146
|
+
}
|
|
147
|
+
export async function claimOwnerRelay(db, input) {
|
|
148
|
+
if (input.authority.messageAt.getTime() < input.cardCreatedAt.getTime()) {
|
|
149
|
+
throw ownerConfirmationRequired("message_predates_card", "The owner's message was sent before this card existed, so it cannot answer it");
|
|
150
|
+
}
|
|
151
|
+
const claimKey = ownerRelayClaimKey(input.authority.ownerText, { interactionId: input.interactionId, issueIdentifier: input.issueIdentifier });
|
|
152
|
+
const [claim] = await db
|
|
153
|
+
.insert(issueThreadInteractionOwnerRelays)
|
|
154
|
+
.values({
|
|
155
|
+
companyId: input.companyId,
|
|
156
|
+
issueId: input.issueId,
|
|
157
|
+
interactionId: input.interactionId,
|
|
158
|
+
channel: input.authority.channel,
|
|
159
|
+
ownerMessageRef: input.authority.ownerMessageRef,
|
|
160
|
+
claimKey,
|
|
161
|
+
ownerUserId: input.authority.ownerUserId,
|
|
162
|
+
relayedByAgentId: input.agentId,
|
|
163
|
+
runId: input.runId,
|
|
164
|
+
})
|
|
165
|
+
.onConflictDoNothing()
|
|
166
|
+
.returning({ id: issueThreadInteractionOwnerRelays.id });
|
|
167
|
+
if (!claim) {
|
|
168
|
+
throw ownerConfirmationRequired("owner_message_consumed", claimKey === "*"
|
|
169
|
+
? "This owner message already answered a card; one message answers one card unless it names each card"
|
|
170
|
+
: "This owner message already answered the card it names");
|
|
171
|
+
}
|
|
172
|
+
return claim.id;
|
|
173
|
+
}
|
|
174
|
+
export async function releaseOwnerRelay(db, claimId) {
|
|
175
|
+
await db.delete(issueThreadInteractionOwnerRelays).where(eq(issueThreadInteractionOwnerRelays.id, claimId));
|
|
176
|
+
}
|
|
177
|
+
export async function markOwnerRelayApplied(db, input) {
|
|
178
|
+
await db
|
|
179
|
+
.update(issueThreadInteractions)
|
|
180
|
+
.set({ resolutionRelay: input.relay })
|
|
181
|
+
.where(and(eq(issueThreadInteractions.id, input.interactionId), eq(issueThreadInteractions.companyId, input.companyId), eq(issueThreadInteractions.resolvedByUserId, input.relay.ownerUserId)));
|
|
182
|
+
}
|
|
183
|
+
export function ownerRelayBlockedReason(card) {
|
|
184
|
+
if (card.kind === "connection_intent")
|
|
185
|
+
return "Connection requests are completed by the connecting user in Paperclip";
|
|
186
|
+
const payload = record(card.payload);
|
|
187
|
+
if (payload.toolAction || payload.secretProposal || payload.connectionAuthorization) {
|
|
188
|
+
return "Governed actions (tool runs, secret bindings, connection authorizations) use their own approval control in Paperclip";
|
|
189
|
+
}
|
|
190
|
+
if (str(payload.openwaApprovalRequestId))
|
|
191
|
+
return "OpenWA approval requests are resolved with openwa_approval_resolve in the owner's chat";
|
|
192
|
+
return null;
|
|
193
|
+
}
|
|
194
|
+
export function ownerRelayTarget(card, answer) {
|
|
195
|
+
const blocked = ownerRelayBlockedReason(card);
|
|
196
|
+
if (blocked)
|
|
197
|
+
throw unprocessable(blocked, { code: "owner_relay_unsupported" });
|
|
198
|
+
const note = answer.note === undefined ? {} : { note: answer.note };
|
|
199
|
+
const mismatch = (shape) => unprocessable("A " + card.kind + " card takes " + shape, { code: "owner_relay_answer_mismatch" });
|
|
200
|
+
switch (card.kind) {
|
|
201
|
+
case "request_confirmation":
|
|
202
|
+
case "request_checkbox_confirmation":
|
|
203
|
+
case "suggest_tasks": {
|
|
204
|
+
if (!answer.decision)
|
|
205
|
+
throw mismatch("decision approve or reject");
|
|
206
|
+
if (answer.decision === "reject")
|
|
207
|
+
return { action: "reject", body: { ...(answer.reason ? { reason: answer.reason } : {}), ...note } };
|
|
208
|
+
if (card.kind === "request_confirmation" && answer.optionIds)
|
|
209
|
+
throw mismatch("no optionIds");
|
|
210
|
+
if (card.kind === "request_checkbox_confirmation" && !answer.optionIds)
|
|
211
|
+
throw mismatch("the optionIds the owner chose");
|
|
212
|
+
const selection = card.kind === "request_checkbox_confirmation"
|
|
213
|
+
? { selectedOptionIds: answer.optionIds }
|
|
214
|
+
: card.kind === "suggest_tasks" && answer.optionIds
|
|
215
|
+
? { selectedClientKeys: answer.optionIds }
|
|
216
|
+
: {};
|
|
217
|
+
return { action: "accept", body: { ...selection, ...note } };
|
|
218
|
+
}
|
|
219
|
+
case "ask_user_questions":
|
|
220
|
+
if (!answer.answers)
|
|
221
|
+
throw mismatch("answers");
|
|
222
|
+
return { action: "respond", body: { answers: answer.answers } };
|
|
223
|
+
case "request_item_verdicts":
|
|
224
|
+
if (!answer.verdicts)
|
|
225
|
+
throw mismatch("verdicts");
|
|
226
|
+
return { action: "verdicts", body: { verdicts: answer.verdicts } };
|
|
227
|
+
default:
|
|
228
|
+
throw unprocessable("This card kind cannot be relayed", { code: "owner_relay_unsupported" });
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
export function dispatchAsOwner(handle, req, input) {
|
|
232
|
+
return new Promise((resolve, reject) => {
|
|
233
|
+
let settled = false;
|
|
234
|
+
const finish = (status, body) => {
|
|
235
|
+
if (settled)
|
|
236
|
+
return;
|
|
237
|
+
settled = true;
|
|
238
|
+
resolve({ status, body });
|
|
239
|
+
};
|
|
240
|
+
const inner = Object.create(req);
|
|
241
|
+
Object.assign(inner, { url: input.url, body: input.body, actor: input.actor, params: {} });
|
|
242
|
+
const headers = new Map();
|
|
243
|
+
const res = {
|
|
244
|
+
statusCode: 200,
|
|
245
|
+
headersSent: false,
|
|
246
|
+
locals: {},
|
|
247
|
+
status(code) {
|
|
248
|
+
res.statusCode = code;
|
|
249
|
+
return res;
|
|
250
|
+
},
|
|
251
|
+
sendStatus(code) {
|
|
252
|
+
res.statusCode = code;
|
|
253
|
+
finish(code, null);
|
|
254
|
+
return res;
|
|
255
|
+
},
|
|
256
|
+
json(body) {
|
|
257
|
+
finish(res.statusCode, body);
|
|
258
|
+
return res;
|
|
259
|
+
},
|
|
260
|
+
send(body) {
|
|
261
|
+
finish(res.statusCode, body);
|
|
262
|
+
return res;
|
|
263
|
+
},
|
|
264
|
+
end() {
|
|
265
|
+
finish(res.statusCode, null);
|
|
266
|
+
return res;
|
|
267
|
+
},
|
|
268
|
+
setHeader(name, value) {
|
|
269
|
+
headers.set(name.toLowerCase(), value);
|
|
270
|
+
return res;
|
|
271
|
+
},
|
|
272
|
+
set(name, value) {
|
|
273
|
+
if (typeof name === "string")
|
|
274
|
+
headers.set(name.toLowerCase(), value);
|
|
275
|
+
else
|
|
276
|
+
for (const [key, entry] of Object.entries(name))
|
|
277
|
+
headers.set(key.toLowerCase(), entry);
|
|
278
|
+
return res;
|
|
279
|
+
},
|
|
280
|
+
header(name, value) {
|
|
281
|
+
return res.set(name, value);
|
|
282
|
+
},
|
|
283
|
+
getHeader: (name) => headers.get(name.toLowerCase()),
|
|
284
|
+
get: (name) => headers.get(name.toLowerCase()),
|
|
285
|
+
append: () => res,
|
|
286
|
+
type: () => res,
|
|
287
|
+
vary: () => res,
|
|
288
|
+
on: () => res,
|
|
289
|
+
once: () => res,
|
|
290
|
+
};
|
|
291
|
+
handle(inner, res, (error) => {
|
|
292
|
+
if (settled)
|
|
293
|
+
return;
|
|
294
|
+
settled = true;
|
|
295
|
+
reject(error ?? new HttpError(500, "Owner relay matched no board answer route"));
|
|
296
|
+
});
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
function text(value) {
|
|
300
|
+
return typeof value === "string" && value.trim() ? value : null;
|
|
301
|
+
}
|
|
302
|
+
function optionList(entries, idKey, labelKey) {
|
|
303
|
+
return (Array.isArray(entries) ? entries : []).flatMap((entry) => {
|
|
304
|
+
const item = record(entry);
|
|
305
|
+
const id = str(item[idKey]);
|
|
306
|
+
const label = text(item[labelKey]);
|
|
307
|
+
return id && label ? [{ id, label, description: text(item.description) }] : [];
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
function cardShape(kind, payload) {
|
|
311
|
+
switch (kind) {
|
|
312
|
+
case "request_confirmation":
|
|
313
|
+
return {
|
|
314
|
+
prompt: text(payload.prompt),
|
|
315
|
+
options: [
|
|
316
|
+
{ id: "approve", label: text(payload.acceptLabel) ?? "Approve", description: null },
|
|
317
|
+
{ id: "reject", label: text(payload.rejectLabel) ?? "Reject", description: null },
|
|
318
|
+
],
|
|
319
|
+
questions: [],
|
|
320
|
+
};
|
|
321
|
+
case "request_checkbox_confirmation":
|
|
322
|
+
case "request_item_verdicts":
|
|
323
|
+
return { prompt: text(payload.prompt), options: optionList(kind === "request_item_verdicts" ? payload.items : payload.options, "id", "label"), questions: [] };
|
|
324
|
+
case "suggest_tasks": {
|
|
325
|
+
const options = optionList(payload.tasks, "clientKey", "title");
|
|
326
|
+
return { prompt: "Create " + options.length + " suggested task" + (options.length === 1 ? "" : "s"), options, questions: [] };
|
|
327
|
+
}
|
|
328
|
+
case "ask_user_questions": {
|
|
329
|
+
const questions = (Array.isArray(payload.questions) ? payload.questions : []).flatMap((entry) => {
|
|
330
|
+
const question = record(entry);
|
|
331
|
+
const id = str(question.id);
|
|
332
|
+
const prompt = text(question.prompt);
|
|
333
|
+
if (!id || !prompt)
|
|
334
|
+
return [];
|
|
335
|
+
return [{ id, prompt, selectionMode: question.selectionMode === "multi" ? "multi" : "single", options: optionList(question.options, "id", "label") }];
|
|
336
|
+
});
|
|
337
|
+
return { prompt: text(payload.title) ?? questions[0]?.prompt ?? null, options: [], questions };
|
|
338
|
+
}
|
|
339
|
+
default:
|
|
340
|
+
return { prompt: text(payload.prompt), options: [], questions: [] };
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
const GOVERNED_APPROVAL_REASON = "Board approvals (hires, budgets, governed actions) carry company-level effects and budget stops; the owner decides them in Paperclip, or an agent holding company:approvals authority uses paperclipApprovalDecision";
|
|
344
|
+
const AGENT_DECISION_REASON = "Agent decision bundles are decided on the Paperclip Decisions desk";
|
|
345
|
+
export async function listPendingDecisions(db, input) {
|
|
346
|
+
const feed = await attentionService(db).list(input.companyId, {
|
|
347
|
+
userId: input.userId ?? undefined,
|
|
348
|
+
actor: input.actor,
|
|
349
|
+
includeDismissed: true,
|
|
350
|
+
all: true,
|
|
351
|
+
allowUnscopedAll: true,
|
|
352
|
+
sort: "decide",
|
|
353
|
+
});
|
|
354
|
+
const items = feed.items.filter((item) => ["issue_thread_interaction", "approval", "decision"].includes(item.sourceKind));
|
|
355
|
+
const interactionIds = items.filter((item) => item.sourceKind === "issue_thread_interaction").map((item) => item.subject.id);
|
|
356
|
+
const cards = interactionIds.length
|
|
357
|
+
? await db
|
|
358
|
+
.select({
|
|
359
|
+
id: issueThreadInteractions.id,
|
|
360
|
+
kind: issueThreadInteractions.kind,
|
|
361
|
+
payload: issueThreadInteractions.payload,
|
|
362
|
+
title: issueThreadInteractions.title,
|
|
363
|
+
createdByUserId: issueThreadInteractions.createdByUserId,
|
|
364
|
+
})
|
|
365
|
+
.from(issueThreadInteractions)
|
|
366
|
+
.where(and(eq(issueThreadInteractions.companyId, input.companyId), inArray(issueThreadInteractions.id, interactionIds)))
|
|
367
|
+
: [];
|
|
368
|
+
const cardById = new Map(cards.map((card) => [card.id, card]));
|
|
369
|
+
const requesterIds = [
|
|
370
|
+
...new Set(items.flatMap((item) => {
|
|
371
|
+
const metadata = record(item.subject.metadata);
|
|
372
|
+
return [item.resolverAudience?.createdByAgentId, str(metadata.createdByAgentId), str(metadata.requestedByAgentId), str(metadata.originAgentId)]
|
|
373
|
+
.filter((id) => Boolean(id));
|
|
374
|
+
})),
|
|
375
|
+
];
|
|
376
|
+
const agentNames = new Map(requesterIds.length
|
|
377
|
+
? (await db
|
|
378
|
+
.select({ id: agents.id, name: agents.name })
|
|
379
|
+
.from(agents)
|
|
380
|
+
.where(and(eq(agents.companyId, input.companyId), inArray(agents.id, requesterIds)))).map((agent) => [agent.id, agent.name])
|
|
381
|
+
: []);
|
|
382
|
+
const requester = (agentId) => ({ requestedByAgentId: agentId, requestedByAgentName: agentId ? (agentNames.get(agentId) ?? null) : null });
|
|
383
|
+
return items.flatMap((item) => {
|
|
384
|
+
const metadata = record(item.subject.metadata);
|
|
385
|
+
const base = {
|
|
386
|
+
id: item.subject.id,
|
|
387
|
+
issueId: item.relatedIssue?.id ?? str(metadata.issueId) ?? str(metadata.originIssueId),
|
|
388
|
+
issueIdentifier: item.relatedIssue?.identifier ?? null,
|
|
389
|
+
issueTitle: item.relatedIssue?.title ?? null,
|
|
390
|
+
title: item.subject.title,
|
|
391
|
+
createdAt: item.createdAt,
|
|
392
|
+
href: item.subject.href,
|
|
393
|
+
};
|
|
394
|
+
if (item.sourceKind === "issue_thread_interaction") {
|
|
395
|
+
const card = cardById.get(item.subject.id);
|
|
396
|
+
if (!card)
|
|
397
|
+
return [];
|
|
398
|
+
const blocked = ownerRelayBlockedReason(card);
|
|
399
|
+
return [{
|
|
400
|
+
...base,
|
|
401
|
+
source: "interaction",
|
|
402
|
+
kind: card.kind,
|
|
403
|
+
title: card.title ?? base.title,
|
|
404
|
+
...cardShape(card.kind, record(card.payload)),
|
|
405
|
+
humanOnly: item.resolverAudience?.effectiveResolverPolicy === "human_only",
|
|
406
|
+
...requester(item.resolverAudience?.createdByAgentId ?? str(metadata.createdByAgentId)),
|
|
407
|
+
requestedByUserId: card.createdByUserId ?? null,
|
|
408
|
+
relayable: blocked === null,
|
|
409
|
+
relayBlockedReason: blocked,
|
|
410
|
+
}];
|
|
411
|
+
}
|
|
412
|
+
return [{
|
|
413
|
+
...base,
|
|
414
|
+
source: item.sourceKind === "approval" ? "approval" : "decision",
|
|
415
|
+
kind: str(metadata.type) ?? item.sourceKind,
|
|
416
|
+
prompt: decisionPrompt(item),
|
|
417
|
+
options: item.decisionVerbs.map((verb) => ({ id: verb.id, label: verb.label, description: verb.description })),
|
|
418
|
+
questions: [],
|
|
419
|
+
humanOnly: true,
|
|
420
|
+
...requester(str(metadata.requestedByAgentId) ?? str(metadata.originAgentId)),
|
|
421
|
+
requestedByUserId: str(metadata.requestedByUserId),
|
|
422
|
+
relayable: false,
|
|
423
|
+
relayBlockedReason: item.sourceKind === "approval" ? GOVERNED_APPROVAL_REASON : AGENT_DECISION_REASON,
|
|
424
|
+
}];
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
function decisionPrompt(item) {
|
|
428
|
+
const detail = item.detail;
|
|
429
|
+
if (detail && "summaryExcerpt" in detail)
|
|
430
|
+
return detail.summaryExcerpt;
|
|
431
|
+
return item.whyNow;
|
|
432
|
+
}
|
|
433
|
+
//# sourceMappingURL=owner-decision-relay.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"owner-decision-relay.js","sourceRoot":"","sources":["../../src/services/owner-decision-relay.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tickernelz/paperclip-pro-server",
|
|
3
|
-
"version": "2026.1012.
|
|
3
|
+
"version": "2026.1012.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"homepage": "https://github.com/tickernelz/paperclip-pro",
|
|
6
6
|
"bugs": {
|
|
@@ -54,25 +54,25 @@
|
|
|
54
54
|
"@openrouter/ai-sdk-provider": "3.1.0",
|
|
55
55
|
"@opentelemetry/api": "^1.9.0",
|
|
56
56
|
"@photon-ai/advanced-imessage": "2.1.0",
|
|
57
|
-
"@tickernelz/paperclip-pro-adapter-claude-local": "2026.1012.
|
|
58
|
-
"@tickernelz/paperclip-pro-adapter-codex-local": "2026.1012.
|
|
59
|
-
"@tickernelz/paperclip-pro-adapter-cursor-cloud": "2026.1012.
|
|
60
|
-
"@tickernelz/paperclip-pro-adapter-cursor-local": "2026.1012.
|
|
61
|
-
"@tickernelz/paperclip-pro-adapter-gemini-local": "2026.1012.
|
|
62
|
-
"@tickernelz/paperclip-pro-adapter-grok-local": "2026.1012.
|
|
63
|
-
"@tickernelz/paperclip-pro-adapter-kimi-local": "2026.1012.
|
|
64
|
-
"@tickernelz/paperclip-pro-adapter-omp-local": "2026.1012.
|
|
65
|
-
"@tickernelz/paperclip-pro-adapter-openclaw-gateway": "2026.1012.
|
|
66
|
-
"@tickernelz/paperclip-pro-adapter-opencode-local": "2026.1012.
|
|
67
|
-
"@tickernelz/paperclip-pro-adapter-pi-local": "2026.1012.
|
|
68
|
-
"@tickernelz/paperclip-pro-adapter-utils": "2026.1012.
|
|
69
|
-
"@tickernelz/paperclip-pro-db": "2026.1012.
|
|
70
|
-
"@tickernelz/paperclip-pro-hermes-paperclip-adapter": "2026.1012.
|
|
71
|
-
"@tickernelz/paperclip-pro-mcp-server": "2026.1012.
|
|
72
|
-
"@tickernelz/paperclip-pro-plugin-sdk": "2026.1012.
|
|
73
|
-
"@tickernelz/paperclip-pro-shared": "2026.1012.
|
|
74
|
-
"@tickernelz/paperclip-pro-skills-catalog": "2026.1012.
|
|
75
|
-
"@tickernelz/paperclip-pro-teams-catalog": "2026.1012.
|
|
57
|
+
"@tickernelz/paperclip-pro-adapter-claude-local": "2026.1012.1",
|
|
58
|
+
"@tickernelz/paperclip-pro-adapter-codex-local": "2026.1012.1",
|
|
59
|
+
"@tickernelz/paperclip-pro-adapter-cursor-cloud": "2026.1012.1",
|
|
60
|
+
"@tickernelz/paperclip-pro-adapter-cursor-local": "2026.1012.1",
|
|
61
|
+
"@tickernelz/paperclip-pro-adapter-gemini-local": "2026.1012.1",
|
|
62
|
+
"@tickernelz/paperclip-pro-adapter-grok-local": "2026.1012.1",
|
|
63
|
+
"@tickernelz/paperclip-pro-adapter-kimi-local": "2026.1012.1",
|
|
64
|
+
"@tickernelz/paperclip-pro-adapter-omp-local": "2026.1012.1",
|
|
65
|
+
"@tickernelz/paperclip-pro-adapter-openclaw-gateway": "2026.1012.1",
|
|
66
|
+
"@tickernelz/paperclip-pro-adapter-opencode-local": "2026.1012.1",
|
|
67
|
+
"@tickernelz/paperclip-pro-adapter-pi-local": "2026.1012.1",
|
|
68
|
+
"@tickernelz/paperclip-pro-adapter-utils": "2026.1012.1",
|
|
69
|
+
"@tickernelz/paperclip-pro-db": "2026.1012.1",
|
|
70
|
+
"@tickernelz/paperclip-pro-hermes-paperclip-adapter": "2026.1012.1",
|
|
71
|
+
"@tickernelz/paperclip-pro-mcp-server": "2026.1012.1",
|
|
72
|
+
"@tickernelz/paperclip-pro-plugin-sdk": "2026.1012.1",
|
|
73
|
+
"@tickernelz/paperclip-pro-shared": "2026.1012.1",
|
|
74
|
+
"@tickernelz/paperclip-pro-skills-catalog": "2026.1012.1",
|
|
75
|
+
"@tickernelz/paperclip-pro-teams-catalog": "2026.1012.1",
|
|
76
76
|
"@vercel/connect": "2.3.3",
|
|
77
77
|
"acorn": "8.18.0",
|
|
78
78
|
"acpx": "0.13.1",
|
|
@@ -128,7 +128,7 @@
|
|
|
128
128
|
"acpx"
|
|
129
129
|
],
|
|
130
130
|
"devDependencies": {
|
|
131
|
-
"@tickernelz/paperclip-pro-paperclip-runner": "2026.1012.
|
|
131
|
+
"@tickernelz/paperclip-pro-paperclip-runner": "2026.1012.1",
|
|
132
132
|
"@types/compression": "^1.8.1",
|
|
133
133
|
"@types/express": "^5.0.0",
|
|
134
134
|
"@types/express-serve-static-core": "^5.1.3",
|
package/skills/openwa/SKILL.md
CHANGED
|
@@ -270,8 +270,10 @@ anew.
|
|
|
270
270
|
either put the items in one task with a checklist or ask once with scope
|
|
271
271
|
`requester` and say the count in `proposedAction`; never ask again after the
|
|
272
272
|
first call. You write `messageToOwners`;
|
|
273
|
-
it goes as one WhatsApp bubble to each owner approval chat
|
|
274
|
-
|
|
273
|
+
it goes as one WhatsApp bubble to each owner approval chat, or to the
|
|
274
|
+
chat's owner report group when the guidance names one. Then tell the
|
|
275
|
+
requester you asked. Never ask for approval by writing in a team or project
|
|
276
|
+
group: this tool is the only way to ask.
|
|
275
277
|
2. Owners answer by replying to that bubble (quoting it) or in the OpenWA
|
|
276
278
|
Approvals tab. A quoted owner reply starts an `approval_reply` run of class
|
|
277
279
|
`owner`. Treat it as a conversation: when the owner asks a question, objects
|
|
@@ -315,6 +317,19 @@ anew.
|
|
|
315
317
|
A gated call without approval fails with `approval_required` and its
|
|
316
318
|
`category`; do not retry it. Live grants are listed in the wake `policy.grants`.
|
|
317
319
|
|
|
320
|
+
## Reporting to the owner
|
|
321
|
+
|
|
322
|
+
A chat may have an owner report group (Settings, Chats, **Report to owner
|
|
323
|
+
via**), shown in the guidance as "Owner reports for this chat go to the group
|
|
324
|
+
...". Then approval requests, owner_absent questions, reminders, any
|
|
325
|
+
`openwa_send` to an owner's number and completion reports owed to the owner go
|
|
326
|
+
to that group automatically: keep using the same tools and never pick the
|
|
327
|
+
group or the owner's direct chat yourself. The receipt of a routed send has
|
|
328
|
+
`ownerReportChat: true`. Owners answer there by quoting the bubble or with an
|
|
329
|
+
unquoted ok/ya/jangan for the newest pending request; that starts the
|
|
330
|
+
`approval_reply` run in the group, and the approved action runs in the origin
|
|
331
|
+
chat. Replies meant for the origin chat stay in it.
|
|
332
|
+
|
|
318
333
|
## Owner-only configuration
|
|
319
334
|
|
|
320
335
|
`openwa_endpoint_config` works only in owner-triggered runs; every other run gets
|
|
@@ -323,12 +338,17 @@ A gated call without approval fails with `approval_required` and its
|
|
|
323
338
|
- `senders: {add?: [{list, number, label?}], remove?: [{list, number}]}` with
|
|
324
339
|
`list` `allow` or `deny` and an E.164 `number`. A denylisted number is ignored
|
|
325
340
|
from its next message on.
|
|
326
|
-
- `chat` plus `chatSettings: {activation?, triggers?, absenceSeconds?, replyPolicy?, note?}`
|
|
341
|
+
- `chat` plus `chatSettings: {activation?, triggers?, absenceSeconds?, replyPolicy?, note?, ownerReportChat?}`
|
|
327
342
|
for one chat (default: the origin chat). `activation` is `auto`, `on` or
|
|
328
343
|
`off`; `replyPolicy` is `allowed`, `ask_owner` or `owner_absent_only`; `null`
|
|
329
344
|
clears an override. `triggers` replaces the chat's trigger overrides, so keep
|
|
330
345
|
the ones it has. A dedicated group, where you handle every message without a
|
|
331
346
|
mention, is `chatSettings: {activation: "on", triggers: {allMessages: true}}`.
|
|
347
|
+
`ownerReportChat` (a group chatRef or id, found with `openwa_find`) sends the
|
|
348
|
+
chat's owner reports and approval requests to that group, for example when
|
|
349
|
+
the owner says "laporan grup ini ke [BOT] DCM"; `null` returns to the owner's
|
|
350
|
+
direct chat. The group must have an owner as member and this number active in
|
|
351
|
+
it, otherwise the call fails with `invalid_arguments`.
|
|
332
352
|
- `approvals: {createTask?, externalTools?, crossChatSend?, waAdmin?, gatewayAdmin?, reminderMinutes?, maxReminders?, pendingTtlHours?}`:
|
|
333
353
|
approval toggles, reminders and the pending request lifetime in hours (1 to 168).
|
|
334
354
|
- `burstWindowSeconds`: 0 to 10 (default 3, 0 = off); messages of one chat sent
|
|
@@ -355,6 +375,34 @@ accepted and audited; questions, verdicts, governed approvals and cards marked
|
|
|
355
375
|
call `{operation: "close", idempotencyKey}` (optionally with `issues`); `list` shows the
|
|
356
376
|
live windows. Other runs get `owner_only`.
|
|
357
377
|
|
|
378
|
+
## Paperclip cards for the owner (owner runs only)
|
|
379
|
+
|
|
380
|
+
A Paperclip card that waits for a person (confirmation, plan approval, question,
|
|
381
|
+
checkbox or verdict card, human-only included) is never "only answerable in
|
|
382
|
+
Paperclip" when the owner is talking to you here. When an owner asks what is
|
|
383
|
+
waiting on them, call `paperclipListPendingDecisions` and summarize each item:
|
|
384
|
+
issue, what it asks, its options. When the owner's own message explicitly
|
|
385
|
+
approves, rejects or answers one specific card, call
|
|
386
|
+
`paperclipAnswerDecisionForOwner` with `issueId`, `interactionId`, the answer
|
|
387
|
+
(`decision` approve or reject with `optionIds` or `reason`, `answers` for
|
|
388
|
+
questions, `verdicts` for verdict cards) and `ownerMessageRef` set to that
|
|
389
|
+
message's `id` from this run's `messages`. The server checks that this run was
|
|
390
|
+
started by that owner's own message and records the answer as theirs, relayed by
|
|
391
|
+
you, through the same path as the Paperclip button; the requester wakes as usual.
|
|
392
|
+
Then confirm in the chat exactly what you submitted.
|
|
393
|
+
|
|
394
|
+
- Never answer a card without the owner's explicit words for that card. A
|
|
395
|
+
general "ok" answers the one card you just presented; ask when it could mean
|
|
396
|
+
more than one. One message answers one card unless it names each card
|
|
397
|
+
(issue identifier or card id).
|
|
398
|
+
- `owner_confirmation_required` (403) means this run was not started by the
|
|
399
|
+
owner's own message, the owner is not linked to a Paperclip user, or that
|
|
400
|
+
message was already used; ask the owner to answer here again or in Paperclip.
|
|
401
|
+
A 409 means the card is already resolved. Items marked not relayable (board
|
|
402
|
+
approvals, agent decisions, governed tool/secret/connection cards, OpenWA
|
|
403
|
+
approval requests) stay with their own controls; say so and link them.
|
|
404
|
+
- Members and non-owner runs cannot relay; tell them the owner must answer.
|
|
405
|
+
|
|
358
406
|
## Linked numbers (owner runs only)
|
|
359
407
|
|
|
360
408
|
The board may link other WhatsApp numbers on the same gateway, such as an
|
|
@@ -761,7 +761,7 @@ For detailed API tables, JSON response schemas, worked examples (IC and Manager
|
|
|
761
761
|
|
|
762
762
|
### Conversational confirmation answers
|
|
763
763
|
|
|
764
|
-
When the user answers a pending confirmation in a message, record the answer before acting. Read current cards and comments with `paperclipListIssueInteractions` and `paperclipListComments`, then call `paperclipApiRequest` with `method: "POST"`, `path: "/issues/{issueId}/interactions/{interactionId}/resolve-from-comment"`, and a `jsonBody` carrying `commentId`, `decision: "accept" | "reject"`, and explicit `selectedOptionIds` for checkbox acceptance (native runners use `call_api`). Ambiguous replies among proposals require clarification. Revisions are not acceptance. Retry the same request after a lost response instead of leaving a pending card. Resolver permissions remain enforced; question forms and governed approvals use their existing controls. See the API reference for scope and retry rules.
|
|
764
|
+
When the user answers a pending confirmation in a message, record the answer before acting. Read current cards and comments with `paperclipListIssueInteractions` and `paperclipListComments`, then call `paperclipApiRequest` with `method: "POST"`, `path: "/issues/{issueId}/interactions/{interactionId}/resolve-from-comment"`, and a `jsonBody` carrying `commentId`, `decision: "accept" | "reject"`, and explicit `selectedOptionIds` for checkbox acceptance (native runners use `call_api`). Ambiguous replies among proposals require clarification. Revisions are not acceptance. Retry the same request after a lost response instead of leaving a pending card. Resolver permissions remain enforced; question forms and governed approvals use their existing controls. See the API reference for scope and retry rules. Human-only cards are answered by a person, but that person does not have to open Paperclip. When a board user's own message started your run (an owner WhatsApp message in an OpenWA run, or their comment that woke you) and it explicitly approves, rejects or answers one specific pending card, call `paperclipAnswerDecisionForOwner` with `issueId`, `interactionId`, the answer (`decision` with `optionIds` or `reason`, `answers`, or `verdicts`) and `ownerMessageRef` set to that message's id. The server verifies the message, records the answer as that user's (relayed by you) through the board answer path, and wakes the requester. List what is waiting with `paperclipListPendingDecisions`. Never answer without the person's explicit words for that card, never reuse one message for several cards unless it names each, and confirm back what you submitted. `owner_confirmation_required` (403) means the run lacks that authority; a 409 means the card is already resolved. Board approvals, agent decisions and governed tool, secret or connection cards are listed read-only and keep their own controls.
|
|
765
765
|
|
|
766
766
|
In Agent Chat, a question is optional: if the user moves on to another topic, answer that message without requiring them to answer or resolve the earlier question. Leave its card unanswered so they can reopen it later. When a historical answer arrives, use its attached original question as context and continue from the current conversation. Unrelated messages are never approval.
|
|
767
767
|
|