@wowyuarm/dsh-agent-team 0.1.4 → 0.1.6
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 +15 -1
- package/README.zh.md +20 -3
- package/package.json +7 -2
- package/packages/agent-team/README.md +6 -0
- package/packages/agent-team/README.zh.md +6 -0
- package/packages/agent-team/core-skills/member-skill-manager/SKILL.md +41 -0
- package/packages/agent-team/core-skills/member-skill-manager/references/auth-and-config.md +30 -0
- package/packages/agent-team/core-skills/member-skill-manager/references/writing-great-skills.md +17 -0
- package/packages/agent-team/lib/auto-compaction.js +39 -1
- package/packages/agent-team/lib/index.js +340 -7
- package/packages/agent-team/lib/ledger.js +219 -7
- package/packages/agent-team/lib/member-context.js +2 -2
- package/packages/agent-team/lib/member-skills.js +94 -0
- package/packages/agent-team/lib/spec.js +38 -0
- package/packages/agent-team/lib/typert.host.js +202 -27
- 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 +155 -22
- package/packages/agent-team/lib/types/auto-compaction.d.ts +9 -0
- package/packages/agent-team/lib/types/auto-compaction.d.ts.map +1 -1
- package/packages/agent-team/lib/types/index.d.ts +81 -1
- package/packages/agent-team/lib/types/index.d.ts.map +1 -1
- package/packages/agent-team/lib/types/ledger.d.ts +49 -1
- package/packages/agent-team/lib/types/ledger.d.ts.map +1 -1
- package/packages/agent-team/lib/types/member-skills.d.ts +45 -0
- package/packages/agent-team/lib/types/member-skills.d.ts.map +1 -0
- package/packages/agent-team/lib/types/spec.d.ts.map +1 -1
- package/packages/agent-team/lib/types/types.d.ts +127 -2
- package/packages/agent-team/lib/types/types.d.ts.map +1 -1
- package/packages/agent-team/preset/team-member/agent.cordis.yml +7 -4
- 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 +677 -363
- package/packages/client-agent-team/lib/client.js.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.d.ts +2 -4
- package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.js +48 -24
- 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 -0
- 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 -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 +73 -17
- package/packages/client-agent-team/lib/types/client/TeamMemberEditor.d.ts +4 -8
- package/packages/client-agent-team/lib/types/client/TeamMemberEditor.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamMemberEditor.js +7 -40
- package/packages/client-agent-team/lib/types/client/TeamMemberSessionComposer.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamMemberSessionComposer.js +16 -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 +48 -18
- package/packages/client-agent-team/lib/types/client/TeamRowMenu.d.ts +3 -2
- package/packages/client-agent-team/lib/types/client/TeamRowMenu.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamSidebarSection.d.ts +5 -2
- package/packages/client-agent-team/lib/types/client/TeamSidebarSection.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamSidebarSection.js +2 -4
- package/packages/client-agent-team/lib/types/client/TeamThreadPage.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamThreadPage.js +82 -22
- package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.d.ts +1 -1
- package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.js +4 -2
- package/packages/client-agent-team/lib/types/client/index.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/index.js +15 -13
- package/packages/client-agent-team/lib/types/client/locales.d.ts +20 -16
- package/packages/client-agent-team/lib/types/client/locales.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/locales.js +20 -16
- package/packages/client-agent-team/lib/types/client/sidebar-sections.d.ts +16 -0
- package/packages/client-agent-team/lib/types/client/sidebar-sections.d.ts.map +1 -0
- package/packages/client-agent-team/lib/types/client/sidebar-sections.js +102 -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/team-formatters.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/team-formatters.js +9 -2
- package/packages/client-agent-team/lib/types/client/timeline-scroll.d.ts +5 -7
- package/packages/client-agent-team/lib/types/client/timeline-scroll.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/timeline-scroll.js +9 -22
- package/packages/tool-agent-team/lib/index.js +25 -5
- package/packages/tool-agent-team/lib/types/index.d.ts.map +1 -1
|
@@ -5,12 +5,10 @@ interface TeamAgentsPanelProps {
|
|
|
5
5
|
readonly workspaceId: WorkspaceId;
|
|
6
6
|
readonly loadMembers: TeamSidebarProps['loadMembers'];
|
|
7
7
|
readonly subscribeChanges: TeamSidebarProps['subscribeChanges'];
|
|
8
|
-
readonly loadChannels: TeamSidebarProps['loadChannels'];
|
|
9
8
|
readonly addMember: TeamSidebarProps['addMember'];
|
|
10
9
|
readonly updateMember: TeamSidebarProps['updateMember'];
|
|
11
10
|
readonly recoverMember: TeamSidebarProps['recoverMember'];
|
|
12
|
-
readonly
|
|
13
|
-
readonly removeChannelMember: TeamSidebarProps['removeChannelMember'];
|
|
11
|
+
readonly clearMemberContext: TeamSidebarProps['clearMemberContext'];
|
|
14
12
|
readonly loadModels: TeamSidebarProps['loadModels'];
|
|
15
13
|
/** The Member Session currently embedded in the conversation seat, if any. */
|
|
16
14
|
readonly memberSessionId?: AgentTeamClientMemberStatus['member']['sessionId'];
|
|
@@ -18,6 +16,6 @@ interface TeamAgentsPanelProps {
|
|
|
18
16
|
readonly onCreatingChange: (request: AgentTeamAddMemberRequest, creating: boolean) => void;
|
|
19
17
|
readonly t: TeamSidebarProps['t'];
|
|
20
18
|
}
|
|
21
|
-
export declare function TeamAgentsPanel({ workspaceId, loadMembers, subscribeChanges,
|
|
19
|
+
export declare function TeamAgentsPanel({ workspaceId, loadMembers, subscribeChanges, addMember, updateMember, recoverMember, clearMemberContext, loadModels, memberSessionId, openMemberSession, onCreatingChange, t }: TeamAgentsPanelProps): import("react").JSX.Element;
|
|
22
20
|
export {};
|
|
23
21
|
//# sourceMappingURL=TeamAgentsPanel.d.ts.map
|
|
@@ -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,EAE5B,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,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,kBAAkB,EAAE,gBAAgB,CAAC,oBAAoB,CAAC,CAAA;IACnE,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,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,kBAAkB,EAAE,UAAU,EAAE,eAAe,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,CAAC,EAAE,EAAE,oBAAoB,+BAmKpO"}
|
|
@@ -1,20 +1,18 @@
|
|
|
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, IconEditOutline16, IconPlayOutline16, IconPlusOutline16, IconRefreshOutline16, Input, Modal, Tooltip } from '@deepseek-ai/dsh-client-ui-primitives';
|
|
3
|
+
import { Button, IconEditOutline16, IconNewChatOutline16, IconPlayOutline16, IconPlusOutline16, IconRefreshOutline16, 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 { useSidebarSectionOpen, setSidebarSectionOpen } from "./sidebar-sections.js";
|
|
7
8
|
import { mintRequestId } from "./requests.js";
|
|
8
9
|
import { TeamRowMenu } from "./TeamRowMenu.js";
|
|
9
10
|
import { TeamSidebarSection } from "./TeamSidebarSection.js";
|
|
10
|
-
import { MultiMenuField } from "./multi-menu-field.js";
|
|
11
11
|
import { AgentEditorDialog, ModelPickerField, sameModel } from "./TeamMemberEditor.js";
|
|
12
12
|
import createCss from './create.module.css';
|
|
13
13
|
import css from './sidebar.module.css';
|
|
14
|
-
export function TeamAgentsPanel({ workspaceId, loadMembers, subscribeChanges,
|
|
14
|
+
export function TeamAgentsPanel({ workspaceId, loadMembers, subscribeChanges, addMember, updateMember, recoverMember, clearMemberContext, loadModels, memberSessionId, openMemberSession, onCreatingChange, t }) {
|
|
15
15
|
const [members, setMembers] = useState([]);
|
|
16
|
-
const [channels, setChannels] = useState([]);
|
|
17
|
-
const [channelRefs, setChannelRefs] = useState([]);
|
|
18
16
|
const [loading, setLoading] = useState(true);
|
|
19
17
|
const [error, setError] = useState();
|
|
20
18
|
const [formOpen, setFormOpen] = useState(false);
|
|
@@ -36,6 +34,7 @@ export function TeamAgentsPanel({ workspaceId, loadMembers, subscribeChanges, lo
|
|
|
36
34
|
void moveSidebarItem(workspaceId, 'agents', orderedAgentRefs, movedRef, targetRef, marker);
|
|
37
35
|
};
|
|
38
36
|
const drag = useSidebarRowDrag({ refs: orderedAgentRefs, onCommit: applyMove });
|
|
37
|
+
const sectionOpen = useSidebarSectionOpen(workspaceId, 'agents');
|
|
39
38
|
const refresh = useCallback(async () => {
|
|
40
39
|
setLoading(true);
|
|
41
40
|
const result = await loadMembers({ workspaceId });
|
|
@@ -49,22 +48,15 @@ export function TeamAgentsPanel({ workspaceId, loadMembers, subscribeChanges, lo
|
|
|
49
48
|
setLoading(false);
|
|
50
49
|
}, [loadMembers, workspaceId]);
|
|
51
50
|
useEffect(() => { void refresh(); }, [refresh]);
|
|
52
|
-
const loadWorkspaceChannels = useCallback(async () => {
|
|
53
|
-
const result = await loadChannels({ workspaceId, topLevelOnly: true, includeActivities: false, limit: 1 });
|
|
54
|
-
if (result.ok)
|
|
55
|
-
setChannels(result.value.channels);
|
|
56
|
-
}, [loadChannels, workspaceId]);
|
|
57
|
-
useEffect(() => { void loadWorkspaceChannels(); }, [loadWorkspaceChannels]);
|
|
58
51
|
useEffect(() => subscribeChanges({ kind: 'workspace', workspaceId }, update => {
|
|
59
52
|
if (update.type === 'failed') {
|
|
60
53
|
setError(update.message);
|
|
61
54
|
return;
|
|
62
55
|
}
|
|
63
|
-
// The section stays mounted across Channel creation, so
|
|
64
|
-
//
|
|
56
|
+
// The section stays mounted across Channel creation, so the Member roster
|
|
57
|
+
// rides every workspace invalidation.
|
|
65
58
|
void refresh();
|
|
66
|
-
|
|
67
|
-
}), [subscribeChanges, refresh, loadWorkspaceChannels, workspaceId]);
|
|
59
|
+
}), [subscribeChanges, refresh, workspaceId]);
|
|
68
60
|
const closeForm = () => {
|
|
69
61
|
if (creating)
|
|
70
62
|
return;
|
|
@@ -86,7 +78,6 @@ export function TeamAgentsPanel({ workspaceId, loadMembers, subscribeChanges, lo
|
|
|
86
78
|
setHandle('');
|
|
87
79
|
setDescription('');
|
|
88
80
|
setModel(undefined);
|
|
89
|
-
setChannelRefs([]);
|
|
90
81
|
setFormOpen(false);
|
|
91
82
|
if (result.value.status.presence === 'unavailable') {
|
|
92
83
|
setError(result.value.status.diagnostic ?? t('statusUnavailable'));
|
|
@@ -118,30 +109,30 @@ export function TeamAgentsPanel({ workspaceId, loadMembers, subscribeChanges, lo
|
|
|
118
109
|
const sameRequest = retryRequest !== undefined && retryRequest.workspaceId === workspaceId
|
|
119
110
|
&& retryRequest.handle === normalizedHandle && retryRequest.description === normalizedDescription
|
|
120
111
|
&& sameModel(retryRequest.model, model)
|
|
121
|
-
&& retryRequest.channelRefs.length ===
|
|
112
|
+
&& retryRequest.channelRefs.length === 0;
|
|
122
113
|
void provision(sameRequest ? retryRequest : {
|
|
123
114
|
requestId: mintRequestId(),
|
|
124
115
|
workspaceId,
|
|
125
116
|
handle: normalizedHandle,
|
|
126
117
|
description: normalizedDescription,
|
|
127
118
|
presetId: 'team-member',
|
|
128
|
-
|
|
119
|
+
// No initial Channels at creation: the Member joins Channels later from
|
|
120
|
+
// the Channel side and stays reachable through its DM view meanwhile.
|
|
121
|
+
channelRefs: [],
|
|
129
122
|
...(model === undefined ? {} : { model }),
|
|
130
123
|
});
|
|
131
124
|
};
|
|
132
|
-
return (_jsxs("div", { className: css.panel, children: [_jsx(Modal, { open: formOpen, onClose: closeForm, title: t('addAgent'), closeLabel: t('close'), contentClassName: createCss.dialogContent, footer: _jsxs(_Fragment, { children: [_jsx(Button, { variant: "outline", disabled: creating, onClick: closeForm, children: t('cancel') }), _jsx(Button, { type: "submit", form: "team-agent-create-form", variant: "primary", disabled: creating || handle.trim().length === 0, children: creating ? t('creatingAgent') : t('createAgent') })] }), children: _jsxs("form", { id: "team-agent-create-form", className: createCss.form, onSubmit: submit, 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); setRetryRequest(undefined); }, disabled: creating, 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); setRetryRequest(undefined); }, disabled: creating })] }), _jsx(ModelPickerField, { model: model, onModelChange: choice => { setModel(choice); setRetryRequest(undefined); }, loadModels: loadModels, disabled: creating, t: t }), _jsx(
|
|
133
|
-
setChannelRefs(current => current.includes(ref) ? current.filter(item => item !== ref) : [...current, ref]);
|
|
134
|
-
setRetryRequest(undefined);
|
|
135
|
-
}, emptyText: t('noChannelsForAgent'), triggerEmptyLabel: t('channelsPickerEmpty'), formatCount: count => t('channelsPickerCount', { count }) }), formOpen && error !== undefined && _jsx("p", { className: createCss.error, role: "alert", children: error })] }) }), _jsxs(TeamSidebarSection, { title: t('agents'), actions: (_jsx(Tooltip, { label: t('addAgent'), delayMs: 500, children: _jsx("button", { ref: triggerRef, type: "button", className: css.iconButton, "aria-label": t('addAgent'), onClick: () => { setError(undefined); setFormOpen(true); }, children: _jsx(IconPlusOutline16, { size: 14 }) }) })), children: [loading && members.length === 0 && _jsx("p", { className: css.emptyState, children: t('loadingAgents') }), !loading && members.length === 0 && _jsx("p", { className: css.emptyState, children: t('emptyAgents') }), _jsx("div", { className: css.agentList, children: orderedMembers.map(status => (_jsx(SortableRow, { drag: drag, orderKey: status.member.memberId, children: _jsx(AgentRow, { status: status, ...(memberSessionId === undefined ? {} : { current: status.member.sessionId === memberSessionId }), channels: channels, loadChannels: loadChannels, updateMember: updateMember, recoverMember: recoverMember, joinChannel: joinChannel, removeChannelMember: removeChannelMember, loadModels: loadModels, openMemberSession: openMemberSession, onUpdated: () => { void refresh(); }, t: t }) }, status.member.memberId))) })] }), !formOpen && error !== undefined && (_jsxs("div", { className: css.retryError, role: "alert", children: [_jsx("span", { children: error }), retryRequest !== undefined && _jsx("button", { type: "button", className: css.textButton, disabled: creating, onClick: () => { setFormOpen(true); }, children: t('retry') })] }))] }));
|
|
125
|
+
return (_jsxs("div", { className: css.panel, children: [_jsx(Modal, { open: formOpen, onClose: closeForm, title: t('addAgent'), closeLabel: t('close'), contentClassName: createCss.dialogContent, footer: _jsxs(_Fragment, { children: [_jsx(Button, { variant: "outline", disabled: creating, onClick: closeForm, children: t('cancel') }), _jsx(Button, { type: "submit", form: "team-agent-create-form", variant: "primary", disabled: creating || handle.trim().length === 0, children: creating ? t('creatingAgent') : t('createAgent') })] }), children: _jsxs("form", { id: "team-agent-create-form", className: createCss.form, onSubmit: submit, 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); setRetryRequest(undefined); }, disabled: creating, 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); setRetryRequest(undefined); }, disabled: creating })] }), _jsx(ModelPickerField, { model: model, onModelChange: choice => { setModel(choice); setRetryRequest(undefined); }, loadModels: loadModels, disabled: creating, t: t }), formOpen && error !== undefined && _jsx("p", { className: createCss.error, role: "alert", children: error })] }) }), _jsxs(TeamSidebarSection, { title: t('agents'), open: sectionOpen, onToggle: open => { setSidebarSectionOpen(workspaceId, 'agents', open); }, actions: (_jsx(Tooltip, { label: t('addAgent'), delayMs: 500, children: _jsx("button", { ref: triggerRef, type: "button", className: css.iconButton, "aria-label": t('addAgent'), onClick: () => { setError(undefined); setFormOpen(true); }, children: _jsx(IconPlusOutline16, { size: 14 }) }) })), children: [loading && members.length === 0 && _jsx("p", { className: css.emptyState, children: t('loadingAgents') }), !loading && members.length === 0 && _jsx("p", { className: css.emptyState, children: t('emptyAgents') }), _jsx("div", { className: css.agentList, children: orderedMembers.map(status => (_jsx(SortableRow, { drag: drag, orderKey: status.member.memberId, children: _jsx(AgentRow, { status: status, ...(memberSessionId === undefined ? {} : { current: status.member.sessionId === memberSessionId }), updateMember: updateMember, recoverMember: recoverMember, clearMemberContext: clearMemberContext, loadModels: loadModels, openMemberSession: openMemberSession, onUpdated: () => { void refresh(); }, t: t }) }, status.member.memberId))) })] }), !formOpen && error !== undefined && (_jsxs("div", { className: css.retryError, role: "alert", children: [_jsx("span", { children: error }), retryRequest !== undefined && _jsx("button", { type: "button", className: css.textButton, disabled: creating, onClick: () => { setFormOpen(true); }, children: t('retry') })] }))] }));
|
|
136
126
|
}
|
|
137
127
|
/**
|
|
138
128
|
* One sidebar Agent row: the select button opens the Member's own Session
|
|
139
129
|
* conversation page, the avatar carries identity plus the presence badge, and
|
|
140
130
|
* the row menu opens the editor.
|
|
141
131
|
*/
|
|
142
|
-
function AgentRow({ status, current,
|
|
132
|
+
function AgentRow({ status, current, updateMember, recoverMember, clearMemberContext, loadModels, openMemberSession, onUpdated, t }) {
|
|
143
133
|
const [menuOpen, setMenuOpen] = useState(false);
|
|
144
134
|
const [editing, setEditing] = useState(false);
|
|
135
|
+
const [clearing, setClearing] = useState(false);
|
|
145
136
|
const [rowAlert, setRowAlert] = useState();
|
|
146
137
|
// Both row actions ride the same runtime remote: the Host steers a live
|
|
147
138
|
// session, rebuilds an orphaned composition, or re-runs a failed activation.
|
|
@@ -171,14 +162,47 @@ function AgentRow({ status, current, channels, loadChannels, updateMember, recov
|
|
|
171
162
|
setRowAlert(t('restartFailed', { message: cause instanceof Error ? cause.message : String(cause) }));
|
|
172
163
|
}
|
|
173
164
|
};
|
|
165
|
+
const clearContext = async () => {
|
|
166
|
+
try {
|
|
167
|
+
const result = await clearMemberContext({
|
|
168
|
+
requestId: mintRequestId(),
|
|
169
|
+
workspaceId: status.member.workspaceId,
|
|
170
|
+
memberId: status.member.memberId,
|
|
171
|
+
});
|
|
172
|
+
await onUpdated();
|
|
173
|
+
if (!result.ok) {
|
|
174
|
+
setRowAlert(t('clearContextFailed', { message: result.error.message }));
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
setRowAlert(undefined);
|
|
178
|
+
// The Host moved the Member onto a fresh Session id (the previous log
|
|
179
|
+
// stays archived on disk). A new id has no resident client instance, so
|
|
180
|
+
// re-entering the member view lazily instantiates it from host truth:
|
|
181
|
+
// blank hero, live updates, and no disposed-generation gray-out.
|
|
182
|
+
if (current === true)
|
|
183
|
+
openMemberSession(result.value.status.member.sessionId);
|
|
184
|
+
}
|
|
185
|
+
catch (cause) {
|
|
186
|
+
setRowAlert(t('clearContextFailed', { message: cause instanceof Error ? cause.message : String(cause) }));
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
// Error Members keep a live idle handle, so starting from a new context
|
|
190
|
+
// is available to them too — it doubles as a recovery path (the broken
|
|
191
|
+
// handle's error markers are dropped with it). Only a running turn or a
|
|
192
|
+
// missing handle gates the entry.
|
|
193
|
+
const contextClearable = status.presence === 'available' || status.presence === 'error';
|
|
174
194
|
return (_jsxs(_Fragment, { children: [_jsxs("div", { className: css.agentRow, "data-menu-open": menuOpen || undefined, children: [_jsxs("button", { type: "button", className: css.agentSelect, "aria-label": t('openAgentSession', { name: status.member.handle }), "aria-current": current ? 'page' : undefined, disabled: status.availability !== 'active', onClick: () => { openMemberSession(status.member.sessionId); }, children: [_jsx(TeamMemberAvatar, { status: status, t: t }), _jsxs("span", { className: css.agentCopy, children: [_jsx("strong", { children: status.member.handle }), _jsx("small", { children: status.member.description })] })] }), _jsx("span", { className: css.rowMenu, children: _jsx(TeamRowMenu, { label: t('actionsAgent', { name: status.member.handle }), items: [
|
|
175
195
|
{ id: 'edit', label: t('editAgent'), icon: _jsx(IconEditOutline16, {}) },
|
|
176
196
|
...(status.presence === 'error' ? [{ id: 'resume', label: t('resumeAgent'), icon: _jsx(IconPlayOutline16, {}) }] : []),
|
|
177
197
|
...(status.availability === 'unavailable' ? [{ id: 'restart', label: t('restartAgent'), icon: _jsx(IconRefreshOutline16, {}) }] : []),
|
|
198
|
+
{ id: 'clear-context', label: t('clearContextAgent'), icon: _jsx(IconNewChatOutline16, {}), danger: true, disabled: !contextClearable },
|
|
199
|
+
...(!contextClearable ? [{ type: 'label', id: 'clear-context-reason', text: status.presence === 'working' ? t('clearContextWorkingReason') : t('clearContextUnavailableReason') }] : []),
|
|
178
200
|
], onSelect: (id) => {
|
|
179
201
|
if (id === 'edit')
|
|
180
202
|
setEditing(true);
|
|
203
|
+
else if (id === 'clear-context')
|
|
204
|
+
setClearing(true);
|
|
181
205
|
else
|
|
182
206
|
void recover();
|
|
183
|
-
}, onOpenChange: setMenuOpen }) })] }), rowAlert !== undefined && _jsx("div", { className: css.rowAlert, role: "alert", children: rowAlert }),
|
|
207
|
+
}, onOpenChange: setMenuOpen }) })] }), rowAlert !== undefined && _jsx("div", { className: css.rowAlert, role: "alert", children: rowAlert }), clearing && (_jsx(Modal, { open: true, onClose: () => { setClearing(false); }, title: t('clearContextTitle', { name: status.member.handle }), closeLabel: t('close'), contentClassName: createCss.dialogContent, footer: _jsxs(_Fragment, { children: [_jsx(Button, { variant: "outline", onClick: () => { setClearing(false); }, children: t('cancel') }), _jsx(Button, { variant: "primary", onClick: () => { setClearing(false); void clearContext(); }, children: t('clearContextConfirm') })] }), children: _jsx("p", { className: createCss.error, children: t('clearContextNotice', { name: status.member.handle }) }) })), editing && (_jsx(AgentEditorDialog, { status: status, updateMember: updateMember, loadModels: loadModels, onCommitted: onUpdated, onClose: () => { setEditing(false); }, t: t }))] }));
|
|
184
208
|
}
|
|
@@ -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;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,+
|
|
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,+BAmVnR"}
|
|
@@ -60,6 +60,26 @@ export function TeamChannelPage({ workspaceId, channelRef, loadChannels, subscri
|
|
|
60
60
|
selectChannel(ref);
|
|
61
61
|
return;
|
|
62
62
|
}
|
|
63
|
+
if (ref.startsWith('thread:')) {
|
|
64
|
+
const match = view?.items.find(item => item.thread.threadRef === ref);
|
|
65
|
+
if (match !== undefined) {
|
|
66
|
+
selectThread(match.thread.threadRef, channelRef, match.task?.taskRef, match.taskNumber);
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
// A ref may point outside the currently loaded Channel window. Ask the
|
|
70
|
+
// Host for the bounded Thread view so it can provide the home Channel.
|
|
71
|
+
void loadChannels({ workspaceId, threadRef: ref, includeActivities: false, limit: 1 }).then(result => {
|
|
72
|
+
if (!result.ok)
|
|
73
|
+
return;
|
|
74
|
+
const target = result.value.items[0];
|
|
75
|
+
if (target !== undefined) {
|
|
76
|
+
const targetChannel = result.value.channels.find(channel => channel.channelRef === target.message.channelRef);
|
|
77
|
+
if (targetChannel !== undefined)
|
|
78
|
+
selectThread(target.thread.threadRef, targetChannel.channelRef, target.task?.taskRef, target.taskNumber);
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
63
83
|
if (ref.startsWith('task:')) {
|
|
64
84
|
const match = view?.items.find(item => item.task?.taskRef === ref);
|
|
65
85
|
if (match !== undefined) {
|
|
@@ -1 +1 @@
|
|
|
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;
|
|
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;AAalD,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,+BA8L9D"}
|
|
@@ -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 { useSidebarSectionOpen, setSidebarSectionOpen } from "./sidebar-sections.js";
|
|
8
9
|
import { mintRequestId } from "./requests.js";
|
|
9
10
|
import { TeamRowMenu } from "./TeamRowMenu.js";
|
|
10
11
|
import { TeamSidebarSection } from "./TeamSidebarSection.js";
|
|
@@ -37,6 +38,7 @@ export function TeamChannelsPanel(props) {
|
|
|
37
38
|
void moveSidebarItem(workspaceId, 'channels', orderedChannelRefs, movedRef, targetRef, marker);
|
|
38
39
|
};
|
|
39
40
|
const drag = useSidebarRowDrag({ refs: orderedChannelRefs, onCommit: applyMove });
|
|
41
|
+
const sectionOpen = useSidebarSectionOpen(workspaceId, 'channels');
|
|
40
42
|
const refresh = useCallback(async () => {
|
|
41
43
|
setLoading(true);
|
|
42
44
|
const [channelResult, memberResult] = await Promise.all([
|
|
@@ -144,7 +146,7 @@ export function TeamChannelsPanel(props) {
|
|
|
144
146
|
return next;
|
|
145
147
|
});
|
|
146
148
|
setPendingCreate(undefined);
|
|
147
|
-
}, triggerEmptyLabel: t('membersPickerEmpty'), formatCount: count => t('membersPickerCount', { count }) }), error !== undefined && _jsx("p", { className: createCss.error, role: "alert", children: error })] }) }), _jsxs(TeamSidebarSection, { title: t('channels'), actions: (_jsx(Tooltip, { label: t('addChannel'), delayMs: 500, children: _jsx("button", { ref: triggerRef, type: "button", className: css.iconButton, "aria-label": t('addChannel'), onClick: () => { setError(undefined); setFormOpen(true); }, children: _jsx(IconPlusOutline16, { size: 14 }) }) })), children: [loading && view === undefined && _jsx("p", { className: css.emptyState, children: t('loadingChannels') }), !loading && (view?.channels.length ?? 0) === 0 && _jsx("p", { className: css.emptyState, children: t('emptyChannels') }), _jsx("div", { className: css.channelList, children: orderedChannels.map(channel => {
|
|
149
|
+
}, triggerEmptyLabel: t('membersPickerEmpty'), formatCount: count => t('membersPickerCount', { count }) }), error !== undefined && _jsx("p", { className: createCss.error, role: "alert", children: error })] }) }), _jsxs(TeamSidebarSection, { title: t('channels'), open: sectionOpen, onToggle: open => { setSidebarSectionOpen(workspaceId, 'channels', open); }, actions: (_jsx(Tooltip, { label: t('addChannel'), delayMs: 500, children: _jsx("button", { ref: triggerRef, type: "button", className: css.iconButton, "aria-label": t('addChannel'), onClick: () => { setError(undefined); setFormOpen(true); }, children: _jsx(IconPlusOutline16, { size: 14 }) }) })), children: [loading && view === undefined && _jsx("p", { className: css.emptyState, children: t('loadingChannels') }), !loading && (view?.channels.length ?? 0) === 0 && _jsx("p", { className: css.emptyState, children: t('emptyChannels') }), _jsx("div", { className: css.channelList, children: orderedChannels.map(channel => {
|
|
148
150
|
const joined = membership.get(channel.channelRef) ?? new Set();
|
|
149
151
|
return (_jsx(SortableRow, { drag: drag, orderKey: channel.channelRef, children: _jsx(ChannelRow, { channel: channel, members: members, joinedIds: joined, selected: selectedChannelRef === channel.channelRef, updateChannel: updateChannel, joinChannel: props.joinChannel, removeChannelMember: props.removeChannelMember, onCommitted: () => { void refresh(); }, selectChannel: selectChannel, t: t }) }, channel.channelRef));
|
|
150
152
|
}) })] }), !formOpen && error !== undefined && _jsx("p", { className: css.error, role: "alert", children: error })] }));
|
|
@@ -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;
|
|
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;AA8DvD,wBAAgB,YAAY,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,aAAa,EAAE,kBAAkB,EAAE,QAAQ,EAAE,WAAW,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC,EAAE,EAAE;IAC3M,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,8EAA8E;IAC9E,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,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,gFAAgF;IAChF,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAA;IACnD,QAAQ,CAAC,CAAC,EAAE,qBAAqB,CAAC,GAAG,CAAC,CAAA;CACvC,+BAqSA"}
|
|
@@ -30,6 +30,13 @@ function mentionCandidates(members, query) {
|
|
|
30
30
|
&& status.member.state !== 'inactive'
|
|
31
31
|
&& status.member.handle.toLocaleLowerCase().startsWith(normalized));
|
|
32
32
|
}
|
|
33
|
+
/** Every member a manual handle pick could reach: the @all expansion snapshot. */
|
|
34
|
+
function allMentionMembers(members) {
|
|
35
|
+
return members.filter(status => status.presence !== 'unavailable' && status.member.state !== 'inactive');
|
|
36
|
+
}
|
|
37
|
+
function containsAllMention(draft) {
|
|
38
|
+
return /(?:^|[^\p{L}\p{N}_])@all(?=$|[^\p{L}\p{N}_])/u.test(draft);
|
|
39
|
+
}
|
|
33
40
|
/** One object URL per draft file; revoked when the draft is removed. */
|
|
34
41
|
const draftPreviewUrls = new WeakMap();
|
|
35
42
|
function draftPreviewUrl(file) {
|
|
@@ -50,9 +57,15 @@ export function TeamComposer({ members, recipients, draft, pending, confirmation
|
|
|
50
57
|
const composingRef = useRef(false);
|
|
51
58
|
const [mention, setMention] = useState();
|
|
52
59
|
const [highlight, setHighlight] = useState(0);
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
const
|
|
60
|
+
// @all is a composer-layer expansion of the same eligibility filter a
|
|
61
|
+
// handle pick uses; the fixed row stays on top of the matching members.
|
|
62
|
+
const memberCandidates = mention === undefined ? [] : mentionCandidates(members, mention.query);
|
|
63
|
+
const options = mention !== undefined && 'all'.startsWith(mention.query.toLocaleLowerCase())
|
|
64
|
+
? [{ kind: 'all' }, ...memberCandidates.map(status => ({ kind: 'member', status }))]
|
|
65
|
+
: memberCandidates.map(status => ({ kind: 'member', status }));
|
|
66
|
+
const menuOpen = mention !== undefined && options.length > 0;
|
|
67
|
+
const activeOption = options[highlight];
|
|
68
|
+
const allCount = allMentionMembers(members).length;
|
|
56
69
|
const listId = 'team-mention-suggestions';
|
|
57
70
|
const menuMaxHeight = useAnchoredMaxHeight(menuRef, 320, menuOpen ? draft : null);
|
|
58
71
|
useDismissOnOutsidePointer(rootRef, menuOpen, open => { if (!open)
|
|
@@ -65,12 +78,12 @@ export function TeamComposer({ members, recipients, draft, pending, confirmation
|
|
|
65
78
|
input.style.height = `${Math.min(input.scrollHeight, 180)}px`;
|
|
66
79
|
}, [draft]);
|
|
67
80
|
useEffect(() => {
|
|
68
|
-
if (mention === undefined ||
|
|
81
|
+
if (mention === undefined || options.length === 0) {
|
|
69
82
|
setHighlight(0);
|
|
70
83
|
return;
|
|
71
84
|
}
|
|
72
|
-
setHighlight(current => Math.min(current,
|
|
73
|
-
}, [mention,
|
|
85
|
+
setHighlight(current => Math.min(current, options.length - 1));
|
|
86
|
+
}, [mention, options.length]);
|
|
74
87
|
// Match the resident DSH composer without stealing a later user choice: Team
|
|
75
88
|
// data can load after navigation, so a dialog or another control may already
|
|
76
89
|
// own focus by the time this composer appears.
|
|
@@ -88,6 +101,10 @@ export function TeamComposer({ members, recipients, draft, pending, confirmation
|
|
|
88
101
|
inputRef.current?.focus({ preventScroll: true });
|
|
89
102
|
}, [confirmation, pending]);
|
|
90
103
|
const pruneRecipients = (nextDraft) => {
|
|
104
|
+
// An @all marker stands for its expansion snapshot: the member handles it
|
|
105
|
+
// stands for are not in the text, so text-based pruning must stand down.
|
|
106
|
+
if (containsAllMention(nextDraft))
|
|
107
|
+
return;
|
|
91
108
|
const knownMembers = new Map(members.map(status => [status.member.memberId, status.member]));
|
|
92
109
|
const next = new Set([...recipients].filter(memberId => {
|
|
93
110
|
const member = knownMembers.get(memberId);
|
|
@@ -117,9 +134,31 @@ export function TeamComposer({ members, recipients, draft, pending, confirmation
|
|
|
117
134
|
pruneRecipients(nextDraft);
|
|
118
135
|
updateMention(nextDraft, event.target.selectionStart ?? nextDraft.length);
|
|
119
136
|
};
|
|
120
|
-
const
|
|
137
|
+
const selectOption = (option) => {
|
|
121
138
|
if (mention === undefined)
|
|
122
139
|
return;
|
|
140
|
+
if (option.kind === 'all') {
|
|
141
|
+
// Expand at pick time: the recipients snapshot is every eligible member
|
|
142
|
+
// a handle pick could reach at this moment.
|
|
143
|
+
const nextDraft = `${draft.slice(0, mention.start)}@all ${draft.slice(mention.end)}`;
|
|
144
|
+
const nextCaret = mention.start + '@all '.length;
|
|
145
|
+
const nextRecipients = new Set(recipients);
|
|
146
|
+
for (const status of allMentionMembers(members))
|
|
147
|
+
nextRecipients.add(status.member.memberId);
|
|
148
|
+
onDraftChange(nextDraft);
|
|
149
|
+
onRecipientsChange(nextRecipients);
|
|
150
|
+
setMention(undefined);
|
|
151
|
+
setHighlight(0);
|
|
152
|
+
requestAnimationFrame(() => {
|
|
153
|
+
const input = inputRef.current;
|
|
154
|
+
if (input === null)
|
|
155
|
+
return;
|
|
156
|
+
input.focus({ preventScroll: true });
|
|
157
|
+
input.setSelectionRange(nextCaret, nextCaret);
|
|
158
|
+
});
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
const member = option.status;
|
|
123
162
|
const inserted = `@${member.member.handle} `;
|
|
124
163
|
const nextDraft = `${draft.slice(0, mention.start)}${inserted}${draft.slice(mention.end)}`;
|
|
125
164
|
const nextCaret = mention.start + inserted.length;
|
|
@@ -136,16 +175,31 @@ export function TeamComposer({ members, recipients, draft, pending, confirmation
|
|
|
136
175
|
input.setSelectionRange(nextCaret, nextCaret);
|
|
137
176
|
});
|
|
138
177
|
};
|
|
178
|
+
// Pasted files (screenshots, copies) join the same chips the "+" picker
|
|
179
|
+
// fills; only a paste that carries files is intercepted, so plain text
|
|
180
|
+
// keeps the browser's native insertion.
|
|
181
|
+
const onPaste = (event) => {
|
|
182
|
+
if (pending || onFilesChange === undefined || pendingFiles === undefined)
|
|
183
|
+
return;
|
|
184
|
+
const files = Array.from(event.clipboardData.items)
|
|
185
|
+
.filter(item => item.kind === 'file')
|
|
186
|
+
.map(item => item.getAsFile())
|
|
187
|
+
.filter((file) => file !== null);
|
|
188
|
+
if (files.length === 0)
|
|
189
|
+
return;
|
|
190
|
+
event.preventDefault();
|
|
191
|
+
onFilesChange([...pendingFiles, ...files]);
|
|
192
|
+
};
|
|
139
193
|
const onKeyDown = (event) => {
|
|
140
194
|
const composing = composingRef.current || event.nativeEvent.isComposing || event.nativeEvent.keyCode === 229;
|
|
141
195
|
if (menuOpen && event.key === 'ArrowDown') {
|
|
142
196
|
event.preventDefault();
|
|
143
|
-
setHighlight(current => (current + 1) %
|
|
197
|
+
setHighlight(current => (current + 1) % options.length);
|
|
144
198
|
return;
|
|
145
199
|
}
|
|
146
200
|
if (menuOpen && event.key === 'ArrowUp') {
|
|
147
201
|
event.preventDefault();
|
|
148
|
-
setHighlight(current => (current - 1 +
|
|
202
|
+
setHighlight(current => (current - 1 + options.length) % options.length);
|
|
149
203
|
return;
|
|
150
204
|
}
|
|
151
205
|
if (event.key === 'Escape' && menuOpen) {
|
|
@@ -156,15 +210,15 @@ export function TeamComposer({ members, recipients, draft, pending, confirmation
|
|
|
156
210
|
// Tab accepts the highlighted candidate; Shift+Tab keeps default focus reversal.
|
|
157
211
|
if (menuOpen && event.key === 'Tab' && !event.shiftKey) {
|
|
158
212
|
event.preventDefault();
|
|
159
|
-
if (
|
|
160
|
-
|
|
213
|
+
if (activeOption !== undefined)
|
|
214
|
+
selectOption(activeOption);
|
|
161
215
|
return;
|
|
162
216
|
}
|
|
163
217
|
if (event.key !== 'Enter' || event.shiftKey || composing || event.repeat)
|
|
164
218
|
return;
|
|
165
|
-
if (menuOpen &&
|
|
219
|
+
if (menuOpen && activeOption !== undefined) {
|
|
166
220
|
event.preventDefault();
|
|
167
|
-
|
|
221
|
+
selectOption(activeOption);
|
|
168
222
|
return;
|
|
169
223
|
}
|
|
170
224
|
event.preventDefault();
|
|
@@ -175,11 +229,13 @@ export function TeamComposer({ members, recipients, draft, pending, confirmation
|
|
|
175
229
|
event.preventDefault();
|
|
176
230
|
if (!pending && draft.trim() !== '')
|
|
177
231
|
onSubmit();
|
|
178
|
-
}, children: [_jsxs("div", { className: css.card, "data-team-composer": true, children: [confirmation !== undefined && _jsx("p", { className: css.confirmation, role: "status", children: confirmation }), _jsxs("div", { className: css.inputArea, children: [menuOpen && _jsx("div", { id: listId, ref: menuRef, className: css.mentionMenu, role: "listbox", "aria-label": t('mentionSuggestions'), style: { maxHeight: menuMaxHeight }, children:
|
|
179
|
-
const optionId = `${listId}-${status.member.memberId}`;
|
|
232
|
+
}, children: [_jsxs("div", { className: css.card, "data-team-composer": true, children: [confirmation !== undefined && _jsx("p", { className: css.confirmation, role: "status", children: confirmation }), _jsxs("div", { className: css.inputArea, children: [menuOpen && _jsx("div", { id: listId, ref: menuRef, className: css.mentionMenu, role: "listbox", "aria-label": t('mentionSuggestions'), style: { maxHeight: menuMaxHeight }, children: options.map((option, index) => {
|
|
233
|
+
const optionId = option.kind === 'all' ? `${listId}-all` : `${listId}-${option.status.member.memberId}`;
|
|
180
234
|
const selected = index === highlight;
|
|
181
|
-
return
|
|
182
|
-
|
|
235
|
+
return option.kind === 'all'
|
|
236
|
+
? _jsxs("button", { id: optionId, type: "button", role: "option", "aria-selected": selected, className: css.mentionOption, onMouseDown: event => { event.preventDefault(); }, onClick: () => { selectOption(option); }, children: [_jsx("span", { className: css.mentionAllDot, "aria-hidden": "true" }), _jsx("span", { className: css.mentionName, children: "@all" }), _jsx("span", { className: css.mentionDescription, children: t('mentionAll', { count: allCount }) })] }, "all")
|
|
237
|
+
: _jsxs("button", { id: optionId, type: "button", role: "option", "aria-selected": selected, className: css.mentionOption, onMouseDown: event => { event.preventDefault(); }, onClick: () => { selectOption(option); }, children: [_jsx(TeamPresenceDot, { status: option.status, t: t }), _jsxs("span", { className: css.mentionName, children: ["@", option.status.member.handle] }), _jsx("span", { className: css.mentionDescription, children: option.status.member.description })] }, option.status.member.memberId);
|
|
238
|
+
}) }), _jsx("textarea", { ref: inputRef, "aria-label": t('messageDraft'), "aria-autocomplete": "list", "aria-controls": menuOpen ? listId : undefined, "aria-activedescendant": menuOpen && activeOption !== undefined ? activeOption.kind === 'all' ? `${listId}-all` : `${listId}-${activeOption.status.member.memberId}` : undefined, "aria-expanded": menuOpen, value: draft, readOnly: pending, placeholder: placeholder ?? t('messagePlaceholder'), rows: 1, onChange: onChange, onPaste: onPaste, onKeyDown: onKeyDown, onSelect: event => { updateMention(event.currentTarget.value, event.currentTarget.selectionStart ?? event.currentTarget.value.length); }, onCompositionStart: () => { composingRef.current = true; }, onCompositionEnd: () => { setTimeout(() => { composingRef.current = false; }, 10); } })] }), recipients.size > 0 && _jsx("p", { className: css.notifyRow, "data-team-notify": true, children: t('composerNotify', { ids: [...recipients].sort().map(memberId => `@${members.find(candidate => candidate.member.memberId === memberId)?.member.handle ?? memberId}`).join(', ') }) }), onFilesChange !== undefined && pendingFiles !== undefined && pendingFiles.length > 0 && (_jsx("ul", { className: css.fileChips, "aria-label": t('attachFiles'), children: pendingFiles.map((file, index) => {
|
|
183
239
|
const previewUrl = draftPreviewUrl(file);
|
|
184
240
|
return _jsxs("li", { className: `${css.fileChip} ${previewUrl !== undefined ? css.imageChip : ''}`, children: [previewUrl !== undefined && _jsx("img", { src: previewUrl, alt: "", className: css.imageChipPreview }), _jsxs("span", { className: css.fileChipName, title: file.name, children: [file.name, _jsx("span", { className: css.fileChipSize, children: formatByteSize(file.size) })] }), _jsx("button", { type: "button", className: css.fileChipRemove, "aria-label": t('removeFile', { name: file.name }), disabled: pending, onClick: () => {
|
|
185
241
|
const url = draftPreviewUrls.get(file);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { AgentTeamClientMemberStatus, AgentTeamModelSelection } from '@wowyuarm/dsh-agent-team/types';
|
|
2
2
|
import type { TeamSidebarProps } from './slots.ts';
|
|
3
3
|
/**
|
|
4
4
|
* Shared provider/model dropdown for the create and edit forms. The option
|
|
@@ -15,16 +15,12 @@ export declare function ModelPickerField({ model, onModelChange, loadModels, dis
|
|
|
15
15
|
}): import("react").JSX.Element;
|
|
16
16
|
/**
|
|
17
17
|
* Agent editor: handle, description, and per-Member model selection commit
|
|
18
|
-
* through one durable update
|
|
19
|
-
*
|
|
18
|
+
* through one durable update. Channel membership is managed from the Channel
|
|
19
|
+
* side, not here.
|
|
20
20
|
*/
|
|
21
|
-
export declare function AgentEditorDialog({ status,
|
|
21
|
+
export declare function AgentEditorDialog({ status, updateMember, loadModels, onCommitted, onClose, t }: {
|
|
22
22
|
readonly status: AgentTeamClientMemberStatus;
|
|
23
|
-
readonly channels: readonly AgentTeamChannel[];
|
|
24
|
-
readonly loadChannels: TeamSidebarProps['loadChannels'];
|
|
25
23
|
readonly updateMember: TeamSidebarProps['updateMember'];
|
|
26
|
-
readonly joinChannel: TeamSidebarProps['joinChannel'];
|
|
27
|
-
readonly removeChannelMember: TeamSidebarProps['removeChannelMember'];
|
|
28
24
|
readonly loadModels: TeamSidebarProps['loadModels'];
|
|
29
25
|
readonly onCommitted: () => Promise<void> | void;
|
|
30
26
|
readonly onClose: () => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TeamMemberEditor.d.ts","sourceRoot":"","sources":["../../../src/client/TeamMemberEditor.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"TeamMemberEditor.d.ts","sourceRoot":"","sources":["../../../src/client/TeamMemberEditor.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,2BAA2B,EAAE,uBAAuB,EAAgC,MAAM,gCAAgC,CAAA;AACxI,OAAO,KAAK,EAAiD,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAYjG;;;;;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,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC,EAAE,EAAE;IAC/F,QAAQ,CAAC,MAAM,EAAE,2BAA2B,CAAA;IAC5C,QAAQ,CAAC,YAAY,EAAE,gBAAgB,CAAC,cAAc,CAAC,CAAA;IACvD,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,+BA0EA;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,uBAAuB,GAAG,SAAS,EAAE,KAAK,EAAE,uBAAuB,GAAG,SAAS,GAAG,OAAO,CAIxH"}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { useEffect, useRef, useState } from 'react';
|
|
3
3
|
import { Button, IconChevronDownOutline14, Input, Menu, Modal } from '@deepseek-ai/dsh-client-ui-primitives';
|
|
4
|
-
import { useChannelMembership } from "./team-membership.js";
|
|
5
4
|
import { mintRequestId } from "./requests.js";
|
|
6
5
|
import createCss from './create.module.css';
|
|
7
6
|
import css from './sidebar.module.css';
|
|
@@ -70,10 +69,10 @@ export function ModelPickerField({ model, onModelChange, loadModels, disabled, t
|
|
|
70
69
|
}
|
|
71
70
|
/**
|
|
72
71
|
* Agent editor: handle, description, and per-Member model selection commit
|
|
73
|
-
* through one durable update
|
|
74
|
-
*
|
|
72
|
+
* through one durable update. Channel membership is managed from the Channel
|
|
73
|
+
* side, not here.
|
|
75
74
|
*/
|
|
76
|
-
export function AgentEditorDialog({ status,
|
|
75
|
+
export function AgentEditorDialog({ status, updateMember, loadModels, onCommitted, onClose, t }) {
|
|
77
76
|
const memberId = status.member.memberId;
|
|
78
77
|
const [handle, setHandle] = useState(status.member.handle);
|
|
79
78
|
const [description, setDescription] = useState(status.member.description);
|
|
@@ -81,35 +80,6 @@ export function AgentEditorDialog({ status, channels, loadChannels, updateMember
|
|
|
81
80
|
const [saving, setSaving] = useState(false);
|
|
82
81
|
const [error, setError] = useState();
|
|
83
82
|
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
83
|
const dirty = handle.trim() !== status.member.handle || description.trim() !== status.member.description
|
|
114
84
|
|| !sameModel(model, status.member.model);
|
|
115
85
|
const submit = async (event) => {
|
|
@@ -123,6 +93,9 @@ export function AgentEditorDialog({ status, channels, loadChannels, updateMember
|
|
|
123
93
|
handle: normalizedHandle,
|
|
124
94
|
description: normalizedDescription,
|
|
125
95
|
...(model === undefined ? {} : { model }),
|
|
96
|
+
// The editor owns no capabilities UI, but an absent field would clear a
|
|
97
|
+
// Remote-written override; echo the stored intent through the edit.
|
|
98
|
+
...(status.member.capabilities === undefined ? {} : { capabilities: status.member.capabilities }),
|
|
126
99
|
};
|
|
127
100
|
const samePending = pendingRequest.current !== undefined && pendingRequest.current.memberId === payload.memberId
|
|
128
101
|
&& pendingRequest.current.handle === payload.handle && pendingRequest.current.description === payload.description
|
|
@@ -152,13 +125,7 @@ export function AgentEditorDialog({ status, channels, loadChannels, updateMember
|
|
|
152
125
|
setSaving(false);
|
|
153
126
|
}
|
|
154
127
|
};
|
|
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 }),
|
|
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 })] }) }));
|
|
128
|
+
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 }), error !== undefined && _jsx("p", { className: createCss.error, role: "alert", children: error })] }) }));
|
|
162
129
|
}
|
|
163
130
|
export function sameModel(left, right) {
|
|
164
131
|
if (left === undefined && right === undefined)
|
|
@@ -1 +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,+
|
|
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,+BA4HvL"}
|