dsh-session-messaging 0.0.0-stage → 0.1.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/tools.js ADDED
@@ -0,0 +1,172 @@
1
+ /**
2
+ * Model-facing tools for cross-session messaging. The tools are thin adapters
3
+ * over {@link SessionMessagingService}; the calling agent's own session is the
4
+ * only identity source, matching the subagent-control tools.
5
+ * @module dsh-session-messaging/tools
6
+ */
7
+ import { defineTool } from '@deepseek-ai/dsh-tools';
8
+ export const name = 'session-messaging-tools';
9
+ export const inject = ['tools', 'sessionMessaging'];
10
+ /**
11
+ * Reject calls without an owning agent session.
12
+ * @param agent - execution identity's agent, when present.
13
+ * @returns the owning agent.
14
+ */
15
+ function requireAgent(agent) {
16
+ if (agent === undefined) {
17
+ throw new Error('session messaging tools require an owning agent session');
18
+ }
19
+ return agent;
20
+ }
21
+ /**
22
+ * Register the peer-list, relay, and opt-in tools.
23
+ * @param ctx - Cordis context with `tools` and `sessionMessaging` ready.
24
+ */
25
+ export function apply(ctx) {
26
+ ctx.tools.register(defineTool({
27
+ name: 'session_peers',
28
+ description: 'List other user-launched Harness sessions in the same working directory that this session can message. Use it before relaying coordination information. Only user-launched top-level sessions can use this tool; subagent sessions must use their parent/child channel. Sessions appear only while live in this Harness process.',
29
+ parameters: {},
30
+ output: {
31
+ schema: {
32
+ type: 'object',
33
+ additionalProperties: false,
34
+ properties: {
35
+ peers: {
36
+ type: 'array',
37
+ required: true,
38
+ items: {
39
+ type: 'object',
40
+ additionalProperties: false,
41
+ properties: {
42
+ sessionId: { type: 'string', required: true, description: 'Stable target id for session_send.' },
43
+ status: { type: 'string', required: true, enum: ['idle', 'running'] },
44
+ canReceive: { type: 'boolean', required: true, description: 'Whether the session accepts peer messages.' },
45
+ writeScopes: {
46
+ type: 'array',
47
+ required: true,
48
+ items: { type: 'string' },
49
+ description: 'Advisory paths that peer session declared it is changing.',
50
+ },
51
+ },
52
+ },
53
+ },
54
+ },
55
+ },
56
+ render: (_args, value) => [{
57
+ type: 'text',
58
+ text: value.peers.length === 0
59
+ ? 'No other live user-launched sessions are available in this working directory.'
60
+ : value.peers.map(peer => `${peer.sessionId} (${peer.status}, ${peer.canReceive ? 'accepting messages' : 'not opted in'})`).join('\n'),
61
+ }],
62
+ presentationMeta: (_args, value) => ({ peers: value.peers }),
63
+ },
64
+ execute(_args, exec) {
65
+ const peers = ctx.sessionMessaging.listPeers(requireAgent(exec.agent));
66
+ return Promise.resolve({ peers: peers.map(peer => ({ ...peer, writeScopes: [...peer.writeScopes] })) });
67
+ },
68
+ presentCall: () => ({ card: 'generic', title: 'List session peers', kind: 'search' }),
69
+ }));
70
+ ctx.tools.register(defineTool({
71
+ name: 'session_send',
72
+ description: 'Send a message to another user-launched Harness session in the same working directory. Use it to coordinate tasks and declared file-write scope with a peer session. The message is recorded as a user message in the target session, attributed to this session; it is peer input, not a user instruction. Both the caller and the target must be user-launched top-level sessions; subagent sessions use their parent/child channel. The target must be live and must not have paused reception. Success means the target accepted the message, not that it acted on it.',
73
+ parameters: {
74
+ targetSessionId: { type: 'string', required: true, description: 'Exact session id from session_peers.' },
75
+ message: { type: 'string', required: true, description: 'Coordination message. State what changed, what you need, and what you will not touch.' },
76
+ writeScopes: {
77
+ type: 'array',
78
+ items: { type: 'string' },
79
+ description: 'Advisory workspace paths this session is changing, so the peer can avoid them.',
80
+ },
81
+ replyTo: { type: 'string', description: 'Optional message id this message answers.' },
82
+ },
83
+ output: {
84
+ schema: {
85
+ type: 'object',
86
+ additionalProperties: false,
87
+ properties: {
88
+ accepted: { type: 'boolean', required: true },
89
+ messageId: { type: 'string', required: true },
90
+ targetSessionId: { type: 'string', required: true },
91
+ targetStatus: { type: 'string', required: true, enum: ['idle', 'running'] },
92
+ conflicts: {
93
+ type: 'array',
94
+ required: true,
95
+ items: {
96
+ type: 'object',
97
+ additionalProperties: false,
98
+ properties: {
99
+ sessionId: { type: 'string', required: true },
100
+ scopes: { type: 'array', required: true, items: { type: 'string' } },
101
+ },
102
+ },
103
+ description: 'Peers whose declared write scopes overlap yours; coordinate before writing.',
104
+ },
105
+ },
106
+ },
107
+ render: (_args, value) => {
108
+ const warning = value.conflicts.length === 0
109
+ ? ''
110
+ : ` Conflict warning: ${value.conflicts.map(conflict => `${conflict.sessionId} also declared ${conflict.scopes.join(', ')}`).join('; ')}. Coordinate before writing those paths.`;
111
+ return [{
112
+ type: 'text',
113
+ text: `Message ${value.messageId} accepted by session ${value.targetSessionId} (${value.targetStatus}). Acceptance means the message is in that session's inbox; it does not confirm the peer processed it.${warning}`,
114
+ }];
115
+ },
116
+ presentationMeta: (_args, value) => ({ targetSessionId: value.targetSessionId, messageId: value.messageId }),
117
+ },
118
+ async execute(args, exec) {
119
+ const receipt = await ctx.sessionMessaging.send(requireAgent(exec.agent), {
120
+ targetSessionId: args.targetSessionId,
121
+ message: args.message,
122
+ ...(args.writeScopes === undefined ? {} : { writeScopes: args.writeScopes }),
123
+ ...(args.replyTo === undefined ? {} : { replyTo: args.replyTo }),
124
+ });
125
+ return {
126
+ ...receipt,
127
+ conflicts: receipt.conflicts.map(conflict => ({
128
+ sessionId: conflict.sessionId,
129
+ scopes: [...conflict.scopes],
130
+ })),
131
+ };
132
+ },
133
+ presentCall: args => ({
134
+ card: 'generic',
135
+ title: `Message ${args.targetSessionId}`,
136
+ kind: 'other',
137
+ rawInput: { targetSessionId: args.targetSessionId, message: args.message },
138
+ }),
139
+ }));
140
+ ctx.tools.register(defineTool({
141
+ name: 'session_reception',
142
+ description: 'Set whether this session accepts peer messages. Reception is on by default; set enabled to false to pause it, or back to true to resume. Only user-launched top-level sessions can use this tool; subagent sessions use their parent/child channel. Optionally declare the workspace paths this session is changing so peers can avoid them.',
143
+ parameters: {
144
+ enabled: { type: 'boolean', required: true, description: 'Whether this session accepts peer messages.' },
145
+ writeScopes: {
146
+ type: 'array',
147
+ items: { type: 'string' },
148
+ description: 'Advisory workspace paths this session is changing.',
149
+ },
150
+ },
151
+ output: {
152
+ schema: {
153
+ type: 'object',
154
+ additionalProperties: false,
155
+ properties: {
156
+ enabled: { type: 'boolean', required: true },
157
+ writeScopes: { type: 'array', required: true, items: { type: 'string' } },
158
+ },
159
+ },
160
+ render: (_args, value) => [{
161
+ type: 'text',
162
+ text: value.enabled
163
+ ? `This session accepts peer messages${value.writeScopes.length > 0 ? ` and declares: ${value.writeScopes.join(', ')}` : ''}.`
164
+ : 'This session has paused peer messages.',
165
+ }],
166
+ },
167
+ execute(args, exec) {
168
+ const entry = ctx.sessionMessaging.setConsent(requireAgent(exec.agent), args.enabled, args.writeScopes);
169
+ return Promise.resolve({ enabled: entry.enabled, writeScopes: [...entry.writeScopes] });
170
+ },
171
+ }));
172
+ }
package/lib/types.d.ts ADDED
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Durable message-source declaration for relayed session messages. Importing
3
+ * this module for its types adds the `session-message` kind to
4
+ * `MessageSourceMap`, which is what makes the receiving `user/message`
5
+ * reconstructable from the session log.
6
+ * @module dsh-session-messaging/types
7
+ */
8
+ import type { SessionId } from '@deepseek-ai/dsh-session';
9
+ declare module '@deepseek-ai/dsh-llm' {
10
+ interface MessageSourceMap {
11
+ /** A message another user-launched session relayed to this one. */
12
+ 'session-message': {
13
+ readonly kind: 'session-message';
14
+ /** Shared relay form used by existing agent-to-agent messages. */
15
+ readonly form: 'relay';
16
+ /** Session id of the sending session. */
17
+ readonly senderSessionId: SessionId;
18
+ /** Sender-minted correlation id for receipts and replies. */
19
+ readonly messageId: string;
20
+ };
21
+ }
22
+ }
23
+ export {};
package/lib/types.js ADDED
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Durable message-source declaration for relayed session messages. Importing
3
+ * this module for its types adds the `session-message` kind to
4
+ * `MessageSourceMap`, which is what makes the receiving `user/message`
5
+ * reconstructable from the session log.
6
+ * @module dsh-session-messaging/types
7
+ */
8
+ export {};
package/locale/en.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "Session Messaging",
4
+ "description": "Peer messaging between user-launched sessions in one workspace: discover peers, relay coordination messages, pause reception, and receive advisory write-scope conflict warnings."
5
+ }
6
+ }
package/locale/zh.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "跨会话消息",
4
+ "description": "让同一工作区里用户自行启动的多个会话互相发消息:发现对等会话、转发协调消息、暂停接收,并获得建议性的文件写入范围冲突提示。"
5
+ }
6
+ }
package/package.json CHANGED
@@ -1,6 +1,92 @@
1
1
  {
2
2
  "name": "dsh-session-messaging",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.2",
4
+ "description": "Peer messaging between user-launched sessions in one workspace: discover peers, relay coordination messages, pause reception, and get advisory write-scope conflict warnings.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "main": "lib/index.js",
8
+ "types": "lib/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./lib/index.d.ts",
12
+ "default": "./lib/index.js"
13
+ },
14
+ "./tools": {
15
+ "types": "./lib/tools.d.ts",
16
+ "default": "./lib/tools.js"
17
+ },
18
+ "./locale/*.json": "./locale/*.json",
19
+ "./tools/locale/*.json": "./tools/locale/*.json",
20
+ "./tools/icon": "./assets/tools-icon.svg",
21
+ "./src/*": "./src/*",
22
+ "./package.json": "./package.json"
23
+ },
24
+ "files": [
25
+ "lib",
26
+ "locale",
27
+ "tools/locale",
28
+ "assets",
29
+ "cordis.patch.yml",
30
+ "README.md",
31
+ "README.zh-CN.md",
32
+ "LICENSE",
33
+ "CHANGELOG.md"
34
+ ],
35
+ "keywords": [
36
+ "deepseek-harness",
37
+ "dsh",
38
+ "dsh-plugin",
39
+ "cordis",
40
+ "session",
41
+ "messaging",
42
+ "multi-agent",
43
+ "agent-collaboration"
44
+ ],
45
+ "repository": {
46
+ "type": "git",
47
+ "url": "git+https://github.com/XBXyftx/dsh-session-messaging.git"
48
+ },
49
+ "homepage": "https://github.com/XBXyftx/dsh-session-messaging#readme",
50
+ "bugs": {
51
+ "url": "https://github.com/XBXyftx/dsh-session-messaging/issues"
52
+ },
53
+ "engines": {
54
+ "node": ">=22.19.0",
55
+ "dsh": ">=0.2.1-rc.2 <0.3.0"
56
+ },
57
+ "peerDependencies": {
58
+ "@deepseek-ai/cordis": "^4.0.5",
59
+ "@deepseek-ai/dsh-agent": "^0.2.1-rc.2",
60
+ "@deepseek-ai/dsh-llm": "^0.2.1-rc.2",
61
+ "@deepseek-ai/dsh-session": "^0.2.1-rc.2",
62
+ "@deepseek-ai/dsh-tools": "^0.2.1-rc.2",
63
+ "@deepseek-ai/schemastery": "^3.18.5"
64
+ },
65
+ "devDependencies": {
66
+ "@deepseek-ai/cordis": "^4.0.5",
67
+ "@deepseek-ai/dsh-agent": "^0.2.1-rc.2",
68
+ "@deepseek-ai/dsh-agent-loop-testkit": "^0.2.1-rc.2",
69
+ "@deepseek-ai/dsh-llm": "^0.2.1-rc.2",
70
+ "@deepseek-ai/dsh-session": "^0.2.1-rc.2",
71
+ "@deepseek-ai/dsh-tools": "^0.2.1-rc.2",
72
+ "@deepseek-ai/schemastery": "^3.18.5",
73
+ "@types/node": "^24.0.0",
74
+ "typescript": "^6.0.3"
75
+ },
76
+ "scripts": {
77
+ "build": "tsc -p tsconfig.build.json",
78
+ "typecheck": "tsc -p tsconfig.json",
79
+ "test": "node --experimental-strip-types --test tests/protocol.test.ts",
80
+ "test:integration": "node --experimental-strip-types tests/integration-smoke.ts",
81
+ "test:model-e2e": "node --experimental-strip-types tests/model-e2e-smoke.ts"
82
+ },
83
+ "dsh": {
84
+ "bundle": {
85
+ "patch": "./cordis.patch.yml"
86
+ }
87
+ },
88
+ "icon": "./assets/icon.svg",
89
+ "publishConfig": {
90
+ "access": "public"
91
+ }
92
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "Session Messaging Tools",
4
+ "description": "Model-facing tools: session_peers (discover peers), session_send (relay a message with optional write scopes), session_reception (pause or resume reception)."
5
+ }
6
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "跨会话消息工具",
4
+ "description": "模型工具:session_peers(发现对等会话)、session_send(发送消息并可声明写范围)、session_reception(暂停或恢复接收)。"
5
+ }
6
+ }