@wowyuarm/dsh-agent-team 0.1.2 → 0.1.3
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 +1 -0
- package/README.zh.md +2 -0
- package/package.json +12 -3
- package/packages/agent-team/README.md +1 -1
- package/packages/agent-team/README.zh.md +1 -1
- 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 +214 -130
- package/packages/agent-team/lib/ledger.js +77 -70
- package/packages/agent-team/lib/recovery.js +30 -35
- package/packages/agent-team/lib/typert.host.js +33 -23
- package/packages/agent-team/lib/typert.remote-client.d.ts.map +1 -1
- package/packages/agent-team/lib/typert.remote-client.js +21 -21
- 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 +40 -12
- package/packages/agent-team/lib/types/index.d.ts.map +1 -1
- package/packages/agent-team/lib/types/ledger.d.ts +13 -0
- 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/preset/team-member/agent.cordis.yml +6 -1
- package/packages/client-agent-team/README.md +1 -1
- package/packages/client-agent-team/README.zh.md +1 -1
- package/packages/client-agent-team/lib/client.js +942 -534
- 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 +5 -166
- package/packages/client-agent-team/lib/types/client/TeamChannelPage.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamChannelPage.js +6 -20
- 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.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamComposer.js +0 -1
- 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.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamMessage.js +83 -43
- package/packages/client-agent-team/lib/types/client/TeamThreadPage.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamThreadPage.js +10 -23
- package/packages/client-agent-team/lib/types/client/index.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/index.js +71 -1
- 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/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.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 +43 -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 +61 -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/lib/index.js +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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TeamAgentsPanel.d.ts","sourceRoot":"","sources":["../../../src/client/TeamAgentsPanel.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,yBAAyB,EACzB,2BAA2B,
|
|
1
|
+
{"version":3,"file":"TeamAgentsPanel.d.ts","sourceRoot":"","sources":["../../../src/client/TeamAgentsPanel.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,yBAAyB,EACzB,2BAA2B,EAG5B,MAAM,gCAAgC,CAAA;AACvC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wCAAwC,CAAA;AAEzE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAYlD,UAAU,oBAAoB;IAC5B,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAA;IACjC,QAAQ,CAAC,WAAW,EAAE,gBAAgB,CAAC,aAAa,CAAC,CAAA;IACrD,QAAQ,CAAC,gBAAgB,EAAE,gBAAgB,CAAC,kBAAkB,CAAC,CAAA;IAC/D,QAAQ,CAAC,YAAY,EAAE,gBAAgB,CAAC,cAAc,CAAC,CAAA;IACvD,QAAQ,CAAC,SAAS,EAAE,gBAAgB,CAAC,WAAW,CAAC,CAAA;IACjD,QAAQ,CAAC,YAAY,EAAE,gBAAgB,CAAC,cAAc,CAAC,CAAA;IACvD,QAAQ,CAAC,aAAa,EAAE,gBAAgB,CAAC,eAAe,CAAC,CAAA;IACzD,QAAQ,CAAC,WAAW,EAAE,gBAAgB,CAAC,aAAa,CAAC,CAAA;IACrD,QAAQ,CAAC,mBAAmB,EAAE,gBAAgB,CAAC,qBAAqB,CAAC,CAAA;IACrE,QAAQ,CAAC,UAAU,EAAE,gBAAgB,CAAC,YAAY,CAAC,CAAA;IACnD,8EAA8E;IAC9E,QAAQ,CAAC,eAAe,CAAC,EAAE,2BAA2B,CAAC,QAAQ,CAAC,CAAC,WAAW,CAAC,CAAA;IAC7E,QAAQ,CAAC,iBAAiB,EAAE,gBAAgB,CAAC,mBAAmB,CAAC,CAAA;IACjE,QAAQ,CAAC,gBAAgB,EAAE,CAAC,OAAO,EAAE,yBAAyB,EAAE,QAAQ,EAAE,OAAO,KAAK,IAAI,CAAA;IAC1F,QAAQ,CAAC,CAAC,EAAE,gBAAgB,CAAC,GAAG,CAAC,CAAA;CAClC;AAED,wBAAgB,eAAe,CAAC,EAAE,WAAW,EAAE,WAAW,EAAE,gBAAgB,EAAE,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,mBAAmB,EAAE,UAAU,EAAE,eAAe,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,CAAC,EAAE,EAAE,oBAAoB,+BAiLhQ"}
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
3
|
-
import { Button,
|
|
3
|
+
import { Button, IconEditOutline16, IconPlayOutline16, IconPlusOutline16, Input, Modal, Tooltip } from '@deepseek-ai/dsh-client-ui-primitives';
|
|
4
4
|
import { TeamMemberAvatar } from "./TeamMemberAvatar.js";
|
|
5
5
|
import { SortableRow, useSidebarRowDrag } from "./sidebar-drag.js";
|
|
6
6
|
import { moveSidebarItem, useSidebarOrder } from "./sidebar-order.js";
|
|
7
|
+
import { mintRequestId } from "./requests.js";
|
|
7
8
|
import { TeamRowMenu } from "./TeamRowMenu.js";
|
|
8
9
|
import { TeamSidebarSection } from "./TeamSidebarSection.js";
|
|
9
10
|
import { MultiMenuField } from "./multi-menu-field.js";
|
|
10
|
-
import {
|
|
11
|
+
import { AgentEditorDialog, ModelPickerField, sameModel } from "./TeamMemberEditor.js";
|
|
11
12
|
import createCss from './create.module.css';
|
|
12
13
|
import css from './sidebar.module.css';
|
|
13
14
|
export function TeamAgentsPanel({ workspaceId, loadMembers, subscribeChanges, loadChannels, addMember, updateMember, recoverMember, joinChannel, removeChannelMember, loadModels, memberSessionId, openMemberSession, onCreatingChange, t }) {
|
|
@@ -119,7 +120,7 @@ export function TeamAgentsPanel({ workspaceId, loadMembers, subscribeChanges, lo
|
|
|
119
120
|
&& sameModel(retryRequest.model, model)
|
|
120
121
|
&& retryRequest.channelRefs.length === channelRefs.length && retryRequest.channelRefs.every(ref => channelRefs.includes(ref));
|
|
121
122
|
void provision(sameRequest ? retryRequest : {
|
|
122
|
-
requestId:
|
|
123
|
+
requestId: mintRequestId(),
|
|
123
124
|
workspaceId,
|
|
124
125
|
handle: normalizedHandle,
|
|
125
126
|
description: normalizedDescription,
|
|
@@ -143,7 +144,7 @@ function AgentRow({ status, current, channels, loadChannels, updateMember, recov
|
|
|
143
144
|
const [editing, setEditing] = useState(false);
|
|
144
145
|
const resume = async () => {
|
|
145
146
|
await recoverMember({
|
|
146
|
-
requestId:
|
|
147
|
+
requestId: mintRequestId(),
|
|
147
148
|
workspaceId: status.member.workspaceId,
|
|
148
149
|
memberId: status.member.memberId,
|
|
149
150
|
});
|
|
@@ -159,165 +160,3 @@ function AgentRow({ status, current, channels, loadChannels, updateMember, recov
|
|
|
159
160
|
setEditing(true);
|
|
160
161
|
}, onOpenChange: setMenuOpen }) })] }), editing && (_jsx(AgentEditorDialog, { status: status, channels: channels, loadChannels: loadChannels, updateMember: updateMember, joinChannel: joinChannel, removeChannelMember: removeChannelMember, loadModels: loadModels, onCommitted: onUpdated, onClose: () => { setEditing(false); }, t: t }))] }));
|
|
161
162
|
}
|
|
162
|
-
/** Model option key inside one editor; opaque and resolved against the loaded groups. */
|
|
163
|
-
function modelKey(provider, model) {
|
|
164
|
-
return `${provider}\u0000${model}`;
|
|
165
|
-
}
|
|
166
|
-
/**
|
|
167
|
-
* Shared provider/model dropdown for the create and edit forms. The option
|
|
168
|
-
* list rides the shared Menu primitive (one leading "follow Host default"
|
|
169
|
-
* row, then non-selectable provider headings) with a capped, internally
|
|
170
|
-
* scrolling card so growing model catalogs cannot stretch the dialog.
|
|
171
|
-
*/
|
|
172
|
-
function ModelPickerField({ model, onModelChange, loadModels, disabled, t }) {
|
|
173
|
-
const [groups, setGroups] = useState();
|
|
174
|
-
const [modelsError, setModelsError] = useState();
|
|
175
|
-
const [open, setModelOpen] = useState(false);
|
|
176
|
-
const [effortOpen, setEffortOpen] = useState(false);
|
|
177
|
-
useEffect(() => {
|
|
178
|
-
let mounted = true;
|
|
179
|
-
void loadModels().then(result => {
|
|
180
|
-
if (!mounted)
|
|
181
|
-
return;
|
|
182
|
-
if (result.ok) {
|
|
183
|
-
setGroups(result.value.groups);
|
|
184
|
-
setModelsError(undefined);
|
|
185
|
-
}
|
|
186
|
-
else {
|
|
187
|
-
setModelsError(result.error.message);
|
|
188
|
-
}
|
|
189
|
-
});
|
|
190
|
-
return () => { mounted = false; };
|
|
191
|
-
}, [loadModels]);
|
|
192
|
-
const items = [{ id: '', label: t('modelFollowDefault') }];
|
|
193
|
-
const byKey = new Map();
|
|
194
|
-
for (const group of groups ?? []) {
|
|
195
|
-
items.push({ type: 'label', id: `model-group:${group.id}`, text: group.name });
|
|
196
|
-
for (const entry of group.models) {
|
|
197
|
-
const key = modelKey(group.id, entry.id);
|
|
198
|
-
byKey.set(key, { provider: group.id, id: entry.id, name: entry.name, efforts: entry.reasoning?.efforts ?? [] });
|
|
199
|
-
items.push({ id: key, label: entry.name });
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
const selectedModelKey = model === undefined ? '' : modelKey(model.provider, model.model);
|
|
203
|
-
const triggerLabel = model === undefined
|
|
204
|
-
? t('modelFollowDefault')
|
|
205
|
-
: byKey.get(selectedModelKey)?.name ?? `${model.provider} / ${model.model}`;
|
|
206
|
-
// The effort sub-row only makes sense for a pinned model with adapter-exposed
|
|
207
|
-
// efforts; following the Host default inherits the operator's whole selection.
|
|
208
|
-
const efforts = model === undefined ? [] : byKey.get(selectedModelKey)?.efforts ?? [];
|
|
209
|
-
const effortItems = [{ id: '', label: t('effortFollowDefault') }, ...efforts.map(effort => ({ id: effort.id, label: effort.name }))];
|
|
210
|
-
const selectedEffort = model?.reasoningEffort ?? '';
|
|
211
|
-
const effortTriggerLabel = model === undefined || selectedEffort === ''
|
|
212
|
-
? t('effortFollowDefault')
|
|
213
|
-
: efforts.find(effort => effort.id === selectedEffort)?.name ?? selectedEffort;
|
|
214
|
-
return _jsxs("div", { className: createCss.field, children: [_jsx("span", { children: t('memberModel') }), groups === undefined && modelsError === undefined && _jsx("small", { className: css.editHint, children: t('modelsLoading') }), modelsError !== undefined && _jsx("small", { className: css.editHint, children: t('modelsLoadFailed', { message: modelsError }) }), groups !== undefined && (_jsx(Menu, { open: open, portal: true, className: createCss.menuCap, items: items, selectedId: selectedModelKey, onSelect: key => {
|
|
215
|
-
setModelOpen(false);
|
|
216
|
-
const choice = byKey.get(key);
|
|
217
|
-
onModelChange(choice === undefined ? undefined : { provider: choice.provider, model: choice.id });
|
|
218
|
-
}, onClose: () => { setModelOpen(false); }, anchor: _jsxs("button", { type: "button", className: createCss.selectTrigger, "aria-label": t('memberModel'), "aria-haspopup": "listbox", "aria-expanded": open, disabled: disabled, onClick: () => { setModelOpen(value => !value); }, children: [_jsx("span", { className: createCss.selectValue, children: triggerLabel }), _jsx("span", { className: `${createCss.chevron} ${open ? createCss.chevronOpen : ''}`, "aria-hidden": true, children: _jsx(IconChevronDownOutline14, {}) })] }) })), model !== undefined && efforts.length > 0 && (_jsx(Menu, { open: effortOpen, portal: true, className: createCss.menuCap, items: effortItems, selectedId: selectedEffort, onSelect: key => {
|
|
219
|
-
setEffortOpen(false);
|
|
220
|
-
onModelChange(key === ''
|
|
221
|
-
? { provider: model.provider, model: model.model }
|
|
222
|
-
: { provider: model.provider, model: model.model, reasoningEffort: key });
|
|
223
|
-
}, onClose: () => { setEffortOpen(false); }, anchor: _jsxs("button", { type: "button", className: createCss.selectTrigger, "aria-label": t('reasoningEffort'), "aria-haspopup": "listbox", "aria-expanded": effortOpen, disabled: disabled, onClick: () => { setEffortOpen(value => !value); }, children: [_jsx("span", { className: createCss.selectValue, children: `${t('reasoningEffort')} · ${effortTriggerLabel}` }), _jsx("span", { className: `${createCss.chevron} ${effortOpen ? createCss.chevronOpen : ''}`, "aria-hidden": true, children: _jsx(IconChevronDownOutline14, {}) })] }) }))] });
|
|
224
|
-
}
|
|
225
|
-
/**
|
|
226
|
-
* Agent editor: handle, description, and per-Member model selection commit
|
|
227
|
-
* through one durable update; Channel membership below keeps its own
|
|
228
|
-
* immediate add/remove flow.
|
|
229
|
-
*/
|
|
230
|
-
function AgentEditorDialog({ status, channels, loadChannels, updateMember, joinChannel, removeChannelMember, loadModels, onCommitted, onClose, t }) {
|
|
231
|
-
const memberId = status.member.memberId;
|
|
232
|
-
const [handle, setHandle] = useState(status.member.handle);
|
|
233
|
-
const [description, setDescription] = useState(status.member.description);
|
|
234
|
-
const [model, setModel] = useState(status.member.model);
|
|
235
|
-
const [saving, setSaving] = useState(false);
|
|
236
|
-
const [error, setError] = useState();
|
|
237
|
-
const pendingRequest = useRef();
|
|
238
|
-
// Membership comes from a fresh projection at open time so stale checkbox
|
|
239
|
-
// state never flips a committed fact backwards.
|
|
240
|
-
const [memberships, setMemberships] = useState();
|
|
241
|
-
const [loadError, setLoadError] = useState();
|
|
242
|
-
useEffect(() => {
|
|
243
|
-
let mounted = true;
|
|
244
|
-
void loadChannels({ workspaceId: status.member.workspaceId, topLevelOnly: true, includeActivities: false, limit: 1 }).then(result => {
|
|
245
|
-
if (!mounted)
|
|
246
|
-
return;
|
|
247
|
-
if (result.ok) {
|
|
248
|
-
setMemberships(result.value.members);
|
|
249
|
-
setLoadError(undefined);
|
|
250
|
-
}
|
|
251
|
-
else {
|
|
252
|
-
setLoadError(result.error.message);
|
|
253
|
-
}
|
|
254
|
-
});
|
|
255
|
-
return () => { mounted = false; };
|
|
256
|
-
}, [loadChannels, status.member.workspaceId]);
|
|
257
|
-
const membership = useChannelMembership({ joinChannel, removeChannelMember }, change => change.channelRef, change => {
|
|
258
|
-
setMemberships(current => {
|
|
259
|
-
const base = current ?? [];
|
|
260
|
-
return change.joined
|
|
261
|
-
? base.filter(item => !(item.channelRef === change.channelRef && item.memberId === change.memberId))
|
|
262
|
-
: [...base, { channelRef: change.channelRef, memberId: change.memberId }];
|
|
263
|
-
});
|
|
264
|
-
});
|
|
265
|
-
// A successful join appends the durable fact; removal filters it out above.
|
|
266
|
-
const joinedChannels = new Set((memberships ?? []).filter(item => item.memberId === memberId).map(item => item.channelRef));
|
|
267
|
-
const dirty = handle.trim() !== status.member.handle || description.trim() !== status.member.description
|
|
268
|
-
|| !sameModel(model, status.member.model);
|
|
269
|
-
const submit = async (event) => {
|
|
270
|
-
event.preventDefault();
|
|
271
|
-
const normalizedHandle = handle.trim();
|
|
272
|
-
const normalizedDescription = description.trim();
|
|
273
|
-
if (saving || !dirty || normalizedHandle.length === 0)
|
|
274
|
-
return;
|
|
275
|
-
const payload = {
|
|
276
|
-
memberId,
|
|
277
|
-
handle: normalizedHandle,
|
|
278
|
-
description: normalizedDescription,
|
|
279
|
-
...(model === undefined ? {} : { model }),
|
|
280
|
-
};
|
|
281
|
-
const samePending = pendingRequest.current !== undefined && pendingRequest.current.memberId === payload.memberId
|
|
282
|
-
&& pendingRequest.current.handle === payload.handle && pendingRequest.current.description === payload.description
|
|
283
|
-
&& sameModel(pendingRequest.current.model, model);
|
|
284
|
-
const request = samePending ? pendingRequest.current : {
|
|
285
|
-
requestId: crypto.randomUUID(),
|
|
286
|
-
...payload,
|
|
287
|
-
};
|
|
288
|
-
pendingRequest.current = request;
|
|
289
|
-
setSaving(true);
|
|
290
|
-
setError(undefined);
|
|
291
|
-
try {
|
|
292
|
-
const result = await updateMember(request);
|
|
293
|
-
if (result.ok) {
|
|
294
|
-
pendingRequest.current = undefined;
|
|
295
|
-
await onCommitted();
|
|
296
|
-
onClose();
|
|
297
|
-
}
|
|
298
|
-
else {
|
|
299
|
-
setError(result.error.message);
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
catch (cause) {
|
|
303
|
-
setError(cause instanceof Error ? cause.message : String(cause));
|
|
304
|
-
}
|
|
305
|
-
finally {
|
|
306
|
-
setSaving(false);
|
|
307
|
-
}
|
|
308
|
-
};
|
|
309
|
-
return (_jsx(Modal, { open: true, onClose: onClose, title: t('editAgent'), description: `@${status.member.handle}`, closeLabel: t('close'), contentClassName: createCss.dialogContent, footer: _jsxs(_Fragment, { children: [_jsx(Button, { variant: "outline", disabled: saving, onClick: onClose, children: t('cancel') }), _jsx(Button, { type: "submit", form: "team-agent-edit-form", variant: "primary", disabled: saving || !dirty || handle.trim().length === 0, children: saving ? t('editSaving') : t('editSave') })] }), children: _jsxs("form", { id: "team-agent-edit-form", className: createCss.form, onSubmit: event => { void submit(event); }, children: [_jsxs("label", { className: createCss.field, children: [_jsx("span", { children: t('agentName') }), _jsx(Input, { className: createCss.input, value: handle, onChange: event => { setHandle(event.target.value); pendingRequest.current = undefined; }, disabled: saving, autoFocus: true })] }), _jsxs("label", { className: createCss.field, children: [_jsxs("span", { children: [t('agentDescription'), t('optionalSuffix')] }), _jsx(Input, { className: createCss.input, value: description, placeholder: t('agentDescriptionPlaceholder'), onChange: event => { setDescription(event.target.value); pendingRequest.current = undefined; }, disabled: saving })] }), _jsx(ModelPickerField, { model: model, onModelChange: choice => { pendingRequest.current = undefined; setModel(choice); }, loadModels: loadModels, disabled: saving, t: t }), _jsxs("fieldset", { className: createCss.memberPicker, disabled: saving, children: [_jsx("legend", { children: t('channelMembersSection') }), channels.map(channel => {
|
|
310
|
-
const joined = joinedChannels.has(channel.channelRef);
|
|
311
|
-
const rowPending = membership.pending.has(channel.channelRef);
|
|
312
|
-
const disabled = rowPending || (!joined && status.presence === 'unavailable');
|
|
313
|
-
const rowError = membership.errors.get(channel.channelRef);
|
|
314
|
-
return _jsxs("div", { className: `${css.editMemberRow} ${css.editMemberRowChannels}`, children: [_jsxs("strong", { className: css.editChannelName, children: ["# ", channel.name] }), _jsx(Button, { size: "sm", variant: "outline", disabled: disabled, onClick: () => { void membership.change({ workspaceId: status.member.workspaceId, channelRef: channel.channelRef, memberId, joined }); }, children: rowPending ? t('membershipUpdating') : joined ? t('removeFromChannel') : t('addToChannel') }), rowError !== undefined && _jsx("p", { className: css.rowError, role: "alert", children: rowError })] }, channel.channelRef);
|
|
315
|
-
}), channels.length === 0 && _jsx("small", { children: t('noChannelsForAgent') }), loadError !== undefined && _jsx("p", { className: css.rowError, role: "alert", children: loadError })] }), error !== undefined && _jsx("p", { className: createCss.error, role: "alert", children: error })] }) }));
|
|
316
|
-
}
|
|
317
|
-
function sameModel(left, right) {
|
|
318
|
-
if (left === undefined && right === undefined)
|
|
319
|
-
return true;
|
|
320
|
-
if (left === undefined || right === undefined)
|
|
321
|
-
return false;
|
|
322
|
-
return left.provider === right.provider && left.model === right.model && left.reasoningEffort === right.reasoningEffort;
|
|
323
|
-
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TeamChannelPage.d.ts","sourceRoot":"","sources":["../../../src/client/TeamChannelPage.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAA+B,mBAAmB,EAE7D,MAAM,gCAAgC,CAAA;AACvC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wCAAwC,CAAA;AAEzE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"TeamChannelPage.d.ts","sourceRoot":"","sources":["../../../src/client/TeamChannelPage.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAA+B,mBAAmB,EAE7D,MAAM,gCAAgC,CAAA;AACvC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wCAAwC,CAAA;AAEzE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AAIvD,OAAO,KAAK,EAAgB,cAAc,EAAE,MAAM,aAAa,CAAA;AAc/D,UAAU,oBAAoB;IAC5B,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAA;IACjC,QAAQ,CAAC,UAAU,EAAE,mBAAmB,CAAA;IACxC,QAAQ,CAAC,YAAY,EAAE,qBAAqB,CAAC,cAAc,CAAC,CAAA;IAC5D,QAAQ,CAAC,gBAAgB,EAAE,qBAAqB,CAAC,kBAAkB,CAAC,CAAA;IACpE,QAAQ,CAAC,WAAW,EAAE,qBAAqB,CAAC,aAAa,CAAC,CAAA;IAC1D,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAA;IAC/B,QAAQ,CAAC,aAAa,EAAE,qBAAqB,CAAC,eAAe,CAAC,CAAA;IAC9D,QAAQ,CAAC,aAAa,EAAE,qBAAqB,CAAC,eAAe,CAAC,CAAA;IAC9D,QAAQ,CAAC,WAAW,EAAE,qBAAqB,CAAC,aAAa,CAAC,CAAA;IAC1D,QAAQ,CAAC,WAAW,EAAE,qBAAqB,CAAC,aAAa,CAAC,CAAA;IAC1D,QAAQ,CAAC,mBAAmB,EAAE,qBAAqB,CAAC,qBAAqB,CAAC,CAAA;IAC1E,QAAQ,CAAC,YAAY,EAAE,qBAAqB,CAAC,cAAc,CAAC,CAAA;IAC5D,QAAQ,CAAC,aAAa,EAAE,qBAAqB,CAAC,eAAe,CAAC,CAAA;IAC9D,QAAQ,CAAC,eAAe,EAAE,qBAAqB,CAAC,iBAAiB,CAAC,CAAA;IAClE,QAAQ,CAAC,cAAc,EAAE,qBAAqB,CAAC,gBAAgB,CAAC,CAAA;IAChE,QAAQ,CAAC,CAAC,EAAE,qBAAqB,CAAC,GAAG,CAAC,CAAA;CACvC;AAmBD,wBAAgB,eAAe,CAAC,EAAE,WAAW,EAAE,UAAU,EAAE,YAAY,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,EAAE,aAAa,EAAE,aAAa,EAAE,WAAW,EAAE,WAAW,EAAE,mBAAmB,EAAE,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,eAAe,EAAE,CAAC,EAAE,EAAE,oBAAoB,+BAqTnR"}
|
|
@@ -2,6 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { Fragment, useEffect, useRef, useState, useSyncExternalStore } from 'react';
|
|
3
3
|
import { Button, IconChevronLeftOutline14, IconChevronRightOutline14, Modal, StateDot } from '@deepseek-ai/dsh-client-ui-primitives';
|
|
4
4
|
import { bytesToBase64 } from "./attachment-preview.js";
|
|
5
|
+
import { mintRequestId } from "./requests.js";
|
|
5
6
|
import { TeamComposer } from "./TeamComposer.js";
|
|
6
7
|
import { TeamPresenceDot } from "./TeamPresenceDot.js";
|
|
7
8
|
import { TeamMessage } from "./TeamMessage.js";
|
|
@@ -9,7 +10,7 @@ import { TeamRunDivider } from "./TeamRunDivider.js";
|
|
|
9
10
|
import { formatTaskStatus, taskStatusDot, mentionNamesOf } from "./team-formatters.js";
|
|
10
11
|
import { useChannelMembership } from "./team-membership.js";
|
|
11
12
|
import { useTimelineScroll } from "./timeline-scroll.js";
|
|
12
|
-
import {
|
|
13
|
+
import { hostTaskRefLookup, jumpToTaskThread } from "./task-refs.js";
|
|
13
14
|
import { chunkRunsWithDays, isRunGap } from "./team-separators.js";
|
|
14
15
|
import channelCss from './channel.module.css';
|
|
15
16
|
import css from './conversation.module.css';
|
|
@@ -66,24 +67,10 @@ export function TeamChannelPage({ workspaceId, channelRef, loadChannels, subscri
|
|
|
66
67
|
}
|
|
67
68
|
// Not in the loaded timeline: resolve through the Host and jump to the
|
|
68
69
|
// Task's home Channel.
|
|
69
|
-
|
|
70
|
-
.then(result => {
|
|
71
|
-
if (!result.ok)
|
|
72
|
-
return;
|
|
73
|
-
const hit = result.value.resolved[0];
|
|
74
|
-
if (hit !== undefined)
|
|
75
|
-
selectThread(hit.taskRef, hit.threadRef, hit.channelRef, hit.taskNumber);
|
|
76
|
-
});
|
|
70
|
+
jumpToTaskThread(resolveTaskRefs, workspaceId, ref, selectThread);
|
|
77
71
|
}
|
|
78
72
|
};
|
|
79
|
-
const lookupTaskRefs = (
|
|
80
|
-
.then(result => {
|
|
81
|
-
if (!result.ok)
|
|
82
|
-
return [];
|
|
83
|
-
for (const entry of result.value.resolved)
|
|
84
|
-
rememberResolvedTaskRef(entry);
|
|
85
|
-
return result.value.resolved;
|
|
86
|
-
});
|
|
73
|
+
const lookupTaskRefs = hostTaskRefLookup(resolveTaskRefs, workspaceId);
|
|
87
74
|
const timeline = useTimelineScroll(`${view?.items.length ?? 0}:${channelLastItem?.message.messageRef ?? ''}`);
|
|
88
75
|
const channel = view?.channels.find(item => item.channelRef === channelRef);
|
|
89
76
|
const channelMemberIds = new Set(view?.members.filter(item => item.channelRef === channelRef).map(item => item.memberId) ?? []);
|
|
@@ -219,11 +206,10 @@ export function TeamChannelPage({ workspaceId, channelRef, loadChannels, subscri
|
|
|
219
206
|
// definitive outcomes (committed or rejected) start the next send fresh.
|
|
220
207
|
const pendingSendId = useRef();
|
|
221
208
|
const send = async () => {
|
|
222
|
-
console.log('DBG send entry pending=%s draft=%j files=%d', pending, draft, pendingFiles.length);
|
|
223
209
|
if (pending || draft.trim() === '')
|
|
224
210
|
return;
|
|
225
211
|
const recipientIds = [...recipients].sort();
|
|
226
|
-
const requestId = pendingSendId.current ??
|
|
212
|
+
const requestId = pendingSendId.current ?? mintRequestId();
|
|
227
213
|
pendingSendId.current = requestId;
|
|
228
214
|
setPending(true);
|
|
229
215
|
setError(undefined);
|
|
@@ -234,7 +220,7 @@ export function TeamChannelPage({ workspaceId, channelRef, loadChannels, subscri
|
|
|
234
220
|
const attachmentIds = [];
|
|
235
221
|
for (const file of pendingFiles) {
|
|
236
222
|
const uploaded = await putAttachment({
|
|
237
|
-
requestId:
|
|
223
|
+
requestId: mintRequestId(),
|
|
238
224
|
workspaceId,
|
|
239
225
|
name: file.name,
|
|
240
226
|
mediaType: file.type === '' ? undefined : file.type,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TeamChannelsPanel.d.ts","sourceRoot":"","sources":["../../../src/client/TeamChannelsPanel.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,yBAAyB,EAEzB,mBAAmB,
|
|
1
|
+
{"version":3,"file":"TeamChannelsPanel.d.ts","sourceRoot":"","sources":["../../../src/client/TeamChannelsPanel.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,yBAAyB,EAEzB,mBAAmB,EAMpB,MAAM,gCAAgC,CAAA;AACvC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wCAAwC,CAAA;AAEzE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAYlD,UAAU,sBAAsB;IAC9B,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAA;IACjC,QAAQ,CAAC,WAAW,EAAE,gBAAgB,CAAC,aAAa,CAAC,CAAA;IACrD,QAAQ,CAAC,YAAY,EAAE,gBAAgB,CAAC,cAAc,CAAC,CAAA;IACvD,wGAAwG;IACxG,QAAQ,CAAC,gBAAgB,EAAE,gBAAgB,CAAC,kBAAkB,CAAC,CAAA;IAC/D,QAAQ,CAAC,aAAa,EAAE,gBAAgB,CAAC,eAAe,CAAC,CAAA;IACzD,QAAQ,CAAC,aAAa,EAAE,gBAAgB,CAAC,eAAe,CAAC,CAAA;IACzD,QAAQ,CAAC,WAAW,EAAE,gBAAgB,CAAC,aAAa,CAAC,CAAA;IACrD,QAAQ,CAAC,mBAAmB,EAAE,gBAAgB,CAAC,qBAAqB,CAAC,CAAA;IACrE,QAAQ,CAAC,cAAc,EAAE,SAAS,yBAAyB,EAAE,CAAA;IAC7D,QAAQ,CAAC,kBAAkB,CAAC,EAAE,mBAAmB,CAAA;IACjD,QAAQ,CAAC,aAAa,EAAE,gBAAgB,CAAC,eAAe,CAAC,CAAA;IACzD,QAAQ,CAAC,CAAC,EAAE,gBAAgB,CAAC,GAAG,CAAC,CAAA;CAClC;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,sBAAsB,+BA2L9D"}
|
|
@@ -5,6 +5,7 @@ import { TeamPresenceDot } from "./TeamPresenceDot.js";
|
|
|
5
5
|
import { MultiMenuField } from "./multi-menu-field.js";
|
|
6
6
|
import { SortableRow, useSidebarRowDrag } from "./sidebar-drag.js";
|
|
7
7
|
import { moveSidebarItem, useSidebarOrder } from "./sidebar-order.js";
|
|
8
|
+
import { mintRequestId } from "./requests.js";
|
|
8
9
|
import { TeamRowMenu } from "./TeamRowMenu.js";
|
|
9
10
|
import { TeamSidebarSection } from "./TeamSidebarSection.js";
|
|
10
11
|
import { useChannelMembership } from "./team-membership.js";
|
|
@@ -98,7 +99,7 @@ export function TeamChannelsPanel(props) {
|
|
|
98
99
|
&& pendingCreate.name === payload.name && pendingCreate.description === payload.description
|
|
99
100
|
&& JSON.stringify(pendingCreate.memberIds) === JSON.stringify(payload.memberIds);
|
|
100
101
|
const request = samePending ? pendingCreate : {
|
|
101
|
-
requestId:
|
|
102
|
+
requestId: mintRequestId(), ...payload,
|
|
102
103
|
};
|
|
103
104
|
setPendingCreate(request);
|
|
104
105
|
setMutating(true);
|
|
@@ -178,7 +179,7 @@ function ChannelEditorDialog({ channel, members, joinedIds, updateChannel, joinC
|
|
|
178
179
|
const samePending = pendingRequest.current !== undefined && pendingRequest.current.channelRef === channel.channelRef
|
|
179
180
|
&& pendingRequest.current.name === normalizedName && pendingRequest.current.description === normalizedDescription;
|
|
180
181
|
const request = samePending ? pendingRequest.current : {
|
|
181
|
-
requestId:
|
|
182
|
+
requestId: mintRequestId(),
|
|
182
183
|
workspaceId: channel.workspaceId,
|
|
183
184
|
channelRef: channel.channelRef,
|
|
184
185
|
name: normalizedName,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TeamComposer.d.ts","sourceRoot":"","sources":["../../../src/client/TeamComposer.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,2BAA2B,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAA;AAEpG,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AAkDvD,wBAAgB,YAAY,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,aAAa,EAAE,kBAAkB,EAAE,QAAQ,EAAE,YAAY,EAAE,aAAa,EAAE,CAAC,EAAE,EAAE;IACtK,QAAQ,CAAC,OAAO,EAAE,SAAS,2BAA2B,EAAE,CAAA;IACxD,QAAQ,CAAC,UAAU,EAAE,WAAW,CAAC,iBAAiB,CAAC,CAAA;IACnD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAA;IAC9B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IAC/C,QAAQ,CAAC,kBAAkB,EAAE,CAAC,UAAU,EAAE,WAAW,CAAC,iBAAiB,CAAC,KAAK,IAAI,CAAA;IACjF,QAAQ,CAAC,QAAQ,EAAE,MAAM,IAAI,CAAA;IAC7B,gGAAgG;IAChG,QAAQ,CAAC,YAAY,CAAC,EAAE,SAAS,IAAI,EAAE,CAAA;IACvC,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,SAAS,IAAI,EAAE,KAAK,IAAI,CAAA;IACzD,QAAQ,CAAC,CAAC,EAAE,qBAAqB,CAAC,GAAG,CAAC,CAAA;CACvC,+
|
|
1
|
+
{"version":3,"file":"TeamComposer.d.ts","sourceRoot":"","sources":["../../../src/client/TeamComposer.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,2BAA2B,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAA;AAEpG,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AAkDvD,wBAAgB,YAAY,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,aAAa,EAAE,kBAAkB,EAAE,QAAQ,EAAE,YAAY,EAAE,aAAa,EAAE,CAAC,EAAE,EAAE;IACtK,QAAQ,CAAC,OAAO,EAAE,SAAS,2BAA2B,EAAE,CAAA;IACxD,QAAQ,CAAC,UAAU,EAAE,WAAW,CAAC,iBAAiB,CAAC,CAAA;IACnD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAA;IAC9B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IAC/C,QAAQ,CAAC,kBAAkB,EAAE,CAAC,UAAU,EAAE,WAAW,CAAC,iBAAiB,CAAC,KAAK,IAAI,CAAA;IACjF,QAAQ,CAAC,QAAQ,EAAE,MAAM,IAAI,CAAA;IAC7B,gGAAgG;IAChG,QAAQ,CAAC,YAAY,CAAC,EAAE,SAAS,IAAI,EAAE,CAAA;IACvC,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,SAAS,IAAI,EAAE,KAAK,IAAI,CAAA;IACzD,QAAQ,CAAC,CAAC,EAAE,qBAAqB,CAAC,GAAG,CAAC,CAAA;CACvC,+BAgOA"}
|
|
@@ -172,7 +172,6 @@ export function TeamComposer({ members, recipients, draft, pending, confirmation
|
|
|
172
172
|
onSubmit();
|
|
173
173
|
};
|
|
174
174
|
return _jsxs("form", { ref: rootRef, className: css.root, onSubmit: event => {
|
|
175
|
-
console.log('DBG composer submit pending=%s draft=%j', pending, draft);
|
|
176
175
|
event.preventDefault();
|
|
177
176
|
if (!pending && draft.trim() !== '')
|
|
178
177
|
onSubmit();
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { AgentTeamChannel, AgentTeamClientMemberStatus, AgentTeamModelSelection } from '@wowyuarm/dsh-agent-team/types';
|
|
2
|
+
import type { TeamSidebarProps } from './slots.ts';
|
|
3
|
+
/**
|
|
4
|
+
* Shared provider/model dropdown for the create and edit forms. The option
|
|
5
|
+
* list rides the shared Menu primitive (one leading "follow Host default"
|
|
6
|
+
* row, then non-selectable provider headings) with a capped, internally
|
|
7
|
+
* scrolling card so growing model catalogs cannot stretch the dialog.
|
|
8
|
+
*/
|
|
9
|
+
export declare function ModelPickerField({ model, onModelChange, loadModels, disabled, t }: {
|
|
10
|
+
readonly model: AgentTeamModelSelection | undefined;
|
|
11
|
+
readonly onModelChange: (choice: AgentTeamModelSelection | undefined) => void;
|
|
12
|
+
readonly loadModels: TeamSidebarProps['loadModels'];
|
|
13
|
+
readonly disabled: boolean;
|
|
14
|
+
readonly t: TeamSidebarProps['t'];
|
|
15
|
+
}): import("react").JSX.Element;
|
|
16
|
+
/**
|
|
17
|
+
* Agent editor: handle, description, and per-Member model selection commit
|
|
18
|
+
* through one durable update; Channel membership below keeps its own
|
|
19
|
+
* immediate add/remove flow.
|
|
20
|
+
*/
|
|
21
|
+
export declare function AgentEditorDialog({ status, channels, loadChannels, updateMember, joinChannel, removeChannelMember, loadModels, onCommitted, onClose, t }: {
|
|
22
|
+
readonly status: AgentTeamClientMemberStatus;
|
|
23
|
+
readonly channels: readonly AgentTeamChannel[];
|
|
24
|
+
readonly loadChannels: TeamSidebarProps['loadChannels'];
|
|
25
|
+
readonly updateMember: TeamSidebarProps['updateMember'];
|
|
26
|
+
readonly joinChannel: TeamSidebarProps['joinChannel'];
|
|
27
|
+
readonly removeChannelMember: TeamSidebarProps['removeChannelMember'];
|
|
28
|
+
readonly loadModels: TeamSidebarProps['loadModels'];
|
|
29
|
+
readonly onCommitted: () => Promise<void> | void;
|
|
30
|
+
readonly onClose: () => void;
|
|
31
|
+
readonly t: TeamSidebarProps['t'];
|
|
32
|
+
}): import("react").JSX.Element;
|
|
33
|
+
export declare function sameModel(left: AgentTeamModelSelection | undefined, right: AgentTeamModelSelection | undefined): boolean;
|
|
34
|
+
//# sourceMappingURL=TeamMemberEditor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TeamMemberEditor.d.ts","sourceRoot":"","sources":["../../../src/client/TeamMemberEditor.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAA8B,2BAA2B,EAAE,uBAAuB,EAAgC,MAAM,gCAAgC,CAAA;AACtL,OAAO,KAAK,EAAiD,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAajG;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC,EAAE,EAAE;IAClF,QAAQ,CAAC,KAAK,EAAE,uBAAuB,GAAG,SAAS,CAAA;IACnD,QAAQ,CAAC,aAAa,EAAE,CAAC,MAAM,EAAE,uBAAuB,GAAG,SAAS,KAAK,IAAI,CAAA;IAC7E,QAAQ,CAAC,UAAU,EAAE,gBAAgB,CAAC,YAAY,CAAC,CAAA;IACnD,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;IAC1B,QAAQ,CAAC,CAAC,EAAE,gBAAgB,CAAC,GAAG,CAAC,CAAA;CAClC,+BA0GA;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,mBAAmB,EAAE,UAAU,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC,EAAE,EAAE;IACzJ,QAAQ,CAAC,MAAM,EAAE,2BAA2B,CAAA;IAC5C,QAAQ,CAAC,QAAQ,EAAE,SAAS,gBAAgB,EAAE,CAAA;IAC9C,QAAQ,CAAC,YAAY,EAAE,gBAAgB,CAAC,cAAc,CAAC,CAAA;IACvD,QAAQ,CAAC,YAAY,EAAE,gBAAgB,CAAC,cAAc,CAAC,CAAA;IACvD,QAAQ,CAAC,WAAW,EAAE,gBAAgB,CAAC,aAAa,CAAC,CAAA;IACrD,QAAQ,CAAC,mBAAmB,EAAE,gBAAgB,CAAC,qBAAqB,CAAC,CAAA;IACrE,QAAQ,CAAC,UAAU,EAAE,gBAAgB,CAAC,YAAY,CAAC,CAAA;IACnD,QAAQ,CAAC,WAAW,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;IAChD,QAAQ,CAAC,OAAO,EAAE,MAAM,IAAI,CAAA;IAC5B,QAAQ,CAAC,CAAC,EAAE,gBAAgB,CAAC,GAAG,CAAC,CAAA;CAClC,+BA0HA;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,uBAAuB,GAAG,SAAS,EAAE,KAAK,EAAE,uBAAuB,GAAG,SAAS,GAAG,OAAO,CAIxH"}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useRef, useState } from 'react';
|
|
3
|
+
import { Button, IconChevronDownOutline14, Input, Menu, Modal } from '@deepseek-ai/dsh-client-ui-primitives';
|
|
4
|
+
import { useChannelMembership } from "./team-membership.js";
|
|
5
|
+
import { mintRequestId } from "./requests.js";
|
|
6
|
+
import createCss from './create.module.css';
|
|
7
|
+
import css from './sidebar.module.css';
|
|
8
|
+
/** Model option key inside one editor; opaque and resolved against the loaded groups. */
|
|
9
|
+
function modelKey(provider, model) {
|
|
10
|
+
return `${provider}\u0000${model}`;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Shared provider/model dropdown for the create and edit forms. The option
|
|
14
|
+
* list rides the shared Menu primitive (one leading "follow Host default"
|
|
15
|
+
* row, then non-selectable provider headings) with a capped, internally
|
|
16
|
+
* scrolling card so growing model catalogs cannot stretch the dialog.
|
|
17
|
+
*/
|
|
18
|
+
export function ModelPickerField({ model, onModelChange, loadModels, disabled, t }) {
|
|
19
|
+
const [groups, setGroups] = useState();
|
|
20
|
+
const [modelsError, setModelsError] = useState();
|
|
21
|
+
const [open, setModelOpen] = useState(false);
|
|
22
|
+
const [effortOpen, setEffortOpen] = useState(false);
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
let mounted = true;
|
|
25
|
+
void loadModels().then(result => {
|
|
26
|
+
if (!mounted)
|
|
27
|
+
return;
|
|
28
|
+
if (result.ok) {
|
|
29
|
+
setGroups(result.value.groups);
|
|
30
|
+
setModelsError(undefined);
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
setModelsError(result.error.message);
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
return () => { mounted = false; };
|
|
37
|
+
}, [loadModels]);
|
|
38
|
+
const items = [{ id: '', label: t('modelFollowDefault') }];
|
|
39
|
+
const byKey = new Map();
|
|
40
|
+
for (const group of groups ?? []) {
|
|
41
|
+
items.push({ type: 'label', id: `model-group:${group.id}`, text: group.name });
|
|
42
|
+
for (const entry of group.models) {
|
|
43
|
+
const key = modelKey(group.id, entry.id);
|
|
44
|
+
byKey.set(key, { provider: group.id, id: entry.id, name: entry.name, efforts: entry.reasoning?.efforts ?? [] });
|
|
45
|
+
items.push({ id: key, label: entry.name });
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
const selectedModelKey = model === undefined ? '' : modelKey(model.provider, model.model);
|
|
49
|
+
const triggerLabel = model === undefined
|
|
50
|
+
? t('modelFollowDefault')
|
|
51
|
+
: byKey.get(selectedModelKey)?.name ?? `${model.provider} / ${model.model}`;
|
|
52
|
+
// The effort sub-row only makes sense for a pinned model with adapter-exposed
|
|
53
|
+
// efforts; following the Host default inherits the operator's whole selection.
|
|
54
|
+
const efforts = model === undefined ? [] : byKey.get(selectedModelKey)?.efforts ?? [];
|
|
55
|
+
const effortItems = [{ id: '', label: t('effortFollowDefault') }, ...efforts.map(effort => ({ id: effort.id, label: effort.name }))];
|
|
56
|
+
const selectedEffort = model?.reasoningEffort ?? '';
|
|
57
|
+
const effortTriggerLabel = model === undefined || selectedEffort === ''
|
|
58
|
+
? t('effortFollowDefault')
|
|
59
|
+
: efforts.find(effort => effort.id === selectedEffort)?.name ?? selectedEffort;
|
|
60
|
+
return _jsxs("div", { className: createCss.field, children: [_jsx("span", { children: t('memberModel') }), groups === undefined && modelsError === undefined && _jsx("small", { className: css.editHint, children: t('modelsLoading') }), modelsError !== undefined && _jsx("small", { className: css.editHint, children: t('modelsLoadFailed', { message: modelsError }) }), groups !== undefined && (_jsx(Menu, { open: open, portal: true, className: createCss.menuCap, items: items, selectedId: selectedModelKey, onSelect: key => {
|
|
61
|
+
setModelOpen(false);
|
|
62
|
+
const choice = byKey.get(key);
|
|
63
|
+
onModelChange(choice === undefined ? undefined : { provider: choice.provider, model: choice.id });
|
|
64
|
+
}, onClose: () => { setModelOpen(false); }, anchor: _jsxs("button", { type: "button", className: createCss.selectTrigger, "aria-label": t('memberModel'), "aria-haspopup": "listbox", "aria-expanded": open, disabled: disabled, onClick: () => { setModelOpen(value => !value); }, children: [_jsx("span", { className: createCss.selectValue, children: triggerLabel }), _jsx("span", { className: `${createCss.chevron} ${open ? createCss.chevronOpen : ''}`, "aria-hidden": true, children: _jsx(IconChevronDownOutline14, {}) })] }) })), model !== undefined && efforts.length > 0 && (_jsx(Menu, { open: effortOpen, portal: true, className: createCss.menuCap, items: effortItems, selectedId: selectedEffort, onSelect: key => {
|
|
65
|
+
setEffortOpen(false);
|
|
66
|
+
onModelChange(key === ''
|
|
67
|
+
? { provider: model.provider, model: model.model }
|
|
68
|
+
: { provider: model.provider, model: model.model, reasoningEffort: key });
|
|
69
|
+
}, onClose: () => { setEffortOpen(false); }, anchor: _jsxs("button", { type: "button", className: createCss.selectTrigger, "aria-label": t('reasoningEffort'), "aria-haspopup": "listbox", "aria-expanded": effortOpen, disabled: disabled, onClick: () => { setEffortOpen(value => !value); }, children: [_jsx("span", { className: createCss.selectValue, children: `${t('reasoningEffort')} · ${effortTriggerLabel}` }), _jsx("span", { className: `${createCss.chevron} ${effortOpen ? createCss.chevronOpen : ''}`, "aria-hidden": true, children: _jsx(IconChevronDownOutline14, {}) })] }) }))] });
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Agent editor: handle, description, and per-Member model selection commit
|
|
73
|
+
* through one durable update; Channel membership below keeps its own
|
|
74
|
+
* immediate add/remove flow.
|
|
75
|
+
*/
|
|
76
|
+
export function AgentEditorDialog({ status, channels, loadChannels, updateMember, joinChannel, removeChannelMember, loadModels, onCommitted, onClose, t }) {
|
|
77
|
+
const memberId = status.member.memberId;
|
|
78
|
+
const [handle, setHandle] = useState(status.member.handle);
|
|
79
|
+
const [description, setDescription] = useState(status.member.description);
|
|
80
|
+
const [model, setModel] = useState(status.member.model);
|
|
81
|
+
const [saving, setSaving] = useState(false);
|
|
82
|
+
const [error, setError] = useState();
|
|
83
|
+
const pendingRequest = useRef();
|
|
84
|
+
// Membership comes from a fresh projection at open time so stale checkbox
|
|
85
|
+
// state never flips a committed fact backwards.
|
|
86
|
+
const [memberships, setMemberships] = useState();
|
|
87
|
+
const [loadError, setLoadError] = useState();
|
|
88
|
+
useEffect(() => {
|
|
89
|
+
let mounted = true;
|
|
90
|
+
void loadChannels({ workspaceId: status.member.workspaceId, topLevelOnly: true, includeActivities: false, limit: 1 }).then(result => {
|
|
91
|
+
if (!mounted)
|
|
92
|
+
return;
|
|
93
|
+
if (result.ok) {
|
|
94
|
+
setMemberships(result.value.members);
|
|
95
|
+
setLoadError(undefined);
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
setLoadError(result.error.message);
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
return () => { mounted = false; };
|
|
102
|
+
}, [loadChannels, status.member.workspaceId]);
|
|
103
|
+
const membership = useChannelMembership({ joinChannel, removeChannelMember }, change => change.channelRef, change => {
|
|
104
|
+
setMemberships(current => {
|
|
105
|
+
const base = current ?? [];
|
|
106
|
+
return change.joined
|
|
107
|
+
? base.filter(item => !(item.channelRef === change.channelRef && item.memberId === change.memberId))
|
|
108
|
+
: [...base, { channelRef: change.channelRef, memberId: change.memberId }];
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
// A successful join appends the durable fact; removal filters it out above.
|
|
112
|
+
const joinedChannels = new Set((memberships ?? []).filter(item => item.memberId === memberId).map(item => item.channelRef));
|
|
113
|
+
const dirty = handle.trim() !== status.member.handle || description.trim() !== status.member.description
|
|
114
|
+
|| !sameModel(model, status.member.model);
|
|
115
|
+
const submit = async (event) => {
|
|
116
|
+
event.preventDefault();
|
|
117
|
+
const normalizedHandle = handle.trim();
|
|
118
|
+
const normalizedDescription = description.trim();
|
|
119
|
+
if (saving || !dirty || normalizedHandle.length === 0)
|
|
120
|
+
return;
|
|
121
|
+
const payload = {
|
|
122
|
+
memberId,
|
|
123
|
+
handle: normalizedHandle,
|
|
124
|
+
description: normalizedDescription,
|
|
125
|
+
...(model === undefined ? {} : { model }),
|
|
126
|
+
};
|
|
127
|
+
const samePending = pendingRequest.current !== undefined && pendingRequest.current.memberId === payload.memberId
|
|
128
|
+
&& pendingRequest.current.handle === payload.handle && pendingRequest.current.description === payload.description
|
|
129
|
+
&& sameModel(pendingRequest.current.model, model);
|
|
130
|
+
const request = samePending ? pendingRequest.current : {
|
|
131
|
+
requestId: mintRequestId(),
|
|
132
|
+
...payload,
|
|
133
|
+
};
|
|
134
|
+
pendingRequest.current = request;
|
|
135
|
+
setSaving(true);
|
|
136
|
+
setError(undefined);
|
|
137
|
+
try {
|
|
138
|
+
const result = await updateMember(request);
|
|
139
|
+
if (result.ok) {
|
|
140
|
+
pendingRequest.current = undefined;
|
|
141
|
+
await onCommitted();
|
|
142
|
+
onClose();
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
setError(result.error.message);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
catch (cause) {
|
|
149
|
+
setError(cause instanceof Error ? cause.message : String(cause));
|
|
150
|
+
}
|
|
151
|
+
finally {
|
|
152
|
+
setSaving(false);
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
return (_jsx(Modal, { open: true, onClose: onClose, title: t('editAgent'), description: `@${status.member.handle}`, closeLabel: t('close'), contentClassName: createCss.dialogContent, footer: _jsxs(_Fragment, { children: [_jsx(Button, { variant: "outline", disabled: saving, onClick: onClose, children: t('cancel') }), _jsx(Button, { type: "submit", form: "team-agent-edit-form", variant: "primary", disabled: saving || !dirty || handle.trim().length === 0, children: saving ? t('editSaving') : t('editSave') })] }), children: _jsxs("form", { id: "team-agent-edit-form", className: createCss.form, onSubmit: event => { void submit(event); }, children: [_jsxs("label", { className: createCss.field, children: [_jsx("span", { children: t('agentName') }), _jsx(Input, { className: createCss.input, value: handle, onChange: event => { setHandle(event.target.value); pendingRequest.current = undefined; }, disabled: saving, autoFocus: true })] }), _jsxs("label", { className: createCss.field, children: [_jsxs("span", { children: [t('agentDescription'), t('optionalSuffix')] }), _jsx(Input, { className: createCss.input, value: description, placeholder: t('agentDescriptionPlaceholder'), onChange: event => { setDescription(event.target.value); pendingRequest.current = undefined; }, disabled: saving })] }), _jsx(ModelPickerField, { model: model, onModelChange: choice => { pendingRequest.current = undefined; setModel(choice); }, loadModels: loadModels, disabled: saving, t: t }), _jsxs("fieldset", { className: createCss.memberPicker, disabled: saving, children: [_jsx("legend", { children: t('channelMembersSection') }), channels.map(channel => {
|
|
156
|
+
const joined = joinedChannels.has(channel.channelRef);
|
|
157
|
+
const rowPending = membership.pending.has(channel.channelRef);
|
|
158
|
+
const disabled = rowPending || (!joined && status.presence === 'unavailable');
|
|
159
|
+
const rowError = membership.errors.get(channel.channelRef);
|
|
160
|
+
return _jsxs("div", { className: `${css.editMemberRow} ${css.editMemberRowChannels}`, children: [_jsxs("strong", { className: css.editChannelName, children: ["# ", channel.name] }), _jsx(Button, { size: "sm", variant: "outline", disabled: disabled, onClick: () => { void membership.change({ workspaceId: status.member.workspaceId, channelRef: channel.channelRef, memberId, joined }); }, children: rowPending ? t('membershipUpdating') : joined ? t('removeFromChannel') : t('addToChannel') }), rowError !== undefined && _jsx("p", { className: css.rowError, role: "alert", children: rowError })] }, channel.channelRef);
|
|
161
|
+
}), channels.length === 0 && _jsx("small", { children: t('noChannelsForAgent') }), loadError !== undefined && _jsx("p", { className: css.rowError, role: "alert", children: loadError })] }), error !== undefined && _jsx("p", { className: createCss.error, role: "alert", children: error })] }) }));
|
|
162
|
+
}
|
|
163
|
+
export function sameModel(left, right) {
|
|
164
|
+
if (left === undefined && right === undefined)
|
|
165
|
+
return true;
|
|
166
|
+
if (left === undefined || right === undefined)
|
|
167
|
+
return false;
|
|
168
|
+
return left.provider === right.provider && left.model === right.model && left.reasoningEffort === right.reasoningEffort;
|
|
169
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
|
|
2
|
+
import type { InputTriggerController } from '@deepseek-ai/dsh-client-ui-input-trigger/client';
|
|
3
|
+
/** Public composer-bar slot currency plus Team's scoped trigger controller. */
|
|
4
|
+
export type TeamMemberSessionComposerProps = PropsRuntime<'conversation.composer.bar'> & {
|
|
5
|
+
readonly controller: InputTriggerController;
|
|
6
|
+
/** Team inject provides public Session.cancel as the running stop action. */
|
|
7
|
+
readonly stop?: (() => void) | undefined;
|
|
8
|
+
/** Team inject keeps delivery inside the public InputMachine facade. */
|
|
9
|
+
readonly submitInput: (mode: 'queue' | 'steer') => void;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Narrow, Team-owned member-session composer. It deliberately uses the public
|
|
13
|
+
* input state/actions and trigger controller rather than the shipped InputBar;
|
|
14
|
+
* owner-provided overlay remains inside the card so the shared menu renders.
|
|
15
|
+
*/
|
|
16
|
+
export declare function TeamMemberSessionComposer({ controller, inputActions, overlay, placeholder, disabled, blocked, stop, submitInput, useInput, useSession }: TeamMemberSessionComposerProps): import("react").JSX.Element;
|
|
17
|
+
//# sourceMappingURL=TeamMemberSessionComposer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TeamMemberSessionComposer.d.ts","sourceRoot":"","sources":["../../../src/client/TeamMemberSessionComposer.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAA;AACpE,OAAO,KAAK,EAAE,sBAAsB,EAAc,MAAM,iDAAiD,CAAA;AAIzG,+EAA+E;AAC/E,MAAM,MAAM,8BAA8B,GAAG,YAAY,CAAC,2BAA2B,CAAC,GAAG;IACvF,QAAQ,CAAC,UAAU,EAAE,sBAAsB,CAAA;IAC3C,6EAA6E;IAC7E,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAA;IACxC,wEAAwE;IACxE,QAAQ,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,KAAK,IAAI,CAAA;CACxD,CAAA;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,EAAE,UAAU,EAAE,YAAY,EAAE,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,8BAA8B,+BA6GvL"}
|