@nextclaw/server 0.17.0 → 0.17.2

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/dist/index.js CHANGED
@@ -2895,6 +2895,7 @@ function buildConfigView(config, options) {
2895
2895
  }
2896
2896
  return {
2897
2897
  companion: sanitizePublicConfigValue(config.companion, "companion", uiHints),
2898
+ productAnalytics: { ...config.productAnalytics },
2898
2899
  agents: sanitizePublicConfigValue(config.agents, "agents", uiHints),
2899
2900
  providers,
2900
2901
  search: buildSearchView(config),
@@ -3260,6 +3261,14 @@ function updateSecrets(configPath, patch) {
3260
3261
  refs: { ...next.secrets.refs }
3261
3262
  };
3262
3263
  }
3264
+ function updateProductAnalytics(configPath, patch) {
3265
+ const config = loadConfigOrDefault(configPath);
3266
+ if (Object.prototype.hasOwnProperty.call(patch, "enabled")) config.productAnalytics.enabled = Boolean(patch.enabled);
3267
+ if (patch.audience === "external" || patch.audience === "internal" || patch.audience === "qa") config.productAnalytics.audience = patch.audience;
3268
+ const next = ConfigSchema.parse(config);
3269
+ saveConfig(next, configPath);
3270
+ return { ...next.productAnalytics };
3271
+ }
3263
3272
  //#endregion
3264
3273
  //#region src/features/config/services/provider-connectivity.service.ts
3265
3274
  const PROVIDER_TEST_MAX_TOKENS = 16;
@@ -4228,6 +4237,13 @@ var ConfigRoutesController = class {
4228
4237
  await this.publishConfigUpdates(["secrets"]);
4229
4238
  return c.json(ok(result));
4230
4239
  };
4240
+ updateProductAnalytics = async (c) => {
4241
+ const body = await readJson(c.req.raw);
4242
+ if (!body.ok) return c.json(err("INVALID_BODY", "invalid json body"), 400);
4243
+ const result = updateProductAnalytics(this.options.configPath, body.data);
4244
+ await this.publishConfigUpdates(["productAnalytics"]);
4245
+ return c.json(ok(result));
4246
+ };
4231
4247
  updateRuntime = async (c) => {
4232
4248
  const body = await readJson(c.req.raw);
4233
4249
  if (!body.ok || !body.data || typeof body.data !== "object") return c.json(err("INVALID_BODY", "invalid json body"), 400);
@@ -5433,17 +5449,25 @@ function serializePayload(value) {
5433
5449
  return String(value);
5434
5450
  }
5435
5451
  }
5436
- function toolPayloadBytes(message) {
5452
+ function serializedBytes(value) {
5453
+ return Buffer.byteLength(serializePayload(value), "utf8");
5454
+ }
5455
+ function toolPayloadCost(message) {
5437
5456
  let bytes = 0;
5457
+ let toolCalls = 0;
5438
5458
  for (const part of message.parts) {
5439
5459
  if (part.type !== "tool-invocation") continue;
5460
+ toolCalls += 1;
5440
5461
  bytes += Buffer.byteLength(serializePayload(part.args), "utf8");
5441
5462
  bytes += Buffer.byteLength(serializePayload(part.result), "utf8");
5442
5463
  }
5443
- return bytes;
5464
+ return {
5465
+ bytes,
5466
+ toolCalls
5467
+ };
5444
5468
  }
5445
5469
  function isDeferrableMessage(message) {
5446
- return message.role === "assistant" && message.status === "final";
5470
+ return message.role === "assistant" && (message.status === "final" || message.status === "error");
5447
5471
  }
5448
5472
  function deferMessageToolPayload(message) {
5449
5473
  const tools = message.parts.filter((part) => part.type === "tool-invocation");
@@ -5476,14 +5500,16 @@ function deferMessageToolPayload(message) {
5476
5500
  };
5477
5501
  }
5478
5502
  function buildSessionMessageHistoryPayloadView(params) {
5479
- const { messageDetailCursors, messages } = params;
5480
- const messageBudgetBytes = params.messageBudgetBytes ?? 262144;
5481
- const pageBudgetBytes = params.pageBudgetBytes ?? 2097152;
5503
+ const { messageBudgetBytes: requestedMessageBudgetBytes, messageDetailCursors, messages, messageToolCallBudget: requestedMessageToolCallBudget, pageBudgetBytes: requestedPageBudgetBytes, pageToolCallBudget: requestedPageToolCallBudget } = params;
5504
+ const messageBudgetBytes = requestedMessageBudgetBytes ?? 262144;
5505
+ const pageBudgetBytes = requestedPageBudgetBytes ?? 2097152;
5506
+ const messageToolCallBudget = requestedMessageToolCallBudget ?? 12;
5507
+ const pageToolCallBudget = requestedPageToolCallBudget ?? 80;
5482
5508
  const candidates = messages.filter((message) => isDeferrableMessage(message) && Boolean(messageDetailCursors[message.id])).map((message) => ({
5483
5509
  message,
5484
- bytes: toolPayloadBytes(message)
5485
- })).filter((candidate) => candidate.bytes > 0);
5486
- const deferredIds = new Set(candidates.filter((candidate) => candidate.bytes > messageBudgetBytes).map((candidate) => candidate.message.id));
5510
+ ...toolPayloadCost(message)
5511
+ })).filter((candidate) => candidate.toolCalls > 0);
5512
+ const deferredIds = new Set(candidates.filter((candidate) => candidate.bytes > messageBudgetBytes || candidate.toolCalls > messageToolCallBudget).map((candidate) => candidate.message.id));
5487
5513
  let eagerPageBytes = candidates.reduce((total, candidate) => total + (deferredIds.has(candidate.message.id) ? 0 : candidate.bytes), 0);
