neoctl 0.2.49 → 0.2.50

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.
@@ -60,6 +60,9 @@ export type AgentEvent = {
60
60
  } | {
61
61
  type: "context.metrics";
62
62
  metrics: ContextMetrics;
63
+ } | {
64
+ type: "context.compaction.delta";
65
+ text: string;
63
66
  } | {
64
67
  type: "context.compacted";
65
68
  compaction: CompactionReport;
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env node
2
+ import { type SessionPageOptions } from "../session/session-pagination.js";
2
3
  import { type ToolInputChange } from "../model/tool-input-stream.js";
3
4
  import { type ToolActivity } from "./tool-activity.js";
4
5
  import type { TimingRecord } from "../core/query-timing.js";
@@ -210,6 +211,7 @@ type WebActionResult<T extends object = object> = ({
210
211
  ok: true;
211
212
  } & T) | WebActionFailure;
212
213
  interface UiStatus {
214
+ compactionText?: string;
213
215
  modelOutput?: {
214
216
  kind: "text";
215
217
  } | {
@@ -800,9 +802,17 @@ export declare class WebRepl {
800
802
  }>;
801
803
  private enqueueInput;
802
804
  private startRun;
803
- listSessions(): Promise<{
805
+ listSessions(options?: SessionPageOptions): Promise<{
806
+ runningSessionIds: string[];
804
807
  sessions: import("../index.js").SessionSummary[];
808
+ total: number;
809
+ totalCount: number;
810
+ page: number;
811
+ pageSize: number;
812
+ totalPages: number;
813
+ } | {
805
814
  runningSessionIds: string[];
815
+ sessions: import("../index.js").SessionSummary[];
806
816
  }>;
807
817
  resumeSession(sessionId: string): Promise<WebActionResult>;
808
818
  newSession(): Promise<WebActionResult>;
package/dist/web/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env node
2
+ import { paginateSessions, sessionPageOptions } from "../session/session-pagination.js";
2
3
  import { applyToolInputChanges } from "../model/tool-input-stream.js";
3
4
  import { toolActivity } from "./tool-activity.js";
4
5
  import { toolObservationResult } from "./tool-observation-result.js";
@@ -1097,10 +1098,10 @@ export class WebRepl {
1097
1098
  this.foregroundRun = undefined;
1098
1099
  }).catch(() => undefined);
1099
1100
  }
1100
- async listSessions() {
1101
+ async listSessions(options) {
1101
1102
  const sessions = await this.runtime.engine.listSessions(Number.POSITIVE_INFINITY);
1102
1103
  const runningSessionIds = [...this.backgroundSessionRuns.keys()];
1103
- return { sessions, runningSessionIds };
1104
+ return { ...(options ? paginateSessions(sessions, options) : { sessions }), runningSessionIds };
1104
1105
  }
1105
1106
  async resumeSession(sessionId) {
1106
1107
  if (!sessionId)
@@ -1347,11 +1348,15 @@ export class WebRepl {
1347
1348
  if (showProgress) {
1348
1349
  this.compactingSession = engine;
1349
1350
  this.busy = true;
1350
- this.setStatus({ ...this.status, phase: "compacting", detail: "manualcompact: generating context summary", activityTick: this.status.activityTick + 1 });
1351
+ this.setStatus({ ...this.status, phase: "compacting", compactionText: "", detail: "manualcompact: generating context summary", activityTick: this.status.activityTick + 1 });
1351
1352
  }
1352
1353
  try {
1353
1354
  // An idle click executes now through the settings barrier, not the chat/input queue.
1354
- const result = await engine.updateSessionSettings({ compact: true }, { abortSignal: controller?.signal });
1355
+ const result = await engine.updateSessionSettings({ compact: true }, { abortSignal: controller?.signal, onCompactionDelta: text => {
1356
+ if (showProgress && this.runtime.engine === engine && this.foregroundRunToken === runToken && !controller?.signal.aborted) {
1357
+ this.handleEvent({ type: "context.compaction.delta", text });
1358
+ }
1359
+ } });
1355
1360
  if (this.runtime.engine === engine && this.foregroundRunToken === runToken) {
1356
1361
  if (result.compaction?.report)
1357
1362
  this.appendCompaction(result.compaction.report);
@@ -1545,6 +1550,8 @@ export class WebRepl {
1545
1550
  this.broadcastSync();
1546
1551
  }
1547
1552
  setStatus(next) {
1553
+ if (next.phase !== "compacting")
1554
+ next = { ...next, compactionText: undefined };
1548
1555
  const waiting = next.phase === "calling_model" && !next.modelOutput;
1549
1556
  const wasWaiting = this.status.phase === "calling_model" && !this.status.modelOutput;
1550
1557
  next = { ...next, responseWaitStartedAt: waiting
@@ -2002,6 +2009,10 @@ export class WebRepl {
2002
2009
  this.liveToolLineIds.set(event.toolUse.id, this.append(patch));
2003
2010
  return;
2004
2011
  }
2012
+ if (event.type === "context.compaction.delta") {
2013
+ this.queueDeltaStatus();
2014
+ return;
2015
+ }
2005
2016
  if (event.type === "tool_call.delta") {
2006
2017
  this.queueDeltaStatus();
2007
2018
  return;
@@ -2336,10 +2347,13 @@ export class WebRepl {
2336
2347
  this.activeAbortController = abortController;
2337
2348
  this.interruptArmed = false;
2338
2349
  this.setBusy(true);
2339
- this.setStatus({ ...this.status, phase: "compacting", detail: type === "compact" ? "manual compact" : "pure compact", activityTick: this.status.activityTick + 1 });
2350
+ this.setStatus({ ...this.status, phase: "compacting", compactionText: "", detail: type === "compact" ? "manual compact" : "pure compact", activityTick: this.status.activityTick + 1 });
2340
2351
  try {
2341
2352
  const result = type === "compact"
2342
- ? await this.runtime.engine.compact({ abortSignal: abortController.signal })
2353
+ ? await this.runtime.engine.compact({ abortSignal: abortController.signal, onCompactionDelta: text => {
2354
+ if (this.foregroundRunToken === runToken && !abortController.signal.aborted)
2355
+ this.handleEvent({ type: "context.compaction.delta", text });
2356
+ } })
2343
2357
  : await this.runtime.engine.pureCompact({ abortSignal: abortController.signal });
2344
2358
  if (this.foregroundRunToken !== runToken)
2345
2359
  return;
@@ -2755,7 +2769,7 @@ export async function handleWebRequest(req, res, router) {
2755
2769
  if (req.method === "POST" && url.pathname === "/api/queue/send-now")
2756
2770
  return sendJson(res, await repl.sendQueuedNow());
2757
2771
  if (req.method === "GET" && url.pathname === "/api/sessions")
2758
- return sendJson(res, await repl.listSessions());
2772
+ return sendJson(res, await repl.listSessions(sessionPageOptions(url.searchParams)));
2759
2773
  if (req.method === "POST" && url.pathname === "/api/sessions/resume") {
2760
2774
  const body = await readJsonBody(req);
2761
2775
  return sendJson(res, await repl.resumeSession(String(body.sessionId ?? "")));
@@ -3115,8 +3129,10 @@ function toolStreamStepStatus(phase) {
3115
3129
  return "running";
3116
3130
  }
3117
3131
  function reduceStatus(status, event) {
3132
+ if (event.type === "context.compaction.delta")
3133
+ return { ...status, phase: "compacting", compactionText: (status.compactionText || "") + event.text, activityTick: status.activityTick + 1 };
3118
3134
  if (event.type === "state")
3119
- return { ...status, phase: event.phase, detail: event.detail, modelOutput: undefined, currentTool: event.phase === "running_tools" ? status.currentTool : undefined, usage: event.phase === "preparing" ? undefined : status.usage, streamedOutputTokens: event.phase === "preparing" ? 0 : status.streamedOutputTokens, inputTokenUpdatedAt: event.phase === "preparing" ? undefined : status.inputTokenUpdatedAt, outputTokenUpdatedAt: event.phase === "preparing" ? undefined : status.outputTokenUpdatedAt, retryCooldownUntil: event.phase === "preparing" ? undefined : status.retryCooldownUntil, activityTick: status.activityTick + 1 };
3135
+ return { ...status, phase: event.phase, detail: event.detail, compactionText: event.phase === "compacting" && status.phase === "compacting" ? status.compactionText : undefined, modelOutput: undefined, currentTool: event.phase === "running_tools" ? status.currentTool : undefined, usage: event.phase === "preparing" ? undefined : status.usage, streamedOutputTokens: event.phase === "preparing" ? 0 : status.streamedOutputTokens, inputTokenUpdatedAt: event.phase === "preparing" ? undefined : status.inputTokenUpdatedAt, outputTokenUpdatedAt: event.phase === "preparing" ? undefined : status.outputTokenUpdatedAt, retryCooldownUntil: event.phase === "preparing" ? undefined : status.retryCooldownUntil, activityTick: status.activityTick + 1 };
3120
3136
  if (event.type === "context.compacted")
3121
3137
  return { ...status, phase: "compacting", detail: formatCompactionReportSummary(event.compaction), activityTick: status.activityTick + 1 };
3122
3138
  if (event.type === "context.metrics")