@bbigbang/channel-bridge 0.1.0
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/assetCache.d.ts +15 -0
- package/dist/assetCache.js +50 -0
- package/dist/contextBundleFormat.d.ts +3 -0
- package/dist/contextBundleFormat.js +82 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +2065 -0
- package/dist/messageFormat.d.ts +26 -0
- package/dist/messageFormat.js +85 -0
- package/dist/panelFormat.d.ts +25 -0
- package/dist/panelFormat.js +391 -0
- package/dist/surfaceFormats.d.ts +15 -0
- package/dist/surfaceFormats.js +349 -0
- package/dist/taskUpdateFormat.d.ts +3 -0
- package/dist/taskUpdateFormat.js +17 -0
- package/dist/textPreview.d.ts +9 -0
- package/dist/textPreview.js +38 -0
- package/dist/workspaceFormats.d.ts +7 -0
- package/dist/workspaceFormats.js +41 -0
- package/package.json +36 -0
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
function formatTaskIdentity(agentTaskRef, taskNumber) {
|
|
2
|
+
if (agentTaskRef && taskNumber != null)
|
|
3
|
+
return `${agentTaskRef} · #t${taskNumber}`;
|
|
4
|
+
if (agentTaskRef)
|
|
5
|
+
return agentTaskRef;
|
|
6
|
+
if (taskNumber != null)
|
|
7
|
+
return `#t${taskNumber}`;
|
|
8
|
+
return 'task';
|
|
9
|
+
}
|
|
10
|
+
export function formatToolResult(format, text, data) {
|
|
11
|
+
if (format === 'json') {
|
|
12
|
+
return JSON.stringify(data, null, 2);
|
|
13
|
+
}
|
|
14
|
+
if (format === 'both') {
|
|
15
|
+
return `${text}\n\n## Structured\n\`\`\`json\n${JSON.stringify(data, null, 2)}\n\`\`\``;
|
|
16
|
+
}
|
|
17
|
+
return text;
|
|
18
|
+
}
|
|
19
|
+
export function formatSendMessageDiagnostics(data) {
|
|
20
|
+
const diagnostics = data.diagnostics && typeof data.diagnostics === 'object'
|
|
21
|
+
? data.diagnostics
|
|
22
|
+
: null;
|
|
23
|
+
const panel = diagnostics?.panel && typeof diagnostics.panel === 'object'
|
|
24
|
+
? diagnostics.panel
|
|
25
|
+
: null;
|
|
26
|
+
const unattachedPanelIds = Array.isArray(panel?.unattachedProducedPanelIds)
|
|
27
|
+
? panel.unattachedProducedPanelIds
|
|
28
|
+
.map((id) => typeof id === 'string' ? id.trim() : '')
|
|
29
|
+
.filter((id) => id.length > 0)
|
|
30
|
+
: [];
|
|
31
|
+
if (unattachedPanelIds.length === 0)
|
|
32
|
+
return '';
|
|
33
|
+
const recommendation = typeof panel?.recommendation === 'string' && panel.recommendation.trim()
|
|
34
|
+
? `\nRecommendation: ${panel.recommendation.trim()}`
|
|
35
|
+
: '';
|
|
36
|
+
return `\n\nPanel diagnostic: this run produced additional panels that were not attached to this message: ${unattachedPanelIds.join(', ')}.${recommendation}`;
|
|
37
|
+
}
|
|
38
|
+
export function formatConversationListText(conversations) {
|
|
39
|
+
if (conversations.length === 0)
|
|
40
|
+
return 'No conversations found.';
|
|
41
|
+
const lines = conversations.map((conversation) => {
|
|
42
|
+
const context = getConversationContext(conversation);
|
|
43
|
+
const parts = [
|
|
44
|
+
`${conversation.replyTarget} [${conversation.status}]`,
|
|
45
|
+
`surface=${conversation.surfaceKind}`,
|
|
46
|
+
`unread=${conversation.unreadCount}`,
|
|
47
|
+
`queued=${conversation.queuedPromptCount}`,
|
|
48
|
+
];
|
|
49
|
+
if (context?.myRole)
|
|
50
|
+
parts.push(`role=${context.myRole}`);
|
|
51
|
+
if (context?.goal)
|
|
52
|
+
parts.push(`goal=${context.goal}`);
|
|
53
|
+
if (context?.nextStep)
|
|
54
|
+
parts.push(`next=${context.nextStep}`);
|
|
55
|
+
if (context?.blockers?.length)
|
|
56
|
+
parts.push(`blockers=${context.blockers.join('; ')}`);
|
|
57
|
+
if (context?.lastMessage) {
|
|
58
|
+
parts.push(`last=@${context.lastMessage.senderName}: ${context.lastMessage.preview}`);
|
|
59
|
+
}
|
|
60
|
+
return `- ${parts.join(' ')}`;
|
|
61
|
+
}).join('\n');
|
|
62
|
+
return `## My Conversations (${conversations.length})\n\n${lines}`;
|
|
63
|
+
}
|
|
64
|
+
export function formatConversationSummaryToolText(conversation) {
|
|
65
|
+
if (conversation.reportText?.trim())
|
|
66
|
+
return conversation.reportText.trim();
|
|
67
|
+
const context = getConversationContext(conversation);
|
|
68
|
+
const lines = [
|
|
69
|
+
`Target: ${conversation.replyTarget}`,
|
|
70
|
+
`Status: ${conversation.status}`,
|
|
71
|
+
`Surface: ${conversation.surfaceKind}`,
|
|
72
|
+
`Unread: ${conversation.unreadCount}`,
|
|
73
|
+
`Queued prompts: ${conversation.queuedPromptCount}`,
|
|
74
|
+
];
|
|
75
|
+
if (context?.goal)
|
|
76
|
+
lines.push(`Goal: ${context.goal}`);
|
|
77
|
+
if (context?.recentState)
|
|
78
|
+
lines.push(`Recent state: ${context.recentState}`);
|
|
79
|
+
if (context?.blockers?.length)
|
|
80
|
+
lines.push(`Blockers: ${context.blockers.join('; ')}`);
|
|
81
|
+
if (context?.nextStep)
|
|
82
|
+
lines.push(`Next: ${context.nextStep}`);
|
|
83
|
+
if (context?.myRole)
|
|
84
|
+
lines.push(`My role: ${context.myRole}`);
|
|
85
|
+
if (context?.ownerName)
|
|
86
|
+
lines.push(`Owner: @${context.ownerName}`);
|
|
87
|
+
if (context?.boundTask) {
|
|
88
|
+
lines.push(`Bound task: ${formatTaskIdentity(context.boundTask.agentTaskRef, context.boundTask.taskNumber)} [${context.boundTask.status}]`);
|
|
89
|
+
}
|
|
90
|
+
if (context?.participants?.length) {
|
|
91
|
+
lines.push(`Participants: ${context.participants.map((name) => `@${name}`).join(', ')}`);
|
|
92
|
+
}
|
|
93
|
+
if (context?.activeHandoff) {
|
|
94
|
+
lines.push(`Active handoff: ${context.activeHandoff.handoffId} ${context.activeHandoff.mode} [${context.activeHandoff.status}] -> ${context.activeHandoff.targetReplyTarget}`);
|
|
95
|
+
}
|
|
96
|
+
if (context?.lastMessage) {
|
|
97
|
+
lines.push(`Last message: @${context.lastMessage.senderName} — ${context.lastMessage.preview}`);
|
|
98
|
+
}
|
|
99
|
+
return lines.join('\n');
|
|
100
|
+
}
|
|
101
|
+
export function formatRuntimePresenceToolText(presence) {
|
|
102
|
+
if (presence.reportText?.trim())
|
|
103
|
+
return presence.reportText.trim();
|
|
104
|
+
const driverNames = (presence.runtime?.runtimeDrivers ?? []).map((driver) => driver.agentType).join(', ') || 'none';
|
|
105
|
+
const lines = [
|
|
106
|
+
'[Runtime presence]',
|
|
107
|
+
`node: ${presence.node?.nodeId ?? 'none'}${presence.node?.machineName ? ` (${presence.node.machineName})` : ''} [${presence.node?.status ?? 'unknown'}]`,
|
|
108
|
+
`runtime: workspace_root=${presence.runtime?.workspaceRoot ?? 'unknown'} | terminals=${presence.runtime?.terminalBackendAvailable == null ? 'unknown' : (presence.runtime.terminalBackendAvailable ? 'yes' : 'no')} | drivers=${driverNames}`,
|
|
109
|
+
`hosts: total=${presence.summary?.totalHosts ?? 0}, active=${presence.summary?.activeHosts ?? 0}, idle=${presence.summary?.idleHosts ?? 0}, failed=${presence.summary?.failedHosts ?? 0}, approval=${presence.summary?.hostsWithPendingApproval ?? 0}, resumable=${presence.summary?.resumableHosts ?? 0}`,
|
|
110
|
+
];
|
|
111
|
+
if (presence.currentHost) {
|
|
112
|
+
lines.push(`current_host: ${(presence.currentHost.replyTarget ?? presence.currentHost.hostKey)} [${presence.currentHost.state}] | pending_dispatch=${presence.currentHost.pendingDispatchCount} | approval=${presence.currentHost.hasPendingApproval ? 'yes' : 'no'}`);
|
|
113
|
+
}
|
|
114
|
+
return lines.join('\n');
|
|
115
|
+
}
|
|
116
|
+
export function buildCompactRuntimePresenceData(presence) {
|
|
117
|
+
return {
|
|
118
|
+
generatedAt: presence.generatedAt ?? null,
|
|
119
|
+
node: presence.node ?? null,
|
|
120
|
+
runtime: presence.runtime
|
|
121
|
+
? {
|
|
122
|
+
workspaceRoot: presence.runtime.workspaceRoot ?? null,
|
|
123
|
+
terminalBackendAvailable: presence.runtime.terminalBackendAvailable ?? null,
|
|
124
|
+
runtimeDrivers: (presence.runtime.runtimeDrivers ?? []).map((driver) => driver.agentType),
|
|
125
|
+
capabilities: presence.runtime.capabilities
|
|
126
|
+
? Object.entries(presence.runtime.capabilities)
|
|
127
|
+
.filter(([, enabled]) => Boolean(enabled))
|
|
128
|
+
.map(([name]) => name)
|
|
129
|
+
: [],
|
|
130
|
+
}
|
|
131
|
+
: null,
|
|
132
|
+
summary: presence.summary ?? null,
|
|
133
|
+
currentHost: presence.currentHost
|
|
134
|
+
? {
|
|
135
|
+
target: presence.currentHost.replyTarget ?? null,
|
|
136
|
+
state: presence.currentHost.state,
|
|
137
|
+
pendingDispatchCount: presence.currentHost.pendingDispatchCount,
|
|
138
|
+
hasPendingApproval: presence.currentHost.hasPendingApproval,
|
|
139
|
+
resumable: presence.currentHost.resumable,
|
|
140
|
+
}
|
|
141
|
+
: null,
|
|
142
|
+
otherHosts: (presence.otherHosts ?? []).map((host) => ({
|
|
143
|
+
target: host.replyTarget ?? null,
|
|
144
|
+
state: host.state,
|
|
145
|
+
pendingDispatchCount: host.pendingDispatchCount,
|
|
146
|
+
hasPendingApproval: host.hasPendingApproval,
|
|
147
|
+
})),
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
export function formatSelfStateToolText(state) {
|
|
151
|
+
if (state.reportText?.trim())
|
|
152
|
+
return state.reportText.trim();
|
|
153
|
+
const currentConversationId = state.currentConversation?.conversationId ?? null;
|
|
154
|
+
const otherSurfaces = (state.conversations ?? []).filter((item) => item.conversationId !== currentConversationId);
|
|
155
|
+
const lines = ['[Agent self state]'];
|
|
156
|
+
if (state.currentContext?.myRole)
|
|
157
|
+
lines.push(`role_here: ${state.currentContext.myRole}`);
|
|
158
|
+
if (state.currentContext?.boundTask) {
|
|
159
|
+
lines.push(`bound_task: ${formatTaskIdentity(state.currentContext.boundTask.agentTaskRef, state.currentContext.boundTask.taskNumber)} [${state.currentContext.boundTask.status}]`);
|
|
160
|
+
}
|
|
161
|
+
lines.push('other_surfaces:');
|
|
162
|
+
if (otherSurfaces.length === 0) {
|
|
163
|
+
lines.push('- none');
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
for (const conversation of otherSurfaces.slice(0, 6)) {
|
|
167
|
+
const summary = getConversationContext(conversation);
|
|
168
|
+
const extras = [];
|
|
169
|
+
if (conversation.unreadCount > 0)
|
|
170
|
+
extras.push(`unread=${conversation.unreadCount}`);
|
|
171
|
+
if (summary?.myRole)
|
|
172
|
+
extras.push(`role=${summary.myRole}`);
|
|
173
|
+
if (summary?.boundTask) {
|
|
174
|
+
extras.push(`task=${formatTaskIdentity(summary.boundTask.agentTaskRef, summary.boundTask.taskNumber)} [${summary.boundTask.status}]`);
|
|
175
|
+
}
|
|
176
|
+
if (summary?.activeHandoff) {
|
|
177
|
+
extras.push(`handoff=${summary.activeHandoff.handoffId} ${summary.activeHandoff.mode} [${summary.activeHandoff.status}]`);
|
|
178
|
+
}
|
|
179
|
+
const teaser = buildSelfStateTeaser(summary);
|
|
180
|
+
if (teaser)
|
|
181
|
+
extras.push(`teaser=${teaser}`);
|
|
182
|
+
lines.push(`- ${conversation.replyTarget} [${conversation.surfaceKind}, ${conversation.status}]${extras.length ? ` | ${extras.join(' | ')}` : ''}`);
|
|
183
|
+
}
|
|
184
|
+
const hiddenSurfaces = otherSurfaces.slice(6);
|
|
185
|
+
if (hiddenSurfaces.length > 0) {
|
|
186
|
+
lines.push(`- hidden=${hiddenSurfaces.length}${formatHiddenSurfaceBreakdown(hiddenSurfaces)}`);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
return lines.join('\n');
|
|
190
|
+
}
|
|
191
|
+
export function buildCompactSelfStateData(state) {
|
|
192
|
+
const currentConversationId = state.currentConversation?.conversationId ?? null;
|
|
193
|
+
const currentBoundTaskId = state.currentContext?.boundTask?.taskId ?? null;
|
|
194
|
+
const allOtherSurfaces = (state.conversations ?? [])
|
|
195
|
+
.filter((conversation) => conversation.conversationId !== currentConversationId);
|
|
196
|
+
const otherSurfaces = allOtherSurfaces
|
|
197
|
+
.slice(0, 4)
|
|
198
|
+
.map((conversation) => {
|
|
199
|
+
const summary = getConversationContext(conversation);
|
|
200
|
+
const activeHandoff = summary?.activeHandoff ?? null;
|
|
201
|
+
return {
|
|
202
|
+
target: conversation.replyTarget,
|
|
203
|
+
status: conversation.status,
|
|
204
|
+
surfaceKind: conversation.surfaceKind,
|
|
205
|
+
...(conversation.unreadCount > 0 ? { unreadCount: conversation.unreadCount } : {}),
|
|
206
|
+
role: summary?.myRole ?? null,
|
|
207
|
+
task: toCompactBoundTask(summary?.boundTask ?? null),
|
|
208
|
+
activeHandoff: activeHandoff
|
|
209
|
+
? {
|
|
210
|
+
handoffId: activeHandoff.handoffId,
|
|
211
|
+
mode: activeHandoff.mode,
|
|
212
|
+
status: activeHandoff.status,
|
|
213
|
+
target: activeHandoff.targetReplyTarget,
|
|
214
|
+
}
|
|
215
|
+
: null,
|
|
216
|
+
teaser: buildSelfStateTeaser(summary),
|
|
217
|
+
};
|
|
218
|
+
});
|
|
219
|
+
const hiddenSurfaces = allOtherSurfaces.slice(4);
|
|
220
|
+
const visibleTasks = (state.recentTasks ?? [])
|
|
221
|
+
.filter((task) => task.taskId !== currentBoundTaskId)
|
|
222
|
+
.slice(0, 3);
|
|
223
|
+
const hiddenTasksCount = Math.max(0, (state.summary?.involvedTasks ?? 0) - (currentBoundTaskId ? 1 : 0) - visibleTasks.length);
|
|
224
|
+
return {
|
|
225
|
+
generatedAt: state.generatedAt ?? null,
|
|
226
|
+
agent: state.agent
|
|
227
|
+
? {
|
|
228
|
+
name: state.agent.name ?? null,
|
|
229
|
+
agentType: state.agent.agentType ?? null,
|
|
230
|
+
joinedChannels: (state.agent.joinedChannels ?? []).map((channel) => channel.target),
|
|
231
|
+
}
|
|
232
|
+
: null,
|
|
233
|
+
runtimePresence: state.runtimePresence
|
|
234
|
+
? buildCompactRuntimePresenceData(state.runtimePresence)
|
|
235
|
+
: null,
|
|
236
|
+
summary: state.summary
|
|
237
|
+
? {
|
|
238
|
+
conversations: state.summary.totalConversations ?? 0,
|
|
239
|
+
active: state.summary.activeConversations ?? 0,
|
|
240
|
+
queued: state.summary.queuedConversations ?? 0,
|
|
241
|
+
recovering: state.summary.recoveringConversations ?? 0,
|
|
242
|
+
approval: state.summary.awaitingApprovalConversations ?? 0,
|
|
243
|
+
failed: state.summary.failedConversations ?? 0,
|
|
244
|
+
surfacesWithNewActivity: state.summary.surfacesWithUnread ?? 0,
|
|
245
|
+
pending: state.summary.pendingPrompts ?? 0,
|
|
246
|
+
tasks: {
|
|
247
|
+
claimed: state.summary.claimedTasks ?? 0,
|
|
248
|
+
involved: state.summary.involvedTasks ?? 0,
|
|
249
|
+
review: state.summary.inReviewTasks ?? 0,
|
|
250
|
+
},
|
|
251
|
+
}
|
|
252
|
+
: null,
|
|
253
|
+
current: state.currentConversation
|
|
254
|
+
? {
|
|
255
|
+
target: state.currentConversation.replyTarget,
|
|
256
|
+
status: state.currentConversation.status,
|
|
257
|
+
surfaceKind: state.currentConversation.surfaceKind,
|
|
258
|
+
role: state.currentContext?.myRole ?? null,
|
|
259
|
+
task: toCompactBoundTask(state.currentContext?.boundTask ?? null),
|
|
260
|
+
blockers: (state.currentContext?.blockers ?? [])
|
|
261
|
+
.map((blocker) => summarizeInline(blocker, 96))
|
|
262
|
+
.filter((blocker) => Boolean(blocker)),
|
|
263
|
+
activeHandoff: state.currentContext?.activeHandoff
|
|
264
|
+
? {
|
|
265
|
+
handoffId: state.currentContext.activeHandoff.handoffId,
|
|
266
|
+
mode: state.currentContext.activeHandoff.mode,
|
|
267
|
+
status: state.currentContext.activeHandoff.status,
|
|
268
|
+
target: state.currentContext.activeHandoff.targetReplyTarget,
|
|
269
|
+
}
|
|
270
|
+
: null,
|
|
271
|
+
}
|
|
272
|
+
: null,
|
|
273
|
+
otherSurfaces,
|
|
274
|
+
...(hiddenSurfaces.length > 0
|
|
275
|
+
? {
|
|
276
|
+
hiddenSurfaces: {
|
|
277
|
+
count: hiddenSurfaces.length,
|
|
278
|
+
byStatus: summarizeHiddenSurfaceStatuses(hiddenSurfaces),
|
|
279
|
+
},
|
|
280
|
+
}
|
|
281
|
+
: {}),
|
|
282
|
+
tasks: visibleTasks
|
|
283
|
+
.map((task) => ({
|
|
284
|
+
task: formatTaskIdentity(task.agentTaskRef, task.taskNumber),
|
|
285
|
+
status: task.status,
|
|
286
|
+
title: summarizeInline(task.title),
|
|
287
|
+
target: task.threadTarget ?? task.sourceTarget ?? null,
|
|
288
|
+
})),
|
|
289
|
+
...(hiddenTasksCount > 0 ? { hiddenTasksCount } : {}),
|
|
290
|
+
handoffs: (state.recentHandoffs ?? [])
|
|
291
|
+
.filter((handoff) => handoff.status !== 'completed')
|
|
292
|
+
.slice(0, 3)
|
|
293
|
+
.map((handoff) => ({
|
|
294
|
+
handoffId: handoff.handoffId,
|
|
295
|
+
mode: handoff.mode,
|
|
296
|
+
status: handoff.status,
|
|
297
|
+
source: handoff.sourceTarget ?? null,
|
|
298
|
+
target: handoff.targetReplyTarget,
|
|
299
|
+
})),
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
function summarizeInline(value, maxLength = 96) {
|
|
303
|
+
const trimmed = value?.trim() ?? '';
|
|
304
|
+
if (!trimmed)
|
|
305
|
+
return null;
|
|
306
|
+
if (trimmed.length <= maxLength)
|
|
307
|
+
return trimmed;
|
|
308
|
+
return `${trimmed.slice(0, Math.max(0, maxLength - 3)).trimEnd()}...`;
|
|
309
|
+
}
|
|
310
|
+
function getConversationContext(conversation) {
|
|
311
|
+
return conversation?.context ?? null;
|
|
312
|
+
}
|
|
313
|
+
function buildSelfStateTeaser(summary, maxLength = 64) {
|
|
314
|
+
const candidates = [
|
|
315
|
+
summary?.boundTask?.title,
|
|
316
|
+
summary?.goal,
|
|
317
|
+
summary?.lastMessage?.preview,
|
|
318
|
+
];
|
|
319
|
+
for (const candidate of candidates) {
|
|
320
|
+
const teaser = summarizeInline(candidate, maxLength);
|
|
321
|
+
if (teaser)
|
|
322
|
+
return teaser;
|
|
323
|
+
}
|
|
324
|
+
return null;
|
|
325
|
+
}
|
|
326
|
+
function formatHiddenSurfaceBreakdown(conversations) {
|
|
327
|
+
const parts = Object.entries(summarizeHiddenSurfaceStatuses(conversations))
|
|
328
|
+
.map(([status, count]) => `${status}=${count}`);
|
|
329
|
+
return parts.length > 0 ? `(${parts.join(',')})` : '';
|
|
330
|
+
}
|
|
331
|
+
function summarizeHiddenSurfaceStatuses(conversations) {
|
|
332
|
+
const order = ['active', 'queued', 'recovering', 'awaiting_approval', 'failed', 'idle'];
|
|
333
|
+
const counts = new Map();
|
|
334
|
+
for (const conversation of conversations) {
|
|
335
|
+
counts.set(conversation.status, (counts.get(conversation.status) ?? 0) + 1);
|
|
336
|
+
}
|
|
337
|
+
const result = {};
|
|
338
|
+
for (const status of order) {
|
|
339
|
+
const count = counts.get(status) ?? 0;
|
|
340
|
+
if (count > 0)
|
|
341
|
+
result[status] = count;
|
|
342
|
+
}
|
|
343
|
+
return result;
|
|
344
|
+
}
|
|
345
|
+
function toCompactBoundTask(boundTask) {
|
|
346
|
+
if (!boundTask)
|
|
347
|
+
return null;
|
|
348
|
+
return `${formatTaskIdentity(boundTask.agentTaskRef, boundTask.taskNumber)} [${boundTask.status}]`;
|
|
349
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export function formatTaskUpdateDeliveryText(delivery) {
|
|
2
|
+
const noteTargets = delivery.recommendedNoteTargets.length > 0
|
|
3
|
+
? delivery.recommendedNoteTargets.join(', ')
|
|
4
|
+
: 'none';
|
|
5
|
+
return [
|
|
6
|
+
delivery.summaryText,
|
|
7
|
+
`Recommended note targets: ${noteTargets}`,
|
|
8
|
+
delivery.noteGuidance,
|
|
9
|
+
delivery.memoryReminder,
|
|
10
|
+
].join('\n');
|
|
11
|
+
}
|
|
12
|
+
export function formatTaskUpdateDeliveriesSection(deliveries) {
|
|
13
|
+
if (deliveries.length === 0)
|
|
14
|
+
return '';
|
|
15
|
+
const blocks = deliveries.map((delivery) => formatTaskUpdateDeliveryText(delivery)).join('\n\n');
|
|
16
|
+
return `\n\nTask update guidance:\n${blocks}`;
|
|
17
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
declare const DEFAULT_INLINE_TEXT_PREVIEW_MAX_BYTES: number;
|
|
2
|
+
export declare function buildInlineTextPreview(params: {
|
|
3
|
+
attachmentId: string;
|
|
4
|
+
mimeType: string;
|
|
5
|
+
sizeLabel: string;
|
|
6
|
+
fileBuffer: Buffer;
|
|
7
|
+
maxBytes?: number;
|
|
8
|
+
}): string;
|
|
9
|
+
export { DEFAULT_INLINE_TEXT_PREVIEW_MAX_BYTES };
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
const DEFAULT_INLINE_TEXT_PREVIEW_MAX_BYTES = 64 * 1024;
|
|
2
|
+
function trimIncompleteUtf8Suffix(buffer) {
|
|
3
|
+
if (buffer.length === 0)
|
|
4
|
+
return buffer;
|
|
5
|
+
let continuationBytes = 0;
|
|
6
|
+
while (continuationBytes < Math.min(3, buffer.length)
|
|
7
|
+
&& (buffer[buffer.length - 1 - continuationBytes] & 0b1100_0000) === 0b1000_0000) {
|
|
8
|
+
continuationBytes += 1;
|
|
9
|
+
}
|
|
10
|
+
const leadIndex = buffer.length - 1 - continuationBytes;
|
|
11
|
+
if (leadIndex < 0) {
|
|
12
|
+
return buffer.subarray(0, buffer.length - continuationBytes);
|
|
13
|
+
}
|
|
14
|
+
const leadByte = buffer[leadIndex];
|
|
15
|
+
const expectedLength = ((leadByte & 0b1000_0000) === 0 ? 1
|
|
16
|
+
: (leadByte & 0b1110_0000) === 0b1100_0000 ? 2
|
|
17
|
+
: (leadByte & 0b1111_0000) === 0b1110_0000 ? 3
|
|
18
|
+
: (leadByte & 0b1111_1000) === 0b1111_0000 ? 4
|
|
19
|
+
: 1);
|
|
20
|
+
const actualLength = buffer.length - leadIndex;
|
|
21
|
+
if (actualLength < expectedLength) {
|
|
22
|
+
return buffer.subarray(0, leadIndex);
|
|
23
|
+
}
|
|
24
|
+
return buffer;
|
|
25
|
+
}
|
|
26
|
+
export function buildInlineTextPreview(params) {
|
|
27
|
+
const maxBytes = params.maxBytes ?? DEFAULT_INLINE_TEXT_PREVIEW_MAX_BYTES;
|
|
28
|
+
const truncated = params.fileBuffer.length > maxBytes;
|
|
29
|
+
const previewBuffer = truncated
|
|
30
|
+
? params.fileBuffer.subarray(0, maxBytes)
|
|
31
|
+
: params.fileBuffer;
|
|
32
|
+
const previewText = trimIncompleteUtf8Suffix(previewBuffer).toString('utf8');
|
|
33
|
+
const suffix = truncated
|
|
34
|
+
? `\n\n[truncated preview: showing first ${(maxBytes / 1024).toFixed(0)} KB of ${params.sizeLabel}; inspect locally for the full file.]`
|
|
35
|
+
: '';
|
|
36
|
+
return `Attachment ${params.attachmentId} (${params.mimeType}, ${params.sizeLabel}):\n\n${previewText}${suffix}`;
|
|
37
|
+
}
|
|
38
|
+
export { DEFAULT_INLINE_TEXT_PREVIEW_MAX_BYTES };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { AgentWorkspaceFileResult, AgentWorkspaceListResult, AgentWorkspaceInspectResult } from '@bbigbang/protocol';
|
|
2
|
+
export declare function formatWorkspaceInspectToolText(result: AgentWorkspaceInspectResult & {
|
|
3
|
+
reportText?: string | null;
|
|
4
|
+
}): string;
|
|
5
|
+
export declare function buildCompactWorkspaceInspectData(result: AgentWorkspaceInspectResult): Record<string, unknown>;
|
|
6
|
+
export declare function formatWorkspaceTreeToolText(result: AgentWorkspaceListResult): string;
|
|
7
|
+
export declare function formatWorkspaceFileToolText(result: AgentWorkspaceFileResult): string;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export function formatWorkspaceInspectToolText(result) {
|
|
2
|
+
if (result.reportText?.trim())
|
|
3
|
+
return result.reportText.trim();
|
|
4
|
+
const inspect = result.inspect;
|
|
5
|
+
return [
|
|
6
|
+
'[Workspace inspect]',
|
|
7
|
+
`node: ${result.nodeId ?? 'none'}`,
|
|
8
|
+
`workspace_root: ${result.workspaceRoot ?? 'none'}`,
|
|
9
|
+
`git: ${inspect?.isGit ? 'yes' : 'no'} | kind=${inspect?.workspaceKind ?? 'unknown'} | branch=${inspect?.branchName ?? 'none'}`,
|
|
10
|
+
inspect?.repoRoot ? `repo_root: ${inspect.repoRoot}` : null,
|
|
11
|
+
inspect?.remoteUrl ? `remote: ${inspect.remoteUrl}` : null,
|
|
12
|
+
].filter(Boolean).join('\n');
|
|
13
|
+
}
|
|
14
|
+
export function buildCompactWorkspaceInspectData(result) {
|
|
15
|
+
return {
|
|
16
|
+
nodeId: result.nodeId ?? null,
|
|
17
|
+
workspaceRoot: result.workspaceRoot ?? null,
|
|
18
|
+
inspect: result.inspect ?? null,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export function formatWorkspaceTreeToolText(result) {
|
|
22
|
+
const prefix = result.path ? result.path : '.';
|
|
23
|
+
if (!result.entries.length)
|
|
24
|
+
return `[Workspace tree]\npath: ${prefix}\n(entries: empty)`;
|
|
25
|
+
const lines = result.entries.map((entry) => `- ${entry.path} [${entry.kind}]`);
|
|
26
|
+
return `[Workspace tree]\npath: ${prefix}\n${lines.join('\n')}`;
|
|
27
|
+
}
|
|
28
|
+
export function formatWorkspaceFileToolText(result) {
|
|
29
|
+
const fence = result.mimeType === 'text/markdown' ? 'markdown' : 'text';
|
|
30
|
+
return [
|
|
31
|
+
'[Workspace file]',
|
|
32
|
+
`path: ${result.path}`,
|
|
33
|
+
`mime: ${result.mimeType}`,
|
|
34
|
+
`size: ${result.size}`,
|
|
35
|
+
result.modifiedAt != null ? `modified_at: ${new Date(result.modifiedAt).toISOString()}` : null,
|
|
36
|
+
'',
|
|
37
|
+
`\`\`\`${fence}`,
|
|
38
|
+
result.content,
|
|
39
|
+
'\`\`\`',
|
|
40
|
+
].filter((line) => line !== null).join('\n');
|
|
41
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@bbigbang/channel-bridge",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"bin": {
|
|
6
|
+
"channel-bridge": "dist/index.js"
|
|
7
|
+
},
|
|
8
|
+
"main": "dist/index.js",
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"!dist/**/__tests__/**",
|
|
12
|
+
"!dist/**/*.test.*",
|
|
13
|
+
"!dist/**/*.map",
|
|
14
|
+
"package.json"
|
|
15
|
+
],
|
|
16
|
+
"exports": {
|
|
17
|
+
".": "./dist/index.js"
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
21
|
+
"zod": "^4.3.6",
|
|
22
|
+
"@bbigbang/protocol": "0.1.0"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"@types/node": "^25.3.3",
|
|
26
|
+
"typescript": "^5.9.3",
|
|
27
|
+
"vitest": "^3.2.1"
|
|
28
|
+
},
|
|
29
|
+
"scripts": {
|
|
30
|
+
"build": "tsc -p tsconfig.json",
|
|
31
|
+
"typecheck": "tsc --noEmit -p tsconfig.json",
|
|
32
|
+
"lint": "echo 'No lint configured'",
|
|
33
|
+
"dev": "tsc -p tsconfig.json --watch",
|
|
34
|
+
"test": "vitest run"
|
|
35
|
+
}
|
|
36
|
+
}
|