@rallycry/conveyor-agent 11.0.32 → 11.0.34

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.
@@ -8,7 +8,7 @@ import {
8
8
  readWorkspaceBytes,
9
9
  statWorkspacePath,
10
10
  workspacePathExists
11
- } from "./chunk-IHNXVFIB.js";
11
+ } from "./chunk-VDK54VLS.js";
12
12
  import {
13
13
  reportBootMilestone
14
14
  } from "./chunk-Q4FQOJ7D.js";
@@ -97,7 +97,7 @@ import {
97
97
  statWorkspacePath,
98
98
  updateRemoteToken,
99
99
  verifyGitCredential
100
- } from "./chunk-IHNXVFIB.js";
100
+ } from "./chunk-VDK54VLS.js";
101
101
  import {
102
102
  registerBootMilestoneSocketFallback,
103
103
  reportBootMilestone
@@ -947,6 +947,8 @@ function mapAssistant(record) {
947
947
  type: "assistant",
948
948
  message: { role: "assistant", content }
949
949
  };
950
+ const id = stringField(message, "id");
951
+ if (id !== void 0) result.message.id = id;
950
952
  const usage = mapUsage(message);
951
953
  if (usage !== void 0) result.message.usage = usage;
952
954
  if (record.isApiErrorMessage === true) result.isApiError = true;
@@ -2112,11 +2114,19 @@ function userRecordText(record) {
2112
2114
  if (content.some((b) => isRecord3(b) && b.type === "tool_result")) return void 0;
2113
2115
  return content.filter((b) => isRecord3(b) && b.type === "text").map((b) => typeof b.text === "string" ? b.text : "").filter((t) => t.length > 0).join("\n");
2114
2116
  }
2115
- function isBackgroundTaskNotificationRecord(raw) {
2116
- if (!isRecord3(raw) || raw.type !== "user") return false;
2117
- if (raw.isSidechain === true || raw.isMeta === true) return false;
2118
- const text = userRecordText(raw);
2119
- return text !== void 0 && text.trimStart().startsWith(TASK_NOTIFICATION_PREFIX);
2117
+ function backgroundTaskCompletion(raw) {
2118
+ if (!isRecord3(raw) || raw.isSidechain === true || raw.isMeta === true) return null;
2119
+ const text = notificationText(raw);
2120
+ if (text === void 0 || !text.trimStart().startsWith(TASK_NOTIFICATION_PREFIX)) return null;
2121
+ const taskId = /<task-id>([^<]+)<\/task-id>/.exec(text)?.[1]?.trim();
2122
+ return { taskId: taskId || null };
2123
+ }
2124
+ function notificationText(record) {
2125
+ if (record.type === "user") return userRecordText(record);
2126
+ if (record.type !== "attachment") return void 0;
2127
+ const attachment = record.attachment;
2128
+ if (!isRecord3(attachment) || attachment.commandMode !== "task-notification") return void 0;
2129
+ return typeof attachment.prompt === "string" ? attachment.prompt : void 0;
2120
2130
  }
2121
2131
  function mapSystem2(record) {
2122
2132
  if (record.subtype === "init") {
@@ -3666,7 +3676,8 @@ var PtySession = class {
3666
3676
  * backgrounded gate/subagent just finished) and the chat-proxy projection.
3667
3677
  */
3668
3678
  handleRawRecord(raw) {
3669
- if (isBackgroundTaskNotificationRecord(raw)) this.bridge?.notifyBackgroundTaskDone?.();
3679
+ const completion = backgroundTaskCompletion(raw);
3680
+ if (completion) this.bridge?.notifyBackgroundTaskDone?.(completion.taskId);
3670
3681
  if (typeof this.bridge?.sendChatEvent === "function") this.relayChatRecord(raw);
3671
3682
  }
3672
3683
  /**
@@ -12035,26 +12046,46 @@ function safeVoid(promise, context) {
12035
12046
  });
12036
12047
  }
12037
12048
  }
12038
- function addTurnUsage(total, usage) {
12039
- const next = {
12040
- inputTokens: total.inputTokens + (usage.input_tokens ?? 0),
12041
- outputTokens: total.outputTokens + (usage.output_tokens ?? 0),
12042
- cacheReadInputTokens: total.cacheReadInputTokens + (usage.cache_read_input_tokens ?? 0),
12043
- cacheCreationInputTokens: total.cacheCreationInputTokens + (usage.cache_creation_input_tokens ?? 0),
12044
- totalTokens: 0
12045
- };
12046
- next.totalTokens = next.inputTokens + next.outputTokens + next.cacheReadInputTokens + next.cacheCreationInputTokens;
12047
- return next;
12048
- }
12049
- function emptyTurnUsage() {
12049
+ function maxUsage2(a, b) {
12050
12050
  return {
12051
- inputTokens: 0,
12052
- outputTokens: 0,
12053
- cacheReadInputTokens: 0,
12054
- cacheCreationInputTokens: 0,
12055
- totalTokens: 0
12051
+ input_tokens: Math.max(a.input_tokens ?? 0, b.input_tokens ?? 0),
12052
+ output_tokens: Math.max(a.output_tokens ?? 0, b.output_tokens ?? 0),
12053
+ cache_read_input_tokens: Math.max(
12054
+ a.cache_read_input_tokens ?? 0,
12055
+ b.cache_read_input_tokens ?? 0
12056
+ ),
12057
+ cache_creation_input_tokens: Math.max(
12058
+ a.cache_creation_input_tokens ?? 0,
12059
+ b.cache_creation_input_tokens ?? 0
12060
+ )
12056
12061
  };
12057
12062
  }
12063
+ var TurnUsageLedger = class {
12064
+ byMessage = /* @__PURE__ */ new Map();
12065
+ anonymous = 0;
12066
+ add(usage, messageId) {
12067
+ const id = messageId ?? `anon-${this.anonymous++}`;
12068
+ const previous = this.byMessage.get(id);
12069
+ this.byMessage.set(id, previous ? maxUsage2(previous, usage) : usage);
12070
+ }
12071
+ total() {
12072
+ const sum = {
12073
+ inputTokens: 0,
12074
+ outputTokens: 0,
12075
+ cacheReadInputTokens: 0,
12076
+ cacheCreationInputTokens: 0,
12077
+ totalTokens: 0
12078
+ };
12079
+ for (const usage of this.byMessage.values()) {
12080
+ sum.inputTokens += usage.input_tokens ?? 0;
12081
+ sum.outputTokens += usage.output_tokens ?? 0;
12082
+ sum.cacheReadInputTokens += usage.cache_read_input_tokens ?? 0;
12083
+ sum.cacheCreationInputTokens += usage.cache_creation_input_tokens ?? 0;
12084
+ }
12085
+ sum.totalTokens = sum.inputTokens + sum.outputTokens + sum.cacheReadInputTokens + sum.cacheCreationInputTokens;
12086
+ return sum;
12087
+ }
12088
+ };
12058
12089
  function epochSecondsToISO(value) {
12059
12090
  if (typeof value === "string") return value;
12060
12091
  if (typeof value !== "number" || value <= 0) return void 0;
@@ -12417,7 +12448,7 @@ async function processAssistantCase(event, host, state) {
12417
12448
  const usage = await handleAssistantCase(event, host, state.turnToolCalls);
12418
12449
  if (usage) {
12419
12450
  state.lastAssistantUsage = usage;
12420
- state.turnUsage = addTurnUsage(state.turnUsage, usage);
12451
+ state.turnUsage.add(usage, event.message.id);
12421
12452
  }
12422
12453
  if (!state.sawApiError || event.isApiError && !state.terminalApiError) {
12423
12454
  const fullText = event.message.content.filter((b) => b.type === "text").map((b) => b.text).join(" ");
@@ -12438,7 +12469,7 @@ async function processResultCase(event, host, context, startTime, state) {
12438
12469
  startTime,
12439
12470
  state.isTyping,
12440
12471
  state.lastAssistantUsage,
12441
- state.turnUsage
12472
+ state.turnUsage.total()
12442
12473
  );
12443
12474
  if (info.stoppedTyping) state.isTyping = false;
12444
12475
  state.retriable = info.retriable;
@@ -12471,7 +12502,7 @@ async function processEvents(events, context, host) {
12471
12502
  staleSession: void 0,
12472
12503
  authError: void 0,
12473
12504
  lastAssistantUsage: void 0,
12474
- turnUsage: emptyTurnUsage(),
12505
+ turnUsage: new TurnUsageLedger(),
12475
12506
  turnToolCalls: [],
12476
12507
  questionPending: false
12477
12508
  };
@@ -13916,7 +13947,7 @@ var QueryBridge = class {
13916
13947
  let bridge;
13917
13948
  if (harnessKind === "pty") {
13918
13949
  this.directStream = wrapBridgeWithDirectStream(
13919
- buildPtyBridge(connection, () => this.onBackgroundTaskDone?.()),
13950
+ buildPtyBridge(connection, (taskId) => this.onBackgroundTaskDone?.(taskId)),
13920
13951
  connection
13921
13952
  );
13922
13953
  bridge = this.directStream.bridge;
@@ -14641,6 +14672,8 @@ function isBackgroundLaunch(tool2, input) {
14641
14672
  var BackgroundWorkTracker = class {
14642
14673
  /** Absolute expiry (epoch ms) of each outstanding launch, oldest first. */
14643
14674
  deadlines = [];
14675
+ /** CLI task ids already counted as complete. */
14676
+ completedTaskIds = /* @__PURE__ */ new Set();
14644
14677
  maxMs;
14645
14678
  onChange;
14646
14679
  log;
@@ -14669,7 +14702,11 @@ var BackgroundWorkTracker = class {
14669
14702
  * runner never saw, a re-injected record) must be a no-op, never a negative
14670
14703
  * balance that would keep the pod awake after the real work finished.
14671
14704
  */
14672
- noteCompletion(now = Date.now()) {
14705
+ noteCompletion(now = Date.now(), taskId = null) {
14706
+ if (taskId !== null) {
14707
+ if (this.completedTaskIds.has(taskId)) return;
14708
+ this.completedTaskIds.add(taskId);
14709
+ }
14673
14710
  this.prune(now);
14674
14711
  if (this.deadlines.length === 0) return;
14675
14712
  this.deadlines.shift();
@@ -14689,6 +14726,7 @@ var BackgroundWorkTracker = class {
14689
14726
  }
14690
14727
  /** Drop everything (shutdown / session teardown). */
14691
14728
  clear() {
14729
+ this.completedTaskIds.clear();
14692
14730
  if (this.deadlines.length === 0) return;
14693
14731
  this.deadlines.length = 0;
14694
14732
  this.onChange?.();
@@ -16057,7 +16095,7 @@ var SessionRunner = class _SessionRunner {
16057
16095
  onUserQuestion: (signal) => this.handleUserQuestionSignal(signal)
16058
16096
  });
16059
16097
  bridge.isParentTask = this.fullContext?.isParentTask ?? false;
16060
- bridge.onBackgroundTaskDone = () => this.backgroundWork.noteCompletion();
16098
+ bridge.onBackgroundTaskDone = (taskId) => this.backgroundWork.noteCompletion(Date.now(), taskId ?? null);
16061
16099
  bridge.onSoftStop = () => {
16062
16100
  process.stderr.write("[conveyor-agent] Soft stop requested (discovery ExitPlanMode)\n");
16063
16101
  this.softStop();
@@ -4085,14 +4085,19 @@ var CATALOG = {
4085
4085
  lgtm: {
4086
4086
  name: "lgtm",
4087
4087
  image: "grafana/otel-lgtm:0.11.6",
4088
- // The otel-lgtm image's own CMD is ["/otel-lgtm/run-all.sh"] (WORKDIR
4089
- // /otel-lgtm). Declaring it explicitly makes lgtm a command-based service so
4090
- // the lazy start-file gate wraps it like the others — otherwise it launches
4091
- // via image CMD at boot and can't be parked (which is why warm-booting it at
4092
- // a minimal request OOMKilled it). getSidecarSpecs strips this command for a
4093
- // baked lgtm image, so it only applies to the stock image whose launcher is
4094
- // exactly this path.
4095
- command: ["/otel-lgtm/run-all.sh"],
4088
+ // Runs the image's own launcher (/otel-lgtm/run-all.sh) after capping
4089
+ // Tempo's retention. The image ships Tempo with the 14-day default, and its
4090
+ // blocks live on the container's writable layer, which counts against the
4091
+ // 1Gi ephemeral-storage limit below; overrunning it evicts the whole pod.
4092
+ // At 100% sampling a busy dev stack writes up to ~2 GB of traces a day, so
4093
+ // keep 3h (plus 10m before a retired block leaves disk). The grep keeps it
4094
+ // idempotent, and a failed append still starts the stack. lgtm has no bake,
4095
+ // so no baked image ever strips this command.
4096
+ command: [
4097
+ "sh",
4098
+ "-c",
4099
+ "grep -q '^compactor:' /otel-lgtm/tempo-config.yaml || printf '\\ncompactor:\\n compaction:\\n block_retention: 3h\\n compacted_block_retention: 10m\\n' >> /otel-lgtm/tempo-config.yaml; exec /otel-lgtm/run-all.sh"
4100
+ ],
4096
4101
  ports: [
4097
4102
  // OTLP gRPC + HTTP — agents and user code emit telemetry here.
4098
4103
  4317,
package/dist/cli.js CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  WorkspaceCommandSupervisor,
8
8
  startWorkspaceCommandsAfterConnect,
9
9
  stopWorkspaceCommands
10
- } from "./chunk-XZDTLVWA.js";
10
+ } from "./chunk-6WVCWKDN.js";
11
11
  import {
12
12
  PtyHarness,
13
13
  SessionRunner,
@@ -27,7 +27,7 @@ import {
27
27
  runUsageProbe,
28
28
  sampleKeyUsage,
29
29
  usesNativeUsageReporting
30
- } from "./chunk-Q2E2TM3J.js";
30
+ } from "./chunk-IQP2LHB4.js";
31
31
  import "./chunk-37J5MMQT.js";
32
32
  import {
33
33
  inheritedEnv,
@@ -46,7 +46,7 @@ import {
46
46
  createServiceLogger,
47
47
  fetchBootstrap,
48
48
  loadConveyorConfig
49
- } from "./chunk-IHNXVFIB.js";
49
+ } from "./chunk-VDK54VLS.js";
50
50
  import "./chunk-Q4FQOJ7D.js";
51
51
  import "./chunk-W4LZ7R6Z.js";
52
52
  import "./chunk-372R6E4C.js";
@@ -1468,7 +1468,7 @@ if (!RUNNER_MODES.includes(CONVEYOR_MODE)) {
1468
1468
  process.exit(1);
1469
1469
  }
1470
1470
  if (CONVEYOR_MODE === "serving") {
1471
- const { runServingSession } = await import("./serve-boot-VDR3RXRA.js");
1471
+ const { runServingSession } = await import("./serve-boot-QOXREHJK.js");
1472
1472
  exitContext.runnerMode = "serving";
1473
1473
  exitContext.sessionId = process.env.CONVEYOR_SESSION_ID ?? exitContext.sessionId;
1474
1474
  const outcome = await runServingSession({
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  SessionRunner,
3
3
  unshallowRepo
4
- } from "./chunk-Q2E2TM3J.js";
4
+ } from "./chunk-IQP2LHB4.js";
5
5
  import "./chunk-37J5MMQT.js";
6
6
  import "./chunk-EKTPDG3G.js";
7
7
  import {
@@ -17,7 +17,7 @@ import {
17
17
  stageAndCommit,
18
18
  updateRemoteToken,
19
19
  workspacePathExists
20
- } from "./chunk-IHNXVFIB.js";
20
+ } from "./chunk-VDK54VLS.js";
21
21
  import "./chunk-Q4FQOJ7D.js";
22
22
  import {
23
23
  runAuthTokenCommand,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  WorkspaceCommandSupervisor
3
- } from "./chunk-XZDTLVWA.js";
3
+ } from "./chunk-6WVCWKDN.js";
4
4
  import {
5
5
  AgentConnection,
6
6
  CodespacePortVisibility,
@@ -11,7 +11,7 @@ import {
11
11
  createServiceLogger,
12
12
  ensureOnTaskBranch,
13
13
  loadConveyorConfig
14
- } from "./chunk-IHNXVFIB.js";
14
+ } from "./chunk-VDK54VLS.js";
15
15
  import "./chunk-Q4FQOJ7D.js";
16
16
  import "./chunk-W4LZ7R6Z.js";
17
17
  import "./chunk-IA45XHOA.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rallycry/conveyor-agent",
3
- "version": "11.0.32",
3
+ "version": "11.0.34",
4
4
  "description": "Conveyor Agent Runner v10 - PTY harness for the task chat (SDK harness for audit/project-chat). Agent-as-User architecture with BaseService patterns. Works locally too.",
5
5
  "keywords": [
6
6
  "agent",