dsh-connect 0.6.4 → 0.6.7
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 +17 -18
- package/README.zh.md +17 -18
- package/lib/commands.d.ts +3 -0
- package/lib/commands.d.ts.map +1 -1
- package/lib/commands.js +4 -0
- package/lib/commands.js.map +1 -1
- package/lib/i18n.d.ts +14 -0
- package/lib/i18n.d.ts.map +1 -1
- package/lib/i18n.js +52 -24
- package/lib/i18n.js.map +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +3 -1
- package/lib/index.js.map +1 -1
- package/lib/runner.d.ts +27 -0
- package/lib/runner.d.ts.map +1 -1
- package/lib/runner.js +219 -26
- package/lib/runner.js.map +1 -1
- package/lib/service.d.ts +1 -1
- package/lib/service.d.ts.map +1 -1
- package/lib/service.js +8 -1
- package/lib/service.js.map +1 -1
- package/package.json +5 -5
- package/LICENSE +0 -21
package/lib/index.js
CHANGED
|
@@ -40,7 +40,9 @@ export const Config = z.object({
|
|
|
40
40
|
});
|
|
41
41
|
/** Register the `connect` service; adapters resolve it via `inject: ["connect"]`. */
|
|
42
42
|
export function apply(ctx, config = {}) {
|
|
43
|
-
|
|
43
|
+
// The DSH loader passes `null` for entries without an explicit config
|
|
44
|
+
// (and does not run schema coercion on this path), so treat it as empty.
|
|
45
|
+
void new ConnectService(ctx, config ?? {});
|
|
44
46
|
}
|
|
45
47
|
export default ConnectService;
|
|
46
48
|
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAOA,OAAO,CAAC,MAAM,0BAA0B,CAAC;AACzC,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAG9C,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,aAAa,EAAE,aAAa,EAAE,cAAc,EAAE,oBAAoB,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEhK,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEvE,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEvD,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAgBrC,qDAAqD;AACrD,MAAM,CAAC,MAAM,IAAI,GAAG,SAAS,CAAC;AAE9B,6EAA6E;AAC7E,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,QAAQ,EAAE,UAAU,EAAE,mBAAmB,CAAC,CAAC;AAElE,wEAAwE;AACxE,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC;IAC7B,qFAAqF;IACrF,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE;IACvB,yEAAyE;IACzE,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;IACnB,oEAAoE;IACpE,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IAC/B,uFAAuF;IACvF,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC;IAClE,4DAA4D;IAC5D,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;IACjD,qDAAqD;IACrD,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IAC/B,iDAAiD;IACjD,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IAC/B,qDAAqD;IACrD,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE;IACpB,0EAA0E;IAC1E,UAAU,EAAE,CAAC,CAAC,OAAO,EAAE;IACvB,6FAA6F;IAC7F,iBAAiB,EAAE,CAAC,CAAC,MAAM,EAAE;IAC7B,+EAA+E;IAC/E,WAAW,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC;IAChF,4GAA4G;IAC5G,iBAAiB,EAAE,CAAC,CAAC,MAAM,EAAE;CAC9B,CAAC,CAAC;AAQH,qFAAqF;AACrF,MAAM,UAAU,KAAK,CAAC,GAAY,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAOA,OAAO,CAAC,MAAM,0BAA0B,CAAC;AACzC,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAG9C,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,aAAa,EAAE,aAAa,EAAE,cAAc,EAAE,oBAAoB,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEhK,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEvE,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEvD,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAgBrC,qDAAqD;AACrD,MAAM,CAAC,MAAM,IAAI,GAAG,SAAS,CAAC;AAE9B,6EAA6E;AAC7E,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,QAAQ,EAAE,UAAU,EAAE,mBAAmB,CAAC,CAAC;AAElE,wEAAwE;AACxE,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC;IAC7B,qFAAqF;IACrF,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE;IACvB,yEAAyE;IACzE,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;IACnB,oEAAoE;IACpE,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IAC/B,uFAAuF;IACvF,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC;IAClE,4DAA4D;IAC5D,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;IACjD,qDAAqD;IACrD,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IAC/B,iDAAiD;IACjD,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IAC/B,qDAAqD;IACrD,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE;IACpB,0EAA0E;IAC1E,UAAU,EAAE,CAAC,CAAC,OAAO,EAAE;IACvB,6FAA6F;IAC7F,iBAAiB,EAAE,CAAC,CAAC,MAAM,EAAE;IAC7B,+EAA+E;IAC/E,WAAW,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC;IAChF,4GAA4G;IAC5G,iBAAiB,EAAE,CAAC,CAAC,MAAM,EAAE;CAC9B,CAAC,CAAC;AAQH,qFAAqF;AACrF,MAAM,UAAU,KAAK,CAAC,GAAY,EAAE,SAA+B,EAAE;IACnE,sEAAsE;IACtE,yEAAyE;IACzE,KAAK,IAAI,cAAc,CAAC,GAAG,EAAE,MAAM,IAAI,EAAE,CAAC,CAAC;AAC7C,CAAC;AAED,eAAe,cAAc,CAAC"}
|
package/lib/runner.d.ts
CHANGED
|
@@ -124,6 +124,12 @@ export declare class AgentRunner {
|
|
|
124
124
|
enqueue(msg: InboundMessage): void;
|
|
125
125
|
/** Route one live session event to the active turn's chunk queue. */
|
|
126
126
|
onSessionEvent(session: Session, event: SessionEvent): void;
|
|
127
|
+
/**
|
|
128
|
+
* Proactive context-high nudge: when the turn's observed context usage
|
|
129
|
+
* crosses the compaction threshold, ask the user (once per turn) whether to
|
|
130
|
+
* compact now, instead of waiting until the turn ends to report it.
|
|
131
|
+
*/
|
|
132
|
+
private maybeNudgeContext;
|
|
127
133
|
private target;
|
|
128
134
|
/** Completion-card target: in groups, @ the requester so they notice the result. */
|
|
129
135
|
private taskTarget;
|
|
@@ -142,6 +148,21 @@ export declare class AgentRunner {
|
|
|
142
148
|
* Best-effort: without a workspace registry this is a no-op.
|
|
143
149
|
*/
|
|
144
150
|
private attachToWorkspace;
|
|
151
|
+
/**
|
|
152
|
+
* Historical sessions for the CURRENT work directory: this chat's binding
|
|
153
|
+
* records (filtered by workDir), then any other session the DSH workspace
|
|
154
|
+
* registry attaches to the directory (e.g. Web-created or older-chat
|
|
155
|
+
* sessions). Titles come from the binding record when known, otherwise from
|
|
156
|
+
* the host's session title service. Sorted newest first.
|
|
157
|
+
*/
|
|
158
|
+
private collectWorkdirSessions;
|
|
159
|
+
/**
|
|
160
|
+
* Session ids the DSH workspace registry attaches to a work directory.
|
|
161
|
+
* Best-effort: without a workspace registry this returns `[]`.
|
|
162
|
+
*/
|
|
163
|
+
private workspaceSessionIds;
|
|
164
|
+
/** Latest display title of a session via the host query service, or undefined. */
|
|
165
|
+
private sessionTitleOf;
|
|
145
166
|
private get agents();
|
|
146
167
|
private get sessions();
|
|
147
168
|
private defaultSelection;
|
|
@@ -193,6 +214,12 @@ export declare class AgentRunner {
|
|
|
193
214
|
private sendTurnStats;
|
|
194
215
|
private handleCommand;
|
|
195
216
|
private disposeAgent;
|
|
217
|
+
/**
|
|
218
|
+
* `/ps <note>` — append a note to the running task. Uses the agent's `steer`
|
|
219
|
+
* inbox: a running driver consumes the note at its next step boundary (so it
|
|
220
|
+
* steers the in-flight task), and an idle driver starts a new turn with it.
|
|
221
|
+
*/
|
|
222
|
+
private handleAppend;
|
|
196
223
|
private recordSession;
|
|
197
224
|
/**
|
|
198
225
|
* Automatically create a Web mirror for the session.
|
package/lib/runner.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAA2B,KAAK,OAAO,EAAE,KAAK,YAAY,EAAiB,MAAM,0BAA0B,CAAC;AAGnH,OAAO,KAAK,EAAE,cAAc,EAAgB,cAAc,EAA+B,WAAW,EAAc,MAAM,YAAY,CAAC;AAGrI,OAAO,KAAK,EAAE,YAAY,EAAkC,MAAM,cAAc,CAAC;AACjF,OAAO,EAAY,KAAK,QAAQ,EAAiB,MAAM,WAAW,CAAC;AAEnE,MAAM,WAAW,aAAa;IAC5B,gFAAgF;IAChF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gFAAgF;IAChF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oEAAoE;IACpE,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,8EAA8E;IAC9E,WAAW,CAAC,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAClD,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,wEAAwE;IACxE,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,6FAA6F;IAC7F,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,+EAA+E;IAC/E,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,4JAA4J;IAC5J,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,qBAAqB;IACpC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,WAAW,CAAC,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAClD,QAAQ,EAAE,QAAQ,CAAC;IACnB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,OAAO,CAAC;IACpB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,WAAW,EAAE,WAAW,CAAC;IACzB,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,aAAa,GAAG,qBAAqB,CAejF;
|
|
1
|
+
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"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"}
|
package/lib/runner.js
CHANGED
|
@@ -349,6 +349,10 @@ function detectImageMediaType(buf) {
|
|
|
349
349
|
return "image/gif";
|
|
350
350
|
return "image/png";
|
|
351
351
|
}
|
|
352
|
+
/** Compare two work-directory paths ignoring trailing slashes and case (Windows). */
|
|
353
|
+
function sameDir(a, b) {
|
|
354
|
+
return a.replace(/[\\/]+$/, "").toLowerCase() === b.replace(/[\\/]+$/, "").toLowerCase();
|
|
355
|
+
}
|
|
352
356
|
/** How often the proactive progress watchdog re-checks whether a status card is due (ms). */
|
|
353
357
|
const PROGRESS_WATCHDOG_CHECK_MS = 15_000;
|
|
354
358
|
export class AgentRunner {
|
|
@@ -452,6 +456,13 @@ export class AgentRunner {
|
|
|
452
456
|
});
|
|
453
457
|
return;
|
|
454
458
|
}
|
|
459
|
+
// A task is already running (or queued): tell the user they can append a
|
|
460
|
+
// note to the in-flight task with /ps instead of queueing a brand-new turn
|
|
461
|
+
// behind it. The message still queues as before.
|
|
462
|
+
if (this.running) {
|
|
463
|
+
const hint = this.t.busyHint(truncate(msg.text, 20));
|
|
464
|
+
void this.adapter.sendText(this.target(msg), hint).catch(() => undefined);
|
|
465
|
+
}
|
|
455
466
|
this.queue.push(msg);
|
|
456
467
|
void this.drain();
|
|
457
468
|
}
|
|
@@ -464,6 +475,21 @@ export class AgentRunner {
|
|
|
464
475
|
return;
|
|
465
476
|
if (event.seq < turn.firstSeq)
|
|
466
477
|
return;
|
|
478
|
+
// Track context usage while the turn runs so we can nudge the user to
|
|
479
|
+
// compact before the window fills up (deduped to one nudge per turn).
|
|
480
|
+
if (event.type === "request/context") {
|
|
481
|
+
if (typeof event.data.contextWindow === "number")
|
|
482
|
+
turn.contextWindow = event.data.contextWindow;
|
|
483
|
+
this.maybeNudgeContext(turn);
|
|
484
|
+
return;
|
|
485
|
+
}
|
|
486
|
+
if (event.type === "assistant/message") {
|
|
487
|
+
const usage = event.data.usage;
|
|
488
|
+
if (usage !== undefined && typeof usage.inputTokens === "number") {
|
|
489
|
+
turn.contextSize = usage.inputTokens;
|
|
490
|
+
this.maybeNudgeContext(turn);
|
|
491
|
+
}
|
|
492
|
+
}
|
|
467
493
|
if (event.type === "assistant/chunk") {
|
|
468
494
|
const chunk = event.data.chunk;
|
|
469
495
|
// First reasoning delta = the milestone the proactive progress notice reports.
|
|
@@ -501,6 +527,45 @@ export class AgentRunner {
|
|
|
501
527
|
applyToolCall(turn, label);
|
|
502
528
|
}
|
|
503
529
|
}
|
|
530
|
+
/**
|
|
531
|
+
* Proactive context-high nudge: when the turn's observed context usage
|
|
532
|
+
* crosses the compaction threshold, ask the user (once per turn) whether to
|
|
533
|
+
* compact now, instead of waiting until the turn ends to report it.
|
|
534
|
+
*/
|
|
535
|
+
maybeNudgeContext(turn) {
|
|
536
|
+
if (turn.contextNudged)
|
|
537
|
+
return;
|
|
538
|
+
const size = turn.contextSize;
|
|
539
|
+
const window = turn.contextWindow;
|
|
540
|
+
if (size === undefined || window === undefined || window <= 0)
|
|
541
|
+
return;
|
|
542
|
+
const pct = Math.round((size / window) * 100);
|
|
543
|
+
if (pct < AgentRunner.COMPACT_THRESHOLD_PCT)
|
|
544
|
+
return;
|
|
545
|
+
turn.contextNudged = true;
|
|
546
|
+
void (async () => {
|
|
547
|
+
const target = { chatKey: this.chatKey, chatType: this.chatType };
|
|
548
|
+
const nudge = this.t.contextHighPrompt(pct);
|
|
549
|
+
try {
|
|
550
|
+
if (await this.confirmAction(target, nudge)) {
|
|
551
|
+
if (this.agent?.status === "running" || this.running) {
|
|
552
|
+
// Compaction needs an idle agent; run it right after this turn ends.
|
|
553
|
+
turn.compactAfterTurn = true;
|
|
554
|
+
await this.adapter.sendText(target, this.t.compactQueued);
|
|
555
|
+
}
|
|
556
|
+
else {
|
|
557
|
+
await this.compact(target);
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
else {
|
|
561
|
+
await this.adapter.sendText(target, this.t.actionCancelled);
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
catch (error) {
|
|
565
|
+
this.log(`connect: context nudge failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
566
|
+
}
|
|
567
|
+
})();
|
|
568
|
+
}
|
|
504
569
|
target(msg) {
|
|
505
570
|
return {
|
|
506
571
|
chatKey: this.chatKey,
|
|
@@ -548,7 +613,7 @@ export class AgentRunner {
|
|
|
548
613
|
}
|
|
549
614
|
}
|
|
550
615
|
/** Present a destructive-action confirmation; true only when the user confirms. */
|
|
551
|
-
async confirmAction(target, promptText) {
|
|
616
|
+
async confirmAction(target, promptText, messageId) {
|
|
552
617
|
const { choice } = await this.adapter.promptChoice(target, {
|
|
553
618
|
title: this.t.confirmTitle,
|
|
554
619
|
description: promptText,
|
|
@@ -556,7 +621,7 @@ export class AgentRunner {
|
|
|
556
621
|
{ id: "confirm:yes", label: this.t.confirmYes },
|
|
557
622
|
{ id: "confirm:no", label: this.t.confirmNo },
|
|
558
623
|
],
|
|
559
|
-
});
|
|
624
|
+
}, messageId);
|
|
560
625
|
return choice === "confirm:yes";
|
|
561
626
|
}
|
|
562
627
|
async drain() {
|
|
@@ -706,6 +771,69 @@ export class AgentRunner {
|
|
|
706
771
|
this.log(`connect: attachToWorkspace(${sessionId}) skipped: ${String(error)}`);
|
|
707
772
|
}
|
|
708
773
|
}
|
|
774
|
+
/**
|
|
775
|
+
* Historical sessions for the CURRENT work directory: this chat's binding
|
|
776
|
+
* records (filtered by workDir), then any other session the DSH workspace
|
|
777
|
+
* registry attaches to the directory (e.g. Web-created or older-chat
|
|
778
|
+
* sessions). Titles come from the binding record when known, otherwise from
|
|
779
|
+
* the host's session title service. Sorted newest first.
|
|
780
|
+
*/
|
|
781
|
+
async collectWorkdirSessions() {
|
|
782
|
+
const binding = this.bindings.get(this.channel, this.chatKey);
|
|
783
|
+
const byId = new Map();
|
|
784
|
+
for (const s of binding?.sessions ?? []) {
|
|
785
|
+
if (sameDir(s.workDir, this.workDir))
|
|
786
|
+
byId.set(s.sessionId, s.title);
|
|
787
|
+
}
|
|
788
|
+
for (const sessionId of await this.workspaceSessionIds(this.workDir)) {
|
|
789
|
+
if (byId.has(sessionId))
|
|
790
|
+
continue;
|
|
791
|
+
const known = (binding?.sessions ?? []).find((s) => s.sessionId === sessionId);
|
|
792
|
+
const title = known?.title ?? (await this.sessionTitleOf(sessionId)) ?? sessionId;
|
|
793
|
+
byId.set(sessionId, title);
|
|
794
|
+
}
|
|
795
|
+
const lastActive = new Map();
|
|
796
|
+
for (const s of binding?.sessions ?? [])
|
|
797
|
+
lastActive.set(s.sessionId, s.lastActiveAt);
|
|
798
|
+
return [...byId.entries()]
|
|
799
|
+
.map(([sessionId, title]) => ({ sessionId, title }))
|
|
800
|
+
.sort((a, b) => (lastActive.get(b.sessionId) ?? 0) - (lastActive.get(a.sessionId) ?? 0));
|
|
801
|
+
}
|
|
802
|
+
/**
|
|
803
|
+
* Session ids the DSH workspace registry attaches to a work directory.
|
|
804
|
+
* Best-effort: without a workspace registry this returns `[]`.
|
|
805
|
+
*/
|
|
806
|
+
async workspaceSessionIds(workDir) {
|
|
807
|
+
const registry = this.ctx.get("workspaceRegistry");
|
|
808
|
+
if (registry?.resolveByPath === undefined)
|
|
809
|
+
return [];
|
|
810
|
+
try {
|
|
811
|
+
const ws = await registry.resolveByPath(workDir);
|
|
812
|
+
return (ws?.sessionIds ?? []).map(String);
|
|
813
|
+
}
|
|
814
|
+
catch {
|
|
815
|
+
return [];
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
/** Latest display title of a session via the host query service, or undefined. */
|
|
819
|
+
async sessionTitleOf(sessionId) {
|
|
820
|
+
const query = this.ctx.get("sessionQuery");
|
|
821
|
+
if (query?.readTitle === undefined)
|
|
822
|
+
return undefined;
|
|
823
|
+
try {
|
|
824
|
+
// `readTitle` returns the folded `SessionTitleSnapshot` object in some
|
|
825
|
+
// host versions and the bare title string in others — accept both.
|
|
826
|
+
const result = await query.readTitle(sessionId);
|
|
827
|
+
if (typeof result === "string")
|
|
828
|
+
return result;
|
|
829
|
+
if (result !== undefined && typeof result.title === "string")
|
|
830
|
+
return result.title;
|
|
831
|
+
return undefined;
|
|
832
|
+
}
|
|
833
|
+
catch {
|
|
834
|
+
return undefined;
|
|
835
|
+
}
|
|
836
|
+
}
|
|
709
837
|
// Service lookups must go through ctx.get(): property access (ctx.agents) is
|
|
710
838
|
// fiber-scoped and rejected from the async Feishu callback with "without inject".
|
|
711
839
|
get agents() {
|
|
@@ -773,7 +901,7 @@ export class AgentRunner {
|
|
|
773
901
|
this.turn = {
|
|
774
902
|
firstSeq, chunks, lastText: "",
|
|
775
903
|
reasoning: false, hintPushed: false, lastIndex: undefined, pushedAny: false,
|
|
776
|
-
startedAt: now, lastPushAt: now, toolCount: 0,
|
|
904
|
+
startedAt: now, lastPushAt: now, toolCount: 0, contextNudged: false, compactAfterTurn: false,
|
|
777
905
|
};
|
|
778
906
|
// Liveness heartbeat: while the agent is working, keep the streaming card
|
|
779
907
|
// visibly alive even through long reasoning or tool-execution stretches
|
|
@@ -850,6 +978,14 @@ export class AgentRunner {
|
|
|
850
978
|
}
|
|
851
979
|
endChunks();
|
|
852
980
|
await streamPromise;
|
|
981
|
+
// The user confirmed a compaction nudge while this turn was still running:
|
|
982
|
+
// the agent is idle now, so compact before summarizing.
|
|
983
|
+
const compactAfterTurn = this.turn.compactAfterTurn;
|
|
984
|
+
if (compactAfterTurn) {
|
|
985
|
+
await this.compact(this.target(msg)).catch((error) => {
|
|
986
|
+
this.log(`connect: deferred compaction failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
987
|
+
});
|
|
988
|
+
}
|
|
853
989
|
const outcome = summarizeTurn(agent.session.events, firstSeq);
|
|
854
990
|
const text = outcome.text !== "" ? outcome.text : this.turn.lastText;
|
|
855
991
|
this.turn = undefined;
|
|
@@ -1265,6 +1401,10 @@ export class AgentRunner {
|
|
|
1265
1401
|
await this.handleExport(target, command.format);
|
|
1266
1402
|
break;
|
|
1267
1403
|
}
|
|
1404
|
+
case "ps": {
|
|
1405
|
+
await this.handleAppend(command.text, target, msg);
|
|
1406
|
+
break;
|
|
1407
|
+
}
|
|
1268
1408
|
case "help": {
|
|
1269
1409
|
await this.adapter.sendText(target, helpText(this.t));
|
|
1270
1410
|
break;
|
|
@@ -1285,6 +1425,27 @@ export class AgentRunner {
|
|
|
1285
1425
|
}
|
|
1286
1426
|
await handle?.dispose().catch(() => undefined);
|
|
1287
1427
|
}
|
|
1428
|
+
/**
|
|
1429
|
+
* `/ps <note>` — append a note to the running task. Uses the agent's `steer`
|
|
1430
|
+
* inbox: a running driver consumes the note at its next step boundary (so it
|
|
1431
|
+
* steers the in-flight task), and an idle driver starts a new turn with it.
|
|
1432
|
+
*/
|
|
1433
|
+
async handleAppend(text, target, msg) {
|
|
1434
|
+
if (text === "") {
|
|
1435
|
+
await this.adapter.sendText(target, this.t.psUsage);
|
|
1436
|
+
return;
|
|
1437
|
+
}
|
|
1438
|
+
const agent = this.agent;
|
|
1439
|
+
if (agent === undefined) {
|
|
1440
|
+
await this.adapter.sendText(target, this.t.psNoActiveSession);
|
|
1441
|
+
return;
|
|
1442
|
+
}
|
|
1443
|
+
const note = this.t.psAppendLabel(text);
|
|
1444
|
+
const content = await this.buildUserContent({ ...msg, text: note });
|
|
1445
|
+
agent.steer(createUserMessage({ content, source: { kind: "user" } }));
|
|
1446
|
+
this.touchBinding(msg);
|
|
1447
|
+
await this.adapter.sendText(target, this.t.psReceived(text));
|
|
1448
|
+
}
|
|
1288
1449
|
recordSession(sessionId, title, ownerKey) {
|
|
1289
1450
|
const binding = this.bindings.get(this.channel, this.chatKey);
|
|
1290
1451
|
const others = (binding?.sessions ?? []).filter((s) => s.sessionId !== sessionId);
|
|
@@ -1438,11 +1599,20 @@ export class AgentRunner {
|
|
|
1438
1599
|
return;
|
|
1439
1600
|
}
|
|
1440
1601
|
const item = items.find((i) => i.id === choice);
|
|
1441
|
-
if (item === undefined)
|
|
1602
|
+
if (item === undefined) {
|
|
1603
|
+
// The tap belonged to a previous card generation (e.g. a rapid second
|
|
1604
|
+
// tap on the old menu while the new one was still being redrawn). Don't
|
|
1605
|
+
// silently swallow it: redraw the current menu so the chain stays usable.
|
|
1606
|
+
await this.openMenu(target, msg, menuId, stack, messageId);
|
|
1442
1607
|
return;
|
|
1443
|
-
|
|
1608
|
+
}
|
|
1609
|
+
const feedback = await item.onSelect(target, msg, messageId);
|
|
1444
1610
|
if (item.leaf === true) {
|
|
1445
|
-
//
|
|
1611
|
+
// Every leaf press must answer visibly: send the action's result feedback
|
|
1612
|
+
// (if any) before returning to the root menu on the same card.
|
|
1613
|
+
if (feedback !== undefined && feedback !== "") {
|
|
1614
|
+
await this.adapter.sendText(target, feedback).catch(() => undefined);
|
|
1615
|
+
}
|
|
1446
1616
|
await this.openMenu(target, msg, "root", [], messageId);
|
|
1447
1617
|
}
|
|
1448
1618
|
}
|
|
@@ -1470,39 +1640,47 @@ export class AgentRunner {
|
|
|
1470
1640
|
onSelect: async (t, m) => {
|
|
1471
1641
|
this.workDir = w.path;
|
|
1472
1642
|
await this.newChat(m);
|
|
1643
|
+
return this.t.dirSwitched(w.path);
|
|
1473
1644
|
},
|
|
1474
1645
|
}));
|
|
1475
1646
|
}
|
|
1476
1647
|
case "chat": {
|
|
1477
1648
|
const binding = this.bindings.get(this.channel, this.chatKey);
|
|
1478
|
-
const sessions = binding?.sessions ?? [];
|
|
1479
1649
|
const active = binding?.sessionId;
|
|
1480
1650
|
const hasWebMirror = binding?.webMirrorSessionId !== undefined;
|
|
1481
|
-
const items =
|
|
1482
|
-
|
|
1483
|
-
const isMirrored = hasWebMirror && binding.webMirrorSessionId === s.sessionId;
|
|
1651
|
+
const items = (await this.collectWorkdirSessions()).map(({ sessionId, title }) => {
|
|
1652
|
+
const isMirrored = hasWebMirror && binding?.webMirrorSessionId === sessionId;
|
|
1484
1653
|
const mirrorIndicator = isMirrored ? ` ${this.t.webMirrorIndicator}` : "";
|
|
1485
|
-
const activeIndicator =
|
|
1654
|
+
const activeIndicator = sessionId === active ? "●" : "○";
|
|
1486
1655
|
return {
|
|
1487
|
-
id: `session:${
|
|
1488
|
-
label: `${activeIndicator} ${
|
|
1656
|
+
id: `session:${sessionId}`,
|
|
1657
|
+
label: `${activeIndicator} ${title || sessionId}${mirrorIndicator}`,
|
|
1489
1658
|
leaf: true,
|
|
1490
1659
|
onSelect: async (t, m) => {
|
|
1491
|
-
await this.switchTo(
|
|
1660
|
+
await this.switchTo(sessionId, m.senderKey);
|
|
1661
|
+
return this.t.sessionSwitched(title || sessionId);
|
|
1492
1662
|
},
|
|
1493
1663
|
};
|
|
1494
1664
|
});
|
|
1665
|
+
if (items.length === 0) {
|
|
1666
|
+
items.push({
|
|
1667
|
+
id: "none:history",
|
|
1668
|
+
label: this.t.noSessionsInWorkdir(this.workDir),
|
|
1669
|
+
leaf: true,
|
|
1670
|
+
onSelect: async () => this.t.noSessionsInWorkdir(this.workDir),
|
|
1671
|
+
});
|
|
1672
|
+
}
|
|
1495
1673
|
items.push({
|
|
1496
1674
|
id: "action:new",
|
|
1497
1675
|
label: this.t.menuNewChat,
|
|
1498
1676
|
leaf: true,
|
|
1499
|
-
onSelect: async (t, m) => {
|
|
1500
|
-
|
|
1677
|
+
onSelect: async (t, m, messageId) => {
|
|
1678
|
+
// Reuse the menu card for the confirm prompt so no stale card is left behind.
|
|
1679
|
+
if (await this.confirmAction(t, this.t.confirmNewText, messageId)) {
|
|
1501
1680
|
await this.newChat(m);
|
|
1681
|
+
return this.t.newChatDone;
|
|
1502
1682
|
}
|
|
1503
|
-
|
|
1504
|
-
await this.adapter.sendText(t, this.t.actionCancelled);
|
|
1505
|
-
}
|
|
1683
|
+
return this.t.actionCancelled;
|
|
1506
1684
|
},
|
|
1507
1685
|
});
|
|
1508
1686
|
return items;
|
|
@@ -1676,10 +1854,11 @@ export class AgentRunner {
|
|
|
1676
1854
|
leaf: true,
|
|
1677
1855
|
onSelect: async (t, m) => {
|
|
1678
1856
|
await this.setModel(c.provider, c.model, m);
|
|
1857
|
+
return this.t.modelSet(c.name);
|
|
1679
1858
|
},
|
|
1680
1859
|
}));
|
|
1681
1860
|
if (items.length === 0) {
|
|
1682
|
-
items.push({ id: "model:none", label: this.t.noModelsFound, onSelect: async () =>
|
|
1861
|
+
items.push({ id: "model:none", label: this.t.noModelsFound, leaf: true, onSelect: async () => this.t.noModelsFound });
|
|
1683
1862
|
}
|
|
1684
1863
|
return items;
|
|
1685
1864
|
}
|
|
@@ -1725,6 +1904,7 @@ export class AgentRunner {
|
|
|
1725
1904
|
leaf: true,
|
|
1726
1905
|
onSelect: async (t, m) => {
|
|
1727
1906
|
await this.setReasoning(undefined, m);
|
|
1907
|
+
return this.t.reasoningSet(this.t.effortDefault);
|
|
1728
1908
|
},
|
|
1729
1909
|
},
|
|
1730
1910
|
];
|
|
@@ -1735,6 +1915,7 @@ export class AgentRunner {
|
|
|
1735
1915
|
leaf: true,
|
|
1736
1916
|
onSelect: async (t, m) => {
|
|
1737
1917
|
await this.setReasoning(e.id, m);
|
|
1918
|
+
return this.t.reasoningSet(e.name);
|
|
1738
1919
|
},
|
|
1739
1920
|
});
|
|
1740
1921
|
}
|
|
@@ -1752,11 +1933,14 @@ export class AgentRunner {
|
|
|
1752
1933
|
}
|
|
1753
1934
|
/** Switch the user-facing language for this chat, persisted in its binding. */
|
|
1754
1935
|
async setLanguage(lang, target, msg) {
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1936
|
+
const changed = lang !== this.language;
|
|
1937
|
+
if (changed) {
|
|
1938
|
+
this.language = lang;
|
|
1939
|
+
this.t = messages(lang);
|
|
1940
|
+
}
|
|
1759
1941
|
// Persist into the chat's binding (create one if the chat has no session yet).
|
|
1942
|
+
// Persisting again for the already-active language is harmless and keeps the
|
|
1943
|
+
// button press answer visible either way.
|
|
1760
1944
|
const binding = this.bindings.get(this.channel, this.chatKey);
|
|
1761
1945
|
if (binding !== undefined) {
|
|
1762
1946
|
this.bindings.put({ ...binding, language: lang, lastActiveAt: Date.now() });
|
|
@@ -1774,7 +1958,8 @@ export class AgentRunner {
|
|
|
1774
1958
|
sessions: [],
|
|
1775
1959
|
});
|
|
1776
1960
|
}
|
|
1777
|
-
|
|
1961
|
+
const label = lang === "zh" ? this.t.languageZh : this.t.languageEn;
|
|
1962
|
+
await this.adapter.sendText(target, changed ? this.t.languageSet(label) : this.t.languageAlready(label));
|
|
1778
1963
|
}
|
|
1779
1964
|
/**
|
|
1780
1965
|
* Switch the notification level for this chat (persisted in its binding and
|
|
@@ -1941,7 +2126,15 @@ export class AgentRunner {
|
|
|
1941
2126
|
async showHistory(target, limit) {
|
|
1942
2127
|
const agent = this.agent;
|
|
1943
2128
|
if (agent === undefined) {
|
|
1944
|
-
|
|
2129
|
+
// No live agent: there may still be historical sessions for the current
|
|
2130
|
+
// work directory. List them instead of a bare "no active session".
|
|
2131
|
+
const sessions = await this.collectWorkdirSessions();
|
|
2132
|
+
if (sessions.length === 0) {
|
|
2133
|
+
await this.adapter.sendText(target, this.t.noSessionsInWorkdir(this.workDir));
|
|
2134
|
+
return;
|
|
2135
|
+
}
|
|
2136
|
+
const lines = sessions.slice(0, limit).map((s, i) => `${i + 1}. ${s.title || s.sessionId}`);
|
|
2137
|
+
await this.adapter.sendText(target, this.t.historySessions(sessions.length, lines.join("\n")));
|
|
1945
2138
|
return;
|
|
1946
2139
|
}
|
|
1947
2140
|
const events = agent.session.events;
|