oasis_test 0.1.37 → 0.1.39

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.
Files changed (2) hide show
  1. package/dist/index.js +162 -46
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -25136,10 +25136,12 @@ async function startOasisServer(opts) {
25136
25136
  if (!body.actorId) {
25137
25137
  throw new ApiError(400, "CHAT_ACTOR_REQUIRED", "\u8111\u66B4\u5BF9\u8BDD\u5FC5\u987B\u9009\u62E9\u4E00\u4E2A\u6570\u5B57\u5458\u5DE5");
25138
25138
  }
25139
+ const inheritedRuntimeSessionId = !body.sessionId && body.chatSessionId && opts.chatSession ? await opts.chatSession.getSession(body.chatSessionId).catch(() => null).then((s2) => s2 && s2.humanActorId === actor ? s2.runtimeSessionId ?? void 0 : void 0) : void 0;
25140
+ const effectiveSessionId = body.sessionId ?? inheritedRuntimeSessionId;
25139
25141
  const session = await opts.dispatchChat({
25140
25142
  actorId: body.actorId,
25141
25143
  message: body.message,
25142
- ...body.sessionId ? { sessionId: body.sessionId } : {},
25144
+ ...effectiveSessionId ? { sessionId: effectiveSessionId } : {},
25143
25145
  ...body.chatSessionId ? { chatSessionId: body.chatSessionId } : {},
25144
25146
  ...body.workspace ? { workspace: body.workspace } : {},
25145
25147
  ...currentCompanyId !== void 0 ? { companyId: currentCompanyId } : {},
@@ -25164,26 +25166,52 @@ async function startOasisServer(opts) {
25164
25166
  ...persistAttachments.length ? { attachments: persistAttachments } : {}
25165
25167
  }).catch(() => void 0);
25166
25168
  }
25169
+ let assistantMsgId;
25170
+ if (chatStore && persistTarget) {
25171
+ const { randomUUID: randomUUID19 } = await import("node:crypto");
25172
+ const id = randomUUID19();
25173
+ await chatStore.appendMessage({
25174
+ id,
25175
+ sessionId: persistTarget.id,
25176
+ role: "assistant",
25177
+ content: "",
25178
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
25179
+ status: "running",
25180
+ ...session.runId ? { runId: session.runId } : {}
25181
+ }).then(() => {
25182
+ assistantMsgId = id;
25183
+ }).catch(() => void 0);
25184
+ }
25167
25185
  let assistantText = "";
25168
25186
  let persisted = false;
25169
25187
  let live = null;
25170
25188
  const localParts = [];
25171
25189
  const collectedParts = () => (live ? live.bufferedParts() : localParts).filter((p2) => p2.type !== "done");
25172
- const finalizeAssistant = async () => {
25190
+ const finalizeAssistant = async (status = "done") => {
25173
25191
  if (persisted || !chatStore || !persistTarget) return;
25174
25192
  persisted = true;
25175
25193
  const parts = collectedParts();
25176
- if (!assistantText && !session.runId && parts.length === 0) return;
25177
- const { randomUUID: randomUUID19 } = await import("node:crypto");
25178
- await chatStore.appendMessage({
25179
- id: randomUUID19(),
25180
- sessionId: persistTarget.id,
25181
- role: "assistant",
25182
- content: assistantText,
25183
- createdAt: (/* @__PURE__ */ new Date()).toISOString(),
25184
- ...session.runId ? { runId: session.runId } : {},
25185
- ...parts.length ? { parts } : {}
25186
- }).catch(() => void 0);
25194
+ if (assistantMsgId) {
25195
+ await chatStore.updateMessage(assistantMsgId, {
25196
+ content: assistantText,
25197
+ status,
25198
+ ...parts.length ? { parts } : {},
25199
+ ...session.runId ? { runId: session.runId } : {}
25200
+ }).catch(() => void 0);
25201
+ } else {
25202
+ if (!assistantText && !session.runId && parts.length === 0) return;
25203
+ const { randomUUID: randomUUID19 } = await import("node:crypto");
25204
+ await chatStore.appendMessage({
25205
+ id: randomUUID19(),
25206
+ sessionId: persistTarget.id,
25207
+ role: "assistant",
25208
+ content: assistantText,
25209
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
25210
+ status,
25211
+ ...session.runId ? { runId: session.runId } : {},
25212
+ ...parts.length ? { parts } : {}
25213
+ }).catch(() => void 0);
25214
+ }
25187
25215
  await chatStore.updateSession(persistTarget.id, {
25188
25216
  // 优先落 runtime-native id(codex rollout / ACP session/new 返回),让下一轮 resume
25189
25217
  // 能命中 runtime 认可的 id;claude-code 等接受任意外部 id 的仍回退 session.id 兼容原行为。
@@ -25213,11 +25241,13 @@ async function startOasisServer(opts) {
25213
25241
  }
25214
25242
  }) : null;
25215
25243
  let localSeq = 0;
25244
+ let ckptDirty = false;
25216
25245
  const writeToRes = (part) => {
25217
25246
  if (!res.destroyed) res.write(`${JSON.stringify(part)}
25218
25247
  `);
25219
25248
  };
25220
25249
  const emit = (part) => {
25250
+ ckptDirty = true;
25221
25251
  if (live) return live.emit(part);
25222
25252
  const withSeq = { ...part, seq: ++localSeq };
25223
25253
  if (part.type !== "done") localParts.push(withSeq);
@@ -25233,6 +25263,13 @@ async function startOasisServer(opts) {
25233
25263
  });
25234
25264
  res.flushHeaders();
25235
25265
  stopKeepalive = startStreamKeepalive(res);
25266
+ const ckptTimer = setInterval(() => {
25267
+ if (!ckptDirty || !assistantMsgId || !chatStore) return;
25268
+ ckptDirty = false;
25269
+ const parts = collectedParts();
25270
+ void chatStore.updateMessage(assistantMsgId, { content: assistantText, status: "running", ...parts.length ? { parts } : {} }).catch(() => void 0);
25271
+ }, 2e3);
25272
+ ckptTimer.unref?.();
25236
25273
  if (live) detachViewer = live.subscribe(writeToRes);
25237
25274
  let sawTextOutput = false;
25238
25275
  session.onOutput((chunk) => {
@@ -25253,7 +25290,8 @@ async function startOasisServer(opts) {
25253
25290
  emit({ type: "error", text: err instanceof Error ? err.message : String(err) });
25254
25291
  }
25255
25292
  finished = true;
25256
- await finalizeAssistant();
25293
+ clearInterval(ckptTimer);
25294
+ await finalizeAssistant(errored ? "error" : "done");
25257
25295
  emit({ type: "done", sessionId: session.id });
25258
25296
  live?.finish(errored ? "error" : "done");
25259
25297
  stopKeepalive?.();
@@ -28896,6 +28934,17 @@ var init_dev_store = __esm({
28896
28934
  this.messages.set(m2.sessionId, list);
28897
28935
  return record5;
28898
28936
  }
28937
+ async updateMessage(id, patch) {
28938
+ for (const list of this.messages.values()) {
28939
+ const item = list.find((x2) => x2.id === id);
28940
+ if (!item) continue;
28941
+ if (patch.content !== void 0) item.content = patch.content;
28942
+ if (patch.parts !== void 0) item.parts = patch.parts;
28943
+ if (patch.status !== void 0) item.status = patch.status;
28944
+ if (patch.runId !== void 0) item.runId = patch.runId;
28945
+ return;
28946
+ }
28947
+ }
28899
28948
  async listMessages(sessionId, limit) {
28900
28949
  const list = (this.messages.get(sessionId) ?? []).sort((a, b2) => a.seq - b2.seq);
28901
28950
  return limit ? list.slice(-limit) : list;
@@ -28944,6 +28993,10 @@ var init_dev_store = __esm({
28944
28993
  this.save();
28945
28994
  return record5;
28946
28995
  }
28996
+ async updateMessage(id, patch) {
28997
+ await super.updateMessage(id, patch);
28998
+ this.save();
28999
+ }
28947
29000
  async linkWorkOrder(sessionId, workOrderId) {
28948
29001
  await super.linkWorkOrder(sessionId, workOrderId);
28949
29002
  this.save();
@@ -37926,6 +37979,31 @@ function codexSessionsRoot() {
37926
37979
  }
37927
37980
  return "";
37928
37981
  }
37982
+ function codexRolloutExists(sessionId, root = codexSessionsRoot()) {
37983
+ if (!sessionId || !root) return false;
37984
+ const suffix = `-${sessionId}.jsonl`;
37985
+ let hit = false;
37986
+ const walk = (d) => {
37987
+ if (hit) return;
37988
+ let ents;
37989
+ try {
37990
+ ents = fs8.readdirSync(d, { withFileTypes: true });
37991
+ } catch {
37992
+ return;
37993
+ }
37994
+ for (const ent of ents) {
37995
+ if (hit) return;
37996
+ const p2 = path8.join(d, ent.name);
37997
+ if (ent.isDirectory()) walk(p2);
37998
+ else if (ent.isFile() && ent.name.startsWith("rollout-") && ent.name.endsWith(suffix)) {
37999
+ hit = true;
38000
+ return;
38001
+ }
38002
+ }
38003
+ };
38004
+ walk(root);
38005
+ return hit;
38006
+ }
37929
38007
  function listRecentRollouts(root, sinceMs) {
37930
38008
  const margin = sinceMs - 6e4;
37931
38009
  const found = [];
@@ -38176,7 +38254,9 @@ var init_codex = __esm({
38176
38254
  const task = job.bundle.files["TASK.md"];
38177
38255
  if (!task) throw new Error("bundle \u7F3A TASK.md\uFF08\u88C5\u914D\u5668\u5951\u7EA6\uFF09");
38178
38256
  const prompt = job.systemPrompt ? ["# System Prompt", job.systemPrompt, "", "# Task", task].join("\n") : task;
38179
- const isResume = Boolean(job.resumeRuntimeSession && job.runtimeSessionId);
38257
+ const isResume = Boolean(
38258
+ job.resumeRuntimeSession && job.runtimeSessionId && codexRolloutExists(job.runtimeSessionId)
38259
+ );
38180
38260
  const args = [
38181
38261
  "exec",
38182
38262
  "-C",
@@ -40216,39 +40296,47 @@ function nodesDomain(deps) {
40216
40296
  if (msg.type !== "hello") return;
40217
40297
  const d = hub.connectedDaemons().find((c) => c.daemonId === daemonId);
40218
40298
  if (!d) return;
40219
- if (msg.meta.runtimes) {
40220
- const existing = await nodeStore.getNode(daemonId);
40221
- await nodeStore.upsertNode({
40222
- id: daemonId,
40223
- hostname: d.meta.hostname,
40224
- nodeVersion: d.meta.nodeVersion ?? "unknown",
40225
- status: "online",
40226
- // revives a previously soft-deleted node
40227
- lastSeenAt: now(),
40228
- enrolledAt: existing?.enrolledAt ?? now(),
40229
- ...d.meta.nodeName ? { name: d.meta.nodeName } : existing?.name ? { name: existing.name } : {}
40230
- });
40231
- for (const cap of msg.meta.runtimes) {
40232
- await nodeStore.addRuntimeIfAbsent({
40233
- id: `runtime:${daemonId}:${cap.kind}`,
40234
- nodeId: daemonId,
40235
- kind: cap.kind,
40299
+ try {
40300
+ if (msg.meta.runtimes) {
40301
+ const existing = await nodeStore.getNode(daemonId);
40302
+ await nodeStore.upsertNode({
40303
+ id: daemonId,
40236
40304
  hostname: d.meta.hostname,
40237
- ...cap.binary ? { binary: cap.binary } : {},
40238
- ...cap.version ? { version: cap.version } : {},
40305
+ nodeVersion: d.meta.nodeVersion ?? "unknown",
40239
40306
  status: "online",
40240
- lastSeenAt: now()
40307
+ // revives a previously soft-deleted node
40308
+ lastSeenAt: now(),
40309
+ enrolledAt: existing?.enrolledAt ?? now(),
40310
+ ...d.meta.nodeName ? { name: d.meta.nodeName } : existing?.name ? { name: existing.name } : {}
40241
40311
  });
40312
+ for (const cap of msg.meta.runtimes) {
40313
+ await nodeStore.addRuntimeIfAbsent({
40314
+ id: `runtime:${daemonId}:${cap.kind}`,
40315
+ nodeId: daemonId,
40316
+ kind: cap.kind,
40317
+ hostname: d.meta.hostname,
40318
+ ...cap.binary ? { binary: cap.binary } : {},
40319
+ ...cap.version ? { version: cap.version } : {},
40320
+ status: "online",
40321
+ lastSeenAt: now()
40322
+ });
40323
+ }
40324
+ await nodeStore.setNodeRuntimesOnline(daemonId, true);
40325
+ } else {
40326
+ await nodeStore.setNodeOnline(daemonId, true);
40327
+ await nodeStore.setNodeRuntimesOnline(daemonId, true);
40242
40328
  }
40243
- await nodeStore.setNodeRuntimesOnline(daemonId, true);
40244
- } else {
40245
- await nodeStore.setNodeOnline(daemonId, true);
40246
- await nodeStore.setNodeRuntimesOnline(daemonId, true);
40329
+ } catch (err) {
40330
+ console.warn(`[nodes] hello \u5904\u7406\u5931\u8D25(node=${daemonId})\uFF1A${err instanceof Error ? err.message : String(err)}`);
40247
40331
  }
40248
40332
  });
40249
40333
  hub.onDaemonDisconnected = async (daemonId) => {
40250
- await nodeStore.setNodeOnline(daemonId, false);
40251
- await nodeStore.setNodeRuntimesOnline(daemonId, false);
40334
+ try {
40335
+ await nodeStore.setNodeOnline(daemonId, false);
40336
+ await nodeStore.setNodeRuntimesOnline(daemonId, false);
40337
+ } catch (err) {
40338
+ console.warn(`[nodes] disconnect \u5904\u7406\u5931\u8D25(node=${daemonId})\uFF1A${err instanceof Error ? err.message : String(err)}`);
40339
+ }
40252
40340
  };
40253
40341
  }
40254
40342
  return (router) => {
@@ -54232,6 +54320,7 @@ var PostgresChatSessionStore = class _PostgresChatSessionStore {
54232
54320
  await pool.query(`ALTER TABLE "${s2}".chat_messages ADD COLUMN IF NOT EXISTS run_id text`);
54233
54321
  await pool.query(`ALTER TABLE "${s2}".chat_messages ADD COLUMN IF NOT EXISTS parts jsonb`);
54234
54322
  await pool.query(`ALTER TABLE "${s2}".chat_messages ADD COLUMN IF NOT EXISTS attachments jsonb`);
54323
+ await pool.query(`ALTER TABLE "${s2}".chat_messages ADD COLUMN IF NOT EXISTS status text`);
54235
54324
  await pool.query(`ALTER TABLE "${s2}".chat_sessions ADD COLUMN IF NOT EXISTS workspace text`);
54236
54325
  await pool.query(`
54237
54326
  WITH ranked AS (
@@ -54297,11 +54386,11 @@ var PostgresChatSessionStore = class _PostgresChatSessionStore {
54297
54386
  async appendMessage(m2) {
54298
54387
  const insert = async () => {
54299
54388
  const r = await this.pool.query(
54300
- `INSERT INTO ${this.s}.chat_messages (id, session_id, role, content, seq, created_at, run_id, parts, attachments)
54301
- SELECT $1,$2,$3,$4, COALESCE(MAX(seq),0)+1, $5,$6,$7,$8
54389
+ `INSERT INTO ${this.s}.chat_messages (id, session_id, role, content, seq, created_at, run_id, parts, attachments, status)
54390
+ SELECT $1,$2,$3,$4, COALESCE(MAX(seq),0)+1, $5,$6,$7,$8,$9
54302
54391
  FROM ${this.s}.chat_messages WHERE session_id = $2
54303
54392
  RETURNING seq`,
54304
- [m2.id, m2.sessionId, m2.role, m2.content, m2.createdAt, m2.runId ?? null, m2.parts !== void 0 ? JSON.stringify(m2.parts) : null, m2.attachments !== void 0 ? JSON.stringify(m2.attachments) : null]
54393
+ [m2.id, m2.sessionId, m2.role, m2.content, m2.createdAt, m2.runId ?? null, m2.parts !== void 0 ? JSON.stringify(m2.parts) : null, m2.attachments !== void 0 ? JSON.stringify(m2.attachments) : null, m2.status ?? null]
54305
54394
  );
54306
54395
  return Number(r.rows[0].seq);
54307
54396
  };
@@ -54315,6 +54404,29 @@ var PostgresChatSessionStore = class _PostgresChatSessionStore {
54315
54404
  }
54316
54405
  }
54317
54406
  }
54407
+ async updateMessage(id, patch) {
54408
+ const sets = [];
54409
+ const args = [];
54410
+ if (patch.content !== void 0) {
54411
+ args.push(patch.content);
54412
+ sets.push(`content = $${args.length}`);
54413
+ }
54414
+ if (patch.parts !== void 0) {
54415
+ args.push(JSON.stringify(patch.parts));
54416
+ sets.push(`parts = $${args.length}`);
54417
+ }
54418
+ if (patch.status !== void 0) {
54419
+ args.push(patch.status);
54420
+ sets.push(`status = $${args.length}`);
54421
+ }
54422
+ if (patch.runId !== void 0) {
54423
+ args.push(patch.runId);
54424
+ sets.push(`run_id = $${args.length}`);
54425
+ }
54426
+ if (sets.length === 0) return;
54427
+ args.push(id);
54428
+ await this.pool.query(`UPDATE ${this.s}.chat_messages SET ${sets.join(", ")} WHERE id = $${args.length}`, args);
54429
+ }
54318
54430
  async listMessages(sessionId, limit) {
54319
54431
  const limitClause = limit ? `LIMIT ${limit}` : "";
54320
54432
  const r = await this.pool.query(
@@ -54358,7 +54470,8 @@ var rowToMessage = (row) => ({
54358
54470
  createdAt: new Date(row.created_at).toISOString(),
54359
54471
  ...row.run_id != null ? { runId: row.run_id } : {},
54360
54472
  ...row.parts != null ? { parts: row.parts } : {},
54361
- ...row.attachments != null ? { attachments: row.attachments } : {}
54473
+ ...row.attachments != null ? { attachments: row.attachments } : {},
54474
+ ...row.status != null ? { status: row.status } : {}
54362
54475
  });
54363
54476
 
54364
54477
  // ../storage/src/postgres-nodes.ts
@@ -55062,6 +55175,9 @@ async function startServe(opts) {
55062
55175
  return service.listSkillFiles(skillId);
55063
55176
  }
55064
55177
  });
55178
+ process.on("unhandledRejection", (reason) => {
55179
+ console.error(`[serve] unhandledRejection\uFF08\u5DF2\u515C\u5E95\uFF0C\u4E0D\u5D29\u8FDB\u7A0B\uFF09\uFF1A${reason instanceof Error ? reason.stack ?? reason.message : String(reason)}`);
55180
+ });
55065
55181
  const server = await startOasisServer({
55066
55182
  kernel: engine.kernel,
55067
55183
  blobs: engine.blobs,
@@ -58005,7 +58121,7 @@ ${res.warning}`);
58005
58121
  }
58006
58122
 
58007
58123
  // src/index.ts
58008
- var PKG_VERSION = true ? "0.1.37" : "dev";
58124
+ var PKG_VERSION = true ? "0.1.39" : "dev";
58009
58125
  var OASIS_DIR = path18.join(os10.homedir(), ".oasis");
58010
58126
  var CONFIG_FILE = path18.join(OASIS_DIR, "node-config.json");
58011
58127
  var PID_FILE = path18.join(OASIS_DIR, "node.pid");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oasis_test",
3
- "version": "0.1.37",
3
+ "version": "0.1.39",
4
4
  "description": "Oasis node daemon + CLI — background daemon, auto-start, full server CLI",
5
5
  "bin": {
6
6
  "oasis": "./dist/index.js"