@coze-arch/cli 0.0.13 → 0.0.14-alpha.c52ee4
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/lib/__templates__/expo/AGENTS.md +15 -7
- package/lib/__templates__/expo/README.md +15 -7
- package/lib/__templates__/expo/client/eslint.config.mjs +3 -0
- package/lib/__templates__/expo/eslint-plugins/expo/index.js +9 -0
- package/lib/__templates__/expo/eslint-plugins/expo/rule.js +105 -0
- package/lib/__templates__/expo/eslint-plugins/expo/tech.md +108 -0
- package/lib/__templates__/nextjs/AGENTS.md +9 -0
- package/lib/__templates__/nextjs/eslint.config.mjs +15 -0
- package/lib/__templates__/pi-agent/.coze +10 -0
- package/lib/__templates__/pi-agent/AGENTS.md +150 -0
- package/lib/__templates__/pi-agent/README.md +155 -0
- package/lib/__templates__/pi-agent/_gitignore +3 -0
- package/lib/__templates__/pi-agent/docs/project-overview.md +273 -0
- package/lib/__templates__/pi-agent/docs/user/getting-started.md +46 -0
- package/lib/__templates__/pi-agent/package.json +52 -0
- package/lib/__templates__/pi-agent/pnpm-lock.yaml +7840 -0
- package/lib/__templates__/pi-agent/scripts/dev.sh +14 -0
- package/lib/__templates__/pi-agent/scripts/prepare.sh +2 -0
- package/lib/__templates__/pi-agent/src/agent.ts +367 -0
- package/lib/__templates__/pi-agent/src/channels/feishu/index.ts +760 -0
- package/lib/__templates__/pi-agent/src/channels/feishu/streaming-card.ts +297 -0
- package/lib/__templates__/pi-agent/src/channels/wechat/index.ts +171 -0
- package/lib/__templates__/pi-agent/src/config.ts +596 -0
- package/lib/__templates__/pi-agent/src/core.ts +218 -0
- package/lib/__templates__/pi-agent/src/dashboard/api/channels.ts +148 -0
- package/lib/__templates__/pi-agent/src/dashboard/api/docs.ts +204 -0
- package/lib/__templates__/pi-agent/src/dashboard/api/models.ts +141 -0
- package/lib/__templates__/pi-agent/src/dashboard/api/overview.ts +33 -0
- package/lib/__templates__/pi-agent/src/dashboard/config-store.ts +64 -0
- package/lib/__templates__/pi-agent/src/dashboard/index.ts +39 -0
- package/lib/__templates__/pi-agent/src/dashboard/server.ts +622 -0
- package/lib/__templates__/pi-agent/src/dashboard/types.ts +25 -0
- package/lib/__templates__/pi-agent/src/dashboard/web/index.html +13 -0
- package/lib/__templates__/pi-agent/src/dashboard/web/postcss.config.cjs +7 -0
- package/lib/__templates__/pi-agent/src/dashboard/web/src/components/app-layout.tsx +186 -0
- package/lib/__templates__/pi-agent/src/dashboard/web/src/components/page-title.tsx +17 -0
- package/lib/__templates__/pi-agent/src/dashboard/web/src/components/ui/alert.tsx +22 -0
- package/lib/__templates__/pi-agent/src/dashboard/web/src/components/ui/badge.tsx +25 -0
- package/lib/__templates__/pi-agent/src/dashboard/web/src/components/ui/button.tsx +40 -0
- package/lib/__templates__/pi-agent/src/dashboard/web/src/components/ui/card.tsx +29 -0
- package/lib/__templates__/pi-agent/src/dashboard/web/src/components/ui/input.tsx +18 -0
- package/lib/__templates__/pi-agent/src/dashboard/web/src/components/ui/label.tsx +8 -0
- package/lib/__templates__/pi-agent/src/dashboard/web/src/components/ui/select.tsx +80 -0
- package/lib/__templates__/pi-agent/src/dashboard/web/src/components/ui/separator.tsx +23 -0
- package/lib/__templates__/pi-agent/src/dashboard/web/src/hooks/use-fetch.ts +32 -0
- package/lib/__templates__/pi-agent/src/dashboard/web/src/hooks/use-local-storage-state.ts +23 -0
- package/lib/__templates__/pi-agent/src/dashboard/web/src/main.tsx +30 -0
- package/lib/__templates__/pi-agent/src/dashboard/web/src/pages/channels-page.tsx +188 -0
- package/lib/__templates__/pi-agent/src/dashboard/web/src/pages/chat-page.tsx +451 -0
- package/lib/__templates__/pi-agent/src/dashboard/web/src/pages/docs-page.tsx +65 -0
- package/lib/__templates__/pi-agent/src/dashboard/web/src/pages/models-page.tsx +122 -0
- package/lib/__templates__/pi-agent/src/dashboard/web/src/pages/overview-page.tsx +134 -0
- package/lib/__templates__/pi-agent/src/dashboard/web/src/services/chat-ws-service.ts +167 -0
- package/lib/__templates__/pi-agent/src/dashboard/web/src/styles.css +294 -0
- package/lib/__templates__/pi-agent/src/dashboard/web/src/utils/index.ts +11 -0
- package/lib/__templates__/pi-agent/src/dashboard/web/tsconfig.json +13 -0
- package/lib/__templates__/pi-agent/src/dashboard/web/vite.config.ts +17 -0
- package/lib/__templates__/pi-agent/src/index.ts +123 -0
- package/lib/__templates__/pi-agent/src/session-store.ts +223 -0
- package/lib/__templates__/pi-agent/template.config.js +45 -0
- package/lib/__templates__/pi-agent/tests/config.test.ts +292 -0
- package/lib/__templates__/pi-agent/tests/dashboard-docs-api.test.ts +125 -0
- package/lib/__templates__/pi-agent/tests/dashboard-models-api.test.ts +171 -0
- package/lib/__templates__/pi-agent/tests/feishu-channel.test.ts +149 -0
- package/lib/__templates__/pi-agent/tests/feishu-streaming-card.test.ts +15 -0
- package/lib/__templates__/pi-agent/tests/session-store.test.ts +61 -0
- package/lib/__templates__/pi-agent/tests/smoke/run-smoke.ts +275 -0
- package/lib/__templates__/pi-agent/tsconfig.json +20 -0
- package/lib/__templates__/pi-agent/types/larksuiteoapi-node-sdk.d.ts +113 -0
- package/lib/__templates__/taro/pnpm-lock.yaml +24 -14
- package/lib/__templates__/taro/server/package.json +0 -2
- package/lib/__templates__/taro/src/presets/dev-debug.ts +2 -2
- package/lib/__templates__/templates.json +24 -0
- package/lib/__templates__/vite/AGENTS.md +5 -0
- package/lib/cli.js +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
5
|
+
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
|
6
|
+
|
|
7
|
+
cd "${PROJECT_ROOT}"
|
|
8
|
+
|
|
9
|
+
set -a
|
|
10
|
+
[ -f .env ] && source .env
|
|
11
|
+
[ -f .env.local ] && source .env.local
|
|
12
|
+
set +a
|
|
13
|
+
|
|
14
|
+
exec node --import tsx src/index.ts
|
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
import { mkdirSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import {
|
|
4
|
+
type AgentRuntime,
|
|
5
|
+
type AgentRuntimeConfig,
|
|
6
|
+
type BotMessage,
|
|
7
|
+
getSessionKey
|
|
8
|
+
} from "./core.js";
|
|
9
|
+
import { resolveRuntimeModel } from "./config.js";
|
|
10
|
+
import type { AgentSession } from "@mariozechner/pi-coding-agent";
|
|
11
|
+
import {
|
|
12
|
+
AuthStorage,
|
|
13
|
+
createAgentSession,
|
|
14
|
+
DefaultResourceLoader,
|
|
15
|
+
ModelRegistry,
|
|
16
|
+
SessionManager,
|
|
17
|
+
SettingsManager
|
|
18
|
+
} from "@mariozechner/pi-coding-agent";
|
|
19
|
+
import { SessionStore } from "./session-store.js";
|
|
20
|
+
|
|
21
|
+
export type PiAgentStreamHandlers = {
|
|
22
|
+
onMeta?: (meta: { sessionKey: string }) => void;
|
|
23
|
+
onDelta?: (delta: string) => void;
|
|
24
|
+
onError?: (error: string) => void;
|
|
25
|
+
/**
|
|
26
|
+
* Optional hook for forwarding raw session events (useful for debugging/telemetry).
|
|
27
|
+
* Keep this best-effort: callers should not rely on a stable event schema here.
|
|
28
|
+
*/
|
|
29
|
+
onEvent?: (event: unknown) => void;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Extension of AgentRuntime used by the dashboard.
|
|
34
|
+
* Channels keep using the stable `run()` API.
|
|
35
|
+
*/
|
|
36
|
+
export interface PiAgentRuntime extends AgentRuntime {
|
|
37
|
+
stream(message: BotMessage, handlers: PiAgentStreamHandlers): Promise<{ sessionKey: string; finalText: string }>;
|
|
38
|
+
getSessionIfExists(sessionKey: string): AgentSession | undefined;
|
|
39
|
+
listSessionKeys(): string[];
|
|
40
|
+
ensureSessionLoaded(sessionKey: string): Promise<AgentSession | undefined>;
|
|
41
|
+
abortSession(sessionKey: string): Promise<void>;
|
|
42
|
+
resetSession(sessionKey: string): Promise<void>;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function extractAssistantText(session: AgentSession): string {
|
|
46
|
+
const messages = [...session.state.messages].reverse();
|
|
47
|
+
|
|
48
|
+
for (const message of messages) {
|
|
49
|
+
if ((message as { role?: string }).role !== "assistant") {
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const content = (message as { content?: unknown }).content;
|
|
54
|
+
if (typeof content === "string") {
|
|
55
|
+
return content.trim();
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (!Array.isArray(content)) {
|
|
59
|
+
return "";
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return content
|
|
63
|
+
.flatMap((part) => {
|
|
64
|
+
if (!part || typeof part !== "object") {
|
|
65
|
+
return [];
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const typedPart = part as { type?: unknown; text?: unknown };
|
|
69
|
+
return typedPart.type === "text" && typeof typedPart.text === "string" ? [typedPart.text] : [];
|
|
70
|
+
})
|
|
71
|
+
.join("")
|
|
72
|
+
.trim();
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return "";
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function extractAssistantTextFromMessage(message: unknown): string {
|
|
79
|
+
if (!message || typeof message !== "object") return "";
|
|
80
|
+
if ((message as { role?: unknown }).role !== "assistant") return "";
|
|
81
|
+
|
|
82
|
+
const content = (message as { content?: unknown }).content;
|
|
83
|
+
if (typeof content === "string") {
|
|
84
|
+
return content;
|
|
85
|
+
}
|
|
86
|
+
if (!Array.isArray(content)) {
|
|
87
|
+
return "";
|
|
88
|
+
}
|
|
89
|
+
return content
|
|
90
|
+
.flatMap((part) => {
|
|
91
|
+
if (!part || typeof part !== "object") return [];
|
|
92
|
+
const typedPart = part as { type?: unknown; text?: unknown };
|
|
93
|
+
return typedPart.type === "text" && typeof typedPart.text === "string" ? [typedPart.text] : [];
|
|
94
|
+
})
|
|
95
|
+
.join("");
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export function createMockAgentRuntime(): PiAgentRuntime {
|
|
99
|
+
const sessionHistory = new Map<string, string[]>();
|
|
100
|
+
|
|
101
|
+
return {
|
|
102
|
+
async run(message: BotMessage): Promise<string> {
|
|
103
|
+
const sessionKey = getSessionKey(message);
|
|
104
|
+
const history = sessionHistory.get(sessionKey) ?? [];
|
|
105
|
+
history.push(message.text);
|
|
106
|
+
sessionHistory.set(sessionKey, history);
|
|
107
|
+
return `mock:${sessionKey}: ${message.text}`;
|
|
108
|
+
},
|
|
109
|
+
async stream(message: BotMessage, handlers: PiAgentStreamHandlers) {
|
|
110
|
+
const sessionKey = getSessionKey(message);
|
|
111
|
+
handlers.onMeta?.({ sessionKey });
|
|
112
|
+
const history = sessionHistory.get(sessionKey) ?? [];
|
|
113
|
+
history.push(message.text);
|
|
114
|
+
sessionHistory.set(sessionKey, history);
|
|
115
|
+
const text = `mock:${sessionKey}: ${message.text}`;
|
|
116
|
+
handlers.onDelta?.(text);
|
|
117
|
+
return { sessionKey, finalText: text };
|
|
118
|
+
},
|
|
119
|
+
getSessionIfExists(_sessionKey: string): AgentSession | undefined {
|
|
120
|
+
return undefined;
|
|
121
|
+
},
|
|
122
|
+
listSessionKeys(): string[] {
|
|
123
|
+
return Array.from(sessionHistory.keys());
|
|
124
|
+
},
|
|
125
|
+
async ensureSessionLoaded(_sessionKey: string): Promise<AgentSession | undefined> {
|
|
126
|
+
return undefined;
|
|
127
|
+
},
|
|
128
|
+
async abortSession(_sessionKey: string): Promise<void> {},
|
|
129
|
+
async resetSession(_sessionKey: string): Promise<void> {},
|
|
130
|
+
async dispose(): Promise<void> {}
|
|
131
|
+
} satisfies PiAgentRuntime;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export async function createPiAgentRuntime(config: AgentRuntimeConfig): Promise<PiAgentRuntime> {
|
|
135
|
+
const cwd = config.cwd ?? process.cwd();
|
|
136
|
+
const agentDir = config.agentDir;
|
|
137
|
+
const sessionRootDir = agentDir ?? cwd;
|
|
138
|
+
const authStorage = agentDir ? AuthStorage.create(join(agentDir, "auth.json")) : AuthStorage.create();
|
|
139
|
+
const modelRegistry = new ModelRegistry(
|
|
140
|
+
authStorage,
|
|
141
|
+
agentDir ? join(agentDir, "models.json") : undefined
|
|
142
|
+
);
|
|
143
|
+
const settingsManager = SettingsManager.create(cwd, agentDir);
|
|
144
|
+
const resourceLoader = new DefaultResourceLoader({
|
|
145
|
+
cwd,
|
|
146
|
+
agentDir,
|
|
147
|
+
settingsManager
|
|
148
|
+
});
|
|
149
|
+
const resolvedModel = resolveRuntimeModel({
|
|
150
|
+
provider: config.provider,
|
|
151
|
+
model: config.model,
|
|
152
|
+
baseUrl: config.baseUrl,
|
|
153
|
+
configPath: config.configPath
|
|
154
|
+
});
|
|
155
|
+
const sessions = new Map<string, AgentSession>();
|
|
156
|
+
const pendingSessionLoads = new Map<string, Promise<AgentSession>>();
|
|
157
|
+
const sessionGenerations = new Map<string, number>();
|
|
158
|
+
const sessionStore = new SessionStore(sessionRootDir);
|
|
159
|
+
|
|
160
|
+
if (agentDir) {
|
|
161
|
+
mkdirSync(agentDir, { recursive: true });
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
await resourceLoader.reload();
|
|
165
|
+
sessionStore.load();
|
|
166
|
+
|
|
167
|
+
if (resolvedModel?.apiKey) {
|
|
168
|
+
authStorage.setRuntimeApiKey(resolvedModel.model.provider, resolvedModel.apiKey);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
async function getOrCreateSession(sessionKey: string): Promise<AgentSession> {
|
|
172
|
+
const existing = sessions.get(sessionKey);
|
|
173
|
+
if (existing) return existing;
|
|
174
|
+
|
|
175
|
+
const pending = pendingSessionLoads.get(sessionKey);
|
|
176
|
+
if (pending) return pending;
|
|
177
|
+
|
|
178
|
+
const capturedGen = sessionGenerations.get(sessionKey) ?? 0;
|
|
179
|
+
const sessionPromise = (async () => {
|
|
180
|
+
const record = sessionStore.ensureSession(sessionKey);
|
|
181
|
+
const sessionManager = SessionManager.open(record.sessionFile);
|
|
182
|
+
const { session } = await createAgentSession({
|
|
183
|
+
authStorage,
|
|
184
|
+
cwd,
|
|
185
|
+
agentDir,
|
|
186
|
+
model: resolvedModel?.model,
|
|
187
|
+
modelRegistry,
|
|
188
|
+
thinkingLevel: config.thinkingLevel,
|
|
189
|
+
tools: [],
|
|
190
|
+
customTools: [],
|
|
191
|
+
resourceLoader,
|
|
192
|
+
settingsManager,
|
|
193
|
+
sessionManager
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
const currentGen = sessionGenerations.get(sessionKey) ?? 0;
|
|
197
|
+
if (currentGen !== capturedGen) {
|
|
198
|
+
// Session was reset while we were creating it; discard this instance.
|
|
199
|
+
try {
|
|
200
|
+
(session as unknown as { dispose?: () => void }).dispose?.();
|
|
201
|
+
} catch {
|
|
202
|
+
// ignore
|
|
203
|
+
}
|
|
204
|
+
throw new Error("stale session");
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
sessions.set(sessionKey, session);
|
|
208
|
+
return session;
|
|
209
|
+
})();
|
|
210
|
+
|
|
211
|
+
pendingSessionLoads.set(sessionKey, sessionPromise);
|
|
212
|
+
|
|
213
|
+
try {
|
|
214
|
+
return await sessionPromise;
|
|
215
|
+
} finally {
|
|
216
|
+
pendingSessionLoads.delete(sessionKey);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
return {
|
|
221
|
+
async run(message: BotMessage): Promise<string> {
|
|
222
|
+
const sessionKey = getSessionKey(message);
|
|
223
|
+
const session = await getOrCreateSession(sessionKey);
|
|
224
|
+
if (session.isStreaming) {
|
|
225
|
+
await session.prompt(message.text, { streamingBehavior: "followUp" });
|
|
226
|
+
} else {
|
|
227
|
+
await session.prompt(message.text);
|
|
228
|
+
}
|
|
229
|
+
return extractAssistantText(session);
|
|
230
|
+
},
|
|
231
|
+
async stream(message: BotMessage, handlers: PiAgentStreamHandlers) {
|
|
232
|
+
const sessionKey = getSessionKey(message);
|
|
233
|
+
handlers.onMeta?.({ sessionKey });
|
|
234
|
+
|
|
235
|
+
const session = await (async () => {
|
|
236
|
+
try {
|
|
237
|
+
return await getOrCreateSession(sessionKey);
|
|
238
|
+
} catch (err) {
|
|
239
|
+
if (String(err).includes("stale session")) {
|
|
240
|
+
// Race with reset; retry once against the latest transcript.
|
|
241
|
+
return await getOrCreateSession(sessionKey);
|
|
242
|
+
}
|
|
243
|
+
throw err;
|
|
244
|
+
}
|
|
245
|
+
})();
|
|
246
|
+
if (session.isStreaming) {
|
|
247
|
+
// Dashboard UI expects a single in-flight stream per session.
|
|
248
|
+
throw new Error(`Session is busy: ${sessionKey}`);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
let lastText = "";
|
|
252
|
+
let sawTextDelta = false;
|
|
253
|
+
|
|
254
|
+
const unsubscribe = session.subscribe((event) => {
|
|
255
|
+
handlers.onEvent?.(event);
|
|
256
|
+
|
|
257
|
+
// Primary streaming signal in pi-coding-agent is `assistantMessageEvent.text_delta`.
|
|
258
|
+
// Keep a fallback for older/alternate event shapes.
|
|
259
|
+
if (!event || typeof event !== "object") return;
|
|
260
|
+
const type = (event as { type?: unknown }).type;
|
|
261
|
+
|
|
262
|
+
if (type === "message_update") {
|
|
263
|
+
const assistantMessageEvent = (event as { assistantMessageEvent?: unknown }).assistantMessageEvent;
|
|
264
|
+
if (assistantMessageEvent && typeof assistantMessageEvent === "object") {
|
|
265
|
+
const evtType = (assistantMessageEvent as { type?: unknown }).type;
|
|
266
|
+
const delta = (assistantMessageEvent as { delta?: unknown }).delta;
|
|
267
|
+
if (evtType === "text_delta" && typeof delta === "string" && delta) {
|
|
268
|
+
sawTextDelta = true;
|
|
269
|
+
handlers.onDelta?.(delta);
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// Fallback: stream by diffing assistant full text snapshots.
|
|
276
|
+
// IMPORTANT: once we have real text_delta events, do not mix snapshot-based
|
|
277
|
+
// fallback deltas into the same output stream, otherwise we may duplicate
|
|
278
|
+
// or corrupt the accumulated text.
|
|
279
|
+
if (sawTextDelta) return;
|
|
280
|
+
if (type !== "message_start" && type !== "message_update" && type !== "message_end") return;
|
|
281
|
+
|
|
282
|
+
const msg = (event as { message?: unknown }).message;
|
|
283
|
+
if (!msg || typeof msg !== "object") return;
|
|
284
|
+
if ((msg as { role?: unknown }).role !== "assistant") return;
|
|
285
|
+
|
|
286
|
+
const fullText = extractAssistantTextFromMessage(msg);
|
|
287
|
+
if (fullText.length < lastText.length || !fullText.startsWith(lastText)) {
|
|
288
|
+
lastText = fullText;
|
|
289
|
+
if (fullText) {
|
|
290
|
+
console.log("[pi-bot][agent-stream] fallback_fulltext", fullText);
|
|
291
|
+
handlers.onDelta?.(fullText);
|
|
292
|
+
}
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
const delta = fullText.slice(lastText.length);
|
|
296
|
+
lastText = fullText;
|
|
297
|
+
if (delta) {
|
|
298
|
+
handlers.onDelta?.(delta);
|
|
299
|
+
}
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
try {
|
|
303
|
+
await session.prompt(message.text);
|
|
304
|
+
const finalText = extractAssistantText(session);
|
|
305
|
+
return { sessionKey, finalText };
|
|
306
|
+
} catch (err) {
|
|
307
|
+
handlers.onError?.(String(err));
|
|
308
|
+
throw err;
|
|
309
|
+
} finally {
|
|
310
|
+
unsubscribe();
|
|
311
|
+
}
|
|
312
|
+
},
|
|
313
|
+
getSessionIfExists(sessionKey: string): AgentSession | undefined {
|
|
314
|
+
return sessions.get(sessionKey);
|
|
315
|
+
},
|
|
316
|
+
listSessionKeys(): string[] {
|
|
317
|
+
const all = new Set<string>([...sessionStore.listSessionKeys(), ...sessions.keys()]);
|
|
318
|
+
return Array.from(all);
|
|
319
|
+
},
|
|
320
|
+
async ensureSessionLoaded(sessionKey: string): Promise<AgentSession | undefined> {
|
|
321
|
+
try {
|
|
322
|
+
return await getOrCreateSession(sessionKey);
|
|
323
|
+
} catch (err) {
|
|
324
|
+
if (String(err).includes("stale session")) {
|
|
325
|
+
return await getOrCreateSession(sessionKey);
|
|
326
|
+
}
|
|
327
|
+
throw err;
|
|
328
|
+
}
|
|
329
|
+
},
|
|
330
|
+
async abortSession(sessionKey: string): Promise<void> {
|
|
331
|
+
const session = sessions.get(sessionKey);
|
|
332
|
+
if (!session) return;
|
|
333
|
+
await session.abort();
|
|
334
|
+
},
|
|
335
|
+
async resetSession(sessionKey: string): Promise<void> {
|
|
336
|
+
const nextGen = (sessionGenerations.get(sessionKey) ?? 0) + 1;
|
|
337
|
+
sessionGenerations.set(sessionKey, nextGen);
|
|
338
|
+
sessionStore.resetSession(sessionKey);
|
|
339
|
+
const session = sessions.get(sessionKey);
|
|
340
|
+
if (!session) return;
|
|
341
|
+
try {
|
|
342
|
+
if (session.isStreaming) {
|
|
343
|
+
await session.abort();
|
|
344
|
+
}
|
|
345
|
+
} catch {
|
|
346
|
+
// ignore
|
|
347
|
+
}
|
|
348
|
+
try {
|
|
349
|
+
(session as unknown as { dispose?: () => void }).dispose?.();
|
|
350
|
+
} catch {
|
|
351
|
+
// ignore
|
|
352
|
+
}
|
|
353
|
+
sessions.delete(sessionKey);
|
|
354
|
+
},
|
|
355
|
+
async dispose(): Promise<void> {
|
|
356
|
+
sessions.clear();
|
|
357
|
+
}
|
|
358
|
+
} satisfies PiAgentRuntime;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
export async function createAgentRuntime(config: AgentRuntimeConfig): Promise<PiAgentRuntime> {
|
|
362
|
+
if (config.mode === "mock") {
|
|
363
|
+
return createMockAgentRuntime();
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
return createPiAgentRuntime(config);
|
|
367
|
+
}
|