@wowyuarm/dsh-agent-team 0.1.7 → 0.1.9
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/package.json +2 -1
- package/packages/agent-team/README.md +5 -3
- package/packages/agent-team/README.zh.md +5 -3
- package/packages/agent-team/core-skills/member-skill-manager/SKILL.md +2 -0
- package/packages/agent-team/lib/attachments.js +14 -4
- package/packages/agent-team/lib/context-management.js +379 -0
- package/packages/agent-team/lib/context-projection.js +574 -0
- package/packages/agent-team/lib/context-source.js +72 -0
- package/packages/agent-team/lib/index.js +1258 -54
- package/packages/agent-team/lib/ledger.js +357 -26
- package/packages/agent-team/lib/member-context.js +7 -3
- package/packages/agent-team/lib/member-runtime.js +159 -4
- package/packages/agent-team/lib/pressure-policy.js +200 -0
- package/packages/agent-team/lib/progress-nudge.js +320 -0
- package/packages/agent-team/lib/spec.js +18 -0
- package/packages/agent-team/lib/typert.host.js +124 -42
- package/packages/agent-team/lib/typert.remote-client.d.ts.map +1 -1
- package/packages/agent-team/lib/typert.remote-client.js +39 -25
- package/packages/agent-team/lib/types/attachments.d.ts +1 -1
- package/packages/agent-team/lib/types/attachments.d.ts.map +1 -1
- package/packages/agent-team/lib/types/context-management.d.ts +142 -0
- package/packages/agent-team/lib/types/context-management.d.ts.map +1 -0
- package/packages/agent-team/lib/types/context-projection.d.ts +219 -0
- package/packages/agent-team/lib/types/context-projection.d.ts.map +1 -0
- package/packages/agent-team/lib/types/context-source.d.ts +83 -0
- package/packages/agent-team/lib/types/context-source.d.ts.map +1 -0
- package/packages/agent-team/lib/types/index.d.ts +283 -2
- package/packages/agent-team/lib/types/index.d.ts.map +1 -1
- package/packages/agent-team/lib/types/ledger.d.ts +120 -7
- package/packages/agent-team/lib/types/ledger.d.ts.map +1 -1
- package/packages/agent-team/lib/types/member-context.d.ts.map +1 -1
- package/packages/agent-team/lib/types/member-runtime.d.ts +30 -2
- package/packages/agent-team/lib/types/member-runtime.d.ts.map +1 -1
- package/packages/agent-team/lib/types/pressure-policy.d.ts +106 -0
- package/packages/agent-team/lib/types/pressure-policy.d.ts.map +1 -0
- package/packages/agent-team/lib/types/progress-nudge.d.ts +136 -0
- package/packages/agent-team/lib/types/progress-nudge.d.ts.map +1 -0
- package/packages/agent-team/lib/types/spec.d.ts.map +1 -1
- package/packages/agent-team/lib/types/types/entities.d.ts +32 -1
- package/packages/agent-team/lib/types/types/entities.d.ts.map +1 -1
- package/packages/agent-team/lib/types/types/operations.d.ts +38 -3
- package/packages/agent-team/lib/types/types/operations.d.ts.map +1 -1
- package/packages/agent-team/lib/types/types/requests-results.d.ts +54 -1
- package/packages/agent-team/lib/types/types/requests-results.d.ts.map +1 -1
- package/packages/agent-team/preset/team-member/agent.cordis.yml +10 -2
- package/packages/client-agent-team/lib/client.js +283 -398
- package/packages/client-agent-team/lib/client.js.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.d.ts +1 -2
- package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.js +61 -41
- package/packages/client-agent-team/lib/types/client/TeamChannelPage.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamChannelPage.js +3 -7
- package/packages/client-agent-team/lib/types/client/TeamComposer.d.ts +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 +37 -27
- package/packages/client-agent-team/lib/types/client/TeamConversation.d.ts +1 -1
- package/packages/client-agent-team/lib/types/client/TeamConversation.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamConversation.js +2 -2
- package/packages/client-agent-team/lib/types/client/TeamMemberAvatar.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamMemberAvatar.js +3 -2
- package/packages/client-agent-team/lib/types/client/TeamMessage.js +5 -0
- package/packages/client-agent-team/lib/types/client/TeamPresenceDot.d.ts +2 -2
- package/packages/client-agent-team/lib/types/client/TeamPresenceDot.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamPresenceDot.js +4 -6
- package/packages/client-agent-team/lib/types/client/TeamStateDot.d.ts +14 -0
- package/packages/client-agent-team/lib/types/client/TeamStateDot.d.ts.map +1 -0
- package/packages/client-agent-team/lib/types/client/TeamStateDot.js +15 -0
- package/packages/client-agent-team/lib/types/client/TeamThreadPage.d.ts +1 -0
- package/packages/client-agent-team/lib/types/client/TeamThreadPage.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamThreadPage.js +41 -16
- 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 +2 -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 +36 -78
- package/packages/client-agent-team/lib/types/client/locales.d.ts +0 -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 +0 -16
- package/packages/client-agent-team/lib/types/client/sidebar-drag.d.ts +1 -2
- package/packages/client-agent-team/lib/types/client/sidebar-drag.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/slots.d.ts +8 -1
- package/packages/client-agent-team/lib/types/client/slots.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/task-refs.d.ts +7 -1
- package/packages/client-agent-team/lib/types/client/task-refs.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/task-refs.js +25 -3
- package/packages/client-agent-team/lib/types/client/team-formatters.d.ts +11 -10
- 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 +14 -11
- package/packages/tool-agent-team/README.md +8 -5
- package/packages/tool-agent-team/README.zh.md +8 -5
- package/packages/tool-agent-team/lib/context-tools.js +179 -0
- package/packages/tool-agent-team/lib/index.js +144 -25
- package/packages/tool-agent-team/lib/types/context-tools.d.ts +16 -0
- package/packages/tool-agent-team/lib/types/context-tools.d.ts.map +1 -0
- package/packages/tool-agent-team/lib/types/index.d.ts.map +1 -1
- package/packages/agent-team/lib/auto-compaction.js +0 -201
- package/packages/agent-team/lib/types/auto-compaction.d.ts +0 -47
- package/packages/agent-team/lib/types/auto-compaction.d.ts.map +0 -1
- package/packages/client-agent-team/lib/types/client/TeamMemberDock.d.ts +0 -12
- package/packages/client-agent-team/lib/types/client/TeamMemberDock.d.ts.map +0 -1
- package/packages/client-agent-team/lib/types/client/TeamMemberDock.js +0 -13
- package/packages/client-agent-team/lib/types/client/member-session-input.d.ts +0 -20
- package/packages/client-agent-team/lib/types/client/member-session-input.d.ts.map +0 -1
- package/packages/client-agent-team/lib/types/client/member-session-input.js +0 -110
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import type { AgentTeamActivity, AgentTeamClaim, AgentTeamMemberId, AgentTeamTask, AgentTeamTaskRef } from '@wowyuarm/dsh-agent-team/types';
|
|
2
2
|
import type { TeamConversationProps } from './slots.ts';
|
|
3
|
+
import type { TeamStateDotState } from './TeamStateDot.tsx';
|
|
3
4
|
export declare function formatTaskStatus(status: AgentTeamTask['status'], t: TeamConversationProps['t']): string;
|
|
4
5
|
export declare function formatClaimState(state: AgentTeamClaim['state'], t: TeamConversationProps['t']): string;
|
|
5
6
|
/**
|
|
6
|
-
* Status indicator
|
|
7
|
-
* variants; every status renders a dot so
|
|
8
|
-
* language — todo is a hollow ring (not started), closed a
|
|
9
|
-
* (archived).
|
|
7
|
+
* Status indicator for a Task status, the dot every Task surface renders.
|
|
8
|
+
* Active states map to StateDot variants; every status renders a dot so they
|
|
9
|
+
* share one shape language — todo is a hollow ring (not started), closed a
|
|
10
|
+
* quiet gray dot (archived).
|
|
10
11
|
*/
|
|
11
|
-
export declare function taskStatusDot(status: AgentTeamTask['status']):
|
|
12
|
+
export declare function taskStatusDot(status: AgentTeamTask['status']): TeamStateDotState;
|
|
12
13
|
/** One-line title snippet derived from the Task's root Message body. */
|
|
13
14
|
export declare function formatTaskTitle(body: string): string;
|
|
14
15
|
/** Deterministic avatar hue for one Member identity; stable across sessions and themes. */
|
|
@@ -21,11 +22,11 @@ export interface RefSegment {
|
|
|
21
22
|
}
|
|
22
23
|
/**
|
|
23
24
|
* Split a literal text run into plain and branded-ref segments. The pattern
|
|
24
|
-
* anchors on the fixed ref prefixes plus
|
|
25
|
-
* containing a colon never linkifies; a doubled colon from
|
|
26
|
-
* tolerated. Segment refs are always canonical, so resolution
|
|
27
|
-
* work regardless of how the ref was spelled; text without any
|
|
28
|
-
* back as one untouched segment.
|
|
25
|
+
* anchors on the fixed ref prefixes plus a UUID shape (full or abbreviated),
|
|
26
|
+
* so ordinary prose containing a colon never linkifies; a doubled colon from
|
|
27
|
+
* model output is tolerated. Segment refs are always canonical, so resolution
|
|
28
|
+
* and navigation work regardless of how the ref was spelled; text without any
|
|
29
|
+
* ref comes back as one untouched segment.
|
|
29
30
|
*/
|
|
30
31
|
export declare function splitBrandedRefs(text: string): readonly RefSegment[];
|
|
31
32
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"team-formatters.d.ts","sourceRoot":"","sources":["../../../src/client/team-formatters.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,iBAAiB,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAA;AAC3I,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"team-formatters.d.ts","sourceRoot":"","sources":["../../../src/client/team-formatters.ts"],"names":[],"mappings":"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"}
|
|
@@ -15,13 +15,13 @@ export function formatClaimState(state, t) {
|
|
|
15
15
|
}[state]);
|
|
16
16
|
}
|
|
17
17
|
/**
|
|
18
|
-
* Status indicator
|
|
19
|
-
* variants; every status renders a dot so
|
|
20
|
-
* language — todo is a hollow ring (not started), closed a
|
|
21
|
-
* (archived).
|
|
18
|
+
* Status indicator for a Task status, the dot every Task surface renders.
|
|
19
|
+
* Active states map to StateDot variants; every status renders a dot so they
|
|
20
|
+
* share one shape language — todo is a hollow ring (not started), closed a
|
|
21
|
+
* quiet gray dot (archived).
|
|
22
22
|
*/
|
|
23
23
|
export function taskStatusDot(status) {
|
|
24
|
-
return { todo: 'todo', in_progress: 'ongoing', in_review: 'warning', done: 'done', closed: '
|
|
24
|
+
return { todo: 'todo', in_progress: 'ongoing', in_review: 'warning', done: 'done', closed: 'quiet' }[status];
|
|
25
25
|
}
|
|
26
26
|
/** One-line title snippet derived from the Task's root Message body. */
|
|
27
27
|
export function formatTaskTitle(body) {
|
|
@@ -35,7 +35,10 @@ export function memberHue(memberId) {
|
|
|
35
35
|
hash = (hash * 31 + memberId.charCodeAt(index)) % 360;
|
|
36
36
|
return hash;
|
|
37
37
|
}
|
|
38
|
-
|
|
38
|
+
// Full UUIDs and abbreviated forms (prefix plus the first 6+ hex chars, with
|
|
39
|
+
// or without the original hyphens) both match; resolution decides whether an
|
|
40
|
+
// abbreviation is real, so unresolvable matches stay plain text.
|
|
41
|
+
const BRANDED_REF_PATTERN = /\b(task|channel|thread):{1,2}[0-9a-f]{6,}(?:-[0-9a-f]{1,})*\b/gi;
|
|
39
42
|
/**
|
|
40
43
|
* Canonical form of one matched ref: models occasionally double the colon or
|
|
41
44
|
* uppercase the UUID when citing a ref in prose, while Host lookups and
|
|
@@ -46,11 +49,11 @@ function canonicalBrandedRef(match) {
|
|
|
46
49
|
}
|
|
47
50
|
/**
|
|
48
51
|
* Split a literal text run into plain and branded-ref segments. The pattern
|
|
49
|
-
* anchors on the fixed ref prefixes plus
|
|
50
|
-
* containing a colon never linkifies; a doubled colon from
|
|
51
|
-
* tolerated. Segment refs are always canonical, so resolution
|
|
52
|
-
* work regardless of how the ref was spelled; text without any
|
|
53
|
-
* back as one untouched segment.
|
|
52
|
+
* anchors on the fixed ref prefixes plus a UUID shape (full or abbreviated),
|
|
53
|
+
* so ordinary prose containing a colon never linkifies; a doubled colon from
|
|
54
|
+
* model output is tolerated. Segment refs are always canonical, so resolution
|
|
55
|
+
* and navigation work regardless of how the ref was spelled; text without any
|
|
56
|
+
* ref comes back as one untouched segment.
|
|
54
57
|
*/
|
|
55
58
|
export function splitBrandedRefs(text) {
|
|
56
59
|
const segments = [];
|
|
@@ -6,15 +6,18 @@ 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.
|
|
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. The render states total unread/direct counts (including Threads beyond the bounded list) and each item's exact unread/direct counts, Channel ref, and Task status.
|
|
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. Activity facts render structured — actor, Task ref, and the Claim refs each activity claimed, completed, accepted, or released — and the header states the Task's status/resolution on taskful Threads. The Claims snapshot renders one line per Claim, the anchor renders whenever it is not already among the facts, message facts carry unread/direct markers, a read footer states read-through sequence and remaining unread count, and a history footer states the cursor and hasMore for paging. 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 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. A committed start renders the new Thread ref (and Task ref when taskful); typed rejections render the refs and counts needed to reread and retry.
|
|
12
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,
|
|
13
|
+
- `team_view` discovers bounded, membership-authorized Channel, top-level Thread, Task, and Member summaries. Thread entries carry refs, revision, message count, and Task status where applicable; it does not return Thread messages or activities. The render ends with the shared cursor and a hasMore verdict; Task rows carry their Thread and Channel refs with the current revision.
|
|
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.
|
|
20
|
+
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. `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
21
|
|
|
19
22
|
The complete implemented protocol is documented in [`../../docs/team-collaboration.md`](../../docs/team-collaboration.md).
|
|
20
23
|
|
|
@@ -6,15 +6,18 @@
|
|
|
6
6
|
|
|
7
7
|
## 工具
|
|
8
8
|
|
|
9
|
-
- `team_inbox` 列出调用方 Member 的有界未读 Thread 摘要,先按 direct work、再按最近活动排序;只有 Thread 存在真实 Task overlay 时才出现 Task status/number。
|
|
10
|
-
- `team_thread` 读取 Thread、分页历史、follow 或 unfollow。`threadRef` 是主身份;`taskRef` 只对 released task-only Client 是 Host alias。`read` 原子返回 Thread anchor、可选的当前 Task 与 Claim 快照、有界背景和一批连续未读事实,并推进持久 watermark;`history` 不改变 read 状态。
|
|
11
|
-
- `team_message` 创建顶层 Thread,或回复已有 Thread。它默认创建 taskless Thread;传入 `asTask: true` 才原子创建 Task。Reply 必须携带准确的 `baseRevision`,并在检查 revision 前先处理未读门禁。
|
|
9
|
+
- `team_inbox` 列出调用方 Member 的有界未读 Thread 摘要,先按 direct work、再按最近活动排序;只有 Thread 存在真实 Task overlay 时才出现 Task status/number。渲染给出 unread/direct 总数(含有界列表之外的 Threads),每个条目显示精确的 unread/direct 计数、Channel ref 与 Task status。
|
|
10
|
+
- `team_thread` 读取 Thread、分页历史、follow 或 unfollow。`threadRef` 是主身份;`taskRef` 只对 released task-only Client 是 Host alias。`read` 原子返回 Thread anchor、可选的当前 Task 与 Claim 快照、有界背景和一批连续未读事实,并推进持久 watermark;`history` 不改变 read 状态。Activity facts 结构化渲染——actor、Task ref,以及每条 activity claim、完成、接受或 release 的 Claim refs——taskful Thread 的 header 呈现 Task status/resolution。Claims 快照逐条渲染,anchor 未出现在 facts 中时也会渲染,message facts 携带 unread/direct 标记,read 页脚给出 read-through sequence 与剩余 unread 计数,history 页脚给出 cursor 与 hasMore 供翻页。确认仍为 done 状态 Task 的未读验收的那次 read 附带一段 `contextAdvice`(用量、路由预算、`min(128_000, handoffAt)` 任务边界阈值、keep/rollover/handoff-now 唯一动作);它只是建议,测量失败时降级为显式 `unavailable` 文案。
|
|
11
|
+
- `team_message` 创建顶层 Thread,或回复已有 Thread。它默认创建 taskless Thread;传入 `asTask: true` 才原子创建 Task。Reply 必须携带准确的 `baseRevision`,并在检查 revision 前先处理未读门禁。commit 的 start 渲染新 Thread ref(taskful 时含 Task ref);类型化拒绝渲染重读与重试所需的 refs 与计数。
|
|
12
12
|
- `team_claim` 通过 `list`、`claim`、`done`、`release` 读取或修改调用方 Member 的 Direction Claim;它只适用于真实 Task。Direction 互斥键执行 Unicode NFKC normalization、trim、空白压缩和确定性大小写折叠。
|
|
13
|
-
- `team_view` 发现有界、按 membership 授权的 Channel
|
|
13
|
+
- `team_view` 发现有界、按 membership 授权的 Channel、顶层 Thread、Task 和 Member 摘要。Thread 条目携带 refs、revision、message 数及适用的 Task status;不返回 Thread Message 或 Activity。渲染以共享 cursor 与 hasMore 结论收尾;Task 行携带其 Thread、Channel ref 与当前 revision。
|
|
14
|
+
- `context_rollover` 为调用方 Member 安排一次进入全新上下文的 rollover。工具向 Host 校验有界的私有 `handoff`(及可选 `relatedFiles`;传入 `checkpointRef` 则改为回返到已记录的 checkpoint),结束当前 turn 并返回 `status: 'scheduled'`;Host 只在成功的 tool result 持久落盘后才执行真正的换窗。`checkpointRef` 在工具与参数两级 description 上做了 copy hardening:普通续代与压力换窗必须省略,只有引用 `context_timeline` 结果中列为 restorable 的精确 ref 时才提供——绝不合成或猜测。当下不可能成功的 `checkpointRef`——伪造、未 resolve、无法归属、不缩减、不可测量、超预算或被多个 active Claim 阻塞——以 model-visible 的 error result 拒绝,而不是返回假 `scheduled`;可变 guards(jobs、route limits)在换窗 seam 复查,seam 失败后 Member 仍可通过后续 turn 的显式 fresh rollover 恢复。`context_rollover` 与 `context_checkpoint` 都会结束 Agent turn(换窗后不得再接旧代工作;checkpoint 在其所属 turn 结束时 resolve)。
|
|
15
|
+
- `context_checkpoint` 为调用的 Member 记录一个命名的当前上下文 checkpoint。durable checkpoint 就是 Session projection 折叠的成功 `tool/call`+`tool/result` 对;返回的 ref 由 Member Session 身份加 tool call id 确定性派生。工具体不做 lifecycle 副作用,但会结束 turn:checkpoint 在其所属 turn 结束时 resolve,因此模型把它作为一个完整工作单元的最后动作来记录。
|
|
16
|
+
- `context_timeline` 返回该 Member 跨当前 Session 与已归档祖先 lineage 的上下文代际有界结构视图:已记录的 checkpoints 与 handoff/Team/compaction 边界,无法证明可安全回返的条目携带拒绝原因。仅结构信息——不含任何 transcript 正文。fresh 的 `context_rollover` 从不需要先查 timeline。
|
|
14
17
|
|
|
15
18
|
Agent 不能通过 mention 静默把另一个 unfollowed Agent 加入 Thread;Host 返回 `member_not_following`。Human confirmation 属于单独的 Host/Client 流程。Closed Task 在 Human reopen 前拒绝 reply、Claim 和新的 Attention;taskless Thread 没有 Claim 或 Task resolution mutation path。
|
|
16
19
|
|
|
17
|
-
Canonical result 包含稳定 refs、可选的 Task status、Thread revision、Claim history、Attention 和未读 facts。类型化的 `unread_required` 与 `stale_revision` 结果包含重新读取和审慎重试所需字段。工具执行通过准确的 live `exec.agent` 解析 actor;参数不能选择或冒充 actor 或 Workspace。写操作的 request identity 由 sessionId 与 tool callId
|
|
20
|
+
Canonical result 包含稳定 refs、可选的 Task status、Thread revision、Claim history、Attention 和未读 facts。类型化的 `unread_required` 与 `stale_revision` 结果包含重新读取和审慎重试所需字段。工具执行通过准确的 live `exec.agent` 解析 actor;参数不能选择或冒充 actor 或 Workspace。写操作的 request identity 由 sessionId 与 tool callId 派生。`context_rollover` 与 `context_checkpoint` 结束 Agent turn;其余 Team tools 将结果返回模型循环,不主动结束 turn。
|
|
18
21
|
|
|
19
22
|
完整的已实现协议见 [`../../docs/team-collaboration.md`](../../docs/team-collaboration.md)。
|
|
20
23
|
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Model-facing context-management tools for Team Members. Thin adapters
|
|
3
|
+
* only: validation runs in the Host adapter, the successful result is the
|
|
4
|
+
* durable intent, and every lifecycle side effect — generation swap, Session
|
|
5
|
+
* creation, inbox handling — happens in the Host coordinator after the
|
|
6
|
+
* result is durably appended. `concludeTurn()` rides the success result of
|
|
7
|
+
* `context_rollover` and `context_checkpoint`, so sibling calls settle in model
|
|
8
|
+
* order before the turn closes.
|
|
9
|
+
* @module @wowyuarm/dsh-agent-team/context-tools
|
|
10
|
+
*/
|
|
11
|
+
import { defineTool } from '@deepseek-ai/dsh-tools';
|
|
12
|
+
function service(agent) {
|
|
13
|
+
const host = agent.ctx.get('agentTeam');
|
|
14
|
+
if (host === undefined)
|
|
15
|
+
throw new Error('Agent Team Host is unavailable');
|
|
16
|
+
return host;
|
|
17
|
+
}
|
|
18
|
+
function member(agent) {
|
|
19
|
+
const current = service(agent).memberForAgent(agent);
|
|
20
|
+
if (current === undefined)
|
|
21
|
+
throw new Error('team tool requires an active Team Member');
|
|
22
|
+
return current;
|
|
23
|
+
}
|
|
24
|
+
const MAX_HANDOFF_CHARS = 32 * 1024;
|
|
25
|
+
const MAX_RELATED_FILES = 32;
|
|
26
|
+
const contextRollover = defineTool({
|
|
27
|
+
name: 'context_rollover',
|
|
28
|
+
description: 'context_rollover: end this context generation and continue as the same Team Member in a new one. Without checkpointRef the context starts fresh and empty, seeded only by your handoff — this is the default, cheapest path at context pressure, and the right choice for ordinary generation changes and pressure-driven handoffs. Omit checkpointRef unless you are deliberately returning to a restorable anchor you just selected from a context_timeline result: supply a checkpointRef only when that timeline listed it as restorable and you are citing its exact ref — never synthesize, guess, or reconstruct one; a fabricated ref rejects as a model-visible error. Write the handoff as one prose string covering: current objective and every active Thread/Claim; verified facts and evidence; inferences and unresolved conflicts; current external side effects and their verification state (files, git, jobs, browser state, remote calls); one explicit next step. A context change never rolls back any external effect — describe current state so the next generation can re-verify. Record anything worth keeping in your private memory/notes first. Collect or stop your background jobs before calling: a rollover is refused while jobs this Member owns are still running.',
|
|
29
|
+
parameters: {
|
|
30
|
+
handoff: { type: 'string', required: true, description: 'Prose handoff for the next context generation: objective, active Threads/Claims, verified facts, inferences, external side effects and their verification state, next step.' },
|
|
31
|
+
checkpointRef: { type: 'string', description: 'Optional. Omit for the default fresh rollover — ordinary generation changes and pressure-driven handoffs must not supply this. Provide it only to resume from a restorable anchor you just selected in a context_timeline result, citing that exact ref; never synthesize or guess a ref.' },
|
|
32
|
+
relatedFiles: { type: 'array', items: { type: 'object', additionalProperties: false, properties: { path: { type: 'string', required: true }, reason: { type: 'string', required: true } } }, description: 'Workspace paths the next generation should look at first, each with one reason.' },
|
|
33
|
+
},
|
|
34
|
+
output: {
|
|
35
|
+
schema: { type: 'object', additionalProperties: false, properties: {
|
|
36
|
+
mode: { type: 'string', required: true }, status: { type: 'string', required: true },
|
|
37
|
+
} },
|
|
38
|
+
render: (_args, value) => [{ type: 'text', text: `Context rollover scheduled (${value.mode}). Finish this turn; the Host switches you to the next context generation afterward.` }],
|
|
39
|
+
},
|
|
40
|
+
async execute(args, exec) {
|
|
41
|
+
const agent = exec.agent;
|
|
42
|
+
if (agent === undefined)
|
|
43
|
+
throw new Error('context_rollover requires an Agent session');
|
|
44
|
+
const current = member(agent);
|
|
45
|
+
const host = service(agent);
|
|
46
|
+
const handoff = typeof args.handoff === 'string' ? args.handoff : '';
|
|
47
|
+
if (handoff.trim() === '')
|
|
48
|
+
throw new Error('context_rollover requires a non-empty handoff');
|
|
49
|
+
if (handoff.length > MAX_HANDOFF_CHARS)
|
|
50
|
+
throw new Error(`context_rollover handoff exceeds ${MAX_HANDOFF_CHARS} characters`);
|
|
51
|
+
const relatedFilesInput = Array.isArray(args.relatedFiles) ? args.relatedFiles : [];
|
|
52
|
+
if (relatedFilesInput.length > MAX_RELATED_FILES)
|
|
53
|
+
throw new Error(`context_rollover accepts at most ${MAX_RELATED_FILES} related files`);
|
|
54
|
+
// Tool argument validation is layered: the Harness schema (required and
|
|
55
|
+
// type checks) rejects at the execute boundary, and this body adds the
|
|
56
|
+
// checks the schema cannot express — each related file is validated
|
|
57
|
+
// here, so a blank path/reason rejects instead of seeding the handoff
|
|
58
|
+
// envelope with empty fields.
|
|
59
|
+
const relatedFiles = [];
|
|
60
|
+
for (const [index, entry] of relatedFilesInput.entries()) {
|
|
61
|
+
if (typeof entry !== 'object' || entry === null)
|
|
62
|
+
throw new Error(`context_rollover relatedFiles[${index}] must be an object with path and reason`);
|
|
63
|
+
const candidate = entry;
|
|
64
|
+
if (typeof candidate.path !== 'string' || candidate.path.trim() === '')
|
|
65
|
+
throw new Error(`context_rollover relatedFiles[${index}].path must be a non-empty string`);
|
|
66
|
+
if (typeof candidate.reason !== 'string' || candidate.reason.trim() === '')
|
|
67
|
+
throw new Error(`context_rollover relatedFiles[${index}].reason must be a non-empty string`);
|
|
68
|
+
relatedFiles.push({ path: candidate.path, reason: candidate.reason });
|
|
69
|
+
}
|
|
70
|
+
// Tool schemas are open at the root (Harness parameter specs set no
|
|
71
|
+
// `additionalProperties: false`), so an undeclared shape can still reach
|
|
72
|
+
// the body. Any supplied value that is not a non-empty string rejects
|
|
73
|
+
// here rather than being treated as absent — an absent ref means fresh,
|
|
74
|
+
// which is not what the model asked for.
|
|
75
|
+
const raw = args;
|
|
76
|
+
const suppliedRef = Object.hasOwn(raw, 'checkpointRef') ? raw.checkpointRef : undefined;
|
|
77
|
+
if (suppliedRef !== undefined && (typeof suppliedRef !== 'string' || suppliedRef.trim() === '')) {
|
|
78
|
+
throw new Error('context_rollover checkpointRef must be a non-empty string when supplied');
|
|
79
|
+
}
|
|
80
|
+
const checkpointRef = typeof suppliedRef === 'string' ? suppliedRef.trim() : undefined;
|
|
81
|
+
const outcome = await host.requestNewContext(agent, {
|
|
82
|
+
memberId: current.memberId,
|
|
83
|
+
...(checkpointRef === undefined || checkpointRef === '' ? {} : { checkpointRef: checkpointRef }),
|
|
84
|
+
...(relatedFiles.length === 0 ? {} : { relatedFiles }),
|
|
85
|
+
});
|
|
86
|
+
exec.concludeTurn();
|
|
87
|
+
return { mode: outcome.mode, status: 'scheduled' };
|
|
88
|
+
},
|
|
89
|
+
});
|
|
90
|
+
const contextCheckpoint = defineTool({
|
|
91
|
+
name: 'context_checkpoint',
|
|
92
|
+
description: 'Record a named checkpoint at the end of the current turn: an opaque, private, restorable anchor for this Member\'s context lineage. Use it before a noisy or risky phase — a broad refactor, an experiment whose value is unproven — when returning to the current completed state may later be useful. The checkpoint resolves only when this turn completes; the Host continues work in the next turn automatically. A checkpoint never snapshots files, git, jobs, or any external state: returning to one (via context_rollover with its checkpointRef) resumes the conversation prefix and nothing else. Checkpoints are private context structure, not Team facts, and are never visible to other Members.',
|
|
93
|
+
parameters: {
|
|
94
|
+
name: { type: 'string', required: true, description: 'Short semantic label for this checkpoint, shown in context_timeline.' },
|
|
95
|
+
},
|
|
96
|
+
output: {
|
|
97
|
+
schema: { type: 'object', additionalProperties: false, properties: {
|
|
98
|
+
checkpointRef: { type: 'string', required: true }, name: { type: 'string', required: true },
|
|
99
|
+
} },
|
|
100
|
+
// The ref is the selection surface for `context_rollover`: rendering only the
|
|
101
|
+
// name left the model with no legitimate way to cite the anchor it just
|
|
102
|
+
// recorded. Renders are the only channel results reach the model through.
|
|
103
|
+
render: (_args, value) => [{ type: 'text', text: `Checkpoint recorded: ${value.name} (ref: ${value.checkpointRef}). Work continues in the next turn; the Host will continue automatically.` }],
|
|
104
|
+
},
|
|
105
|
+
async execute(args, exec) {
|
|
106
|
+
const agent = exec.agent;
|
|
107
|
+
if (agent === undefined)
|
|
108
|
+
throw new Error('context_checkpoint requires an Agent session');
|
|
109
|
+
const current = member(agent);
|
|
110
|
+
const host = service(agent);
|
|
111
|
+
const name = typeof args.name === 'string' ? args.name : '';
|
|
112
|
+
// The Host validates binding, running-turn fencing, and the name budget;
|
|
113
|
+
// the durable checkpoint is the successful call/result pair the Session
|
|
114
|
+
// projection folds, and the ref derives from the tool call id.
|
|
115
|
+
const outcome = host.recordCheckpointForAgent(agent, { memberId: current.memberId, callId: exec.callId, name });
|
|
116
|
+
exec.concludeTurn();
|
|
117
|
+
return { checkpointRef: outcome.checkpointRef, name: outcome.name };
|
|
118
|
+
},
|
|
119
|
+
});
|
|
120
|
+
const contextTimeline = defineTool({
|
|
121
|
+
name: 'context_timeline',
|
|
122
|
+
description: 'Inspect the bounded structural timeline of this Member\'s context lineage: named checkpoints you recorded, Team boundaries (effect anchors: a committed team_message, a successful team_claim mutation, a follow/unfollow — rendered as `Team message`, `Team task claim change`, `Team attention change`; plus a Thread\'s first delivered notice, rendered as `First arrival: <refs>`), handoff and compaction boundaries, and the current head — across the current generation and its archived ancestors. Only the first delivery of a Thread\'s facts anchors; later re-deliveries and reminders produce no boundary. Returns approximate retained/discarded token estimates, current usage against the pressure budget, the Threads whose facts entered your context by each anchor, and which anchors are restorable. A Team boundary is a selectable default checkpoint exactly when it resolved at a completed turn and exactly one Thread is attributable to it; unattributable or multi-Thread boundaries state their reason. Structural only: no transcript content. A fresh context_rollover (no checkpointRef) never requires consulting this timeline first — call it directly. Use this tool only when you specifically intend a checkpointRef return: to pick the smallest sufficient ref, or to confirm that a fresh handoff is the better path when every anchor is marked non-restorable.',
|
|
123
|
+
parameters: {
|
|
124
|
+
limit: { type: 'number', description: 'Maximum number of items to return (default 12, at most 24).' },
|
|
125
|
+
},
|
|
126
|
+
output: {
|
|
127
|
+
schema: { type: 'object', additionalProperties: false, properties: {
|
|
128
|
+
usageTokens: { type: 'number', required: true },
|
|
129
|
+
hardLimit: { type: 'number', required: true },
|
|
130
|
+
handoffAt: { type: 'number', required: true },
|
|
131
|
+
items: { type: 'array', required: true, items: { type: 'object', additionalProperties: false, properties: {
|
|
132
|
+
checkpointRef: { type: 'string', required: true },
|
|
133
|
+
name: { type: 'string', required: true },
|
|
134
|
+
source: { type: 'string', required: true },
|
|
135
|
+
retainedTokens: { type: 'number', required: true },
|
|
136
|
+
discardedTokens: { type: 'number', required: true },
|
|
137
|
+
affectedThreads: { type: 'array', required: true, items: { type: 'string' } },
|
|
138
|
+
restorable: { type: 'boolean', required: true },
|
|
139
|
+
reason: { type: 'string' },
|
|
140
|
+
sourceSessionId: { type: 'string' },
|
|
141
|
+
} } },
|
|
142
|
+
} },
|
|
143
|
+
// The item list is the whole decision surface: without each anchor's
|
|
144
|
+
// ref, label, source, size estimates, affected Threads, and
|
|
145
|
+
// restorable/reason verdict, the model cannot pick a `checkpointRef` for
|
|
146
|
+
// `context_rollover` — the summary line alone left the tool unusable for
|
|
147
|
+
// seeded returns. The Host bounds items (default 12, at most 24), so this
|
|
148
|
+
// list cannot grow unbounded.
|
|
149
|
+
render: (_args, value) => {
|
|
150
|
+
const lines = [`Context timeline: ${value.usageTokens} tokens used (handoff at ${value.handoffAt}, hard limit ${value.hardLimit}). ${value.items.length} item(s):`];
|
|
151
|
+
for (const item of value.items) {
|
|
152
|
+
const threads = item.affectedThreads.length === 0 ? 'no Threads' : `Threads ${item.affectedThreads.join(', ')}`;
|
|
153
|
+
const size = `retained ~${item.retainedTokens}, discarded ~${item.discardedTokens}`;
|
|
154
|
+
const restorable = item.restorable
|
|
155
|
+
? `restorable — ref: ${item.checkpointRef}`
|
|
156
|
+
: `not restorable — ${item.reason ?? 'no reason given'}`;
|
|
157
|
+
lines.push(`- ${item.name} [source: ${item.source}] (${size}; ${threads}) — ${restorable}`);
|
|
158
|
+
}
|
|
159
|
+
return [{ type: 'text', text: lines.join('\n') }];
|
|
160
|
+
},
|
|
161
|
+
},
|
|
162
|
+
async execute(args, exec) {
|
|
163
|
+
const agent = exec.agent;
|
|
164
|
+
if (agent === undefined)
|
|
165
|
+
throw new Error('context_timeline requires an Agent session');
|
|
166
|
+
const current = member(agent);
|
|
167
|
+
const host = service(agent);
|
|
168
|
+
const limit = typeof args.limit === 'number' ? args.limit : undefined;
|
|
169
|
+
const result = await host.contextTimelineForAgent(agent, { memberId: current.memberId, ...(limit === undefined ? {} : { limit }) });
|
|
170
|
+
// The Host result is deeply immutable; the tool output contract carries
|
|
171
|
+
// plain arrays, so re-shape without any semantic change.
|
|
172
|
+
return { usageTokens: result.usageTokens, hardLimit: result.hardLimit, handoffAt: result.handoffAt, items: result.items.map(item => ({ ...item, affectedThreads: [...item.affectedThreads] })) };
|
|
173
|
+
},
|
|
174
|
+
});
|
|
175
|
+
export function registerContextTools(ctx) {
|
|
176
|
+
ctx.tools.register(contextRollover);
|
|
177
|
+
ctx.tools.register(contextCheckpoint);
|
|
178
|
+
ctx.tools.register(contextTimeline);
|
|
179
|
+
}
|