@my-life-buddies/cli 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/README.md +42 -7
- package/dist/bin/buddy.js +8 -3
- package/dist/bin/buddy.js.map +2 -2
- package/dist/bin/core.js +475 -312
- package/dist/bin/core.js.map +4 -4
- package/dist/bin/preview.js +158 -46
- package/dist/bin/preview.js.map +2 -2
- package/dist/web/app.css +15 -8
- package/dist/web/app.js +85 -8
- package/dist/web/index.html +4 -0
- package/package.json +3 -3
package/dist/bin/preview.js
CHANGED
|
@@ -32,6 +32,12 @@ var PreviewController = class {
|
|
|
32
32
|
#observedActiveRuns = /* @__PURE__ */ new Set();
|
|
33
33
|
#events = [];
|
|
34
34
|
#runOrdinal = 0;
|
|
35
|
+
#conversationRevision = 0;
|
|
36
|
+
#resetting = false;
|
|
37
|
+
#sendingMessage = false;
|
|
38
|
+
get resetting() {
|
|
39
|
+
return this.#resetting;
|
|
40
|
+
}
|
|
35
41
|
#state = Object.freeze({ phase: "idle", revision: 0 });
|
|
36
42
|
#handle;
|
|
37
43
|
#simulator;
|
|
@@ -71,7 +77,7 @@ var PreviewController = class {
|
|
|
71
77
|
return () => this.#simulatorListeners.delete(listener);
|
|
72
78
|
}
|
|
73
79
|
simulatorSnapshot() {
|
|
74
|
-
return this.#simulatorState;
|
|
80
|
+
return Object.freeze({ ...this.#simulatorState, conversationRevision: this.#conversationRevision });
|
|
75
81
|
}
|
|
76
82
|
start() {
|
|
77
83
|
if (this.#startPromise) return this.#startPromise;
|
|
@@ -160,49 +166,87 @@ var PreviewController = class {
|
|
|
160
166
|
this.#simulatorListeners.clear();
|
|
161
167
|
}
|
|
162
168
|
async simulatorState(signal) {
|
|
163
|
-
|
|
164
|
-
|
|
169
|
+
if (this.#resetting) return this.simulatorSnapshot();
|
|
170
|
+
const simulator = this.#requiredSimulator();
|
|
171
|
+
const revision = this.#conversationRevision;
|
|
172
|
+
const state = await simulator.state({ signal });
|
|
173
|
+
if (!this.#resetting && revision === this.#conversationRevision && simulator === this.#simulator) {
|
|
174
|
+
this.#observeSimulatorState(state);
|
|
175
|
+
}
|
|
176
|
+
return this.simulatorSnapshot();
|
|
177
|
+
}
|
|
178
|
+
async resetSimulator() {
|
|
179
|
+
if (this.#resetting || this.#sendingMessage || this.#simulatorState.activeRun) {
|
|
180
|
+
throw Object.assign(new Error("\u8BF7\u7B49\u5F85\u5F53\u524D\u56DE\u590D\u6216\u64CD\u4F5C\u5B8C\u6210\u540E\u518D\u6E05\u7A7A"), { status: 409, code: "SIMULATOR_BUSY" });
|
|
181
|
+
}
|
|
182
|
+
const simulator = this.#requiredSimulator();
|
|
183
|
+
if (!simulator.reset) {
|
|
184
|
+
throw Object.assign(new Error("\u5F53\u524D\u5E73\u53F0\u6682\u4E0D\u652F\u6301\u6E05\u7A7A\u5BF9\u8BDD"), { status: 501, code: "RESET_UNSUPPORTED", publicMessage: "\u5F53\u524D\u5E73\u53F0\u6682\u4E0D\u652F\u6301\u6E05\u7A7A\u5BF9\u8BDD" });
|
|
185
|
+
}
|
|
186
|
+
this.#resetting = true;
|
|
187
|
+
try {
|
|
188
|
+
await simulator.reset();
|
|
189
|
+
this.#conversationRevision++;
|
|
190
|
+
this.#stopOutputWatchers();
|
|
191
|
+
this.#runs.clear();
|
|
192
|
+
this.#observedActiveRuns.clear();
|
|
193
|
+
this.#events.length = 0;
|
|
194
|
+
this.#runOrdinal = 0;
|
|
195
|
+
this.#lastActiveRunId = void 0;
|
|
196
|
+
this.#messages = Object.freeze([]);
|
|
197
|
+
this.#simulatorState = Object.freeze({ messages: this.#messages });
|
|
198
|
+
this.#notifySimulator();
|
|
199
|
+
return this.simulatorSnapshot();
|
|
200
|
+
} finally {
|
|
201
|
+
this.#resetting = false;
|
|
202
|
+
}
|
|
165
203
|
}
|
|
166
204
|
async sendSimulatorMessage(input, signal) {
|
|
167
|
-
|
|
168
|
-
this.#
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
205
|
+
if (this.#resetting || this.#sendingMessage) throw Object.assign(new Error("\u6A21\u62DF\u5668\u6B63\u5728\u5904\u7406\u5176\u4ED6\u64CD\u4F5C"), { status: 409, code: "SIMULATOR_BUSY" });
|
|
206
|
+
this.#sendingMessage = true;
|
|
207
|
+
try {
|
|
208
|
+
const started = this.#now();
|
|
209
|
+
this.#record({ channel: "client", type: "message.send", summary: "\u53D1\u9001\u4E00\u6761\u79C1\u804A\u6D88\u606F" });
|
|
210
|
+
const accepted = await this.#requiredSimulator().send(input, { signal });
|
|
211
|
+
if (this.#runs.has(accepted.runId)) return accepted;
|
|
212
|
+
const acceptedAt = this.#now();
|
|
213
|
+
const latency = Math.max(0, acceptedAt.getTime() - started.getTime());
|
|
214
|
+
this.#upsertRun({
|
|
215
|
+
runId: accepted.runId,
|
|
216
|
+
messageId: accepted.messageId,
|
|
217
|
+
status: "accepted",
|
|
218
|
+
startedAt: started.toISOString(),
|
|
219
|
+
updatedAt: acceptedAt.toISOString(),
|
|
220
|
+
acceptLatencyMs: latency
|
|
221
|
+
});
|
|
222
|
+
this.#lastActiveRunId = accepted.runId;
|
|
223
|
+
this.#record({
|
|
224
|
+
channel: "app_server",
|
|
225
|
+
type: "run.accepted",
|
|
226
|
+
summary: "App Server \u5DF2\u63A5\u53D7\u6D88\u606F\uFF0C\u5DF2\u8BB0\u5F55\u53D1\u9001\u56DE\u6267",
|
|
227
|
+
runId: accepted.runId,
|
|
228
|
+
durationMs: latency
|
|
229
|
+
});
|
|
230
|
+
this.#simulatorState = Object.freeze({
|
|
231
|
+
messages: Object.freeze([
|
|
232
|
+
...this.#simulatorState.messages.filter((message2) => message2.messageId !== accepted.messageId),
|
|
233
|
+
Object.freeze({
|
|
234
|
+
messageId: accepted.messageId,
|
|
235
|
+
role: "user",
|
|
236
|
+
text: input.text,
|
|
237
|
+
createdAt: acceptedAt.toISOString()
|
|
238
|
+
})
|
|
239
|
+
]),
|
|
240
|
+
latestRun: Object.freeze({ runId: accepted.runId, status: "pending" }),
|
|
241
|
+
activeRun: Object.freeze({ runId: accepted.runId, status: "pending" })
|
|
242
|
+
});
|
|
243
|
+
this.#messages = this.#simulatorState.messages;
|
|
244
|
+
this.#notifySimulator();
|
|
245
|
+
this.#startOutputWatcher(this.#requiredSimulator(), accepted.runId);
|
|
246
|
+
return accepted;
|
|
247
|
+
} finally {
|
|
248
|
+
this.#sendingMessage = false;
|
|
249
|
+
}
|
|
206
250
|
}
|
|
207
251
|
async cancelSimulatorRun(runId, signal) {
|
|
208
252
|
this.#record({
|
|
@@ -388,7 +432,10 @@ var PreviewController = class {
|
|
|
388
432
|
this.#outputWatchers.set(runId, controller);
|
|
389
433
|
void simulator.watchOutput(runId, {
|
|
390
434
|
signal: controller.signal,
|
|
391
|
-
onEvent: (event) =>
|
|
435
|
+
onEvent: (event) => {
|
|
436
|
+
if (this.#resetting || simulator !== this.#simulator) return;
|
|
437
|
+
return this.#observeOutputEvent(event);
|
|
438
|
+
}
|
|
392
439
|
}).catch((cause) => {
|
|
393
440
|
if (controller.signal.aborted) return;
|
|
394
441
|
this.#failedOutputRuns.add(runId);
|
|
@@ -487,7 +534,7 @@ var PreviewController = class {
|
|
|
487
534
|
}
|
|
488
535
|
#notifySimulator() {
|
|
489
536
|
if (this.#simulatorListeners.size === 0) return;
|
|
490
|
-
const value = Object.freeze({ state: this
|
|
537
|
+
const value = Object.freeze({ state: this.simulatorSnapshot(), debug: this.debugSnapshot() });
|
|
491
538
|
for (const listener of this.#simulatorListeners) {
|
|
492
539
|
try {
|
|
493
540
|
listener(value);
|
|
@@ -688,8 +735,8 @@ function requestFailure(cause) {
|
|
|
688
735
|
function publicProject(config) {
|
|
689
736
|
return {
|
|
690
737
|
buddyId: config.buddyId,
|
|
691
|
-
|
|
692
|
-
|
|
738
|
+
...config.model === void 0 ? {} : { model: config.model },
|
|
739
|
+
datasets: (config.datasets ?? []).map(({ id, purpose }) => ({ id, purpose }))
|
|
693
740
|
};
|
|
694
741
|
}
|
|
695
742
|
async function startPreviewControlServer(options) {
|
|
@@ -810,6 +857,20 @@ data: ${JSON.stringify({
|
|
|
810
857
|
request.once("close", () => listeners.delete(response));
|
|
811
858
|
return;
|
|
812
859
|
}
|
|
860
|
+
if (request.method === "POST" && options.controller.resetting) {
|
|
861
|
+
return apiError(response, 409, "SIMULATOR_BUSY", "\u6B63\u5728\u6E05\u7A7A\u5BF9\u8BDD\u5E76\u91CD\u542F DEV\uFF0C\u8BF7\u7A0D\u5019");
|
|
862
|
+
}
|
|
863
|
+
if (request.method === "POST" && url.pathname === "/api/simulator/reset") {
|
|
864
|
+
try {
|
|
865
|
+
const body = exactObject(await readJsonBody(request), ["confirm"]);
|
|
866
|
+
if (body?.confirm !== true) return apiError(response, 400, "RESET_CONFIRMATION_REQUIRED", "\u8BF7\u786E\u8BA4\u6E05\u7A7A\u5F53\u524D\u5F00\u53D1\u7248\u5BF9\u8BDD");
|
|
867
|
+
const state = await options.controller.resetSimulator();
|
|
868
|
+
return json(response, 200, { state, dev: options.controller.state(), debug: options.controller.debugSnapshot() });
|
|
869
|
+
} catch (cause) {
|
|
870
|
+
const failure = requestFailure(cause);
|
|
871
|
+
return apiError(response, failure.status, failure.code, failure.message);
|
|
872
|
+
}
|
|
873
|
+
}
|
|
813
874
|
if (request.method === "POST" && url.pathname === "/api/dev/start") {
|
|
814
875
|
if (Number(request.headers["content-length"] ?? 0) > 0) {
|
|
815
876
|
return apiError(response, 400, "BODY_NOT_ALLOWED", "\u8BE5\u64CD\u4F5C\u4E0D\u63A5\u53D7\u8BF7\u6C42\u6B63\u6587");
|
|
@@ -1205,6 +1266,8 @@ var MlbSimulatorClient = class {
|
|
|
1205
1266
|
#accessToken;
|
|
1206
1267
|
#fetch;
|
|
1207
1268
|
#sending = false;
|
|
1269
|
+
#resetTarget;
|
|
1270
|
+
#resetArchived = false;
|
|
1208
1271
|
#lastSend;
|
|
1209
1272
|
#privateId;
|
|
1210
1273
|
#privatePromise;
|
|
@@ -1230,6 +1293,7 @@ var MlbSimulatorClient = class {
|
|
|
1230
1293
|
return details;
|
|
1231
1294
|
}
|
|
1232
1295
|
async state(options = {}) {
|
|
1296
|
+
this.#assertResetComplete();
|
|
1233
1297
|
const privateId = await this.#ensurePrivate(options.signal);
|
|
1234
1298
|
const value = await this.#request("GET", `/app/privates/${encodeURIComponent(privateId)}`, {
|
|
1235
1299
|
signal: options.signal
|
|
@@ -1271,6 +1335,7 @@ var MlbSimulatorClient = class {
|
|
|
1271
1335
|
if (typeof input.text !== "string" || !input.text.trim() || Buffer.byteLength(input.text, "utf8") > 32 * 1024) {
|
|
1272
1336
|
throw new TypeError("message text is invalid");
|
|
1273
1337
|
}
|
|
1338
|
+
this.#assertResetComplete();
|
|
1274
1339
|
const idempotencyKey = safeText(input.idempotencyKey, "idempotencyKey", 128);
|
|
1275
1340
|
if (this.#lastSend?.key === idempotencyKey) {
|
|
1276
1341
|
if (this.#lastSend.text !== input.text.trim()) throw httpError(409, { error: "\u540C\u4E00\u6761\u6D88\u606F\u4E0D\u80FD\u6539\u5199\u5185\u5BB9" });
|
|
@@ -1327,6 +1392,53 @@ var MlbSimulatorClient = class {
|
|
|
1327
1392
|
this.#sending = false;
|
|
1328
1393
|
}
|
|
1329
1394
|
}
|
|
1395
|
+
#assertResetComplete() {
|
|
1396
|
+
if (this.#resetTarget) throw Object.assign(new Error("\u8BF7\u518D\u6B21\u70B9\u51FB\u6E05\u7A7A\u5BF9\u8BDD\uFF0C\u5B8C\u6210\u65B0\u4F1A\u8BDD\u521B\u5EFA"), {
|
|
1397
|
+
code: "RESET_INCOMPLETE",
|
|
1398
|
+
status: 409,
|
|
1399
|
+
publicMessage: "\u4F1A\u8BDD\u91CD\u7F6E\u5C1A\u672A\u5B8C\u6210\uFF0C\u8BF7\u518D\u6B21\u70B9\u51FB\u300C\u6E05\u7A7A\u5BF9\u8BDD\u300D\u91CD\u8BD5"
|
|
1400
|
+
});
|
|
1401
|
+
}
|
|
1402
|
+
async reset(options = {}) {
|
|
1403
|
+
if (this.#sending) throw httpError(409, { error: "\u6D88\u606F\u6B63\u5728\u53D1\u9001\uFF0C\u8BF7\u7A0D\u540E\u6E05\u7A7A" });
|
|
1404
|
+
if (!this.#resetTarget) {
|
|
1405
|
+
const privateId = await this.#ensurePrivate(options.signal);
|
|
1406
|
+
const current = object(await this.#request("GET", `/app/privates/${encodeURIComponent(privateId)}`, options));
|
|
1407
|
+
const conversation = object(current?.private);
|
|
1408
|
+
if (conversation?.id !== privateId || conversation?.buddyId !== this.#buddyId || typeof current?.replying !== "boolean") {
|
|
1409
|
+
throw httpError(502, { error: "\u65E0\u6CD5\u786E\u8BA4\u5F53\u524D\u79C1\u804A\u72B6\u6001\uFF0C\u672A\u6E05\u7A7A\u5BF9\u8BDD" });
|
|
1410
|
+
}
|
|
1411
|
+
if (current.replying) throw httpError(409, { error: "\u8BF7\u7B49\u5F85\u5F53\u524D\u56DE\u590D\u5B8C\u6210\u540E\u518D\u6E05\u7A7A" });
|
|
1412
|
+
this.#resetTarget = privateId;
|
|
1413
|
+
}
|
|
1414
|
+
try {
|
|
1415
|
+
if (!this.#resetArchived) {
|
|
1416
|
+
const receipt = object(await this.#request("DELETE", `/app/privates/${encodeURIComponent(this.#resetTarget)}`, options));
|
|
1417
|
+
if (receipt?.ok !== true) throw httpError(502, { error: "\u65E0\u6CD5\u786E\u8BA4\u65E7\u4F1A\u8BDD\u5DF2\u7ED3\u675F" });
|
|
1418
|
+
this.#resetArchived = true;
|
|
1419
|
+
this.#privateId = void 0;
|
|
1420
|
+
}
|
|
1421
|
+
const nextId = await this.#ensurePrivate(options.signal);
|
|
1422
|
+
if (nextId === this.#resetTarget) {
|
|
1423
|
+
this.#privateId = void 0;
|
|
1424
|
+
throw httpError(502, { error: "MLB \u672A\u8FD4\u56DE\u65B0\u7684\u4F1A\u8BDD\u8EAB\u4EFD" });
|
|
1425
|
+
}
|
|
1426
|
+
} catch (cause) {
|
|
1427
|
+
const detail = object(cause)?.publicMessage;
|
|
1428
|
+
throw Object.assign(new Error("\u4F1A\u8BDD\u91CD\u7F6E\u5C1A\u672A\u5B8C\u6210", { cause }), {
|
|
1429
|
+
code: "RESET_INCOMPLETE",
|
|
1430
|
+
status: 502,
|
|
1431
|
+
publicMessage: `${this.#resetArchived ? "\u65E7\u4F1A\u8BDD\u5DF2\u7ED3\u675F\uFF0C\u65B0\u4F1A\u8BDD\u521B\u5EFA\u672A\u5B8C\u6210" : "\u5C1A\u672A\u786E\u8BA4\u65E7\u4F1A\u8BDD\u5DF2\u7ED3\u675F"}\uFF0C\u8BF7\u518D\u6B21\u70B9\u51FB\u300C\u6E05\u7A7A\u5BF9\u8BDD\u300D\u91CD\u8BD5\u3002${typeof detail === "string" ? `\uFF08${detail}\uFF09` : ""}`
|
|
1432
|
+
});
|
|
1433
|
+
}
|
|
1434
|
+
this.#active = void 0;
|
|
1435
|
+
this.#latest = void 0;
|
|
1436
|
+
this.#streaming = void 0;
|
|
1437
|
+
this.#lastSend = void 0;
|
|
1438
|
+
this.#messages = Object.freeze([]);
|
|
1439
|
+
this.#resetTarget = void 0;
|
|
1440
|
+
this.#resetArchived = false;
|
|
1441
|
+
}
|
|
1330
1442
|
async cancel(_runId, _options = {}) {
|
|
1331
1443
|
throw Object.assign(new Error("\u5F53\u524D MLB \u534F\u8BAE\u5C1A\u672A\u63D0\u4F9B\u7EC8\u6B62\u56DE\u590D\u63A5\u53E3"), {
|
|
1332
1444
|
code: "TURN_CANCEL_UNSUPPORTED",
|