5488
5514
  if (eagerPageBytes > pageBudgetBytes) {
5489
5515
  const remaining = candidates.filter((candidate) => !deferredIds.has(candidate.message.id)).sort((left, right) => right.bytes - left.bytes);
@@ -5493,12 +5519,41 @@ function buildSessionMessageHistoryPayloadView(params) {
5493
5519
  eagerPageBytes -= candidate.bytes;
5494
5520
  }
5495
5521
  }
5522
+ let eagerPageToolCalls = candidates.reduce((total, candidate) => total + (deferredIds.has(candidate.message.id) ? 0 : candidate.toolCalls), 0);
5523
+ if (eagerPageToolCalls > pageToolCallBudget) {
5524
+ const remaining = candidates.filter((candidate) => !deferredIds.has(candidate.message.id)).sort((left, right) => right.toolCalls - left.toolCalls || right.bytes - left.bytes);
5525
+ for (const candidate of remaining) {
5526
+ if (eagerPageToolCalls <= pageToolCallBudget) break;
5527
+ deferredIds.add(candidate.message.id);
5528
+ eagerPageToolCalls -= candidate.toolCalls;
5529
+ }
5530
+ }
5496
5531
  const deferredToolPayloads = Object.fromEntries([...deferredIds].map((messageId) => [messageId, { cursor: messageDetailCursors[messageId] }]));
5497
5532
  return {
5498
5533
  messages: messages.map((message) => deferredIds.has(message.id) ? deferMessageToolPayload(message) : message),
5499
5534
  deferredToolPayloads
5500
5535
  };
5501
5536
  }
5537
+ function compactSessionMessageHistoryPayloadView(params) {
5538
+ const { view } = params;
5539
+ const budgetBytes = params.budgetBytes ?? 24576;
5540
+ const minimumMessages = Math.max(1, Math.trunc(params.minimumMessages ?? 5));
5541
+ let startIndex = Math.max(0, view.messages.length - minimumMessages);
5542
+ let bytes = view.messages.slice(startIndex).reduce((total, message) => total + serializedBytes(message), 0);
5543
+ while (startIndex > 0) {
5544
+ const previousBytes = serializedBytes(view.messages[startIndex - 1]);
5545
+ if (bytes + previousBytes > budgetBytes) break;
5546
+ startIndex -= 1;
5547
+ bytes += previousBytes;
5548
+ }
5549
+ const messages = view.messages.slice(startIndex);
5550
+ const visibleIds = new Set(messages.map((message) => message.id));
5551
+ return {
5552
+ messages,
5553
+ deferredToolPayloads: Object.fromEntries(Object.entries(view.deferredToolPayloads).filter(([messageId]) => visibleIds.has(messageId))),
5554
+ startIndex
5555
+ };
5556
+ }
5502
5557
  //#endregion
5503
5558
  //#region src/features/sessions/controllers/sessions.controller.ts
5504
5559
  const DEFAULT_SESSION_MESSAGE_PAGE_SIZE = 40;
@@ -5601,21 +5656,30 @@ var NcpSessionRoutesController = class {
5601
5656
  throw error;
5602
5657
  }
5603
5658
  if (!page) return c.json(err("NOT_FOUND", `ncp session not found: ${sessionId}`), 404);
