@wowyuarm/dsh-agent-team 0.1.8 → 0.1.10

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.
Files changed (81) hide show
  1. package/README.md +4 -11
  2. package/README.zh.md +4 -11
  3. package/package.json +54 -44
  4. package/packages/agent-team/README.md +7 -5
  5. package/packages/agent-team/README.zh.md +7 -4
  6. package/packages/agent-team/lib/attachments.js +14 -4
  7. package/packages/agent-team/lib/context-management.js +382 -0
  8. package/packages/agent-team/lib/context-projection.js +578 -0
  9. package/packages/agent-team/lib/context-source.js +212 -0
  10. package/packages/agent-team/lib/index.js +1272 -76
  11. package/packages/agent-team/lib/ledger.js +333 -44
  12. package/packages/agent-team/lib/member-context.js +6 -2
  13. package/packages/agent-team/lib/member-runtime.js +159 -4
  14. package/packages/agent-team/lib/member-time-context.js +126 -0
  15. package/packages/agent-team/lib/pressure-policy.js +199 -0
  16. package/packages/agent-team/lib/progress-nudge.js +12 -4
  17. package/packages/agent-team/lib/session-remediation.js +481 -0
  18. package/packages/agent-team/lib/spec.js +21 -2
  19. package/packages/agent-team/lib/time-format.js +56 -0
  20. package/packages/agent-team/lib/typert.host.js +168 -54
  21. package/packages/agent-team/lib/typert.remote-client.d.ts.map +1 -1
  22. package/packages/agent-team/lib/typert.remote-client.js +59 -25
  23. package/packages/agent-team/lib/types/attachments.d.ts +1 -1
  24. package/packages/agent-team/lib/types/attachments.d.ts.map +1 -1
  25. package/packages/agent-team/lib/types/context-management.d.ts +147 -0
  26. package/packages/agent-team/lib/types/context-management.d.ts.map +1 -0
  27. package/packages/agent-team/lib/types/context-projection.d.ts +219 -0
  28. package/packages/agent-team/lib/types/context-projection.d.ts.map +1 -0
  29. package/packages/agent-team/lib/types/context-source.d.ts +117 -0
  30. package/packages/agent-team/lib/types/context-source.d.ts.map +1 -0
  31. package/packages/agent-team/lib/types/index.d.ts +300 -2
  32. package/packages/agent-team/lib/types/index.d.ts.map +1 -1
  33. package/packages/agent-team/lib/types/ledger.d.ts +119 -6
  34. package/packages/agent-team/lib/types/ledger.d.ts.map +1 -1
  35. package/packages/agent-team/lib/types/member-context.d.ts.map +1 -1
  36. package/packages/agent-team/lib/types/member-runtime.d.ts +30 -2
  37. package/packages/agent-team/lib/types/member-runtime.d.ts.map +1 -1
  38. package/packages/agent-team/lib/types/member-time-context.d.ts +83 -0
  39. package/packages/agent-team/lib/types/member-time-context.d.ts.map +1 -0
  40. package/packages/agent-team/lib/types/pressure-policy.d.ts +106 -0
  41. package/packages/agent-team/lib/types/pressure-policy.d.ts.map +1 -0
  42. package/packages/agent-team/lib/types/progress-nudge.d.ts.map +1 -1
  43. package/packages/agent-team/lib/types/session-remediation.d.ts +149 -0
  44. package/packages/agent-team/lib/types/session-remediation.d.ts.map +1 -0
  45. package/packages/agent-team/lib/types/spec.d.ts.map +1 -1
  46. package/packages/agent-team/lib/types/time-format.d.ts +28 -0
  47. package/packages/agent-team/lib/types/time-format.d.ts.map +1 -0
  48. package/packages/agent-team/lib/types/types/entities.d.ts +22 -1
  49. package/packages/agent-team/lib/types/types/entities.d.ts.map +1 -1
  50. package/packages/agent-team/lib/types/types/operations.d.ts +38 -3
  51. package/packages/agent-team/lib/types/types/operations.d.ts.map +1 -1
  52. package/packages/agent-team/lib/types/types/requests-results.d.ts +58 -1
  53. package/packages/agent-team/lib/types/types/requests-results.d.ts.map +1 -1
  54. package/packages/agent-team/preset/team-member/agent.cordis.yml +27 -4
  55. package/packages/client-agent-team/lib/client.js +369 -352
  56. package/packages/client-agent-team/lib/client.js.map +1 -1
  57. package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.d.ts +1 -2
  58. package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.d.ts.map +1 -1
  59. package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.js +61 -41
  60. package/packages/client-agent-team/lib/types/client/TeamMessage.js +2 -2
  61. package/packages/client-agent-team/lib/types/client/TeamThreadPage.js +4 -4
  62. package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.d.ts +1 -1
  63. package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.d.ts.map +1 -1
  64. package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.js +2 -2
  65. package/packages/client-agent-team/lib/types/client/index.d.ts.map +1 -1
  66. package/packages/client-agent-team/lib/types/client/index.js +44 -16
  67. package/packages/client-agent-team/lib/types/client/locales.d.ts +0 -14
  68. package/packages/client-agent-team/lib/types/client/locales.d.ts.map +1 -1
  69. package/packages/client-agent-team/lib/types/client/locales.js +0 -14
  70. package/packages/client-agent-team/lib/types/client/slots.d.ts +6 -1
  71. package/packages/client-agent-team/lib/types/client/slots.d.ts.map +1 -1
  72. package/packages/tool-agent-team/README.md +11 -6
  73. package/packages/tool-agent-team/README.zh.md +11 -6
  74. package/packages/tool-agent-team/lib/context-tools.js +179 -0
  75. package/packages/tool-agent-team/lib/index.js +369 -58
  76. package/packages/tool-agent-team/lib/types/context-tools.d.ts +16 -0
  77. package/packages/tool-agent-team/lib/types/context-tools.d.ts.map +1 -0
  78. package/packages/tool-agent-team/lib/types/index.d.ts.map +1 -1
  79. package/packages/agent-team/lib/auto-compaction.js +0 -201
  80. package/packages/agent-team/lib/types/auto-compaction.d.ts +0 -47
  81. package/packages/agent-team/lib/types/auto-compaction.d.ts.map +0 -1
