@plurnk/plurnk-agui 0.3.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/.env.example +37 -0
- package/README.md +65 -0
- package/SPEC.md +115 -0
- package/dist/AguiPlus.d.ts +58 -0
- package/dist/AguiPlus.d.ts.map +1 -0
- package/dist/AguiPlus.js +67 -0
- package/dist/AguiPlus.js.map +1 -0
- package/dist/DaemonClient.d.ts +9 -0
- package/dist/DaemonClient.d.ts.map +1 -0
- package/dist/DaemonClient.js +55 -0
- package/dist/DaemonClient.js.map +1 -0
- package/dist/DaemonSeam.d.ts +103 -0
- package/dist/DaemonSeam.d.ts.map +1 -0
- package/dist/DaemonSeam.js +7 -0
- package/dist/DaemonSeam.js.map +1 -0
- package/dist/EventRouter.d.ts +14 -0
- package/dist/EventRouter.d.ts.map +1 -0
- package/dist/EventRouter.js +27 -0
- package/dist/EventRouter.js.map +1 -0
- package/dist/Module.d.ts +23 -0
- package/dist/Module.d.ts.map +1 -0
- package/dist/Module.js +200 -0
- package/dist/Module.js.map +1 -0
- package/dist/Portal.d.ts +33 -0
- package/dist/Portal.d.ts.map +1 -0
- package/dist/Portal.js +62 -0
- package/dist/Portal.js.map +1 -0
- package/dist/ProposalHitl.d.ts +14 -0
- package/dist/ProposalHitl.d.ts.map +1 -0
- package/dist/ProposalHitl.js +64 -0
- package/dist/ProposalHitl.js.map +1 -0
- package/dist/Server.d.ts +10 -0
- package/dist/Server.d.ts.map +1 -0
- package/dist/Server.js +232 -0
- package/dist/Server.js.map +1 -0
- package/dist/Translator.d.ts +17 -0
- package/dist/Translator.d.ts.map +1 -0
- package/dist/Translator.js +200 -0
- package/dist/Translator.js.map +1 -0
- package/dist/bin/serve.d.ts +3 -0
- package/dist/bin/serve.d.ts.map +1 -0
- package/dist/bin/serve.js +9 -0
- package/dist/bin/serve.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +134 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +10 -0
- package/dist/types.js.map +1 -0
- package/package.json +65 -0
package/dist/Module.js
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
// The in-process transport module (plurnk-agui#2) — what the daemon's boot plug-point
|
|
2
|
+
// activates: registerModule(aguiModule(opts)) hands this the CoreSeam handle; it opens
|
|
3
|
+
// the AG-UI+ HTTP/SSE listener and owns the client interface from there.
|
|
4
|
+
//
|
|
5
|
+
// This is the SINGLE-INTERFACE surface (AG-UI+), not the legacy bridge dialect:
|
|
6
|
+
// POST / — the only endpoint. A run streams SSE. HITL is terminate-resume: a
|
|
7
|
+
// stopped-world emits a request_approval/request_user_input TOOL_CALL and the run
|
|
8
|
+
// FINISHES (the loop stays paused in-engine); the resume arrives as the next run's
|
|
9
|
+
// tool-result message → resolveProposal → the continued loop streams there.
|
|
10
|
+
// Reads ride STATE_SNAPSHOT on RUN_STARTED; no /plurnk/rpc, no /resolve.
|
|
11
|
+
// An AG-UI threadId IS a plurnk session (`<prefix>-<threadId>`); the envelope's
|
|
12
|
+
// modelRunId binds the thread (no lazy inference — createSession returns it).
|
|
13
|
+
var _a;
|
|
14
|
+
import { createServer } from "node:http";
|
|
15
|
+
import Portal from "./Portal.js";
|
|
16
|
+
import { stateSnapshot } from "./AguiPlus.js";
|
|
17
|
+
class Module {
|
|
18
|
+
#seam;
|
|
19
|
+
#opts;
|
|
20
|
+
#portal;
|
|
21
|
+
#http;
|
|
22
|
+
#threads = new Map(); // threadId → envelope
|
|
23
|
+
constructor(seam, opts) {
|
|
24
|
+
this.#seam = seam;
|
|
25
|
+
this.#opts = opts;
|
|
26
|
+
this.#portal = new Portal(seam);
|
|
27
|
+
this.#http = createServer((req, res) => { void this.#route(req, res); });
|
|
28
|
+
}
|
|
29
|
+
// The boot-plug-point init: `daemon.registerModule(Module.init(opts))`.
|
|
30
|
+
static init(opts) {
|
|
31
|
+
return async (seam) => {
|
|
32
|
+
const m = new _a(seam, opts);
|
|
33
|
+
await m.listen();
|
|
34
|
+
return m;
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
async listen() {
|
|
38
|
+
this.#portal.start();
|
|
39
|
+
await new Promise((resolve) => this.#http.listen(this.#opts.port, this.#opts.host, resolve));
|
|
40
|
+
const addr = this.#http.address();
|
|
41
|
+
if (addr === null || typeof addr === "string")
|
|
42
|
+
throw new Error("plurnk-agui: listener bound no TCP address");
|
|
43
|
+
return { host: this.#opts.host, port: addr.port };
|
|
44
|
+
}
|
|
45
|
+
address() {
|
|
46
|
+
const addr = this.#http.address();
|
|
47
|
+
if (addr === null || typeof addr === "string")
|
|
48
|
+
throw new Error("plurnk-agui: not listening");
|
|
49
|
+
return { host: this.#opts.host, port: addr.port };
|
|
50
|
+
}
|
|
51
|
+
async close() {
|
|
52
|
+
this.#portal.stop();
|
|
53
|
+
await new Promise((resolve, reject) => this.#http.close((e) => (e ? reject(e) : resolve())));
|
|
54
|
+
}
|
|
55
|
+
async #route(req, res) {
|
|
56
|
+
try {
|
|
57
|
+
res.setHeader("access-control-allow-origin", "*");
|
|
58
|
+
res.setHeader("access-control-allow-headers", "content-type, authorization");
|
|
59
|
+
if (req.method === "OPTIONS") {
|
|
60
|
+
res.writeHead(204).end();
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
// The perimeter (§governance): bearer check before any body read.
|
|
64
|
+
const token = this.#opts.token ?? "";
|
|
65
|
+
if (token.length > 0 && req.headers.authorization !== `Bearer ${token}`) {
|
|
66
|
+
res.writeHead(401, { "content-type": "application/json" }).end(JSON.stringify({ error: "bearer token required" }));
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
if (req.method === "POST" && (req.url === "/" || req.url === "/agui"))
|
|
70
|
+
return await this.#run(req, res);
|
|
71
|
+
res.writeHead(404, { "content-type": "application/json" }).end(JSON.stringify({ error: "POST / (AG-UI run) is the interface" }));
|
|
72
|
+
}
|
|
73
|
+
catch (err) {
|
|
74
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
75
|
+
if (!res.headersSent)
|
|
76
|
+
res.writeHead(500, { "content-type": "application/json" });
|
|
77
|
+
res.end(JSON.stringify({ error: message }));
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
// threadId → envelope: reattach by name, else create (session options ride the
|
|
81
|
+
// first run's forwardedProps.plurnk, as before).
|
|
82
|
+
async #envelope(threadId, forwarded) {
|
|
83
|
+
const cached = this.#threads.get(threadId);
|
|
84
|
+
if (cached !== undefined)
|
|
85
|
+
return { env: cached, reattached: true };
|
|
86
|
+
const name = `${this.#opts.sessionPrefix}-${threadId}`;
|
|
87
|
+
const known = (await this.#seam.listSessions()).find((s) => s.name === name);
|
|
88
|
+
let env;
|
|
89
|
+
let reattached = false;
|
|
90
|
+
if (known !== undefined) {
|
|
91
|
+
env = await this.#seam.attachSession({ sessionId: known.id });
|
|
92
|
+
reattached = true;
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
const opts = forwarded ?? {};
|
|
96
|
+
env = await this.#seam.createSession({
|
|
97
|
+
name,
|
|
98
|
+
...(typeof opts.projectRoot === "string" ? { projectRoot: opts.projectRoot } : {}),
|
|
99
|
+
...(Array.isArray(opts.constraints) ? { constraints: opts.constraints } : {}),
|
|
100
|
+
...(typeof opts.settings === "object" && opts.settings !== null ? { settings: JSON.stringify(opts.settings) } : {}),
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
this.#threads.set(threadId, env);
|
|
104
|
+
return { env, reattached };
|
|
105
|
+
}
|
|
106
|
+
async #run(req, res) {
|
|
107
|
+
const input = JSON.parse(await _a.#body(req));
|
|
108
|
+
if (typeof input.threadId !== "string" || input.threadId.length === 0)
|
|
109
|
+
throw new Error("RunAgentInput.threadId required");
|
|
110
|
+
const forwarded = input.forwardedProps?.plurnk;
|
|
111
|
+
const { env, reattached } = await this.#envelope(input.threadId, forwarded);
|
|
112
|
+
const sessionId = env.sessionId;
|
|
113
|
+
const runId = env.runId; // the DRIVE run (client envelope); the model run binds the render below
|
|
114
|
+
res.writeHead(200, { "content-type": "text/event-stream", "cache-control": "no-cache", "connection": "keep-alive" });
|
|
115
|
+
let finished = false;
|
|
116
|
+
let pausedOnProposal = false;
|
|
117
|
+
const finish = () => {
|
|
118
|
+
if (finished)
|
|
119
|
+
return;
|
|
120
|
+
finished = true;
|
|
121
|
+
this.#portal.closeThread(sessionId);
|
|
122
|
+
res.end();
|
|
123
|
+
};
|
|
124
|
+
const emit = (events) => {
|
|
125
|
+
for (const e of events) {
|
|
126
|
+
res.write(`data: ${JSON.stringify(e)}\n\n`);
|
|
127
|
+
// Terminate-resume, the terminate half: a proposal tool-call ENDS this
|
|
128
|
+
// run (the loop stays paused in-engine awaiting the resume run).
|
|
129
|
+
if (e.type === "TOOL_CALL_END" && e.toolCallId.startsWith("prop:"))
|
|
130
|
+
pausedOnProposal = true;
|
|
131
|
+
if (e.type === "RUN_FINISHED" || e.type === "RUN_ERROR")
|
|
132
|
+
finish();
|
|
133
|
+
}
|
|
134
|
+
if (pausedOnProposal && !finished) {
|
|
135
|
+
res.write(`data: ${JSON.stringify({ type: "RUN_FINISHED", threadId: input.threadId, runId: input.runId })}\n\n`);
|
|
136
|
+
finish();
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
this.#portal.openThread({ sessionId, runId, threadId: input.threadId, emit, modelRunId: env.modelRunId });
|
|
140
|
+
emit([
|
|
141
|
+
{ type: "RUN_STARTED", threadId: input.threadId, runId: input.runId },
|
|
142
|
+
stateSnapshot({ providers: this.#seam.listProviders().aliases, session: { id: sessionId, name: env.sessionName, projectRoot: env.projectRoot } }),
|
|
143
|
+
]);
|
|
144
|
+
if (finished)
|
|
145
|
+
return;
|
|
146
|
+
// Terminate-resume, the resume half: a tool-result message resolves the paused
|
|
147
|
+
// proposal; the continued loop streams on THIS run. No new loop is driven.
|
|
148
|
+
const toolResult = [...(input.messages ?? [])].reverse().find((m) => m.role === "tool");
|
|
149
|
+
if (toolResult !== undefined && this.#portal.resolve(toolResult)) {
|
|
150
|
+
req.on("close", finish); // client hangup on a resume just detaches; the loop already runs
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
const lastUser = [...(input.messages ?? [])].reverse().find((m) => m.role === "user");
|
|
154
|
+
if (lastUser?.content === undefined || lastUser.content.length === 0)
|
|
155
|
+
throw new Error("RunAgentInput.messages must carry a user message or a tool result");
|
|
156
|
+
if (reattached) {
|
|
157
|
+
const history = await this.#seam.readLog({ sessionId, runId: env.modelRunId ?? runId, limit: 1000 }).catch(() => null);
|
|
158
|
+
if (history !== null)
|
|
159
|
+
emit([...this.#threadRouterReplay(sessionId, history)]);
|
|
160
|
+
}
|
|
161
|
+
await this.#portal.run({
|
|
162
|
+
sessionId, runId, prompt: lastUser.content,
|
|
163
|
+
...(typeof forwarded?.maxTurns === "number" ? { maxTurns: forwarded.maxTurns } : this.#opts.maxTurns !== undefined ? { maxTurns: this.#opts.maxTurns } : {}),
|
|
164
|
+
...(typeof forwarded?.flags === "object" && forwarded.flags !== null ? { flags: forwarded.flags } : {}),
|
|
165
|
+
});
|
|
166
|
+
// A dropped SSE on a LIVE run cancels the loop (hangup is the abort). A run we
|
|
167
|
+
// finished ourselves — terminal event or proposal-terminate — leaves the engine
|
|
168
|
+
// alone (the paused loop is exactly what the resume run needs).
|
|
169
|
+
req.on("close", () => {
|
|
170
|
+
if (finished)
|
|
171
|
+
return;
|
|
172
|
+
this.#seam.cancelDrain(runId);
|
|
173
|
+
finish();
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
#threadRouterReplay(sessionId, entries) {
|
|
177
|
+
// Replay via the thread's own router (MESSAGES_SNAPSHOT of the model SENDs).
|
|
178
|
+
const messages = [];
|
|
179
|
+
for (const e of entries) {
|
|
180
|
+
if (e.op === "SEND" && e.origin === "model") {
|
|
181
|
+
const tx = e.tx;
|
|
182
|
+
const body = tx !== null && typeof tx === "object" && typeof tx.body === "string" ? tx.body : "";
|
|
183
|
+
if (body.length > 0)
|
|
184
|
+
messages.push({ id: String(e.coordinate ?? e.id), role: "assistant", content: body });
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return [{ type: "MESSAGES_SNAPSHOT", messages }];
|
|
188
|
+
}
|
|
189
|
+
static #body(req) {
|
|
190
|
+
return new Promise((resolve, reject) => {
|
|
191
|
+
let data = "";
|
|
192
|
+
req.on("data", (c) => { data += c.toString(); });
|
|
193
|
+
req.on("end", () => resolve(data));
|
|
194
|
+
req.on("error", reject);
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
_a = Module;
|
|
199
|
+
export default Module;
|
|
200
|
+
//# sourceMappingURL=Module.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Module.js","sourceRoot":"","sources":["../src/Module.ts"],"names":[],"mappings":"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"}
|
package/dist/Portal.d.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { DaemonSeam } from "./DaemonSeam.ts";
|
|
2
|
+
import type { AguiEvent } from "./types.ts";
|
|
3
|
+
import type { ToolResultMessage } from "./AguiPlus.ts";
|
|
4
|
+
type PortalSeam = Pick<DaemonSeam, "subscribeToEvents" | "pendingProposals" | "resolveProposal" | "runLoop" | "cancelDrain">;
|
|
5
|
+
export default class Portal {
|
|
6
|
+
#private;
|
|
7
|
+
constructor(seam: PortalSeam);
|
|
8
|
+
start(): void;
|
|
9
|
+
stop(): void;
|
|
10
|
+
openThread(args: {
|
|
11
|
+
sessionId: number;
|
|
12
|
+
runId: number;
|
|
13
|
+
threadId: string;
|
|
14
|
+
emit: (events: AguiEvent[]) => void;
|
|
15
|
+
modelRunId?: number | null;
|
|
16
|
+
}): void;
|
|
17
|
+
closeThread(sessionId: number): void;
|
|
18
|
+
run(args: {
|
|
19
|
+
sessionId: number;
|
|
20
|
+
runId: number;
|
|
21
|
+
prompt: string;
|
|
22
|
+
maxTurns?: number;
|
|
23
|
+
flags?: {
|
|
24
|
+
yolo?: boolean;
|
|
25
|
+
};
|
|
26
|
+
}): Promise<{
|
|
27
|
+
loopId: number;
|
|
28
|
+
}>;
|
|
29
|
+
cancel(runId: number): boolean;
|
|
30
|
+
resolve(message: ToolResultMessage): boolean;
|
|
31
|
+
}
|
|
32
|
+
export {};
|
|
33
|
+
//# sourceMappingURL=Portal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Portal.d.ts","sourceRoot":"","sources":["../src/Portal.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAMvD,KAAK,UAAU,GAAG,IAAI,CAAC,UAAU,EAAE,mBAAmB,GAAG,kBAAkB,GAAG,iBAAiB,GAAG,SAAS,GAAG,aAAa,CAAC,CAAC;AAE7H,MAAM,CAAC,OAAO,OAAO,MAAM;;IAMvB,YAAY,IAAI,EAAE,UAAU,EAI3B;IAGD,KAAK,IAAI,IAAI,CAOZ;IAED,IAAI,IAAI,IAAI,CAIX;IAYD,UAAU,CAAC,IAAI,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,CAAC,MAAM,EAAE,SAAS,EAAE,KAAK,IAAI,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI,CAG9I;IAED,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAqC;IAInE,GAAG,CAAC,IAAI,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE;YAAE,IAAI,CAAC,EAAE,OAAO,CAAA;SAAE,CAAA;KAAE,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAKhJ;IAED,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAA0C;IAGxE,OAAO,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAwC;CACvF"}
|
package/dist/Portal.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// The in-process module's orchestration engine (plurnk-agui#2). Composes the seam +
|
|
2
|
+
// the render router + the HITL core into the run flow: subscribe ONCE to the event
|
|
3
|
+
// source, fan each event to the bound thread for its session, drive/cancel loops via
|
|
4
|
+
// the seam, and route a resume tool-result to resolveProposal. Transport-agnostic —
|
|
5
|
+
// the HTTP/SSE listener (the outward edge) and session establishment (session-lifecycle
|
|
6
|
+
// hook, pending) wrap this; the engine is testable against a mock seam today.
|
|
7
|
+
import EventRouter from "./EventRouter.js";
|
|
8
|
+
import ProposalHitl from "./ProposalHitl.js";
|
|
9
|
+
export default class Portal {
|
|
10
|
+
#seam;
|
|
11
|
+
#threads = new Map(); // by sessionId (the AG-UI thread's bound session)
|
|
12
|
+
#hitl;
|
|
13
|
+
#off = null;
|
|
14
|
+
constructor(seam) {
|
|
15
|
+
this.#seam = seam;
|
|
16
|
+
// HITL fans its tool-calls through the same session→thread route as the router.
|
|
17
|
+
this.#hitl = new ProposalHitl(seam, (sessionId, events) => this.#fan(sessionId, events));
|
|
18
|
+
}
|
|
19
|
+
// One subscription for the whole module: render each event to its session's thread.
|
|
20
|
+
start() {
|
|
21
|
+
this.#hitl.start();
|
|
22
|
+
this.#off = this.#seam.subscribeToEvents((sessionId, method, params) => {
|
|
23
|
+
if (sessionId === null)
|
|
24
|
+
return; // global (session/created) handled out-of-band
|
|
25
|
+
const thread = this.#threads.get(sessionId);
|
|
26
|
+
if (thread !== undefined)
|
|
27
|
+
this.#fan(sessionId, thread.router.route(method, params));
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
stop() {
|
|
31
|
+
this.#hitl.stop();
|
|
32
|
+
this.#off?.();
|
|
33
|
+
this.#off = null;
|
|
34
|
+
}
|
|
35
|
+
#fan(sessionId, events) {
|
|
36
|
+
if (events.length > 0)
|
|
37
|
+
this.#threads.get(sessionId)?.emit(events);
|
|
38
|
+
}
|
|
39
|
+
// Bind a client's SSE to a session/run. The emit consumer ends its stream when it
|
|
40
|
+
// sees RUN_FINISHED / RUN_ERROR (the router's terminal projection) — the engine
|
|
41
|
+
// just fans; the edge owns the socket lifecycle. `runId` is the DRIVE run (the
|
|
42
|
+
// client envelope's); `modelRunId` binds the render (null → the router lazily
|
|
43
|
+
// adopts the first model-origin row's run — a fresh session's model run is born
|
|
44
|
+
// at the drain).
|
|
45
|
+
openThread(args) {
|
|
46
|
+
const router = new EventRouter({ threadId: args.threadId, runId: String(args.runId), modelRunId: args.modelRunId ?? null, sessionId: args.sessionId });
|
|
47
|
+
this.#threads.set(args.sessionId, { runId: args.runId, router, emit: args.emit });
|
|
48
|
+
}
|
|
49
|
+
closeThread(sessionId) { this.#threads.delete(sessionId); }
|
|
50
|
+
// Drive a prompt through the loop (fire-and-forget — the outcome streams via the
|
|
51
|
+
// subscription as loop/terminated). Re-surface any pending stopped-world first.
|
|
52
|
+
async run(args) {
|
|
53
|
+
const pending = await this.#hitl.resurface(args.sessionId);
|
|
54
|
+
this.#fan(args.sessionId, pending);
|
|
55
|
+
const ack = await this.#seam.runLoop(args);
|
|
56
|
+
return { loopId: ack.loopId };
|
|
57
|
+
}
|
|
58
|
+
cancel(runId) { return this.#seam.cancelDrain(runId); }
|
|
59
|
+
// A resume run's tool-result → resolveProposal (true if it resolved a proposal).
|
|
60
|
+
resolve(message) { return this.#hitl.resolve(message); }
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=Portal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Portal.js","sourceRoot":"","sources":["../src/Portal.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { AguiEvent } from "./types.ts";
|
|
2
|
+
import type { DaemonSeam } from "./DaemonSeam.ts";
|
|
3
|
+
import { type ToolResultMessage } from "./AguiPlus.ts";
|
|
4
|
+
type HitlSeam = Pick<DaemonSeam, "subscribeToEvents" | "pendingProposals" | "resolveProposal">;
|
|
5
|
+
export default class ProposalHitl {
|
|
6
|
+
#private;
|
|
7
|
+
constructor(seam: HitlSeam, emit: (sessionId: number, events: AguiEvent[]) => void);
|
|
8
|
+
start(): void;
|
|
9
|
+
stop(): void;
|
|
10
|
+
resurface(sessionId: number): Promise<AguiEvent[]>;
|
|
11
|
+
resolve(message: ToolResultMessage): boolean;
|
|
12
|
+
}
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=ProposalHitl.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ProposalHitl.d.ts","sourceRoot":"","sources":["../src/ProposalHitl.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,SAAS,EAAwB,MAAM,YAAY,CAAC;AAClE,OAAO,KAAK,EAAE,UAAU,EAAmB,MAAM,iBAAiB,CAAC;AACnE,OAAO,EAA8C,KAAK,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAGnG,KAAK,QAAQ,GAAG,IAAI,CAAC,UAAU,EAAE,mBAAmB,GAAG,kBAAkB,GAAG,iBAAiB,CAAC,CAAC;AAE/F,MAAM,CAAC,OAAO,OAAO,YAAY;;IAK7B,YAAY,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,IAAI,EAGjF;IAGD,KAAK,IAAI,IAAI,CAKZ;IAED,IAAI,IAAI,IAAI,CAGX;IAIK,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAGvD;IAKD,OAAO,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAK3C;CAqBJ"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// The in-process HITL core (service#355 hooks B + C + A-resolve; plurnk-agui#2 WS-1).
|
|
2
|
+
// Subscribes to the daemon's event source, renders each stopped-world proposal as an
|
|
3
|
+
// AG-UI tool-call (via AguiPlus), re-surfaces a session's pending proposals on
|
|
4
|
+
// (re)connect, and maps a resume run's tool-result back to resolveProposal. The
|
|
5
|
+
// engine's pause/gate/applyResolution stay core; this is the view + the round-trip.
|
|
6
|
+
import { proposalToolCall, resolutionFromToolResult } from "./AguiPlus.js";
|
|
7
|
+
export default class ProposalHitl {
|
|
8
|
+
#seam;
|
|
9
|
+
#emit; // fan-out to the session's client(s)
|
|
10
|
+
#off = null;
|
|
11
|
+
constructor(seam, emit) {
|
|
12
|
+
this.#seam = seam;
|
|
13
|
+
this.#emit = emit;
|
|
14
|
+
}
|
|
15
|
+
// Subscribe to the event source; project each live stopped-world as a tool-call.
|
|
16
|
+
start() {
|
|
17
|
+
this.#off = this.#seam.subscribeToEvents((sessionId, method, params) => {
|
|
18
|
+
if (method !== "loop/proposal" || sessionId === null)
|
|
19
|
+
return;
|
|
20
|
+
this.#emit(sessionId, proposalToolCall(params));
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
stop() {
|
|
24
|
+
this.#off?.();
|
|
25
|
+
this.#off = null;
|
|
26
|
+
}
|
|
27
|
+
// Re-surface a session's pending stopped-worlds on (re)connect — a days-old
|
|
28
|
+
// question is discoverable, not lost — each as a tool-call the frontend renders.
|
|
29
|
+
async resurface(sessionId) {
|
|
30
|
+
const pending = await this.#seam.pendingProposals(sessionId);
|
|
31
|
+
return pending.flatMap((p) => proposalToolCall(ProposalHitl.#normalize(p)));
|
|
32
|
+
}
|
|
33
|
+
// A resume run's tool-result → resolveProposal. Returns true if it resolved a
|
|
34
|
+
// proposal (false = not a plurnk proposal tool-result; the caller handles it as
|
|
35
|
+
// an ordinary message).
|
|
36
|
+
resolve(message) {
|
|
37
|
+
const res = resolutionFromToolResult(message);
|
|
38
|
+
if (res === null)
|
|
39
|
+
return false;
|
|
40
|
+
this.#seam.resolveProposal(res.logEntryId, { decision: res.decision, ...(res.body !== undefined ? { body: res.body } : {}) });
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
// The DB-shaped pending row → the ProposalNotification AguiPlus renders. attrs/tx
|
|
44
|
+
// arrive as JSON strings; parse at the edge.
|
|
45
|
+
static #normalize(p) {
|
|
46
|
+
return {
|
|
47
|
+
logEntryId: p.logEntryId, sessionId: 0, runId: p.runId, loopId: p.loopId, turnId: p.turnId,
|
|
48
|
+
op: p.op, target: { scheme: p.scheme, pathname: p.pathname },
|
|
49
|
+
body: p.tx ?? "", attrs: ProposalHitl.#parseAttrs(p.attrs), flags: {}, staleClobberRisk: false,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
static #parseAttrs(a) {
|
|
53
|
+
if (a === null)
|
|
54
|
+
return {};
|
|
55
|
+
try {
|
|
56
|
+
const v = JSON.parse(a);
|
|
57
|
+
return v !== null && typeof v === "object" ? v : {};
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return {};
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=ProposalHitl.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ProposalHitl.js","sourceRoot":"","sources":["../src/ProposalHitl.ts"],"names":[],"mappings":"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"}
|
package/dist/Server.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Server.d.ts","sourceRoot":"","sources":["../src/Server.ts"],"names":[],"mappings":"AAgBA,MAAM,CAAC,OAAO,OAAO,MAAM;;IAKvB,cAGC;IAEK,MAAM,IAAI,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAMtD;IAEK,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAG3B;CAkLJ"}
|