@wowyuarm/dsh-agent-team 0.1.8 → 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.
Files changed (66) hide show
  1. package/package.json +2 -1
  2. package/packages/agent-team/README.md +5 -3
  3. package/packages/agent-team/README.zh.md +5 -3
  4. package/packages/agent-team/lib/attachments.js +14 -4
  5. package/packages/agent-team/lib/context-management.js +379 -0
  6. package/packages/agent-team/lib/context-projection.js +574 -0
  7. package/packages/agent-team/lib/context-source.js +72 -0
  8. package/packages/agent-team/lib/index.js +1208 -62
  9. package/packages/agent-team/lib/ledger.js +222 -14
  10. package/packages/agent-team/lib/member-context.js +6 -2
  11. package/packages/agent-team/lib/member-runtime.js +159 -4
  12. package/packages/agent-team/lib/pressure-policy.js +200 -0
  13. package/packages/agent-team/lib/spec.js +18 -0
  14. package/packages/agent-team/lib/typert.host.js +122 -41
  15. package/packages/agent-team/lib/typert.remote-client.d.ts.map +1 -1
  16. package/packages/agent-team/lib/typert.remote-client.js +38 -25
  17. package/packages/agent-team/lib/types/attachments.d.ts +1 -1
  18. package/packages/agent-team/lib/types/attachments.d.ts.map +1 -1
  19. package/packages/agent-team/lib/types/context-management.d.ts +142 -0
  20. package/packages/agent-team/lib/types/context-management.d.ts.map +1 -0
  21. package/packages/agent-team/lib/types/context-projection.d.ts +219 -0
  22. package/packages/agent-team/lib/types/context-projection.d.ts.map +1 -0
  23. package/packages/agent-team/lib/types/context-source.d.ts +83 -0
  24. package/packages/agent-team/lib/types/context-source.d.ts.map +1 -0
  25. package/packages/agent-team/lib/types/index.d.ts +275 -2
  26. package/packages/agent-team/lib/types/index.d.ts.map +1 -1
  27. package/packages/agent-team/lib/types/ledger.d.ts +94 -6
  28. package/packages/agent-team/lib/types/ledger.d.ts.map +1 -1
  29. package/packages/agent-team/lib/types/member-context.d.ts.map +1 -1
  30. package/packages/agent-team/lib/types/member-runtime.d.ts +30 -2
  31. package/packages/agent-team/lib/types/member-runtime.d.ts.map +1 -1
  32. package/packages/agent-team/lib/types/pressure-policy.d.ts +106 -0
  33. package/packages/agent-team/lib/types/pressure-policy.d.ts.map +1 -0
  34. package/packages/agent-team/lib/types/spec.d.ts.map +1 -1
  35. package/packages/agent-team/lib/types/types/entities.d.ts +14 -1
  36. package/packages/agent-team/lib/types/types/entities.d.ts.map +1 -1
  37. package/packages/agent-team/lib/types/types/operations.d.ts +38 -3
  38. package/packages/agent-team/lib/types/types/operations.d.ts.map +1 -1
  39. package/packages/agent-team/lib/types/types/requests-results.d.ts +52 -1
  40. package/packages/agent-team/lib/types/types/requests-results.d.ts.map +1 -1
  41. package/packages/agent-team/preset/team-member/agent.cordis.yml +9 -1
  42. package/packages/client-agent-team/lib/client.js +314 -323
  43. package/packages/client-agent-team/lib/client.js.map +1 -1
  44. package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.d.ts +1 -2
  45. package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.d.ts.map +1 -1
  46. package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.js +61 -41
  47. package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.d.ts +1 -1
  48. package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.d.ts.map +1 -1
  49. package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.js +2 -2
  50. package/packages/client-agent-team/lib/types/client/index.d.ts.map +1 -1
  51. package/packages/client-agent-team/lib/types/client/index.js +34 -11
  52. package/packages/client-agent-team/lib/types/client/locales.d.ts +0 -14
  53. package/packages/client-agent-team/lib/types/client/locales.d.ts.map +1 -1
  54. package/packages/client-agent-team/lib/types/client/locales.js +0 -14
  55. package/packages/client-agent-team/lib/types/client/slots.d.ts +5 -0
  56. package/packages/client-agent-team/lib/types/client/slots.d.ts.map +1 -1
  57. package/packages/tool-agent-team/README.md +8 -5
  58. package/packages/tool-agent-team/README.zh.md +8 -5
  59. package/packages/tool-agent-team/lib/context-tools.js +179 -0
  60. package/packages/tool-agent-team/lib/index.js +135 -16
  61. package/packages/tool-agent-team/lib/types/context-tools.d.ts +16 -0
  62. package/packages/tool-agent-team/lib/types/context-tools.d.ts.map +1 -0
  63. package/packages/tool-agent-team/lib/types/index.d.ts.map +1 -1
  64. package/packages/agent-team/lib/auto-compaction.js +0 -201
  65. package/packages/agent-team/lib/types/auto-compaction.d.ts +0 -47
  66. package/packages/agent-team/lib/types/auto-compaction.d.ts.map +0 -1
