@deepseek-ai/dsh-tmux-context 0.1.6-alpha.2 → 0.1.7-alpha.2
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/lib/index.js +35 -57
- package/lib/types/index.d.ts +12 -0
- package/package.json +15 -15
package/lib/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
2
|
import z from "@deepseek-ai/schemastery";
|
|
3
3
|
import { z as z$1 } from "zod";
|
|
4
|
-
import { Service } from "@deepseek-ai/cordis";
|
|
4
|
+
import { Context, Service } from "@deepseek-ai/cordis";
|
|
5
5
|
//#region ../../typert/protocol/src/remote-error.ts
|
|
6
6
|
/**
|
|
7
7
|
* One Remote call failure: a real Error carrying its stable code and typed
|
|
@@ -47,7 +47,10 @@ function isTypertRemoteSegment(value) {
|
|
|
47
47
|
}
|
|
48
48
|
const REMOTE_METHOD_DESCRIPTOR = "@deepseek-ai/dsh-typert-protocol/remote-methods";
|
|
49
49
|
/**
|
|
50
|
-
* Bind one visible Service field to a Cordis key and Remote namespace.
|
|
50
|
+
* Bind one visible Service field to a Cordis key and Remote namespace. A
|
|
51
|
+
* service that owns a Cordis Context also gives its tree `ctx.invocation`,
|
|
52
|
+
* `undefined` outside a Remote call, so no `TypertRemoteService` is needed for
|
|
53
|
+
* a Host composition to read it.
|
|
51
54
|
* @param service - owning Service instance, normally `this`.
|
|
52
55
|
* @param serviceKey - exact Cordis service key.
|
|
53
56
|
* @param options - optional distinct wire namespace.
|
|
@@ -57,6 +60,8 @@ function bindTypertRemote(service, serviceKey, options = {}) {
|
|
|
57
60
|
validateName("service key", serviceKey);
|
|
58
61
|
const namespace = options.namespace ?? serviceKey;
|
|
59
62
|
validateName("namespace", namespace);
|
|
63
|
+
const ctx = Reflect.get(service, "ctx");
|
|
64
|
+
if (ctx instanceof Context) provideInvocationAccessor(ctx);
|
|
60
65
|
return Object.freeze({
|
|
61
66
|
service,
|
|
62
67
|
serviceKey,
|
|
@@ -78,6 +83,16 @@ var TypertRemoteService = class extends Service {
|
|
|
78
83
|
this.typertRemote = bindTypertRemote(this, this.name, options);
|
|
79
84
|
}
|
|
80
85
|
};
|
|
86
|
+
/**
|
|
87
|
+
* Make `ctx.invocation` read as `undefined` outside a Remote call instead of the
|
|
88
|
+
* reflect service's "cannot get property" error; a call-derived Context shadows
|
|
89
|
+
* the accessor with its own property. The first Remote Service constructed in a
|
|
90
|
+
* tree registers it on the root, where it outlives any one Service.
|
|
91
|
+
*/
|
|
92
|
+
function provideInvocationAccessor(ctx) {
|
|
93
|
+
if (Object.hasOwn(ctx.root.reflect.props, "invocation")) return;
|
|
94
|
+
ctx.root.accessor("invocation", { get: () => void 0 });
|
|
95
|
+
}
|
|
81
96
|
function Remote(methodExportOrOptions, context) {
|
|
82
97
|
if (typeof methodExportOrOptions === "string") {
|
|
83
98
|
validateName("Remote export name", methodExportOrOptions);
|
|
@@ -231,10 +246,10 @@ function freezeMessage(message) {
|
|
|
231
246
|
* @returns an immutable message with a fresh stable identity.
|
|
232
247
|
*/
|
|
233
248
|
function createMessage(input) {
|
|
234
|
-
return
|
|
249
|
+
return deepFreeze(structuredClone({
|
|
235
250
|
...input,
|
|
236
251
|
id: brandString(randomUUID())
|
|
237
|
-
});
|
|
252
|
+
}));
|
|
238
253
|
}
|
|
239
254
|
/**
|
|
240
255
|
* Create one identified user-role message and freeze it before publication.
|
|
@@ -510,25 +525,23 @@ function textOnlyImageText(ref) {
|
|
|
510
525
|
return `[image omitted because this model accepts text only; attachment sha256:${String(ref.attachmentId).slice(7, 15)}]`;
|
|
511
526
|
}
|
|
512
527
|
/**
|
|
513
|
-
* True when typed model content contains an image block
|
|
514
|
-
*
|
|
515
|
-
*
|
|
516
|
-
* survey), so a consumer cannot silently diverge on nesting depth.
|
|
528
|
+
* True when typed model content contains an image block. This is the one image
|
|
529
|
+
* walk shared by every image policy (capability gating, text-only
|
|
530
|
+
* serialization, compaction survey), so a consumer cannot silently diverge.
|
|
517
531
|
* @param content - typed model content blocks.
|
|
518
|
-
* @returns whether any
|
|
532
|
+
* @returns whether any block is an image.
|
|
519
533
|
*/
|
|
520
534
|
function contentHasImage(content) {
|
|
521
|
-
return content.some((block) => block.type === "image"
|
|
535
|
+
return content.some((block) => block.type === "image");
|
|
522
536
|
}
|
|
523
537
|
/**
|
|
524
|
-
* True when typed model content contains a file block
|
|
525
|
-
* tool-result content on the same recursion every file policy shares.
|
|
538
|
+
* True when typed model content contains a file block.
|
|
526
539
|
* Reads current content on every call without retaining scan results.
|
|
527
540
|
* @param content - typed model content blocks.
|
|
528
|
-
* @returns whether any
|
|
541
|
+
* @returns whether any block is a file.
|
|
529
542
|
*/
|
|
530
543
|
function contentHasFile(content) {
|
|
531
|
-
for (const block of content) if (block.type === "file"
|
|
544
|
+
for (const block of content) if (block.type === "file") return true;
|
|
532
545
|
return false;
|
|
533
546
|
}
|
|
534
547
|
/**
|
|
@@ -545,7 +558,7 @@ function fileHandleText(ref, readonlyPath) {
|
|
|
545
558
|
if (readonlyPath === void 0) return `[${identity} was uploaded, but the current execution environment cannot access a readable path. Report that limitation if its contents are needed; do not claim to have read it.]`;
|
|
546
559
|
return `[${identity}: verbatim read-only copy saved at ${quoted(readonlyPath)}. Read that path with your file tools when its contents are needed; copy it to a writable location before modifying it. When delegating file work, include this saved path in the delegation prompt; only subagents sharing this execution environment can read it.]`;
|
|
547
560
|
}
|
|
548
|
-
/** Replace every file occurrence
|
|
561
|
+
/** Replace every file occurrence with handle text. */
|
|
549
562
|
function replaceFilesWithHandles(blocks, resolvePath) {
|
|
550
563
|
let next;
|
|
551
564
|
for (const [index, block] of blocks.entries()) {
|
|
@@ -557,29 +570,10 @@ function replaceFilesWithHandles(blocks, resolvePath) {
|
|
|
557
570
|
});
|
|
558
571
|
continue;
|
|
559
572
|
}
|
|
560
|
-
if (block.type === "tool-result") {
|
|
561
|
-
const content = replaceFilesWithHandles(block.content, resolvePath);
|
|
562
|
-
if (content !== block.content) {
|
|
563
|
-
next ??= blocks.slice(0, index);
|
|
564
|
-
next.push({
|
|
565
|
-
...block,
|
|
566
|
-
content
|
|
567
|
-
});
|
|
568
|
-
continue;
|
|
569
|
-
}
|
|
570
|
-
}
|
|
571
573
|
next?.push(block);
|
|
572
574
|
}
|
|
573
575
|
return next ?? blocks;
|
|
574
576
|
}
|
|
575
|
-
/**
|
|
576
|
-
* Project durable file history into deterministic handle text for every model
|
|
577
|
-
* route. Unlike images, no provider receives file blocks natively, so this
|
|
578
|
-
* projection is unconditional in request assembly.
|
|
579
|
-
* @param messages - complete request history.
|
|
580
|
-
* @param resolvePath - resolve one reference's current execution-world read path.
|
|
581
|
-
* @returns the original list without files, otherwise shallow message copies with handle text.
|
|
582
|
-
*/
|
|
583
577
|
function projectFilesToText(messages, resolvePath) {
|
|
584
578
|
if (!messages.some((message) => contentHasFile(message.content))) return messages;
|
|
585
579
|
return messages.map((message) => {
|
|
@@ -590,7 +584,7 @@ function projectFilesToText(messages, resolvePath) {
|
|
|
590
584
|
};
|
|
591
585
|
});
|
|
592
586
|
}
|
|
593
|
-
/** Replace every image occurrence
|
|
587
|
+
/** Replace every image occurrence for a text-only model. */
|
|
594
588
|
function replaceImagesForTextModel(blocks) {
|
|
595
589
|
let next;
|
|
596
590
|
for (const [index, block] of blocks.entries()) {
|
|
@@ -602,26 +596,10 @@ function replaceImagesForTextModel(blocks) {
|
|
|
602
596
|
});
|
|
603
597
|
continue;
|
|
604
598
|
}
|
|
605
|
-
if (block.type === "tool-result") {
|
|
606
|
-
const content = replaceImagesForTextModel(block.content);
|
|
607
|
-
if (content !== block.content) {
|
|
608
|
-
next ??= blocks.slice(0, index);
|
|
609
|
-
next.push({
|
|
610
|
-
...block,
|
|
611
|
-
content
|
|
612
|
-
});
|
|
613
|
-
continue;
|
|
614
|
-
}
|
|
615
|
-
}
|
|
616
599
|
next?.push(block);
|
|
617
600
|
}
|
|
618
601
|
return next ?? blocks;
|
|
619
602
|
}
|
|
620
|
-
/**
|
|
621
|
-
* Project durable image history into deterministic text for an exact text-only model.
|
|
622
|
-
* @param messages - complete request history.
|
|
623
|
-
* @returns the original list without images, otherwise shallow message copies with stable placeholders.
|
|
624
|
-
*/
|
|
625
603
|
function projectImagesForTextModel(messages) {
|
|
626
604
|
if (!messages.some((message) => contentHasImage(message.content))) return messages;
|
|
627
605
|
return messages.map((message) => {
|
|
@@ -1214,8 +1192,9 @@ var LlmError = class extends HarnessError {
|
|
|
1214
1192
|
/** Remove replay state whose historical route is owned by another adapter. */
|
|
1215
1193
|
forAdapter(options, adapter) {
|
|
1216
1194
|
const messages = options.messages.map((message) => {
|
|
1195
|
+
if (message.role !== "assistant") return message;
|
|
1217
1196
|
const source = message.source;
|
|
1218
|
-
if (
|
|
1197
|
+
if (source.replayState === void 0) return message;
|
|
1219
1198
|
if (this.adapters.get(source.provider)?.adapter === adapter) return message;
|
|
1220
1199
|
return freezeMessage({
|
|
1221
1200
|
...message,
|
|
@@ -1441,10 +1420,10 @@ async function queryTmuxLocation(bash, logger, processId, signal) {
|
|
|
1441
1420
|
].join("\n");
|
|
1442
1421
|
let result;
|
|
1443
1422
|
try {
|
|
1444
|
-
result = await bash.
|
|
1423
|
+
result = await (await bash.execute(bash.resolve({
|
|
1445
1424
|
command,
|
|
1446
1425
|
signal
|
|
1447
|
-
}));
|
|
1426
|
+
}))).result();
|
|
1448
1427
|
} catch (error) {
|
|
1449
1428
|
const message = error instanceof Error ? error.message : String(error);
|
|
1450
1429
|
logger.warn(`tmux location query failed: ${message}; injecting no location this turn`);
|
|
@@ -1501,7 +1480,7 @@ function apply(ctx, config) {
|
|
|
1501
1480
|
stateSchema: tmuxContextStateSchema,
|
|
1502
1481
|
init: () => null,
|
|
1503
1482
|
apply: (state, event) => {
|
|
1504
|
-
if (event.type !== "user/message" || event.data.source.kind !== "
|
|
1483
|
+
if (event.type !== "user/message" || event.data.source.kind !== "tmux-context") return state;
|
|
1505
1484
|
const [block] = event.data.content;
|
|
1506
1485
|
if (block?.type !== "text") return state;
|
|
1507
1486
|
const newline = block.text.indexOf("\n");
|
|
@@ -1534,8 +1513,7 @@ function apply(ctx, config) {
|
|
|
1534
1513
|
text
|
|
1535
1514
|
}],
|
|
1536
1515
|
source: {
|
|
1537
|
-
kind:
|
|
1538
|
-
plugin: name,
|
|
1516
|
+
kind: name,
|
|
1539
1517
|
form: "snapshot",
|
|
1540
1518
|
sections: [{
|
|
1541
1519
|
name,
|
package/lib/types/index.d.ts
CHANGED
|
@@ -20,6 +20,18 @@
|
|
|
20
20
|
import type { Context } from '@deepseek-ai/cordis';
|
|
21
21
|
import z from '@deepseek-ai/schemastery';
|
|
22
22
|
import { z as zod } from 'zod';
|
|
23
|
+
import type { ContextFormed } from '@deepseek-ai/dsh-llm';
|
|
24
|
+
declare module '@deepseek-ai/dsh-llm' {
|
|
25
|
+
interface MessageSourceMap {
|
|
26
|
+
/** Location attribution; readers preserve the content without this producer.
|
|
27
|
+
* Its projection uses the kind to avoid repeated injection.
|
|
28
|
+
* @persistenceAttribution
|
|
29
|
+
*/
|
|
30
|
+
'tmux-context': {
|
|
31
|
+
kind: 'tmux-context';
|
|
32
|
+
} & ContextFormed;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
23
35
|
/** Cordis plugin name used by loader diagnostics. */
|
|
24
36
|
export declare const name = "tmux-context";
|
|
25
37
|
/** The agent registry that owns pre-step processing. */
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deepseek-ai/dsh-tmux-context",
|
|
3
3
|
"description": "Opt-in durable per-step context with this agent's tmux pane and window location",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.7-alpha.2",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -28,23 +28,23 @@
|
|
|
28
28
|
"license": "MIT",
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"zod": "^4.4.3",
|
|
31
|
-
"@deepseek-ai/schemastery": "
|
|
31
|
+
"@deepseek-ai/schemastery": "~3.18.4"
|
|
32
32
|
},
|
|
33
33
|
"peerDependencies": {
|
|
34
|
-
"@deepseek-ai/dsh-
|
|
35
|
-
"@deepseek-ai/dsh-
|
|
36
|
-
"@deepseek-ai/dsh-session": "
|
|
37
|
-
"@deepseek-ai/
|
|
38
|
-
"@deepseek-ai/
|
|
34
|
+
"@deepseek-ai/dsh-shell": "0.1.7-alpha.2",
|
|
35
|
+
"@deepseek-ai/dsh-agent": "0.1.7-alpha.2",
|
|
36
|
+
"@deepseek-ai/dsh-session": "0.1.7-alpha.2",
|
|
37
|
+
"@deepseek-ai/cordis": "~4.0.4",
|
|
38
|
+
"@deepseek-ai/dsh-session-projection": "0.1.7-alpha.2"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
|
-
"@deepseek-ai/dsh-agent": "
|
|
42
|
-
"@deepseek-ai/dsh-agent-loop-testkit": "
|
|
43
|
-
"@deepseek-ai/dsh-shell": "
|
|
44
|
-
"@deepseek-ai/dsh-
|
|
45
|
-
"@deepseek-ai/dsh-
|
|
46
|
-
"@deepseek-ai/dsh-
|
|
47
|
-
"@deepseek-ai/cordis": "
|
|
48
|
-
"@deepseek-ai/dsh-
|
|
41
|
+
"@deepseek-ai/dsh-agent": "0.1.7-alpha.2",
|
|
42
|
+
"@deepseek-ai/dsh-agent-loop-testkit": "0.1.7-alpha.2",
|
|
43
|
+
"@deepseek-ai/dsh-shell": "0.1.7-alpha.2",
|
|
44
|
+
"@deepseek-ai/dsh-session": "0.1.7-alpha.2",
|
|
45
|
+
"@deepseek-ai/dsh-llm": "0.1.7-alpha.2",
|
|
46
|
+
"@deepseek-ai/dsh-system-prompt": "0.1.7-alpha.2",
|
|
47
|
+
"@deepseek-ai/cordis": "~4.0.4",
|
|
48
|
+
"@deepseek-ai/dsh-session-projection": "0.1.7-alpha.2"
|
|
49
49
|
}
|
|
50
50
|
}
|