@wowyuarm/dsh-agent-team 0.1.15 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -4
- package/README.zh.md +8 -4
- package/cordis.patch.yml +26 -12
- package/package.json +52 -47
- package/packages/agent-team/lib/attachments.js +63 -4
- package/packages/agent-team/lib/compaction-engine.js +18 -0
- package/packages/agent-team/lib/context-continuity-host.js +198 -4
- package/packages/agent-team/lib/context-judge.js +150 -0
- package/packages/agent-team/lib/context-source.js +11 -6
- package/packages/agent-team/lib/environment-check.js +102 -0
- package/packages/agent-team/lib/human-profile.js +23 -37
- package/packages/agent-team/lib/index.js +510 -99
- package/packages/agent-team/lib/installed-manifest.js +32 -0
- package/packages/agent-team/lib/invariant.js +36 -12
- package/packages/agent-team/lib/ledger.js +37 -1
- package/packages/agent-team/lib/member-context.js +2 -4
- package/packages/agent-team/lib/member-runtime.js +2 -1
- package/packages/agent-team/lib/member-time-context.js +2 -4
- package/packages/agent-team/lib/recovery.js +53 -4
- package/packages/agent-team/lib/typert.host.js +225 -54
- package/packages/agent-team/lib/typert.remote-client.d.ts +5 -1
- package/packages/agent-team/lib/typert.remote-client.d.ts.map +1 -1
- package/packages/agent-team/lib/typert.remote-client.js +127 -39
- package/packages/agent-team/lib/types/attachments.d.ts +32 -2
- package/packages/agent-team/lib/types/attachments.d.ts.map +1 -1
- package/packages/agent-team/lib/types/compaction-engine.d.ts +19 -0
- package/packages/agent-team/lib/types/compaction-engine.d.ts.map +1 -0
- package/packages/agent-team/lib/types/context-continuity-host.d.ts +131 -4
- package/packages/agent-team/lib/types/context-continuity-host.d.ts.map +1 -1
- package/packages/agent-team/lib/types/context-judge.d.ts +82 -0
- package/packages/agent-team/lib/types/context-judge.d.ts.map +1 -0
- package/packages/agent-team/lib/types/context-source.d.ts +7 -4
- package/packages/agent-team/lib/types/context-source.d.ts.map +1 -1
- package/packages/agent-team/lib/types/environment-check.d.ts +66 -0
- package/packages/agent-team/lib/types/environment-check.d.ts.map +1 -0
- package/packages/agent-team/lib/types/human-profile.d.ts +21 -27
- package/packages/agent-team/lib/types/human-profile.d.ts.map +1 -1
- package/packages/agent-team/lib/types/index.d.ts +281 -18
- package/packages/agent-team/lib/types/index.d.ts.map +1 -1
- package/packages/agent-team/lib/types/installed-manifest.d.ts +16 -0
- package/packages/agent-team/lib/types/installed-manifest.d.ts.map +1 -0
- package/packages/agent-team/lib/types/invariant.d.ts +27 -5
- package/packages/agent-team/lib/types/invariant.d.ts.map +1 -1
- package/packages/agent-team/lib/types/ledger.d.ts +12 -0
- 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 +1 -1
- package/packages/agent-team/lib/types/member-runtime.d.ts.map +1 -1
- package/packages/agent-team/lib/types/member-time-context.d.ts.map +1 -1
- package/packages/agent-team/lib/types/recovery.d.ts +19 -6
- package/packages/agent-team/lib/types/recovery.d.ts.map +1 -1
- package/packages/agent-team/lib/types/types/entities.d.ts +1 -8
- package/packages/agent-team/lib/types/types/entities.d.ts.map +1 -1
- package/packages/agent-team/lib/types/types/requests-results.d.ts +94 -2
- package/packages/agent-team/lib/types/types/requests-results.d.ts.map +1 -1
- package/packages/agent-team/lib/types/types.d.ts +9 -0
- package/packages/agent-team/lib/types/types.d.ts.map +1 -1
- package/packages/client-agent-team/lib/client.js +1264 -383
- package/packages/client-agent-team/lib/client.js.map +1 -1
- package/packages/client-agent-team/lib/types/client/EnvironmentCheck.d.ts +18 -0
- package/packages/client-agent-team/lib/types/client/EnvironmentCheck.d.ts.map +1 -0
- package/packages/client-agent-team/lib/types/client/EnvironmentCheck.js +58 -0
- package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.js +0 -5
- package/packages/client-agent-team/lib/types/client/TeamPresenceDot.d.ts +1 -1
- package/packages/client-agent-team/lib/types/client/TeamPresenceDot.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamPresenceDot.js +2 -7
- package/packages/client-agent-team/lib/types/client/TeamSettingsSection.d.ts +26 -0
- package/packages/client-agent-team/lib/types/client/TeamSettingsSection.d.ts.map +1 -0
- package/packages/client-agent-team/lib/types/client/TeamSettingsSection.js +195 -0
- package/packages/client-agent-team/lib/types/client/attachment-preview.d.ts +7 -11
- package/packages/client-agent-team/lib/types/client/attachment-preview.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/attachment-preview.js +13 -3
- package/packages/client-agent-team/lib/types/client/context-judge.d.ts +64 -0
- package/packages/client-agent-team/lib/types/client/context-judge.d.ts.map +1 -0
- package/packages/client-agent-team/lib/types/client/context-judge.js +78 -0
- package/packages/client-agent-team/lib/types/client/environment-check.d.ts +65 -0
- package/packages/client-agent-team/lib/types/client/environment-check.d.ts.map +1 -0
- package/packages/client-agent-team/lib/types/client/environment-check.js +78 -0
- package/packages/client-agent-team/lib/types/client/index.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/index.js +84 -11
- package/packages/client-agent-team/lib/types/client/judge-form.d.ts +99 -0
- package/packages/client-agent-team/lib/types/client/judge-form.d.ts.map +1 -0
- package/packages/client-agent-team/lib/types/client/judge-form.js +208 -0
- package/packages/client-agent-team/lib/types/client/locales.d.ts +70 -14
- package/packages/client-agent-team/lib/types/client/locales.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/locales.js +76 -14
- package/packages/tool-agent-team/README.md +6 -3
- package/packages/tool-agent-team/README.zh.md +6 -3
- package/packages/tool-agent-team/lib/context-tools.js +148 -164
- package/packages/tool-agent-team/lib/index.js +17 -2
- package/packages/tool-agent-team/lib/types/context-tools.d.ts +32 -7
- package/packages/tool-agent-team/lib/types/context-tools.d.ts.map +1 -1
- package/packages/tool-agent-team/lib/types/index.d.ts.map +1 -1
- package/packages/agent-team/lib/pressure-policy.js +0 -230
- package/packages/agent-team/lib/types/pressure-policy.d.ts +0 -130
- package/packages/agent-team/lib/types/pressure-policy.d.ts.map +0 -1
- package/packages/client-agent-team/lib/types/client/HumanSettingsSection.d.ts +0 -15
- package/packages/client-agent-team/lib/types/client/HumanSettingsSection.d.ts.map +0 -1
- package/packages/client-agent-team/lib/types/client/HumanSettingsSection.js +0 -115
|
@@ -1,230 +0,0 @@
|
|
|
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 { AGENT_TEAM_PLUGIN_ID, isAgentTeamSourceKind } from "./context-source.js";
|
|
20
|
-
import { advanceOwnedSessionEventCursor } from "./session-event-cursor.js";
|
|
21
|
-
/**
|
|
22
|
-
* Stable summary of the one-shot rollover pressure notice. It is a durable
|
|
23
|
-
* marker: the notice's own presence in a Session's log is what latches the
|
|
24
|
-
* policy, so the wording is read back and must not drift.
|
|
25
|
-
*/
|
|
26
|
-
export const CONTEXT_PRESSURE_NOTICE_SUMMARY = 'Context pressure: prepare a handoff';
|
|
27
|
-
/**
|
|
28
|
-
* Whether this Session's own span already carries the pressure notice: either
|
|
29
|
-
* surfaced as a `user/message` or still queued in a durable
|
|
30
|
-
* `agent/inbox/spliced` insert. Expressed as a fold rather than a scan because
|
|
31
|
-
* the answer is monotone — once delivered it stays delivered for the
|
|
32
|
-
* generation — so the cursor only ever has to read events it has not seen.
|
|
33
|
-
*/
|
|
34
|
-
export const PRESSURE_NOTICE_FOLD = {
|
|
35
|
-
start: false,
|
|
36
|
-
step: (delivered, event) => {
|
|
37
|
-
if (delivered)
|
|
38
|
-
return true;
|
|
39
|
-
if (event.type === 'user/message' && isPressureNotice(event.data))
|
|
40
|
-
return true;
|
|
41
|
-
if (event.type === 'agent/inbox/spliced' && event.data.inserted.some(isPressureNotice))
|
|
42
|
-
return true;
|
|
43
|
-
return false;
|
|
44
|
-
},
|
|
45
|
-
};
|
|
46
|
-
/** One pressure-notice text; concise, structured, and inside the reserve. */
|
|
47
|
-
export function contextPressureNoticeText(input) {
|
|
48
|
-
const claims = input.activeClaims.length === 0 ? 'none' : input.activeClaims.join(', ');
|
|
49
|
-
const jobs = input.runningJobs.length === 0 ? 'none' : `${input.runningJobs.length} running (collect or stop them before switching)`;
|
|
50
|
-
return [
|
|
51
|
-
`Context pressure: ${input.usageTokens} tokens measured; the handoff budget is ${input.handoffAt} and the hard limit is ${input.hardLimit}.`,
|
|
52
|
-
`Active Claims: ${claims}. Owner jobs: ${jobs}.`,
|
|
53
|
-
'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.',
|
|
54
|
-
].join(' ');
|
|
55
|
-
}
|
|
56
|
-
/** Whether one user message is this policy's one-shot pressure notice. */
|
|
57
|
-
function isPressureNotice(message) {
|
|
58
|
-
// The source arrives untyped from the inbox; identity is matched by exact
|
|
59
|
-
// kind — the shape written now and the read-time conversion's V3 rename.
|
|
60
|
-
const source = message.source;
|
|
61
|
-
return isAgentTeamSourceKind(source?.kind)
|
|
62
|
-
&& source?.summary === CONTEXT_PRESSURE_NOTICE_SUMMARY;
|
|
63
|
-
}
|
|
64
|
-
export class PressurePolicyCoordinator {
|
|
65
|
-
options;
|
|
66
|
-
/**
|
|
67
|
-
* Retry budget per agent for the current provider-overflow sequence.
|
|
68
|
-
* Process-only by design: a restart re-earns one sequence per chain.
|
|
69
|
-
*/
|
|
70
|
-
overflowRetries = new Map();
|
|
71
|
-
/**
|
|
72
|
-
* Whether the one-shot notice was already delivered, folded incrementally per
|
|
73
|
-
* Member. The scan below is a monotone "has this ever happened" fold over the
|
|
74
|
-
* Session's own events, so a cursor can replace re-scanning the whole log on
|
|
75
|
-
* every step; identity guarding falls back to a cold fold when the Member's
|
|
76
|
-
* Session changed under the entry.
|
|
77
|
-
*/
|
|
78
|
-
noticeSeen = new Map();
|
|
79
|
-
disposed = false;
|
|
80
|
-
constructor(options) {
|
|
81
|
-
this.options = options;
|
|
82
|
-
}
|
|
83
|
-
/**
|
|
84
|
-
* The one-shot pressure notice is durable Session evidence, not process
|
|
85
|
-
* state: a `CONTEXT_PRESSURE_NOTICE_SUMMARY` notice already surfaced as a
|
|
86
|
-
* `user/message`, or still queued in a durable `agent/inbox/spliced`
|
|
87
|
-
* insert (a steered notice surfaces only at the next step boundary, and a
|
|
88
|
-
* Host restart replays the splice before surfacing), marks the current
|
|
89
|
-
* generation as already notified. A resume or restart stays quiet; a
|
|
90
|
-
* rollover starts a fresh Session whose own event span has no notice yet,
|
|
91
|
-
* which is exactly the documented re-arm.
|
|
92
|
-
*/
|
|
93
|
-
noticeDelivered(agent, memberId) {
|
|
94
|
-
const owned = advanceOwnedSessionEventCursor(this.noticeSeen.get(memberId), agent.session.id, PRESSURE_NOTICE_FOLD, agent.session.ownEvents(), agent.session.inheritedEventCount);
|
|
95
|
-
this.noticeSeen.set(memberId, owned);
|
|
96
|
-
return owned.cursor.value;
|
|
97
|
-
}
|
|
98
|
-
dispose() {
|
|
99
|
-
this.disposed = true;
|
|
100
|
-
this.overflowRetries.clear();
|
|
101
|
-
}
|
|
102
|
-
/** A successful assistant response ends any open overflow-recovery sequence. */
|
|
103
|
-
onAssistantMessage(agent) {
|
|
104
|
-
this.overflowRetries.delete(agent);
|
|
105
|
-
}
|
|
106
|
-
/**
|
|
107
|
-
* Pre-step policy for one Member agent: below the handoff budget nothing
|
|
108
|
-
* happens; at the handoff budget one structured notice per generation is
|
|
109
|
-
* steered into the running turn; at the hard limit the request is forced
|
|
110
|
-
* through compaction first and fails closed when that cannot be proven.
|
|
111
|
-
* Returns the decision for the step: `continue` forwards, `reject` blocks.
|
|
112
|
-
*/
|
|
113
|
-
async onPreStep(agent, signal) {
|
|
114
|
-
if (this.disposed || signal.aborted)
|
|
115
|
-
return { kind: 'continue' };
|
|
116
|
-
const member = this.options.memberForAgent(agent);
|
|
117
|
-
if (member === undefined)
|
|
118
|
-
return { kind: 'continue' };
|
|
119
|
-
const limits = await this.options.limitsForAgent(agent);
|
|
120
|
-
if (limits === undefined) {
|
|
121
|
-
// A missing route capacity must be explicit, never an accidental
|
|
122
|
-
// unlimited policy: reject the step with a recoverable diagnostic.
|
|
123
|
-
const diagnostic = 'context pressure policy: the routed model capacity is unknown; refusing to forward a request without a bounded context budget';
|
|
124
|
-
this.options.failed(member.memberId, member.sessionId, diagnostic);
|
|
125
|
-
return { kind: 'reject' };
|
|
126
|
-
}
|
|
127
|
-
const { usageTokens, hardLimit, handoffAt } = limits;
|
|
128
|
-
if (usageTokens >= hardLimit) {
|
|
129
|
-
const outcome = await this.enforceHardLimit(agent, member.memberId, member.sessionId, signal);
|
|
130
|
-
return outcome ? { kind: 'continue' } : { kind: 'reject' };
|
|
131
|
-
}
|
|
132
|
-
if (usageTokens >= handoffAt && !this.noticeDelivered(agent, member.memberId)) {
|
|
133
|
-
const notice = createUserMessage({
|
|
134
|
-
content: [{ type: 'text', text: contextPressureNoticeText({
|
|
135
|
-
usageTokens, handoffAt, hardLimit,
|
|
136
|
-
activeClaims: this.options.activeClaimLabels(member.memberId),
|
|
137
|
-
runningJobs: this.options.runningJobLabels(member.memberId),
|
|
138
|
-
}) }],
|
|
139
|
-
source: { kind: AGENT_TEAM_PLUGIN_ID, form: 'notice', summary: CONTEXT_PRESSURE_NOTICE_SUMMARY },
|
|
140
|
-
});
|
|
141
|
-
try {
|
|
142
|
-
agent.steer(notice);
|
|
143
|
-
}
|
|
144
|
-
catch (error) {
|
|
145
|
-
this.options.log(`context pressure notice failed: ${error instanceof Error ? error.message : String(error)} (member ${member.memberId})`);
|
|
146
|
-
}
|
|
147
|
-
return { kind: 'notice' };
|
|
148
|
-
}
|
|
149
|
-
return { kind: 'continue' };
|
|
150
|
-
}
|
|
151
|
-
/**
|
|
152
|
-
* Provider-overflow recovery: one bounded compact-and-retry sequence per
|
|
153
|
-
* open failure chain. Returns whether the request may retry once.
|
|
154
|
-
*/
|
|
155
|
-
async onRequestError(agent, failure, signal) {
|
|
156
|
-
if (this.disposed || signal.aborted)
|
|
157
|
-
return false;
|
|
158
|
-
if (failure.code !== CONTEXT_WINDOW_EXCEEDED_CODE)
|
|
159
|
-
return false;
|
|
160
|
-
const member = this.options.memberForAgent(agent);
|
|
161
|
-
if (member === undefined)
|
|
162
|
-
return false;
|
|
163
|
-
const retries = this.overflowRetries.get(agent) ?? 0;
|
|
164
|
-
if (retries >= 1)
|
|
165
|
-
return false;
|
|
166
|
-
const engine = this.options.compactionForAgent(agent);
|
|
167
|
-
if (engine === undefined)
|
|
168
|
-
return false;
|
|
169
|
-
const generation = agent.session.surface.replaceGeneration;
|
|
170
|
-
try {
|
|
171
|
-
await engine.compactIfNeeded(agent, 'context-overflow', signal);
|
|
172
|
-
}
|
|
173
|
-
catch (error) {
|
|
174
|
-
// Durable prune progress before a later summary failure justifies the
|
|
175
|
-
// single retry; cancellation never does.
|
|
176
|
-
if (!signal.aborted && agent.session.surface.replaceGeneration > generation) {
|
|
177
|
-
this.overflowRetries.set(agent, retries + 1);
|
|
178
|
-
return true;
|
|
179
|
-
}
|
|
180
|
-
this.options.log(`context-overflow recovery failed: ${error instanceof Error ? error.message : String(error)} (member ${member.memberId})`);
|
|
181
|
-
return false;
|
|
182
|
-
}
|
|
183
|
-
if (signal.aborted || agent.session.surface.replaceGeneration <= generation)
|
|
184
|
-
return false;
|
|
185
|
-
this.overflowRetries.set(agent, retries + 1);
|
|
186
|
-
return true;
|
|
187
|
-
}
|
|
188
|
-
/**
|
|
189
|
-
* The one Team hard-limit translation: force a CompactionEngine reduction
|
|
190
|
-
* in the current Agent/Session and prove it advanced the durable surface
|
|
191
|
-
* (or measurably reduced pressure) before continuing. Background jobs are
|
|
192
|
-
* untouched — compaction never cancels or discards them.
|
|
193
|
-
* @returns whether the request may proceed.
|
|
194
|
-
*/
|
|
195
|
-
async enforceHardLimit(agent, memberId, sessionId, signal) {
|
|
196
|
-
const engine = this.options.compactionForAgent(agent);
|
|
197
|
-
if (engine === undefined) {
|
|
198
|
-
const diagnostic = 'context hard limit reached and compaction is unavailable in the Member scope; the request was blocked';
|
|
199
|
-
this.options.failed(memberId, sessionId, diagnostic);
|
|
200
|
-
return false;
|
|
201
|
-
}
|
|
202
|
-
const meter = agent.ctx.get('tokenMeter');
|
|
203
|
-
const before = meter?.measure(agent.session)?.totalTokens ?? Number.POSITIVE_INFINITY;
|
|
204
|
-
const generation = agent.session.surface.replaceGeneration;
|
|
205
|
-
let result;
|
|
206
|
-
try {
|
|
207
|
-
result = await engine.compactIfNeeded(agent, 'context-overflow', signal);
|
|
208
|
-
}
|
|
209
|
-
catch (error) {
|
|
210
|
-
const diagnostic = `context hard limit compaction failed: ${error instanceof Error ? error.message : String(error)}; the request was blocked`;
|
|
211
|
-
this.options.failed(memberId, sessionId, diagnostic);
|
|
212
|
-
return false;
|
|
213
|
-
}
|
|
214
|
-
if (signal.aborted)
|
|
215
|
-
return false;
|
|
216
|
-
const after = meter?.measure(agent.session)?.totalTokens ?? Number.POSITIVE_INFINITY;
|
|
217
|
-
const surfaceAdvanced = agent.session.surface.replaceGeneration > generation;
|
|
218
|
-
const pressureReduced = meter === undefined ? false : after < before;
|
|
219
|
-
if (!surfaceAdvanced && !pressureReduced) {
|
|
220
|
-
// No-op or unchanged replacement generation: fail closed rather than
|
|
221
|
-
// knowingly submit over the Team limit.
|
|
222
|
-
const diagnostic = result === null
|
|
223
|
-
? 'context hard limit reached and no compactable range exists; the request was blocked'
|
|
224
|
-
: 'context hard limit compaction produced no measurable reduction; the request was blocked';
|
|
225
|
-
this.options.failed(memberId, sessionId, diagnostic);
|
|
226
|
-
return false;
|
|
227
|
-
}
|
|
228
|
-
return true;
|
|
229
|
-
}
|
|
230
|
-
}
|
|
@@ -1,130 +0,0 @@
|
|
|
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 type { Agent } from '@deepseek-ai/dsh-agent';
|
|
18
|
-
import type { CompactionEngine } from '@deepseek-ai/dsh-compaction';
|
|
19
|
-
import type { AgentTeamMemberId } from './types.ts';
|
|
20
|
-
import type { SessionEvent } from '@deepseek-ai/dsh-session';
|
|
21
|
-
import { type SessionEventFold } from './session-event-cursor.ts';
|
|
22
|
-
/**
|
|
23
|
-
* Stable summary of the one-shot rollover pressure notice. It is a durable
|
|
24
|
-
* marker: the notice's own presence in a Session's log is what latches the
|
|
25
|
-
* policy, so the wording is read back and must not drift.
|
|
26
|
-
*/
|
|
27
|
-
export declare const CONTEXT_PRESSURE_NOTICE_SUMMARY = "Context pressure: prepare a handoff";
|
|
28
|
-
/**
|
|
29
|
-
* Whether this Session's own span already carries the pressure notice: either
|
|
30
|
-
* surfaced as a `user/message` or still queued in a durable
|
|
31
|
-
* `agent/inbox/spliced` insert. Expressed as a fold rather than a scan because
|
|
32
|
-
* the answer is monotone — once delivered it stays delivered for the
|
|
33
|
-
* generation — so the cursor only ever has to read events it has not seen.
|
|
34
|
-
*/
|
|
35
|
-
export declare const PRESSURE_NOTICE_FOLD: SessionEventFold<boolean, SessionEvent>;
|
|
36
|
-
/** One pressure-notice text; concise, structured, and inside the reserve. */
|
|
37
|
-
export declare function contextPressureNoticeText(input: {
|
|
38
|
-
readonly usageTokens: number;
|
|
39
|
-
readonly handoffAt: number;
|
|
40
|
-
readonly hardLimit: number;
|
|
41
|
-
readonly activeClaims: readonly string[];
|
|
42
|
-
readonly runningJobs: readonly string[];
|
|
43
|
-
}): string;
|
|
44
|
-
export interface PressurePolicyOptions {
|
|
45
|
-
/** Resolve the live Agent of one Member. */
|
|
46
|
-
readonly agentForMember: (memberId: AgentTeamMemberId) => Agent | undefined;
|
|
47
|
-
/** Resolve the durable Member of one live Agent. */
|
|
48
|
-
readonly memberForAgent: (agent: Agent) => {
|
|
49
|
-
readonly memberId: AgentTeamMemberId;
|
|
50
|
-
readonly sessionId: Agent['id'];
|
|
51
|
-
} | undefined;
|
|
52
|
-
/** Resolve the Member-scoped compaction engine. */
|
|
53
|
-
readonly compactionForAgent: (agent: Agent) => CompactionEngine | undefined;
|
|
54
|
-
/** Effective budgets for one Member's current route; undefined means the route window is unknown. */
|
|
55
|
-
readonly limitsForAgent: (agent: Agent) => Promise<{
|
|
56
|
-
readonly usageTokens: number;
|
|
57
|
-
readonly hardLimit: number;
|
|
58
|
-
readonly handoffAt: number;
|
|
59
|
-
} | undefined> | {
|
|
60
|
-
readonly usageTokens: number;
|
|
61
|
-
readonly hardLimit: number;
|
|
62
|
-
readonly handoffAt: number;
|
|
63
|
-
} | undefined;
|
|
64
|
-
/** The model-visible active-Claim labels for one Member's notice. */
|
|
65
|
-
readonly activeClaimLabels: (memberId: AgentTeamMemberId) => readonly string[];
|
|
66
|
-
/** The model-visible running-job labels for one Member's notice. */
|
|
67
|
-
readonly runningJobLabels: (memberId: AgentTeamMemberId) => readonly string[];
|
|
68
|
-
/** Report a Member failure with a recoverable diagnostic. */
|
|
69
|
-
readonly failed: (memberId: AgentTeamMemberId, sessionId: Agent['id'], diagnostic: string) => void;
|
|
70
|
-
/** Log one coordinator diagnostic. */
|
|
71
|
-
readonly log: (message: string) => void;
|
|
72
|
-
}
|
|
73
|
-
export declare class PressurePolicyCoordinator {
|
|
74
|
-
private readonly options;
|
|
75
|
-
/**
|
|
76
|
-
* Retry budget per agent for the current provider-overflow sequence.
|
|
77
|
-
* Process-only by design: a restart re-earns one sequence per chain.
|
|
78
|
-
*/
|
|
79
|
-
private readonly overflowRetries;
|
|
80
|
-
/**
|
|
81
|
-
* Whether the one-shot notice was already delivered, folded incrementally per
|
|
82
|
-
* Member. The scan below is a monotone "has this ever happened" fold over the
|
|
83
|
-
* Session's own events, so a cursor can replace re-scanning the whole log on
|
|
84
|
-
* every step; identity guarding falls back to a cold fold when the Member's
|
|
85
|
-
* Session changed under the entry.
|
|
86
|
-
*/
|
|
87
|
-
private readonly noticeSeen;
|
|
88
|
-
private disposed;
|
|
89
|
-
constructor(options: PressurePolicyOptions);
|
|
90
|
-
/**
|
|
91
|
-
* The one-shot pressure notice is durable Session evidence, not process
|
|
92
|
-
* state: a `CONTEXT_PRESSURE_NOTICE_SUMMARY` notice already surfaced as a
|
|
93
|
-
* `user/message`, or still queued in a durable `agent/inbox/spliced`
|
|
94
|
-
* insert (a steered notice surfaces only at the next step boundary, and a
|
|
95
|
-
* Host restart replays the splice before surfacing), marks the current
|
|
96
|
-
* generation as already notified. A resume or restart stays quiet; a
|
|
97
|
-
* rollover starts a fresh Session whose own event span has no notice yet,
|
|
98
|
-
* which is exactly the documented re-arm.
|
|
99
|
-
*/
|
|
100
|
-
private noticeDelivered;
|
|
101
|
-
dispose(): void;
|
|
102
|
-
/** A successful assistant response ends any open overflow-recovery sequence. */
|
|
103
|
-
onAssistantMessage(agent: Agent): void;
|
|
104
|
-
/**
|
|
105
|
-
* Pre-step policy for one Member agent: below the handoff budget nothing
|
|
106
|
-
* happens; at the handoff budget one structured notice per generation is
|
|
107
|
-
* steered into the running turn; at the hard limit the request is forced
|
|
108
|
-
* through compaction first and fails closed when that cannot be proven.
|
|
109
|
-
* Returns the decision for the step: `continue` forwards, `reject` blocks.
|
|
110
|
-
*/
|
|
111
|
-
onPreStep(agent: Agent, signal: AbortSignal): Promise<{
|
|
112
|
-
readonly kind: 'continue' | 'reject' | 'notice';
|
|
113
|
-
}>;
|
|
114
|
-
/**
|
|
115
|
-
* Provider-overflow recovery: one bounded compact-and-retry sequence per
|
|
116
|
-
* open failure chain. Returns whether the request may retry once.
|
|
117
|
-
*/
|
|
118
|
-
onRequestError(agent: Agent, failure: {
|
|
119
|
-
readonly code?: string;
|
|
120
|
-
}, signal: AbortSignal): Promise<boolean>;
|
|
121
|
-
/**
|
|
122
|
-
* The one Team hard-limit translation: force a CompactionEngine reduction
|
|
123
|
-
* in the current Agent/Session and prove it advanced the durable surface
|
|
124
|
-
* (or measurably reduced pressure) before continuing. Background jobs are
|
|
125
|
-
* untouched — compaction never cancels or discards them.
|
|
126
|
-
* @returns whether the request may proceed.
|
|
127
|
-
*/
|
|
128
|
-
private enforceHardLimit;
|
|
129
|
-
}
|
|
130
|
-
//# sourceMappingURL=pressure-policy.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"pressure-policy.d.ts","sourceRoot":"","sources":["../../src/pressure-policy.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import type { PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
|
|
2
|
-
import { type TeamHumanIdentityFace } from './human-identity.ts';
|
|
3
|
-
export interface HumanSettingsSectionInjected {
|
|
4
|
-
/** The shared Human identity projection: profile facts plus post-write refresh. */
|
|
5
|
-
identity: TeamHumanIdentityFace;
|
|
6
|
-
/** Persist one renamed display name; the failure message when the Host refuses it. */
|
|
7
|
-
saveName: (name: string) => Promise<string | undefined>;
|
|
8
|
-
/** Upload one image file, persist its reference; the failure message when it does not stick. */
|
|
9
|
-
uploadAvatar: (file: File) => Promise<string | undefined>;
|
|
10
|
-
/** Clear the avatar; the identity falls back to the initial. */
|
|
11
|
-
removeAvatar: () => Promise<string | undefined>;
|
|
12
|
-
}
|
|
13
|
-
export type HumanSettingsSectionProps = PropsRuntime<'settings.section'> & PropsLocale<'team'> & HumanSettingsSectionInjected;
|
|
14
|
-
export declare function HumanSettingsSection(props: HumanSettingsSectionProps): import("react").JSX.Element;
|
|
15
|
-
//# sourceMappingURL=HumanSettingsSection.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"HumanSettingsSection.d.ts","sourceRoot":"","sources":["../../../src/client/HumanSettingsSection.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAA;AAEjF,OAAO,EAAoB,KAAK,qBAAqB,EAAE,MAAM,qBAAqB,CAAA;AAiBlF,MAAM,WAAW,4BAA4B;IAC3C,mFAAmF;IACnF,QAAQ,EAAE,qBAAqB,CAAA;IAC/B,sFAAsF;IACtF,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAA;IACvD,gGAAgG;IAChG,YAAY,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAA;IACzD,gEAAgE;IAChE,YAAY,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAA;CAChD;AAED,MAAM,MAAM,yBAAyB,GACjC,YAAY,CAAC,kBAAkB,CAAC,GAChC,WAAW,CAAC,MAAM,CAAC,GACnB,4BAA4B,CAAA;AAsBhC,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,yBAAyB,+BAiKpE"}
|
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useRef, useState } from 'react';
|
|
3
|
-
import { Button, Input } from '@deepseek-ai/dsh-client-ui-primitives';
|
|
4
|
-
import { useHumanIdentity } from "./human-identity.js";
|
|
5
|
-
import { useAvatarImage } from "./avatar-image.js";
|
|
6
|
-
import css from './human-settings.module.css';
|
|
7
|
-
/**
|
|
8
|
-
* The Human's own settings page: display name, avatar, and the version
|
|
9
|
-
* footnote.
|
|
10
|
-
*
|
|
11
|
-
* The page owns no durable fact and no copy of one. Name, avatar, and version
|
|
12
|
-
* all arrive from the shared identity projection, so a save here moves the
|
|
13
|
-
* message rows and member refs at the same moment; a failed write keeps the
|
|
14
|
-
* typed name in the field and reports the Host's own reason.
|
|
15
|
-
*/
|
|
16
|
-
/** Host-side avatar ceiling (`ATTACHMENT_MAX_BYTES`): the settings page refuses larger files before the round trip. */
|
|
17
|
-
const AVATAR_MAX_BYTES = 10 * 1024 * 1024;
|
|
18
|
-
/**
|
|
19
|
-
* Run one durable write and reduce every failure to the message the page
|
|
20
|
-
* reports. A rejected Remote call (a dropped carrier, a refused write) is a
|
|
21
|
-
* failure like any other: without this the field would sit on "saving" forever
|
|
22
|
-
* and report nothing.
|
|
23
|
-
*/
|
|
24
|
-
async function failureOf(action) {
|
|
25
|
-
try {
|
|
26
|
-
return await action();
|
|
27
|
-
}
|
|
28
|
-
catch (error) {
|
|
29
|
-
return error instanceof Error ? error.message : String(error);
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
/** First visible character of a display name, or the neutral `H` before one is known. */
|
|
33
|
-
function avatarInitial(name) {
|
|
34
|
-
const trimmed = (name ?? '').replace(/^@/, '').trim();
|
|
35
|
-
return trimmed === '' ? 'H' : trimmed.slice(0, 1).toUpperCase();
|
|
36
|
-
}
|
|
37
|
-
export function HumanSettingsSection(props) {
|
|
38
|
-
const { t, identity } = props;
|
|
39
|
-
const profile = useHumanIdentity(identity);
|
|
40
|
-
// Undefined means "follow the Host value": the field re-syncs whenever the
|
|
41
|
-
// profile changes underneath, without a background read clobbering a name
|
|
42
|
-
// the reader is still editing.
|
|
43
|
-
const [draft, setDraft] = useState(undefined);
|
|
44
|
-
const [saving, setSaving] = useState(false);
|
|
45
|
-
const [uploading, setUploading] = useState(false);
|
|
46
|
-
const [notice, setNotice] = useState(null);
|
|
47
|
-
const filePicker = useRef(null);
|
|
48
|
-
const name = draft ?? profile.name ?? '';
|
|
49
|
-
const dirty = draft !== undefined && draft.trim() !== (profile.name ?? '');
|
|
50
|
-
const emptyName = draft !== undefined && draft.trim() === '';
|
|
51
|
-
const hasAvatar = profile.avatarRef !== undefined;
|
|
52
|
-
// The circle answers to decoded bytes, not to a stored reference: the Host
|
|
53
|
-
// accepts any `image/…` payload, so a file this browser cannot read has to
|
|
54
|
-
// fall back to the initial exactly as a removed one does.
|
|
55
|
-
const avatar = useAvatarImage(profile.avatarUrl);
|
|
56
|
-
const submitName = async () => {
|
|
57
|
-
if (!dirty || emptyName || saving)
|
|
58
|
-
return;
|
|
59
|
-
setSaving(true);
|
|
60
|
-
setNotice(null);
|
|
61
|
-
const failure = await failureOf(() => props.saveName(name.trim()));
|
|
62
|
-
setSaving(false);
|
|
63
|
-
if (failure !== undefined) {
|
|
64
|
-
setNotice(t('humanSettingsNameFailed', { message: failure }));
|
|
65
|
-
return;
|
|
66
|
-
}
|
|
67
|
-
setDraft(undefined);
|
|
68
|
-
};
|
|
69
|
-
const pickAvatar = async (file) => {
|
|
70
|
-
if (file === undefined)
|
|
71
|
-
return;
|
|
72
|
-
setNotice(null);
|
|
73
|
-
if (!file.type.startsWith('image/')) {
|
|
74
|
-
setNotice(t('humanSettingsAvatarNotImage'));
|
|
75
|
-
return;
|
|
76
|
-
}
|
|
77
|
-
if (file.size > AVATAR_MAX_BYTES) {
|
|
78
|
-
setNotice(t('humanSettingsAvatarTooLarge'));
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
81
|
-
setUploading(true);
|
|
82
|
-
const failure = await failureOf(() => props.uploadAvatar(file));
|
|
83
|
-
setUploading(false);
|
|
84
|
-
if (failure !== undefined)
|
|
85
|
-
setNotice(t('humanSettingsAvatarFailed', { message: failure }));
|
|
86
|
-
};
|
|
87
|
-
const removeAvatar = async () => {
|
|
88
|
-
setNotice(null);
|
|
89
|
-
const failure = await failureOf(() => props.removeAvatar());
|
|
90
|
-
if (failure !== undefined)
|
|
91
|
-
setNotice(t('humanSettingsAvatarFailed', { message: failure }));
|
|
92
|
-
};
|
|
93
|
-
// The page says what it is before it says what happened: the settings nav
|
|
94
|
-
// lists it beside the Harness's own pages, so the title alone leaves "whose
|
|
95
|
-
// profile is this, and where does it apply?" unanswered — and every state,
|
|
96
|
-
// including a failed read, has to answer it.
|
|
97
|
-
const pageHeader = _jsxs(_Fragment, { children: [_jsx("h2", { className: css.heading, children: t('humanSettingsTitle') }), _jsx("p", { className: css.intro, children: t('humanSettingsIntro') })] });
|
|
98
|
-
if (profile.status === 'loading' && profile.name === undefined) {
|
|
99
|
-
return _jsxs("div", { className: css.section, children: [pageHeader, _jsx("p", { className: css.state, role: "status", children: t('humanSettingsLoading') })] });
|
|
100
|
-
}
|
|
101
|
-
if (profile.name === undefined) {
|
|
102
|
-
return _jsxs("div", { className: css.section, children: [pageHeader, _jsx("p", { className: css.state, role: "alert", children: t('humanSettingsUnavailable', { message: profile.error ?? '' }) }), _jsx("div", { className: css.stateAction, children: _jsx(Button, { variant: "outline", onClick: () => { void identity.refresh(); }, children: t('retry') }) })] });
|
|
103
|
-
}
|
|
104
|
-
return (_jsxs("div", { className: css.section, children: [pageHeader, _jsxs("div", { className: css.rows, children: [_jsxs("div", { className: css.row, children: [_jsxs("div", { className: css.rowText, children: [_jsx("div", { className: css.title, children: t('humanSettingsName') }), _jsx("div", { className: css.desc, children: t('humanSettingsNameHint') })] }), _jsxs("form", { className: css.controls, onSubmit: (event) => {
|
|
105
|
-
event.preventDefault();
|
|
106
|
-
void submitName();
|
|
107
|
-
}, children: [_jsx(Input, { className: css.nameInput, "aria-label": t('humanSettingsName'), "aria-invalid": emptyName || undefined, value: name, disabled: saving, onChange: (event) => { setDraft(event.target.value); } }), _jsx(Button, { type: "submit", variant: "primary", disabled: saving || !dirty || emptyName, children: saving ? t('humanSettingsSaving') : t('humanSettingsSave') })] })] }), _jsxs("div", { className: css.row, children: [_jsxs("div", { className: css.rowText, children: [_jsx("div", { className: css.title, children: t('humanSettingsAvatar') }), _jsx("div", { className: css.desc, children: t('humanSettingsAvatarHint') })] }), _jsxs("div", { className: css.controls, children: [avatar.src === undefined
|
|
108
|
-
? _jsx("span", { className: `${css.identity} ${css.identityFallback}`, "data-avatar": "initial", "aria-hidden": "true", children: avatarInitial(profile.name) })
|
|
109
|
-
: _jsx("img", { className: `${css.identity} ${css.identityImage}`, "data-avatar": "image", src: avatar.src, alt: "", onError: avatar.failed }), _jsx("input", { ref: filePicker, type: "file", accept: "image/*", tabIndex: -1, "aria-hidden": "true", hidden: true, onChange: (event) => {
|
|
110
|
-
void pickAvatar(event.target.files?.[0]);
|
|
111
|
-
event.target.value = '';
|
|
112
|
-
} }), _jsx(Button, { variant: "outline", disabled: uploading, onClick: () => { filePicker.current?.click(); }, children: uploading ? t('humanSettingsUploading') : hasAvatar ? t('humanSettingsReplace') : t('humanSettingsUpload') }), hasAvatar && _jsx(Button, { disabled: uploading, onClick: () => { void removeAvatar(); }, children: t('humanSettingsRemoveAvatar') })] })] })] }), _jsxs("div", { className: css.footnote, children: [_jsx("span", { children: t('humanSettingsVersion', { version: profile.version ?? '' }) }), _jsx("span", { "aria-hidden": "true", children: "\u00B7" }), _jsx("a", { className: css.link, href: profile.repoUrl ?? '', target: "_blank", rel: "noreferrer", children: "GitHub" }), profile.updateAvailable && profile.latestVersion !== undefined
|
|
113
|
-
? _jsx("a", { className: css.link, href: `${profile.repoUrl ?? ''}/releases`, target: "_blank", rel: "noreferrer", children: t('humanSettingsUpdateAvailable', { version: profile.latestVersion }) })
|
|
114
|
-
: null] }), emptyName && _jsx("p", { className: css.notice, children: t('humanSettingsNameEmpty') }), notice === null ? null : _jsx("p", { className: css.notice, role: "alert", children: notice })] }));
|
|
115
|
-
}
|