@@ -0,0 +1,200 @@
1
+ /**
2
+ * Team-owned context pressure policy.
3
+ *
4
+ * The Team preset mounts `compaction-basic` with `auto: false`; this
5
+ * coordinator owns both policy entry points instead — the proactive handoff
6
+ * notice near the effective handoff budget and the forced CompactionEngine
7
+ * reduction before any request at or above the effective hard limit — while
8
+ * reusing the public CompactionEngine implementation. The hard-limit
9
+ * translation lives in exactly one method; no caller re-derives it.
10
+ *
11
+ * Fail-closed rule: at the hard limit, a compaction that no-ops, throws, is
12
+ * cancelled, or does not advance the durable surface must block the model
13
+ * request (reject the step) rather than knowingly submit over the Team limit.
14
+ * A blocked Member keeps its log and reports a recoverable error.
15
+ * @module @wowyuarm/dsh-agent-team/pressure-policy
16
+ */
17
+ import { CONTEXT_WINDOW_EXCEEDED_CODE } from '@deepseek-ai/dsh-llm';
18
+ import { createUserMessage } from '@deepseek-ai/dsh-llm';
19
+ import { CONTEXT_PRESSURE_NOTICE_SUMMARY } from "./context-management.js";
20
+ /** Plugin identity of the Agent Team Host, for the notice source. */
21
+ const AGENT_TEAM_PLUGIN_ID = '@wowyuarm/dsh-agent-team';
22
+ /** One pressure-notice text; concise, structured, and inside the reserve. */
23
+ export function contextPressureNoticeText(input) {
24
+ const claims = input.activeClaims.length === 0 ? 'none' : input.activeClaims.join(', ');
25
+ const jobs = input.runningJobs.length === 0 ? 'none' : `${input.runningJobs.length} running (collect or stop them before switching)`;
26
+ return [
27
+ `Context pressure: ${input.usageTokens} tokens measured; the handoff budget is ${input.handoffAt} and the hard limit is ${input.hardLimit}.`,
28
+ `Active Claims: ${claims}. Owner jobs: ${jobs}.`,
29
+ 'Finish the current atomic action, then call context_rollover with a handoff covering your objective, verified facts, and external side effects — a fresh context is the default path. Record anything durable in your private memory/notes first.',
30
+ ].join(' ');
31
+ }
32
+ /** Whether one user message is this policy's one-shot pressure notice. */
33
+ function isPressureNotice(message) {
34
+ const source = message.source;
35
+ return source?.plugin === AGENT_TEAM_PLUGIN_ID
36
+ && source?.summary === CONTEXT_PRESSURE_NOTICE_SUMMARY;
37
+ }
38
+ export class PressurePolicyCoordinator {
39
+ options;
40
+ /**
41
+ * Retry budget per agent for the current provider-overflow sequence.
42
+ * Process-only by design: a restart re-earns one sequence per chain.
43
+ */
44
+ overflowRetries = new Map();
45
+ disposed = false;
46
+ constructor(options) {
47
+ this.options = options;
48
+ }
49
+ /**
50
+ * The one-shot pressure notice is durable Session evidence, not process
51
+ * state: a `CONTEXT_PRESSURE_NOTICE_SUMMARY` notice already surfaced as a
52
+ * `user/message`, or still queued in a durable `agent/inbox/spliced`
53
+ * insert (a steered notice surfaces only at the next step boundary, and a
54
+ * Host restart replays the splice before surfacing), marks the current
55
+ * generation as already notified. A resume or restart stays quiet; a
56
+ * rollover starts a fresh Session whose own event span has no notice yet,
57
+ * which is exactly the documented re-arm.
58
+ */
59
+ noticeDelivered(agent) {
60
+ for (const event of agent.session.ownEvents()) {
61
+ if (event.type === 'user/message' && isPressureNotice(event.data))
62
+ return true;
63
+ if (event.type === 'agent/inbox/spliced' && event.data.inserted.some(isPressureNotice))
64
+ return true;
65
+ }
66
+ return false;
67
+ }
68
+ dispose() {
69
+ this.disposed = true;
70
+ this.overflowRetries.clear();
71
+ }
72
+ /** A successful assistant response ends any open overflow-recovery sequence. */
73
+ onAssistantMessage(agent) {
74
+ this.overflowRetries.delete(agent);
75
+ }
76
+ /**
77
+ * Pre-step policy for one Member agent: below the handoff budget nothing
78
+ * happens; at the handoff budget one structured notice per generation is
79
+ * steered into the running turn; at the hard limit the request is forced
80
+ * through compaction first and fails closed when that cannot be proven.
81
+ * Returns the decision for the step: `continue` forwards, `reject` blocks.
82
+ */
83
+ async onPreStep(agent, signal) {
84
+ if (this.disposed || signal.aborted)
85
+ return { kind: 'continue' };
86
+ const member = this.options.memberForAgent(agent);
87
+ if (member === undefined)
88
+ return { kind: 'continue' };
89
+ const limits = await this.options.limitsForAgent(agent);
90
+ if (limits === undefined) {
91
+ // A missing route capacity must be explicit, never an accidental
92
+ // unlimited policy: reject the step with a recoverable diagnostic.
93
+ const diagnostic = 'context pressure policy: the routed model capacity is unknown; refusing to forward a request without a bounded context budget';
94
+ this.options.failed(member.memberId, member.sessionId, diagnostic);
95
+ return { kind: 'reject' };
96
+ }
97
+ const { usageTokens, hardLimit, handoffAt } = limits;
98
+ if (usageTokens >= hardLimit) {
99
+ const outcome = await this.enforceHardLimit(agent, member.memberId, member.sessionId, signal);
100
+ return outcome ? { kind: 'continue' } : { kind: 'reject' };
101
+ }
102
+ if (usageTokens >= handoffAt && !this.noticeDelivered(agent)) {
103
+ const notice = createUserMessage({
104
+ content: [{ type: 'text', text: contextPressureNoticeText({
105
+ usageTokens, handoffAt, hardLimit,
106
+ activeClaims: this.options.activeClaimLabels(member.memberId),
107
+ runningJobs: this.options.runningJobLabels(member.memberId),
108
+ }) }],
109
+ source: { kind: 'plugin', plugin: AGENT_TEAM_PLUGIN_ID, form: 'notice', summary: CONTEXT_PRESSURE_NOTICE_SUMMARY },
110
+ });
111
+ try {
112
+ agent.steer(notice);
113
+ }
114
+ catch (error) {
115
+ this.options.log(`context pressure notice failed: ${error instanceof Error ? error.message : String(error)} (member ${member.memberId})`);
116
+ }
117
+ return { kind: 'notice' };
118
+ }
119
+ return { kind: 'continue' };
120
+ }
121
+ /**
122
+ * Provider-overflow recovery: one bounded compact-and-retry sequence per
123
+ * open failure chain. Returns whether the request may retry once.
124
+ */
125
+ async onRequestError(agent, failure, signal) {
126
+ if (this.disposed || signal.aborted)
127
+ return false;
128
+ if (failure.code !== CONTEXT_WINDOW_EXCEEDED_CODE)
129
+ return false;
130
+ const member = this.options.memberForAgent(agent);
131
+ if (member === undefined)
132
+ return false;
133
+ const retries = this.overflowRetries.get(agent) ?? 0;
134
+ if (retries >= 1)
135
+ return false;
136
+ const engine = this.options.compactionForAgent(agent);
137
+ if (engine === undefined)
138
+ return false;
139
+ const generation = agent.session.surface.replaceGeneration;
140
+ try {
141
+ await engine.compactIfNeeded(agent, 'context-overflow', signal);
142
+ }
143
+ catch (error) {
144
+ // Durable prune progress before a later summary failure justifies the
145
+ // single retry; cancellation never does.
146
+ if (!signal.aborted && agent.session.surface.replaceGeneration > generation) {
147
+ this.overflowRetries.set(agent, retries + 1);
148
+ return true;
149
+ }
150
+ this.options.log(`context-overflow recovery failed: ${error instanceof Error ? error.message : String(error)} (member ${member.memberId})`);
151
+ return false;
152
+ }
153
+ if (signal.aborted || agent.session.surface.replaceGeneration <= generation)
154
+ return false;
155
+ this.overflowRetries.set(agent, retries + 1);
156
+ return true;
157
+ }
158
+ /**
159
+ * The one Team hard-limit translation: force a CompactionEngine reduction
160
+ * in the current Agent/Session and prove it advanced the durable surface
161
+ * (or measurably reduced pressure) before continuing. Background jobs are
162
+ * untouched — compaction never cancels or discards them.
163
+ * @returns whether the request may proceed.
164
+ */
165
+ async enforceHardLimit(agent, memberId, sessionId, signal) {
166
+ const engine = this.options.compactionForAgent(agent);
167
+ if (engine === undefined) {
168
+ const diagnostic = 'context hard limit reached and compaction is unavailable in the Member scope; the request was blocked';
169
+ this.options.failed(memberId, sessionId, diagnostic);
170
+ return false;
171
+ }
172
+ const meter = agent.ctx.get('tokenMeter');
173
+ const before = meter?.measure(agent.session)?.totalTokens ?? Number.POSITIVE_INFINITY;
174
+ const generation = agent.session.surface.replaceGeneration;
175
+ let result;
176
+ try {
177
+ result = await engine.compactIfNeeded(agent, 'context-overflow', signal);
178
+ }
179
+ catch (error) {
180
+ const diagnostic = `context hard limit compaction failed: ${error instanceof Error ? error.message : String(error)}; the request was blocked`;
181
+ this.options.failed(memberId, sessionId, diagnostic);
182
+ return false;
183
+ }
184
+ if (signal.aborted)
185
+ return false;
186
+ const after = meter?.measure(agent.session)?.totalTokens ?? Number.POSITIVE_INFINITY;
187
+ const surfaceAdvanced = agent.session.surface.replaceGeneration > generation;
188
+ const pressureReduced = meter === undefined ? false : after < before;
189
+ if (!surfaceAdvanced && !pressureReduced) {
190
+ // No-op or unchanged replacement generation: fail closed rather than
191
+ // knowingly submit over the Team limit.
192
+ const diagnostic = result === null
193
+ ? 'context hard limit reached and no compactable range exists; the request was blocked'
194
+ : 'context hard limit compaction produced no measurable reduction; the request was blocked';
195
+ this.options.failed(memberId, sessionId, diagnostic);
196
+ return false;
197
+ }
198
+ return true;
199
+ }
200
+ }
@@ -5,6 +5,8 @@ const requestIdSchema = z.string().min(1).transform(value => value);
5
5
  const memberIdSchema = z.string().regex(/^member:[^:]+$/).transform(value => value);