@@ -8,7 +8,6 @@ interface TeamAgentsPanelProps {
8
8
  readonly addMember: TeamSidebarProps['addMember'];
9
9
  readonly updateMember: TeamSidebarProps['updateMember'];
10
10
  readonly recoverMember: TeamSidebarProps['recoverMember'];
11
- readonly clearMemberContext: TeamSidebarProps['clearMemberContext'];
12
11
  readonly archiveMember: TeamSidebarProps['archiveMember'];
13
12
  readonly loadModels: TeamSidebarProps['loadModels'];
14
13
  /** The Member Session currently embedded in the conversation seat, if any. */
@@ -17,6 +16,6 @@ interface TeamAgentsPanelProps {
17
16
  readonly onCreatingChange: (request: AgentTeamAddMemberRequest, creating: boolean) => void;
18
17
  readonly t: TeamSidebarProps['t'];
19
18
  }
20
- export declare function TeamAgentsPanel({ workspaceId, loadMembers, subscribeChanges, addMember, updateMember, recoverMember, clearMemberContext, archiveMember, loadModels, memberSessionId, openMemberSession, onCreatingChange, t }: TeamAgentsPanelProps): import("react").JSX.Element;
19
+ export declare function TeamAgentsPanel({ workspaceId, loadMembers, subscribeChanges, addMember, updateMember, recoverMember, archiveMember, loadModels, memberSessionId, openMemberSession, onCreatingChange, t }: TeamAgentsPanelProps): import("react").JSX.Element;
21
20
  export {};
22
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,EAE5B,MAAM,gCAAgC,CAAA;AACvC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kDAAkD,CAAA;AAEnF,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,aAAa,EAAE,gBAAgB,CAAC,eAAe,CAAC,CAAA;IACzD,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,aAAa,EAAE,UAAU,EAAE,eAAe,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,CAAC,EAAE,EAAE,oBAAoB,+BAuKnP"}
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,kDAAkD,CAAA;AAEnF,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,aAAa,EAAE,gBAAgB,CAAC,eAAe,CAAC,CAAA;IACzD,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,aAAa,EAAE,UAAU,EAAE,eAAe,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,CAAC,EAAE,EAAE,oBAAoB,+BA2N/N"}
@@ -1,6 +1,6 @@
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, IconArchiveOutline20, IconEditOutline16, IconNewChatOutline16, IconPlayOutline16, IconPlusOutline16, IconRefreshOutline16, Input, Modal, Tooltip } from '@deepseek-ai/dsh-client-ui-primitives';
3
+ import { Button, IconArchiveOutline20, IconEditOutline16, 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";
@@ -11,7 +11,7 @@ import { TeamSidebarSection } from "./TeamSidebarSection.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, addMember, updateMember, recoverMember, clearMemberContext, archiveMember, loadModels, memberSessionId, openMemberSession, onCreatingChange, t }) {
14
+ export function TeamAgentsPanel({ workspaceId, loadMembers, subscribeChanges, addMember, updateMember, recoverMember, archiveMember, loadModels, memberSessionId, openMemberSession, onCreatingChange, t }) {
15
15
  const [members, setMembers] = useState([]);
16
16
  const [loading, setLoading] = useState(true);
17
17
  const [error, setError] = useState();
@@ -35,20 +35,74 @@ export function TeamAgentsPanel({ workspaceId, loadMembers, subscribeChanges, ad
35
35
  };
36
36
  const drag = useSidebarRowDrag({ refs: orderedAgentRefs, onCommit: applyMove });
37
37
  const sectionOpen = useSidebarSectionOpen(workspaceId, 'agents');
38
+ // Observed old→new Session binding per Member while this panel is
39
+ // mounted. A model-initiated rollover moves the binding without any
40
+ // Client action; when the conversation seat is showing the Member's
41
+ // previous live Session, the panel follows to the new one exactly once —
42
+ // but only after the refreshed status is actually active, so the commit
43
+ // window (binding moved, new Session not yet live) never redirects to a
44
+ // Session that does not exist. The follow requires the seat to still show
45
+ // the previous Session at completion as well: a rollover observed while
46
+ // unavailable stays pending, and navigating away before it completes
47
+ // cancels the follow instead of pulling the pane back.
48
+ const observedSessionIds = useRef(new Map());
49
+ const pendingFollows = useRef(new Map());
50
+ // The seat's embedded Session id rides a ref: the change subscription may
51
+ // deliver an invalidation through a refresh closure captured before the
52
+ // seat rebinds, and the follow decision must always read the live value.
53
+ const seatSessionIdRef = useRef(memberSessionId);
54
+ seatSessionIdRef.current = memberSessionId;
55
+ const openMemberSessionRef = useRef(openMemberSession);
56
+ openMemberSessionRef.current = openMemberSession;
57
+ const followRollover = useCallback((statuses) => {
58
+ for (const status of statuses) {
59
+ const memberId = status.member.memberId;
60
+ const observed = observedSessionIds.current.get(memberId);
61
+ if (observed === undefined) {
62
+ observedSessionIds.current.set(memberId, status.member.sessionId);
63
+ continue;
64
+ }
65
+ if (observed !== status.member.sessionId) {
66
+ observedSessionIds.current.set(memberId, status.member.sessionId);
67
+ // Only the exact previous live page follows; browsing an older
68
+ // archive or another Member stays untouched. A binding change seen
69
+ // before any page is embedded is still recorded so the observation
70
+ // baseline stays current.
71
+ const seatSessionId = seatSessionIdRef.current;
72
+ if (seatSessionId !== undefined && observed === seatSessionId)
73
+ pendingFollows.current.set(memberId, { previousSessionId: observed, nextSessionId: status.member.sessionId });
74
+ else
75
+ pendingFollows.current.delete(memberId);
76
+ }
77
+ const pending = pendingFollows.current.get(memberId);
78
+ if (pending !== undefined && pending.nextSessionId === status.member.sessionId && status.availability === 'active') {
79
+ // The seat must still show the followed Member's previous Session at
80
+ // completion too: the commit window can outlive the user's patience,
81
+ // and navigating away (or onto another Member/archive view) cancels
82
+ // the follow instead of yanking the pane back onto the new Session.
83
+ const seatSessionId = seatSessionIdRef.current;
84
+ pendingFollows.current.delete(memberId);
85
+ if (seatSessionId !== undefined && seatSessionId === pending.previousSessionId)
86
+ openMemberSessionRef.current(pending.nextSessionId);
87
+ }
88
+ }
89
+ }, []);
38
90
  const refresh = useCallback(async () => {
39
91
  setLoading(true);
40
92
  const result = await loadMembers({ workspaceId });
41
93
  if (result.ok) {
42
94
  // Archived Members are hidden from every surface; the row disappears
43
95
  // the moment the workspace-scope wake delivers the archived state.
44
- setMembers(result.value.filter(status => status.member.state !== 'inactive' && status.member.state !== 'archived'));
96
+ const next = result.value.filter(status => status.member.state !== 'inactive' && status.member.state !== 'archived');
97
+ setMembers(next);
98
+ followRollover(next);
45
99
  setError(undefined);
46
100
  }
47
101
  else {
48
102
  setError(result.error.message);
49
103
  }
50
104
  setLoading(false);
51
- }, [loadMembers, workspaceId]);
105
+ }, [loadMembers, workspaceId, followRollover]);
52
106
  useEffect(() => { void refresh(); }, [refresh]);
53
107
  useEffect(() => subscribeChanges({ kind: 'workspace', workspaceId }, update => {
54
108
  if (update.type === 'failed') {
@@ -126,17 +180,16 @@ export function TeamAgentsPanel({ workspaceId, loadMembers, subscribeChanges, ad
126
180
  ...(model === undefined ? {} : { model }),
127
181
  });
128
182
  };
129
- 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, archiveMember: archiveMember, 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') })] }))] }));
183
+ 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, archiveMember: archiveMember, 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') })] }))] }));
130
184
  }
131
185
  /**
132
186
  * One sidebar Agent row: the select button opens the Member's own Session
133
187
  * conversation page, the avatar carries identity plus the presence badge, and
134
188
  * the row menu opens the editor.
135
189
  */
136
- function AgentRow({ status, current, updateMember, recoverMember, clearMemberContext, archiveMember, loadModels, openMemberSession, onUpdated, t }) {
190
+ function AgentRow({ status, current, updateMember, recoverMember, archiveMember, loadModels, openMemberSession, onUpdated, t }) {
137
191
  const [menuOpen, setMenuOpen] = useState(false);
138
192
  const [editing, setEditing] = useState(false);
139
- const [clearing, setClearing] = useState(false);
140
193
  const [archiving, setArchiving] = useState(false);
141
194
  const [rowAlert, setRowAlert] = useState();
142
195
  // Both row actions ride the same runtime remote: the Host steers a live
@@ -167,35 +220,6 @@ function AgentRow({ status, current, updateMember, recoverMember, clearMemberCon
167
220
  setRowAlert(t('restartFailed', { message: cause instanceof Error ? cause.message : String(cause) }));
168
221
  }
169
222
  };
170
- const clearContext = async () => {
171
- try {
172
- const result = await clearMemberContext({
173
- requestId: mintRequestId(),
174
- workspaceId: status.member.workspaceId,
175
- memberId: status.member.memberId,
176
- });
177
- await onUpdated();
178
- if (!result.ok) {
179
- setRowAlert(t('clearContextFailed', { message: result.error.message }));
180
- return;
181
- }
182
- setRowAlert(undefined);
183
- // The Host moved the Member onto a fresh Session id (the previous log
184
- // stays archived on disk). A new id has no resident client instance, so
185
- // re-entering the member view lazily instantiates it from host truth:
186
- // blank hero, live updates, and no disposed-generation gray-out.
187
- if (current === true)
188
- openMemberSession(result.value.status.member.sessionId);
189
- }
190
- catch (cause) {
191
- setRowAlert(t('clearContextFailed', { message: cause instanceof Error ? cause.message : String(cause) }));
192
- }
193
- };
194
- // Error Members keep a live idle handle, so starting from a new context
195
- // is available to them too — it doubles as a recovery path (the broken
196
- // handle's error markers are dropped with it). Only a running turn or a
197
- // missing handle gates the entry.
198
- const contextClearable = status.presence === 'available' || status.presence === 'error';
199
223
  const archive = async () => {
200
224
  try {
201
225
  const result = await archiveMember({
@@ -215,17 +239,13 @@ function AgentRow({ status, current, updateMember, recoverMember, clearMemberCon
215
239
  { id: 'edit', label: t('editAgent'), icon: _jsx(IconEditOutline16, {}) },
216
240
  ...(status.presence === 'error' ? [{ id: 'resume', label: t('resumeAgent'), icon: _jsx(IconPlayOutline16, {}) }] : []),
217
241
  ...(status.availability === 'unavailable' ? [{ id: 'restart', label: t('restartAgent'), icon: _jsx(IconRefreshOutline16, {}) }] : []),
218
- { id: 'clear-context', label: t('clearContextAgent'), icon: _jsx(IconNewChatOutline16, {}), danger: true, disabled: !contextClearable },
219
- ...(!contextClearable ? [{ type: 'label', id: 'clear-context-reason', text: status.presence === 'working' ? t('clearContextWorkingReason') : t('clearContextUnavailableReason') }] : []),
220
242
  { id: 'archive', label: t('archiveAgent'), icon: _jsx(IconArchiveOutline20, { size: 16 }), danger: true },
221
243
  ], onSelect: (id) => {
222
244
  if (id === 'edit')
223
245
  setEditing(true);
224
- else if (id === 'clear-context')
225
- setClearing(true);
226
246
  else if (id === 'archive')
227
247
  setArchiving(true);
228
248
  else
229
249
  void recover();
230
- }, 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 }) }) })), archiving && (_jsx(Modal, { open: true, onClose: () => { setArchiving(false); }, title: t('archiveAgentTitle', { name: status.member.handle }), closeLabel: t('close'), contentClassName: createCss.dialogContent, footer: _jsxs(_Fragment, { children: [_jsx(Button, { variant: "outline", onClick: () => { setArchiving(false); }, children: t('cancel') }), _jsx(Button, { variant: "primary", onClick: () => { setArchiving(false); void archive(); }, children: t('archiveAgentConfirm') })] }), children: _jsx("p", { className: createCss.error, children: t('archiveAgentNotice', { name: status.member.handle }) }) })), editing && (_jsx(AgentEditorDialog, { status: status, updateMember: updateMember, loadModels: loadModels, onCommitted: onUpdated, onClose: () => { setEditing(false); }, t: t }))] }));
250
+ }, onOpenChange: setMenuOpen }) })] }), rowAlert !== undefined && _jsx("div", { className: css.rowAlert, role: "alert", children: rowAlert }), archiving && (_jsx(Modal, { open: true, onClose: () => { setArchiving(false); }, title: t('archiveAgentTitle', { name: status.member.handle }), closeLabel: t('close'), contentClassName: createCss.dialogContent, footer: _jsxs(_Fragment, { children: [_jsx(Button, { variant: "outline", onClick: () => { setArchiving(false); }, children: t('cancel') }), _jsx(Button, { variant: "primary", onClick: () => { setArchiving(false); void archive(); }, children: t('archiveAgentConfirm') })] }), children: _jsx("p", { className: createCss.error, children: t('archiveAgentNotice', { name: status.member.handle }) }) })), editing && (_jsx(AgentEditorDialog, { status: status, updateMember: updateMember, loadModels: loadModels, onCommitted: onUpdated, onClose: () => { setEditing(false); }, t: t }))] }));
231
251
  }
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Fragment, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
3
- import { MarkdownText, MessageText, Modal } from '@deepseek-ai/dsh-client-ui-primitives';
3
+ import { MarkdownText, Modal } from '@deepseek-ai/dsh-client-ui-primitives';
4
4
  import { cachedAttachmentDataUrl, formatByteSize, loadAttachmentDataUrl } from "./attachment-preview.js";
