@deepseek-ai/dsh-api-remotes 0.1.1-rc.2 → 0.1.2-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/README.i18n.yaml +2 -2
- package/README.md +53 -10
- package/README.zh.md +53 -11
- package/lib/client.js +3723 -755
- package/lib/index.js +180 -150
- package/lib/types/client/index.d.ts +22 -6
- package/lib/types/client/index.js +8 -2
- package/lib/types/index.d.ts +6 -4
- package/lib/types/index.js +119 -12
- package/lib/types/remote-events.d.ts +57 -7
- package/lib/types/remote-events.js +20 -17
- package/lib/types/types.d.ts +1 -1
- package/package.json +30 -39
- package/lib/types/agent-lookup.d.ts +0 -95
- package/lib/types/agent-lookup.js +0 -166
package/lib/index.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { homedir } from "node:os";
|
|
2
|
+
import { Deque } from "@deepseek-ai/dsh-deque";
|
|
3
|
+
import { carrierKeyOf } from "@deepseek-ai/dsh-scope";
|
|
4
|
+
import { isJsonValue } from "@deepseek-ai/dsh-util-values";
|
|
2
5
|
//#region lib/types/remote-events.js
|
|
3
6
|
/**
|
|
4
7
|
* The one home of this application's forwarded-Host-event allowlist. Both
|
|
@@ -8,165 +11,192 @@ import { TypertLookupFailure } from "@deepseek-ai/dsh-typert-protocol";
|
|
|
8
11
|
* type-only.
|
|
9
12
|
*/
|
|
10
13
|
/**
|
|
11
|
-
* Host events this application forwards
|
|
12
|
-
*
|
|
13
|
-
* the payload is its argument list, so this array is simultaneously the whole
|
|
14
|
-
* control point over what a consumer can receive and the legal key set of
|
|
15
|
-
* `ctx.remote.$on`. Forwarding one more event is an entry here and nothing
|
|
16
|
-
* else.
|
|
14
|
+
* Host events this application forwards without renaming. The explicit mode is
|
|
15
|
+
* both the Host dispatch strategy and the legal key set of `ctx.remote.$on`.
|
|
17
16
|
*/
|
|
18
17
|
const API_REMOTE_FORWARDED_EVENTS = [
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
18
|
+
{
|
|
19
|
+
event: "agent-preset/selected",
|
|
20
|
+
mode: "emit"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
event: "approval/request",
|
|
24
|
+
mode: "waterfall"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
event: "api-session/activity",
|
|
28
|
+
mode: "emit"
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
event: "api-session/added",
|
|
32
|
+
mode: "emit"
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
event: "api-session/error",
|
|
36
|
+
mode: "emit"
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
event: "api-session/removed",
|
|
40
|
+
mode: "emit"
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
event: "api-session/status",
|
|
44
|
+
mode: "emit"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
event: "commands/change",
|
|
48
|
+
mode: "emit"
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
event: "credentials/reference-updated",
|
|
52
|
+
mode: "emit"
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
event: "cordis/request-run",
|
|
56
|
+
mode: "emit"
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
event: "cordis/request-run-resolved",
|
|
60
|
+
mode: "emit"
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
event: "cordis/dynamic-package",
|
|
64
|
+
mode: "emit"
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
event: "cordis/dynamic-retract",
|
|
68
|
+
mode: "emit"
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
event: "cordis/inspect-query",
|
|
72
|
+
mode: "emit"
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
event: "cordis/inspect-query-resolved",
|
|
76
|
+
mode: "emit"
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
event: "llm/adapters-updated",
|
|
80
|
+
mode: "emit"
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
event: "settings/document-updated",
|
|
84
|
+
mode: "emit"
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
event: "user-questions/request",
|
|
88
|
+
mode: "waterfall"
|
|
89
|
+
}
|
|
30
90
|
];
|
|
31
91
|
//#endregion
|
|
32
|
-
//#region lib/types/
|
|
33
|
-
/** Host BFF
|
|
34
|
-
/**
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Construct the ownership fence.
|
|
41
|
-
* @param sessionId - identity reserved to subagent routing.
|
|
42
|
-
*/
|
|
43
|
-
constructor(sessionId) {
|
|
44
|
-
super(`session "${sessionId}" is a subagent session; use subagent delivery`);
|
|
45
|
-
this.sessionId = sessionId;
|
|
46
|
-
}
|
|
47
|
-
};
|
|
48
|
-
/**
|
|
49
|
-
* Test whether generic Host routing must leave an identity to subagent routing.
|
|
50
|
-
* @param ctx - Host Context carrying the live Agent registry.
|
|
51
|
-
* @param session - attached or live Session metadata.
|
|
52
|
-
* @param agent - live Agent when one is registered.
|
|
53
|
-
* @returns whether generic Remote and legacy API calls must reject the identity.
|
|
54
|
-
*/
|
|
55
|
-
function hasApiRemoteSubagentOwner(ctx, session, agent) {
|
|
56
|
-
if (session.header.origin === "subagent") return true;
|
|
57
|
-
const parentId = session.header.parentSession;
|
|
58
|
-
if (parentId === void 0 || agent === void 0) return false;
|
|
59
|
-
const parent = ctx.agents.get(parentId);
|
|
60
|
-
return parent !== void 0 && ctx.agents.isOwnedBy(agent.id, parent);
|
|
61
|
-
}
|
|
62
|
-
/**
|
|
63
|
-
* Build the stable caller-facing ownership rejection.
|
|
64
|
-
* @param sessionId - identity reserved to subagent routing.
|
|
65
|
-
* @returns the existing `agent-busy` RPC shape.
|
|
66
|
-
*/
|
|
67
|
-
function apiRemoteSubagentOwnershipError(sessionId) {
|
|
68
|
-
return {
|
|
69
|
-
code: "agent-busy",
|
|
70
|
-
message: `session "${sessionId}" is owned by subagent routing`,
|
|
71
|
-
details: { reason: "use subagent delivery for this child session" }
|
|
72
|
-
};
|
|
92
|
+
//#region lib/types/index.js
|
|
93
|
+
/** Host BFF entry and Loader shell for the Remote contribution assembly. */
|
|
94
|
+
/** Required Host service: the Gateway owns the physical Remote stream mux. */
|
|
95
|
+
const inject = ["typertGateway"];
|
|
96
|
+
/** Host plugin body registering this application's selected Cordis event source. */
|
|
97
|
+
function apply(ctx) {
|
|
98
|
+
ctx.effect(() => ctx.typertGateway.registerRemoteEvents(remoteEventSource(ctx), { home: homedir() }), "api-remotes: forwarded Cordis event source");
|
|
73
99
|
}
|
|
74
|
-
/**
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
100
|
+
/** Create the sole queue and listener set consumed by the registered Gateway. */
|
|
101
|
+
function remoteEventSource(ctx) {
|
|
102
|
+
return (signal) => {
|
|
103
|
+
const queue = new RemoteEventQueue();
|
|
104
|
+
const disposers = API_REMOTE_FORWARDED_EVENTS.map(({ event, mode }) => {
|
|
105
|
+
if (mode === "emit") return ctx.on(event, ((...args) => {
|
|
106
|
+
queue.push({
|
|
107
|
+
event,
|
|
108
|
+
args: assertJsonArgs(event, args)
|
|
109
|
+
});
|
|
110
|
+
}));
|
|
111
|
+
return ctx.on(event, (function(request, next) {
|
|
112
|
+
const subject = carrierKeyOf(this);
|
|
113
|
+
if (subject === void 0) return next();
|
|
114
|
+
const value = Reflect.get(subject, "ctx");
|
|
115
|
+
if (typeof value !== "object" || value === null) throw new TypeError(`forwarded scoped event ${JSON.stringify(event)} has no live Context`);
|
|
116
|
+
return forwardWaterfall(queue, event, request, {
|
|
117
|
+
value,
|
|
118
|
+
subject
|
|
119
|
+
}, next);
|
|
120
|
+
}));
|
|
121
|
+
});
|
|
122
|
+
return queue.iterate(signal, () => {
|
|
123
|
+
for (const dispose of disposers) dispose();
|
|
124
|
+
});
|
|
91
125
|
};
|
|
92
126
|
}
|
|
93
|
-
/**
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
if (
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
const fenced = fencedLiveAgent(sessionId);
|
|
111
|
-
if (fenced !== void 0) return fenced;
|
|
112
|
-
const attached = ctx.sessions.get(sessionId);
|
|
113
|
-
if (attached !== void 0 && hasApiRemoteSubagentOwner(ctx, attached, void 0)) return { error: apiRemoteSubagentOwnershipError(sessionId) };
|
|
114
|
-
let resume = resumes.get(sessionId);
|
|
115
|
-
if (resume === void 0) {
|
|
116
|
-
resume = (async () => {
|
|
117
|
-
try {
|
|
118
|
-
const inspected = await inspectApiRemoteSession(ctx, sessionId);
|
|
119
|
-
if (hasApiRemoteSubagentOwner(ctx, { header: inspected.meta }, void 0)) throw new ApiRemoteSubagentSessionOwnership(sessionId);
|
|
120
|
-
const setup = options.setup === void 0 ? void 0 : await options.setup(inspected);
|
|
121
|
-
const publishedSession = ctx.sessions.get(sessionId);
|
|
122
|
-
const publishedAgent = ctx.agents.get(sessionId);
|
|
123
|
-
if (publishedSession !== void 0 && hasApiRemoteSubagentOwner(ctx, publishedSession, publishedAgent)) throw new ApiRemoteSubagentSessionOwnership(sessionId);
|
|
124
|
-
return (await ctx.agents.resume({
|
|
125
|
-
resumeSessionId: sessionId,
|
|
126
|
-
...options.agentOptions === void 0 ? {} : { agentOptions: options.agentOptions() },
|
|
127
|
-
...setup === void 0 ? {} : { setup }
|
|
128
|
-
})).agent;
|
|
129
|
-
} finally {
|
|
130
|
-
resumes.delete(sessionId);
|
|
131
|
-
}
|
|
132
|
-
})();
|
|
133
|
-
resumes.set(sessionId, resume);
|
|
127
|
+
/** One pull-driven queue bridging synchronous Cordis listeners to an AsyncIterable. */
|
|
128
|
+
var RemoteEventQueue = class {
|
|
129
|
+
buffer = new Deque();
|
|
130
|
+
waiter;
|
|
131
|
+
done = false;
|
|
132
|
+
push(frame) {
|
|
133
|
+
if (this.done) return false;
|
|
134
|
+
this.buffer.pushBack(frame);
|
|
135
|
+
this.waiter?.();
|
|
136
|
+
return true;
|
|
137
|
+
}
|
|
138
|
+
end(reason) {
|
|
139
|
+
if (this.done) return;
|
|
140
|
+
this.done = true;
|
|
141
|
+
while (this.buffer.size > 0) {
|
|
142
|
+
const dispatch = this.buffer.popFront();
|
|
143
|
+
if ("context" in dispatch) dispatch.reject(reason);
|
|
134
144
|
}
|
|
145
|
+
this.waiter?.();
|
|
146
|
+
}
|
|
147
|
+
async *iterate(signal, cleanup) {
|
|
148
|
+
const abort = () => {
|
|
149
|
+
this.end(remoteEventSourceEndReason(signal));
|
|
150
|
+
};
|
|
151
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
135
152
|
try {
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
return { error: {
|
|
149
|
-
code: "internal",
|
|
150
|
-
message: `resume failed for session "${sessionId}": ${String(error)}`,
|
|
151
|
-
details: {}
|
|
152
|
-
} };
|
|
153
|
+
while (true) {
|
|
154
|
+
if (this.done || signal.aborted) return;
|
|
155
|
+
while (this.buffer.size > 0) yield this.buffer.popFront();
|
|
156
|
+
await new Promise((resolve) => {
|
|
157
|
+
this.waiter = resolve;
|
|
158
|
+
});
|
|
159
|
+
this.waiter = void 0;
|
|
160
|
+
}
|
|
161
|
+
} finally {
|
|
162
|
+
signal.removeEventListener("abort", abort);
|
|
163
|
+
this.end(remoteEventSourceEndReason(signal));
|
|
164
|
+
cleanup();
|
|
153
165
|
}
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
/**
|
|
169
|
+
* Normalize an event-source shutdown for pending Host waterfalls.
|
|
170
|
+
* @param signal - source lifetime whose reason wins after cancellation.
|
|
171
|
+
* @returns the cancellation reason or an unexpected-end failure.
|
|
172
|
+
*/
|
|
173
|
+
function remoteEventSourceEndReason(signal) {
|
|
174
|
+
if (signal.aborted) return signal.reason;
|
|
175
|
+
return /* @__PURE__ */ new Error("api-remotes: forwarded Remote event source ended");
|
|
176
|
+
}
|
|
177
|
+
/** Bridge one Cordis waterfall listener through the Gateway-owned pending event. */
|
|
178
|
+
function forwardWaterfall(queue, event, request, context, next) {
|
|
179
|
+
const settled = Promise.withResolvers();
|
|
180
|
+
const dispatch = {
|
|
181
|
+
event,
|
|
182
|
+
request,
|
|
183
|
+
context,
|
|
184
|
+
resolve: (outcome) => {
|
|
185
|
+
if (outcome.kind === "result") {
|
|
186
|
+
settled.resolve(outcome.value);
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
Promise.resolve().then(next).then(settled.resolve, settled.reject);
|
|
190
|
+
},
|
|
191
|
+
reject: settled.reject
|
|
154
192
|
};
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
typeCtx.typert.lookups.configure("session", async (sessionId) => (await resolveAgent(sessionId)).session);
|
|
163
|
-
typeCtx.typert.contexts.configureHost("agent", async (sessionId) => (await resolveAgent(sessionId)).ctx);
|
|
164
|
-
});
|
|
165
|
-
return agentFor;
|
|
193
|
+
if (!queue.push(dispatch)) Promise.resolve().then(next).then(settled.resolve, settled.reject);
|
|
194
|
+
return settled.promise;
|
|
195
|
+
}
|
|
196
|
+
/** Reject an allowlisted event whose runtime arguments are not lossless JSON data. */
|
|
197
|
+
function assertJsonArgs(event, args) {
|
|
198
|
+
for (const [index, arg] of args.entries()) if (!isJsonValue(arg)) throw new Error(`forwarded host event "${event}" argument ${String(index)} is not lossless JSON data`);
|
|
199
|
+
return args;
|
|
166
200
|
}
|
|
167
201
|
//#endregion
|
|
168
|
-
|
|
169
|
-
/** Host plugin body; the selected contributions mount only in Client environments. */
|
|
170
|
-
function apply() {}
|
|
171
|
-
//#endregion
|
|
172
|
-
export { API_REMOTE_FORWARDED_EVENTS, ApiRemoteSessionNotFound, ApiRemoteSubagentSessionOwnership, apiRemoteSubagentOwnershipError, apply, createApiRemoteAgentResolver, hasApiRemoteSubagentOwner, inspectApiRemoteSession };
|
|
202
|
+
export { API_REMOTE_FORWARDED_EVENTS, apply, inject };
|
|
@@ -1,14 +1,23 @@
|
|
|
1
1
|
/** Platform-neutral assembly of generated Host Remote contributions. */
|
|
2
2
|
import type { Context } from '@deepseek-ai/cordis';
|
|
3
|
-
import type {
|
|
4
|
-
export type {
|
|
3
|
+
import type { ClientRemote } from '@deepseek-ai/dsh-api-gateway/client';
|
|
4
|
+
export type { ClientRemote } from '@deepseek-ai/dsh-api-gateway/client';
|
|
5
5
|
export type { PluginInventorySnapshot } from '@deepseek-ai/dsh-host-plugin-inventory/types';
|
|
6
|
+
export type {} from '@deepseek-ai/dsh-agent-presets/remote';
|
|
6
7
|
export type {} from '@deepseek-ai/dsh-commands/remote';
|
|
7
|
-
export type {} from '@deepseek-ai/dsh-
|
|
8
|
+
export type {} from '@deepseek-ai/dsh-api-settings-controller/remote';
|
|
8
9
|
export type {} from '@deepseek-ai/dsh-goal/remote';
|
|
10
|
+
export type {} from '@deepseek-ai/dsh-llm/remote';
|
|
9
11
|
export type {} from '@deepseek-ai/dsh-host-plugin-inventory/remote';
|
|
10
12
|
export type {} from '@deepseek-ai/dsh-message-feedback/remote';
|
|
11
13
|
export type {} from '@deepseek-ai/dsh-session-reference/remote';
|
|
14
|
+
export type {} from '@deepseek-ai/dsh-subagent/remote';
|
|
15
|
+
export type * from '@deepseek-ai/dsh-subagent/client';
|
|
16
|
+
export type {} from '@deepseek-ai/dsh-api-session-controller/remote';
|
|
17
|
+
export type * from '@deepseek-ai/dsh-api-session-controller/types';
|
|
18
|
+
export type {} from '@deepseek-ai/dsh-api-workspace-controller/remote';
|
|
19
|
+
export type * from '@deepseek-ai/dsh-api-workspace-controller/types';
|
|
20
|
+
export type { SessionJob as JobView } from '@deepseek-ai/dsh-api-session-controller/types';
|
|
12
21
|
export type { ApiRemoteForwardedEvent } from '../types.ts';
|
|
13
22
|
export type {} from '@deepseek-ai/dsh-commands/types';
|
|
14
23
|
export type {} from '@deepseek-ai/dsh-cordis-host-runner/types';
|
|
@@ -16,22 +25,29 @@ export type {} from '@deepseek-ai/dsh-credentials/types';
|
|
|
16
25
|
export type {} from '@deepseek-ai/dsh-llm/types';
|
|
17
26
|
export type {} from '@deepseek-ai/dsh-agent-presets/types';
|
|
18
27
|
export type {} from '@deepseek-ai/dsh-settings/types';
|
|
28
|
+
export type {} from '@deepseek-ai/dsh-user-approval/types';
|
|
29
|
+
export type {} from '@deepseek-ai/dsh-user-questions/types';
|
|
30
|
+
export type {} from '@deepseek-ai/dsh-api-session-controller/types';
|
|
19
31
|
/**
|
|
20
32
|
* The carrier's Client-facing types, re-exported so a business package names one
|
|
21
33
|
* assembly package instead of both this facade and the Connection plugin. Type-only:
|
|
22
34
|
* the carrier's runtime values stay behind their own module edge.
|
|
23
35
|
*/
|
|
24
|
-
export type {
|
|
36
|
+
export type { ConnectionHandle, ConnectionSinks, ContentBlock, MessageId, RpcId, RpcRequest, RpcResponse, RpcResult, SessionId, StreamChunk, } from '@deepseek-ai/dsh-client-connection/client';
|
|
25
37
|
export type {} from '@deepseek-ai/dsh-api-gateway/client';
|
|
26
38
|
export type {} from '@deepseek-ai/dsh-cordis-host-runner/remote';
|
|
27
39
|
export type { ApprovalRequestId, CordisHalfState, CordisDynamicPackageId, CordisDynamicPluginId, CordisDynamicPluginRunId, CordisDynamicRunMode, CordisInspectMethodManifest, CordisInspectPlatform, CordisInspectProviderManifest, CordisInspectProviderView, CordisInspectQueryRequest, CordisInspectQueryResolution, CordisInspectQueryResolved, CordisInspectRequestId, CordisInspectResolveAck, CordisRunDiagnostic, CordisRunStatus, DynamicCordisClientSource, DynamicCordisHostHalfResult, DynamicCordisInventoryRow, DynamicCordisInvokeResult, DynamicCordisPackage, DynamicCordisRequestResolved, DynamicCordisResolveAck, DynamicCordisRetracted, DynamicCordisRunRequest, DynamicCordisRunResolution, DynamicCordisRunAttempt, DynamicCordisRunResponse, DynamicCordisStopResponse, DynamicCordisUndefineReceipt, RequestRunOutcome, } from '@deepseek-ai/dsh-cordis-host-runner/types';
|
|
28
|
-
export type {
|
|
40
|
+
export type { CredentialInfo } from '@deepseek-ai/dsh-credentials/types';
|
|
41
|
+
export type { SettingsDescribeValue, SettingsNamespaceView, SettingsPathOpView, SettingsSecretView, } from '@deepseek-ai/dsh-settings/types';
|
|
42
|
+
export type { LlmConfigurableProvider, LlmDiscoveredModel, LlmModelDiscoveryRequest, LlmProviderInfo, } from '@deepseek-ai/dsh-llm/types';
|
|
29
43
|
export type { FileReferenceCandidate } from '@deepseek-ai/dsh-file-reference/types';
|
|
30
44
|
export type { SessionReferenceMentionCandidate } from '@deepseek-ai/dsh-session-reference/types';
|
|
45
|
+
export type { RemoteErrorCode, RemoteErrorDetailsMap, RemoteFailure, RemoteResult, } from '@deepseek-ai/dsh-typert-protocol';
|
|
46
|
+
export type { RemoteHostFacts } from '@deepseek-ai/dsh-api-gateway/client';
|
|
31
47
|
declare module '@deepseek-ai/cordis' {
|
|
32
48
|
interface Context {
|
|
33
49
|
/** Generated Remote namespaces selected by this Client assembly. */
|
|
34
|
-
remote:
|
|
50
|
+
remote: ClientRemote;
|
|
35
51
|
}
|
|
36
52
|
}
|
|
37
53
|
/** Required service: the typed Client Remote contribution mount. */
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
/** Platform-neutral assembly of generated Host Remote contributions. */
|
|
2
|
+
import agentPresetsRemote from '@deepseek-ai/dsh-agent-presets/remote';
|
|
2
3
|
import commandsRemote from '@deepseek-ai/dsh-commands/remote';
|
|
4
|
+
import settingsControllerRemote from '@deepseek-ai/dsh-api-settings-controller/remote';
|
|
3
5
|
import goalsRemote from '@deepseek-ai/dsh-goal/remote';
|
|
6
|
+
import llmRemote from '@deepseek-ai/dsh-llm/remote';
|
|
4
7
|
import dynamicRemote from '@deepseek-ai/dsh-cordis-host-runner/remote';
|
|
5
|
-
import fileReferencesRemote from '@deepseek-ai/dsh-file-reference/remote';
|
|
6
8
|
import pluginInventoryRemote from '@deepseek-ai/dsh-host-plugin-inventory/remote';
|
|
7
9
|
import messageFeedbackRemote from '@deepseek-ai/dsh-message-feedback/remote';
|
|
8
10
|
import sessionReferencesRemote from '@deepseek-ai/dsh-session-reference/remote';
|
|
11
|
+
import subagentsRemote from '@deepseek-ai/dsh-subagent/remote';
|
|
12
|
+
import sessionRemote from '@deepseek-ai/dsh-api-session-controller/remote';
|
|
13
|
+
import workspaceRemote from '@deepseek-ai/dsh-api-workspace-controller/remote';
|
|
9
14
|
/** Required service: the typed Client Remote contribution mount. */
|
|
10
15
|
export const inject = ['remote'];
|
|
11
16
|
/**
|
|
@@ -17,8 +22,9 @@ export async function apply(ctx) {
|
|
|
17
22
|
const disposers = [];
|
|
18
23
|
try {
|
|
19
24
|
for (const contribution of [
|
|
20
|
-
commandsRemote, goalsRemote,
|
|
25
|
+
agentPresetsRemote, commandsRemote, settingsControllerRemote, goalsRemote, llmRemote, dynamicRemote,
|
|
21
26
|
pluginInventoryRemote, messageFeedbackRemote, sessionReferencesRemote,
|
|
27
|
+
subagentsRemote, sessionRemote, workspaceRemote,
|
|
22
28
|
]) {
|
|
23
29
|
disposers.push(await ctx.remote.$mount(contribution));
|
|
24
30
|
}
|
package/lib/types/index.d.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
/** Host BFF entry and Loader shell for the Remote contribution assembly. */
|
|
2
|
-
|
|
3
|
-
export type {
|
|
2
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
3
|
+
export type {} from '@deepseek-ai/dsh-api-session-controller/types';
|
|
4
4
|
export { API_REMOTE_FORWARDED_EVENTS } from './remote-events.ts';
|
|
5
5
|
export type { ApiRemoteForwardedEvent } from './types.ts';
|
|
6
|
-
/** Host
|
|
7
|
-
export declare
|
|
6
|
+
/** Required Host service: the Gateway owns the physical Remote stream mux. */
|
|
7
|
+
export declare const inject: string[];
|
|
8
|
+
/** Host plugin body registering this application's selected Cordis event source. */
|
|
9
|
+
export declare function apply(ctx: Context): void;
|
|
8
10
|
//# sourceMappingURL=index.d.ts.map
|
package/lib/types/index.js
CHANGED
|
@@ -1,16 +1,123 @@
|
|
|
1
1
|
/** Host BFF entry and Loader shell for the Remote contribution assembly. */
|
|
2
|
+
import { homedir } from 'node:os';
|
|
3
|
+
import { Deque } from '@deepseek-ai/dsh-deque';
|
|
4
|
+
import { carrierKeyOf } from '@deepseek-ai/dsh-scope';
|
|
5
|
+
import { isJsonValue } from '@deepseek-ai/dsh-util-values';
|
|
2
6
|
import { API_REMOTE_FORWARDED_EVENTS } from "./remote-events.js";
|
|
3
|
-
export { ApiRemoteSessionNotFound, ApiRemoteSubagentSessionOwnership, apiRemoteSubagentOwnershipError, createApiRemoteAgentResolver, hasApiRemoteSubagentOwner, inspectApiRemoteSession, } from "./agent-lookup.js";
|
|
4
7
|
export { API_REMOTE_FORWARDED_EVENTS } from "./remote-events.js";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
8
|
+
/** Required Host service: the Gateway owns the physical Remote stream mux. */
|
|
9
|
+
export const inject = ['typertGateway'];
|
|
10
|
+
/** Host plugin body registering this application's selected Cordis event source. */
|
|
11
|
+
export function apply(ctx) {
|
|
12
|
+
ctx.effect(() => ctx.typertGateway.registerRemoteEvents(remoteEventSource(ctx), { home: homedir() }), 'api-remotes: forwarded Cordis event source');
|
|
13
|
+
}
|
|
14
|
+
/** Create the sole queue and listener set consumed by the registered Gateway. */
|
|
15
|
+
function remoteEventSource(ctx) {
|
|
16
|
+
return (signal) => {
|
|
17
|
+
const queue = new RemoteEventQueue();
|
|
18
|
+
const disposers = API_REMOTE_FORWARDED_EVENTS.map(({ event, mode }) => {
|
|
19
|
+
if (mode === 'emit') {
|
|
20
|
+
return ctx.on(event, ((...args) => {
|
|
21
|
+
queue.push({ event, args: assertJsonArgs(event, args) });
|
|
22
|
+
}));
|
|
23
|
+
}
|
|
24
|
+
return ctx.on(event, (function (request, next) {
|
|
25
|
+
const subject = carrierKeyOf(this);
|
|
26
|
+
if (subject === undefined)
|
|
27
|
+
return next();
|
|
28
|
+
const value = Reflect.get(subject, 'ctx');
|
|
29
|
+
if (typeof value !== 'object' || value === null) {
|
|
30
|
+
throw new TypeError(`forwarded scoped event ${JSON.stringify(event)} has no live Context`);
|
|
31
|
+
}
|
|
32
|
+
return forwardWaterfall(queue, event, request, { value: value, subject }, next);
|
|
33
|
+
}));
|
|
34
|
+
});
|
|
35
|
+
return queue.iterate(signal, () => {
|
|
36
|
+
for (const dispose of disposers)
|
|
37
|
+
dispose();
|
|
38
|
+
});
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
/** One pull-driven queue bridging synchronous Cordis listeners to an AsyncIterable. */
|
|
42
|
+
class RemoteEventQueue {
|
|
43
|
+
buffer = new Deque();
|
|
44
|
+
waiter;
|
|
45
|
+
done = false;
|
|
46
|
+
push(frame) {
|
|
47
|
+
if (this.done)
|
|
48
|
+
return false;
|
|
49
|
+
this.buffer.pushBack(frame);
|
|
50
|
+
this.waiter?.();
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
end(reason) {
|
|
54
|
+
if (this.done)
|
|
55
|
+
return;
|
|
56
|
+
this.done = true;
|
|
57
|
+
while (this.buffer.size > 0) {
|
|
58
|
+
const dispatch = this.buffer.popFront();
|
|
59
|
+
if ('context' in dispatch)
|
|
60
|
+
dispatch.reject(reason);
|
|
61
|
+
}
|
|
62
|
+
this.waiter?.();
|
|
63
|
+
}
|
|
64
|
+
async *iterate(signal, cleanup) {
|
|
65
|
+
const abort = () => { this.end(remoteEventSourceEndReason(signal)); };
|
|
66
|
+
signal.addEventListener('abort', abort, { once: true });
|
|
67
|
+
try {
|
|
68
|
+
while (true) {
|
|
69
|
+
if (this.done || signal.aborted)
|
|
70
|
+
return;
|
|
71
|
+
while (this.buffer.size > 0)
|
|
72
|
+
yield this.buffer.popFront();
|
|
73
|
+
await new Promise((resolve) => { this.waiter = resolve; });
|
|
74
|
+
this.waiter = undefined;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
finally {
|
|
78
|
+
signal.removeEventListener('abort', abort);
|
|
79
|
+
this.end(remoteEventSourceEndReason(signal));
|
|
80
|
+
cleanup();
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Normalize an event-source shutdown for pending Host waterfalls.
|
|
86
|
+
* @param signal - source lifetime whose reason wins after cancellation.
|
|
87
|
+
* @returns the cancellation reason or an unexpected-end failure.
|
|
88
|
+
*/
|
|
89
|
+
function remoteEventSourceEndReason(signal) {
|
|
90
|
+
if (signal.aborted)
|
|
91
|
+
return signal.reason;
|
|
92
|
+
return new Error('api-remotes: forwarded Remote event source ended');
|
|
93
|
+
}
|
|
94
|
+
/** Bridge one Cordis waterfall listener through the Gateway-owned pending event. */
|
|
95
|
+
function forwardWaterfall(queue, event, request, context, next) {
|
|
96
|
+
const settled = Promise.withResolvers();
|
|
97
|
+
const dispatch = {
|
|
98
|
+
event,
|
|
99
|
+
request,
|
|
100
|
+
context,
|
|
101
|
+
resolve: (outcome) => {
|
|
102
|
+
if (outcome.kind === 'result') {
|
|
103
|
+
settled.resolve(outcome.value);
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
void Promise.resolve().then(next).then(settled.resolve, settled.reject);
|
|
107
|
+
},
|
|
108
|
+
reject: settled.reject,
|
|
109
|
+
};
|
|
110
|
+
if (!queue.push(dispatch))
|
|
111
|
+
void Promise.resolve().then(next).then(settled.resolve, settled.reject);
|
|
112
|
+
return settled.promise;
|
|
113
|
+
}
|
|
114
|
+
/** Reject an allowlisted event whose runtime arguments are not lossless JSON data. */
|
|
115
|
+
function assertJsonArgs(event, args) {
|
|
116
|
+
for (const [index, arg] of args.entries()) {
|
|
117
|
+
if (!isJsonValue(arg)) {
|
|
118
|
+
throw new Error(`forwarded host event "${event}" argument ${String(index)} is not lossless JSON data`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return args;
|
|
122
|
+
}
|
|
16
123
|
//# sourceMappingURL=index.js.map
|