@junejs/server 1.0.0-dev.13 → 1.0.0-dev.17
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/dist/adapter.d.ts +7 -1
- package/dist/adapter.js +62 -5
- package/dist/agent-compile.d.ts +35 -0
- package/dist/agent-compile.js +139 -0
- package/dist/agent-discover.d.ts +3 -2
- package/dist/agent-discover.js +18 -44
- package/dist/agent-durable.d.ts +12 -2
- package/dist/agent-durable.js +71 -16
- package/dist/agent-native.js +35 -3
- package/dist/build.js +73 -8
- package/dist/client-bundle.js +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/tsconfig-jsx.d.ts +2 -1
- package/dist/tsconfig-jsx.js +1 -1
- package/package.json +13 -3
- package/src/adapter.ts +84 -3
- package/src/agent-compile.ts +245 -0
- package/src/agent-discover.ts +39 -54
- package/src/agent-durable.ts +112 -21
- package/src/agent-native.ts +38 -2
- package/src/build.ts +124 -9
- package/src/index.ts +8 -0
- package/src/tsconfig-jsx.ts +2 -2
package/dist/agent-durable.js
CHANGED
|
@@ -52,6 +52,22 @@ var DoSessionStore = class {
|
|
|
52
52
|
tx(fn) {
|
|
53
53
|
return this.storage.transactionSync(fn);
|
|
54
54
|
}
|
|
55
|
+
reset() {
|
|
56
|
+
return this.storage.transactionSync(() => {
|
|
57
|
+
const sql = this.sql;
|
|
58
|
+
sql.exec(`CREATE TABLE IF NOT EXISTS agent_messages_archive (generation INTEGER, seq INTEGER, body TEXT)`);
|
|
59
|
+
sql.exec(`CREATE TABLE IF NOT EXISTS agent_steps_archive (generation INTEGER, id TEXT, output TEXT)`);
|
|
60
|
+
const rows = this.sql.exec("SELECT v FROM agent_meta WHERE k = 'generation'").toArray();
|
|
61
|
+
const generation = rows.length ? Number(rows[0].v) : 0;
|
|
62
|
+
sql.exec("INSERT INTO agent_messages_archive (generation, seq, body) SELECT ?, seq, body FROM agent_messages", generation);
|
|
63
|
+
sql.exec("DELETE FROM agent_messages");
|
|
64
|
+
sql.exec("INSERT INTO agent_steps_archive (generation, id, output) SELECT ?, id, output FROM agent_steps", generation);
|
|
65
|
+
sql.exec("DELETE FROM agent_steps");
|
|
66
|
+
this.setStatus("new");
|
|
67
|
+
sql.exec("INSERT INTO agent_meta (k, v) VALUES ('generation', ?) ON CONFLICT(k) DO UPDATE SET v = ?", String(generation + 1), String(generation + 1));
|
|
68
|
+
return generation;
|
|
69
|
+
});
|
|
70
|
+
}
|
|
55
71
|
unwrap() {
|
|
56
72
|
return this.sql;
|
|
57
73
|
}
|
|
@@ -83,13 +99,19 @@ var AgentDurableObject = class {
|
|
|
83
99
|
tools;
|
|
84
100
|
channels;
|
|
85
101
|
channelInstructions;
|
|
86
|
-
|
|
102
|
+
resourcesInput;
|
|
103
|
+
resourcesOpened;
|
|
104
|
+
doEnv;
|
|
87
105
|
services;
|
|
106
|
+
resolveResources() {
|
|
107
|
+
return this.resourcesOpened ??= Promise.resolve(typeof this.resourcesInput === "function" ? this.resourcesInput(this.doEnv) : this.resourcesInput ?? {});
|
|
108
|
+
}
|
|
88
109
|
constructor(state, def) {
|
|
89
110
|
assertCoreRuntimeVersion(`AgentDurableObject(${def.name ?? "agent"})`);
|
|
90
111
|
const store = new DoSessionStore(state.storage);
|
|
91
112
|
const model = def.instructions ? withSystem(def.model, def.instructions) : def.model;
|
|
92
|
-
this.
|
|
113
|
+
this.resourcesInput = def.resources;
|
|
114
|
+
this.doEnv = def.env;
|
|
93
115
|
this.services = def.services;
|
|
94
116
|
const name = def.name ?? "agent";
|
|
95
117
|
const sink = new InProcEventSink();
|
|
@@ -146,20 +168,25 @@ var AgentDurableObject = class {
|
|
|
146
168
|
}
|
|
147
169
|
async turn(input) {
|
|
148
170
|
await ensureScope();
|
|
171
|
+
const resources = await this.resolveResources();
|
|
149
172
|
const session = this.resolveSession(input.session);
|
|
150
173
|
return runInScope({
|
|
151
|
-
resources
|
|
174
|
+
resources,
|
|
152
175
|
services: this.services
|
|
153
176
|
}, () => session.turn(input));
|
|
154
177
|
}
|
|
155
178
|
async start(input) {
|
|
156
179
|
await ensureScope();
|
|
180
|
+
const resources = await this.resolveResources();
|
|
157
181
|
const session = this.resolveSession(input.session);
|
|
158
182
|
return runInScope({
|
|
159
|
-
resources
|
|
183
|
+
resources,
|
|
160
184
|
services: this.services
|
|
161
185
|
}, () => session.start(input));
|
|
162
186
|
}
|
|
187
|
+
reset(opts) {
|
|
188
|
+
return this.resolveSession(opts?.session).reset();
|
|
189
|
+
}
|
|
163
190
|
transcript() {
|
|
164
191
|
if (this.session) return this.session.transcript();
|
|
165
192
|
if (this.store.getSessionKey() !== void 0) return this.resolveSession().transcript();
|
|
@@ -171,6 +198,7 @@ var AgentDurableObject = class {
|
|
|
171
198
|
if (req.method === "POST" && url.pathname.endsWith("/turn")) {
|
|
172
199
|
const { userText, turnId, event, trigger } = await req.json();
|
|
173
200
|
await ensureScope();
|
|
201
|
+
const replace = url.searchParams.get("replace") === "1";
|
|
174
202
|
const wantsDeliver = url.searchParams.get("deliver") === "1";
|
|
175
203
|
let deliverChannel;
|
|
176
204
|
if (wantsDeliver) {
|
|
@@ -178,18 +206,20 @@ var AgentDurableObject = class {
|
|
|
178
206
|
deliverChannel = this.channels.find((c) => c.name === event.source);
|
|
179
207
|
if (!deliverChannel?.deliver) return Response.json({ error: `agent "${this.name}": no deliver()-capable channel named "${event.source}" is wired into this DO (DoAgentDef.channels) — the turn was NOT started` }, { status: 501 });
|
|
180
208
|
}
|
|
209
|
+
const resources = await this.resolveResources();
|
|
181
210
|
let session;
|
|
182
211
|
let started;
|
|
183
212
|
try {
|
|
184
213
|
session = this.resolveSession(key);
|
|
185
214
|
started = runInScope({
|
|
186
|
-
resources
|
|
215
|
+
resources,
|
|
187
216
|
services: this.services
|
|
188
217
|
}, () => session.start({
|
|
189
218
|
userText,
|
|
190
219
|
turnId,
|
|
191
220
|
event,
|
|
192
|
-
trigger
|
|
221
|
+
trigger,
|
|
222
|
+
replace
|
|
193
223
|
}));
|
|
194
224
|
} catch (err) {
|
|
195
225
|
return Response.json({ error: err instanceof Error ? err.message : String(err) }, { status: 409 });
|
|
@@ -206,7 +236,7 @@ var AgentDurableObject = class {
|
|
|
206
236
|
recipientTeamId: event.teamId
|
|
207
237
|
};
|
|
208
238
|
Promise.resolve().then(() => runInScope({
|
|
209
|
-
resources
|
|
239
|
+
resources,
|
|
210
240
|
services: this.services
|
|
211
241
|
}, () => deliverChannel.deliver(target, events, { session: this.sessionKey }))).catch(logRenderFailure).finally(() => {
|
|
212
242
|
it.return?.();
|
|
@@ -229,11 +259,12 @@ var AgentDurableObject = class {
|
|
|
229
259
|
resumeChannel = this.channels.find((c) => c.name === source);
|
|
230
260
|
if (!resumeChannel?.deliverResume) return Response.json({ error: `agent "${this.name}": no deliverResume()-capable channel named "${source}" is wired into this DO (DoAgentDef.channels) — the answer was NOT applied` }, { status: 501 });
|
|
231
261
|
}
|
|
262
|
+
const resources = await this.resolveResources();
|
|
232
263
|
let session;
|
|
233
264
|
try {
|
|
234
265
|
session = this.resolveSession(key);
|
|
235
266
|
runInScope({
|
|
236
|
-
resources
|
|
267
|
+
resources,
|
|
237
268
|
services: this.services
|
|
238
269
|
}, () => session.resume(turnId, inputId, input, { by }));
|
|
239
270
|
} catch (err) {
|
|
@@ -246,7 +277,7 @@ var AgentDurableObject = class {
|
|
|
246
277
|
const it = observeTurnEvents(session, turnId)[Symbol.asyncIterator]();
|
|
247
278
|
const events = { [Symbol.asyncIterator]: () => it };
|
|
248
279
|
Promise.resolve().then(() => runInScope({
|
|
249
|
-
resources
|
|
280
|
+
resources,
|
|
250
281
|
services: this.services
|
|
251
282
|
}, () => resumeChannel.deliverResume(target, events, { session: this.sessionKey }))).catch(logRenderFailure).finally(() => {
|
|
252
283
|
it.return?.();
|
|
@@ -258,6 +289,19 @@ var AgentDurableObject = class {
|
|
|
258
289
|
}
|
|
259
290
|
return new Response(sseTurnStream(session, turnId), { headers: SSE_HEADERS });
|
|
260
291
|
}
|
|
292
|
+
if (req.method === "POST" && url.pathname.endsWith("/reset")) {
|
|
293
|
+
let session;
|
|
294
|
+
try {
|
|
295
|
+
session = this.resolveSession(key);
|
|
296
|
+
} catch (err) {
|
|
297
|
+
return Response.json({ error: err instanceof Error ? err.message : String(err) }, { status: 409 });
|
|
298
|
+
}
|
|
299
|
+
try {
|
|
300
|
+
return Response.json(await session.reset());
|
|
301
|
+
} catch (err) {
|
|
302
|
+
return Response.json({ error: err instanceof Error ? err.message : String(err) }, { status: 409 });
|
|
303
|
+
}
|
|
304
|
+
}
|
|
261
305
|
if (url.pathname.endsWith("/transcript")) {
|
|
262
306
|
if (key !== void 0) try {
|
|
263
307
|
return Response.json({ transcript: this.resolveSession(key).transcript() });
|
|
@@ -266,7 +310,7 @@ var AgentDurableObject = class {
|
|
|
266
310
|
}
|
|
267
311
|
return Response.json({ transcript: this.transcript() });
|
|
268
312
|
}
|
|
269
|
-
return new Response("agent DO — POST /turn, POST /resume, or GET /transcript", { status: 404 });
|
|
313
|
+
return new Response("agent DO — POST /turn, POST /resume, POST /reset, or GET /transcript", { status: 404 });
|
|
270
314
|
}
|
|
271
315
|
};
|
|
272
316
|
const SSE_HEADERS = {
|
|
@@ -292,7 +336,7 @@ function sseTurnStream(session, turnId) {
|
|
|
292
336
|
}, 2e4);
|
|
293
337
|
unsub = session.observe((e) => {
|
|
294
338
|
controller.enqueue(enc.encode(`data: ${JSON.stringify(e)}\n\n`));
|
|
295
|
-
if (e.type === "turn.completed" || e.type === "turn.failed" || e.type === "input.requested") {
|
|
339
|
+
if (e.type === "turn.completed" || e.type === "turn.failed" || e.type === "turn.cancelled" || e.type === "input.requested") {
|
|
296
340
|
stop();
|
|
297
341
|
controller.close();
|
|
298
342
|
}
|
|
@@ -309,7 +353,7 @@ function observeTurnEvents(session, turnId) {
|
|
|
309
353
|
let notify;
|
|
310
354
|
const unsub = session.observe((e) => {
|
|
311
355
|
queue.push(e);
|
|
312
|
-
if (e.type === "turn.completed" || e.type === "turn.failed" || e.type === "input.requested") terminal = true;
|
|
356
|
+
if (e.type === "turn.completed" || e.type === "turn.failed" || e.type === "turn.cancelled" || e.type === "input.requested") terminal = true;
|
|
313
357
|
notify?.();
|
|
314
358
|
}, { turnId });
|
|
315
359
|
return { [Symbol.asyncIterator]() {
|
|
@@ -366,6 +410,7 @@ async function sseTurnFinalText(res) {
|
|
|
366
410
|
const e = JSON.parse(line.slice(5).trim());
|
|
367
411
|
if (e.type === "turn.completed") return e.text;
|
|
368
412
|
if (e.type === "turn.failed") throw new Error(e.error.message, { cause: e.error });
|
|
413
|
+
if (e.type === "turn.cancelled") throw new Error(`turn ${e.turnId} was cancelled (${e.reason})`);
|
|
369
414
|
}
|
|
370
415
|
if (done) break;
|
|
371
416
|
}
|
|
@@ -451,7 +496,7 @@ function durableChannelSurface(getNamespace, opts) {
|
|
|
451
496
|
run: async (message, o) => {
|
|
452
497
|
const namespace = getNamespace();
|
|
453
498
|
if (!namespace) throw new Error("durableChannelSurface: no Durable Object namespace bound (env.AGENT)");
|
|
454
|
-
return sseTurnFinalText(await durableFetch(namespace, opts.agentName, o?.session ?? "default", new Request(
|
|
499
|
+
return sseTurnFinalText(await durableFetch(namespace, opts.agentName, o?.session ?? "default", new Request(`https://do/turn${o?.replace ? "?replace=1" : ""}`, {
|
|
455
500
|
method: "POST",
|
|
456
501
|
body: serializeTurn(message, o)
|
|
457
502
|
})));
|
|
@@ -459,7 +504,7 @@ function durableChannelSurface(getNamespace, opts) {
|
|
|
459
504
|
runDetached: async (message, o) => {
|
|
460
505
|
const namespace = getNamespace();
|
|
461
506
|
if (!namespace) throw new Error("durableChannelSurface: no Durable Object namespace bound (env.AGENT)");
|
|
462
|
-
const res = await durableFetch(namespace, opts.agentName, o?.session ?? "default", new Request(
|
|
507
|
+
const res = await durableFetch(namespace, opts.agentName, o?.session ?? "default", new Request(`https://do/turn?detach=1${o?.replace ? "&replace=1" : ""}`, {
|
|
463
508
|
method: "POST",
|
|
464
509
|
body: serializeTurn(message, o)
|
|
465
510
|
}));
|
|
@@ -472,7 +517,7 @@ function durableChannelSurface(getNamespace, opts) {
|
|
|
472
517
|
runDelivered: async (message, o) => {
|
|
473
518
|
const namespace = getNamespace();
|
|
474
519
|
if (!namespace) throw new Error("durableChannelSurface: no Durable Object namespace bound (env.AGENT)");
|
|
475
|
-
const res = await durableFetch(namespace, opts.agentName, o?.session ?? "default", new Request(
|
|
520
|
+
const res = await durableFetch(namespace, opts.agentName, o?.session ?? "default", new Request(`https://do/turn?deliver=1${o?.replace ? "&replace=1" : ""}`, {
|
|
476
521
|
method: "POST",
|
|
477
522
|
body: serializeTurn(message, o)
|
|
478
523
|
}));
|
|
@@ -486,7 +531,7 @@ function durableChannelSurface(getNamespace, opts) {
|
|
|
486
531
|
runStream: async function* (message, o) {
|
|
487
532
|
const namespace = getNamespace();
|
|
488
533
|
if (!namespace) throw new Error("durableChannelSurface: no Durable Object namespace bound (env.AGENT)");
|
|
489
|
-
yield* sseTurnEvents(await durableFetch(namespace, opts.agentName, o?.session ?? "default", new Request(
|
|
534
|
+
yield* sseTurnEvents(await durableFetch(namespace, opts.agentName, o?.session ?? "default", new Request(`https://do/turn${o?.replace ? "?replace=1" : ""}`, {
|
|
490
535
|
method: "POST",
|
|
491
536
|
body: serializeTurn(message, o)
|
|
492
537
|
})));
|
|
@@ -512,6 +557,16 @@ function durableChannelSurface(getNamespace, opts) {
|
|
|
512
557
|
throw new Error(`resumeDelivered: resume was not accepted (status ${res.status}): ${detail}`);
|
|
513
558
|
}
|
|
514
559
|
return await res.json();
|
|
560
|
+
},
|
|
561
|
+
resetSession: async (o) => {
|
|
562
|
+
const namespace = getNamespace();
|
|
563
|
+
if (!namespace) throw new Error("durableChannelSurface: no Durable Object namespace bound (env.AGENT)");
|
|
564
|
+
const res = await durableFetch(namespace, opts.agentName, o?.session ?? "default", new Request("https://do/reset", { method: "POST" }));
|
|
565
|
+
if (!res.ok) {
|
|
566
|
+
const detail = (await res.text()).slice(0, 200);
|
|
567
|
+
throw new Error(`resetSession: reset was not accepted (status ${res.status}): ${detail}`);
|
|
568
|
+
}
|
|
569
|
+
return await res.json();
|
|
515
570
|
}
|
|
516
571
|
});
|
|
517
572
|
}
|
package/dist/agent-native.js
CHANGED
|
@@ -51,6 +51,21 @@ var SqliteSessionStore = class {
|
|
|
51
51
|
throw e;
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
|
+
reset() {
|
|
55
|
+
return this.tx(() => {
|
|
56
|
+
this.db.exec(`CREATE TABLE IF NOT EXISTS agent_messages_archive (session_id TEXT, generation INTEGER, seq INTEGER, body TEXT)`);
|
|
57
|
+
this.db.exec(`CREATE TABLE IF NOT EXISTS agent_steps_archive (session_id TEXT, generation INTEGER, id TEXT, output TEXT)`);
|
|
58
|
+
this.db.exec(`CREATE TABLE IF NOT EXISTS agent_session_generations (session_id TEXT PRIMARY KEY, generation INTEGER)`);
|
|
59
|
+
const generation = this.db.query("SELECT generation FROM agent_session_generations WHERE session_id = ?").get(this.sid)?.generation ?? 0;
|
|
60
|
+
this.db.query("INSERT INTO agent_messages_archive (session_id, generation, seq, body) SELECT session_id, ?, seq, body FROM agent_messages WHERE session_id = ?").run(generation, this.sid);
|
|
61
|
+
this.db.query("DELETE FROM agent_messages WHERE session_id = ?").run(this.sid);
|
|
62
|
+
this.db.query("INSERT INTO agent_steps_archive (session_id, generation, id, output) SELECT session_id, ?, id, output FROM agent_steps WHERE session_id = ?").run(generation, this.sid);
|
|
63
|
+
this.db.query("DELETE FROM agent_steps WHERE session_id = ?").run(this.sid);
|
|
64
|
+
this.db.query("INSERT INTO agent_sessions (session_id, status) VALUES (?, 'new') ON CONFLICT(session_id) DO UPDATE SET status = 'new'").run(this.sid);
|
|
65
|
+
this.db.query("INSERT INTO agent_session_generations (session_id, generation) VALUES (?, ?) ON CONFLICT(session_id) DO UPDATE SET generation = ?").run(this.sid, generation + 1, generation + 1);
|
|
66
|
+
return generation;
|
|
67
|
+
});
|
|
68
|
+
}
|
|
54
69
|
unwrap() {
|
|
55
70
|
return this.db;
|
|
56
71
|
}
|
|
@@ -99,6 +114,8 @@ var MemorySessionStore = class {
|
|
|
99
114
|
msgs = [];
|
|
100
115
|
steps = /* @__PURE__ */ new Map();
|
|
101
116
|
status = "new";
|
|
117
|
+
generation = 0;
|
|
118
|
+
archives = [];
|
|
102
119
|
appendMessage(m) {
|
|
103
120
|
this.msgs.push(m);
|
|
104
121
|
}
|
|
@@ -126,6 +143,18 @@ var MemorySessionStore = class {
|
|
|
126
143
|
tx(fn) {
|
|
127
144
|
return fn();
|
|
128
145
|
}
|
|
146
|
+
reset() {
|
|
147
|
+
const generation = this.generation++;
|
|
148
|
+
this.archives.push({
|
|
149
|
+
generation,
|
|
150
|
+
msgs: this.msgs,
|
|
151
|
+
steps: this.steps
|
|
152
|
+
});
|
|
153
|
+
this.msgs = [];
|
|
154
|
+
this.steps = /* @__PURE__ */ new Map();
|
|
155
|
+
this.status = "new";
|
|
156
|
+
return generation;
|
|
157
|
+
}
|
|
129
158
|
unwrap() {}
|
|
130
159
|
};
|
|
131
160
|
var MemoryRuntime = class {
|
|
@@ -166,14 +195,17 @@ function mountAgent(agent, runtime, opts = {}) {
|
|
|
166
195
|
turnId: o?.turnId,
|
|
167
196
|
userText: message,
|
|
168
197
|
event: o?.event,
|
|
169
|
-
trigger: o?.trigger
|
|
198
|
+
trigger: o?.trigger,
|
|
199
|
+
replace: o?.replace
|
|
170
200
|
}),
|
|
171
201
|
runDetached: async (message, o) => runtime.session(agent.name, o?.session ?? "default").start({
|
|
172
202
|
turnId: o?.turnId,
|
|
173
203
|
userText: message,
|
|
174
204
|
event: o?.event,
|
|
175
|
-
trigger: o?.trigger
|
|
176
|
-
|
|
205
|
+
trigger: o?.trigger,
|
|
206
|
+
replace: o?.replace
|
|
207
|
+
}),
|
|
208
|
+
resetSession: (o) => runtime.session(agent.name, o?.session ?? "default").reset()
|
|
177
209
|
};
|
|
178
210
|
const channels = channelFetch(agent, ctx);
|
|
179
211
|
const surface = async (req) => {
|
package/dist/build.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import { jsxTransform } from "./tsconfig-jsx.js";
|
|
1
2
|
import { deno, staticSite, vercel, workers } from "./adapter.js";
|
|
3
|
+
import { generateAgentModule } from "./agent-compile.js";
|
|
2
4
|
import { findMiddlewareFile } from "./router.js";
|
|
3
5
|
import { resolveBoundary } from "./segment.js";
|
|
4
6
|
import { buildModuleCss, registerCssModules, rolldownCssModulesPlugin } from "./css-modules.js";
|
|
5
|
-
import { jsxTransform } from "./tsconfig-jsx.js";
|
|
6
7
|
import { CLIENT_SCRIPT_URL, bundleClientToFile, findClientEntry } from "./client-bundle.js";
|
|
7
8
|
import { generateIslandRegistry } from "./island-registry.js";
|
|
8
9
|
import { STYLES_URL, cssTargets, findGlobalCss, globalCssUsesTailwind, minifyCss, processCss } from "./css.js";
|
|
@@ -262,6 +263,12 @@ async function buildManifest(appRoot) {
|
|
|
262
263
|
const mod = await import(pathToFileURL(extraFile).href);
|
|
263
264
|
if (typeof mod.default === "function") extra = mod.default;
|
|
264
265
|
}
|
|
266
|
+
let agentName;
|
|
267
|
+
const agentDir = join(appDir, frozen.agent.runtime.dir);
|
|
268
|
+
if (frozen.agent.runtime.enabled && existsSync(agentDir)) {
|
|
269
|
+
const cfgFile = join(agentDir, "agent.ts");
|
|
270
|
+
agentName = (existsSync(cfgFile) ? (await import(pathToFileURL(cfgFile).href)).default : void 0)?.name ?? basename(agentDir);
|
|
271
|
+
}
|
|
265
272
|
return {
|
|
266
273
|
routes,
|
|
267
274
|
dynamicRoutes,
|
|
@@ -271,6 +278,7 @@ async function buildManifest(appRoot) {
|
|
|
271
278
|
loadings,
|
|
272
279
|
document: frozen.document,
|
|
273
280
|
agent: frozen.agent,
|
|
281
|
+
agentName,
|
|
274
282
|
i18n: frozen.i18n,
|
|
275
283
|
earlyHints: frozen.earlyHints,
|
|
276
284
|
extra
|
|
@@ -317,6 +325,24 @@ async function juneBuild(appRoot, options = {}) {
|
|
|
317
325
|
} : void 0 },
|
|
318
326
|
config: fullConfig
|
|
319
327
|
});
|
|
328
|
+
const agentDir = join(appDir, frozen.agent.runtime.dir);
|
|
329
|
+
let agentModule = null;
|
|
330
|
+
if (frozen.agent.runtime.enabled) {
|
|
331
|
+
const generated = generateAgentModule(agentDir);
|
|
332
|
+
if (generated && adapter.capabilities.durableObjects) agentModule = generated;
|
|
333
|
+
else if (generated) console.warn(`[june build] app/${frozen.agent.runtime.dir}/ found, but the ${adapter.name}() target has no Durable Objects — the durable agent is not mounted.`);
|
|
334
|
+
}
|
|
335
|
+
if (agentModule) {
|
|
336
|
+
const sdkResolvable = (fromDir) => {
|
|
337
|
+
for (let d = resolve(fromDir);;) {
|
|
338
|
+
if (existsSync(join(d, "node_modules", "@anthropic-ai", "sdk", "package.json"))) return true;
|
|
339
|
+
const parent = dirname(d);
|
|
340
|
+
if (parent === d) return false;
|
|
341
|
+
d = parent;
|
|
342
|
+
}
|
|
343
|
+
};
|
|
344
|
+
if (!sdkResolvable(appRoot)) throw new Error(`app/${frozen.agent.runtime.dir}/ mounts a durable agent whose model is Claude — add the SDK to the app so it bundles for workerd: bun add @anthropic-ai/sdk`);
|
|
345
|
+
}
|
|
320
346
|
const cssOut = await processCss(appDir, { minify: true });
|
|
321
347
|
let cssAsset = null;
|
|
322
348
|
if (cssOut !== null) {
|
|
@@ -407,7 +433,8 @@ async function juneBuild(appRoot, options = {}) {
|
|
|
407
433
|
imports.push(`import { turso } from "@junejs/server/db";`);
|
|
408
434
|
imports.push(`import { memoizeResources } from "@junejs/server/resources";`);
|
|
409
435
|
} else if (hasResources) imports.push(`import { bindWorkerResources } from "@junejs/server/resources";`);
|
|
410
|
-
const
|
|
436
|
+
const resourcesExpr = tursoDb ? `memoizeResources({ db: turso() })` : hasResources ? `bindWorkerResources(${JSON.stringify(resourceFlags)})` : null;
|
|
437
|
+
const resourcesField = resourcesExpr ? `\n resources: ${resourcesExpr},` : "";
|
|
411
438
|
const dataLayerModule = fullConfig.dataLayer?.module;
|
|
412
439
|
if (dataLayerModule) imports.push(`import { installDataLayer } from ${JSON.stringify(dataLayerModule)};`);
|
|
413
440
|
const dataLayerBoot = dataLayerModule ? "\ninstallDataLayer();\n" : "";
|
|
@@ -417,6 +444,36 @@ async function juneBuild(appRoot, options = {}) {
|
|
|
417
444
|
imports.push(`import { services as __appServices } from ${JSON.stringify(spec)};`);
|
|
418
445
|
}
|
|
419
446
|
const servicesField = servicesModule ? `\n services: __appServices,` : "";
|
|
447
|
+
if (agentModule) {
|
|
448
|
+
imports.push(`import __agentModule from ${JSON.stringify(importPath(genDir, agentModule.file))};`);
|
|
449
|
+
imports.push(`import { assembleDurable } from "@junejs/core/agent-config";`);
|
|
450
|
+
imports.push(`import { anthropic } from "@junejs/core/agent-models";`);
|
|
451
|
+
imports.push(`import { AgentDurableObject } from "@junejs/server/agent-durable";`);
|
|
452
|
+
imports.push(`import { DurableObject } from "cloudflare:workers";`);
|
|
453
|
+
imports.push(`import Anthropic from "@anthropic-ai/sdk";`);
|
|
454
|
+
}
|
|
455
|
+
const agentNameField = agentModule ? `\n agentName: __agentModule.config.name,` : "";
|
|
456
|
+
const doClass = agentModule ? `
|
|
457
|
+
// The durable agent: one Durable Object per session, the compiled agent/
|
|
458
|
+
// directory as its definition — adapted tools (+ read_skill when skills exist),
|
|
459
|
+
// the assembled system prompt, channel factories resolved with the DO's own
|
|
460
|
+
// env, and the app's declared resources opened from THIS isolate's env (lazily,
|
|
461
|
+
// at the first turn — the same ambient db a tool sees in native dev). Model:
|
|
462
|
+
// Anthropic over a statically bundled client (workerd cannot resolve a bare
|
|
463
|
+
// import at runtime), keyed by the ANTHROPIC_API_KEY secret — a missing secret
|
|
464
|
+
// surfaces as the SDK's own clear construction error on the first agent request.
|
|
465
|
+
const __agentDef = assembleDurable(__agentModule);
|
|
466
|
+
export class JuneAgentDO extends DurableObject {
|
|
467
|
+
#agent = new AgentDurableObject(this.ctx, {
|
|
468
|
+
...__agentDef,
|
|
469
|
+
model: anthropic({ model: __agentModule.config.model, client: new Anthropic({ apiKey: (this.env as { ANTHROPIC_API_KEY?: string }).ANTHROPIC_API_KEY }) }),
|
|
470
|
+
env: this.env,${resourcesExpr ? `\n resources: ${resourcesExpr},` : ""}${servicesModule ? "\n services: __appServices(this.env)," : ""}
|
|
471
|
+
});
|
|
472
|
+
fetch(req: Request): Promise<Response> {
|
|
473
|
+
return this.#agent.fetch(req);
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
` : "";
|
|
420
477
|
const entry = `// AUTO-GENERATED by \`june build\` — do not edit. Regenerate: june build .
|
|
421
478
|
${adapterEntry.imports.join("\n")}
|
|
422
479
|
${imports.join("\n")}
|
|
@@ -435,12 +492,12 @@ ${chains.join("\n")}
|
|
|
435
492
|
${loadings.join("\n")}
|
|
436
493
|
},
|
|
437
494
|
document: ${JSON.stringify(frozen.document, null, 2).replace(/\n/g, "\n ")},
|
|
438
|
-
agent: ${JSON.stringify(frozen.agent)},${frozen.i18n ? `\n i18n: ${JSON.stringify(frozen.i18n)},` : ""}
|
|
495
|
+
agent: ${JSON.stringify(frozen.agent)},${agentNameField}${frozen.i18n ? `\n i18n: ${JSON.stringify(frozen.i18n)},` : ""}
|
|
439
496
|
earlyHints: ${JSON.stringify(frozen.earlyHints)},${builtExtraFile ? "\n extra," : ""}${resourcesField}${servicesField}
|
|
440
497
|
});
|
|
441
498
|
|
|
442
499
|
${adapterEntry.wrap("pipeline")}
|
|
443
|
-
`;
|
|
500
|
+
${doClass}`;
|
|
444
501
|
const entryFile = join(genDir, "worker-entry.tsx");
|
|
445
502
|
await writeFile(entryFile, entry);
|
|
446
503
|
const { rolldown } = await import("rolldown");
|
|
@@ -455,6 +512,7 @@ ${adapterEntry.wrap("pipeline")}
|
|
|
455
512
|
plugins: [rolldownCssModulesPlugin(cssModuleMaps)],
|
|
456
513
|
external: (id) => {
|
|
457
514
|
if (isBunSpecifier(id)) return true;
|
|
515
|
+
if (id.startsWith("cloudflare:")) return true;
|
|
458
516
|
if (/\.(wasm|ttf|otf|woff2?|png|jpe?g|avif|webp)$/.test(id)) return true;
|
|
459
517
|
return [...adapter.buildExternal ?? [], ...options.external ?? frozen.buildExternal].some((e) => id === e || id.startsWith(`${e}/`));
|
|
460
518
|
},
|
|
@@ -561,10 +619,16 @@ ${adapterEntry.wrap("pipeline")}
|
|
|
561
619
|
}
|
|
562
620
|
const pkgPath = join(appRoot, "package.json");
|
|
563
621
|
const defaultName = workerName((existsSync(pkgPath) ? JSON.parse(await Bun.file(pkgPath).text()).name : void 0) ?? basename(appRoot));
|
|
564
|
-
const plan =
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
622
|
+
const plan = {
|
|
623
|
+
...resourcesCfg?.db && resourcesCfg.db.kind !== "turso" ? { db: {
|
|
624
|
+
binding: "DB",
|
|
625
|
+
databaseName: `${defaultName}-db`
|
|
626
|
+
} } : {},
|
|
627
|
+
...agentModule ? { agent: {
|
|
628
|
+
binding: "AGENT",
|
|
629
|
+
className: "JuneAgentDO"
|
|
630
|
+
} } : {}
|
|
631
|
+
};
|
|
568
632
|
await adapter.emit({
|
|
569
633
|
appRoot,
|
|
570
634
|
outDir,
|
|
@@ -576,6 +640,7 @@ ${adapterEntry.wrap("pipeline")}
|
|
|
576
640
|
publicFiles
|
|
577
641
|
});
|
|
578
642
|
if (plan.db) console.log(` ↳ d1 binding "${plan.db.binding}" emitted — set database_id in wrangler.jsonc (wrangler d1 create ${plan.db.databaseName})`);
|
|
643
|
+
if (plan.agent) console.log(` ↳ durable agent mounted (${plan.agent.className} → env.${plan.agent.binding}; chat at ${frozen.agent.runtime.chat.path})`);
|
|
579
644
|
return {
|
|
580
645
|
outFile,
|
|
581
646
|
routes: routes.filter((r) => !r.dynamic).map((r) => r.path),
|
package/dist/client-bundle.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { rolldownCssModulesPlugin } from "./css-modules.js";
|
|
2
1
|
import { jsxTransform } from "./tsconfig-jsx.js";
|
|
2
|
+
import { rolldownCssModulesPlugin } from "./css-modules.js";
|
|
3
3
|
import { existsSync } from "node:fs";
|
|
4
4
|
import { mkdir, writeFile } from "node:fs/promises";
|
|
5
5
|
import { dirname, join } from "node:path";
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AdapterCapabilities, AdapterEmitContext, AdapterEntry, JuneAdapter, ResourcePlan, deno, staticSite, vercel, workers } from "./adapter.js";
|
|
2
|
+
import { AGENT_MODULE_FILE, AgentDirScan, emitAgentModule, findAgentDir, generateAgentModule, scanAgentDir } from "./agent-compile.js";
|
|
2
3
|
import { CreateAppOptions, JuneApp, createApp } from "./app.js";
|
|
3
4
|
import { R2Bucket, localBlob, r2 } from "./blob.js";
|
|
4
5
|
import { a as Pipeline, d as createPipeline, n as LayoutComponent, o as PipelineConfig, s as Resolved, u as RouteResolver } from "./pipeline-cCR6MGNK.js";
|
|
@@ -24,4 +25,4 @@ import { Negotiated, negotiate } from "./negotiate.js";
|
|
|
24
25
|
import { blob, currentServices, db, kv } from "@junejs/db";
|
|
25
26
|
import { ServicesConfig, defineServices } from "@junejs/core/config";
|
|
26
27
|
import { I18nConfig, LOCALE_COOKIE, LocaleConfig, LocaleMatch, dirForLang, localeDir, localeHref, matchPinnedLocale, negotiateLocale, parseAcceptLanguage, resolveRequestLocale } from "@junejs/core/i18n";
|
|
27
|
-
export { type AdapterCapabilities, type AdapterEmitContext, type AdapterEntry, type BuildResult, type ContentEntry, type CreateAppOptions, type D1Database, type D1Exec, type DeployResult, type DevServer, type DevServerOptions, type I18nConfig, type JuneAdapter, type JuneApp, type JuneDb, type JuneHost, LOCALE_COOKIE, type LayoutComponent, type LocaleConfig, type LocaleMatch, type MatchOptions, type MigrateResult, type Migration, type Negotiated, type Pipeline, type PipelineConfig, type R2Bucket, type Resolved, type ResourceFlags, type ResourcePlan, type RouteMatch, type RouteResolver, type RouteTreeMatch, type RunResult, type SegmentMatch, type ServeHandle, type ServicesConfig, type SpawnedModule, type WorkerEnv, type WorkerManifest, bindWorkerResources, blob, blockedMessage, buildManifest, classify, collection, createApp, createPipeline, createWorker, currentServices, d1, db, defineServices, deno, dirForLang, entry, freezeConfig, generateContent, host, installAsyncContext, juneBuild, juneDeploy, kv, listRoutes, loadJuneConfig, localBlob, localeDir, localeHref, matchPinnedLocale, matchRoute, matchRouteTree, memoizeResources, memoryKv, migrate, migrateApp, migrateD1, mysql, negotiate, negotiateLocale, parseAcceptLanguage, postgres, r2, readMigrations, redisKv, resolveD1Database, resolveNotFound, resolveRequestLocale, scanRoutes, sqlite, startDevServer, staticSite, turso, typesApp, vercel, workers, wranglerD1 };
|
|
28
|
+
export { AGENT_MODULE_FILE, type AdapterCapabilities, type AdapterEmitContext, type AdapterEntry, type AgentDirScan, type BuildResult, type ContentEntry, type CreateAppOptions, type D1Database, type D1Exec, type DeployResult, type DevServer, type DevServerOptions, type I18nConfig, type JuneAdapter, type JuneApp, type JuneDb, type JuneHost, LOCALE_COOKIE, type LayoutComponent, type LocaleConfig, type LocaleMatch, type MatchOptions, type MigrateResult, type Migration, type Negotiated, type Pipeline, type PipelineConfig, type R2Bucket, type Resolved, type ResourceFlags, type ResourcePlan, type RouteMatch, type RouteResolver, type RouteTreeMatch, type RunResult, type SegmentMatch, type ServeHandle, type ServicesConfig, type SpawnedModule, type WorkerEnv, type WorkerManifest, bindWorkerResources, blob, blockedMessage, buildManifest, classify, collection, createApp, createPipeline, createWorker, currentServices, d1, db, defineServices, deno, dirForLang, emitAgentModule, entry, findAgentDir, freezeConfig, generateAgentModule, generateContent, host, installAsyncContext, juneBuild, juneDeploy, kv, listRoutes, loadJuneConfig, localBlob, localeDir, localeHref, matchPinnedLocale, matchRoute, matchRouteTree, memoizeResources, memoryKv, migrate, migrateApp, migrateD1, mysql, negotiate, negotiateLocale, parseAcceptLanguage, postgres, r2, readMigrations, redisKv, resolveD1Database, resolveNotFound, resolveRequestLocale, scanAgentDir, scanRoutes, sqlite, startDevServer, staticSite, turso, typesApp, vercel, workers, wranglerD1 };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { deno, staticSite, vercel, workers } from "./adapter.js";
|
|
2
|
+
import { AGENT_MODULE_FILE, emitAgentModule, findAgentDir, generateAgentModule, scanAgentDir } from "./agent-compile.js";
|
|
2
3
|
import { listRoutes, matchRoute, matchRouteTree, resolveNotFound } from "./router.js";
|
|
3
4
|
import { negotiate } from "./negotiate.js";
|
|
4
5
|
import { createPipeline } from "./pipeline.js";
|
|
@@ -24,4 +25,4 @@ import { memoryKv, redisKv } from "./kv.js";
|
|
|
24
25
|
import { blob, currentServices, db, kv } from "@junejs/db";
|
|
25
26
|
import { defineServices } from "@junejs/core/config";
|
|
26
27
|
import { LOCALE_COOKIE, dirForLang, localeDir, localeHref, matchPinnedLocale, negotiateLocale, parseAcceptLanguage, resolveRequestLocale } from "@junejs/core/i18n";
|
|
27
|
-
export { LOCALE_COOKIE, bindWorkerResources, blob, blockedMessage, buildManifest, classify, collection, createApp, createPipeline, createWorker, currentServices, d1, db, defineServices, deno, dirForLang, entry, freezeConfig, generateContent, host, installAsyncContext, juneBuild, juneDeploy, kv, listRoutes, loadJuneConfig, localBlob, localeDir, localeHref, matchPinnedLocale, matchRoute, matchRouteTree, memoizeResources, memoryKv, migrate, migrateApp, migrateD1, mysql, negotiate, negotiateLocale, parseAcceptLanguage, postgres, r2, readMigrations, redisKv, resolveD1Database, resolveNotFound, resolveRequestLocale, scanRoutes, sqlite, startDevServer, staticSite, turso, typesApp, vercel, workers, wranglerD1 };
|
|
28
|
+
export { AGENT_MODULE_FILE, LOCALE_COOKIE, bindWorkerResources, blob, blockedMessage, buildManifest, classify, collection, createApp, createPipeline, createWorker, currentServices, d1, db, defineServices, deno, dirForLang, emitAgentModule, entry, findAgentDir, freezeConfig, generateAgentModule, generateContent, host, installAsyncContext, juneBuild, juneDeploy, kv, listRoutes, loadJuneConfig, localBlob, localeDir, localeHref, matchPinnedLocale, matchRoute, matchRouteTree, memoizeResources, memoryKv, migrate, migrateApp, migrateD1, mysql, negotiate, negotiateLocale, parseAcceptLanguage, postgres, r2, readMigrations, redisKv, resolveD1Database, resolveNotFound, resolveRequestLocale, scanAgentDir, scanRoutes, sqlite, startDevServer, staticSite, turso, typesApp, vercel, workers, wranglerD1 };
|
package/dist/tsconfig-jsx.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
//#region src/tsconfig-jsx.d.ts
|
|
2
|
+
declare const stripJsonc: (s: string) => string;
|
|
2
3
|
/** Read the app's tsconfig.json and return compilerOptions.jsxImportSource.
|
|
3
4
|
* Follows one level of `extends` so apps that inherit from a base tsconfig
|
|
4
5
|
* (e.g. "@kurajs/docs/tsconfig.kura.json") are handled correctly.
|
|
@@ -12,4 +13,4 @@ declare function jsxTransform(appRoot: string): Promise<{
|
|
|
12
13
|
importSource?: string;
|
|
13
14
|
}>;
|
|
14
15
|
//#endregion
|
|
15
|
-
export { appJsxImportSource, jsxTransform };
|
|
16
|
+
export { appJsxImportSource, jsxTransform, stripJsonc };
|
package/dist/tsconfig-jsx.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@junejs/server",
|
|
3
|
-
"version": "1.0.0-dev.
|
|
3
|
+
"version": "1.0.0-dev.17",
|
|
4
4
|
"description": "June host adapters + dev server. Host-coupled; depends on the pure @junejs/core contract layer.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -36,6 +36,12 @@
|
|
|
36
36
|
"types": "./dist/agent-discover.d.ts",
|
|
37
37
|
"default": "./dist/agent-discover.js"
|
|
38
38
|
},
|
|
39
|
+
"./agent-compile": {
|
|
40
|
+
"source": "./src/agent-compile.ts",
|
|
41
|
+
"bun": "./src/agent-compile.ts",
|
|
42
|
+
"types": "./dist/agent-compile.d.ts",
|
|
43
|
+
"default": "./dist/agent-compile.js"
|
|
44
|
+
},
|
|
39
45
|
"./db": {
|
|
40
46
|
"source": "./src/db.ts",
|
|
41
47
|
"bun": "./src/db.ts",
|
|
@@ -132,13 +138,14 @@
|
|
|
132
138
|
"rolldown": "^1.1.0"
|
|
133
139
|
},
|
|
134
140
|
"peerDependencies": {
|
|
135
|
-
"@junejs/core": ">=0.2.0-dev.
|
|
141
|
+
"@junejs/core": ">=0.2.0-dev.33",
|
|
136
142
|
"react": "^19.2.0",
|
|
137
143
|
"react-dom": "^19.2.0",
|
|
138
144
|
"react-server-dom-webpack": "19.2.7",
|
|
139
145
|
"pg": "^8.0.0",
|
|
140
146
|
"mysql2": "^3.0.0",
|
|
141
|
-
"@libsql/client": "^0.14.0 || ^0.15.0 || ^0.16.0 || ^0.17.0"
|
|
147
|
+
"@libsql/client": "^0.14.0 || ^0.15.0 || ^0.16.0 || ^0.17.0",
|
|
148
|
+
"@anthropic-ai/sdk": ">=0.60.0"
|
|
142
149
|
},
|
|
143
150
|
"peerDependenciesMeta": {
|
|
144
151
|
"react-server-dom-webpack": {
|
|
@@ -152,6 +159,9 @@
|
|
|
152
159
|
},
|
|
153
160
|
"@libsql/client": {
|
|
154
161
|
"optional": true
|
|
162
|
+
},
|
|
163
|
+
"@anthropic-ai/sdk": {
|
|
164
|
+
"optional": true
|
|
155
165
|
}
|
|
156
166
|
},
|
|
157
167
|
"repository": {
|