5
5
  import { cachedResolvedTaskRef, resolveUnknownTaskRefs, useResolvedTaskRefVersion } from "./task-refs.js";
6
6
  import { formatMessageTime, isSingleBrandedRef, memberHue, planMessageBody, shouldClampMessage, splitBrandedRefs, splitMentionNames } from "./team-formatters.js";
@@ -90,7 +90,7 @@ export function TeamMessage({ senderName, memberId, human, body, occurredAt, men
90
90
  ? _jsx("span", { className: css.mention, children: segment.text }, index)
91
91
  : _jsx(Fragment, { children: renderRefs(segment.text, onOpenRef, taskLabel, refLabel) }, index)) })
92
92
  : plan.render === 'literal'
93
- ? _jsx("div", { className: css.messageText, children: onOpenRef === undefined ? _jsx(MessageText, { text: displayBody }) : renderRefs(displayBody, onOpenRef, taskLabel, refLabel) })
93
+ ? _jsx("div", { className: css.messageText, children: onOpenRef === undefined ? displayBody : renderRefs(displayBody, onOpenRef, taskLabel, refLabel) })
94
94
  : _jsx("div", { ref: markdownRef, className: css.messageMarkdown, children: _jsx(MarkdownText, { text: displayBody, labels: markdownLabels }, `${displayBody}:${onOpenRef === undefined ? 'literal' : 'refs'}`) });
