crewly 1.20.278 → 1.20.280
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 +3 -0
- package/config/skills/agent/core/reply/execute.sh +23 -1
- package/config/skills/agent/core/reply/execute.test.sh +11 -0
- package/dist/backend/backend/src/constants.d.ts +115 -0
- package/dist/backend/backend/src/constants.d.ts.map +1 -1
- package/dist/backend/backend/src/constants.js +115 -0
- package/dist/backend/backend/src/constants.js.map +1 -1
- package/dist/backend/backend/src/controllers/chat/agent-reply.controller.d.ts +10 -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 +25 -0
- package/dist/backend/backend/src/controllers/chat/agent-reply.controller.js.map +1 -1
- package/dist/backend/backend/src/index.d.ts.map +1 -1
- package/dist/backend/backend/src/index.js +207 -3
- package/dist/backend/backend/src/index.js.map +1 -1
- package/dist/backend/backend/src/services/agent/agent-registration.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/agent-registration.service.js +4 -2
- package/dist/backend/backend/src/services/agent/agent-registration.service.js.map +1 -1
- package/dist/backend/backend/src/services/agent/idle-detection.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/idle-detection.service.js +7 -0
- package/dist/backend/backend/src/services/agent/idle-detection.service.js.map +1 -1
- package/dist/backend/backend/src/services/agent/resource-mode.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/resource-mode.service.js +4 -1
- package/dist/backend/backend/src/services/agent/resource-mode.service.js.map +1 -1
- package/dist/backend/backend/src/services/briefing/briefing-cards.d.ts +99 -0
- package/dist/backend/backend/src/services/briefing/briefing-cards.d.ts.map +1 -0
- package/dist/backend/backend/src/services/briefing/briefing-cards.js +156 -0
- package/dist/backend/backend/src/services/briefing/briefing-cards.js.map +1 -0
- package/dist/backend/backend/src/services/briefing/briefing.service.d.ts +8 -0
- package/dist/backend/backend/src/services/briefing/briefing.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/briefing/briefing.service.js +31 -9
- package/dist/backend/backend/src/services/briefing/briefing.service.js.map +1 -1
- package/dist/backend/backend/src/services/chat-v2/chat-v2.service.d.ts +33 -1
- package/dist/backend/backend/src/services/chat-v2/chat-v2.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/chat-v2/chat-v2.service.js +33 -0
- package/dist/backend/backend/src/services/chat-v2/chat-v2.service.js.map +1 -1
- package/dist/backend/backend/src/services/chat-v2/sqlite/message.store.d.ts +21 -0
- package/dist/backend/backend/src/services/chat-v2/sqlite/message.store.d.ts.map +1 -1
- package/dist/backend/backend/src/services/chat-v2/sqlite/message.store.js +37 -0
- package/dist/backend/backend/src/services/chat-v2/sqlite/message.store.js.map +1 -1
- package/dist/backend/backend/src/services/cloud/cloud-talk-inbound.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/cloud/cloud-talk-inbound.service.js +4 -0
- package/dist/backend/backend/src/services/cloud/cloud-talk-inbound.service.js.map +1 -1
- package/dist/backend/backend/src/services/drive/drive-agent.service.d.ts +244 -0
- package/dist/backend/backend/src/services/drive/drive-agent.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/drive/drive-agent.service.js +444 -0
- package/dist/backend/backend/src/services/drive/drive-agent.service.js.map +1 -0
- package/dist/backend/backend/src/services/drive/drive-briefing-snapshot.d.ts +172 -0
- package/dist/backend/backend/src/services/drive/drive-briefing-snapshot.d.ts.map +1 -0
- package/dist/backend/backend/src/services/drive/drive-briefing-snapshot.js +301 -0
- package/dist/backend/backend/src/services/drive/drive-briefing-snapshot.js.map +1 -0
- package/dist/backend/backend/src/services/drive/drive-briefing-sync.service.d.ts +112 -0
- package/dist/backend/backend/src/services/drive/drive-briefing-sync.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/drive/drive-briefing-sync.service.js +247 -0
- package/dist/backend/backend/src/services/drive/drive-briefing-sync.service.js.map +1 -0
- package/dist/backend/backend/src/services/drive/drive-briefing.contract.d.ts +88 -0
- package/dist/backend/backend/src/services/drive/drive-briefing.contract.d.ts.map +1 -0
- package/dist/backend/backend/src/services/drive/drive-briefing.contract.js +18 -0
- package/dist/backend/backend/src/services/drive/drive-briefing.contract.js.map +1 -0
- package/dist/backend/backend/src/services/drive/drive-briefing.wiring.d.ts +73 -0
- package/dist/backend/backend/src/services/drive/drive-briefing.wiring.d.ts.map +1 -0
- package/dist/backend/backend/src/services/drive/drive-briefing.wiring.js +131 -0
- package/dist/backend/backend/src/services/drive/drive-briefing.wiring.js.map +1 -0
- package/dist/backend/backend/src/services/drive/drive-cloud.contract.d.ts +99 -0
- package/dist/backend/backend/src/services/drive/drive-cloud.contract.d.ts.map +1 -0
- package/dist/backend/backend/src/services/drive/drive-cloud.contract.js +118 -0
- package/dist/backend/backend/src/services/drive/drive-cloud.contract.js.map +1 -0
- package/dist/backend/backend/src/services/drive/drive-conversation.store.d.ts +86 -0
- package/dist/backend/backend/src/services/drive/drive-conversation.store.d.ts.map +1 -0
- package/dist/backend/backend/src/services/drive/drive-conversation.store.js +102 -0
- package/dist/backend/backend/src/services/drive/drive-conversation.store.js.map +1 -0
- package/dist/backend/backend/src/services/drive/drive-keep-warm.d.ts +72 -0
- package/dist/backend/backend/src/services/drive/drive-keep-warm.d.ts.map +1 -0
- package/dist/backend/backend/src/services/drive/drive-keep-warm.js +109 -0
- package/dist/backend/backend/src/services/drive/drive-keep-warm.js.map +1 -0
- package/dist/backend/backend/src/services/drive/drive-recall.d.ts +65 -0
- package/dist/backend/backend/src/services/drive/drive-recall.d.ts.map +1 -0
- package/dist/backend/backend/src/services/drive/drive-recall.js +91 -0
- package/dist/backend/backend/src/services/drive/drive-recall.js.map +1 -0
- package/dist/backend/backend/src/services/drive/drive-row.utils.d.ts +19 -0
- package/dist/backend/backend/src/services/drive/drive-row.utils.d.ts.map +1 -0
- package/dist/backend/backend/src/services/drive/drive-row.utils.js +20 -0
- package/dist/backend/backend/src/services/drive/drive-row.utils.js.map +1 -0
- package/dist/backend/backend/src/services/messaging/owner-hook-message.d.ts.map +1 -1
- package/dist/backend/backend/src/services/messaging/owner-hook-message.js +11 -5
- package/dist/backend/backend/src/services/messaging/owner-hook-message.js.map +1 -1
- package/dist/backend/backend/src/services/open-items/open-items.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/open-items/open-items.service.js +14 -2
- package/dist/backend/backend/src/services/open-items/open-items.service.js.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-agent-dm.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-agent-dm.service.js +4 -0
- package/dist/backend/backend/src/services/slack/slack-agent-dm.service.js.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-initializer.d.ts.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-initializer.js +2 -1
- package/dist/backend/backend/src/services/slack/slack-initializer.js.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-team-channel.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-team-channel.service.js +7 -1
- package/dist/backend/backend/src/services/slack/slack-team-channel.service.js.map +1 -1
- package/dist/backend/backend/src/services/talk/talk-live-token.service.d.ts +23 -7
- package/dist/backend/backend/src/services/talk/talk-live-token.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/talk/talk-live-token.service.js +78 -40
- package/dist/backend/backend/src/services/talk/talk-live-token.service.js.map +1 -1
- package/dist/backend/build-info.json +2 -2
- package/dist/cli/backend/src/constants.d.ts +115 -0
- package/dist/cli/backend/src/constants.d.ts.map +1 -1
- package/dist/cli/backend/src/constants.js +115 -0
- package/dist/cli/backend/src/constants.js.map +1 -1
- package/dist/cli/backend/src/services/agent/agent-registration.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/agent/agent-registration.service.js +4 -2
- package/dist/cli/backend/src/services/agent/agent-registration.service.js.map +1 -1
- package/dist/cli/backend/src/services/agent/resource-mode.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/agent/resource-mode.service.js +4 -1
- package/dist/cli/backend/src/services/agent/resource-mode.service.js.map +1 -1
- package/dist/cli/backend/src/services/chat-v2/chat-v2.service.d.ts +33 -1
- package/dist/cli/backend/src/services/chat-v2/chat-v2.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/chat-v2/chat-v2.service.js +33 -0
- package/dist/cli/backend/src/services/chat-v2/chat-v2.service.js.map +1 -1
- package/dist/cli/backend/src/services/chat-v2/sqlite/message.store.d.ts +21 -0
- package/dist/cli/backend/src/services/chat-v2/sqlite/message.store.d.ts.map +1 -1
- package/dist/cli/backend/src/services/chat-v2/sqlite/message.store.js +37 -0
- package/dist/cli/backend/src/services/chat-v2/sqlite/message.store.js.map +1 -1
- package/dist/cli/backend/src/services/drive/drive-keep-warm.d.ts +72 -0
- package/dist/cli/backend/src/services/drive/drive-keep-warm.d.ts.map +1 -0
- package/dist/cli/backend/src/services/drive/drive-keep-warm.js +109 -0
- package/dist/cli/backend/src/services/drive/drive-keep-warm.js.map +1 -0
- package/dist/cli/backend/src/services/drive/drive-row.utils.d.ts +19 -0
- package/dist/cli/backend/src/services/drive/drive-row.utils.d.ts.map +1 -0
- package/dist/cli/backend/src/services/drive/drive-row.utils.js +20 -0
- package/dist/cli/backend/src/services/drive/drive-row.utils.js.map +1 -0
- package/dist/cli/backend/src/services/open-items/open-items.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/open-items/open-items.service.js +14 -2
- package/dist/cli/backend/src/services/open-items/open-items.service.js.map +1 -1
- package/dist/cli/backend/src/services/slack/slack-agent-dm.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/slack/slack-agent-dm.service.js +4 -0
- package/dist/cli/backend/src/services/slack/slack-agent-dm.service.js.map +1 -1
- package/dist/cli/backend/src/services/slack/slack-team-channel.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/slack/slack-team-channel.service.js +7 -1
- package/dist/cli/backend/src/services/slack/slack-team-channel.service.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,444 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DriveAgentService — the machine side of Drive mode
|
|
3
|
+
* (specs/2026-10-08-drive-mode.md §7). Crewly Cloud hosts the session (the
|
|
4
|
+
* voice, the targets, the inbox); this machine does what only it can:
|
|
5
|
+
*
|
|
6
|
+
* - `deliver` (push `op:'deliver'`): fetch the owner's words from Cloud with
|
|
7
|
+
* this machine's token, record them as the owner's voice turn in the
|
|
8
|
+
* agent's DM (a team → its lead's DM; a channel → a thread in its room)
|
|
9
|
+
* and deliver them, with a note: the owner is listening, answer with
|
|
10
|
+
* `reply --drive <session>`, not in Slack;
|
|
11
|
+
* - `agentReply` (`reply --drive`): record the answer in that conversation
|
|
12
|
+
* (kept off Slack) and send it to Cloud for the phone;
|
|
13
|
+
* - `noteChatTurn`: a plain `reply` in a Drive conversation still reaches
|
|
14
|
+
* the phone;
|
|
15
|
+
* - `recall` (push `op:'recall'`): read back an agent's recent messages to
|
|
16
|
+
* the owner;
|
|
17
|
+
* - `end` (push `op:'end'`): ask each agent with an open conversation for
|
|
18
|
+
* ONE recap; the recap (`reply --drive … --recap`) is posted in the
|
|
19
|
+
* owner's DM with the agent, or in the channel, and closes the
|
|
20
|
+
* conversation: owner-message tracking stops, and the open-items tracker
|
|
21
|
+
* takes it as delivered unless it names a next step.
|
|
22
|
+
* - `warm` (push `op:'warm'`, v3): read which agents to keep warm from
|
|
23
|
+
* Cloud, record them in the keep-warm registry (idle stop and slot freeing
|
|
24
|
+
* leave them alone) and pre-start the ones that are stopped;
|
|
25
|
+
* - two-phase answers (v3): the delivered words ask for `reply --drive
|
|
26
|
+
* --ack` within seconds, then the full result.
|
|
27
|
+
*
|
|
28
|
+
* Nothing the owner or the agents say is logged.
|
|
29
|
+
*
|
|
30
|
+
* @module services/drive/drive-agent.service
|
|
31
|
+
*/
|
|
32
|
+
import { DRIVE_CONSTANTS } from '../../constants.js';
|
|
33
|
+
import { LoggerService } from '../core/logger.service.js';
|
|
34
|
+
import { clip, speakable } from '../briefing/briefing.utils.js';
|
|
35
|
+
import { isDriveModeRow } from './drive-row.utils.js';
|
|
36
|
+
import { messagesToOwner, pickRecall } from './drive-recall.js';
|
|
37
|
+
import { parseDeliveryFetch, parseDriveRelayData, parseRecallFetch, parseStateFetch, } from './drive-cloud.contract.js';
|
|
38
|
+
import { getDriveKeepWarm } from './drive-keep-warm.js';
|
|
39
|
+
const C = DRIVE_CONSTANTS;
|
|
40
|
+
/** A recap that says nothing is left to do (the conversation is fully closed). */
|
|
41
|
+
const NOTHING_PENDING = /nothing (is )?(pending|left|open)|no next step|next:\s*(none|nothing)\b|没有待办|无待办|没有后续|无后续|不需要后续|没有了/i;
|
|
42
|
+
/** A Drive mode failure with an HTTP status (for the agent's `reply`). */
|
|
43
|
+
export class DriveAgentError extends Error {
|
|
44
|
+
status;
|
|
45
|
+
constructor(status, message) {
|
|
46
|
+
super(message);
|
|
47
|
+
this.status = status;
|
|
48
|
+
this.name = 'DriveAgentError';
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
let active = false;
|
|
52
|
+
/**
|
|
53
|
+
* Capabilities to advertise to Cloud (heartbeat and uploads).
|
|
54
|
+
*
|
|
55
|
+
* @returns `['drive_message']` while the handler runs, else `[]`
|
|
56
|
+
*/
|
|
57
|
+
export function driveCapabilities() {
|
|
58
|
+
return active ? [C.CAPABILITY] : [];
|
|
59
|
+
}
|
|
60
|
+
/** The machine side of Drive mode — see module docs. */
|
|
61
|
+
export class DriveAgentService {
|
|
62
|
+
deps;
|
|
63
|
+
logger;
|
|
64
|
+
now;
|
|
65
|
+
fetchImpl;
|
|
66
|
+
inFlight = new Set();
|
|
67
|
+
listener = (msg) => {
|
|
68
|
+
void this.handle(msg);
|
|
69
|
+
};
|
|
70
|
+
started = false;
|
|
71
|
+
/**
|
|
72
|
+
* @param deps - Collaborators
|
|
73
|
+
*/
|
|
74
|
+
constructor(deps) {
|
|
75
|
+
this.deps = deps;
|
|
76
|
+
this.logger = deps.logger ?? LoggerService.getInstance().createComponentLogger('DriveAgent');
|
|
77
|
+
this.now = deps.now ?? (() => new Date());
|
|
78
|
+
this.fetchImpl = deps.fetchImpl ?? ((input, init) => fetch(input, init));
|
|
79
|
+
}
|
|
80
|
+
/** Subscribe to relay messages and advertise the capability. Idempotent. */
|
|
81
|
+
start() {
|
|
82
|
+
if (this.started)
|
|
83
|
+
return;
|
|
84
|
+
this.started = true;
|
|
85
|
+
this.deps.source?.on('message', this.listener);
|
|
86
|
+
active = true;
|
|
87
|
+
}
|
|
88
|
+
/** Unsubscribe. */
|
|
89
|
+
stop() {
|
|
90
|
+
if (!this.started)
|
|
91
|
+
return;
|
|
92
|
+
this.started = false;
|
|
93
|
+
this.deps.source?.off('message', this.listener);
|
|
94
|
+
active = false;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* One relay message; anything but a Drive mode push is ignored. Never throws.
|
|
98
|
+
*
|
|
99
|
+
* @param msg - Relay message
|
|
100
|
+
* @returns What was done
|
|
101
|
+
*/
|
|
102
|
+
async handle(msg) {
|
|
103
|
+
if (msg?.type !== C.RELAY_MESSAGE_TYPE)
|
|
104
|
+
return 'ignored';
|
|
105
|
+
const data = parseDriveRelayData(msg.payload);
|
|
106
|
+
if (!data)
|
|
107
|
+
return 'ignored';
|
|
108
|
+
const key = `${data.op}:${data.sessionId}:${data.id ?? ''}`;
|
|
109
|
+
if (this.inFlight.has(key))
|
|
110
|
+
return 'duplicate';
|
|
111
|
+
this.inFlight.add(key);
|
|
112
|
+
try {
|
|
113
|
+
const { instanceId } = await this.deps.identity();
|
|
114
|
+
if (data.instanceId !== instanceId)
|
|
115
|
+
return 'ignored';
|
|
116
|
+
if (data.op === 'deliver')
|
|
117
|
+
await this.deliver(data, instanceId);
|
|
118
|
+
else if (data.op === 'recall')
|
|
119
|
+
await this.recall(data, instanceId);
|
|
120
|
+
else if (data.op === 'warm')
|
|
121
|
+
await this.warm(data, instanceId);
|
|
122
|
+
else
|
|
123
|
+
await this.end(data, instanceId);
|
|
124
|
+
return 'done';
|
|
125
|
+
}
|
|
126
|
+
catch (error) {
|
|
127
|
+
this.logger.warn('Drive mode push failed', { op: data.op, sessionId: data.sessionId, error: error instanceof Error ? error.message : String(error) });
|
|
128
|
+
return 'failed';
|
|
129
|
+
}
|
|
130
|
+
finally {
|
|
131
|
+
this.inFlight.delete(key);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
// ---------------------------------------------------------------------------
|
|
135
|
+
// Owner → agent
|
|
136
|
+
// ---------------------------------------------------------------------------
|
|
137
|
+
async deliver(data, instanceId) {
|
|
138
|
+
const raw = await this.cloudGet(`/${data.sessionId}/machine/deliveries/${encodeURIComponent(data.id)}?instanceId=${encodeURIComponent(instanceId)}`);
|
|
139
|
+
const d = parseDeliveryFetch(raw);
|
|
140
|
+
if (!d)
|
|
141
|
+
throw new Error('Cloud sent a malformed delivery');
|
|
142
|
+
await this.deliverFetched(d);
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Deliver the owner's words (already fetched from Cloud).
|
|
146
|
+
*
|
|
147
|
+
* @param d - Delivery
|
|
148
|
+
* @returns The local conversation
|
|
149
|
+
*/
|
|
150
|
+
async deliverFetched(d) {
|
|
151
|
+
if (this.deps.agentExists && !(await this.deps.agentExists(d.target.agentSession))) {
|
|
152
|
+
throw new Error(`No agent ${d.target.agentSession} on this machine`);
|
|
153
|
+
}
|
|
154
|
+
const existing = await this.deps.store.get(d.sessionId, d.conversationId);
|
|
155
|
+
const where = await this.deps.deliverOwnerTurn({
|
|
156
|
+
kind: d.target.kind,
|
|
157
|
+
agentSession: d.target.agentSession,
|
|
158
|
+
...(d.target.slackChannelId ? { slackChannelId: d.target.slackChannelId } : {}),
|
|
159
|
+
...(existing ? { channelId: existing.channelId, ...(existing.threadId ? { threadId: existing.threadId } : {}) } : {}),
|
|
160
|
+
text: ownerTurnText(d.sessionId, d.target.kind, d.target.name, d.text),
|
|
161
|
+
});
|
|
162
|
+
const at = this.now().toISOString();
|
|
163
|
+
const conv = await this.deps.store.update(d.sessionId, d.conversationId, (cur) => {
|
|
164
|
+
const c = cur ?? {
|
|
165
|
+
sessionId: d.sessionId,
|
|
166
|
+
conversationId: d.conversationId,
|
|
167
|
+
kind: d.target.kind,
|
|
168
|
+
targetName: d.target.name,
|
|
169
|
+
agentSession: d.target.agentSession,
|
|
170
|
+
...(d.target.members ? { members: d.target.members } : {}),
|
|
171
|
+
channelId: where.channelId,
|
|
172
|
+
...(where.threadId ? { threadId: where.threadId } : {}),
|
|
173
|
+
startedAt: at,
|
|
174
|
+
turns: [],
|
|
175
|
+
};
|
|
176
|
+
if (!c.threadId && where.threadId)
|
|
177
|
+
c.threadId = where.threadId;
|
|
178
|
+
c.turns.push({ from: 'owner', name: 'owner', text: d.text, at });
|
|
179
|
+
return c;
|
|
180
|
+
}, this.now().getTime());
|
|
181
|
+
this.logger.info('Drive mode: owner words delivered', { sessionId: d.sessionId, conversationId: d.conversationId, kind: d.target.kind, agent: d.target.agentSession });
|
|
182
|
+
return conv;
|
|
183
|
+
}
|
|
184
|
+
// ---------------------------------------------------------------------------
|
|
185
|
+
// Agent → owner
|
|
186
|
+
// ---------------------------------------------------------------------------
|
|
187
|
+
/**
|
|
188
|
+
* An agent's answer for the owner's phone (`reply --drive <session>`), or
|
|
189
|
+
* its recap (`--recap`).
|
|
190
|
+
*
|
|
191
|
+
* @param agentSession - Who answers
|
|
192
|
+
* @param sessionId - Drive mode session
|
|
193
|
+
* @param input - `{ text, interim, recap }`
|
|
194
|
+
* @returns Which conversation, and whether it closed
|
|
195
|
+
* @throws DriveAgentError 400 / 404 (no such conversation) / 502 (Cloud unreachable)
|
|
196
|
+
*/
|
|
197
|
+
async agentReply(agentSession, sessionId, input) {
|
|
198
|
+
if (!C.SESSION_ID_PATTERN.test(sessionId))
|
|
199
|
+
throw new DriveAgentError(400, 'That is not a Drive mode session id (drv_…).');
|
|
200
|
+
const text = (input.text ?? '').trim();
|
|
201
|
+
if (!text)
|
|
202
|
+
throw new DriveAgentError(400, 'Reply text is required.');
|
|
203
|
+
if (text.length > C.TEXT_MAX_CHARS)
|
|
204
|
+
throw new DriveAgentError(400, `Too long for Drive mode (max ${C.TEXT_MAX_CHARS} characters) — say it short; details go in a normal reply.`);
|
|
205
|
+
const conv = pickConversation(await this.deps.store.list(), sessionId, agentSession, input.recap);
|
|
206
|
+
if (!conv)
|
|
207
|
+
throw new DriveAgentError(404, 'You have no open Drive mode conversation in that session. Answer the usual way (reply).');
|
|
208
|
+
if (input.recap)
|
|
209
|
+
return this.recap(conv, agentSession, text);
|
|
210
|
+
const interim = input.interim || input.ack === true;
|
|
211
|
+
await this.deps.recordAgentTurn({ agentSession, channelId: conv.channelId, ...(conv.threadId ? { threadId: conv.threadId } : {}), text, interim, sessionId });
|
|
212
|
+
await this.forward(conv, agentSession, text, { interim, ...(input.ack ? { ack: true } : {}) });
|
|
213
|
+
return { conversationId: conv.conversationId, closed: false };
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Fallback: an agent answered a Drive mode conversation with a plain
|
|
217
|
+
* `reply` instead of `reply --drive`. Its words still reach the phone. Call
|
|
218
|
+
* for every chat-v2 message. Never throws.
|
|
219
|
+
*
|
|
220
|
+
* @param dto - The chat message
|
|
221
|
+
*/
|
|
222
|
+
async noteChatTurn(dto) {
|
|
223
|
+
try {
|
|
224
|
+
if (dto.senderType !== 'agent' || isDriveModeRow(dto) || !dto.content.trim())
|
|
225
|
+
return;
|
|
226
|
+
const open = (await this.deps.store.list()).filter((c) => !c.closedAt && c.channelId === dto.channelId && (!c.threadId || dto.threadId === c.threadId));
|
|
227
|
+
for (const c of open.reverse()) {
|
|
228
|
+
if (dto.senderId !== c.agentSession && !(c.members ?? []).includes(dto.senderId))
|
|
229
|
+
continue;
|
|
230
|
+
const lastOwner = [...c.turns].reverse().find((t) => t.from === 'owner');
|
|
231
|
+
const lastAgent = [...c.turns].reverse().find((t) => t.from === 'agent' && !t.interim);
|
|
232
|
+
if (!lastOwner || (lastAgent && Date.parse(lastAgent.at) >= Date.parse(lastOwner.at)))
|
|
233
|
+
continue;
|
|
234
|
+
if (dto.createdAt < Date.parse(lastOwner.at))
|
|
235
|
+
continue;
|
|
236
|
+
await this.forward(c, dto.senderId, dto.content, { interim: dto.metadata?.interim === true });
|
|
237
|
+
this.logger.info('Drive mode: picked up a plain reply', { sessionId: c.sessionId, conversationId: c.conversationId });
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
catch (err) {
|
|
242
|
+
this.logger.warn('Drive mode: plain reply not forwarded', { error: err instanceof Error ? err.message : String(err) });
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
async recap(conv, agentSession, text) {
|
|
246
|
+
const nextStep = !NOTHING_PENDING.test(text);
|
|
247
|
+
const posted = await this.deps.postRecap({ conversation: conv, agentSession, text, nextStep });
|
|
248
|
+
await this.forward(conv, agentSession, text, { recap: true, nextStep }).catch((err) => {
|
|
249
|
+
// The recap is posted where it belongs; Cloud learning of it is best effort.
|
|
250
|
+
this.logger.warn('Drive mode: recap not reported to Cloud', { error: err instanceof Error ? err.message : String(err) });
|
|
251
|
+
});
|
|
252
|
+
await this.deps.store.update(conv.sessionId, conv.conversationId, (cur) => (cur ? { ...cur, closedAt: this.now().toISOString() } : null), this.now().getTime());
|
|
253
|
+
this.deps.closeTracking?.(conv.agentSession, conv.channelId);
|
|
254
|
+
this.logger.info('Drive mode recap posted; conversation closed', { sessionId: conv.sessionId, conversationId: conv.conversationId, where: posted.where, nextStep });
|
|
255
|
+
return { conversationId: conv.conversationId, closed: true };
|
|
256
|
+
}
|
|
257
|
+
/** Send an answer to Cloud and keep the local transcript. */
|
|
258
|
+
async forward(conv, agentSession, text, opts) {
|
|
259
|
+
const { instanceId } = await this.deps.identity();
|
|
260
|
+
await this.cloudPost(`/${conv.sessionId}/replies`, {
|
|
261
|
+
instanceId,
|
|
262
|
+
conversationId: conv.conversationId,
|
|
263
|
+
agentSession,
|
|
264
|
+
text: text.slice(0, C.TEXT_MAX_CHARS),
|
|
265
|
+
...(opts.interim ? { interim: true } : {}),
|
|
266
|
+
...(opts.ack ? { ack: true } : {}),
|
|
267
|
+
...(opts.recap ? { recap: true, nextStep: !!opts.nextStep } : {}),
|
|
268
|
+
});
|
|
269
|
+
if (opts.recap)
|
|
270
|
+
return;
|
|
271
|
+
const at = this.now().toISOString();
|
|
272
|
+
await this.deps.store.update(conv.sessionId, conv.conversationId, (cur) => (cur ? { ...cur, turns: [...cur.turns, { from: 'agent', name: agentSession, text: clip(speakable(text), 600), at, ...(opts.interim ? { interim: true } : {}) }] } : null), this.now().getTime());
|
|
273
|
+
}
|
|
274
|
+
// ---------------------------------------------------------------------------
|
|
275
|
+
// Recall / end
|
|
276
|
+
// ---------------------------------------------------------------------------
|
|
277
|
+
async recall(data, instanceId) {
|
|
278
|
+
const path = `/${data.sessionId}/machine/recalls/${encodeURIComponent(data.id)}`;
|
|
279
|
+
const req = parseRecallFetch(await this.cloudGet(`${path}?instanceId=${encodeURIComponent(instanceId)}`));
|
|
280
|
+
if (!req)
|
|
281
|
+
throw new Error('Cloud sent a malformed recall');
|
|
282
|
+
const feed = await this.deps.ownerFeed(this.now().getTime() - C.RECALL_WINDOW_MS);
|
|
283
|
+
const messages = pickRecall(messagesToOwner(feed.messages, feed.ownerTurns, req.agentSessions), req.hint);
|
|
284
|
+
await this.cloudPost(path, { instanceId, messages });
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Keep the agents Cloud names warm while the session runs, and start the
|
|
288
|
+
* ones that are stopped now (warm agents go ahead of ordinary starts).
|
|
289
|
+
*/
|
|
290
|
+
async warm(data, instanceId) {
|
|
291
|
+
const state = parseStateFetch(await this.cloudGet(`/${data.sessionId}/machine/state?instanceId=${encodeURIComponent(instanceId)}`));
|
|
292
|
+
if (!state)
|
|
293
|
+
throw new Error('Cloud sent a malformed session state');
|
|
294
|
+
const registry = this.deps.keepWarm ?? getDriveKeepWarm();
|
|
295
|
+
if (state.ended) {
|
|
296
|
+
registry.end(data.sessionId);
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
const fresh = registry.set(data.sessionId, state.warm, state.warmUntil);
|
|
300
|
+
if (fresh.length)
|
|
301
|
+
this.logger.info('Drive mode: keeping agents warm', { sessionId: data.sessionId, agents: fresh });
|
|
302
|
+
for (const agent of fresh)
|
|
303
|
+
await this.deps.prestart?.(agent).catch(() => undefined);
|
|
304
|
+
}
|
|
305
|
+
async end(data, instanceId) {
|
|
306
|
+
const state = parseStateFetch(await this.cloudGet(`/${data.sessionId}/machine/state?instanceId=${encodeURIComponent(instanceId)}`));
|
|
307
|
+
if (!state || !state.ended)
|
|
308
|
+
return;
|
|
309
|
+
(this.deps.keepWarm ?? getDriveKeepWarm()).end(data.sessionId);
|
|
310
|
+
const wanted = new Set(state.conversations.map((c) => c.conversationId));
|
|
311
|
+
const local = (await this.deps.store.list()).filter((c) => c.sessionId === data.sessionId && wanted.has(c.conversationId) && !c.closedAt && !c.recapAskedAt);
|
|
312
|
+
for (const c of local) {
|
|
313
|
+
const ok = await this.deps.notifyAgent(c.agentSession, recapRequest(c)).catch(() => false);
|
|
314
|
+
if (!ok) {
|
|
315
|
+
this.logger.warn('Drive mode: could not ask for a recap', { sessionId: c.sessionId, conversationId: c.conversationId, agent: c.agentSession });
|
|
316
|
+
continue;
|
|
317
|
+
}
|
|
318
|
+
await this.deps.store.update(c.sessionId, c.conversationId, (cur) => (cur ? { ...cur, recapAskedAt: this.now().toISOString() } : null), this.now().getTime());
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
// ---------------------------------------------------------------------------
|
|
322
|
+
// Cloud
|
|
323
|
+
// ---------------------------------------------------------------------------
|
|
324
|
+
async cloudGet(path) {
|
|
325
|
+
return this.cloudCall('GET', path);
|
|
326
|
+
}
|
|
327
|
+
async cloudPost(path, body) {
|
|
328
|
+
return this.cloudCall('POST', path, body);
|
|
329
|
+
}
|
|
330
|
+
async cloudCall(method, path, body, refreshed = false) {
|
|
331
|
+
const base = this.deps.cloud.getCloudUrl();
|
|
332
|
+
const token = this.deps.cloud.getToken();
|
|
333
|
+
if (!base || !token)
|
|
334
|
+
throw new DriveAgentError(503, 'This machine is not signed in to Crewly Cloud.');
|
|
335
|
+
let res;
|
|
336
|
+
try {
|
|
337
|
+
res = await this.fetchImpl(`${base.replace(/\/+$/, '')}${C.CLOUD_BASE_PATH}${path}`, {
|
|
338
|
+
method,
|
|
339
|
+
headers: { Authorization: `Bearer ${token}`, ...(body !== undefined ? { 'Content-Type': 'application/json' } : {}) },
|
|
340
|
+
...(body !== undefined ? { body: JSON.stringify(body) } : {}),
|
|
341
|
+
signal: AbortSignal.timeout(C.REQUEST_TIMEOUT_MS),
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
catch {
|
|
345
|
+
throw new DriveAgentError(502, 'Could not reach Crewly Cloud — try again in a moment.');
|
|
346
|
+
}
|
|
347
|
+
if (res.status === 401 && !refreshed && this.deps.cloud.tryRefreshToken && (await this.deps.cloud.tryRefreshToken())) {
|
|
348
|
+
return this.cloudCall(method, path, body, true);
|
|
349
|
+
}
|
|
350
|
+
let json = {};
|
|
351
|
+
try {
|
|
352
|
+
json = (await res.json());
|
|
353
|
+
}
|
|
354
|
+
catch {
|
|
355
|
+
json = {};
|
|
356
|
+
}
|
|
357
|
+
if (!res.ok || json.success === false) {
|
|
358
|
+
const why = typeof json.error === 'string' ? json.error : `Crewly Cloud answered ${res.status}`;
|
|
359
|
+
throw new DriveAgentError(res.status >= 500 ? 502 : res.status, why);
|
|
360
|
+
}
|
|
361
|
+
return json.data;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
// ---------------------------------------------------------------------------
|
|
365
|
+
// Pure helpers
|
|
366
|
+
// ---------------------------------------------------------------------------
|
|
367
|
+
/**
|
|
368
|
+
* The owner's words as delivered: the Drive mode note, then the words.
|
|
369
|
+
*
|
|
370
|
+
* @param sessionId - Session
|
|
371
|
+
* @param kind - Target kind
|
|
372
|
+
* @param name - Target name
|
|
373
|
+
* @param text - The owner's words
|
|
374
|
+
* @returns Message text
|
|
375
|
+
*/
|
|
376
|
+
export function ownerTurnText(sessionId, kind, name, text) {
|
|
377
|
+
const forTeam = kind === 'team' ? ` This is for the ${name} team: answer for the team, or hand it on.` : '';
|
|
378
|
+
return (`[Drive mode · session ${sessionId}] The owner is driving and LISTENING on the phone, not reading.${forTeam}\n` +
|
|
379
|
+
`1. Within seconds, before any other work: reply --drive ${sessionId} --ack "<one short sentence: got it and how long, or the direct answer>".\n` +
|
|
380
|
+
`2. If it needs work, do it, then: reply --drive ${sessionId} "<the result>" — conclusion first, at most 3 short spoken sentences; ` +
|
|
381
|
+
'if he must decide, give 2–3 options. No URLs, tables, code or ids; details go in your end-of-session recap. Not in Slack. ' +
|
|
382
|
+
'If the ack already answered it, you are done.\n\n' +
|
|
383
|
+
text);
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* The harness note asking an agent for its recap.
|
|
387
|
+
*
|
|
388
|
+
* @param c - Conversation
|
|
389
|
+
* @returns Note text
|
|
390
|
+
*/
|
|
391
|
+
export function recapRequest(c) {
|
|
392
|
+
const where = c.kind === 'channel' ? c.targetName : c.kind === 'team' ? `your DM with the owner (for the ${c.targetName} team)` : 'your DM with the owner';
|
|
393
|
+
const transcript = c.turns
|
|
394
|
+
.slice(-12)
|
|
395
|
+
.map((t) => `${t.from === 'owner' ? 'Owner' : t.name}: ${clip(t.text, 400)}`)
|
|
396
|
+
.join('\n');
|
|
397
|
+
return [
|
|
398
|
+
`[Drive mode ended · session ${c.sessionId}] The owner ended the Drive mode conversation with you. Post ONE recap now, for reading:`,
|
|
399
|
+
`reply --drive ${c.sessionId} --recap "Drive mode recap — you said …; I did / answered …; next: … (or: nothing pending / waiting on X)"`,
|
|
400
|
+
`It is posted in ${where}. After it the conversation is closed: no follow-ups or nudges unless the recap names a next step.`,
|
|
401
|
+
'',
|
|
402
|
+
'The conversation:',
|
|
403
|
+
transcript,
|
|
404
|
+
].join('\n');
|
|
405
|
+
}
|
|
406
|
+
/**
|
|
407
|
+
* The conversation an agent's reply belongs to: one it answers or is a
|
|
408
|
+
* member of; a recap goes to one whose recap was asked for; otherwise the one
|
|
409
|
+
* waiting for an answer, newest first.
|
|
410
|
+
*
|
|
411
|
+
* @param all - Local conversations
|
|
412
|
+
* @param sessionId - Session
|
|
413
|
+
* @param agentSession - Who replies
|
|
414
|
+
* @param recap - It is the recap
|
|
415
|
+
* @returns Conversation or undefined
|
|
416
|
+
*/
|
|
417
|
+
export function pickConversation(all, sessionId, agentSession, recap) {
|
|
418
|
+
const mine = all.filter((c) => c.sessionId === sessionId && !c.closedAt && (c.agentSession === agentSession || (c.members ?? []).includes(agentSession)));
|
|
419
|
+
const waiting = (c) => {
|
|
420
|
+
const lastOwner = [...c.turns].reverse().find((t) => t.from === 'owner');
|
|
421
|
+
const lastAgent = [...c.turns].reverse().find((t) => t.from === 'agent' && !t.interim);
|
|
422
|
+
return !!lastOwner && (!lastAgent || Date.parse(lastAgent.at) < Date.parse(lastOwner.at));
|
|
423
|
+
};
|
|
424
|
+
const pref = recap ? mine.filter((c) => c.recapAskedAt) : mine.filter(waiting);
|
|
425
|
+
const pool = pref.length > 0 ? pref : mine;
|
|
426
|
+
const own = pool.filter((c) => c.agentSession === agentSession);
|
|
427
|
+
const list = own.length > 0 ? own : pool;
|
|
428
|
+
const lastAt = (c) => Date.parse(c.turns[c.turns.length - 1]?.at ?? c.startedAt);
|
|
429
|
+
return [...list].sort((a, b) => lastAt(b) - lastAt(a))[0];
|
|
430
|
+
}
|
|
431
|
+
let instance = null;
|
|
432
|
+
/** @returns The running service, or null */
|
|
433
|
+
export function getDriveAgentService() {
|
|
434
|
+
return instance;
|
|
435
|
+
}
|
|
436
|
+
/**
|
|
437
|
+
* Install the service (boot, tests).
|
|
438
|
+
*
|
|
439
|
+
* @param service - Service or null
|
|
440
|
+
*/
|
|
441
|
+
export function setDriveAgentService(service) {
|
|
442
|
+
instance = service;
|
|
443
|
+
}
|
|
444
|
+
//# sourceMappingURL=drive-agent.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drive-agent.service.js","sourceRoot":"","sources":["../../../../../../backend/src/services/drive/drive-agent.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build the Drive mode status snapshot (specs/2026-10-09-drive-mode-v3.md §1)
|
|
3
|
+
* from structured data this machine already has. Pure, no LLM calls: the
|
|
4
|
+
* text in it is what agents already wrote — ticket titles and log lines,
|
|
5
|
+
* work item `output.summary`, decision card summaries, their own messages to
|
|
6
|
+
* the owner.
|
|
7
|
+
*
|
|
8
|
+
* - teams: lead, members, counts (open / in progress / review / blocked /
|
|
9
|
+
* done today);
|
|
10
|
+
* - agents: state (working / idle / starting / stopped), what each is on
|
|
11
|
+
* and since when (its running work item, else its ticket in progress),
|
|
12
|
+
* its last few messages to the owner;
|
|
13
|
+
* - items: project tickets and work items not linked to a ticket, in order
|
|
14
|
+
* of attention, done / cancelled ones only from the last 24 h;
|
|
15
|
+
* - waiting: the briefing queue's live owner items (cards, questions,
|
|
16
|
+
* reviews — stale and duplicate ones are already dropped there).
|
|
17
|
+
*
|
|
18
|
+
* Every text field is made speakable, passed through the secret redactor
|
|
19
|
+
* and clipped; the whole snapshot is kept under
|
|
20
|
+
* {@link DRIVE_BRIEFING_CONSTANTS.MAX_BYTES}.
|
|
21
|
+
*
|
|
22
|
+
* @module services/drive/drive-briefing-snapshot
|
|
23
|
+
*/
|
|
24
|
+
import type { OwnerTurnMark } from '../briefing/briefing-cards.js';
|
|
25
|
+
import { type RecallFeedMessage } from './drive-recall.js';
|
|
26
|
+
import type { BriefingAgentState, BriefingItemStatus, BriefingSnapshot } from './drive-briefing.contract.js';
|
|
27
|
+
/** An agent on this machine. */
|
|
28
|
+
export interface SnapshotAgentSource {
|
|
29
|
+
agentSession: string;
|
|
30
|
+
name: string;
|
|
31
|
+
/** Team name */
|
|
32
|
+
team?: string;
|
|
33
|
+
role?: string;
|
|
34
|
+
state: BriefingAgentState;
|
|
35
|
+
}
|
|
36
|
+
/** A team on this machine. */
|
|
37
|
+
export interface SnapshotTeamSource {
|
|
38
|
+
id: string;
|
|
39
|
+
name: string;
|
|
40
|
+
/** Lead's session */
|
|
41
|
+
lead?: string;
|
|
42
|
+
/** Members' sessions */
|
|
43
|
+
members: string[];
|
|
44
|
+
}
|
|
45
|
+
/** A project ticket (the fields used). */
|
|
46
|
+
export interface SnapshotTicketSource {
|
|
47
|
+
/** Project name */
|
|
48
|
+
project: string;
|
|
49
|
+
id: string;
|
|
50
|
+
title: string;
|
|
51
|
+
status: string;
|
|
52
|
+
labels: string[];
|
|
53
|
+
/** Agent session or a person's name */
|
|
54
|
+
assignee: string | null;
|
|
55
|
+
/** Team id */
|
|
56
|
+
team: string | null;
|
|
57
|
+
updatedAt: string;
|
|
58
|
+
workItemId: string | null;
|
|
59
|
+
log: string[];
|
|
60
|
+
}
|
|
61
|
+
/** A task-pool work item (the fields used). */
|
|
62
|
+
export interface SnapshotWorkItemSource {
|
|
63
|
+
id: string;
|
|
64
|
+
title: string;
|
|
65
|
+
status: string;
|
|
66
|
+
target?: string;
|
|
67
|
+
createdAt: string;
|
|
68
|
+
startedAt?: string;
|
|
69
|
+
completedAt?: string;
|
|
70
|
+
statusChangedAt?: string;
|
|
71
|
+
output?: Record<string, unknown>;
|
|
72
|
+
blockedReason?: string;
|
|
73
|
+
error?: string;
|
|
74
|
+
metadata?: Record<string, unknown>;
|
|
75
|
+
}
|
|
76
|
+
/** A live owner item from the briefing queue (the fields used). */
|
|
77
|
+
export interface SnapshotWaitingSource {
|
|
78
|
+
id: string;
|
|
79
|
+
kind: 'decision' | 'question' | 'review';
|
|
80
|
+
agentSession: string;
|
|
81
|
+
agentName: string;
|
|
82
|
+
teamName?: string;
|
|
83
|
+
summary: string;
|
|
84
|
+
since: string;
|
|
85
|
+
urgency: 'high' | 'normal' | 'low';
|
|
86
|
+
answerTarget: {
|
|
87
|
+
kind: string;
|
|
88
|
+
decisionId?: string;
|
|
89
|
+
tkt?: string;
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
/** Everything the snapshot is built from. */
|
|
93
|
+
export interface SnapshotSources {
|
|
94
|
+
now: Date;
|
|
95
|
+
agents: SnapshotAgentSource[];
|
|
96
|
+
teams: SnapshotTeamSource[];
|
|
97
|
+
tickets: SnapshotTicketSource[];
|
|
98
|
+
workItems: SnapshotWorkItemSource[];
|
|
99
|
+
waiting: SnapshotWaitingSource[];
|
|
100
|
+
ownerFeed: {
|
|
101
|
+
messages: RecallFeedMessage[];
|
|
102
|
+
ownerTurns: OwnerTurnMark[];
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Speakable, redacted, clipped text (empty → '').
|
|
107
|
+
*
|
|
108
|
+
* @param raw - Agent-written text
|
|
109
|
+
* @param max - Longest length
|
|
110
|
+
* @returns Safe text
|
|
111
|
+
*/
|
|
112
|
+
export declare function safeText(raw: unknown, max: number): string;
|
|
113
|
+
/**
|
|
114
|
+
* An agent's state from its team member record.
|
|
115
|
+
*
|
|
116
|
+
* @param agentStatus - Connection status
|
|
117
|
+
* @param workingStatus - Activity
|
|
118
|
+
* @returns State
|
|
119
|
+
*/
|
|
120
|
+
export declare function agentStateOf(agentStatus: string | undefined, workingStatus: string | undefined): BriefingAgentState;
|
|
121
|
+
/**
|
|
122
|
+
* A project ticket's status for the voice (`blocked` label wins).
|
|
123
|
+
*
|
|
124
|
+
* @param status - Ticket status
|
|
125
|
+
* @param labels - Ticket labels
|
|
126
|
+
* @returns Normalised status
|
|
127
|
+
*/
|
|
128
|
+
export declare function ticketStatus(status: string, labels: readonly string[]): BriefingItemStatus;
|
|
129
|
+
/**
|
|
130
|
+
* A work item's status for the voice.
|
|
131
|
+
*
|
|
132
|
+
* @param status - WorkItem status
|
|
133
|
+
* @returns Normalised status
|
|
134
|
+
*/
|
|
135
|
+
export declare function workItemStatus(status: string): BriefingItemStatus;
|
|
136
|
+
/**
|
|
137
|
+
* The words of a ticket log line (`<iso> · <actor> · <message>` → message).
|
|
138
|
+
*
|
|
139
|
+
* @param line - Log line
|
|
140
|
+
* @returns The message
|
|
141
|
+
*/
|
|
142
|
+
export declare function logMessage(line: string): string;
|
|
143
|
+
/**
|
|
144
|
+
* Build the snapshot.
|
|
145
|
+
*
|
|
146
|
+
* @param src - Sources
|
|
147
|
+
* @returns Snapshot, under the size cap
|
|
148
|
+
*
|
|
149
|
+
* @example
|
|
150
|
+
* ```typescript
|
|
151
|
+
* const snapshot = buildBriefingSnapshot({ now: new Date(), agents, teams, tickets, workItems, waiting, ownerFeed });
|
|
152
|
+
* ```
|
|
153
|
+
*/
|
|
154
|
+
export declare function buildBriefingSnapshot(src: SnapshotSources): BriefingSnapshot;
|
|
155
|
+
/**
|
|
156
|
+
* A spoken reference for a waiting item: the card id (`D-7`), the ticket
|
|
157
|
+
* (`TKT-5`), or a short question id.
|
|
158
|
+
*
|
|
159
|
+
* @param w - Waiting item
|
|
160
|
+
* @returns Reference
|
|
161
|
+
*/
|
|
162
|
+
export declare function waitingRef(w: Pick<SnapshotWaitingSource, 'id' | 'kind' | 'answerTarget'>): string;
|
|
163
|
+
/**
|
|
164
|
+
* Keep the snapshot under `maxBytes`: drop finished work first, then older
|
|
165
|
+
* messages to the owner, then the least urgent items and waiting entries.
|
|
166
|
+
*
|
|
167
|
+
* @param s - Snapshot
|
|
168
|
+
* @param maxBytes - Size cap (JSON)
|
|
169
|
+
* @returns A snapshot within the cap
|
|
170
|
+
*/
|
|
171
|
+
export declare function capSnapshot(s: BriefingSnapshot, maxBytes: number): BriefingSnapshot;
|
|
172
|
+
//# sourceMappingURL=drive-briefing-snapshot.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drive-briefing-snapshot.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/drive/drive-briefing-snapshot.ts"],"names":[],"mappings":"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"}
|