@wowyuarm/dsh-agent-team 0.1.2 → 0.1.4
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/README.md +8 -1
- package/README.zh.md +9 -1
- package/package.json +12 -3
- package/packages/agent-team/README.md +3 -3
- package/packages/agent-team/README.zh.md +3 -3
- package/packages/agent-team/lib/attachments.js +11 -12
- package/packages/agent-team/lib/auto-compaction.js +163 -0
- package/packages/agent-team/lib/index.js +252 -139
- package/packages/agent-team/lib/ledger.js +344 -170
- package/packages/agent-team/lib/recovery.js +30 -35
- package/packages/agent-team/lib/spec.js +27 -11
- package/packages/agent-team/lib/typert.host.js +197 -88
- package/packages/agent-team/lib/typert.remote-client.d.ts +3 -1
- package/packages/agent-team/lib/typert.remote-client.d.ts.map +1 -1
- package/packages/agent-team/lib/typert.remote-client.js +139 -59
- package/packages/agent-team/lib/types/attachments.d.ts +2 -2
- package/packages/agent-team/lib/types/attachments.d.ts.map +1 -1
- package/packages/agent-team/lib/types/auto-compaction.d.ts +38 -0
- package/packages/agent-team/lib/types/auto-compaction.d.ts.map +1 -0
- package/packages/agent-team/lib/types/index.d.ts +52 -19
- package/packages/agent-team/lib/types/index.d.ts.map +1 -1
- package/packages/agent-team/lib/types/ledger.d.ts +29 -2
- package/packages/agent-team/lib/types/ledger.d.ts.map +1 -1
- package/packages/agent-team/lib/types/recovery.d.ts +15 -16
- package/packages/agent-team/lib/types/recovery.d.ts.map +1 -1
- package/packages/agent-team/lib/types/spec.d.ts.map +1 -1
- package/packages/agent-team/lib/types/types.d.ts +69 -30
- package/packages/agent-team/lib/types/types.d.ts.map +1 -1
- package/packages/agent-team/preset/team-member/agent.cordis.yml +7 -2
- package/packages/client-agent-team/README.md +2 -1
- package/packages/client-agent-team/README.zh.md +2 -1
- package/packages/client-agent-team/lib/client.js +1577 -863
- package/packages/client-agent-team/lib/client.js.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.js +35 -174
- package/packages/client-agent-team/lib/types/client/TeamChannelPage.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamChannelPage.js +20 -30
- package/packages/client-agent-team/lib/types/client/TeamChannelsPanel.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamChannelsPanel.js +3 -2
- package/packages/client-agent-team/lib/types/client/TeamComposer.d.ts +6 -1
- package/packages/client-agent-team/lib/types/client/TeamComposer.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamComposer.js +4 -5
- package/packages/client-agent-team/lib/types/client/TeamConversation.d.ts +1 -1
- package/packages/client-agent-team/lib/types/client/TeamConversation.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamConversation.js +3 -3
- package/packages/client-agent-team/lib/types/client/TeamMemberEditor.d.ts +34 -0
- package/packages/client-agent-team/lib/types/client/TeamMemberEditor.d.ts.map +1 -0
- package/packages/client-agent-team/lib/types/client/TeamMemberEditor.js +169 -0
- package/packages/client-agent-team/lib/types/client/TeamMemberSessionComposer.d.ts +17 -0
- package/packages/client-agent-team/lib/types/client/TeamMemberSessionComposer.d.ts.map +1 -0
- package/packages/client-agent-team/lib/types/client/TeamMemberSessionComposer.js +120 -0
- package/packages/client-agent-team/lib/types/client/TeamMessage.d.ts +4 -1
- package/packages/client-agent-team/lib/types/client/TeamMessage.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamMessage.js +94 -47
- package/packages/client-agent-team/lib/types/client/TeamThreadPage.d.ts +2 -1
- package/packages/client-agent-team/lib/types/client/TeamThreadPage.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamThreadPage.js +81 -39
- package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.js +2 -1
- package/packages/client-agent-team/lib/types/client/index.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/index.js +72 -1
- package/packages/client-agent-team/lib/types/client/locales.d.ts +24 -0
- package/packages/client-agent-team/lib/types/client/locales.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/locales.js +24 -0
- package/packages/client-agent-team/lib/types/client/member-session-input.d.ts +22 -0
- package/packages/client-agent-team/lib/types/client/member-session-input.d.ts.map +1 -0
- package/packages/client-agent-team/lib/types/client/member-session-input.js +98 -0
- package/packages/client-agent-team/lib/types/client/navigation.d.ts +1 -1
- package/packages/client-agent-team/lib/types/client/navigation.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/navigation.js +12 -6
- package/packages/client-agent-team/lib/types/client/requests.d.ts +16 -0
- package/packages/client-agent-team/lib/types/client/requests.d.ts.map +1 -0
- package/packages/client-agent-team/lib/types/client/requests.js +22 -0
- package/packages/client-agent-team/lib/types/client/slots.d.ts +2 -1
- package/packages/client-agent-team/lib/types/client/slots.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/task-refs.d.ts +6 -1
- package/packages/client-agent-team/lib/types/client/task-refs.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/task-refs.js +19 -0
- package/packages/client-agent-team/lib/types/client/team-formatters.d.ts +52 -3
- package/packages/client-agent-team/lib/types/client/team-formatters.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/team-formatters.js +74 -4
- package/packages/client-agent-team/lib/types/client/team-membership.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/team-membership.js +2 -1
- package/packages/tool-agent-team/README.md +7 -7
- package/packages/tool-agent-team/README.zh.md +7 -7
- package/packages/tool-agent-team/lib/index.js +38 -28
- package/packages/tool-agent-team/lib/types/index.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamInboxPanel.d.ts +0 -13
- package/packages/client-agent-team/lib/types/client/TeamInboxPanel.d.ts.map +0 -1
- package/packages/client-agent-team/lib/types/client/TeamInboxPanel.js +0 -90
|
@@ -6,9 +6,10 @@ import { TeamPresenceDot } from "./TeamPresenceDot.js";
|
|
|
6
6
|
import { TeamMessage } from "./TeamMessage.js";
|
|
7
7
|
import { TeamRunDivider } from "./TeamRunDivider.js";
|
|
8
8
|
import { formatActivity, formatClaimState, formatTaskStatus, formatTaskTitle, mentionNamesOf } from "./team-formatters.js";
|
|
9
|
+
import { mintRequestId } from "./requests.js";
|
|
9
10
|
import { daySeparatorLabel, isRunGap, timelineDayKey } from "./team-separators.js";
|
|
10
11
|
import { useTimelineScroll } from "./timeline-scroll.js";
|
|
11
|
-
import {
|
|
12
|
+
import { hostTaskRefLookup, jumpToTaskThread } from "./task-refs.js";
|
|
12
13
|
import { bytesToBase64 } from "./attachment-preview.js";
|
|
13
14
|
import css from './conversation.module.css';
|
|
14
15
|
import threadCss from './thread.module.css';
|
|
@@ -32,7 +33,8 @@ function readMeta(facts) {
|
|
|
32
33
|
return new Map(facts.map(fact => [factKey(fact.fact), fact]));
|
|
33
34
|
}
|
|
34
35
|
export function TeamThreadPage(props) {
|
|
35
|
-
const { workspaceId, channelRef, taskRef, threadRef, taskNumber, backToWorkspace, selectChannel, selectThread, resolveTaskRefs, putAttachment, loadChannels, readThread, loadThreadHistory, subscribeChanges, loadMembers, drafts, getAttachment, reply, changeTask, t, } = props;
|
|
36
|
+
const { workspaceId, channelRef, taskRef, threadRef, taskNumber, backToWorkspace, selectChannel, selectThread, resolveTaskRefs, putAttachment, loadChannels, readThread, loadThreadHistory, subscribeChanges, loadMembers, drafts, getAttachment, reply, changeTask, promoteThread, t, } = props;
|
|
37
|
+
const threadRequest = { threadRef, ...(taskRef === undefined ? {} : { taskRef }) };
|
|
36
38
|
const [projection, setProjection] = useState();
|
|
37
39
|
const [channelView, setChannelView] = useState();
|
|
38
40
|
const [members, setMembers] = useState([]);
|
|
@@ -52,19 +54,22 @@ export function TeamThreadPage(props) {
|
|
|
52
54
|
// confirm dialog lists exactly what will be completed with the Task.
|
|
53
55
|
const [confirmingAccept, setConfirmingAccept] = useState(false);
|
|
54
56
|
useEffect(() => {
|
|
55
|
-
if (confirmingAccept && projection?.task
|
|
57
|
+
if (confirmingAccept && projection?.task?.resolution === 'accepted')
|
|
56
58
|
setConfirmingAccept(false);
|
|
57
|
-
}, [confirmingAccept, projection?.task
|
|
59
|
+
}, [confirmingAccept, projection?.task?.resolution]);
|
|
58
60
|
const [replyRequestId, setReplyRequestId] = useState();
|
|
59
61
|
const [confirmation, setConfirmation] = useState();
|
|
60
62
|
const [statusMessage, setStatusMessage] = useState();
|
|
61
63
|
const [pending, setPending] = useState(false);
|
|
64
|
+
// Label source for the promote/accept buttons only: a reply send also raises
|
|
65
|
+
// the shared `pending` gate, and must not retitle those buttons.
|
|
66
|
+
const [mutating, setMutating] = useState();
|
|
62
67
|
const [loading, setLoading] = useState(true);
|
|
63
68
|
const [error, setError] = useState();
|
|
64
69
|
const mountedRef = useRef(false);
|
|
65
70
|
const currentFactsRef = useRef([]);
|
|
66
71
|
const sequenceRef = useRef(0);
|
|
67
|
-
const readRequestIdRef = useRef(
|
|
72
|
+
const readRequestIdRef = useRef(mintRequestId());
|
|
68
73
|
const mutationRequests = useRef(new Map());
|
|
69
74
|
const threadLastFact = currentFacts[currentFacts.length - 1];
|
|
70
75
|
const timeline = useTimelineScroll(`${currentFacts.length}:${olderFacts.length}:${threadLastFact === undefined ? '' : factKey(threadLastFact)}`);
|
|
@@ -85,12 +90,12 @@ export function TeamThreadPage(props) {
|
|
|
85
90
|
if (!mountedRef.current)
|
|
86
91
|
return false;
|
|
87
92
|
if (newRequest)
|
|
88
|
-
readRequestIdRef.current =
|
|
93
|
+
readRequestIdRef.current = mintRequestId();
|
|
89
94
|
const sequence = sequenceRef.current + 1;
|
|
90
95
|
sequenceRef.current = sequence;
|
|
91
96
|
setLoading(true);
|
|
92
97
|
try {
|
|
93
|
-
const result = await readThread({ requestId: readRequestIdRef.current, workspaceId,
|
|
98
|
+
const result = await readThread({ requestId: readRequestIdRef.current, workspaceId, ...threadRequest });
|
|
94
99
|
if (!mountedRef.current || sequence !== sequenceRef.current)
|
|
95
100
|
return false;
|
|
96
101
|
if (!result.ok) {
|
|
@@ -134,7 +139,7 @@ export function TeamThreadPage(props) {
|
|
|
134
139
|
};
|
|
135
140
|
const refreshPassiveFacts = async () => {
|
|
136
141
|
try {
|
|
137
|
-
const result = await loadThreadHistory({ workspaceId,
|
|
142
|
+
const result = await loadThreadHistory({ workspaceId, ...threadRequest, limit: 100 });
|
|
138
143
|
if (!mountedRef.current || !result.ok)
|
|
139
144
|
return;
|
|
140
145
|
const incoming = result.value.facts;
|
|
@@ -152,7 +157,7 @@ export function TeamThreadPage(props) {
|
|
|
152
157
|
currentFactsRef.current = merged;
|
|
153
158
|
return merged;
|
|
154
159
|
});
|
|
155
|
-
setProjection(current => current === undefined ? current : { ...current, task: result.value.task, thread: result.value.thread, claims: result.value.claims });
|
|
160
|
+
setProjection(current => current === undefined ? current : { ...current, ...(result.value.task === undefined ? {} : { task: result.value.task }), thread: result.value.thread, claims: result.value.claims });
|
|
156
161
|
if (additions.length === 0)
|
|
157
162
|
return;
|
|
158
163
|
// A reader scrolled away from the tail must be offered the explicit
|
|
@@ -199,8 +204,8 @@ export function TeamThreadPage(props) {
|
|
|
199
204
|
// One parallel round covers the whole first paint. The durable read no
|
|
200
205
|
// longer wakes any change scope, so no second wave follows it.
|
|
201
206
|
const [read, history] = await Promise.all([
|
|
202
|
-
readThread({ requestId: readRequestIdRef.current, workspaceId,
|
|
203
|
-
loadThreadHistory({ workspaceId,
|
|
207
|
+
readThread({ requestId: readRequestIdRef.current, workspaceId, ...threadRequest }),
|
|
208
|
+
loadThreadHistory({ workspaceId, ...threadRequest, limit: 20 }).catch(() => undefined),
|
|
204
209
|
]);
|
|
205
210
|
if (!mountedRef.current || sequence !== sequenceRef.current)
|
|
206
211
|
return;
|
|
@@ -261,7 +266,7 @@ export function TeamThreadPage(props) {
|
|
|
261
266
|
return;
|
|
262
267
|
setLoading(true);
|
|
263
268
|
try {
|
|
264
|
-
const result = await loadThreadHistory({ workspaceId,
|
|
269
|
+
const result = await loadThreadHistory({ workspaceId, ...threadRequest, beforeSequence, limit: 20 });
|
|
265
270
|
if (!mountedRef.current)
|
|
266
271
|
return;
|
|
267
272
|
if (!result.ok) {
|
|
@@ -285,6 +290,7 @@ export function TeamThreadPage(props) {
|
|
|
285
290
|
const activeProjection = projection;
|
|
286
291
|
const task = activeProjection?.task;
|
|
287
292
|
const thread = activeProjection?.thread;
|
|
293
|
+
const resolvedTaskNumber = taskNumber ?? channelView?.taskNumbers.find(entry => entry.taskRef === task?.taskRef)?.taskNumber;
|
|
288
294
|
const taskTitle = activeProjection === undefined ? undefined : formatTaskTitle(activeProjection.anchor.body);
|
|
289
295
|
const taskClaims = activeProjection?.claims ?? [];
|
|
290
296
|
const effectiveChannelRef = task?.channelRef ?? channelRef;
|
|
@@ -293,7 +299,7 @@ export function TeamThreadPage(props) {
|
|
|
293
299
|
const mentionHandlesMap = useMemo(() => new Map(members.map(status => [status.member.memberId, status.member.handle.replace(/^@/, '')])), [members]);
|
|
294
300
|
const metadata = useMemo(() => readMeta(readFacts), [readFacts]);
|
|
295
301
|
const unreadIndex = useMemo(() => {
|
|
296
|
-
const all = mergeFacts(
|
|
302
|
+
const all = mergeFacts(...(activeProjection === undefined ? [] : [[messageFact(activeProjection.anchor, activeProjection.anchorMentions)]]), readFacts.map(fact => fact.fact), currentFacts);
|
|
297
303
|
return all.findIndex(fact => metadata.get(factKey(fact))?.unread === true);
|
|
298
304
|
}, [activeProjection?.anchor, readFacts, currentFacts, metadata]);
|
|
299
305
|
const memberName = (memberId) => {
|
|
@@ -312,24 +318,10 @@ export function TeamThreadPage(props) {
|
|
|
312
318
|
selectChannel(ref);
|
|
313
319
|
if (ref.startsWith('task:') && ref !== taskRef) {
|
|
314
320
|
// Another Task cited here: resolve its home Channel and jump.
|
|
315
|
-
|
|
316
|
-
.then(result => {
|
|
317
|
-
if (!result.ok)
|
|
318
|
-
return;
|
|
319
|
-
const hit = result.value.resolved[0];
|
|
320
|
-
if (hit !== undefined)
|
|
321
|
-
selectThread(hit.taskRef, hit.threadRef, hit.channelRef, hit.taskNumber);
|
|
322
|
-
});
|
|
321
|
+
jumpToTaskThread(resolveTaskRefs, workspaceId, ref, selectThread);
|
|
323
322
|
}
|
|
324
323
|
};
|
|
325
|
-
const lookupTaskRefs = (
|
|
326
|
-
.then(result => {
|
|
327
|
-
if (!result.ok)
|
|
328
|
-
return [];
|
|
329
|
-
for (const entry of result.value.resolved)
|
|
330
|
-
rememberResolvedTaskRef(entry);
|
|
331
|
-
return result.value.resolved;
|
|
332
|
-
});
|
|
324
|
+
const lookupTaskRefs = hostTaskRefLookup(resolveTaskRefs, workspaceId);
|
|
333
325
|
const renderFact = (fact, grouped = false) => {
|
|
334
326
|
if (fact.kind === 'message') {
|
|
335
327
|
const sender = memberName(fact.message.sender);
|
|
@@ -384,13 +376,62 @@ export function TeamThreadPage(props) {
|
|
|
384
376
|
await readCurrent(true);
|
|
385
377
|
await refreshSupplemental();
|
|
386
378
|
};
|
|
379
|
+
const convertToTask = async () => {
|
|
380
|
+
if (pending || thread === undefined || task !== undefined)
|
|
381
|
+
return;
|
|
382
|
+
setPending(true);
|
|
383
|
+
setMutating('promote');
|
|
384
|
+
setError(undefined);
|
|
385
|
+
const key = 'promote';
|
|
386
|
+
const requestId = mutationRequests.current.get(key) ?? mintRequestId();
|
|
387
|
+
mutationRequests.current.set(key, requestId);
|
|
388
|
+
try {
|
|
389
|
+
const result = await promoteThread({ requestId, workspaceId, threadRef, baseRevision: thread.revision });
|
|
390
|
+
if (!result.ok) {
|
|
391
|
+
setError(result.error.message);
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
394
|
+
if (result.value.kind === 'committed') {
|
|
395
|
+
mutationRequests.current.delete(key);
|
|
396
|
+
const committed = result.value;
|
|
397
|
+
setProjection(current => current === undefined ? current
|
|
398
|
+
: { ...current, task: committed.task, thread: committed.thread });
|
|
399
|
+
setCurrentFacts(current => {
|
|
400
|
+
const merged = mergeFacts(current, [{ kind: 'activity', sequence: committed.activity.sequence, activity: committed.activity }]);
|
|
401
|
+
currentFactsRef.current = merged;
|
|
402
|
+
return merged;
|
|
403
|
+
});
|
|
404
|
+
await readCurrent(true);
|
|
405
|
+
await refreshSupplemental();
|
|
406
|
+
}
|
|
407
|
+
else if (result.value.kind === 'unread_required') {
|
|
408
|
+
setError(t('unreadRequired', { count: result.value.unreadCount }));
|
|
409
|
+
mutationRequests.current.delete(key);
|
|
410
|
+
await refreshAfterFence();
|
|
411
|
+
}
|
|
412
|
+
else {
|
|
413
|
+
setError(t('staleRevision'));
|
|
414
|
+
mutationRequests.current.delete(key);
|
|
415
|
+
await refreshPassiveFacts();
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
catch (cause) {
|
|
419
|
+
setError(cause instanceof Error ? cause.message : String(cause));
|
|
420
|
+
}
|
|
421
|
+
finally {
|
|
422
|
+
setPending(false);
|
|
423
|
+
setMutating(undefined);
|
|
424
|
+
}
|
|
425
|
+
};
|
|
387
426
|
const mutateTask = async (action) => {
|
|
388
427
|
if (pending || task === undefined || thread === undefined)
|
|
389
428
|
return;
|
|
390
429
|
setPending(true);
|
|
430
|
+
if (action === 'accept')
|
|
431
|
+
setMutating('accept');
|
|
391
432
|
setError(undefined);
|
|
392
433
|
const key = `task:${action}`;
|
|
393
|
-
const requestId = mutationRequests.current.get(key) ??
|
|
434
|
+
const requestId = mutationRequests.current.get(key) ?? mintRequestId();
|
|
394
435
|
mutationRequests.current.set(key, requestId);
|
|
395
436
|
try {
|
|
396
437
|
const result = await changeTask({ requestId, workspaceId, taskRef: task.taskRef, action, baseRevision: thread.revision });
|
|
@@ -426,12 +467,13 @@ export function TeamThreadPage(props) {
|
|
|
426
467
|
}
|
|
427
468
|
finally {
|
|
428
469
|
setPending(false);
|
|
470
|
+
setMutating(undefined);
|
|
429
471
|
}
|
|
430
472
|
};
|
|
431
473
|
const sendReply = async () => {
|
|
432
|
-
if (pending ||
|
|
474
|
+
if (pending || thread === undefined || draft.trim() === '')
|
|
433
475
|
return;
|
|
434
|
-
const id = replyRequestId ??
|
|
476
|
+
const id = replyRequestId ?? mintRequestId();
|
|
435
477
|
setReplyRequestId(id);
|
|
436
478
|
setPending(true);
|
|
437
479
|
setError(undefined);
|
|
@@ -441,7 +483,7 @@ export function TeamThreadPage(props) {
|
|
|
441
483
|
const attachmentIds = [];
|
|
442
484
|
for (const file of pendingFiles) {
|
|
443
485
|
const uploaded = await putAttachment({
|
|
444
|
-
requestId:
|
|
486
|
+
requestId: mintRequestId(),
|
|
445
487
|
workspaceId,
|
|
446
488
|
name: file.name,
|
|
447
489
|
mediaType: file.type === '' ? undefined : file.type,
|
|
@@ -453,7 +495,7 @@ export function TeamThreadPage(props) {
|
|
|
453
495
|
}
|
|
454
496
|
attachmentIds.push(uploaded.value.attachmentId);
|
|
455
497
|
}
|
|
456
|
-
const result = await reply({ requestId: id, workspaceId, taskRef: task.taskRef, body: draft.trim(), baseRevision: thread.revision, recipients: [...recipients].sort(), ...(attachmentIds.length === 0 ? {} : { attachments: attachmentIds }), ...(confirmation === undefined ? {} : { confirmationToken: confirmation }) });
|
|
498
|
+
const result = await reply({ requestId: id, workspaceId, threadRef, ...(task === undefined ? {} : { taskRef: task.taskRef }), body: draft.trim(), baseRevision: thread.revision, recipients: [...recipients].sort(), ...(attachmentIds.length === 0 ? {} : { attachments: attachmentIds }), ...(confirmation === undefined ? {} : { confirmationToken: confirmation }) });
|
|
457
499
|
if (!result.ok) {
|
|
458
500
|
setError(result.error.message);
|
|
459
501
|
return;
|
|
@@ -465,7 +507,7 @@ export function TeamThreadPage(props) {
|
|
|
465
507
|
currentFactsRef.current = merged;
|
|
466
508
|
return merged;
|
|
467
509
|
});
|
|
468
|
-
setProjection(current => current === undefined ? current : { ...current, task: committed.task, thread: committed.thread });
|
|
510
|
+
setProjection(current => current === undefined ? current : { ...current, ...(committed.task === undefined ? {} : { task: committed.task }), thread: committed.thread });
|
|
469
511
|
drafts.clear(draftKey);
|
|
470
512
|
setPendingFiles([]);
|
|
471
513
|
setReplyRequestId(undefined);
|
|
@@ -514,7 +556,7 @@ export function TeamThreadPage(props) {
|
|
|
514
556
|
// Threads are always entered through a Channel page, so a Channel origin
|
|
515
557
|
// returns to its timeline; a Thread restored without one returns further.
|
|
516
558
|
const backLabel = channelRef === undefined ? t('backToWorkspace') : t('backToChannel');
|
|
517
|
-
return _jsxs("main", { className: css.surface, "data-team-thread": threadRef, children: [_jsxs("div", { className: css.surfaceHeader, children: [_jsx("div", { className: css.backRow, children: _jsx(Button, { size: "sm", icon: _jsx(IconChevronLeftOutline14, {}), onClick: backToWorkspace, children: backLabel }) }), _jsxs("header", { className: css.headerRow, children: [_jsxs("div", { className: css.headerCopy, children: [_jsxs("div", { className: threadCss.titleLine, children: [_jsx("h1", { children: task === undefined ? t('
|
|
559
|
+
return _jsxs("main", { className: css.surface, "data-team-thread": threadRef, children: [_jsxs("div", { className: css.surfaceHeader, children: [_jsx("div", { className: css.backRow, children: _jsx(Button, { size: "sm", icon: _jsx(IconChevronLeftOutline14, {}), onClick: backToWorkspace, children: backLabel }) }), _jsxs("header", { className: css.headerRow, children: [_jsxs("div", { className: css.headerCopy, children: [_jsxs("div", { className: threadCss.titleLine, children: [_jsx("h1", { children: task === undefined ? t('threadLabel') : t('taskLabel', { number: resolvedTaskNumber ?? '…' }) }), task !== undefined && _jsx(Pill, { children: formatTaskStatus(task.status, t) })] }), taskTitle !== undefined && taskTitle !== '' && _jsx("p", { className: threadCss.taskTitle, title: taskTitle, children: taskTitle })] }), task === undefined && thread !== undefined && _jsx("div", { className: css.headerActions, children: _jsx(Button, { size: "sm", variant: "primary", disabled: pending, onClick: () => { void convertToTask(); }, children: mutating === 'promote' ? t('promotingTask') : t('promoteToTask') }) }), task !== undefined && thread !== undefined && task.resolution !== 'closed' && _jsxs("div", { className: css.headerActions, children: [(() => {
|
|
518
560
|
const activeClaims = projection?.claims.filter(claim => claim.taskRef === task.taskRef && claim.state === 'active') ?? [];
|
|
519
561
|
const earlyAccept = task.resolution === 'open' && task.status === 'in_progress' && activeClaims.length > 0;
|
|
520
562
|
if (!(task.status === 'in_review' || earlyAccept) || task.resolution !== 'open')
|
|
@@ -531,11 +573,11 @@ export function TeamThreadPage(props) {
|
|
|
531
573
|
// Recomputed here so the confirm list never shows stale rows.
|
|
532
574
|
const activeClaims = projection?.claims.filter(claim => claim.taskRef === task.taskRef && claim.state === 'active') ?? [];
|
|
533
575
|
return _jsxs(Modal, { open: confirmingAccept, onClose: () => { if (!pending)
|
|
534
|
-
setConfirmingAccept(false); }, title: t('acceptEarlyTitle'), closeLabel: t('cancel'), footer: _jsxs(_Fragment, { children: [_jsx(Button, { variant: "outline", disabled: pending, onClick: () => { setConfirmingAccept(false); }, children: t('cancel') }), _jsx(Button, { variant: "primary", disabled: pending, onClick: () => { void mutateTask('accept'); }, children:
|
|
576
|
+
setConfirmingAccept(false); }, title: t('acceptEarlyTitle'), closeLabel: t('cancel'), footer: _jsxs(_Fragment, { children: [_jsx(Button, { variant: "outline", disabled: pending, onClick: () => { setConfirmingAccept(false); }, children: t('cancel') }), _jsx(Button, { variant: "primary", disabled: pending, onClick: () => { void mutateTask('accept'); }, children: mutating === 'accept' ? t('acceptingTask') : t('acceptTask') })] }), children: [_jsx("p", { className: css.confirmBody, children: t('acceptEarlyBody', { count: activeClaims.length }) }), _jsx("ul", { className: css.confirmList, children: activeClaims.map(claim => (_jsxs("li", { children: [memberName(claim.owner), " \u00B7 ", claim.direction] }, claim.claimRef))) })] });
|
|
535
577
|
})(), task !== undefined && thread !== undefined && _jsx("section", { className: threadCss.workSection, "aria-label": t('claims'), children: _jsx(DisclosureRow, { expandOnRowClick: true, expandable: true, open: claimsOpen, onToggle: () => { setClaimsOpen(current => !current); }, icon: _jsx(IconChecklistOutline14, { size: 14 }), title: `${t('claims')} · ${taskClaims.length}`, children: _jsxs("div", { className: threadCss.claimList, children: [taskClaims.length === 0 && _jsx("p", { className: threadCss.emptyClaims, children: t('noClaims') }), taskClaims.map(claim => {
|
|
536
578
|
const ownerStatus = members.find(status => status.member.memberId === claim.owner);
|
|
537
579
|
return _jsxs("article", { className: threadCss.claimRow, children: [ownerStatus === undefined ? _jsx("span", {}) : _jsx(TeamPresenceDot, { status: ownerStatus, t: t }), _jsx("strong", { className: threadCss.claimOwner, children: memberName(claim.owner) }), _jsx("span", { className: threadCss.claimDirection, children: claim.direction }), _jsx("small", { className: threadCss.claimState, children: formatClaimState(claim.state, t) })] }, claim.claimRef);
|
|
538
|
-
})] }) }) })] }), _jsx("section", { ref: timeline.ref, onScroll: timeline.onScroll, className: css.timeline, "aria-label": t('timelineLabel'), children: _jsxs("div", { className: css.timelineContent, children: [loading && projection === undefined && error === undefined && _jsx("div", { className: css.emptySurface, children: _jsxs("p", { className: css.loadingState, children: [_jsx("span", { className: css.loadingMark, "aria-hidden": "true" }), t('loadingThread')] }) }), projection === undefined && error !== undefined && _jsxs("div", { className: css.errorState, role: "alert", children: [_jsx("span", { children: error }), _jsx(Button, { size: "sm", variant: "outline", onClick: () => { void readCurrent(); }, children: t('retry') })] }), olderFacts.length > 0 && _jsxs("section", { className: threadCss.historySection, "aria-label": t('olderHistory'), children: [_jsx("h2", { children: t('olderHistory') }), renderFactBlocks(olderFacts, undefined)] }), historyHasMore && _jsx("div", { className: css.timelineAction, children: _jsx(Button, { size: "sm", onClick: () => { void loadOlder(); }, children: t('loadOlder') }) }), currentFactsWithAnchor.length > 0 && _jsx("section", { className: threadCss.publicSection, children: renderFactBlocks(currentFactsWithAnchor, unreadBoundary) }), newFactsCount > 0 && _jsxs("div", { className: threadCss.newUpdates, role: "status", children: [_jsx("span", { children: t('readNewUpdates', { count: newFactsCount }) }), _jsx(Button, { size: "sm", variant: "outline", disabled: loading, onClick: () => { timeline.jumpToLatest(); void readCurrent(true); }, children: t('markRead') })] }), remainingUnreadCount > 0 && _jsxs("div", { className: css.timelineAction, role: "status", children: [_jsx("span", { children: t('remainingUnread', { count: remainingUnreadCount }) }), _jsx(Button, { size: "sm", onClick: () => { timeline.jumpToBoundary(); void readCurrent(true); }, disabled: loading, children: t('continueReading') })] })] }) }), projection !== undefined &&
|
|
580
|
+
})] }) }) })] }), _jsx("section", { ref: timeline.ref, onScroll: timeline.onScroll, className: css.timeline, "aria-label": t('timelineLabel'), children: _jsxs("div", { className: css.timelineContent, children: [loading && projection === undefined && error === undefined && _jsx("div", { className: css.emptySurface, children: _jsxs("p", { className: css.loadingState, children: [_jsx("span", { className: css.loadingMark, "aria-hidden": "true" }), t('loadingThread')] }) }), projection === undefined && error !== undefined && _jsxs("div", { className: css.errorState, role: "alert", children: [_jsx("span", { children: error }), _jsx(Button, { size: "sm", variant: "outline", onClick: () => { void readCurrent(); }, children: t('retry') })] }), olderFacts.length > 0 && _jsxs("section", { className: threadCss.historySection, "aria-label": t('olderHistory'), children: [_jsx("h2", { children: t('olderHistory') }), renderFactBlocks(olderFacts, undefined)] }), historyHasMore && _jsx("div", { className: css.timelineAction, children: _jsx(Button, { size: "sm", onClick: () => { void loadOlder(); }, children: t('loadOlder') }) }), currentFactsWithAnchor.length > 0 && _jsx("section", { className: threadCss.publicSection, children: renderFactBlocks(currentFactsWithAnchor, unreadBoundary) }), newFactsCount > 0 && _jsxs("div", { className: threadCss.newUpdates, role: "status", children: [_jsx("span", { children: t('readNewUpdates', { count: newFactsCount }) }), _jsx(Button, { size: "sm", variant: "outline", disabled: loading, onClick: () => { timeline.jumpToLatest(); void readCurrent(true); }, children: t('markRead') })] }), remainingUnreadCount > 0 && _jsxs("div", { className: css.timelineAction, role: "status", children: [_jsx("span", { children: t('remainingUnread', { count: remainingUnreadCount }) }), _jsx(Button, { size: "sm", onClick: () => { timeline.jumpToBoundary(); void readCurrent(true); }, disabled: loading, children: t('continueReading') })] })] }) }), projection !== undefined && thread !== undefined ? (task?.resolution === 'closed'
|
|
539
581
|
? _jsxs("div", { className: threadCss.closedBar, "data-team-closed": true, children: [error !== undefined && _jsx("p", { className: css.error, role: "alert", children: error }), _jsxs("div", { className: threadCss.closedNotice, children: [_jsx("span", { children: t('taskClosedNotice') }), _jsx(Button, { size: "sm", variant: "outline", disabled: pending, onClick: () => { void mutateTask('reopen'); }, children: t('reopenTask') })] })] })
|
|
540
|
-
: _jsx(TeamComposer, { members: channelMembers, recipients: recipients, draft: draft, pending: pending, ...(statusMessage === undefined ? {} : { confirmation: statusMessage }), ...(error === undefined ? {} : { error }), onDraftChange: next => { drafts.writeDraft(draftKey, next); setConfirmation(undefined); setReplyRequestId(undefined); setStatusMessage(undefined); }, onRecipientsChange: next => { drafts.writeRecipients(draftKey, next); setConfirmation(undefined); setReplyRequestId(undefined); setStatusMessage(undefined); }, onSubmit: () => { void sendReply(); }, pendingFiles: pendingFiles, onFilesChange: setPendingFiles, t: t }, draftKey)) : _jsx("div", {})] });
|
|
582
|
+
: _jsx(TeamComposer, { members: channelMembers, recipients: recipients, draft: draft, pending: pending, ...(statusMessage === undefined ? {} : { confirmation: statusMessage }), ...(error === undefined ? {} : { error }), onDraftChange: next => { drafts.writeDraft(draftKey, next); setConfirmation(undefined); setReplyRequestId(undefined); setStatusMessage(undefined); }, onRecipientsChange: next => { drafts.writeRecipients(draftKey, next); setConfirmation(undefined); setReplyRequestId(undefined); setStatusMessage(undefined); }, onSubmit: () => { void sendReply(); }, placeholder: t('replyPlaceholder'), pendingFiles: pendingFiles, onFilesChange: setPendingFiles, t: t }, draftKey)) : _jsx("div", {})] });
|
|
541
583
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TeamWorkspaceBrowser.d.ts","sourceRoot":"","sources":["../../../src/client/TeamWorkspaceBrowser.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"TeamWorkspaceBrowser.d.ts","sourceRoot":"","sources":["../../../src/client/TeamWorkspaceBrowser.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AASlD,wBAAgB,oBAAoB,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,UAAU,EAAE,eAAe,EAAE,aAAa,EAAE,CAAC,EAAE,aAAa,EAAE,WAAW,EAAE,gBAAgB,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,mBAAmB,EAAE,UAAU,EAAE,iBAAiB,EAAE,EAAE,gBAAgB,+BA6D/T"}
|
|
@@ -2,6 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { useEffect, useRef, useState, useSyncExternalStore } from 'react';
|
|
3
3
|
import { IconAgentPresetOutline16, IconListPenOutline16, Tooltip } from '@deepseek-ai/dsh-client-ui-primitives';
|
|
4
4
|
import { TeamWorkspaceRow } from "./TeamWorkspaceRow.js";
|
|
5
|
+
import { TeamSidebarSection } from "./TeamSidebarSection.js";
|
|
5
6
|
import { TeamAgentsPanel } from "./TeamAgentsPanel.js";
|
|
6
7
|
import { TeamChannelsPanel } from "./TeamChannelsPanel.js";
|
|
7
8
|
import css from './sidebar.module.css';
|
|
@@ -36,5 +37,5 @@ export function TeamWorkspaceBrowser({ wide, expandSidebar, navigation, selectWo
|
|
|
36
37
|
if (!wide) {
|
|
37
38
|
return _jsxs("nav", { className: css.railWorkspace, "aria-label": t('workspaceSections'), children: [_jsx(Tooltip, { label: t('channels'), side: "right", children: _jsx("button", { type: "button", className: css.railButton, "aria-label": t('channels'), onClick: () => { setPendingSection('channels'); expandSidebar(); }, children: _jsx(IconListPenOutline16, { size: 16 }) }) }), _jsx(Tooltip, { label: t('agents'), side: "right", children: _jsx("button", { type: "button", className: css.railButton, "aria-label": t('agents'), onClick: () => { setPendingSection('agents'); expandSidebar(); }, children: _jsx(IconAgentPresetOutline16, { size: 16 }) }) })] });
|
|
38
39
|
}
|
|
39
|
-
return _jsxs("section", { className: css.workspaceBrowser, "aria-label": t('workspaces'), children: [_jsx(
|
|
40
|
+
return _jsxs("section", { className: css.workspaceBrowser, "aria-label": t('workspaces'), children: [_jsx(TeamSidebarSection, { title: t('workspaces'), children: _jsxs("div", { className: css.workspaceList, children: [workspaces.map(workspace => _jsx(TeamWorkspaceRow, { workspaceId: workspace.workspaceId, title: workspace.title, path: workspace.path, selected: workspace.workspaceId === selectedId, current: workspace.workspaceId === selectedId && overviewIsCurrent, onSelect: selectWorkspace }, workspace.workspaceId)), workspaces.length === 0 && _jsx("p", { className: css.emptyState, children: t('empty') })] }) }), selectedId !== undefined && _jsxs("div", { className: css.workspaceSection, children: [_jsx("div", { ref: channelsRef, children: _jsx(TeamChannelsPanel, { workspaceId: selectedId, loadMembers: loadMembers, loadChannels: loadChannels, subscribeChanges: subscribeChanges, createChannel: createChannel, updateChannel: updateChannel, joinChannel: joinChannel, removeChannelMember: removeChannelMember, creatingAgents: creatingAgents.filter(request => request.workspaceId === selectedId), ...(navigationState.memberSessionId !== undefined || navigationState.channelRef === undefined ? {} : { selectedChannelRef: navigationState.channelRef }), selectChannel: selectChannel, t: t }, selectedId) }), _jsx("div", { ref: agentsRef, children: _jsx(TeamAgentsPanel, { workspaceId: selectedId, loadMembers: loadMembers, subscribeChanges: subscribeChanges, loadChannels: loadChannels, addMember: addMember, updateMember: updateMember, recoverMember: recoverMember, joinChannel: joinChannel, removeChannelMember: removeChannelMember, loadModels: loadModels, ...(navigationState.memberSessionId === undefined ? {} : { memberSessionId: navigationState.memberSessionId }), openMemberSession: openMemberSession, onCreatingChange: (request, creating) => { setCreatingAgents(current => creating ? [...current.filter(item => item.requestId !== request.requestId), request] : current.filter(item => item.requestId !== request.requestId)); }, t: t }, selectedId) })] })] });
|
|
40
41
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAa,MAAM,wCAAwC,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAa,MAAM,wCAAwC,CAAA;AAgCtF,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAEhD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAO5C,OAAO,EAAU,KAAK,OAAO,EAAE,MAAM,cAAc,CAAA;AAEnD,YAAY,EAAE,QAAQ,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAA;AAC9F,YAAY,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAC3C,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAIhD,eAAO,MAAM,MAAM,UAElB,CAAA;AAED,OAAO,QAAQ,kCAAkC,CAAC;IAChD,UAAU,kBAAkB;QAC1B,IAAI,EAAE,OAAO,CAAA;KACd;CACF;AAED,OAAO,QAAQ,qBAAqB,CAAC;IACnC,UAAU,OAAO;QACf,cAAc,EAAE,cAAc,CAAA;QAC9B,UAAU,EAAE,cAAc,CAAA;KAC3B;CACF;AAwND,wBAAsB,KAAK,CAAC,GAAG,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAI7D"}
|
|
@@ -6,11 +6,13 @@ import { TeamFooterAction } from "./TeamFooterAction.js";
|
|
|
6
6
|
import { TeamSettings } from "./TeamSettings.js";
|
|
7
7
|
import { TeamConversation } from "./TeamConversation.js";
|
|
8
8
|
import { TeamWorkspaceBrowser } from "./TeamWorkspaceBrowser.js";
|
|
9
|
+
import { TeamMemberSessionComposer } from "./TeamMemberSessionComposer.js";
|
|
10
|
+
import { admitTeamCompact, createTeamMemberSessionSources } from "./member-session-input.js";
|
|
9
11
|
import { en, zh } from "./locales.js";
|
|
10
12
|
export { TeamNavigation } from "./navigation.js";
|
|
11
13
|
const NS = 'team';
|
|
12
14
|
export const inject = [
|
|
13
|
-
'slots', 'workspaces', 'locale', 'remote', 'sessions', 'connection',
|
|
15
|
+
'slots', 'workspaces', 'locale', 'remote', 'sessions', 'connection', 'conversation', 'inputTriggers',
|
|
14
16
|
];
|
|
15
17
|
function registerModeShadow(ctx, navigation, changes, drafts, name, component, extraInject) {
|
|
16
18
|
// Remote bindings shared by every Team slot; surface-specific entries extend it below.
|
|
@@ -70,6 +72,7 @@ function registerModeShadow(ctx, navigation, changes, drafts, name, component, e
|
|
|
70
72
|
getAttachment: (request) => ctx.remote.agentTeam.getAttachment(request),
|
|
71
73
|
reply: (request) => ctx.remote.agentTeam.reply(request),
|
|
72
74
|
changeTask: (request) => ctx.remote.agentTeam.changeTask(request),
|
|
75
|
+
promoteThread: (request) => ctx.remote.agentTeam.promoteThread(request),
|
|
73
76
|
resolveTaskRefs: (request) => ctx.remote.agentTeam.resolveTaskRefs(request),
|
|
74
77
|
} : {}),
|
|
75
78
|
...(name === 'sidebar.workspaces' ? {
|
|
@@ -93,6 +96,49 @@ function registerModeShadow(ctx, navigation, changes, drafts, name, component, e
|
|
|
93
96
|
};
|
|
94
97
|
});
|
|
95
98
|
}
|
|
99
|
+
function registerMemberSessionComposer(ctx, navigation) {
|
|
100
|
+
ctx.slots.inject('conversation.composer.bar', () => {
|
|
101
|
+
let dispose;
|
|
102
|
+
let registeredSessionId;
|
|
103
|
+
const reconcile = () => {
|
|
104
|
+
const memberSessionId = navigation.getSnapshot().memberSessionId;
|
|
105
|
+
const active = navigation.getSnapshot().mode === 'team' && memberSessionId !== undefined;
|
|
106
|
+
if (dispose !== undefined && (!active || registeredSessionId !== memberSessionId)) {
|
|
107
|
+
dispose();
|
|
108
|
+
dispose = undefined;
|
|
109
|
+
registeredSessionId = undefined;
|
|
110
|
+
}
|
|
111
|
+
if (active && dispose === undefined) {
|
|
112
|
+
registeredSessionId = memberSessionId;
|
|
113
|
+
dispose = ctx.slots.register({
|
|
114
|
+
name: 'conversation.composer.bar',
|
|
115
|
+
priority: -100,
|
|
116
|
+
// The registration may remain live during a session transition, but
|
|
117
|
+
// it elects only when the shell's current Session is the embedded
|
|
118
|
+
// Member. This avoids taking an ordinary Session if selection races.
|
|
119
|
+
select: () => ctx.sessions.list.getSnapshot().current === memberSessionId ? {} : null,
|
|
120
|
+
inject: (sessionId) => {
|
|
121
|
+
const actx = ctx.sessions.scope(sessionId);
|
|
122
|
+
if (actx === undefined)
|
|
123
|
+
throw new Error(`agent-team: Member session ${String(sessionId)} has no client scope`);
|
|
124
|
+
const sessions = ctx.sessions;
|
|
125
|
+
return {
|
|
126
|
+
controller: ctx.get('inputTriggers').sessionOf(actx),
|
|
127
|
+
stop: () => { void sessions.sessionOf(actx)?.cancel(); },
|
|
128
|
+
submitInput: (mode) => ctx.conversation.input.for(actx).submit(mode),
|
|
129
|
+
};
|
|
130
|
+
},
|
|
131
|
+
}, TeamMemberSessionComposer);
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
const offNavigation = navigation.subscribe(reconcile);
|
|
135
|
+
reconcile();
|
|
136
|
+
return () => {
|
|
137
|
+
offNavigation();
|
|
138
|
+
dispose?.();
|
|
139
|
+
};
|
|
140
|
+
});
|
|
141
|
+
}
|
|
96
142
|
function applyUi(ctx) {
|
|
97
143
|
ctx.effect(() => ctx.locale.register(NS, { zh, en }), 'agent-team: dictionaries');
|
|
98
144
|
const navigation = new TeamNavigation();
|
|
@@ -106,6 +152,30 @@ function applyUi(ctx) {
|
|
|
106
152
|
void disposeDrafts();
|
|
107
153
|
}, 'agent-team: navigation service');
|
|
108
154
|
const changes = new TeamChangeStream((request, signal) => ctx.remote.agentTeam.changes(request, signal));
|
|
155
|
+
const triggerSources = createTeamMemberSessionSources({
|
|
156
|
+
isEmbeddedMemberSession: sessionId => {
|
|
157
|
+
const snapshot = navigation.getSnapshot();
|
|
158
|
+
return snapshot.mode === 'team' && snapshot.memberSessionId === sessionId && snapshot.workspaceId !== undefined;
|
|
159
|
+
},
|
|
160
|
+
members: async () => {
|
|
161
|
+
const workspaceId = navigation.getSnapshot().workspaceId;
|
|
162
|
+
if (workspaceId === undefined)
|
|
163
|
+
return [];
|
|
164
|
+
const result = await ctx.remote.agentTeam.members({ workspaceId });
|
|
165
|
+
return result.ok ? result.value : [];
|
|
166
|
+
},
|
|
167
|
+
executeCompact: async (sessionId) => {
|
|
168
|
+
const actx = ctx.sessions.scope(sessionId);
|
|
169
|
+
const session = actx === undefined ? undefined : ctx.sessions.sessionOf(actx);
|
|
170
|
+
return session === undefined ? { kind: 'error', text: 'current Member Session is unavailable' } : admitTeamCompact(session);
|
|
171
|
+
},
|
|
172
|
+
});
|
|
173
|
+
const inputTriggers = ctx.get('inputTriggers');
|
|
174
|
+
ctx.effect(() => {
|
|
175
|
+
const disposers = triggerSources.map(source => inputTriggers.registerSource(source));
|
|
176
|
+
return () => { for (const dispose of disposers)
|
|
177
|
+
dispose(); };
|
|
178
|
+
}, 'agent-team: Member session trigger sources');
|
|
109
179
|
const loadMemberGroups = async () => {
|
|
110
180
|
const workspaces = ctx.workspaces.list.getSnapshot().items;
|
|
111
181
|
const groups = await Promise.all(workspaces.map(async (workspace) => {
|
|
@@ -144,6 +214,7 @@ function applyUi(ctx) {
|
|
|
144
214
|
}, TeamFooterAction));
|
|
145
215
|
registerModeShadow(ctx, navigation, changes, drafts, 'sidebar.workspaces', TeamWorkspaceBrowser);
|
|
146
216
|
registerModeShadow(ctx, navigation, changes, drafts, 'conversation', TeamConversation);
|
|
217
|
+
registerMemberSessionComposer(ctx, navigation);
|
|
147
218
|
registerModeShadow(ctx, navigation, changes, drafts, 'sidebar.settings', TeamSettings, () => ({ loadMemberGroups }));
|
|
148
219
|
}
|
|
149
220
|
export async function apply(ctx) {
|
|
@@ -37,6 +37,9 @@ export declare const zh: {
|
|
|
37
37
|
readonly editChannel: "编辑频道";
|
|
38
38
|
readonly editAgent: "编辑 Agent";
|
|
39
39
|
readonly resumeAgent: "恢复";
|
|
40
|
+
readonly restartAgent: "重启";
|
|
41
|
+
readonly restartStillUnavailable: "重启已执行,成员仍不可用:{diagnostic}";
|
|
42
|
+
readonly restartFailed: "重启执行失败:{message}";
|
|
40
43
|
readonly optionalSuffix: "(可选)";
|
|
41
44
|
readonly agentDescriptionPlaceholder: "留空则暂无描述";
|
|
42
45
|
readonly channelsPickerEmpty: "选择初始频道";
|
|
@@ -49,6 +52,8 @@ export declare const zh: {
|
|
|
49
52
|
readonly removeFile: "移除 {name}";
|
|
50
53
|
readonly attachmentExpired: "文件已过期清理";
|
|
51
54
|
readonly viewImage: "查看大图 {name}";
|
|
55
|
+
readonly expandMessage: "展开全文";
|
|
56
|
+
readonly collapseMessage: "收起";
|
|
52
57
|
readonly actionsChannel: "{name} 的操作";
|
|
53
58
|
readonly actionsAgent: "{name} 的操作";
|
|
54
59
|
readonly editSave: "保存";
|
|
@@ -81,10 +86,16 @@ export declare const zh: {
|
|
|
81
86
|
readonly taskLabel: "Task #{number}";
|
|
82
87
|
readonly taskPending: "Task …";
|
|
83
88
|
readonly openTask: "打开 Task #{number}";
|
|
89
|
+
readonly openThread: "打开讨论";
|
|
90
|
+
readonly threadLabel: "讨论";
|
|
91
|
+
readonly asTask: "作为任务";
|
|
92
|
+
readonly promoteToTask: "转为 Task";
|
|
93
|
+
readonly promotingTask: "正在转为 Task…";
|
|
84
94
|
readonly mentionSuggestions: "提及成员建议";
|
|
85
95
|
readonly messageDraft: "消息内容";
|
|
86
96
|
readonly composerNotify: "将通知:{ids}";
|
|
87
97
|
readonly messagePlaceholder: "写一条消息…";
|
|
98
|
+
readonly replyPlaceholder: "回复此 Thread…";
|
|
88
99
|
readonly sendMessage: "发送";
|
|
89
100
|
readonly sendingMessage: "发送中…";
|
|
90
101
|
readonly loadOlder: "加载更早消息";
|
|
@@ -115,6 +126,7 @@ export declare const zh: {
|
|
|
115
126
|
readonly activityClaimsReleased: "{actor} 因成员权限变化释放了 {count} 个 Claim";
|
|
116
127
|
readonly activityAccepted: "{actor} 验收了此 Task";
|
|
117
128
|
readonly activityAcceptedWithClaims: "{actor} 验收了此 Task,并一并完成了 {count} 个未完成 Claim";
|
|
129
|
+
readonly activityPromoted: "{actor} 为此讨论创建了 Task";
|
|
118
130
|
readonly acceptEarlyTitle: "提前验收任务";
|
|
119
131
|
readonly acceptEarlyBody: "将验收本 Task,并把以下 {count} 个未完成的 Claim 一并标记为完成:";
|
|
120
132
|
readonly acceptingTask: "验收中…";
|
|
@@ -165,6 +177,9 @@ export declare const en: {
|
|
|
165
177
|
readonly editChannel: "Edit Channel";
|
|
166
178
|
readonly editAgent: "Edit Agent";
|
|
167
179
|
readonly resumeAgent: "Resume";
|
|
180
|
+
readonly restartAgent: "Restart";
|
|
181
|
+
readonly restartStillUnavailable: "Restart ran, but the Member is still unavailable: {diagnostic}";
|
|
182
|
+
readonly restartFailed: "Restart failed: {message}";
|
|
168
183
|
readonly optionalSuffix: " (optional)";
|
|
169
184
|
readonly agentDescriptionPlaceholder: "Leave empty if not needed";
|
|
170
185
|
readonly channelsPickerEmpty: "Choose initial channels";
|
|
@@ -177,6 +192,8 @@ export declare const en: {
|
|
|
177
192
|
readonly removeFile: "Remove {name}";
|
|
178
193
|
readonly attachmentExpired: "File expired and cleaned up";
|
|
179
194
|
readonly viewImage: "View image {name}";
|
|
195
|
+
readonly expandMessage: "Show more";
|
|
196
|
+
readonly collapseMessage: "Show less";
|
|
180
197
|
readonly actionsChannel: "{name} actions";
|
|
181
198
|
readonly actionsAgent: "{name} actions";
|
|
182
199
|
readonly editSave: "Save";
|
|
@@ -209,10 +226,16 @@ export declare const en: {
|
|
|
209
226
|
readonly taskLabel: "Task #{number}";
|
|
210
227
|
readonly taskPending: "Task …";
|
|
211
228
|
readonly openTask: "Open Task #{number}";
|
|
229
|
+
readonly openThread: "Open thread";
|
|
230
|
+
readonly threadLabel: "Thread";
|
|
231
|
+
readonly asTask: "As task";
|
|
232
|
+
readonly promoteToTask: "Convert to Task";
|
|
233
|
+
readonly promotingTask: "Converting to Task…";
|
|
212
234
|
readonly mentionSuggestions: "Mention suggestions";
|
|
213
235
|
readonly messageDraft: "Message";
|
|
214
236
|
readonly composerNotify: "Will notify: {ids}";
|
|
215
237
|
readonly messagePlaceholder: "Write a message…";
|
|
238
|
+
readonly replyPlaceholder: "Reply on this Thread…";
|
|
216
239
|
readonly sendMessage: "Send";
|
|
217
240
|
readonly sendingMessage: "Sending…";
|
|
218
241
|
readonly loadOlder: "Load older messages";
|
|
@@ -243,6 +266,7 @@ export declare const en: {
|
|
|
243
266
|
readonly activityClaimsReleased: "{actor} released {count} Claim(s) after a membership change";
|
|
244
267
|
readonly activityAccepted: "{actor} accepted this Task";
|
|
245
268
|
readonly activityAcceptedWithClaims: "{actor} accepted this Task and completed {count} unfinished Claims with it";
|
|
269
|
+
readonly activityPromoted: "{actor} created a Task for this Thread";
|
|
246
270
|
readonly acceptEarlyTitle: "Accept Task early";
|
|
247
271
|
readonly acceptEarlyBody: "This accepts the Task and marks the following {count} unfinished Claims as done:";
|
|
248
272
|
readonly acceptingTask: "Accepting…";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"locales.d.ts","sourceRoot":"","sources":["../../../src/client/locales.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,EAAE
|
|
1
|
+
{"version":3,"file":"locales.d.ts","sourceRoot":"","sources":["../../../src/client/locales.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2IL,CAAA;AAEV,eAAO,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2IL,CAAA;AAEV,MAAM,MAAM,OAAO,GAAG,MAAM,OAAO,EAAE,CAAA"}
|
|
@@ -37,6 +37,9 @@ export const zh = {
|
|
|
37
37
|
editChannel: '编辑频道',
|
|
38
38
|
editAgent: '编辑 Agent',
|
|
39
39
|
resumeAgent: '恢复',
|
|
40
|
+
restartAgent: '重启',
|
|
41
|
+
restartStillUnavailable: '重启已执行,成员仍不可用:{diagnostic}',
|
|
42
|
+
restartFailed: '重启执行失败:{message}',
|
|
40
43
|
optionalSuffix: '(可选)',
|
|
41
44
|
agentDescriptionPlaceholder: '留空则暂无描述',
|
|
42
45
|
channelsPickerEmpty: '选择初始频道',
|
|
@@ -49,6 +52,8 @@ export const zh = {
|
|
|
49
52
|
removeFile: '移除 {name}',
|
|
50
53
|
attachmentExpired: '文件已过期清理',
|
|
51
54
|
viewImage: '查看大图 {name}',
|
|
55
|
+
expandMessage: '展开全文',
|
|
56
|
+
collapseMessage: '收起',
|
|
52
57
|
actionsChannel: '{name} 的操作',
|
|
53
58
|
actionsAgent: '{name} 的操作',
|
|
54
59
|
editSave: '保存',
|
|
@@ -81,10 +86,16 @@ export const zh = {
|
|
|
81
86
|
taskLabel: 'Task #{number}',
|
|
82
87
|
taskPending: 'Task …',
|
|
83
88
|
openTask: '打开 Task #{number}',
|
|
89
|
+
openThread: '打开讨论',
|
|
90
|
+
threadLabel: '讨论',
|
|
91
|
+
asTask: '作为任务',
|
|
92
|
+
promoteToTask: '转为 Task',
|
|
93
|
+
promotingTask: '正在转为 Task…',
|
|
84
94
|
mentionSuggestions: '提及成员建议',
|
|
85
95
|
messageDraft: '消息内容',
|
|
86
96
|
composerNotify: '将通知:{ids}',
|
|
87
97
|
messagePlaceholder: '写一条消息…',
|
|
98
|
+
replyPlaceholder: '回复此 Thread…',
|
|
88
99
|
sendMessage: '发送',
|
|
89
100
|
sendingMessage: '发送中…',
|
|
90
101
|
loadOlder: '加载更早消息',
|
|
@@ -115,6 +126,7 @@ export const zh = {
|
|
|
115
126
|
activityClaimsReleased: '{actor} 因成员权限变化释放了 {count} 个 Claim',
|
|
116
127
|
activityAccepted: '{actor} 验收了此 Task',
|
|
117
128
|
activityAcceptedWithClaims: '{actor} 验收了此 Task,并一并完成了 {count} 个未完成 Claim',
|
|
129
|
+
activityPromoted: '{actor} 为此讨论创建了 Task',
|
|
118
130
|
acceptEarlyTitle: '提前验收任务',
|
|
119
131
|
acceptEarlyBody: '将验收本 Task,并把以下 {count} 个未完成的 Claim 一并标记为完成:',
|
|
120
132
|
acceptingTask: '验收中…',
|
|
@@ -165,6 +177,9 @@ export const en = {
|
|
|
165
177
|
editChannel: 'Edit Channel',
|
|
166
178
|
editAgent: 'Edit Agent',
|
|
167
179
|
resumeAgent: 'Resume',
|
|
180
|
+
restartAgent: 'Restart',
|
|
181
|
+
restartStillUnavailable: 'Restart ran, but the Member is still unavailable: {diagnostic}',
|
|
182
|
+
restartFailed: 'Restart failed: {message}',
|
|
168
183
|
optionalSuffix: ' (optional)',
|
|
169
184
|
agentDescriptionPlaceholder: 'Leave empty if not needed',
|
|
170
185
|
channelsPickerEmpty: 'Choose initial channels',
|
|
@@ -177,6 +192,8 @@ export const en = {
|
|
|
177
192
|
removeFile: 'Remove {name}',
|
|
178
193
|
attachmentExpired: 'File expired and cleaned up',
|
|
179
194
|
viewImage: 'View image {name}',
|
|
195
|
+
expandMessage: 'Show more',
|
|
196
|
+
collapseMessage: 'Show less',
|
|
180
197
|
actionsChannel: '{name} actions',
|
|
181
198
|
actionsAgent: '{name} actions',
|
|
182
199
|
editSave: 'Save',
|
|
@@ -209,10 +226,16 @@ export const en = {
|
|
|
209
226
|
taskLabel: 'Task #{number}',
|
|
210
227
|
taskPending: 'Task …',
|
|
211
228
|
openTask: 'Open Task #{number}',
|
|
229
|
+
openThread: 'Open thread',
|
|
230
|
+
threadLabel: 'Thread',
|
|
231
|
+
asTask: 'As task',
|
|
232
|
+
promoteToTask: 'Convert to Task',
|
|
233
|
+
promotingTask: 'Converting to Task…',
|
|
212
234
|
mentionSuggestions: 'Mention suggestions',
|
|
213
235
|
messageDraft: 'Message',
|
|
214
236
|
composerNotify: 'Will notify: {ids}',
|
|
215
237
|
messagePlaceholder: 'Write a message…',
|
|
238
|
+
replyPlaceholder: 'Reply on this Thread…',
|
|
216
239
|
sendMessage: 'Send',
|
|
217
240
|
sendingMessage: 'Sending…',
|
|
218
241
|
loadOlder: 'Load older messages',
|
|
@@ -243,6 +266,7 @@ export const en = {
|
|
|
243
266
|
activityClaimsReleased: '{actor} released {count} Claim(s) after a membership change',
|
|
244
267
|
activityAccepted: '{actor} accepted this Task',
|
|
245
268
|
activityAcceptedWithClaims: '{actor} accepted this Task and completed {count} unfinished Claims with it',
|
|
269
|
+
activityPromoted: '{actor} created a Task for this Thread',
|
|
246
270
|
acceptEarlyTitle: 'Accept Task early',
|
|
247
271
|
acceptEarlyBody: 'This accepts the Task and marks the following {count} unfinished Claims as done:',
|
|
248
272
|
acceptingTask: 'Accepting…',
|