95
95
  return (_jsxs("article", { className: css.messageRow, "data-human": human || undefined, "data-grouped": grouped || undefined, children: [_jsx("div", { className: css.messageIdentity, style: avatarStyle, "aria-hidden": "true", children: senderName.replace('@', '').slice(0, 1).toUpperCase() }), _jsxs("div", { className: css.messageBody, children: [(!grouped || showGroupedTime === true) && (_jsxs("div", { className: css.nameRow, children: [!grouped && _jsx("strong", { ...(senderTitle === undefined ? {} : { title: senderTitle }), children: senderName }), occurredAt !== undefined && _jsx("span", { className: css.messageTime, children: formatMessageTime(occurredAt) })] })), clampable ? _jsx("div", { className: clamped ? css.messageClamp : undefined, children: bodyNode }) : bodyNode, clampable && (_jsx("button", { type: "button", className: css.messageExpand, "data-message-expand": "true", "aria-expanded": expanded, onClick: () => { setExpanded(value => !value); }, children: expanded ? (t?.('collapseMessage') ?? 'Show less') : (t?.('expandMessage') ?? 'Show more') })), (plan.fallbackNames.length > 0 || plan.fallbackRefs.length > 0) && (_jsxs("div", { className: css.mentionsRow, children: [plan.fallbackNames.map(name => _jsxs("span", { className: css.mention, children: ["@", name] }, name)), plan.fallbackRefs.map(ref => {
96
96
  const resolved = cachedResolvedTaskRef(ref);
@@ -18,7 +18,7 @@ function factKey(fact) {
18
18
  return fact.kind === 'message' ? `message:${fact.message.messageRef}` : `activity:${fact.activity.activityRef}`;
19
19
  }
20
20
  function messageFact(message, mentions = []) {
21
- return { kind: 'message', sequence: message.sequence, message, mentions };
21
+ return { kind: 'message', sequence: message.sequence, message, mentions, occurredAt: message.occurredAt };
22
22
  }
23
23
  function mergeFacts(...groups) {
24
24
  const byKey = new Map();
@@ -480,7 +480,7 @@ export function TeamThreadPage(props) {
480
480
  setProjection(current => current === undefined ? current
481
481
  : { ...current, task: committed.task, thread: committed.thread });
482
482
  setCurrentFacts(current => {
483
- const merged = mergeFacts(current, [{ kind: 'activity', sequence: committed.activity.sequence, activity: committed.activity }]);
483
+ const merged = mergeFacts(current, [{ kind: 'activity', sequence: committed.activity.sequence, activity: committed.activity, occurredAt: committed.receipt.occurredAt }]);
484
484
  currentFactsRef.current = merged;
485
485
  return merged;
486
486
  });
@@ -527,7 +527,7 @@ export function TeamThreadPage(props) {
527
527
  const committed = result.value;
528
528
  setProjection(current => current === undefined ? current : { ...current, task: committed.task, thread: committed.thread, claims: committed.claims });
529
529
  setCurrentFacts(current => {
530
- const merged = mergeFacts(current, [{ kind: 'activity', sequence: committed.activity.sequence, activity: committed.activity }]);
530
+ const merged = mergeFacts(current, [{ kind: 'activity', sequence: committed.activity.sequence, activity: committed.activity, occurredAt: committed.receipt.occurredAt }]);
531
531
  currentFactsRef.current = merged;
532
532
  return merged;
533
533
  });
@@ -586,7 +586,7 @@ export function TeamThreadPage(props) {
586
586
  if (result.value.kind === 'committed') {
587
587
  const committed = result.value;
588
588
  setCurrentFacts(current => {
589
- const merged = mergeFacts(current, [{ kind: 'message', sequence: committed.message.sequence, message: committed.message, mentions: [...recipients].sort() }]);
589
+ const merged = mergeFacts(current, [{ kind: 'message', sequence: committed.message.sequence, message: committed.message, mentions: [...recipients].sort(), occurredAt: committed.receipt.occurredAt }]);
590
590
  currentFactsRef.current = merged;
591
591
  return merged;
592
592
  });
@@ -1,3 +1,3 @@
1
1
  import type { TeamSidebarProps } from './slots.ts';
2
- export declare function TeamWorkspaceBrowser({ wide, expandSidebar, navigation, selectWorkspace, selectChannel, t, useWorkspaces, loadMembers, subscribeChanges, addMember, loadChannels, createChannel, updateChannel, archiveChannel, updateMember, recoverMember, clearMemberContext, archiveMember, joinChannel, removeChannelMember, loadModels, openMemberSession }: TeamSidebarProps): import("react").JSX.Element;
2
+ export declare function TeamWorkspaceBrowser({ wide, expandSidebar, navigation, selectWorkspace, selectChannel, t, useWorkspaces, loadMembers, subscribeChanges, addMember, loadChannels, createChannel, updateChannel, archiveChannel, updateMember, recoverMember, archiveMember, joinChannel, removeChannelMember, loadModels, openMemberSession }: TeamSidebarProps): import("react").JSX.Element;
3
3
  //# sourceMappingURL=TeamWorkspaceBrowser.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"TeamWorkspaceBrowser.d.ts","sourceRoot":"","sources":["../../../src/client/TeamWorkspaceBrowser.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAUlD,wBAAgB,oBAAoB,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,UAAU,EAAE,eAAe,EAAE,aAAa,EAAE,CAAC,EAAE,aAAa,EAAE,WAAW,EAAE,gBAAgB,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,cAAc,EAAE,YAAY,EAAE,aAAa,EAAE,kBAAkB,EAAE,aAAa,EAAE,WAAW,EAAE,mBAAmB,EAAE,UAAU,EAAE,iBAAiB,EAAE,EAAE,gBAAgB,+BA8DlX"}
1
+ {"version":3,"file":"TeamWorkspaceBrowser.d.ts","sourceRoot":"","sources":["../../../src/client/TeamWorkspaceBrowser.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAUlD,wBAAgB,oBAAoB,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,UAAU,EAAE,eAAe,EAAE,aAAa,EAAE,CAAC,EAAE,aAAa,EAAE,WAAW,EAAE,gBAAgB,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,cAAc,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,WAAW,EAAE,mBAAmB,EAAE,UAAU,EAAE,iBAAiB,EAAE,EAAE,gBAAgB,+BA8D9V"}
@@ -7,7 +7,7 @@ import { useSidebarSectionOpen, setSidebarSectionOpen } from "./sidebar-sections
7
7
  import { TeamAgentsPanel } from "./TeamAgentsPanel.js";
8
8
  import { TeamChannelsPanel } from "./TeamChannelsPanel.js";
9
9
  import css from './sidebar.module.css';
10
- export function TeamWorkspaceBrowser({ wide, expandSidebar, navigation, selectWorkspace, selectChannel, t, useWorkspaces, loadMembers, subscribeChanges, addMember, loadChannels, createChannel, updateChannel, archiveChannel, updateMember, recoverMember, clearMemberContext, archiveMember, joinChannel, removeChannelMember, loadModels, openMemberSession }) {
10
+ export function TeamWorkspaceBrowser({ wide, expandSidebar, navigation, selectWorkspace, selectChannel, t, useWorkspaces, loadMembers, subscribeChanges, addMember, loadChannels, createChannel, updateChannel, archiveChannel, updateMember, recoverMember, archiveMember, joinChannel, removeChannelMember, loadModels, openMemberSession }) {
11
11
  const navigationState = useSyncExternalStore(navigation.subscribe, navigation.getSnapshot, navigation.getSnapshot);
12
12
  const workspaces = useWorkspaces(state => state.items);
13
13
  const selected = navigationState.workspaceId;
@@ -39,5 +39,5 @@ export function TeamWorkspaceBrowser({ wide, expandSidebar, navigation, selectWo
39
39
  if (!wide) {
40
40
  return _jsxs("nav", { className: css.railWorkspace, "aria-label": t('workspaceSections'), children: [_jsx(Tooltip, { label: t('channels'), side: "right", children: _jsx("button", { type: "button", className: css.railButton, "aria-label": t('channels'), onClick: () => { setPendingSection('channels'); expandSidebar(); }, children: _jsx(IconListPenOutline16, { size: 16 }) }) }), _jsx(Tooltip, { label: t('agents'), side: "right", children: _jsx("button", { type: "button", className: css.railButton, "aria-label": t('agents'), onClick: () => { setPendingSection('agents'); expandSidebar(); }, children: _jsx(IconAgentPresetOutline16, { size: 16 }) }) })] });
41
41
  }
42
- return _jsxs("section", { className: css.workspaceBrowser, "aria-label": t('workspaces'), children: [_jsx(TeamSidebarSection, { title: t('workspaces'), open: workspacesOpen, onToggle: open => { setSidebarSectionOpen(undefined, 'workspaces', open); }, children: _jsxs("div", { className: css.workspaceList, children: [workspaces.map(workspace => _jsx(TeamWorkspaceRow, { workspaceId: workspace.workspaceId, title: workspace.title, path: workspace.path, selected: workspace.workspaceId === selectedId, current: workspace.workspaceId === selectedId && overviewIsCurrent, onSelect: selectWorkspace }, workspace.workspaceId)), workspaces.length === 0 && _jsx("p", { className: css.emptyState, children: t('empty') })] }) }), selectedId !== undefined && _jsxs("div", { className: css.workspaceSection, children: [_jsx("div", { ref: channelsRef, children: _jsx(TeamChannelsPanel, { workspaceId: selectedId, loadMembers: loadMembers, loadChannels: loadChannels, subscribeChanges: subscribeChanges, createChannel: createChannel, updateChannel: updateChannel, archiveChannel: archiveChannel, joinChannel: joinChannel, removeChannelMember: removeChannelMember, creatingAgents: creatingAgents.filter(request => request.workspaceId === selectedId), ...(navigationState.memberSessionId !== undefined || navigationState.channelRef === undefined ? {} : { selectedChannelRef: navigationState.channelRef }), selectChannel: selectChannel, t: t }, selectedId) }), _jsx("div", { ref: agentsRef, children: _jsx(TeamAgentsPanel, { workspaceId: selectedId, loadMembers: loadMembers, subscribeChanges: subscribeChanges, addMember: addMember, updateMember: updateMember, recoverMember: recoverMember, clearMemberContext: clearMemberContext, archiveMember: archiveMember, loadModels: loadModels, ...(navigationState.memberSessionId === undefined ? {} : { memberSessionId: navigationState.memberSessionId }), openMemberSession: openMemberSession, onCreatingChange: (request, creating) => { setCreatingAgents(current => creating ? [...current.filter(item => item.requestId !== request.requestId), request] : current.filter(item => item.requestId !== request.requestId)); }, t: t }, selectedId) })] })] });
42
+ return _jsxs("section", { className: css.workspaceBrowser, "aria-label": t('workspaces'), children: [_jsx(TeamSidebarSection, { title: t('workspaces'), open: workspacesOpen, onToggle: open => { setSidebarSectionOpen(undefined, 'workspaces', open); }, children: _jsxs("div", { className: css.workspaceList, children: [workspaces.map(workspace => _jsx(TeamWorkspaceRow, { workspaceId: workspace.workspaceId, title: workspace.title, path: workspace.path, selected: workspace.workspaceId === selectedId, current: workspace.workspaceId === selectedId && overviewIsCurrent, onSelect: selectWorkspace }, workspace.workspaceId)), workspaces.length === 0 && _jsx("p", { className: css.emptyState, children: t('empty') })] }) }), selectedId !== undefined && _jsxs("div", { className: css.workspaceSection, children: [_jsx("div", { ref: channelsRef, children: _jsx(TeamChannelsPanel, { workspaceId: selectedId, loadMembers: loadMembers, loadChannels: loadChannels, subscribeChanges: subscribeChanges, createChannel: createChannel, updateChannel: updateChannel, archiveChannel: archiveChannel, joinChannel: joinChannel, removeChannelMember: removeChannelMember, creatingAgents: creatingAgents.filter(request => request.workspaceId === selectedId), ...(navigationState.memberSessionId !== undefined || navigationState.channelRef === undefined ? {} : { selectedChannelRef: navigationState.channelRef }), selectChannel: selectChannel, t: t }, selectedId) }), _jsx("div", { ref: agentsRef, children: _jsx(TeamAgentsPanel, { workspaceId: selectedId, loadMembers: loadMembers, subscribeChanges: subscribeChanges, addMember: addMember, updateMember: updateMember, recoverMember: recoverMember, archiveMember: archiveMember, loadModels: loadModels, ...(navigationState.memberSessionId === undefined ? {} : { memberSessionId: navigationState.memberSessionId }), openMemberSession: openMemberSession, onCreatingChange: (request, creating) => { setCreatingAgents(current => creating ? [...current.filter(item => item.requestId !== request.requestId), request] : current.filter(item => item.requestId !== request.requestId)); }, t: t }, selectedId) })] })] });
43
43
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAoCnE,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAEhD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAK5C,OAAO,EAAU,KAAK,OAAO,EAAE,MAAM,cAAc,CAAA;AAEnD,YAAY,EAAE,QAAQ,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAA;AAC9F,YAAY,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAC3C,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAIhD,eAAO,MAAM,MAAM,UAElB,CAAA;AAED,OAAO,QAAQ,kCAAkC,CAAC;IAChD,UAAU,kBAAkB;QAC1B,IAAI,EAAE,OAAO,CAAA;KACd;CACF;AAED,OAAO,QAAQ,qBAAqB,CAAC;IACnC,UAAU,OAAO;QACf,cAAc,EAAE,cAAc,CAAA;QAC9B,UAAU,EAAE,cAAc,CAAA;KAC3B;CACF;AAyJD,wBAAsB,KAAK,CAAC,GAAG,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAI7D"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAoCnE,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAEhD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAK5C,OAAO,EAAU,KAAK,OAAO,EAAE,MAAM,cAAc,CAAA;AAEnD,YAAY,EAAE,QAAQ,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAA;AAC9F,YAAY,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAC3C,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAIhD,eAAO,MAAM,MAAM,UAElB,CAAA;AAED,OAAO,QAAQ,kCAAkC,CAAC;IAChD,UAAU,kBAAkB;QAC1B,IAAI,EAAE,OAAO,CAAA;KACd;CACF;AAED,OAAO,QAAQ,qBAAqB,CAAC;IACnC,UAAU,OAAO;QACf,cAAc,EAAE,cAAc,CAAA;QAC9B,UAAU,EAAE,cAAc,CAAA;KAC3B;CACF;AAmLD,wBAAsB,KAAK,CAAC,GAAG,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAI7D"}
@@ -12,7 +12,11 @@ const NS = 'team';
12
12
  export const inject = [
13
13
  'slots', 'workspaces', 'locale', 'remote', 'remote.session', 'sessions', 'connection', 'conversation',
14
14
  ];
15
- function registerModeShadow(ctx, navigation, changes, drafts, name, component, extraInject) {
15
+ function registerModeShadow(ctx, navigation, changes, drafts, name, component, extraInject,
16
+ // Keyed seats (`main`) address one panel by key; the reserved 'conversation'
17
+ // key is where the shipped Conversation registers, so the Team seat shadows
18
+ // that same panel instead of adding a second one.
19
+ entryKey) {
16
20
  // Stay in Team mode: the conversation shadow stands down for Member Session
17
21
  // views (see registerModeShadow), so the shipped conversation root renders
18
22
  // the selected Member Session inside the Team shell.
@@ -48,13 +52,14 @@ function registerModeShadow(ctx, navigation, changes, drafts, name, component, e
48
52
  let dispose;
49
53
  const reconcile = () => {
50
54
  const snapshot = navigation.getSnapshot();
51
- // The conversation seat yields to the shipped conversation root while a
55
+ // The main panel seat yields to the shipped conversation root while a
52
56
  // Member Session view is embedded; both sidebar seats stay shadowed so
53
57
  // the Team chrome keeps working around the Member conversation.
54
- const active = snapshot.mode === 'team' && !(name === 'conversation' && snapshot.memberSessionId !== undefined);
58
+ const active = snapshot.mode === 'team' && !(name === 'main' && snapshot.memberSessionId !== undefined);
55
59
  if (active && dispose === undefined) {
56
60
  dispose = ctx.slots.register({
57
61
  name,
62
+ ...(entryKey === undefined ? {} : { key: entryKey }),
58
63
  priority: -100,
59
64
  locale: NS,
60
65
  inject: () => ({
@@ -62,7 +67,7 @@ function registerModeShadow(ctx, navigation, changes, drafts, name, component, e
62
67
  ...extraInject?.(),
63
68
  ...navigation.actions(),
64
69
  ...sharedRemotes,
65
- ...(name === 'conversation' ? {
70
+ ...(name === 'main' ? {
66
71
  readThread: (request) => ctx.remote.agentTeam.readThread(request),
67
72
  loadThreadHistory: (request) => ctx.remote.agentTeam.threadHistory(request),
68
73
  threadObservations: (request) => ctx.remote.agentTeam.threadObservations(request),
@@ -107,6 +112,36 @@ function applyUi(ctx) {
107
112
  void disposeNavigation();
108
113
  void disposeDrafts();
109
114
  }, 'agent-team: navigation service');
115
+ // The one restore owner: leaving an embedded Member Session view must
116
+ // rebind the underlying current session, or the stale Member current later
117
+ // masks to undefined when the Host disposes that session (rollover) and
118
+ // the conversation seat remounts. Takeover is conditional — only when the
119
+ // current still IS the departed Member session — so a selection someone
120
+ // else made in the meantime survives. A dead return target clears instead
121
+ // of opening an unknown id.
122
+ ctx.effect(() => {
123
+ let previous = navigation.getSnapshot();
124
+ const restore = () => {
125
+ const snapshot = navigation.getSnapshot();
126
+ const departed = previous.memberSessionId;
127
+ const returnTo = previous.returnToSessionId;
128
+ previous = snapshot;
129
+ if (departed === undefined || snapshot.memberSessionId !== undefined)
130
+ return;
131
+ const sessions = ctx.sessions;
132
+ if (sessions.list.getSnapshot().current !== departed)
133
+ return;
134
+ if (returnTo !== undefined && sessions.list.getSnapshot().byId[returnTo] !== undefined)
135
+ sessions.open(returnTo);
136
+ else
137
+ sessions.clear();
138
+ };
139
+ const unsubscribe = navigation.subscribe(restore);
140
+ return () => {
141
+ unsubscribe();
142
+ restore();
143
+ };
144
+ }, 'agent-team: member session restore');
110
145
  const changes = new TeamChangeStream((request, signal) => ctx.remote.agentTeam.changes(request, signal));
111
146
  const loadMemberGroups = async () => {
112
147
  const workspaces = ctx.workspaces.list.getSnapshot().items;
@@ -129,26 +164,19 @@ function applyUi(ctx) {
129
164
  inject: () => ({
130
165
  navigation,
131
166
  ...navigation.actions(),
132
- // The footer is the only surface that leaves Team mode; it also closes
133
- // an embedded Member Session view, restoring the session the Human came
134
- // from so the ordinary shell never strands them inside a Member Session.
167
+ // The footer is the only surface that leaves Team mode; closing the
168
+ // embedded Member Session view rebinds the underlying current through
169
+ // the same root-scope restore owner, so there is exactly one restore
170
+ // path and no double open.
135
171
  leaveTeam: () => {
136
- const snapshot = navigation.getSnapshot();
137
- if (snapshot.memberSessionId === undefined) {
138
- navigation.actions().leaveTeam();
139
- return;
140
- }
141
- const returnTo = snapshot.returnToSessionId;
142
172
  navigation.actions().exitMemberSession();
143
- if (returnTo !== undefined)
144
- ctx.sessions.open(returnTo);
145
173
  navigation.actions().leaveTeam();
146
174
  },
147
175
  loadMemberGroups,
148
176
  }),
149
177
  }, TeamFooterAction));
150
178
  registerModeShadow(ctx, navigation, changes, drafts, 'sidebar.workspaces', TeamWorkspaceBrowser);
151
- registerModeShadow(ctx, navigation, changes, drafts, 'conversation', TeamConversation);
179
+ registerModeShadow(ctx, navigation, changes, drafts, 'main', TeamConversation, undefined, 'conversation');
152
180
  registerModeShadow(ctx, navigation, changes, drafts, 'sidebar.settings', TeamSettings, () => ({ loadMemberGroups }));
153
181
  }
154
182
  export async function apply(ctx) {
@@ -41,13 +41,6 @@ export declare const zh: {
41
41
  readonly restartAgent: "重启";
42
42
  readonly restartStillUnavailable: "重启已执行,成员仍不可用:{diagnostic}";
43
43
  readonly restartFailed: "重启执行失败:{message}";
44
- readonly clearContextAgent: "从全新上下文开始";
45
- readonly clearContextWorkingReason: "成员正在工作中,完成后才能清空上下文";
46
- readonly clearContextUnavailableReason: "成员当前不可用,恢复在线且空闲后才能清空上下文";
47
- readonly clearContextTitle: "从全新上下文开始:{name}";
48
- readonly clearContextNotice: "将结束 {name} 当前的会话上下文并从空白开始:旧对话会归档保留在会话记录中。{name} 的身份、私有记忆与 notes、频道和会话绑定都保持不变,后续协作从新上下文继续累积。";
49
- readonly clearContextConfirm: "开始全新上下文";
50
- readonly clearContextFailed: "清空上下文失败:{message}";
51
44
  readonly archiveAgent: "归档";
52
45
  readonly archiveAgentTitle: "归档 Agent:{name}";
53
46
  readonly archiveAgentNotice: "将把 {name} 从所有列表收起:会话与私有记忆保留在磁盘上、活跃 Claim 会释放,但暂无恢复入口。";
@@ -196,13 +189,6 @@ export declare const en: {
196
189
  readonly restartAgent: "Restart";
197
190
  readonly restartStillUnavailable: "Restart ran, but the Member is still unavailable: {diagnostic}";
198
191
  readonly restartFailed: "Restart failed: {message}";
199
- readonly clearContextAgent: "Start from new context";
200
- readonly clearContextWorkingReason: "The Member is working; clear once the current turn ends";
201
- readonly clearContextUnavailableReason: "The Member is unavailable; only an idle available Member can start from a new context";
202
- readonly clearContextTitle: "Start from new context: {name}";
203
- readonly clearContextNotice: "This ends {name}'s current session context and starts blank: the previous conversation is archived and stays in the session history. {name}'s identity, private memory and notes, channel and session bindings are untouched, and future collaboration accumulates from the new context.";
204
- readonly clearContextConfirm: "Start from new context";
205
- readonly clearContextFailed: "Failed to clear context: {message}";
206
192
  readonly archiveAgent: "Archive";
207
193
  readonly archiveAgentTitle: "Archive Agent: {name}";
208
194
  readonly archiveAgentNotice: "This hides {name} from every list: the session log and private memory stay on disk and active Claims release, but there is no restore entry point yet.";
@@ -1 +1 @@
1
- {"version":3,"file":"locales.d.ts","sourceRoot":"","sources":["../../../src/client/locales.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0JL,CAAA;AAEV,eAAO,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0JL,CAAA;AAEV,MAAM,MAAM,OAAO,GAAG,MAAM,OAAO,EAAE,CAAA"}
1
+ {"version":3,"file":"locales.d.ts","sourceRoot":"","sources":["../../../src/client/locales.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmJL,CAAA;AAEV,eAAO,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmJL,CAAA;AAEV,MAAM,MAAM,OAAO,GAAG,MAAM,OAAO,EAAE,CAAA"}
@@ -41,13 +41,6 @@ export const zh = {
41
41
  restartAgent: '重启',
42
42
  restartStillUnavailable: '重启已执行,成员仍不可用:{diagnostic}',
43
43
  restartFailed: '重启执行失败:{message}',
44
- clearContextAgent: '从全新上下文开始',
45
- clearContextWorkingReason: '成员正在工作中,完成后才能清空上下文',
46
- clearContextUnavailableReason: '成员当前不可用,恢复在线且空闲后才能清空上下文',
47
- clearContextTitle: '从全新上下文开始:{name}',
48
- clearContextNotice: '将结束 {name} 当前的会话上下文并从空白开始:旧对话会归档保留在会话记录中。{name} 的身份、私有记忆与 notes、频道和会话绑定都保持不变,后续协作从新上下文继续累积。',
49
- clearContextConfirm: '开始全新上下文',
50
- clearContextFailed: '清空上下文失败:{message}',
51
44
  archiveAgent: '归档',
52
45
  archiveAgentTitle: '归档 Agent:{name}',
53
46
  archiveAgentNotice: '将把 {name} 从所有列表收起:会话与私有记忆保留在磁盘上、活跃 Claim 会释放,但暂无恢复入口。',
@@ -196,13 +189,6 @@ export const en = {
196
189
  restartAgent: 'Restart',
197
190
  restartStillUnavailable: 'Restart ran, but the Member is still unavailable: {diagnostic}',
198
191
  restartFailed: 'Restart failed: {message}',
199
- clearContextAgent: 'Start from new context',
200
- clearContextWorkingReason: 'The Member is working; clear once the current turn ends',
201
- clearContextUnavailableReason: 'The Member is unavailable; only an idle available Member can start from a new context',
202
- clearContextTitle: 'Start from new context: {name}',
203
- clearContextNotice: 'This ends {name}\'s current session context and starts blank: the previous conversation is archived and stays in the session history. {name}\'s identity, private memory and notes, channel and session bindings are untouched, and future collaboration accumulates from the new context.',
204
- clearContextConfirm: 'Start from new context',
205
- clearContextFailed: 'Failed to clear context: {message}',
206
192
  archiveAgent: 'Archive',
207
193
  archiveAgentTitle: 'Archive Agent: {name}',
208
194
  archiveAgentNotice: 'This hides {name} from every list: the session log and private memory stay on disk and active Claims release, but there is no restore entry point yet.',
@@ -50,6 +50,11 @@ export type TeamSidebarProps = PropsRuntime<'sidebar.workspaces'> & PropsLocale<
50
50
  archiveChannel: (request: AgentTeamArchiveChannelRequest) => Promise<RemoteResult<AgentTeamArchiveChannelResult>>;
51
51
  updateMember: (request: AgentTeamUpdateMemberRequest) => Promise<RemoteResult<AgentTeamMemberResult>>;
52
52
  recoverMember: (request: AgentTeamRecoverMemberRequest) => Promise<RemoteResult<AgentTeamRecoverMemberResult>>;
53
+ /**
54
+ * Host clear-context remote kept as a hidden migration escape hatch.
55
+ * The visible row action is retired: Members manage their own context
56
+ * through the context_rollover tool (see docs/architecture.md).
57
+ */
53
58
  clearMemberContext: (request: AgentTeamClearMemberContextRequest) => Promise<RemoteResult<AgentTeamClearMemberContextResult>>;
54
59
  archiveMember: (request: AgentTeamArchiveMemberRequest) => Promise<RemoteResult<AgentTeamArchiveMemberResult>>;
55
60
  joinChannel: (request: AgentTeamJoinChannelRequest) => Promise<RemoteResult<AgentTeamJoinChannelResult>>;
@@ -60,7 +65,7 @@ export type TeamSidebarProps = PropsRuntime<'sidebar.workspaces'> & PropsLocale<
60
65
  openMemberSession: (sessionId: AgentTeamClientMemberStatus['member']['sessionId']) => void;
61
66
  selectedChannelRef?: AgentTeamChannelRef;
62
67
  };
63
- export type TeamConversationProps = PropsRuntime<'conversation'> & PropsLocale<'team'> & TeamNavigationActions & {
68
+ export type TeamConversationProps = PropsRuntime<'main'> & PropsLocale<'team'> & TeamNavigationActions & {
64
69
  navigation: TeamNavigationSource;
65
70
  /** Keyed composer draft cache; one store per Client context. */
66
71
  drafts: TeamDraftStore;
@@ -1 +1 @@
1
- {"version":3,"file":"slots.d.ts","sourceRoot":"","sources":["../../../src/client/slots.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"slots.d.ts","sourceRoot":"","sources":["../../../src/client/slots.ts"],"names":[],"mappings":"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"}
@@ -6,15 +6,20 @@ Model-facing tools for Agent Team Members. The package registers tools in the ca
6
6
 
7
7
  ## Tools
8
8
 
9
- - `team_inbox` lists bounded unread Thread summaries for the calling Member, ordered by direct work and then recency; Task status/number appear only where the Thread has a real Task overlay.
10
- - `team_thread` reads a Thread, pages history, follows, or unfollows. `threadRef` is primary; a `taskRef` is a Host alias only for released task-only Clients. `read` atomically returns the Thread anchor, optional current Task and Claim snapshot, bounded orientation facts, and one contiguous unread batch while advancing the durable watermark; `history` never changes read state.
11
- - `team_message` starts a top-level Thread or replies to an existing Thread. It defaults to a taskless Thread; pass `asTask: true` for atomic Task creation. Replies require the exact `baseRevision` and reject unread work before checking revision freshness.
12
- - `team_claim` lists or mutates the calling Member's Direction Claims through `list`, `claim`, `done`, and `release`; it applies only to real Tasks. Direction exclusion uses Unicode NFKC normalization, trim, whitespace compression, and deterministic case folding.
13
- - `team_view` discovers bounded, membership-authorized Channel, real Task, and Member summaries. It does not return Thread messages or activities.
9
+ - `team_inbox` lists bounded unread Thread summaries for the calling Member, ordered by direct work and then recency; Task standing appears only where the Thread has a real Task overlay. The header states total unread/direct counts and the number of Threads shown (with a truncation conclusion when unread work lies beyond the bounded list); each item shows its exact unread/direct counts, Channel ref, and Task standing. The footer routes reading to `team_thread read`; the render carries no revision and no write token.
10
+ - `team_thread` reads a Thread, pages history, follows, or unfollows. `threadRef` is primary; a `taskRef` is a Host alias only for released task-only Clients. The five actions render separately: `status`/`follow`/`unfollow` answer only the Attention question in one line; `read` renders outcome, Thread identity, orientation (full anchor when Host-supplied background is present, bounded anchor subject otherwise, never a duplicate of an in-facts anchor), active Claims only, the chronological facts with inline unread/direct markers, and a read-through/remaining-unread footer; `history` renders a historical page with the full anchor on a first page and the bounded subject on continuation pages, never current Claims or advice. `read` advances the durable watermark and is the only read-side source of a next-write token — rendered only when no unread remains; your own committed public mutations hand off a fresh token as well. Activity facts render structured — actor, Task ref, and the Claim refs each activity claimed, completed, accepted, or released. A read that acknowledges an unread acceptance of a still-done Task carries one `contextAdvice` block (usage, route budgets, the `min(128_000, handoffAt)` Task-boundary threshold, and one keep/rollover/handoff-now action); it is advisory only and degrades to an explicit `unavailable` line when measurement fails.
11
+ - `team_message` starts a top-level Thread, replies to an existing Thread, or sends a DM. It defaults to a taskless Thread; pass `asTask: true` for atomic Task creation. A committed start/reply renders one committed-verb outcome (Thread created / reply added) with the Message, Thread, and optional Task refs, and exactly one next-write token hand-off. Replies reject unread work before checking token freshness. Typed rejections begin `Not committed`, keep the structured refs and counts needed to reread and retry, and render no numeric revision or write token — recovery is read-and-reconsider. DMs distinguish `Delivered` from `Recorded, not delivered` (with the delivery note and a no-blind-duplicate warning).
12
+ - `team_claim` lists or mutates the calling Member's Direction Claims through `list`, `claim`, `done`, and `release`; it applies only to real Tasks. `list` renders the Task/Thread identity with active Claims only (the collision surface) and no write token. A committed mutation names its action (Claim created/completed/released), renders the authoritative affected Claim first, and hands off one next-write token. Rejections share the message rejection form. Direction exclusion uses Unicode NFKC normalization, trim, whitespace compression, and deterministic case folding.
13
+ - `team_view` is the address book: bounded, membership-authorized Channel, top-level Thread, and Member summaries current addresses, not a work queue. Threads are the sole paginated catalog: newest-first rows carrying threadRef, Channel ref, a bounded anchor subject, and Task standing inline (never a second Task index, never revision or message count). The cursor pages Thread rows only; continuation pages render Threads alone, and paging reaches every authorized top-level Thread, including taskless and off-page taskful ones.
14
+ - `context_rollover` schedules one rollover of the calling Member into a fresh context. The tool validates the bounded private `handoff` (plus optional `relatedFiles`, or a `checkpointRef` to return to a recorded checkpoint instead) against the Host, concludes the turn, and returns `status: 'scheduled'`; the Host performs the actual swap only after the successful tool result is durably appended. The `checkpointRef` copy is hardened on both the tool and parameter descriptions: omit it for ordinary generation changes and pressure-driven handoffs, and supply it only when citing the exact ref a `context_timeline` result listed as restorable — never a synthesized or guessed one. A `checkpointRef` that cannot succeed now — fabricated, unresolved, unattributable, nonshrinking, unmeasurable, over-budget, or blocked by multiple active Claims — rejects as a model-visible error result instead of a fake `scheduled`; the mutable guards (jobs, route limits) are revalidated at the swap seam, and a seam failure leaves the Member recoverable through a later-turn fresh rollover. `context_rollover` and `context_checkpoint` both conclude the Agent turn.
15
+ - `context_checkpoint` records one named checkpoint of the calling Member's current context. The durable checkpoint is the successful `tool/call`+`tool/result` pair the Session projection folds; the returned ref is deterministic from the Member Session identity plus the tool call id. It performs no lifecycle side effect in the tool body and concludes the turn: a checkpoint resolves at its containing turn's end, so the model records it as its final action of a completed unit of work.
16
+ - `context_timeline` returns one bounded structural view of the Member's context generations across the current Session and its archived ancestor lineage: recorded checkpoints and handoff/Team/compaction boundaries, with restorability reasons where a return cannot be proven safe. Structural only — no transcript content. A fresh `context_rollover` never requires consulting the timeline first.
14
17
 
15
18
  An Agent cannot silently enroll an unfollowed Agent through a mention; the Host returns `member_not_following`. Human confirmation is a separate Host/Client flow. Closed Tasks reject replies, Claims, and new Attention until a Human reopens them; taskless Threads have no Claim or Task-resolution mutation path.
16
19
 
17
- Canonical results expose stable refs, optional Task status, Thread revision, Claim history, Attention, and unread facts. Typed `unread_required` and `stale_revision` results include the fields needed to reread and retry deliberately. Tool execution resolves the exact live `exec.agent`; arguments cannot select or impersonate the actor or Workspace. Write request identity derives from sessionId plus tool callId. Team tools return to the model loop and never conclude the turn.
20
+ Every agent-facing render carries absolute event instants in the fixed Team coordination zone UTC+8 with an explicit offset (`2026-09-08T17:00:00+08:00`): `team_thread` fact lines and anchors stamp each fact with its committing operation's instant, `team_inbox` rows carry `newestOccurredAt`, `team_view` Thread rows carry `lastActivityAt`, notifications state `Occurred at:`, and committed mutations render `Committed at:` from the receipt. The same stored instant renders byte-identically on every reread path; only absolute timestamps are rendered, never relative text, and sequence and revision not wall-clock time remain the ordering authority.
21
+
22
+ Canonical results expose stable refs, optional Task status, Thread revision, Claim history, Attention, and unread facts as structured fields. The model-visible renders follow the action decision surface: the write token appears only on a fully drained `team_thread read` and a committed public mutation; browsing results (`team_view`, `team_inbox`, status/follow/unfollow, `history`, `team_claim list`) and all typed rejections render no revision and no token. Typed `unread_required` and `stale_revision` results keep the structured fields needed to reread and retry deliberately. Tool execution resolves the exact live `exec.agent`; arguments cannot select or impersonate the actor or Workspace. Write request identity derives from sessionId plus tool callId. `context_rollover` and `context_checkpoint` conclude the Agent turn (a rollover must not be followed by old-generation work, and a checkpoint resolves at its containing turn's end); every other Team tool returns to the model loop.
18
23
 
19
24
  The complete implemented protocol is documented in [`../../docs/team-collaboration.md`](../../docs/team-collaboration.md).
20
25