@junejs/server 0.1.2 → 0.2.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/assets/icon-latin.LICENSE.txt +92 -0
- package/assets/icon-latin.ttf +0 -0
- package/dist/adapter-DcZ-W1-7.d.ts +62 -0
- package/dist/adapter.d.ts +2 -56
- package/dist/adapter.js +62 -5
- package/dist/agent-compile.d.ts +38 -0
- package/dist/agent-compile.js +145 -0
- package/dist/agent-discover.d.ts +4 -4
- package/dist/agent-discover.js +30 -44
- package/dist/agent-durable.d.ts +94 -19
- package/dist/agent-durable.js +647 -32
- package/dist/agent-native.d.ts +44 -13
- package/dist/agent-native.js +264 -27
- package/dist/app.d.ts +5 -5
- package/dist/app.js +42 -10
- package/dist/blob.d.ts +4 -5
- package/dist/build.d.ts +8 -29
- package/dist/build.js +138 -289
- package/dist/client-bundle.d.ts +8 -9
- package/dist/client-bundle.js +1 -1
- package/dist/config-freeze-CyXvNqi2.d.ts +17 -0
- package/dist/config-freeze.d.ts +2 -0
- package/dist/config-freeze.js +54 -0
- package/dist/config-loader.d.ts +3 -4
- package/dist/connection-auth.d.ts +38 -0
- package/dist/connection-auth.js +31 -0
- package/dist/content-freeze-CyiW2fRK.d.ts +4 -0
- package/dist/content-freeze.d.ts +2 -0
- package/dist/content-freeze.js +83 -0
- package/dist/content.d.ts +22 -9
- package/dist/content.js +43 -3
- package/dist/core-version.d.ts +4 -0
- package/dist/core-version.js +12 -0
- package/dist/css-modules-ambient.d.ts +2 -1
- package/dist/css-modules.d.ts +10 -11
- package/dist/css.d.ts +9 -10
- package/dist/d1-migrate.d.ts +6 -7
- package/dist/d1-migrate.js +3 -2
- package/dist/db.d.ts +2 -2
- package/dist/deploy.d.ts +3 -4
- package/dist/deploy.js +3 -2
- package/dist/dev-reload.d.ts +3 -4
- package/dist/dev.d.ts +8 -5
- package/dist/dev.js +40 -9
- package/dist/favicon.d.ts +37 -0
- package/dist/favicon.js +248 -0
- package/dist/host.d.ts +6 -5
- package/dist/host.js +2 -1
- package/dist/icon-letter.d.ts +3 -0
- package/dist/icon-letter.js +8 -0
- package/dist/index.d.ts +11 -5
- package/dist/index.js +9 -3
- package/dist/instrumentation.d.ts +2 -3
- package/dist/instrumentation.js +2 -1
- package/dist/island-registry.d.ts +6 -7
- package/dist/isolate-local.d.ts +5 -0
- package/dist/isolate-local.js +12 -0
- package/dist/kv.d.ts +3 -4
- package/dist/llms-links.d.ts +9 -0
- package/dist/llms-links.js +65 -0
- package/dist/manifest-CwTT1zVs.d.ts +11 -0
- package/dist/manifest.d.ts +2 -0
- package/dist/manifest.js +113 -0
- package/dist/negotiate.d.ts +4 -3
- package/dist/negotiate.js +24 -14
- package/dist/{pipeline-CCp9idQ4.d.ts → pipeline-BHUjBO0G.d.ts} +13 -1
- package/dist/pipeline.d.ts +2 -2
- package/dist/pipeline.js +286 -35
- package/dist/resources.d.ts +5 -6
- package/dist/route-rank.d.ts +10 -0
- package/dist/route-rank.js +38 -0
- package/dist/route-scan-BMbBzPIB.d.ts +20 -0
- package/dist/route-scan.d.ts +2 -0
- package/dist/route-scan.js +100 -0
- package/dist/router.d.ts +12 -13
- package/dist/router.js +58 -44
- package/dist/rsc-build.d.ts +6 -7
- package/dist/rsc-bundle.d.ts +6 -7
- package/dist/rsc-manifest.d.ts +5 -6
- package/dist/rsc-runtime/flight-render-routes.d.ts +3 -4
- package/dist/rsc-runtime/flight-render.d.ts +2 -3
- package/dist/rsc-runtime/flight-to-html.d.ts +2 -3
- package/dist/rsc-runtime/flight-to-html.js +3 -2
- package/dist/rsc-runtime/rsc-worker.js +11 -8
- package/dist/rsc-runtime/rsdw-shims.d.ts +2 -1
- package/dist/segment.d.ts +4 -5
- package/dist/sqlite-driver.d.ts +11 -11
- package/dist/sqlite-driver.js +17 -4
- package/dist/static-files.d.ts +4 -5
- package/dist/tsconfig-jsx.d.ts +4 -4
- package/dist/tsconfig-jsx.js +1 -1
- package/dist/turn-events.d.ts +4 -0
- package/dist/turn-events.js +46 -0
- package/dist/web-manifest.d.ts +5 -0
- package/dist/web-manifest.js +42 -0
- package/dist/worker-2qbQjj2c.d.ts +64 -0
- package/dist/worker.d.ts +2 -56
- package/dist/worker.js +121 -103
- package/package.json +22 -9
- package/src/adapter.ts +84 -3
- package/src/agent-compile.ts +271 -0
- package/src/agent-discover.ts +77 -63
- package/src/agent-durable.ts +998 -30
- package/src/agent-native.ts +370 -35
- package/src/app.ts +75 -6
- package/src/build.ts +237 -444
- package/src/config-freeze.ts +109 -0
- package/src/connection-auth.ts +101 -0
- package/src/content-freeze.ts +151 -0
- package/src/content.ts +55 -4
- package/src/core-version.ts +34 -0
- package/src/dev.ts +41 -8
- package/src/favicon.ts +325 -0
- package/src/host.ts +4 -3
- package/src/icon-letter.ts +14 -0
- package/src/index.ts +22 -0
- package/src/isolate-local.ts +33 -0
- package/src/llms-links.ts +96 -0
- package/src/manifest.ts +130 -0
- package/src/negotiate.ts +39 -15
- package/src/pipeline.ts +494 -44
- package/src/route-rank.ts +60 -0
- package/src/route-scan.ts +161 -0
- package/src/router.ts +75 -58
- package/src/rsc-runtime/rsc-worker.tsx +5 -4
- package/src/sqlite-driver.ts +36 -6
- package/src/tsconfig-jsx.ts +2 -2
- package/src/turn-events.ts +43 -0
- package/src/web-manifest.ts +38 -0
- package/src/worker.ts +197 -117
package/dist/agent-native.d.ts
CHANGED
|
@@ -1,40 +1,71 @@
|
|
|
1
1
|
import { SyncSqlite } from "./sqlite-driver.js";
|
|
2
2
|
import { AgentDefinition, ChannelContext } from "@junejs/core/agent-config";
|
|
3
|
-
import { AgentSession, Model, Runtime, Tool } from "@junejs/core/agent-runtime";
|
|
3
|
+
import { AgentSession, ChannelPolicy, InputAnnouncement, Model, Runtime, Tool } from "@junejs/core/agent-runtime";
|
|
4
|
+
import { FileStore } from "@junejs/core/agent-files";
|
|
4
5
|
//#region src/agent-native.d.ts
|
|
5
|
-
type AgentDef = {
|
|
6
|
+
export type AgentDef = {
|
|
6
7
|
model: Model;
|
|
7
8
|
tools: Tool[];
|
|
8
9
|
instructions?: string;
|
|
10
|
+
channelInstructions?: Record<string, string | ChannelPolicy>;
|
|
11
|
+
onInputAnnouncement?: (a: InputAnnouncement) => void | Promise<void>;
|
|
9
12
|
};
|
|
10
|
-
declare
|
|
13
|
+
export declare function toAgentDef(agent: AgentDefinition, model: Model): AgentDef;
|
|
14
|
+
export type NativeRuntimeOptions = {
|
|
15
|
+
maxSessions?: number;
|
|
16
|
+
files?: FileStore;
|
|
17
|
+
};
|
|
18
|
+
export declare class NativeRuntime implements Runtime {
|
|
11
19
|
private actors;
|
|
12
20
|
private readonly agents;
|
|
13
21
|
private readonly db;
|
|
14
|
-
|
|
22
|
+
private readonly announceRetry;
|
|
23
|
+
private readonly maxSessions;
|
|
24
|
+
private closing;
|
|
25
|
+
readonly files: FileStore | undefined;
|
|
26
|
+
constructor(agents: Record<string, AgentDef>, db: SyncSqlite, opts?: NativeRuntimeOptions);
|
|
27
|
+
agentDef(name: string): AgentDef | undefined;
|
|
15
28
|
session(agent: string, id: string): AgentSession;
|
|
29
|
+
get sessionCount(): number;
|
|
30
|
+
recoverAnnouncements(): void;
|
|
31
|
+
close(): Promise<void>;
|
|
32
|
+
private evictIdle;
|
|
16
33
|
}
|
|
17
|
-
declare function createNativeRuntime(agents: Record<string, AgentDef>, path?: string): Promise<NativeRuntime>;
|
|
18
|
-
declare class MemoryRuntime implements Runtime {
|
|
34
|
+
export declare function createNativeRuntime(agents: Record<string, AgentDef>, path?: string, opts?: NativeRuntimeOptions): Promise<NativeRuntime>;
|
|
35
|
+
export declare class MemoryRuntime implements Runtime {
|
|
19
36
|
private actors;
|
|
20
37
|
private stores;
|
|
21
38
|
private readonly agents;
|
|
22
|
-
|
|
39
|
+
private readonly announceRetry;
|
|
40
|
+
private closed;
|
|
41
|
+
readonly files: FileStore | undefined;
|
|
42
|
+
constructor(agents: Record<string, AgentDef>, opts?: {
|
|
43
|
+
files?: FileStore;
|
|
44
|
+
});
|
|
45
|
+
agentDef(name: string): AgentDef | undefined;
|
|
23
46
|
session(agent: string, id: string): AgentSession;
|
|
47
|
+
close(): Promise<void>;
|
|
24
48
|
}
|
|
25
|
-
type AgentBackend = "native" | "memory" | "durable";
|
|
26
|
-
|
|
49
|
+
export type AgentBackend = "native" | "memory" | "durable";
|
|
50
|
+
export type InProcessRuntime = Runtime & {
|
|
51
|
+
close(): Promise<void>;
|
|
52
|
+
readonly files?: FileStore;
|
|
53
|
+
};
|
|
54
|
+
export declare function createAgentRuntime(agents: Record<string, AgentDef>, opts?: {
|
|
27
55
|
backend?: AgentBackend;
|
|
28
56
|
path?: string;
|
|
29
|
-
|
|
30
|
-
|
|
57
|
+
maxSessions?: number;
|
|
58
|
+
files?: FileStore;
|
|
59
|
+
}): Promise<InProcessRuntime>;
|
|
60
|
+
export declare function mountAgent(agent: AgentDefinition, runtime: Runtime, opts?: {
|
|
31
61
|
chatPath?: string;
|
|
32
62
|
channels?: boolean;
|
|
63
|
+
services?: unknown;
|
|
64
|
+
files?: FileStore;
|
|
33
65
|
}): {
|
|
34
66
|
surface: (req: Request) => Promise<Response | null>;
|
|
35
67
|
fetch: (req: Request) => Promise<Response | null>;
|
|
36
68
|
startAll: () => Promise<void>;
|
|
37
69
|
ctx: ChannelContext;
|
|
38
70
|
};
|
|
39
|
-
//#endregion
|
|
40
|
-
export { AgentBackend, AgentDef, MemoryRuntime, NativeRuntime, createAgentRuntime, createNativeRuntime, mountAgent };
|
|
71
|
+
//#endregion
|
package/dist/agent-native.js
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
|
+
import { observeTurnEvents } from "./turn-events.js";
|
|
2
|
+
import { assertCoreRuntimeVersion } from "./core-version.js";
|
|
1
3
|
import { openLocalSqliteSync } from "./sqlite-driver.js";
|
|
2
|
-
import { channelFetch } from "@junejs/core/agent-config";
|
|
3
|
-
import { AgentSession, withSystem } from "@junejs/core/agent-runtime";
|
|
4
|
+
import { buildSystemPrompt, channelFetch } from "@junejs/core/agent-config";
|
|
5
|
+
import { AgentSession, grantAnswer, withSystem } from "@junejs/core/agent-runtime";
|
|
4
6
|
//#region src/agent-native.ts
|
|
5
7
|
function initSchema(db) {
|
|
6
8
|
db.exec(`CREATE TABLE IF NOT EXISTS agent_sessions (session_id TEXT PRIMARY KEY, status TEXT)`);
|
|
7
9
|
db.exec(`CREATE TABLE IF NOT EXISTS agent_messages (seq INTEGER PRIMARY KEY AUTOINCREMENT, session_id TEXT, body TEXT)`);
|
|
10
|
+
db.exec(`CREATE INDEX IF NOT EXISTS agent_messages_session ON agent_messages (session_id, seq)`);
|
|
8
11
|
db.exec(`CREATE TABLE IF NOT EXISTS agent_steps (session_id TEXT, id TEXT, output TEXT, PRIMARY KEY (session_id, id))`);
|
|
9
12
|
}
|
|
10
13
|
var SqliteSessionStore = class {
|
|
@@ -20,8 +23,8 @@ var SqliteSessionStore = class {
|
|
|
20
23
|
messages() {
|
|
21
24
|
return this.db.query("SELECT body FROM agent_messages WHERE session_id = ? ORDER BY seq").all(this.sid).map((r) => JSON.parse(r.body));
|
|
22
25
|
}
|
|
23
|
-
|
|
24
|
-
return this.
|
|
26
|
+
hasOpeningMessage(turnId) {
|
|
27
|
+
return this.db.query("SELECT 1 FROM agent_messages WHERE session_id = ? AND json_extract(body, '$.turnId') = ? AND json_extract(body, '$.role') IN ('user', 'trigger') LIMIT 1").get(this.sid, turnId) != null;
|
|
25
28
|
}
|
|
26
29
|
getStep(id) {
|
|
27
30
|
const r = this.db.query("SELECT output FROM agent_steps WHERE session_id = ? AND id = ?").get(this.sid, id);
|
|
@@ -30,6 +33,9 @@ var SqliteSessionStore = class {
|
|
|
30
33
|
putStep(id, output) {
|
|
31
34
|
this.db.query("INSERT INTO agent_steps (session_id, id, output) VALUES (?, ?, ?)").run(this.sid, id, JSON.stringify(output));
|
|
32
35
|
}
|
|
36
|
+
delStep(id) {
|
|
37
|
+
this.db.query("DELETE FROM agent_steps WHERE session_id = ? AND id = ?").run(this.sid, id);
|
|
38
|
+
}
|
|
33
39
|
getStatus() {
|
|
34
40
|
return this.db.query("SELECT status FROM agent_sessions WHERE session_id = ?").get(this.sid)?.status ?? "new";
|
|
35
41
|
}
|
|
@@ -47,16 +53,32 @@ var SqliteSessionStore = class {
|
|
|
47
53
|
throw e;
|
|
48
54
|
}
|
|
49
55
|
}
|
|
56
|
+
reset(inTx) {
|
|
57
|
+
return this.tx(() => {
|
|
58
|
+
this.db.exec(`CREATE TABLE IF NOT EXISTS agent_messages_archive (session_id TEXT, generation INTEGER, seq INTEGER, body TEXT)`);
|
|
59
|
+
this.db.exec(`CREATE TABLE IF NOT EXISTS agent_steps_archive (session_id TEXT, generation INTEGER, id TEXT, output TEXT)`);
|
|
60
|
+
this.db.exec(`CREATE TABLE IF NOT EXISTS agent_session_generations (session_id TEXT PRIMARY KEY, generation INTEGER)`);
|
|
61
|
+
const generation = this.db.query("SELECT generation FROM agent_session_generations WHERE session_id = ?").get(this.sid)?.generation ?? 0;
|
|
62
|
+
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);
|
|
63
|
+
this.db.query("DELETE FROM agent_messages WHERE session_id = ?").run(this.sid);
|
|
64
|
+
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);
|
|
65
|
+
this.db.query("DELETE FROM agent_steps WHERE session_id = ?").run(this.sid);
|
|
66
|
+
this.db.query("INSERT INTO agent_sessions (session_id, status) VALUES (?, 'new') ON CONFLICT(session_id) DO UPDATE SET status = 'new'").run(this.sid);
|
|
67
|
+
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);
|
|
68
|
+
inTx?.();
|
|
69
|
+
return generation;
|
|
70
|
+
});
|
|
71
|
+
}
|
|
50
72
|
unwrap() {
|
|
51
73
|
return this.db;
|
|
52
74
|
}
|
|
53
75
|
};
|
|
54
|
-
var
|
|
76
|
+
var InProcEventSink = class {
|
|
55
77
|
subs = /* @__PURE__ */ new Set();
|
|
56
|
-
|
|
78
|
+
emit(e) {
|
|
57
79
|
this.subs.forEach((cb) => {
|
|
58
80
|
try {
|
|
59
|
-
cb(
|
|
81
|
+
cb(e);
|
|
60
82
|
} catch {}
|
|
61
83
|
});
|
|
62
84
|
}
|
|
@@ -64,44 +86,176 @@ var InProcBroadcaster = class {
|
|
|
64
86
|
this.subs.add(cb);
|
|
65
87
|
return () => this.subs.delete(cb);
|
|
66
88
|
}
|
|
89
|
+
get size() {
|
|
90
|
+
return this.subs.size;
|
|
91
|
+
}
|
|
67
92
|
};
|
|
93
|
+
var AnnouncementRetry = class {
|
|
94
|
+
flush;
|
|
95
|
+
state = /* @__PURE__ */ new Map();
|
|
96
|
+
stopped = false;
|
|
97
|
+
constructor(flush) {
|
|
98
|
+
this.flush = flush;
|
|
99
|
+
}
|
|
100
|
+
delivered(key) {
|
|
101
|
+
const s = this.state.get(key);
|
|
102
|
+
if (s?.timer) clearTimeout(s.timer);
|
|
103
|
+
this.state.delete(key);
|
|
104
|
+
}
|
|
105
|
+
failed(key, agent, id) {
|
|
106
|
+
if (this.stopped) return;
|
|
107
|
+
const s = this.state.get(key) ?? { failures: 0 };
|
|
108
|
+
this.state.set(key, s);
|
|
109
|
+
if (s.timer) return;
|
|
110
|
+
const delay = Math.min(5e3 * 2 ** s.failures, 3e5);
|
|
111
|
+
s.failures++;
|
|
112
|
+
s.timer = setTimeout(() => {
|
|
113
|
+
s.timer = void 0;
|
|
114
|
+
this.flush(agent, id);
|
|
115
|
+
}, delay);
|
|
116
|
+
s.timer.unref?.();
|
|
117
|
+
}
|
|
118
|
+
stop() {
|
|
119
|
+
this.stopped = true;
|
|
120
|
+
for (const s of this.state.values()) if (s.timer) clearTimeout(s.timer);
|
|
121
|
+
this.state.clear();
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
const ownedDbs = /* @__PURE__ */ new WeakSet();
|
|
125
|
+
function wireAnnouncements(session, def, retry) {
|
|
126
|
+
const hook = def.onInputAnnouncement;
|
|
127
|
+
if (hook) {
|
|
128
|
+
const key = `${session.agent}:${session.id}`;
|
|
129
|
+
session.onAnnounce = async (a) => {
|
|
130
|
+
try {
|
|
131
|
+
await hook(a);
|
|
132
|
+
} catch (err) {
|
|
133
|
+
retry.failed(key, session.agent, session.id);
|
|
134
|
+
throw err;
|
|
135
|
+
}
|
|
136
|
+
retry.delivered(key);
|
|
137
|
+
};
|
|
138
|
+
session.flushAnnouncements();
|
|
139
|
+
}
|
|
140
|
+
return session;
|
|
141
|
+
}
|
|
142
|
+
const ANNOUNCE_OUTBOX_STEP = "announce-outbox";
|
|
143
|
+
function toAgentDef(agent, model) {
|
|
144
|
+
return {
|
|
145
|
+
model,
|
|
146
|
+
tools: agent.tools,
|
|
147
|
+
instructions: buildSystemPrompt(agent),
|
|
148
|
+
...agent.channelInstructions ? { channelInstructions: agent.channelInstructions } : {},
|
|
149
|
+
...agent.onInputAnnouncement ? { onInputAnnouncement: agent.onInputAnnouncement } : {}
|
|
150
|
+
};
|
|
151
|
+
}
|
|
68
152
|
var NativeRuntime = class {
|
|
69
153
|
actors = /* @__PURE__ */ new Map();
|
|
70
154
|
agents;
|
|
71
155
|
db;
|
|
72
|
-
|
|
156
|
+
announceRetry = new AnnouncementRetry((agent, id) => {
|
|
157
|
+
this.session(agent, id).flushAnnouncements();
|
|
158
|
+
});
|
|
159
|
+
maxSessions;
|
|
160
|
+
closing;
|
|
161
|
+
files;
|
|
162
|
+
constructor(agents, db, opts = {}) {
|
|
163
|
+
assertCoreRuntimeVersion("NativeRuntime");
|
|
73
164
|
this.agents = agents;
|
|
74
165
|
this.db = db;
|
|
166
|
+
this.files = opts.files;
|
|
167
|
+
const max = opts.maxSessions ?? 1e3;
|
|
168
|
+
if (!(Number.isInteger(max) && max >= 1) && max !== Infinity) throw new RangeError(`NativeRuntime: maxSessions must be an integer >= 1 (or Infinity for no cap), got ${max}`);
|
|
169
|
+
this.maxSessions = max;
|
|
75
170
|
initSchema(db);
|
|
76
171
|
}
|
|
172
|
+
agentDef(name) {
|
|
173
|
+
return this.agents[name];
|
|
174
|
+
}
|
|
77
175
|
session(agent, id) {
|
|
78
176
|
const key = `${agent}:${id}`;
|
|
79
|
-
|
|
80
|
-
if (!
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
177
|
+
const hit = this.actors.get(key);
|
|
178
|
+
if (!hit && this.closing) throw new Error(`NativeRuntime is closed: cannot open session "${key}"`);
|
|
179
|
+
if (hit) {
|
|
180
|
+
this.actors.delete(key);
|
|
181
|
+
this.actors.set(key, hit);
|
|
182
|
+
return hit.session;
|
|
183
|
+
}
|
|
184
|
+
const def = this.agents[agent];
|
|
185
|
+
if (!def) throw new Error(`unknown agent: ${agent}`);
|
|
186
|
+
const model = def.instructions ? withSystem(def.model, def.instructions) : def.model;
|
|
187
|
+
const sink = new InProcEventSink();
|
|
188
|
+
const built = new AgentSession(agent, id, new SqliteSessionStore(this.db, key), sink, model, def.tools, this, def.channelInstructions);
|
|
189
|
+
built.files = this.files;
|
|
190
|
+
const session = wireAnnouncements(built, def, this.announceRetry);
|
|
191
|
+
this.evictIdle();
|
|
192
|
+
this.actors.set(key, {
|
|
193
|
+
session,
|
|
194
|
+
sink
|
|
195
|
+
});
|
|
196
|
+
return session;
|
|
197
|
+
}
|
|
198
|
+
get sessionCount() {
|
|
199
|
+
return this.actors.size;
|
|
200
|
+
}
|
|
201
|
+
recoverAnnouncements() {
|
|
202
|
+
const rows = this.db.query("SELECT output FROM agent_steps WHERE id = ?").all(ANNOUNCE_OUTBOX_STEP);
|
|
203
|
+
for (const { output } of rows) {
|
|
204
|
+
const [first] = JSON.parse(output);
|
|
205
|
+
if (first && this.agents[first.agent]?.onInputAnnouncement) this.session(first.agent, first.session);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
close() {
|
|
209
|
+
this.closing ??= (async () => {
|
|
210
|
+
this.announceRetry.stop();
|
|
211
|
+
while ([...this.actors.values()].some((a) => !a.session.idle())) await new Promise((r) => setTimeout(r, 10));
|
|
212
|
+
this.actors.clear();
|
|
213
|
+
if (ownedDbs.has(this.db)) {
|
|
214
|
+
ownedDbs.delete(this.db);
|
|
215
|
+
this.db.close();
|
|
216
|
+
}
|
|
217
|
+
})();
|
|
218
|
+
return this.closing;
|
|
219
|
+
}
|
|
220
|
+
evictIdle() {
|
|
221
|
+
if (this.actors.size < this.maxSessions) return;
|
|
222
|
+
for (const [key, a] of this.actors) {
|
|
223
|
+
if (this.actors.size < this.maxSessions) break;
|
|
224
|
+
if (a.session.idle() && a.sink.size === 0) this.actors.delete(key);
|
|
86
225
|
}
|
|
87
|
-
return a;
|
|
88
226
|
}
|
|
89
227
|
};
|
|
90
|
-
async function createNativeRuntime(agents, path = ":memory:") {
|
|
91
|
-
|
|
228
|
+
async function createNativeRuntime(agents, path = ":memory:", opts = {}) {
|
|
229
|
+
const db = await openLocalSqliteSync(path);
|
|
230
|
+
ownedDbs.add(db);
|
|
231
|
+
let runtime;
|
|
232
|
+
try {
|
|
233
|
+
runtime = new NativeRuntime(agents, db, opts);
|
|
234
|
+
runtime.recoverAnnouncements();
|
|
235
|
+
return runtime;
|
|
236
|
+
} catch (err) {
|
|
237
|
+
if (runtime) await runtime.close();
|
|
238
|
+
else {
|
|
239
|
+
ownedDbs.delete(db);
|
|
240
|
+
db.close();
|
|
241
|
+
}
|
|
242
|
+
throw err;
|
|
243
|
+
}
|
|
92
244
|
}
|
|
93
245
|
var MemorySessionStore = class {
|
|
94
246
|
msgs = [];
|
|
95
247
|
steps = /* @__PURE__ */ new Map();
|
|
96
248
|
status = "new";
|
|
249
|
+
generation = 0;
|
|
250
|
+
archives = [];
|
|
97
251
|
appendMessage(m) {
|
|
98
252
|
this.msgs.push(m);
|
|
99
253
|
}
|
|
100
254
|
messages() {
|
|
101
255
|
return this.msgs.slice();
|
|
102
256
|
}
|
|
103
|
-
|
|
104
|
-
return this.msgs.some((m) => m.role === "user" && m.turnId === turnId);
|
|
257
|
+
hasOpeningMessage(turnId) {
|
|
258
|
+
return this.msgs.some((m) => (m.role === "user" || m.role === "trigger") && m.turnId === turnId);
|
|
105
259
|
}
|
|
106
260
|
getStep(id) {
|
|
107
261
|
return this.steps.has(id) ? this.steps.get(id) : void 0;
|
|
@@ -109,6 +263,9 @@ var MemorySessionStore = class {
|
|
|
109
263
|
putStep(id, output) {
|
|
110
264
|
this.steps.set(id, output);
|
|
111
265
|
}
|
|
266
|
+
delStep(id) {
|
|
267
|
+
this.steps.delete(id);
|
|
268
|
+
}
|
|
112
269
|
getStatus() {
|
|
113
270
|
return this.status;
|
|
114
271
|
}
|
|
@@ -118,44 +275,124 @@ var MemorySessionStore = class {
|
|
|
118
275
|
tx(fn) {
|
|
119
276
|
return fn();
|
|
120
277
|
}
|
|
278
|
+
reset(inTx) {
|
|
279
|
+
const generation = this.generation++;
|
|
280
|
+
this.archives.push({
|
|
281
|
+
generation,
|
|
282
|
+
msgs: this.msgs,
|
|
283
|
+
steps: this.steps
|
|
284
|
+
});
|
|
285
|
+
this.msgs = [];
|
|
286
|
+
this.steps = /* @__PURE__ */ new Map();
|
|
287
|
+
this.status = "new";
|
|
288
|
+
inTx?.();
|
|
289
|
+
return generation;
|
|
290
|
+
}
|
|
121
291
|
unwrap() {}
|
|
122
292
|
};
|
|
123
293
|
var MemoryRuntime = class {
|
|
124
294
|
actors = /* @__PURE__ */ new Map();
|
|
125
295
|
stores = /* @__PURE__ */ new Map();
|
|
126
296
|
agents;
|
|
127
|
-
|
|
297
|
+
announceRetry = new AnnouncementRetry((agent, id) => {
|
|
298
|
+
this.session(agent, id).flushAnnouncements();
|
|
299
|
+
});
|
|
300
|
+
closed = false;
|
|
301
|
+
files;
|
|
302
|
+
constructor(agents, opts = {}) {
|
|
303
|
+
assertCoreRuntimeVersion("MemoryRuntime");
|
|
128
304
|
this.agents = agents;
|
|
305
|
+
this.files = opts.files;
|
|
306
|
+
}
|
|
307
|
+
agentDef(name) {
|
|
308
|
+
return this.agents[name];
|
|
129
309
|
}
|
|
130
310
|
session(agent, id) {
|
|
131
311
|
const key = `${agent}:${id}`;
|
|
132
312
|
let a = this.actors.get(key);
|
|
133
313
|
if (!a) {
|
|
314
|
+
if (this.closed) throw new Error(`MemoryRuntime is closed: cannot open session "${key}"`);
|
|
134
315
|
const def = this.agents[agent];
|
|
135
316
|
if (!def) throw new Error(`unknown agent: ${agent}`);
|
|
136
317
|
const store = new MemorySessionStore();
|
|
137
318
|
this.stores.set(key, store);
|
|
138
|
-
|
|
319
|
+
const model = def.instructions ? withSystem(def.model, def.instructions) : def.model;
|
|
320
|
+
const built = new AgentSession(agent, id, store, new InProcEventSink(), model, def.tools, this, def.channelInstructions);
|
|
321
|
+
built.files = this.files;
|
|
322
|
+
a = wireAnnouncements(built, def, this.announceRetry);
|
|
139
323
|
this.actors.set(key, a);
|
|
140
324
|
}
|
|
141
325
|
return a;
|
|
142
326
|
}
|
|
327
|
+
async close() {
|
|
328
|
+
this.closed = true;
|
|
329
|
+
this.announceRetry.stop();
|
|
330
|
+
this.actors.clear();
|
|
331
|
+
this.stores.clear();
|
|
332
|
+
}
|
|
143
333
|
};
|
|
144
334
|
async function createAgentRuntime(agents, opts = {}) {
|
|
145
335
|
const backend = opts.backend ?? "native";
|
|
146
|
-
if (backend === "memory") return new MemoryRuntime(agents);
|
|
147
|
-
if (backend === "native") return createNativeRuntime(agents, opts.path
|
|
336
|
+
if (backend === "memory") return new MemoryRuntime(agents, { files: opts.files });
|
|
337
|
+
if (backend === "native") return createNativeRuntime(agents, opts.path, {
|
|
338
|
+
maxSessions: opts.maxSessions,
|
|
339
|
+
files: opts.files
|
|
340
|
+
});
|
|
148
341
|
throw new Error("backend 'durable' is the Cloudflare Durable Object target — construct AgentDurableObject in your worker, not via createAgentRuntime");
|
|
149
342
|
}
|
|
343
|
+
function warnOnDrift(agent, runtime) {
|
|
344
|
+
const def = runtime.agentDef?.(agent.name);
|
|
345
|
+
if (!def) return;
|
|
346
|
+
const names = (tools) => tools.map((t) => t.spec.name).sort();
|
|
347
|
+
const want = names(agent.tools), have = names(def.tools);
|
|
348
|
+
if (want.join("\0") !== have.join("\0")) {
|
|
349
|
+
const missing = want.filter((n) => !have.includes(n)), extra = have.filter((n) => !want.includes(n));
|
|
350
|
+
console.warn(`[june] mountAgent("${agent.name}"): the runtime's tools differ from the agent definition's` + (missing.length ? ` — missing from the runtime: ${missing.join(", ")}` : "") + (extra.length ? ` — only in the runtime: ${extra.join(", ")}` : "") + `. Build the runtime entry with toAgentDef(agent, model) so both come from one definition.`);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
150
353
|
function mountAgent(agent, runtime, opts = {}) {
|
|
151
354
|
const chatPath = opts.chatPath ?? "/message";
|
|
152
355
|
const channelsOn = opts.channels ?? true;
|
|
356
|
+
warnOnDrift(agent, runtime);
|
|
153
357
|
const ctx = {
|
|
154
358
|
agent,
|
|
359
|
+
services: opts.services,
|
|
360
|
+
files: opts.files ?? runtime.files,
|
|
155
361
|
run: (message, o) => runtime.session(agent.name, o?.session ?? "default").turn({
|
|
156
362
|
turnId: o?.turnId,
|
|
157
|
-
userText: message
|
|
158
|
-
|
|
363
|
+
userText: message,
|
|
364
|
+
event: o?.event,
|
|
365
|
+
trigger: o?.trigger,
|
|
366
|
+
replace: o?.replace
|
|
367
|
+
}),
|
|
368
|
+
runDetached: async (message, o) => runtime.session(agent.name, o?.session ?? "default").start({
|
|
369
|
+
turnId: o?.turnId,
|
|
370
|
+
userText: message,
|
|
371
|
+
event: o?.event,
|
|
372
|
+
trigger: o?.trigger,
|
|
373
|
+
replace: o?.replace
|
|
374
|
+
}),
|
|
375
|
+
runStream: async function* (message, o) {
|
|
376
|
+
const session = runtime.session(agent.name, o?.session ?? "default");
|
|
377
|
+
const { turnId } = session.start({
|
|
378
|
+
turnId: o?.turnId,
|
|
379
|
+
userText: message,
|
|
380
|
+
event: o?.event,
|
|
381
|
+
trigger: o?.trigger,
|
|
382
|
+
replace: o?.replace
|
|
383
|
+
});
|
|
384
|
+
yield* observeTurnEvents(session, turnId);
|
|
385
|
+
},
|
|
386
|
+
resumeStream: async function* (o) {
|
|
387
|
+
const session = runtime.session(agent.name, o.session ?? "default");
|
|
388
|
+
const granted = await grantAnswer(session, o, agent.authorizeAnswer);
|
|
389
|
+
const { turnId } = session.resume(o.turnId, o.inputId, o.input, {
|
|
390
|
+
by: o.by,
|
|
391
|
+
granted
|
|
392
|
+
});
|
|
393
|
+
yield* observeTurnEvents(session, turnId);
|
|
394
|
+
},
|
|
395
|
+
resetSession: (o) => runtime.session(agent.name, o?.session ?? "default").reset()
|
|
159
396
|
};
|
|
160
397
|
const channels = channelFetch(agent, ctx);
|
|
161
398
|
const surface = async (req) => {
|
|
@@ -176,4 +413,4 @@ function mountAgent(agent, runtime, opts = {}) {
|
|
|
176
413
|
};
|
|
177
414
|
}
|
|
178
415
|
//#endregion
|
|
179
|
-
export { MemoryRuntime, NativeRuntime, createAgentRuntime, createNativeRuntime, mountAgent };
|
|
416
|
+
export { MemoryRuntime, NativeRuntime, createAgentRuntime, createNativeRuntime, mountAgent, toAgentDef };
|
package/dist/app.d.ts
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { JuneConfig } from "@junejs/core/config";
|
|
2
2
|
//#region src/app.d.ts
|
|
3
|
-
type CreateAppOptions = {
|
|
3
|
+
export type CreateAppOptions = {
|
|
4
4
|
appDir: string;
|
|
5
5
|
config?: JuneConfig;
|
|
6
6
|
};
|
|
7
|
-
type JuneApp = {
|
|
7
|
+
export type JuneApp = {
|
|
8
8
|
fetch(request: Request): Promise<Response>;
|
|
9
9
|
warmup(): Promise<void>;
|
|
10
10
|
routePaths(): Promise<string[]>;
|
|
11
11
|
earlyHints(): string[];
|
|
12
|
+
close(): Promise<void>;
|
|
12
13
|
};
|
|
13
|
-
declare function createApp({ appDir: appDirInput, config }: CreateAppOptions): JuneApp;
|
|
14
|
-
//#endregion
|
|
15
|
-
export { CreateAppOptions, JuneApp, createApp };
|
|
14
|
+
export declare function createApp({ appDir: appDirInput, config }: CreateAppOptions): JuneApp;
|
|
15
|
+
//#endregion
|
package/dist/app.js
CHANGED
|
@@ -1,21 +1,24 @@
|
|
|
1
1
|
import { discoverAgent } from "./agent-discover.js";
|
|
2
|
-
import { createAgentRuntime, mountAgent } from "./agent-native.js";
|
|
2
|
+
import { createAgentRuntime, mountAgent, toAgentDef } from "./agent-native.js";
|
|
3
3
|
import { findMiddlewareFile, isResourceFile, listRoutes, matchRouteTree, resolveNotFound, routeFiles } from "./router.js";
|
|
4
|
+
import { routeProblems, scanRoutes } from "./route-scan.js";
|
|
4
5
|
import { createPipeline } from "./pipeline.js";
|
|
5
6
|
import { resolveBoundary } from "./segment.js";
|
|
6
7
|
import { memoizeResources } from "./resources.js";
|
|
8
|
+
import { localBlob } from "./blob.js";
|
|
7
9
|
import { MODULE_STYLES_URL, buildModuleCss, registerCssModules } from "./css-modules.js";
|
|
8
10
|
import { CLIENT_SCRIPT_URL, bundleClientSplit, findClientEntry } from "./client-bundle.js";
|
|
9
11
|
import { generateIslandRegistry } from "./island-registry.js";
|
|
10
12
|
import { STYLES_URL, findGlobalCss, globalCssUsesTailwind, processCssCached } from "./css.js";
|
|
11
13
|
import { contentTypeFor, safeRelativePath } from "./static-files.js";
|
|
14
|
+
import { GENERATED_ICONS, googleFontFetcher, publicFileCheck, renderIcons, resolveIcons } from "./favicon.js";
|
|
12
15
|
import { existsSync, lstatSync, realpathSync } from "node:fs";
|
|
13
16
|
import { readFile } from "node:fs/promises";
|
|
14
17
|
import { dirname, join, resolve } from "node:path";
|
|
15
18
|
import { pathToFileURL } from "node:url";
|
|
16
|
-
import {
|
|
19
|
+
import { blobFileStore, memoryFileStore } from "@junejs/core/agent-files";
|
|
17
20
|
import { routeFromModule } from "@junejs/core/route";
|
|
18
|
-
import { resolveAgent, resolveClientRouter, resolveSpeculationRules } from "@junejs/core/config";
|
|
21
|
+
import { deployOrigin, resolveAgent, resolveClientRouter, resolveSpeculationRules } from "@junejs/core/config";
|
|
19
22
|
import { runWithTrace } from "@junejs/core/instrumentation";
|
|
20
23
|
import { anthropic } from "@junejs/core/agent-models";
|
|
21
24
|
//#region src/app.ts
|
|
@@ -69,19 +72,31 @@ function createApp({ appDir: appDirInput, config = {} }) {
|
|
|
69
72
|
try {
|
|
70
73
|
if (lstatSync(publicDir).isDirectory()) publicRoot = realpathSync(publicDir);
|
|
71
74
|
} catch {}
|
|
75
|
+
const iconPlan = resolveIcons(config.site ?? {}, publicFileCheck(publicDir));
|
|
76
|
+
let iconsPromise;
|
|
77
|
+
const getIcons = () => iconsPromise ??= renderIcons({
|
|
78
|
+
site: config.site ?? {},
|
|
79
|
+
fetchFont: googleFontFetcher(join(dirname(appDir), "node_modules", ".cache", "june", "fonts")),
|
|
80
|
+
warn: (msg) => console.warn(msg)
|
|
81
|
+
}).catch((err) => {
|
|
82
|
+
iconsPromise = void 0;
|
|
83
|
+
throw err;
|
|
84
|
+
});
|
|
72
85
|
const agent = resolveAgent(config.agent);
|
|
73
86
|
const speculation = config.speculation;
|
|
74
87
|
const clientEntry = findClientEntry(appDir) ?? findClientEntry(join(dirname(appDir), ".june", "routes"));
|
|
75
88
|
const cssEntry = findGlobalCss(appDir);
|
|
76
89
|
const docConfig = {
|
|
77
90
|
site: config.site ?? {},
|
|
91
|
+
deployOrigin: deployOrigin(config),
|
|
78
92
|
speculationRules: resolveSpeculationRules(speculation ?? void 0),
|
|
79
93
|
speculationDelivery: speculation ? speculation.delivery ?? "inline" : "inline",
|
|
80
94
|
viewTransitions: config.viewTransitions ?? true,
|
|
81
95
|
cssReset: config.cssReset ?? !globalCssUsesTailwind(appDir),
|
|
82
96
|
clientRouter: resolveClientRouter(config.clientRouter),
|
|
83
97
|
clientScript: clientEntry ? CLIENT_SCRIPT_URL : null,
|
|
84
|
-
styles: cssEntry ? STYLES_URL : null
|
|
98
|
+
styles: cssEntry ? STYLES_URL : null,
|
|
99
|
+
icons: iconPlan.icons
|
|
85
100
|
};
|
|
86
101
|
let moduleCssPromise;
|
|
87
102
|
const getModuleCss = () => moduleCssPromise ??= buildModuleCss(appDir, dirname(appDir));
|
|
@@ -103,6 +118,7 @@ function createApp({ appDir: appDirInput, config = {} }) {
|
|
|
103
118
|
config.dataLayer?.install();
|
|
104
119
|
let pipelinePromise;
|
|
105
120
|
const getPipeline = () => pipelinePromise ??= buildPipeline();
|
|
121
|
+
let agentRuntime;
|
|
106
122
|
async function buildPipeline() {
|
|
107
123
|
const { maps, css } = await getModuleCss();
|
|
108
124
|
await registerCssModules(maps);
|
|
@@ -125,11 +141,14 @@ function createApp({ appDir: appDirInput, config = {} }) {
|
|
|
125
141
|
const def = await discoverAgent(agentDir);
|
|
126
142
|
const backend = agent.runtime.backend === "durable" ? "native" : agent.runtime.backend;
|
|
127
143
|
const model = anthropic({ model: def.model });
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
144
|
+
let blobOpened;
|
|
145
|
+
const files = backend === "memory" ? memoryFileStore() : blobFileStore(() => blobOpened ??= resources().then(async (r) => r.blob ?? await localBlob().open()));
|
|
146
|
+
const rt = await createAgentRuntime({ [def.name]: toAgentDef(def, model) }, {
|
|
147
|
+
backend,
|
|
148
|
+
files
|
|
149
|
+
});
|
|
150
|
+
agentRuntime = rt;
|
|
151
|
+
const mounted = mountAgent(def, rt, {
|
|
133
152
|
chatPath: agent.runtime.chat.path,
|
|
134
153
|
channels: agent.runtime.channels
|
|
135
154
|
});
|
|
@@ -238,9 +257,18 @@ function createApp({ appDir: appDirInput, config = {} }) {
|
|
|
238
257
|
}
|
|
239
258
|
}
|
|
240
259
|
}
|
|
260
|
+
if (iconPlan.generate && (request.method === "GET" || request.method === "HEAD")) {
|
|
261
|
+
const name = new URL(request.url).pathname.slice(1);
|
|
262
|
+
if (GENERATED_ICONS.includes(name)) return getIcons().then((icons) => new Response(request.method === "HEAD" ? null : icons[name], { headers: {
|
|
263
|
+
"content-type": contentTypeFor(name),
|
|
264
|
+
"cache-control": "public, max-age=0, must-revalidate"
|
|
265
|
+
} }), () => toPipeline());
|
|
266
|
+
}
|
|
241
267
|
return toPipeline();
|
|
242
268
|
},
|
|
243
269
|
async warmup() {
|
|
270
|
+
const problems = routeProblems([await scanRoutes(appDir), hasJuneRoutes ? await scanRoutes(juneRoutesDir) : []], dirname(appDir));
|
|
271
|
+
if (problems) console.error(problems);
|
|
244
272
|
const files = await routeFiles(appDir, { pageConvention: true });
|
|
245
273
|
if (hasJuneRoutes) files.push(...await routeFiles(juneRoutesDir, { pageConvention: true }));
|
|
246
274
|
for (const file of files) await import(pathToFileURL(file).href).catch((err) => {
|
|
@@ -248,7 +276,11 @@ function createApp({ appDir: appDirInput, config = {} }) {
|
|
|
248
276
|
});
|
|
249
277
|
},
|
|
250
278
|
routePaths,
|
|
251
|
-
earlyHints: () => config.earlyHints ?? []
|
|
279
|
+
earlyHints: () => config.earlyHints ?? [],
|
|
280
|
+
async close() {
|
|
281
|
+
await pipelinePromise?.catch(() => {});
|
|
282
|
+
await agentRuntime?.close();
|
|
283
|
+
}
|
|
252
284
|
};
|
|
253
285
|
}
|
|
254
286
|
//#endregion
|
package/dist/blob.d.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { BlobFactory } from "@junejs/core/resources";
|
|
2
2
|
//#region src/blob.d.ts
|
|
3
|
-
declare function localBlob(opts?: {
|
|
3
|
+
export declare function localBlob(opts?: {
|
|
4
4
|
dir?: string;
|
|
5
5
|
}): BlobFactory;
|
|
6
6
|
interface R2ObjectBody {
|
|
7
7
|
arrayBuffer(): Promise<ArrayBuffer>;
|
|
8
8
|
}
|
|
9
|
-
interface R2Bucket {
|
|
9
|
+
export interface R2Bucket {
|
|
10
10
|
get(key: string): Promise<R2ObjectBody | null>;
|
|
11
11
|
put(key: string, data: ArrayBuffer | Uint8Array | string): Promise<unknown>;
|
|
12
12
|
delete(key: string): Promise<void>;
|
|
@@ -18,6 +18,5 @@ interface R2Bucket {
|
|
|
18
18
|
}[];
|
|
19
19
|
}>;
|
|
20
20
|
}
|
|
21
|
-
declare function r2(bucket: R2Bucket): BlobFactory;
|
|
22
|
-
//#endregion
|
|
23
|
-
export { R2Bucket, localBlob, r2 };
|
|
21
|
+
export declare function r2(bucket: R2Bucket): BlobFactory;
|
|
22
|
+
//#endregion
|