5604
- const historyPayload = c.req.query("toolPayload") === "summary" ? buildSessionMessageHistoryPayloadView({
5659
+ const useSummaryPayload = c.req.query("toolPayload") === "summary";
5660
+ const historyPayload = useSummaryPayload ? buildSessionMessageHistoryPayloadView({
5605
5661
  messages: page.messages,
5606
5662
  messageDetailCursors: page.messageDetailCursors
5607
5663
  }) : {
5608
5664
  messages: page.messages,
5609
5665
  deferredToolPayloads: {}
5610
5666
  };
5667
+ const compactHistoryPayload = useSummaryPayload && !c.req.query("cursor") && c.req.query("initialPayload") === "compact" ? compactSessionMessageHistoryPayloadView({ view: historyPayload }) : {
5668
+ ...historyPayload,
5669
+ startIndex: 0
5670
+ };
5671
+ const compactStartCursor = compactHistoryPayload.startIndex > 0 ? page.messageDetailCursors[page.messages[compactHistoryPayload.startIndex - 1]?.id ?? ""] ?? page.pageInfo.startCursor : page.pageInfo.startCursor;
5611
5672
  const payload = {
5612
5673
  sessionId,
5613
5674
  status: this.options.kernel.isSessionRunning(sessionId) ? "running" : "idle",
5614
- messages: historyPayload.messages,
5615
- ...Object.keys(historyPayload.deferredToolPayloads).length > 0 ? { deferredToolPayloads: historyPayload.deferredToolPayloads } : {},
5675
+ messages: compactHistoryPayload.messages,
5676
+ ...Object.keys(compactHistoryPayload.deferredToolPayloads).length > 0 ? { deferredToolPayloads: compactHistoryPayload.deferredToolPayloads } : {},
5616
5677
  ...page.contextWindow ? { contextWindow: page.contextWindow } : {},
5617
5678
  total: page.total,
5618
- pageInfo: page.pageInfo
5679
+ pageInfo: {
5680
+ startCursor: compactStartCursor,
5681
+ hasPreviousPage: page.pageInfo.hasPreviousPage || compactHistoryPayload.startIndex > 0
5682
+ }
5619
5683
  };
5620
5684
  return c.json(ok(payload));
5621
5685
  };
@@ -5655,15 +5719,35 @@ var NcpSessionRoutesController = class {
5655
5719
  if (!await this.options.kernel.sessionManager.getSession(sessionId)) return c.json(err("NOT_FOUND", `ncp session not found: ${sessionId}`), 404);
5656
5720
  const payload = {
5657
5721
  sessionId,
5658
- inputs: [...this.options.kernel.agentRunRequestManager.listQueuedInputs(sessionId)]
5722
+ inputs: [...this.options.kernel.agentRunRequestManager.pendingInputs.listQueuedInputs(sessionId)]
5723
+ };
5724
+ return c.json(ok(payload));
5725
+ };
5726
+ listSessionPendingInputs = async (c) => {
5727
+ const sessionId = decodeURIComponent(c.req.param("sessionId"));
5728
+ if (!await this.options.kernel.sessionManager.getSession(sessionId)) return c.json(err("NOT_FOUND", `ncp session not found: ${sessionId}`), 404);
5729
+ const payload = {
5730
+ sessionId,
5731
+ inputs: [...this.options.kernel.agentRunRequestManager.pendingInputs.listPendingInputs(sessionId)]
5659
5732
  };
5660
5733
  return c.json(ok(payload));
5661
5734
  };
5735
+ steerSessionQueuedInput = async (c) => {
5736
+ const sessionId = decodeURIComponent(c.req.param("sessionId"));
5737
+ const queuedInputId = decodeURIComponent(c.req.param("queuedInputId"));
5738
+ if (!await this.options.kernel.sessionManager.getSession(sessionId)) return c.json(err("NOT_FOUND", `ncp session not found: ${sessionId}`), 404);
5739
+ const result = await this.options.kernel.agentRunRequestManager.pendingInputs.steerQueuedInput(sessionId, queuedInputId);
5740
+ if (!result.ok) {
5741
+ if (result.reason === "not-found") return c.json(err("NOT_FOUND", `queued input not found in session ${sessionId}: ${queuedInputId}`), 404);
5742
+ return c.json(err("STEER_UNAVAILABLE", "The active runtime cannot accept this input at the next safe step."), 409);
5743
+ }
5744
+ return c.json(ok(result.input));
5745
+ };
5662
5746
  deleteSessionQueuedInput = async (c) => {
5663
5747
  const sessionId = decodeURIComponent(c.req.param("sessionId"));
5664
5748
  const queuedInputId = decodeURIComponent(c.req.param("queuedInputId"));
5665
5749
  if (!await this.options.kernel.sessionManager.getSession(sessionId)) return c.json(err("NOT_FOUND", `ncp session not found: ${sessionId}`), 404);
5666
- const removed = this.options.kernel.agentRunRequestManager.removeQueuedInput(sessionId, queuedInputId);
5750
+ const removed = this.options.kernel.agentRunRequestManager.pendingInputs.removeQueuedInput(sessionId, queuedInputId);
5667
5751
  if (!removed) return c.json(err("NOT_FOUND", `queued input not found in session ${sessionId}: ${queuedInputId}`), 404);
5668
5752
  return c.json(ok(removed));
5669
5753
  };
@@ -6208,6 +6292,7 @@ function statusForServiceAppError(code) {
6208
6292
  case "SERVICE_APP_ACTION_NOT_DECLARED": return 403;
6209
6293
  case "SERVICE_APP_ACTION_NOT_FOUND":
6210
6294
  case "SERVICE_APP_NOT_FOUND": return 404;
6295
+ case "SERVICE_APP_RUNTIME_FAILED": return 502;
6211
6296
  default: return 400;
6212
6297
  }
6213
6298
  }