6
6
  const workspaceIdSchema = z.string().min(1).transform(value => value);
7
7
  const sessionIdSchema = z.string().min(1).transform(value => value);
8
+ const sessionSeqSchema = z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER).transform(value => value);
9
+ const contextCheckpointRefSchema = z.string().regex(/^(context-checkpoint-[0-9a-f]{64}|team-boundary-[0-9a-f]{64})$/).transform(value => value);
8
10
  const channelRefSchema = z.string().regex(/^channel:[^:]+$/).transform(value => value);
9
11
  const messageRefSchema = z.string().regex(/^message:[^:]+$/).transform(value => value);
10
12
  const taskRefSchema = z.string().regex(/^task:[^:]+$/).transform(value => value);
@@ -181,6 +183,7 @@ const taskActivitySchema = z.object({
181
183
  kind: z.union([z.literal('promote'), z.literal('accept'), z.literal('close'), z.literal('reopen')]),
182
184
  releasedClaimRefs: z.array(claimRefSchema).min(1).optional(),
183
185
  completedClaimRefs: z.array(claimRefSchema).min(1).optional(),
186
+ acceptedClaimRefs: z.array(claimRefSchema).optional(),
184
187
  }).strict();
185
188
  const claimsReleasedActivitySchema = z.object({
186
189
  ...activityBase,
@@ -279,6 +282,21 @@ const storedAgentTeamOperationSchema = z.discriminatedUnion('kind', [
279
282
  kind: z.literal('team/member-session-renewed'),
280
283
  data: z.object({ member: memberSchema, previousSessionId: sessionIdSchema }).strict(),
281
284
  }).strict(),
285
+ z.object({
286
+ ...operationBase,
287
+ previousOperationId: operationIdSchema.nullable(),
288
+ kind: z.literal('team/member-session-rolled-over'),
289
+ data: z.object({
290
+ member: memberSchema,
291
+ previousSessionId: sessionIdSchema,
292
+ newSessionId: sessionIdSchema,
293
+ sourceSessionId: sessionIdSchema.optional(),
294
+ sourceThroughSeq: sessionSeqSchema.optional(),
295
+ handoffEventSeq: sessionSeqSchema,
296
+ checkpointRef: contextCheckpointRefSchema.optional(),
297
+ trigger: z.enum(['model', 'pressure']),
298
+ }).strict(),
299
+ }).strict(),
282
300
  z.object({
283
301
  ...operationBase,
284
302
  previousOperationId: operationIdSchema.nullable(),