dsh-interconnect 0.6.4 → 0.7.0
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 +32 -2
- package/lib/index.js +81 -2
- package/lib/interconnect/index.js +81 -2
- package/lib/interconnect/index.js.map +2 -2
- package/lib/tool-interconnect/index.js +85 -1
- package/lib/tool-interconnect/index.js.map +2 -2
- package/lib/types/interconnect/index.d.ts +24 -2
- package/lib/types/interconnect/index.d.ts.map +1 -1
- package/lib/types/interconnect/types.d.ts +71 -1
- package/lib/types/interconnect/types.d.ts.map +1 -1
- package/lib/types/tool-interconnect/index.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -67,11 +67,17 @@ function apply(ctx) {
|
|
|
67
67
|
return [{ type: "text", text }];
|
|
68
68
|
}
|
|
69
69
|
},
|
|
70
|
-
async execute(args) {
|
|
70
|
+
async execute(args, exec) {
|
|
71
|
+
const sessionId = exec.agent?.session.id;
|
|
72
|
+
const self = sessionId === void 0 ? void 0 : interconnect.selfSender(String(sessionId));
|
|
71
73
|
const result = await interconnect.send({
|
|
72
74
|
baseUrl: args.baseUrl,
|
|
73
75
|
sessionId: args.sessionId,
|
|
74
76
|
text: args.text,
|
|
77
|
+
// Attribute this instance as the sender when configured, so the peer
|
|
78
|
+
// can reply back. The calling session id comes from the executing
|
|
79
|
+
// agent (the session that is sending).
|
|
80
|
+
...self === void 0 ? {} : { sender: self },
|
|
75
81
|
...args.delivery === void 0 ? {} : { delivery: args.delivery },
|
|
76
82
|
...args.resume === void 0 ? {} : { resume: args.resume }
|
|
77
83
|
});
|
|
@@ -174,6 +180,84 @@ function apply(ctx) {
|
|
|
174
180
|
};
|
|
175
181
|
}
|
|
176
182
|
}));
|
|
183
|
+
ctx.tools.register(defineTool({
|
|
184
|
+
name: "interconnect_reply",
|
|
185
|
+
description: 'Deliver one text message back to the peer that this session last received an interconnect message from. Only the LOCAL session id and the reply text are needed: the outbound target (the peer origin and its session id) is recalled from the message this session received, so you do not ask for an address twice. A session that never received a message through interconnect \u2014 or received one without a sender identity \u2014 reports reason "no-sender-known".',
|
|
186
|
+
parameters: {
|
|
187
|
+
sessionId: {
|
|
188
|
+
type: "string",
|
|
189
|
+
required: true,
|
|
190
|
+
description: "The LOCAL session id that received the message being replied to."
|
|
191
|
+
},
|
|
192
|
+
text: {
|
|
193
|
+
type: "string",
|
|
194
|
+
required: true,
|
|
195
|
+
description: "Message text delivered back to the recorded sender session."
|
|
196
|
+
},
|
|
197
|
+
delivery: {
|
|
198
|
+
type: "string",
|
|
199
|
+
enum: ["followup", "steer", "inject"],
|
|
200
|
+
description: "How the reply reaches the target agent, as in interconnect_send. Omit to use the receiver's configured default."
|
|
201
|
+
},
|
|
202
|
+
resume: {
|
|
203
|
+
type: "boolean",
|
|
204
|
+
description: "Wake the target session if it is persisted but has no running agent, as in interconnect_send. Off by default; the receiver may refuse."
|
|
205
|
+
}
|
|
206
|
+
},
|
|
207
|
+
output: {
|
|
208
|
+
schema: {
|
|
209
|
+
type: "object",
|
|
210
|
+
additionalProperties: false,
|
|
211
|
+
properties: {
|
|
212
|
+
delivered: { type: "boolean", required: true },
|
|
213
|
+
instance: { type: "string", required: true },
|
|
214
|
+
delivery: { type: "string" },
|
|
215
|
+
reason: { type: "string" }
|
|
216
|
+
}
|
|
217
|
+
},
|
|
218
|
+
render: (_args, value) => {
|
|
219
|
+
if (value.delivered) {
|
|
220
|
+
return [{
|
|
221
|
+
type: "text",
|
|
222
|
+
text: `replied to ${value.instance}${value.delivery === void 0 ? "" : ` via ${value.delivery}`}`
|
|
223
|
+
}];
|
|
224
|
+
}
|
|
225
|
+
const text = (() => {
|
|
226
|
+
if (value.reason === "no-sender-known") {
|
|
227
|
+
return `not delivered: no sender recorded for "${_args.sessionId}" \u2014 this session never received an interconnect message with a sender identity`;
|
|
228
|
+
}
|
|
229
|
+
if (value.reason === "session-owned-by-subagent") {
|
|
230
|
+
return `not delivered: "${_args.sessionId}" is a subagent's session \u2014 its parent agent owns delivery`;
|
|
231
|
+
}
|
|
232
|
+
if (value.reason === "unreachable") {
|
|
233
|
+
return `not delivered: the recorded sender did not answer (unreachable or unauthorized)`;
|
|
234
|
+
}
|
|
235
|
+
if (value.reason === "resume-refused") {
|
|
236
|
+
return `not delivered: the recorded sender does not allow waking persisted sessions`;
|
|
237
|
+
}
|
|
238
|
+
if (value.reason === "resume-failed") {
|
|
239
|
+
return `not delivered: could not wake the recorded sender's session`;
|
|
240
|
+
}
|
|
241
|
+
return `not delivered: the recorded sender's session is not live`;
|
|
242
|
+
})();
|
|
243
|
+
return [{ type: "text", text }];
|
|
244
|
+
}
|
|
245
|
+
},
|
|
246
|
+
async execute(args) {
|
|
247
|
+
const result = await interconnect.reply({
|
|
248
|
+
sessionId: args.sessionId,
|
|
249
|
+
text: args.text,
|
|
250
|
+
...args.delivery === void 0 ? {} : { delivery: args.delivery },
|
|
251
|
+
...args.resume === void 0 ? {} : { resume: args.resume }
|
|
252
|
+
});
|
|
253
|
+
return {
|
|
254
|
+
delivered: result.delivered,
|
|
255
|
+
instance: result.instance,
|
|
256
|
+
...result.delivery === void 0 ? {} : { delivery: result.delivery },
|
|
257
|
+
...result.reason === void 0 ? {} : { reason: result.reason }
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
}));
|
|
177
261
|
}
|
|
178
262
|
export {
|
|
179
263
|
apply,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/tool-interconnect/index.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Model-facing tools for cross-instance message handoff: `interconnect_send`\n * delivers one text message to a live session on a peer DSH instance, and\n * `interconnect_ping` probes a peer's liveness and identity.\n *\n * The tools consume the host-plane `interconnect` service and publish nothing\n * themselves, so this row sits as an ordinary tool plugin in a preset while\n * the service it reaches stays host-side (the same split `tool-goal` uses\n * against `goals`).\n * @module @deepseek-ai/dsh-tool-interconnect\n */\n\nimport { Context } from '@deepseek-ai/cordis'\nimport { defineTool } from '@deepseek-ai/dsh-tools'\n// Activates the `Context.interconnect` merge declared by the interconnect service plugin.\nimport type {} from '../interconnect/index.ts'\n\n/** Services required before the tools can register. */\nexport const inject = ['interconnect', 'tools']\n\n/**\n * Register the two tool surfaces. Registration is idempotent per fiber; the\n * tools unregister with the owning fiber.\n * @param ctx - connection context carrying the interconnect service and the tool registry.\n */\nexport function apply(ctx: Context): void {\n const interconnect = ctx.interconnect\n\n ctx.tools.register(defineTool({\n name: 'interconnect_send',\n description: 'Deliver one text message to a live session on another DSH instance (same machine, '\n + 'another machine, or another session), over a shared-secret-authenticated channel. '\n + 'Returns whether the peer instance received it and which instance answered. '\n + 'Only a session with a running agent can receive a message; when none is running the result '\n + 'reports reason \"session-not-live\", and interconnect_list shows which sessions are live there.',\n parameters: {\n baseUrl: {\n type: 'string',\n required: true,\n description: 'Receiver instance origin, e.g. http://127.0.0.1:3080 or http://peer-host:9001.',\n },\n sessionId: {\n type: 'string',\n required: true,\n description: 'Target session id on the receiving instance to deliver the message to.',\n },\n text: {\n type: 'string',\n required: true,\n description: 'Message text delivered to the peer session.',\n },\n delivery: {\n type: 'string',\n enum: ['followup', 'steer', 'inject'],\n description: 'How the message reaches the target agent. `followup` queues it as its own turn '\n + 'behind whatever that agent is doing now. `steer` cuts into the nearest step boundary of a '\n + 'running turn, so an urgent message does not wait for that turn to end. `inject` seeds '\n + 'context without waking an idle agent, so it may sit unread. Omit to use the receiver\\'s '\n + 'configured default.',\n },\n resume: {\n type: 'boolean',\n description: 'Wake the target session if it is persisted but has no running agent. Off by '\n + 'default because delivery to a woken session starts a real agent turn \u2014 a billed model call '\n + 'with that session\\'s full toolset \u2014 in a conversation nobody is watching. Prefer '\n + 'interconnect_list and an already-live target; set this only when that specific session must '\n + 'be reached. The receiver may refuse, answering reason \"resume-refused\".',\n },\n },\n output: {\n schema: {\n type: 'object',\n additionalProperties: false,\n properties: {\n delivered: { type: 'boolean', required: true },\n instance: { type: 'string', required: true },\n delivery: { type: 'string' },\n reason: { type: 'string' },\n },\n },\n render: (_args, value) => {\n if (value.delivered) {\n return [{\n type: 'text',\n text: `delivered to ${value.instance}${value.delivery === undefined ? '' : ` via ${value.delivery}`}`,\n }]\n }\n // Each failure gets the response it actually needs: a not-live target is\n // the caller's to re-choose, while an unreachable peer may just be worth\n // retrying. The old single line claimed \"no live session\" even when the\n // peer never answered, which pointed at the wrong thing entirely.\n const text = ((): string => {\n switch (value.reason) {\n case 'unreachable':\n return `not delivered: ${value.instance} did not answer (unreachable or unauthorized)`\n case 'resume-refused':\n return `not delivered: ${value.instance} does not allow waking persisted sessions`\n case 'resume-failed':\n return `not delivered: could not wake \"${_args.sessionId}\" on ${value.instance}`\n + ' (no such persisted session, or another owner holds it)'\n case 'session-owned-by-subagent':\n return `not delivered: \"${_args.sessionId}\" is a subagent's session on ${value.instance}`\n + ' \u2014 its parent agent owns delivery, so reach it through that parent'\n default:\n return `not delivered: no live session \"${_args.sessionId}\" on ${value.instance}`\n + ' \u2014 use interconnect_list to see which sessions are live there,'\n + ' or set resume to wake this one'\n }\n })()\n return [{ type: 'text', text }]\n },\n },\n async execute(args) {\n const result = await interconnect.send({\n baseUrl: args.baseUrl,\n sessionId: args.sessionId,\n text: args.text,\n ...(args.delivery === undefined ? {} : { delivery: args.delivery }),\n ...(args.resume === undefined ? {} : { resume: args.resume }),\n })\n return {\n delivered: result.delivered,\n instance: result.instance,\n ...(result.delivery === undefined ? {} : { delivery: result.delivery }),\n ...(result.reason === undefined ? {} : { reason: result.reason }),\n }\n },\n }))\n\n ctx.tools.register(defineTool({\n name: 'interconnect_ping',\n description: 'Probe a peer DSH instance for liveness and identity over the shared-secret channel. '\n + 'Returns the peer instance id when reachable, or null on transport/auth failure.',\n parameters: {\n baseUrl: {\n type: 'string',\n required: true,\n description: 'Peer instance origin, e.g. http://127.0.0.1:3080.',\n },\n },\n output: {\n schema: {\n type: 'object',\n additionalProperties: false,\n properties: {\n reachable: { type: 'boolean', required: true },\n instance: { type: 'string' },\n },\n },\n render: (_args, value) => [{\n type: 'text',\n text: value.reachable\n ? `reachable: ${value.instance ?? '(unknown instance)'}`\n : 'unreachable or unauthorized',\n }],\n },\n async execute(args) {\n const result = await interconnect.ping(args.baseUrl)\n if (result === undefined) return { reachable: false }\n return { reachable: true, instance: result.instance }\n },\n }))\n\n ctx.tools.register(defineTool({\n name: 'interconnect_list',\n description: 'List the live sessions on a peer DSH instance, so a message can be addressed without '\n + 'knowing a session id in advance. Every returned sessionId is a valid interconnect_send target at '\n + 'the time of the call. Only live sessions appear: a session that exists on the peer but has no '\n + 'running agent is not listed and cannot receive a message.',\n parameters: {\n baseUrl: {\n type: 'string',\n required: true,\n description: 'Peer instance origin, e.g. http://127.0.0.1:3080.',\n },\n },\n output: {\n schema: {\n type: 'object',\n additionalProperties: false,\n properties: {\n reachable: { type: 'boolean', required: true },\n instance: { type: 'string' },\n sessions: {\n type: 'array',\n items: {\n type: 'object',\n additionalProperties: false,\n properties: {\n sessionId: { type: 'string', required: true },\n title: { type: 'string' },\n status: { type: 'string' },\n },\n },\n },\n },\n },\n render: (_args, value) => {\n if (!value.reachable) return [{ type: 'text', text: 'unreachable or unauthorized' }]\n const sessions = value.sessions ?? []\n if (sessions.length === 0) {\n return [{ type: 'text', text: `no live sessions on ${value.instance ?? '(unknown instance)'}` }]\n }\n const lines = sessions.map((session) => {\n const title = session.title === undefined ? '' : ` ${session.title}`\n const status = session.status === undefined ? '' : ` [${session.status}]`\n return `${session.sessionId}${title}${status}`\n })\n return [{ type: 'text', text: lines.join('\\n') }]\n },\n },\n async execute(args) {\n const result = await interconnect.list(args.baseUrl)\n if (result === undefined) return { reachable: false }\n return {\n reachable: true,\n instance: result.instance,\n // Rebuild each row so an optional key stays absent rather than\n // becoming an explicit undefined the wire schema would reject.\n sessions: result.sessions.map(session => ({\n sessionId: session.sessionId,\n ...(session.title === undefined ? {} : { title: session.title }),\n ...(session.status === undefined ? {} : { status: session.status }),\n })),\n }\n },\n }))\n}\n"],
|
|
5
|
-
"mappings": ";AAaA,SAAS,kBAAkB;AAKpB,IAAM,SAAS,CAAC,gBAAgB,OAAO;AAOvC,SAAS,MAAM,KAAoB;AACxC,QAAM,eAAe,IAAI;AAEzB,MAAI,MAAM,SAAS,WAAW;AAAA,IAC5B,MAAM;AAAA,IACN,aAAa;AAAA,IAKb,YAAY;AAAA,MACV,SAAS;AAAA,QACP,MAAM;AAAA,QACN,UAAU;AAAA,QACV,aAAa;AAAA,MACf;AAAA,MACA,WAAW;AAAA,QACT,MAAM;AAAA,QACN,UAAU;AAAA,QACV,aAAa;AAAA,MACf;AAAA,MACA,MAAM;AAAA,QACJ,MAAM;AAAA,QACN,UAAU;AAAA,QACV,aAAa;AAAA,MACf;AAAA,MACA,UAAU;AAAA,QACR,MAAM;AAAA,QACN,MAAM,CAAC,YAAY,SAAS,QAAQ;AAAA,QACpC,aAAa;AAAA,MAKf;AAAA,MACA,QAAQ;AAAA,QACN,MAAM;AAAA,QACN,aAAa;AAAA,MAKf;AAAA,IACF;AAAA,IACA,QAAQ;AAAA,MACN,QAAQ;AAAA,QACN,MAAM;AAAA,QACN,sBAAsB;AAAA,QACtB,YAAY;AAAA,UACV,WAAW,EAAE,MAAM,WAAW,UAAU,KAAK;AAAA,UAC7C,UAAU,EAAE,MAAM,UAAU,UAAU,KAAK;AAAA,UAC3C,UAAU,EAAE,MAAM,SAAS;AAAA,UAC3B,QAAQ,EAAE,MAAM,SAAS;AAAA,QAC3B;AAAA,MACF;AAAA,MACA,QAAQ,CAAC,OAAO,UAAU;AACxB,YAAI,MAAM,WAAW;AACnB,iBAAO,CAAC;AAAA,YACN,MAAM;AAAA,YACN,MAAM,gBAAgB,MAAM,QAAQ,GAAG,MAAM,aAAa,SAAY,KAAK,QAAQ,MAAM,QAAQ,EAAE;AAAA,UACrG,CAAC;AAAA,QACH;AAKA,cAAM,QAAQ,MAAc;AAC1B,kBAAQ,MAAM,QAAQ;AAAA,YACpB,KAAK;AACH,qBAAO,kBAAkB,MAAM,QAAQ;AAAA,YACzC,KAAK;AACH,qBAAO,kBAAkB,MAAM,QAAQ;AAAA,YACzC,KAAK;AACH,qBAAO,kCAAkC,MAAM,SAAS,QAAQ,MAAM,QAAQ;AAAA,YAEhF,KAAK;AACH,qBAAO,mBAAmB,MAAM,SAAS,gCAAgC,MAAM,QAAQ;AAAA,YAEzF;AACE,qBAAO,mCAAmC,MAAM,SAAS,QAAQ,MAAM,QAAQ;AAAA,UAGnF;AAAA,QACF,GAAG;AACH,eAAO,CAAC,EAAE,MAAM,QAAQ,KAAK,CAAC;AAAA,MAChC;AAAA,IACF;AAAA,IACA,MAAM,QAAQ,MAAM;
|
|
4
|
+
"sourcesContent": ["/**\n * Model-facing tools for cross-instance message handoff: `interconnect_send`\n * delivers one text message to a live session on a peer DSH instance, and\n * `interconnect_ping` probes a peer's liveness and identity.\n *\n * The tools consume the host-plane `interconnect` service and publish nothing\n * themselves, so this row sits as an ordinary tool plugin in a preset while\n * the service it reaches stays host-side (the same split `tool-goal` uses\n * against `goals`).\n * @module @deepseek-ai/dsh-tool-interconnect\n */\n\nimport { Context } from '@deepseek-ai/cordis'\nimport { defineTool } from '@deepseek-ai/dsh-tools'\n// Activates the `Context.interconnect` merge declared by the interconnect service plugin.\nimport type {} from '../interconnect/index.ts'\n\n/** Services required before the tools can register. */\nexport const inject = ['interconnect', 'tools']\n\n/**\n * Register the two tool surfaces. Registration is idempotent per fiber; the\n * tools unregister with the owning fiber.\n * @param ctx - connection context carrying the interconnect service and the tool registry.\n */\nexport function apply(ctx: Context): void {\n const interconnect = ctx.interconnect\n\n ctx.tools.register(defineTool({\n name: 'interconnect_send',\n description: 'Deliver one text message to a live session on another DSH instance (same machine, '\n + 'another machine, or another session), over a shared-secret-authenticated channel. '\n + 'Returns whether the peer instance received it and which instance answered. '\n + 'Only a session with a running agent can receive a message; when none is running the result '\n + 'reports reason \"session-not-live\", and interconnect_list shows which sessions are live there.',\n parameters: {\n baseUrl: {\n type: 'string',\n required: true,\n description: 'Receiver instance origin, e.g. http://127.0.0.1:3080 or http://peer-host:9001.',\n },\n sessionId: {\n type: 'string',\n required: true,\n description: 'Target session id on the receiving instance to deliver the message to.',\n },\n text: {\n type: 'string',\n required: true,\n description: 'Message text delivered to the peer session.',\n },\n delivery: {\n type: 'string',\n enum: ['followup', 'steer', 'inject'],\n description: 'How the message reaches the target agent. `followup` queues it as its own turn '\n + 'behind whatever that agent is doing now. `steer` cuts into the nearest step boundary of a '\n + 'running turn, so an urgent message does not wait for that turn to end. `inject` seeds '\n + 'context without waking an idle agent, so it may sit unread. Omit to use the receiver\\'s '\n + 'configured default.',\n },\n resume: {\n type: 'boolean',\n description: 'Wake the target session if it is persisted but has no running agent. Off by '\n + 'default because delivery to a woken session starts a real agent turn \u2014 a billed model call '\n + 'with that session\\'s full toolset \u2014 in a conversation nobody is watching. Prefer '\n + 'interconnect_list and an already-live target; set this only when that specific session must '\n + 'be reached. The receiver may refuse, answering reason \"resume-refused\".',\n },\n },\n output: {\n schema: {\n type: 'object',\n additionalProperties: false,\n properties: {\n delivered: { type: 'boolean', required: true },\n instance: { type: 'string', required: true },\n delivery: { type: 'string' },\n reason: { type: 'string' },\n },\n },\n render: (_args, value) => {\n if (value.delivered) {\n return [{\n type: 'text',\n text: `delivered to ${value.instance}${value.delivery === undefined ? '' : ` via ${value.delivery}`}`,\n }]\n }\n // Each failure gets the response it actually needs: a not-live target is\n // the caller's to re-choose, while an unreachable peer may just be worth\n // retrying. The old single line claimed \"no live session\" even when the\n // peer never answered, which pointed at the wrong thing entirely.\n const text = ((): string => {\n switch (value.reason) {\n case 'unreachable':\n return `not delivered: ${value.instance} did not answer (unreachable or unauthorized)`\n case 'resume-refused':\n return `not delivered: ${value.instance} does not allow waking persisted sessions`\n case 'resume-failed':\n return `not delivered: could not wake \"${_args.sessionId}\" on ${value.instance}`\n + ' (no such persisted session, or another owner holds it)'\n case 'session-owned-by-subagent':\n return `not delivered: \"${_args.sessionId}\" is a subagent's session on ${value.instance}`\n + ' \u2014 its parent agent owns delivery, so reach it through that parent'\n default:\n return `not delivered: no live session \"${_args.sessionId}\" on ${value.instance}`\n + ' \u2014 use interconnect_list to see which sessions are live there,'\n + ' or set resume to wake this one'\n }\n })()\n return [{ type: 'text', text }]\n },\n },\n async execute(args, exec) {\n const sessionId = exec.agent?.session.id\n const self = sessionId === undefined ? undefined : interconnect.selfSender(String(sessionId))\n const result = await interconnect.send({\n baseUrl: args.baseUrl,\n sessionId: args.sessionId,\n text: args.text,\n // Attribute this instance as the sender when configured, so the peer\n // can reply back. The calling session id comes from the executing\n // agent (the session that is sending).\n ...(self === undefined ? {} : { sender: self }),\n ...(args.delivery === undefined ? {} : { delivery: args.delivery }),\n ...(args.resume === undefined ? {} : { resume: args.resume }),\n })\n return {\n delivered: result.delivered,\n instance: result.instance,\n ...(result.delivery === undefined ? {} : { delivery: result.delivery }),\n ...(result.reason === undefined ? {} : { reason: result.reason }),\n }\n },\n }))\n\n ctx.tools.register(defineTool({\n name: 'interconnect_ping',\n description: 'Probe a peer DSH instance for liveness and identity over the shared-secret channel. '\n + 'Returns the peer instance id when reachable, or null on transport/auth failure.',\n parameters: {\n baseUrl: {\n type: 'string',\n required: true,\n description: 'Peer instance origin, e.g. http://127.0.0.1:3080.',\n },\n },\n output: {\n schema: {\n type: 'object',\n additionalProperties: false,\n properties: {\n reachable: { type: 'boolean', required: true },\n instance: { type: 'string' },\n },\n },\n render: (_args, value) => [{\n type: 'text',\n text: value.reachable\n ? `reachable: ${value.instance ?? '(unknown instance)'}`\n : 'unreachable or unauthorized',\n }],\n },\n async execute(args) {\n const result = await interconnect.ping(args.baseUrl)\n if (result === undefined) return { reachable: false }\n return { reachable: true, instance: result.instance }\n },\n }))\n\n ctx.tools.register(defineTool({\n name: 'interconnect_list',\n description: 'List the live sessions on a peer DSH instance, so a message can be addressed without '\n + 'knowing a session id in advance. Every returned sessionId is a valid interconnect_send target at '\n + 'the time of the call. Only live sessions appear: a session that exists on the peer but has no '\n + 'running agent is not listed and cannot receive a message.',\n parameters: {\n baseUrl: {\n type: 'string',\n required: true,\n description: 'Peer instance origin, e.g. http://127.0.0.1:3080.',\n },\n },\n output: {\n schema: {\n type: 'object',\n additionalProperties: false,\n properties: {\n reachable: { type: 'boolean', required: true },\n instance: { type: 'string' },\n sessions: {\n type: 'array',\n items: {\n type: 'object',\n additionalProperties: false,\n properties: {\n sessionId: { type: 'string', required: true },\n title: { type: 'string' },\n status: { type: 'string' },\n },\n },\n },\n },\n },\n render: (_args, value) => {\n if (!value.reachable) return [{ type: 'text', text: 'unreachable or unauthorized' }]\n const sessions = value.sessions ?? []\n if (sessions.length === 0) {\n return [{ type: 'text', text: `no live sessions on ${value.instance ?? '(unknown instance)'}` }]\n }\n const lines = sessions.map((session) => {\n const title = session.title === undefined ? '' : ` ${session.title}`\n const status = session.status === undefined ? '' : ` [${session.status}]`\n return `${session.sessionId}${title}${status}`\n })\n return [{ type: 'text', text: lines.join('\\n') }]\n },\n },\n async execute(args) {\n const result = await interconnect.list(args.baseUrl)\n if (result === undefined) return { reachable: false }\n return {\n reachable: true,\n instance: result.instance,\n // Rebuild each row so an optional key stays absent rather than\n // becoming an explicit undefined the wire schema would reject.\n sessions: result.sessions.map(session => ({\n sessionId: session.sessionId,\n ...(session.title === undefined ? {} : { title: session.title }),\n ...(session.status === undefined ? {} : { status: session.status }),\n })),\n }\n },\n }))\n\n ctx.tools.register(defineTool({\n name: 'interconnect_reply',\n description: 'Deliver one text message back to the peer that this session last received an '\n + 'interconnect message from. Only the LOCAL session id and the reply text are needed: the '\n + 'outbound target (the peer origin and its session id) is recalled from the message this '\n + 'session received, so you do not ask for an address twice. A session that never received a '\n + 'message through interconnect \u2014 or received one without a sender identity \u2014 reports reason '\n + '\"no-sender-known\".',\n parameters: {\n sessionId: {\n type: 'string',\n required: true,\n description: 'The LOCAL session id that received the message being replied to.',\n },\n text: {\n type: 'string',\n required: true,\n description: 'Message text delivered back to the recorded sender session.',\n },\n delivery: {\n type: 'string',\n enum: ['followup', 'steer', 'inject'],\n description: 'How the reply reaches the target agent, as in interconnect_send. Omit to use '\n + \"the receiver's configured default.\",\n },\n resume: {\n type: 'boolean',\n description: 'Wake the target session if it is persisted but has no running agent, as in '\n + 'interconnect_send. Off by default; the receiver may refuse.',\n },\n },\n output: {\n schema: {\n type: 'object',\n additionalProperties: false,\n properties: {\n delivered: { type: 'boolean', required: true },\n instance: { type: 'string', required: true },\n delivery: { type: 'string' },\n reason: { type: 'string' },\n },\n },\n render: (_args, value) => {\n if (value.delivered) {\n return [{\n type: 'text',\n text: `replied to ${value.instance}${value.delivery === undefined ? '' : ` via ${value.delivery}`}`,\n }]\n }\n const text = ((): string => {\n if (value.reason === 'no-sender-known') {\n return `not delivered: no sender recorded for \"${_args.sessionId}\"`\n + ' \u2014 this session never received an interconnect message with a sender identity'\n }\n if (value.reason === 'session-owned-by-subagent') {\n return `not delivered: \"${_args.sessionId}\" is a subagent's session \u2014 its parent agent owns delivery`\n }\n if (value.reason === 'unreachable') {\n return `not delivered: the recorded sender did not answer (unreachable or unauthorized)`\n }\n if (value.reason === 'resume-refused') {\n return `not delivered: the recorded sender does not allow waking persisted sessions`\n }\n if (value.reason === 'resume-failed') {\n return `not delivered: could not wake the recorded sender's session`\n }\n return `not delivered: the recorded sender's session is not live`\n })()\n return [{ type: 'text', text }]\n },\n },\n async execute(args) {\n const result = await interconnect.reply({\n sessionId: args.sessionId,\n text: args.text,\n ...(args.delivery === undefined ? {} : { delivery: args.delivery }),\n ...(args.resume === undefined ? {} : { resume: args.resume }),\n })\n return {\n delivered: result.delivered,\n instance: result.instance,\n ...(result.delivery === undefined ? {} : { delivery: result.delivery }),\n ...(result.reason === undefined ? {} : { reason: result.reason }),\n }\n },\n }))\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
import { Context, Service } from '@deepseek-ai/cordis';
|
|
15
15
|
import z from '@deepseek-ai/schemastery';
|
|
16
16
|
import WebSocket from 'ws';
|
|
17
|
-
import { type Config, type EventNotification, type ListResult, type PingResult, type SendResult, type SendRequest, type WebSocketLinkHandle } from './types.ts';
|
|
17
|
+
import { type Config, type EventNotification, type ListResult, type PingResult, type ReplyRequest, type SendResult, type SendRequest, type SenderIdentity, type WebSocketLinkHandle } from './types.ts';
|
|
18
18
|
export type * from './types.ts';
|
|
19
19
|
export { INTERCONNECT_CHANNEL, INTERCONNECT_TOKEN_REF } from './types.ts';
|
|
20
20
|
declare module '@deepseek-ai/cordis' {
|
|
@@ -39,6 +39,7 @@ export declare class InterconnectService extends Service {
|
|
|
39
39
|
static inject: string[];
|
|
40
40
|
static Config: z<Config>;
|
|
41
41
|
private readonly instanceId;
|
|
42
|
+
private readonly selfBaseUrl;
|
|
42
43
|
private readonly requestTimeoutMs;
|
|
43
44
|
private readonly delivery;
|
|
44
45
|
private readonly allowResume;
|
|
@@ -50,8 +51,24 @@ export declare class InterconnectService extends Service {
|
|
|
50
51
|
private heartbeatTimer;
|
|
51
52
|
/** Peer identity each live socket announced via its `hello` frame, if any. */
|
|
52
53
|
private readonly peerOf;
|
|
54
|
+
/** Sender each local session last received a send from, keyed by local session id. */
|
|
55
|
+
private readonly senders;
|
|
53
56
|
constructor(ctx: Context, config: Config);
|
|
57
|
+
/**
|
|
58
|
+
* This instance's identity to attach to outbound messages, when configured.
|
|
59
|
+
* Absent (`selfBaseUrl` unset) outbound sends are not attributable and the
|
|
60
|
+
* peer cannot reply to them.
|
|
61
|
+
* @param sessionId - the local session that is sending, used as the reply target.
|
|
62
|
+
*/
|
|
63
|
+
selfSender(sessionId: string): SenderIdentity | undefined;
|
|
54
64
|
send(request: SendRequest): Promise<SendResult>;
|
|
65
|
+
/**
|
|
66
|
+
* Deliver one text message back to the peer that a local session last
|
|
67
|
+
* received a send from. `sessionId` names the LOCAL replying session; the
|
|
68
|
+
* outbound target is the `sender` that session recorded, resolved to a
|
|
69
|
+
* `send` against the recalled baseUrl and remote session id.
|
|
70
|
+
*/
|
|
71
|
+
reply(request: ReplyRequest): Promise<SendResult>;
|
|
55
72
|
ping(baseUrl: string): Promise<PingResult | undefined>;
|
|
56
73
|
/**
|
|
57
74
|
* List the peer's live sessions so a caller can discover a valid `send`
|
|
@@ -120,7 +137,12 @@ export declare class InterconnectService extends Service {
|
|
|
120
137
|
* when the sender asked and this receiver allows it.
|
|
121
138
|
*/
|
|
122
139
|
private deliver;
|
|
123
|
-
/**
|
|
140
|
+
/**
|
|
141
|
+
* Inbound `reply` dispatch: forward a request to {link reply}, resolving the
|
|
142
|
+
* outbound sender for the named local session. Kept separate from {link
|
|
143
|
+
* deliver} so the two wire endpoints stay distinct in the request pipeline.
|
|
144
|
+
*/
|
|
145
|
+
private replyForSession;
|
|
124
146
|
private post;
|
|
125
147
|
private resolveToken;
|
|
126
148
|
/** Resolve the shared token for an outbound dial (same source as inbound). */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/interconnect/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAkBtD,OAAO,CAAC,MAAM,0BAA0B,CAAA;AACxC,OAAO,SAA8B,MAAM,IAAI,CAAA;AAE/C,OAAO,EAGL,KAAK,MAAM,EAEX,KAAK,iBAAiB,EAGtB,KAAK,UAAU,EACf,KAAK,UAAU,EAEf,KAAK,UAAU,EACf,KAAK,WAAW,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/interconnect/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -29,6 +29,25 @@ export declare const INTERCONNECT_TOKEN_REF = "DSH_INTERCONNECT_TOKEN";
|
|
|
29
29
|
* an idle agent, so it can sit unread until something else wakes it.
|
|
30
30
|
*/
|
|
31
31
|
export type DeliveryMode = 'followup' | 'steer' | 'inject';
|
|
32
|
+
/**
|
|
33
|
+
* Self-reported identity of the peer that sent a message, carried for reply
|
|
34
|
+
* attribution and echoed `sessionId` of the sending instance. All three fields
|
|
35
|
+
* are sender-supplied and self-reported — the receiver stores them only to
|
|
36
|
+
* address a `reply`, never as an auth or routing authority (the shared secret
|
|
37
|
+
* still authenticates the connection itself).
|
|
38
|
+
*/
|
|
39
|
+
export interface SenderIdentity {
|
|
40
|
+
/**
|
|
41
|
+
* Origin the receiver can reach the sender's instance at when replying, e.g.
|
|
42
|
+
* `http://peer-host:9001`. This must be addressable FROM the receiver; a
|
|
43
|
+
* loopback address only makes sense when both sides share the same machine.
|
|
44
|
+
*/
|
|
45
|
+
readonly baseUrl: string;
|
|
46
|
+
/** The sender's self-reported instance id (diagnostic, as in `ping`). */
|
|
47
|
+
readonly instanceId: string;
|
|
48
|
+
/** Session id on the sender's instance to which a `reply` is addressed. */
|
|
49
|
+
readonly sessionId: string;
|
|
50
|
+
}
|
|
32
51
|
/**
|
|
33
52
|
* Business payload for the `send` endpoint: deliver one text message to one
|
|
34
53
|
* live session of the receiving instance.
|
|
@@ -38,6 +57,12 @@ export interface SendPayload {
|
|
|
38
57
|
readonly sessionId: string;
|
|
39
58
|
/** Message text delivered to the peer session's inbox. */
|
|
40
59
|
readonly text: string;
|
|
60
|
+
/**
|
|
61
|
+
* The sender's identity, so the receiver can attribute the message and
|
|
62
|
+
* address a reply back. Optional for backward compatibility: a peer running
|
|
63
|
+
* an older version omits it, and the receiver simply has nothing to reply to.
|
|
64
|
+
*/
|
|
65
|
+
readonly sender?: SenderIdentity;
|
|
41
66
|
/**
|
|
42
67
|
* Per-message override of the receiver's configured delivery mode. Urgency is
|
|
43
68
|
* a property of one message, not of the link, so a sender may ask to cut into
|
|
@@ -72,8 +97,12 @@ export interface SendPayload {
|
|
|
72
97
|
* - `session-owned-by-subagent` — the session is reserved to subagent routing,
|
|
73
98
|
* so its parent agent owns delivery. Injecting here would race that parent;
|
|
74
99
|
* the sender must reach the child through its parent instead.
|
|
100
|
+
* - `no-sender-known` — a `reply` was addressed to a local session that never
|
|
101
|
+
* recorded a sender, either because that session did not receive a message
|
|
102
|
+
* through this service or the incoming message carried no `sender` identity
|
|
103
|
+
* (an older peer omitted it).
|
|
75
104
|
*/
|
|
76
|
-
export type SendFailure = 'session-not-live' | 'unreachable' | 'resume-refused' | 'resume-failed' | 'session-owned-by-subagent';
|
|
105
|
+
export type SendFailure = 'session-not-live' | 'unreachable' | 'resume-refused' | 'resume-failed' | 'session-owned-by-subagent' | 'no-sender-known';
|
|
77
106
|
/** Business result of a `send` endpoint call. */
|
|
78
107
|
export interface SendResult {
|
|
79
108
|
/** True when the target session is live on the receiving instance and the message was delivered. */
|
|
@@ -134,11 +163,44 @@ export interface SendRequest {
|
|
|
134
163
|
readonly baseUrl: string;
|
|
135
164
|
readonly sessionId: string;
|
|
136
165
|
readonly text: string;
|
|
166
|
+
/**
|
|
167
|
+
* This sender's identity, forwarded so the receiver can attribute the
|
|
168
|
+
* message and address a reply back. Absent when the caller does not know its
|
|
169
|
+
* own addressable origin (see {@link Config.selfBaseUrl}).
|
|
170
|
+
*/
|
|
171
|
+
readonly sender?: SenderIdentity;
|
|
137
172
|
/** Per-message delivery override forwarded to the receiver. */
|
|
138
173
|
readonly delivery?: DeliveryMode;
|
|
139
174
|
/** Ask the receiver to wake a persisted session; see {@link SendPayload.resume}. */
|
|
140
175
|
readonly resume?: boolean;
|
|
141
176
|
}
|
|
177
|
+
/**
|
|
178
|
+
* Business payload for the `reply` endpoint: deliver one text message back to
|
|
179
|
+
* the peer that a given local session most recently received a message from.
|
|
180
|
+
* `sessionId` names the LOCAL session; the outbound target is the sender this
|
|
181
|
+
* session recorded, so the caller does not need to know the peer's origin or
|
|
182
|
+
* session id again.
|
|
183
|
+
*/
|
|
184
|
+
export interface ReplyPayload {
|
|
185
|
+
/** Local session id that received the message being replied to. */
|
|
186
|
+
readonly sessionId: string;
|
|
187
|
+
/** Message text delivered back to the recorded sender's session. */
|
|
188
|
+
readonly text: string;
|
|
189
|
+
/** Per-message delivery override forwarded to the recalled sender. */
|
|
190
|
+
readonly delivery?: DeliveryMode;
|
|
191
|
+
/** Ask the recalled sender's receiver to wake a persisted session. */
|
|
192
|
+
readonly resume?: boolean;
|
|
193
|
+
}
|
|
194
|
+
/** Outbound reply request: which local session is replying, plus the text. */
|
|
195
|
+
export interface ReplyRequest {
|
|
196
|
+
/** Local session id that received the message being replied to. */
|
|
197
|
+
readonly sessionId: string;
|
|
198
|
+
readonly text: string;
|
|
199
|
+
/** Per-message delivery override forwarded to the recalled sender. */
|
|
200
|
+
readonly delivery?: DeliveryMode;
|
|
201
|
+
/** Ask the recalled sender's receiver to wake a persisted session. */
|
|
202
|
+
readonly resume?: boolean;
|
|
203
|
+
}
|
|
142
204
|
/**
|
|
143
205
|
* One serializable lifecycle fact pushed from an emitting instance to its
|
|
144
206
|
* peers. `kind` discriminates the union; the remaining fields are the compact
|
|
@@ -204,6 +266,14 @@ export interface WebSocketLinkHandle {
|
|
|
204
266
|
export interface Config {
|
|
205
267
|
/** Self-reported id of this instance, echoed in ping/send results for diagnostics. */
|
|
206
268
|
readonly instanceId: string;
|
|
269
|
+
/**
|
|
270
|
+
* Origin this instance is reachable at from peers, e.g. `http://my-box:3080`.
|
|
271
|
+
* When set, outbound `send` calls attach this instance's identity as the
|
|
272
|
+
* `sender` so the peer can reply back (chainable). Absent, outbound messages
|
|
273
|
+
* are not attributable and a peer `reply` reports `no-sender-known`. Must be
|
|
274
|
+
* addressable FROM peers — a loopback address only fits a same-machine link.
|
|
275
|
+
*/
|
|
276
|
+
readonly selfBaseUrl?: string;
|
|
207
277
|
/** Request timeout for outbound deliveries, in milliseconds. */
|
|
208
278
|
readonly requestTimeoutMs: number;
|
|
209
279
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/interconnect/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;GAGG;AACH,eAAO,MAAM,oBAAoB,kBAAkB,CAAA;AAEnD;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,2BAA2B,CAAA;AAE9D;;;;;;;;;;GAUG;AACH,MAAM,MAAM,YAAY,GAAG,UAAU,GAAG,OAAO,GAAG,QAAQ,CAAA;AAE1D;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,mDAAmD;IACnD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,0DAA0D;IAC1D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,YAAY,CAAA;IAChC;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAC1B;AAED
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/interconnect/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tool-interconnect/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAK7C,uDAAuD;AACvD,eAAO,MAAM,MAAM,UAA4B,CAAA;AAE/C;;;;GAIG;AACH,wBAAgB,KAAK,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tool-interconnect/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAK7C,uDAAuD;AACvD,eAAO,MAAM,MAAM,UAA4B,CAAA;AAE/C;;;;GAIG;AACH,wBAAgB,KAAK,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAuSxC"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-interconnect",
|
|
3
3
|
"description": "Cross-instance message/event handoff plugins for DeepSeek Harness (DSH): interconnect service + model-facing tools",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.7.0",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "lib/index.js",
|