@@ -6348,7 +6433,7 @@ var ServiceAppsRoutesController = class {
6348
6433
  if (isServiceAppError(error)) return c.json(err(error.code, error.message), statusForServiceAppError(error.code));
6349
6434
  if (isPanelAppError(error)) return c.json(err(error.code, error.message), 404);
6350
6435
  if (error instanceof Error && error.message === "panel app bridge session is required") return c.json(err("PANEL_APP_BRIDGE_SESSION_REQUIRED", error.message), 401);
6351
- throw error;
6436
+ return c.json(err("SERVICE_APP_REQUEST_FAILED", "The Service App request failed. Please retry."), 500);
6352
6437
  };
6353
6438
  };
6354
6439
  //#endregion
@@ -6593,6 +6678,16 @@ var UiRouteRegistry = class {
6593
6678
  "/api/ncp/sessions/:sessionId/queued-inputs/:queuedInputId",
6594
6679
  ncpSession.deleteSessionQueuedInput
6595
6680
  ],
6681
+ [
6682
+ "post",
6683
+ "/api/ncp/sessions/:sessionId/queued-inputs/:queuedInputId/steer",
6684
+ ncpSession.steerSessionQueuedInput
6685
+ ],
6686
+ [
6687
+ "get",
6688
+ "/api/ncp/sessions/:sessionId/pending-inputs",
6689
+ ncpSession.listSessionPendingInputs
6690
+ ],
6596
6691
  [
6597
6692
  "get",
6598
6693
  "/api/ncp/sessions/:sessionId/skills",
@@ -7130,6 +7225,11 @@ var UiRouteRegistry = class {
7130
7225
  "/api/config/secrets",
7131
7226
  config.updateSecrets
7132
7227
  ],
7228
+ [
7229
+ "put",
7230
+ "/api/config/product-analytics",
7231
+ config.updateProductAnalytics
7232
+ ],
7133
7233
  [
7134
7234
  "put",
7135
7235
  "/api/config/runtime",
@@ -7506,6 +7606,6 @@ async function startUiServer(gateway) {
7506
7606
  };
7507
7607
  }
7508
7608
  //#endregion
7509
- export { AppDataRoutesController, AppPackagesRoutesController, ConfigRoutesController, InboxDeliveriesRoutesController, PanelAppsRoutesController, RuntimeControlRoutesController, ServiceAppsRoutesController, buildConfigMeta, buildConfigSchemaView, buildConfigView, buildProviderTemplatesView, buildProvidersView, createProvider, createUiRouter, deleteProvider, ensureUiBridgeSecret, executeConfigAction, getUiBridgeSecretPath, loadConfigOrDefault, readUiBridgeSecret, startUiServer, updateChannel, updateModel, updateProvider, updateRuntime, updateSearch, updateSecrets };
7609
+ export { AppDataRoutesController, AppPackagesRoutesController, ConfigRoutesController, InboxDeliveriesRoutesController, PanelAppsRoutesController, RuntimeControlRoutesController, ServiceAppsRoutesController, buildConfigMeta, buildConfigSchemaView, buildConfigView, buildProviderTemplatesView, buildProvidersView, createProvider, createUiRouter, deleteProvider, ensureUiBridgeSecret, executeConfigAction, getUiBridgeSecretPath, loadConfigOrDefault, readUiBridgeSecret, startUiServer, updateChannel, updateModel, updateProductAnalytics, updateProvider, updateRuntime, updateSearch, updateSecrets };
7510
7610
 
7511
7611
  //# sourceMappingURL=index.js.map