oasis_test 0.1.135 → 0.1.136

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 +121 -5
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -157798,9 +157798,12 @@ async function runProtocolSession(job, cfg) {
157798
157798
  unlockWorkdir(dir);
157799
157799
  touchMetaExit(dir, { at: (/* @__PURE__ */ new Date()).toISOString(), ...info.reason ? { reason: info.reason } : {}, runId: id });
157800
157800
  }
157801
+ const extras = cfg.exitExtras?.(state) ?? {};
157801
157802
  exited = {
157802
157803
  ...info,
157803
157804
  ...sid && !info.runtimeSessionId ? { runtimeSessionId: sid } : {},
157805
+ ...extras.usage && !info.usage ? { usage: extras.usage } : {},
157806
+ ...extras.model && !info.model ? { model: extras.model } : {},
157804
157807
  ...info.workdirRef ? {} : { workdirRef: dir },
157805
157808
  ...info.transcriptRef ? {} : { transcriptRef }
157806
157809
  };
@@ -157961,6 +157964,26 @@ var init_protocol_session = __esm({
157961
157964
  function codexNum(v2) {
157962
157965
  return typeof v2 === "number" && Number.isFinite(v2) ? v2 : 0;
157963
157966
  }
157967
+ function parseCodexAppServerTurnUsage(params) {
157968
+ const p2 = params;
157969
+ const last = p2?.tokenUsage?.last;
157970
+ if (!last || typeof last !== "object") return void 0;
157971
+ return {
157972
+ input: codexNum(last["inputTokens"]),
157973
+ cacheRead: codexNum(last["cachedInputTokens"]),
157974
+ cacheWrite: codexNum(last["cacheWriteInputTokens"]),
157975
+ output: codexNum(last["outputTokens"]) + codexNum(last["reasoningOutputTokens"])
157976
+ };
157977
+ }
157978
+ function addCodexBuckets(acc, add) {
157979
+ acc.input += add.input;
157980
+ acc.cacheRead += add.cacheRead;
157981
+ acc.cacheWrite += add.cacheWrite;
157982
+ acc.output += add.output;
157983
+ }
157984
+ function codexUsageFromBuckets(b2) {
157985
+ return usageFromBuckets(b2);
157986
+ }
157964
157987
  function parseCodexSessionId(lines) {
157965
157988
  const first = lines[0];
157966
157989
  if (!first) return void 0;
@@ -158445,7 +158468,17 @@ var init_codex = __esm({
158445
158468
  env: this.opts.env,
158446
158469
  runtimeKind: "codex",
158447
158470
  syncSkills: this.opts.syncSkills,
158448
- createState: () => ({ threadId: void 0, turnId: void 0, active: false, codex: createCodexNormalizeState() }),
158471
+ createState: () => ({
158472
+ threadId: void 0,
158473
+ turnId: void 0,
158474
+ active: false,
158475
+ codex: createCodexNormalizeState(),
158476
+ // 本次 run 的用量:逐轮累加 `thread/tokenUsage/updated` 的 `last`(见该解析函数注释)。
158477
+ usage: { input: 0, cacheRead: 0, cacheWrite: 0, output: 0 },
158478
+ sawUsage: false,
158479
+ // `thread/started` 会直接给出本会话 rollout 的绝对路径——取实际模型时不必再满盘搜。
158480
+ rolloutPath: void 0
158481
+ }),
158449
158482
  initialCommand: () => ({
158450
158483
  jsonrpc: "2.0",
158451
158484
  method: "initialize",
@@ -158494,6 +158527,14 @@ ${task}` : task;
158494
158527
  if (method === "thread/started") {
158495
158528
  const thread = params?.thread;
158496
158529
  if (typeof thread?.id === "string") state.threadId = thread.id;
158530
+ if (typeof thread?.path === "string") state.rolloutPath = thread.path;
158531
+ }
158532
+ if (method === "thread/tokenUsage/updated") {
158533
+ const turn = parseCodexAppServerTurnUsage(params);
158534
+ if (turn) {
158535
+ addCodexBuckets(state.usage, turn);
158536
+ state.sawUsage = true;
158537
+ }
158497
158538
  }
158498
158539
  if (method === "turn/started") {
158499
158540
  const turn = params?.turn;
@@ -158523,6 +158564,20 @@ ${task}` : task;
158523
158564
  return true;
158524
158565
  },
158525
158566
  runtimeSessionId: (state) => state.threadId,
158567
+ exitExtras: (state) => {
158568
+ let model;
158569
+ if (state.rolloutPath) {
158570
+ try {
158571
+ model = parseCodexModel(fs10.readFileSync(state.rolloutPath, "utf8").split("\n"));
158572
+ } catch {
158573
+ }
158574
+ }
158575
+ model ??= resolvedModel2;
158576
+ return {
158577
+ ...state.sawUsage ? { usage: codexUsageFromBuckets(state.usage) } : {},
158578
+ ...model ? { model } : {}
158579
+ };
158580
+ },
158526
158581
  async append(input, state, send) {
158527
158582
  if (!state.threadId || !state.turnId) return { accepted: false, reason: "rejected" };
158528
158583
  if (input.interrupt) {
@@ -199107,6 +199162,15 @@ function attachmentArgs(args) {
199107
199162
  ...typeof a.contentType === "string" ? { contentType: a.contentType } : {}
199108
199163
  }));
199109
199164
  }
199165
+ function coordinatorOfWorkspaceInKernel(kernel, workspaceId) {
199166
+ for (const artifact of kernel.model.artifacts.values()) {
199167
+ if (artifact.workspace !== workspaceId) continue;
199168
+ if (artifact.type !== "brief") continue;
199169
+ const raw = artifact.fields?.["manager"];
199170
+ if (typeof raw === "string" && raw) return raw;
199171
+ }
199172
+ return null;
199173
+ }
199110
199174
  function hasOpenHumanChangeRequest2(kernel, artifactId) {
199111
199175
  return hasOpenHumanChangeRequest(kernel.model, artifactId);
199112
199176
  }
@@ -202001,7 +202065,8 @@ async function startOasisServer(opts) {
202001
202065
  if (req.method === "GET" && /^\/api\/chat-sessions\/[^/]+\/stream$/.test(url.pathname)) {
202002
202066
  const sid = decodeURIComponent(url.pathname.split("/")[3] ?? "");
202003
202067
  const cs = await (await chatStoreNowOrNull())?.getSession(sid).catch(() => null) ?? null;
202004
- if (!cs || cs.humanActorId !== actor) {
202068
+ const canReadStream = !!cs && (cs.humanActorId === actor || !!cs.workspace && cs.aiActorId === coordinatorOfWorkspaceInKernel(engine.kernel, cs.workspace));
202069
+ if (!canReadStream) {
202005
202070
  res.writeHead(404, { "content-type": "application/json" }).end(JSON.stringify({ error: "CHAT_SESSION_NOT_FOUND" }));
202006
202071
  return;
202007
202072
  }
@@ -208731,6 +208796,10 @@ var init_dev_store = __esm({
208731
208796
  async listSessionsByAnalyzedRun(analyzedRunId) {
208732
208797
  return [...this.sessions.values()].filter((s2) => s2.analyzedRunId === analyzedRunId).sort((a, b2) => b2.touchedAt.localeCompare(a.touchedAt)).map((s2) => this.withQuality(s2));
208733
208798
  }
208799
+ /** 语义同 postgres 版:`workspace = ?`,排除分析/后台执行会话,touched_at 倒序。 */
208800
+ async listSessionsByWorkspace(workspace) {
208801
+ return [...this.sessions.values()].filter((s2) => s2.workspace === workspace && !s2.analyzedRunId && s2.visibility !== "internal").sort((a, b2) => b2.touchedAt.localeCompare(a.touchedAt)).map((s2) => this.withQuality(s2));
208802
+ }
208734
208803
  async listAllAnalysisSessions(opts = {}) {
208735
208804
  const limit = opts.limit ?? 100;
208736
208805
  const sorted = [...this.sessions.values()].filter((s2) => !!s2.analyzedRunId).sort((a, b2) => b2.touchedAt.localeCompare(a.touchedAt) || b2.id.localeCompare(a.id));
@@ -226811,6 +226880,29 @@ function createChatSessionsDomain(opts) {
226811
226880
  const n = Number(raw);
226812
226881
  return raw && Number.isInteger(n) && n > 0 ? n : 0;
226813
226882
  }
226883
+ function coordinatorOfWorkspace(workspaceId) {
226884
+ if (!opts.kernel) return null;
226885
+ let manager;
226886
+ for (const artifact of opts.kernel.model.artifacts.values()) {
226887
+ if (artifact.workspace !== workspaceId) continue;
226888
+ if (artifact.type !== "brief") continue;
226889
+ const raw = artifact.fields?.["manager"];
226890
+ if (typeof raw === "string" && raw) {
226891
+ manager = raw;
226892
+ break;
226893
+ }
226894
+ }
226895
+ return manager ? manager : null;
226896
+ }
226897
+ function ensureSessionReadable(session, actor) {
226898
+ if (!session) throw new ApiError(404, "NOT_FOUND", "session not found");
226899
+ if (session.humanActorId === actor) return session;
226900
+ if (session.workspace) {
226901
+ const coordinator = coordinatorOfWorkspace(session.workspace);
226902
+ if (coordinator && session.aiActorId === coordinator) return session;
226903
+ }
226904
+ throw new ApiError(404, "NOT_FOUND", "session not found");
226905
+ }
226814
226906
  async function listRecentTurns(store2, sessionId, turns) {
226815
226907
  if (turns <= 0) return { messages: await store2.listMessages(sessionId), hasMoreBefore: false };
226816
226908
  if (store2.listRecentTurns) return store2.listRecentTurns(sessionId, turns);
@@ -226911,8 +227003,7 @@ function createChatSessionsDomain(opts) {
226911
227003
  });
226912
227004
  router.get("/api/chat-sessions/:id", async (req) => {
226913
227005
  const store2 = await storeFor(req);
226914
- const session = await store2.getSession(req.params.id);
226915
- if (!session || session.humanActorId !== req.auth.actor) throw new ApiError(404, "NOT_FOUND", "session not found");
227006
+ const session = ensureSessionReadable(await store2.getSession(req.params.id), req.auth.actor);
226916
227007
  const [window2, curRuntimeId] = await Promise.all([
226917
227008
  listRecentTurns(store2, session.id, parseTurns(req.query?.get("turns"))),
226918
227009
  currentRuntimeId(session.aiActorId)
@@ -227156,6 +227247,15 @@ function createChatSessionsDomain(opts) {
227156
227247
  }
227157
227248
  return { status: 200, body: { items } };
227158
227249
  });
227250
+ router.get("/api/workorders/:workorderId/coordinator-chat-sessions", async (req) => {
227251
+ const workorderId = req.params["workorderId"];
227252
+ const coordinator = coordinatorOfWorkspace(workorderId);
227253
+ if (!coordinator) return { status: 200, body: { items: [] } };
227254
+ const store2 = await storeFor(req);
227255
+ const sessions = await store2.listSessionsByWorkspace(workorderId);
227256
+ const items = sessions.filter((s2) => s2.aiActorId === coordinator);
227257
+ return { status: 200, body: { items } };
227258
+ });
227159
227259
  router.get("/api/chat-sessions/:id/work-orders", async (req) => {
227160
227260
  const store2 = await storeFor(req);
227161
227261
  const session = await store2.getSession(req.params.id);
@@ -240076,6 +240176,22 @@ var init_postgres_chat_sessions = __esm({
240076
240176
  );
240077
240177
  return r.rows.map(rowToSessionWithQuality);
240078
240178
  }
240179
+ async listSessionsByWorkspace(workspace) {
240180
+ const r = await this.pool.query(
240181
+ `SELECT s.*, lm.status AS last_assistant_status, lm.content AS last_assistant_content
240182
+ FROM ${this.s}.chat_sessions s
240183
+ LEFT JOIN LATERAL (
240184
+ SELECT status, content FROM ${this.s}.chat_messages
240185
+ WHERE session_id = s.id AND role = 'assistant'
240186
+ ORDER BY seq DESC LIMIT 1
240187
+ ) lm ON TRUE
240188
+ WHERE s.company_id = $2 AND s.workspace = $1 AND s.analyzed_run_id IS NULL
240189
+ AND s.visibility IS DISTINCT FROM 'internal'
240190
+ ORDER BY s.touched_at DESC`,
240191
+ [workspace, this.companyId]
240192
+ );
240193
+ return r.rows.map(rowToSessionWithQuality);
240194
+ }
240079
240195
  async listSessionsByAnalyzedRun(analyzedRunId) {
240080
240196
  const r = await this.pool.query(
240081
240197
  `SELECT s.*, lm.status AS last_assistant_status, lm.content AS last_assistant_content
@@ -259272,7 +259388,7 @@ function shimScript() {
259272
259388
  }
259273
259389
 
259274
259390
  // src/index.ts
259275
- var PKG_VERSION = true ? "0.1.135" : "dev";
259391
+ var PKG_VERSION = true ? "0.1.136" : "dev";
259276
259392
  var LOCAL_BIN = localBin();
259277
259393
  var NPM_PREFIX = npmPrefix();
259278
259394
  var INSTANCE = DEFAULT_INSTANCE;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oasis_test",
3
- "version": "0.1.135",
3
+ "version": "0.1.136",
4
4
  "description": "Oasis node daemon + CLI — background daemon, auto-start, full server CLI",
5
5
  "bin": {
6
6
  "oasis": "./dist/index.js"