crewly 1.20.459 → 1.20.461
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/config/skills/agent/core/reply/SKILL.md +1 -0
- package/config/skills/agent/core/reply/execute.sh +7 -1
- package/config/skills/agent/core/reply/execute.test.sh +3 -0
- package/dist/backend/backend/src/controllers/chat/agent-reply.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/chat/agent-reply.controller.js +5 -0
- package/dist/backend/backend/src/controllers/chat/agent-reply.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/chat/chat.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/chat/chat.controller.js +1 -0
- package/dist/backend/backend/src/controllers/chat/chat.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/chat-v2/chat-v2.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/chat-v2/chat-v2.controller.js +1 -0
- package/dist/backend/backend/src/controllers/chat-v2/chat-v2.controller.js.map +1 -1
- package/dist/backend/backend/src/index.d.ts.map +1 -1
- package/dist/backend/backend/src/index.js +29 -0
- package/dist/backend/backend/src/index.js.map +1 -1
- package/dist/backend/backend/src/services/decisions/decision-card.d.ts +15 -1
- package/dist/backend/backend/src/services/decisions/decision-card.d.ts.map +1 -1
- package/dist/backend/backend/src/services/decisions/decision-card.js +20 -4
- package/dist/backend/backend/src/services/decisions/decision-card.js.map +1 -1
- package/dist/backend/backend/src/services/decisions/decision.service.d.ts +2 -0
- package/dist/backend/backend/src/services/decisions/decision.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/decisions/decision.service.js +5 -4
- package/dist/backend/backend/src/services/decisions/decision.service.js.map +1 -1
- package/dist/backend/backend/src/services/orc/private-share-decisions.d.ts +139 -0
- package/dist/backend/backend/src/services/orc/private-share-decisions.d.ts.map +1 -0
- package/dist/backend/backend/src/services/orc/private-share-decisions.js +200 -0
- package/dist/backend/backend/src/services/orc/private-share-decisions.js.map +1 -0
- package/dist/backend/backend/src/services/orc/reply-audience.d.ts +26 -0
- package/dist/backend/backend/src/services/orc/reply-audience.d.ts.map +1 -1
- package/dist/backend/backend/src/services/orc/reply-audience.js +61 -9
- package/dist/backend/backend/src/services/orc/reply-audience.js.map +1 -1
- package/dist/backend/backend/src/services/orc/reply-destination.wiring.d.ts +26 -0
- package/dist/backend/backend/src/services/orc/reply-destination.wiring.d.ts.map +1 -1
- package/dist/backend/backend/src/services/orc/reply-destination.wiring.js +66 -9
- package/dist/backend/backend/src/services/orc/reply-destination.wiring.js.map +1 -1
- package/dist/backend/backend/src/services/v3/owner-receipt/owner-pulls-weekly.d.ts.map +1 -1
- package/dist/backend/backend/src/services/v3/owner-receipt/owner-pulls-weekly.js +1 -0
- package/dist/backend/backend/src/services/v3/owner-receipt/owner-pulls-weekly.js.map +1 -1
- package/dist/backend/backend/src/types/decision.types.d.ts +26 -1
- package/dist/backend/backend/src/types/decision.types.d.ts.map +1 -1
- package/dist/backend/build-info.json +2 -2
- package/dist/cli/backend/src/services/decisions/decision-card.d.ts +15 -1
- package/dist/cli/backend/src/services/decisions/decision-card.d.ts.map +1 -1
- package/dist/cli/backend/src/services/decisions/decision-card.js +20 -4
- package/dist/cli/backend/src/services/decisions/decision-card.js.map +1 -1
- package/dist/cli/backend/src/services/decisions/decision.service.d.ts +2 -0
- package/dist/cli/backend/src/services/decisions/decision.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/decisions/decision.service.js +5 -4
- package/dist/cli/backend/src/services/decisions/decision.service.js.map +1 -1
- package/dist/cli/backend/src/types/decision.types.d.ts +26 -1
- package/dist/cli/backend/src/types/decision.types.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Private-share decisions (crewly#969, specs/per-person-access.md).
|
|
3
|
+
*
|
|
4
|
+
* When the audience check moves an agent's reply from a shared place to the
|
|
5
|
+
* owner's DM (it draws on someone's private data), the owner gets a card
|
|
6
|
+
* under it: *Share in #room?* — Share / Keep private. A tap on Share posts
|
|
7
|
+
* the reply where it was going, as written, and logs the share; anything
|
|
8
|
+
* else leaves it in the DM. The default, applied unanswered after a day, is
|
|
9
|
+
* Keep private.
|
|
10
|
+
*
|
|
11
|
+
* The post happens in exactly one place, {@link PrivateShareDecisions.onSettled},
|
|
12
|
+
* which the decision service calls when the card settles. Nothing an agent
|
|
13
|
+
* can call reaches it, so an agent cannot share its own held reply (the
|
|
14
|
+
* owner's word in the DM plus `reply --share` remains the other way).
|
|
15
|
+
*
|
|
16
|
+
* @module services/orc/private-share-decisions
|
|
17
|
+
*/
|
|
18
|
+
import { LoggerService } from '../core/logger.service.js';
|
|
19
|
+
import { recordActivity } from '../activity/activity-log.service.js';
|
|
20
|
+
import { PRIVATE_REPLY_ACTIONS } from './reply-audience.js';
|
|
21
|
+
import { stripTraceMarkers } from '../trace/trace-markers.js';
|
|
22
|
+
/** Option keys on the card. */
|
|
23
|
+
export const PRIVATE_SHARE_KEYS = { SHARE: 'share', KEEP: 'keep' };
|
|
24
|
+
/** How long the card waits before the (safe) default, Keep private, applies. */
|
|
25
|
+
export const PRIVATE_SHARE_DEADLINE_MS = 24 * 60 * 60 * 1000;
|
|
26
|
+
/** Reply characters quoted on the card. */
|
|
27
|
+
const PREVIEW_CHARS = 400;
|
|
28
|
+
/**
|
|
29
|
+
* Who acted on the card for the activity log: the owner when they answered
|
|
30
|
+
* and how; a deadline outcome is the system.
|
|
31
|
+
*
|
|
32
|
+
* @param decision - Settled decision
|
|
33
|
+
* @returns Actor
|
|
34
|
+
*/
|
|
35
|
+
function decisionActor(decision) {
|
|
36
|
+
if (decision.answeredVia === 'deadline' || decision.status === 'expired' || decision.status === 'defaulted')
|
|
37
|
+
return { type: 'system', via: 'deadline' };
|
|
38
|
+
return { type: 'owner', ...(decision.answeredBy ? { id: decision.answeredBy } : {}), ...(decision.answeredVia ? { via: decision.answeredVia } : {}) };
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Names for a list of person ids ("Alice and Bob").
|
|
42
|
+
*
|
|
43
|
+
* @param people - Person ids
|
|
44
|
+
* @param name - Lookup
|
|
45
|
+
* @returns Names joined for a sentence
|
|
46
|
+
*/
|
|
47
|
+
function namesOf(people, name) {
|
|
48
|
+
const names = people.map((p) => name?.(p) || p);
|
|
49
|
+
if (names.length <= 1)
|
|
50
|
+
return names.join('');
|
|
51
|
+
return `${names.slice(0, -1).join(', ')} and ${names[names.length - 1]}`;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Raises the share card for a held reply and applies the owner's answer.
|
|
55
|
+
*/
|
|
56
|
+
export class PrivateShareDecisions {
|
|
57
|
+
deps;
|
|
58
|
+
logger;
|
|
59
|
+
constructor(deps) {
|
|
60
|
+
this.deps = deps;
|
|
61
|
+
this.logger = LoggerService.getInstance().createComponentLogger('PrivateShareDecisions');
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Whether a card would go up for a held reply right now (the DM copy's
|
|
65
|
+
* note can then point at it).
|
|
66
|
+
*
|
|
67
|
+
* @returns True when the decision service is up and Slack is connected
|
|
68
|
+
*/
|
|
69
|
+
offersCard() {
|
|
70
|
+
try {
|
|
71
|
+
return !!this.deps.decisions() && this.deps.canAsk();
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* A reply was moved to the owner DM: ask the owner, in that DM, whether to
|
|
79
|
+
* post it where it was going. One open card per agent + place + text.
|
|
80
|
+
*
|
|
81
|
+
* @param held - The held reply
|
|
82
|
+
* @returns The card's decision, or null when none was raised
|
|
83
|
+
*/
|
|
84
|
+
async onHeld(held) {
|
|
85
|
+
const decisions = this.deps.decisions();
|
|
86
|
+
if (!decisions || !this.deps.canAsk())
|
|
87
|
+
return null;
|
|
88
|
+
const open = await decisions.list('open').catch(() => []);
|
|
89
|
+
const same = open.find((d) => d.kind === 'private_share' && d.privateShare?.agentSession === held.session && d.privateShare.heldFrom === held.heldFrom && d.privateShare.content === held.content);
|
|
90
|
+
if (same) {
|
|
91
|
+
this.logger.info('Held reply asked again while its card is open — reusing it', { decisionId: same.id, session: held.session });
|
|
92
|
+
return same;
|
|
93
|
+
}
|
|
94
|
+
const agentName = (await this.deps.agentNameOf?.(held.session).catch(() => undefined)) ?? held.session;
|
|
95
|
+
const who = namesOf(held.people, this.deps.personName);
|
|
96
|
+
const slackDm = this.deps.slackChannelOf(held.ownerDm);
|
|
97
|
+
const shown = stripTraceMarkers(held.content).trim();
|
|
98
|
+
const preview = shown.length > PREVIEW_CHARS ? `${shown.slice(0, PREVIEW_CHARS)}…` : shown;
|
|
99
|
+
const decision = await decisions.askPrebuilt({
|
|
100
|
+
kind: 'private_share',
|
|
101
|
+
asker: held.session,
|
|
102
|
+
question: `Share ${agentName}'s reply in ${held.heldFrom}? It draws on ${who}'s data, which only you and they may see.`,
|
|
103
|
+
options: [
|
|
104
|
+
{ key: PRIVATE_SHARE_KEYS.SHARE, label: 'Share', detail: `post it in ${held.heldFrom} as written, once` },
|
|
105
|
+
{ key: PRIVATE_SHARE_KEYS.KEEP, label: 'Keep private', detail: 'it stays here in your DM' },
|
|
106
|
+
],
|
|
107
|
+
defaultKey: PRIVATE_SHARE_KEYS.KEEP,
|
|
108
|
+
yesKey: PRIVATE_SHARE_KEYS.SHARE,
|
|
109
|
+
deadline: new Date((this.deps.now?.() ?? Date.now()) + PRIVATE_SHARE_DEADLINE_MS),
|
|
110
|
+
title: 'Private data',
|
|
111
|
+
body: [`> ${preview.replace(/\n/g, '\n> ')}`],
|
|
112
|
+
...(slackDm ? { place: { slackChannelId: slackDm } } : {}),
|
|
113
|
+
privateShare: {
|
|
114
|
+
agentSession: held.session,
|
|
115
|
+
agentName,
|
|
116
|
+
content: held.content,
|
|
117
|
+
destination: held.destination,
|
|
118
|
+
heldFrom: held.heldFrom,
|
|
119
|
+
people: held.people,
|
|
120
|
+
ownerDm: held.ownerDm,
|
|
121
|
+
},
|
|
122
|
+
});
|
|
123
|
+
this.logger.info('Asked the owner whether to share a held reply', { decisionId: decision.id, session: held.session, heldFrom: held.heldFrom });
|
|
124
|
+
return decision;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* A `private_share` card settled. The only place a held reply is posted
|
|
128
|
+
* from a card.
|
|
129
|
+
*
|
|
130
|
+
* @param decision - The settled decision
|
|
131
|
+
* @returns Note for the agent, or null (a quiet default wakes nobody)
|
|
132
|
+
*/
|
|
133
|
+
async onSettled(decision) {
|
|
134
|
+
const subject = decision.privateShare;
|
|
135
|
+
if (!subject)
|
|
136
|
+
return null;
|
|
137
|
+
const shareChosen = decision.status === 'resolved' && decision.chosenKey === PRIVATE_SHARE_KEYS.SHARE;
|
|
138
|
+
const record = this.deps.record ?? recordActivity;
|
|
139
|
+
if (!shareChosen) {
|
|
140
|
+
this.logger.info('Held reply kept private', { decisionId: decision.id, status: decision.status });
|
|
141
|
+
if (decision.status !== 'resolved')
|
|
142
|
+
return null;
|
|
143
|
+
record({
|
|
144
|
+
actor: decisionActor(decision),
|
|
145
|
+
action: PRIVATE_REPLY_ACTIONS.KEPT,
|
|
146
|
+
target: { type: 'conversation', id: subject.ownerDm },
|
|
147
|
+
after: { people: subject.people, heldFrom: subject.heldFrom, decisionId: decision.id },
|
|
148
|
+
note: `the owner kept ${subject.agentSession}'s reply held from ${subject.heldFrom} private`,
|
|
149
|
+
});
|
|
150
|
+
return `[PRIVATE] The owner kept your reply held from ${subject.heldFrom} in their DM. Do not post it there another way.`;
|
|
151
|
+
}
|
|
152
|
+
const held = {
|
|
153
|
+
session: subject.agentSession,
|
|
154
|
+
content: subject.content,
|
|
155
|
+
destination: subject.destination,
|
|
156
|
+
heldFrom: subject.heldFrom,
|
|
157
|
+
people: subject.people,
|
|
158
|
+
ownerDm: subject.ownerDm,
|
|
159
|
+
};
|
|
160
|
+
let posted;
|
|
161
|
+
try {
|
|
162
|
+
posted = await this.deps.post(held);
|
|
163
|
+
}
|
|
164
|
+
catch (err) {
|
|
165
|
+
posted = { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
166
|
+
}
|
|
167
|
+
if (!posted.ok) {
|
|
168
|
+
this.logger.warn('Owner tapped Share but the held reply could not be posted', { decisionId: decision.id, error: posted.error });
|
|
169
|
+
return `[PRIVATE] The owner tapped Share on your reply held from ${subject.heldFrom}, but it could not be posted there: ${posted.error}. Tell the owner in your DM.`;
|
|
170
|
+
}
|
|
171
|
+
record({
|
|
172
|
+
actor: decisionActor(decision),
|
|
173
|
+
action: PRIVATE_REPLY_ACTIONS.SHARED,
|
|
174
|
+
target: held.destination.kind === 'conversation' ? { type: 'conversation', id: held.destination.conversationId } : { type: 'reply', id: subject.agentSession },
|
|
175
|
+
after: { people: subject.people, sharedTo: posted.place, decisionId: decision.id },
|
|
176
|
+
note: `the owner shared ${subject.agentSession}'s reply drawing on ${namesOf(subject.people, this.deps.personName)}'s data in ${posted.place} from the card`,
|
|
177
|
+
});
|
|
178
|
+
this.logger.info('Held reply shared from the card', { decisionId: decision.id, session: subject.agentSession, place: posted.place });
|
|
179
|
+
return `[PRIVATE] The owner shared your reply held from ${subject.heldFrom}; it is posted there now. Nothing more to send.`;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
let instance = null;
|
|
183
|
+
/**
|
|
184
|
+
* The private-share handler the composition root registered, or null.
|
|
185
|
+
*
|
|
186
|
+
* @returns Handler or null
|
|
187
|
+
*/
|
|
188
|
+
export function getPrivateShareDecisions() {
|
|
189
|
+
return instance;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Register (or clear, with null) the private-share handler the reply
|
|
193
|
+
* delivery raises cards through.
|
|
194
|
+
*
|
|
195
|
+
* @param handler - Handler or null
|
|
196
|
+
*/
|
|
197
|
+
export function setPrivateShareDecisions(handler) {
|
|
198
|
+
instance = handler;
|
|
199
|
+
}
|
|
200
|
+
//# sourceMappingURL=private-share-decisions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"private-share-decisions.js","sourceRoot":"","sources":["../../../../../../backend/src/services/orc/private-share-decisions.ts"],"names":[],"mappings":"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"}
|
|
@@ -22,6 +22,10 @@ export declare const PRIVATE_REPLY_ACTIONS: {
|
|
|
22
22
|
readonly REDIRECTED: "connector.private_output.redirected";
|
|
23
23
|
/** The reply was held: no owner DM to move it to */
|
|
24
24
|
readonly HELD: "connector.private_output.held";
|
|
25
|
+
/** The owner said to share it: posted to the shared place with `--share` */
|
|
26
|
+
readonly SHARED: "connector.private_output.shared";
|
|
27
|
+
/** The owner kept a held reply in their DM (the card's Keep private) */
|
|
28
|
+
readonly KEPT: "connector.private_output.kept";
|
|
25
29
|
};
|
|
26
30
|
/** What the check needs to know. */
|
|
27
31
|
export interface ReplyAudienceDeps {
|
|
@@ -39,6 +43,8 @@ export interface ReplyAudienceDeps {
|
|
|
39
43
|
conversationPlace?(conversationId: string): string | null;
|
|
40
44
|
/** Activity-log writer (default: the real one) */
|
|
41
45
|
record?(input: ActivityEntryInput): void;
|
|
46
|
+
/** Whether a Share / Keep private card follows the DM copy (the note then points at it) */
|
|
47
|
+
offersCard?(): boolean;
|
|
42
48
|
}
|
|
43
49
|
/** The check's verdict. */
|
|
44
50
|
export type ReplyAudienceVerdict =
|
|
@@ -74,6 +80,26 @@ export type ReplyAudienceVerdict =
|
|
|
74
80
|
export declare function isSharedPlace(dest: Exclude<ReplyDestination, {
|
|
75
81
|
kind: 'unresolved';
|
|
76
82
|
}>, deps: ReplyAudienceDeps): boolean;
|
|
83
|
+
/**
|
|
84
|
+
* The people (other than the owner) whose grants the session read recently.
|
|
85
|
+
*
|
|
86
|
+
* @param session - Agent session
|
|
87
|
+
* @param deps - Lookups
|
|
88
|
+
* @returns Person ids; empty when none or when the tracker fails
|
|
89
|
+
*/
|
|
90
|
+
export declare function privatePeopleOf(session: string, deps: Pick<ReplyAudienceDeps, 'recentPeople'>): string[];
|
|
91
|
+
/**
|
|
92
|
+
* Note that the owner had a private-sourced reply posted to a shared place
|
|
93
|
+
* (`reply --share` after the owner said so in the agent's DM).
|
|
94
|
+
*
|
|
95
|
+
* @param session - Agent session
|
|
96
|
+
* @param dest - Where it goes
|
|
97
|
+
* @param deps - Lookups
|
|
98
|
+
* @returns The people the reply draws on (empty: nothing private, nothing logged)
|
|
99
|
+
*/
|
|
100
|
+
export declare function recordPrivateShare(session: string, dest: Exclude<ReplyDestination, {
|
|
101
|
+
kind: 'unresolved';
|
|
102
|
+
}>, deps: ReplyAudienceDeps): string[];
|
|
77
103
|
/**
|
|
78
104
|
* Check whether a reply may go where the resolver sent it.
|
|
79
105
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reply-audience.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/orc/reply-audience.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,EAAkB,KAAK,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AAE9F,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AAExE,iDAAiD;AACjD,eAAO,MAAM,qBAAqB;IAChC,0CAA0C;;IAE1C,oDAAoD;;
|
|
1
|
+
{"version":3,"file":"reply-audience.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/orc/reply-audience.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,EAAkB,KAAK,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AAE9F,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AAExE,iDAAiD;AACjD,eAAO,MAAM,qBAAqB;IAChC,0CAA0C;;IAE1C,oDAAoD;;IAEpD,4EAA4E;;IAE5E,wEAAwE;;CAEhE,CAAC;AAEX,oCAAoC;AACpC,MAAM,WAAW,iBAAiB;IAChC,kFAAkF;IAClF,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACxC,oFAAoF;IACpF,gBAAgB,CAAC,cAAc,EAAE,MAAM,GAAG,IAAI,GAAG,QAAQ,GAAG,SAAS,CAAC;IACtE,2FAA2F;IAC3F,cAAc,CAAC,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IACvD,iDAAiD;IACjD,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACjD,8BAA8B;IAC9B,UAAU,CAAC,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IAC5C,6DAA6D;IAC7D,iBAAiB,CAAC,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAC1D,kDAAkD;IAClD,MAAM,CAAC,CAAC,KAAK,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACzC,2FAA2F;IAC3F,UAAU,CAAC,IAAI,OAAO,CAAC;CACxB;AAED,2BAA2B;AAC3B,MAAM,MAAM,oBAAoB;AAC9B,4DAA4D;AAC1D;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE;AAClB,+EAA+E;GAC7E;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,WAAW,EAAE,OAAO,CAAC,gBAAgB,EAAE;QAAE,IAAI,EAAE,cAAc,CAAA;KAAE,CAAC,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE;AAC1I,qFAAqF;GACnF;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtF;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,OAAO,CAAC,gBAAgB,EAAE;IAAE,IAAI,EAAE,YAAY,CAAA;CAAE,CAAC,EAAE,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAYvH;AA+BD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,iBAAiB,EAAE,cAAc,CAAC,GAAG,MAAM,EAAE,CAMxG;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,gBAAgB,EAAE;IAAE,IAAI,EAAE,YAAY,CAAA;CAAE,CAAC,EAAE,IAAI,EAAE,iBAAiB,GAAG,MAAM,EAAE,CAY9I;AAgBD;;;;;;;GAOG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,OAAO,CAAC,gBAAgB,EAAE;IAAE,IAAI,EAAE,YAAY,CAAA;CAAE,CAAC,EACvD,IAAI,EAAE,iBAAiB,GACtB,OAAO,CAAC,oBAAoB,CAAC,CA8C/B"}
|
|
@@ -23,6 +23,10 @@ export const PRIVATE_REPLY_ACTIONS = {
|
|
|
23
23
|
REDIRECTED: 'connector.private_output.redirected',
|
|
24
24
|
/** The reply was held: no owner DM to move it to */
|
|
25
25
|
HELD: 'connector.private_output.held',
|
|
26
|
+
/** The owner said to share it: posted to the shared place with `--share` */
|
|
27
|
+
SHARED: 'connector.private_output.shared',
|
|
28
|
+
/** The owner kept a held reply in their DM (the card's Keep private) */
|
|
29
|
+
KEPT: 'connector.private_output.kept',
|
|
26
30
|
};
|
|
27
31
|
/**
|
|
28
32
|
* Whether a resolved destination is a place other people can read.
|
|
@@ -81,21 +85,67 @@ function namesOf(people, deps) {
|
|
|
81
85
|
return `${names.slice(0, -1).join(', ')} and ${names[names.length - 1]}`;
|
|
82
86
|
}
|
|
83
87
|
/**
|
|
84
|
-
*
|
|
88
|
+
* The people (other than the owner) whose grants the session read recently.
|
|
85
89
|
*
|
|
86
90
|
* @param session - Agent session
|
|
87
|
-
* @param dest - The resolved destination
|
|
88
91
|
* @param deps - Lookups
|
|
89
|
-
* @returns
|
|
92
|
+
* @returns Person ids; empty when none or when the tracker fails
|
|
90
93
|
*/
|
|
91
|
-
export
|
|
92
|
-
let people;
|
|
94
|
+
export function privatePeopleOf(session, deps) {
|
|
93
95
|
try {
|
|
94
|
-
|
|
96
|
+
return deps.recentPeople(session).filter((p) => p && p !== PEOPLE_CONSTANTS.OWNER_ID);
|
|
95
97
|
}
|
|
96
98
|
catch {
|
|
97
|
-
return
|
|
99
|
+
return [];
|
|
98
100
|
}
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Note that the owner had a private-sourced reply posted to a shared place
|
|
104
|
+
* (`reply --share` after the owner said so in the agent's DM).
|
|
105
|
+
*
|
|
106
|
+
* @param session - Agent session
|
|
107
|
+
* @param dest - Where it goes
|
|
108
|
+
* @param deps - Lookups
|
|
109
|
+
* @returns The people the reply draws on (empty: nothing private, nothing logged)
|
|
110
|
+
*/
|
|
111
|
+
export function recordPrivateShare(session, dest, deps) {
|
|
112
|
+
const people = privatePeopleOf(session, deps);
|
|
113
|
+
if (people.length === 0 || !isSharedPlace(dest, deps))
|
|
114
|
+
return [];
|
|
115
|
+
const place = placeOf(dest, deps);
|
|
116
|
+
(deps.record ?? recordActivity)({
|
|
117
|
+
actor: { type: 'agent', id: session },
|
|
118
|
+
action: PRIVATE_REPLY_ACTIONS.SHARED,
|
|
119
|
+
target: dest.kind === 'conversation' ? { type: 'conversation', id: dest.conversationId } : { type: 'reply', id: session },
|
|
120
|
+
after: { people, sharedTo: place },
|
|
121
|
+
note: `${session} posted a reply drawing on ${namesOf(people, deps)}'s data to ${place} after the owner said to share it`,
|
|
122
|
+
});
|
|
123
|
+
return people;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Whether a share card follows the DM copy (never throws).
|
|
127
|
+
*
|
|
128
|
+
* @param deps - Lookups
|
|
129
|
+
* @returns True when the card is offered
|
|
130
|
+
*/
|
|
131
|
+
function offersCard(deps) {
|
|
132
|
+
try {
|
|
133
|
+
return deps.offersCard?.() === true;
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Check whether a reply may go where the resolver sent it.
|
|
141
|
+
*
|
|
142
|
+
* @param session - Agent session
|
|
143
|
+
* @param dest - The resolved destination
|
|
144
|
+
* @param deps - Lookups
|
|
145
|
+
* @returns The verdict (never throws)
|
|
146
|
+
*/
|
|
147
|
+
export async function checkReplyAudience(session, dest, deps) {
|
|
148
|
+
const people = privatePeopleOf(session, deps);
|
|
99
149
|
if (people.length === 0)
|
|
100
150
|
return { kind: 'open' };
|
|
101
151
|
if (!isSharedPlace(dest, deps))
|
|
@@ -115,7 +165,7 @@ export async function checkReplyAudience(session, dest, deps) {
|
|
|
115
165
|
return {
|
|
116
166
|
kind: 'held',
|
|
117
167
|
reason: `it draws on ${who}'s data (read through their connection in the last minutes) and ${heldFrom} has other members`,
|
|
118
|
-
fix: `send it to the owner's DM (ask your team lead to open one)
|
|
168
|
+
fix: `send it to the owner's DM (ask your team lead to open one); once the owner says to share it there, run the same reply with --share`,
|
|
119
169
|
people,
|
|
120
170
|
heldFrom,
|
|
121
171
|
};
|
|
@@ -135,7 +185,9 @@ export async function checkReplyAudience(session, dest, deps) {
|
|
|
135
185
|
source: 'owner-dm',
|
|
136
186
|
reason: `held from ${heldFrom}: it draws on ${who}'s data`,
|
|
137
187
|
},
|
|
138
|
-
note:
|
|
188
|
+
note: offersCard(deps)
|
|
189
|
+
? `_Held from ${heldFrom}: this draws on ${who}'s data, which only you and they may see. Tap *Share* on the card below, or say "share it" here, and I will post it there._`
|
|
190
|
+
: `_Held from ${heldFrom}: this draws on ${who}'s data, which only you and they may see. Say "share it" here and I will post it there._`,
|
|
139
191
|
people,
|
|
140
192
|
heldFrom,
|
|
141
193
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reply-audience.js","sourceRoot":"","sources":["../../../../../../backend/src/services/orc/reply-audience.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,cAAc,EAA2B,MAAM,qCAAqC,CAAC;AAC9F,OAAO,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAGzD,iDAAiD;AACjD,MAAM,CAAC,MAAM,qBAAqB,GAAG;IACnC,0CAA0C;IAC1C,UAAU,EAAE,qCAAqC;IACjD,oDAAoD;IACpD,IAAI,EAAE,+BAA+B;CAC7B,CAAC;
|
|
1
|
+
{"version":3,"file":"reply-audience.js","sourceRoot":"","sources":["../../../../../../backend/src/services/orc/reply-audience.ts"],"names":[],"mappings":"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"}
|
|
@@ -12,6 +12,7 @@ import { type WorkDestinationDeps } from './work-item-destination.wiring.js';
|
|
|
12
12
|
import { type MessageRoute, type RouteCheckOutcome } from './message-route.js';
|
|
13
13
|
import { type TurnTrigger } from '../trace/turn-trigger.js';
|
|
14
14
|
import { type ReplyAudienceDeps } from './reply-audience.js';
|
|
15
|
+
import { type HeldReply, type HeldReplyPost } from './private-share-decisions.js';
|
|
15
16
|
/** Forget recent deliveries (tests). */
|
|
16
17
|
export declare function resetReplyDeliveryGuardForTesting(): void;
|
|
17
18
|
/** Delivery into a chat-v2 conversation (chat.controller `deliverAgentReplyToConversation`). */
|
|
@@ -93,6 +94,12 @@ export interface ReplyDeliveryDeps {
|
|
|
93
94
|
* place. Omitted: no check.
|
|
94
95
|
*/
|
|
95
96
|
audience?: ReplyAudienceDeps;
|
|
97
|
+
/**
|
|
98
|
+
* A reply was moved to the owner DM: raise the Share / Keep private card
|
|
99
|
+
* under it (crewly#969). Called after the DM copy landed; a failure is
|
|
100
|
+
* logged, the DM copy stands.
|
|
101
|
+
*/
|
|
102
|
+
privateShareCard?: (held: HeldReply) => Promise<unknown>;
|
|
96
103
|
}
|
|
97
104
|
/** What a delivery did. */
|
|
98
105
|
export type ReplyDelivery = {
|
|
@@ -107,6 +114,8 @@ export type ReplyDelivery = {
|
|
|
107
114
|
messageTs?: string;
|
|
108
115
|
/** The agent an internal message went to (work with an agent origin, crewly#1357) */
|
|
109
116
|
agentSession?: string;
|
|
117
|
+
/** The shared place the reply was held from when it went to the owner DM instead (crewly#969) */
|
|
118
|
+
heldFrom?: string;
|
|
110
119
|
} | {
|
|
111
120
|
ok: false;
|
|
112
121
|
error: string;
|
|
@@ -123,6 +132,12 @@ export interface DeliverReplyInput {
|
|
|
123
132
|
noOwnerDm?: boolean;
|
|
124
133
|
/** Post even when a colleague already answered the owner here (`--adds-new`) */
|
|
125
134
|
addsNew?: boolean;
|
|
135
|
+
/**
|
|
136
|
+
* The owner said in the agent's DM to share a private-sourced reply in the
|
|
137
|
+
* shared place it was held from (`--share`, crewly#969). Honoured only
|
|
138
|
+
* while the owner's message in that DM is recent.
|
|
139
|
+
*/
|
|
140
|
+
share?: boolean;
|
|
126
141
|
}
|
|
127
142
|
/**
|
|
128
143
|
* Resolve and deliver an agent's message. Never guesses: a destination that
|
|
@@ -226,6 +241,17 @@ export declare function notDelivered(why: string, fix: string): string;
|
|
|
226
241
|
* @returns Deps
|
|
227
242
|
*/
|
|
228
243
|
export declare function defaultReplyDeliveryDeps(): Promise<ReplyDeliveryDeps>;
|
|
244
|
+
/**
|
|
245
|
+
* Post a reply the audience check held, where it was going, as written: the
|
|
246
|
+
* owner tapped Share on its card (crewly#969). The audience check is not run
|
|
247
|
+
* again (the owner's tap is the approval); the share itself is logged by the
|
|
248
|
+
* card handler.
|
|
249
|
+
*
|
|
250
|
+
* @param held - The held reply
|
|
251
|
+
* @param deps - Delivery deps (default: the real ones)
|
|
252
|
+
* @returns What happened
|
|
253
|
+
*/
|
|
254
|
+
export declare function postHeldReply(held: HeldReply, deps?: ReplyDeliveryDeps): Promise<HeldReplyPost>;
|
|
229
255
|
/** The chat-v2 lookups {@link chatConversationPlace} and {@link ownerWroteInThreadRecently} use. */
|
|
230
256
|
interface ChatChannelLookup {
|
|
231
257
|
getChannelForBridge(id: string): {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reply-destination.wiring.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/orc/reply-destination.wiring.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AASH,OAAO,EAIL,KAAK,gBAAgB,EACrB,KAAK,UAAU,EACf,KAAK,cAAc,EAEnB,KAAK,iBAAiB,EACvB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAA8B,KAAK,sBAAsB,EAAE,MAAM,oCAAoC,CAAC;AAC7G,OAAO,EAAwD,KAAK,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AAEnI,OAAO,EAAuD,KAAK,YAAY,EAAkB,KAAK,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAKpJ,OAAO,EAAyB,KAAK,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAInF,OAAO,
|
|
1
|
+
{"version":3,"file":"reply-destination.wiring.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/orc/reply-destination.wiring.ts"],"names":[],"mappings":"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"}
|
|
@@ -25,7 +25,8 @@ import { getTurnTriggerTracker } from '../trace/turn-trigger.js';
|
|
|
25
25
|
import { triggeredByMetadata, triggeredByPhrase, withTriggeredByLine } from './triggered-by.js';
|
|
26
26
|
import { stripOwnerTextIds } from '../../utils/owner-text-ids.utils.js';
|
|
27
27
|
import { memberNameFromSession } from '../../utils/member-session-name.utils.js';
|
|
28
|
-
import { checkReplyAudience } from './reply-audience.js';
|
|
28
|
+
import { checkReplyAudience, recordPrivateShare } from './reply-audience.js';
|
|
29
|
+
import { getPrivateShareDecisions } from './private-share-decisions.js';
|
|
29
30
|
/** How long an identical reply from one agent counts as a duplicate send. */
|
|
30
31
|
const REPLY_DUPLICATE_WINDOW_MS = 120_000;
|
|
31
32
|
/** Deliveries that landed recently, by agent + text hash. */
|
|
@@ -184,19 +185,40 @@ async function deliverReplyUntraced(input, deps) {
|
|
|
184
185
|
}
|
|
185
186
|
// crewly#969: what the agent read through a person's grant is that person's
|
|
186
187
|
// data; a reply drawing on it does not go where other people read.
|
|
188
|
+
let heldFrom;
|
|
189
|
+
let held;
|
|
187
190
|
if (d.audience) {
|
|
188
|
-
const
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
191
|
+
const audience = { ...d.audience, ...(d.conversationPlace ? { conversationPlace: d.conversationPlace } : {}) };
|
|
192
|
+
const shared = input.share === true && (await ownerSaidShare(input.session, d)) ? recordPrivateShare(input.session, dest, audience) : [];
|
|
193
|
+
if (shared.length > 0) {
|
|
194
|
+
logger.info('Agent posts a private-sourced reply to a shared place: the owner said to share it', { session: input.session, people: shared });
|
|
192
195
|
}
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
196
|
+
else {
|
|
197
|
+
const verdict = await checkReplyAudience(input.session, dest, audience);
|
|
198
|
+
if (input.share === true && verdict.kind !== 'open') {
|
|
199
|
+
logger.warn('--share ignored: the owner did not say so in the agent DM recently', { session: input.session, heldFrom: verdict.heldFrom });
|
|
200
|
+
}
|
|
201
|
+
if (verdict.kind === 'held') {
|
|
202
|
+
logger.warn('Agent reply held: it draws on private data and the place is shared', { session: input.session, heldFrom: verdict.heldFrom, people: verdict.people });
|
|
203
|
+
return { ok: false, destination: dest, error: notDelivered(verdict.reason, verdict.fix), held: true };
|
|
204
|
+
}
|
|
205
|
+
if (verdict.kind === 'redirect') {
|
|
206
|
+
logger.info('Agent reply moved to the owner DM: it draws on private data', { session: input.session, heldFrom: verdict.heldFrom, people: verdict.people });
|
|
207
|
+
held = { session: input.session, content: input.content, destination: dest, heldFrom: verdict.heldFrom, people: verdict.people, ownerDm: verdict.destination.conversationId };
|
|
208
|
+
dest = verdict.destination;
|
|
209
|
+
heldFrom = verdict.heldFrom;
|
|
210
|
+
input = { ...input, content: `${verdict.note}\n\n${input.content}` };
|
|
211
|
+
}
|
|
197
212
|
}
|
|
198
213
|
}
|
|
199
214
|
let result = await attempt(input, dest, prompt, d);
|
|
215
|
+
if (result.ok && heldFrom) {
|
|
216
|
+
result = { ...result, heldFrom };
|
|
217
|
+
if (held && d.privateShareCard) {
|
|
218
|
+
const card = held;
|
|
219
|
+
void d.privateShareCard(card).catch((err) => logger.warn('Share card not raised for a held reply', { session: card.session, heldFrom: card.heldFrom, error: err instanceof Error ? err.message : String(err) }));
|
|
220
|
+
}
|
|
221
|
+
}
|
|
200
222
|
if (result.ok || ('held' in result && result.held))
|
|
201
223
|
return result;
|
|
202
224
|
// Work handed over from the owner's DM with another agent (a lead's
|
|
@@ -932,8 +954,42 @@ export async function defaultReplyDeliveryDeps() {
|
|
|
932
954
|
currentTrace: (session) => getTraceContext().currentTrace(session),
|
|
933
955
|
conversationPlace: (id) => chatConversationPlace(chatLookup, id),
|
|
934
956
|
audience: await defaultAudienceDeps(resolver, chatLookup),
|
|
957
|
+
privateShareCard: (held) => getPrivateShareDecisions()?.onHeld(held) ?? Promise.resolve(null),
|
|
935
958
|
};
|
|
936
959
|
}
|
|
960
|
+
/**
|
|
961
|
+
* Post a reply the audience check held, where it was going, as written: the
|
|
962
|
+
* owner tapped Share on its card (crewly#969). The audience check is not run
|
|
963
|
+
* again (the owner's tap is the approval); the share itself is logged by the
|
|
964
|
+
* card handler.
|
|
965
|
+
*
|
|
966
|
+
* @param held - The held reply
|
|
967
|
+
* @param deps - Delivery deps (default: the real ones)
|
|
968
|
+
* @returns What happened
|
|
969
|
+
*/
|
|
970
|
+
export async function postHeldReply(held, deps) {
|
|
971
|
+
const d = deps ?? (await defaultReplyDeliveryDeps());
|
|
972
|
+
const place = (held.destination.kind === 'conversation' ? d.conversationPlace?.(held.destination.conversationId) : null) ?? held.heldFrom;
|
|
973
|
+
const result = await attempt({ session: held.session, content: held.content }, held.destination, undefined, d);
|
|
974
|
+
if (!result.ok)
|
|
975
|
+
return { ok: false, error: result.error };
|
|
976
|
+
logger.info('Held reply posted where it was going: the owner tapped Share', { session: held.session, place });
|
|
977
|
+
return { ok: true, place };
|
|
978
|
+
}
|
|
979
|
+
/**
|
|
980
|
+
* Whether the owner wrote to the agent in its owner DM recently — the
|
|
981
|
+
* approval `reply --share` stands on (crewly#969).
|
|
982
|
+
*
|
|
983
|
+
* @param session - Agent session
|
|
984
|
+
* @param d - Delivery deps
|
|
985
|
+
* @returns True when the owner DM exists and the owner asked there within the window
|
|
986
|
+
*/
|
|
987
|
+
async function ownerSaidShare(session, d) {
|
|
988
|
+
if (!d.audience || !d.ownerAskedRecently)
|
|
989
|
+
return false;
|
|
990
|
+
const dm = await d.audience.ownerDm(session).catch(() => null);
|
|
991
|
+
return !!dm && d.ownerAskedRecently(session, dm) === true;
|
|
992
|
+
}
|
|
937
993
|
/**
|
|
938
994
|
* The real audience-check lookups (crewly#969): the private-source tracker,
|
|
939
995
|
* chat-v2 conversation kinds and the people directory.
|
|
@@ -960,6 +1016,7 @@ async function defaultAudienceDeps(resolver, chatLookup) {
|
|
|
960
1016
|
},
|
|
961
1017
|
slackChannelOf: (id) => resolver.slackChannelOfConversation(id),
|
|
962
1018
|
ownerDm: (session) => resolver.ownerDm(session),
|
|
1019
|
+
offersCard: () => getPrivateShareDecisions()?.offersCard() ?? false,
|
|
963
1020
|
personName: (id) => {
|
|
964
1021
|
try {
|
|
965
1022
|
return getPeopleDirectory().get(id)?.name ?? undefined;
|