@rallycry/conveyor-agent 9.1.0 → 10.0.0
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/{chunk-P3QCTUHC.js → chunk-34NA4BCK.js} +53 -130
- package/dist/chunk-34NA4BCK.js.map +1 -0
- package/dist/cli.js +1 -1
- package/dist/index.d.ts +8 -26
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-P3QCTUHC.js.map +0 -1
|
@@ -378,6 +378,14 @@ var AgentConnection = class _AgentConnection {
|
|
|
378
378
|
static RECONNECT_MAX_DELAY_MS = 6e4;
|
|
379
379
|
static RECONNECT_STATUS_EVERY_N = 3;
|
|
380
380
|
isReconnecting = false;
|
|
381
|
+
/**
|
|
382
|
+
* Invoked after every successful session reconnect (the `connectAgent` RPC
|
|
383
|
+
* re-established the session room). The runner uses this to force a TUI
|
|
384
|
+
* repaint: the reconnect may have landed on a different/restarted API
|
|
385
|
+
* process whose PTY scrollback ring is empty, and a quiet terminal would
|
|
386
|
+
* otherwise never re-seed it.
|
|
387
|
+
*/
|
|
388
|
+
onReconnected;
|
|
381
389
|
async reconnectToSession() {
|
|
382
390
|
if (this.isReconnecting) return;
|
|
383
391
|
this.isReconnecting = true;
|
|
@@ -409,6 +417,10 @@ var AgentConnection = class _AgentConnection {
|
|
|
409
417
|
reason: "reconnected",
|
|
410
418
|
attempts: attempt
|
|
411
419
|
});
|
|
420
|
+
try {
|
|
421
|
+
this.onReconnected?.();
|
|
422
|
+
} catch {
|
|
423
|
+
}
|
|
412
424
|
return;
|
|
413
425
|
} catch (err) {
|
|
414
426
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
@@ -667,17 +679,6 @@ var AgentConnection = class _AgentConnection {
|
|
|
667
679
|
this.sendEvent({ type: "agent_typing_stop" });
|
|
668
680
|
}
|
|
669
681
|
// ── RPC convenience wrappers (v6 compat, will migrate to call()) ───
|
|
670
|
-
trackSpending(params) {
|
|
671
|
-
if (!this.socket) return;
|
|
672
|
-
void this.call("trackSpending", {
|
|
673
|
-
sessionId: this.config.sessionId,
|
|
674
|
-
inputTokens: params.modelUsage?.reduce((s, m) => s + (m.inputTokens ?? 0), 0) ?? 0,
|
|
675
|
-
outputTokens: params.modelUsage?.reduce((s, m) => s + (m.outputTokens ?? 0), 0) ?? 0,
|
|
676
|
-
costUsd: params.totalCostUsd,
|
|
677
|
-
model: params.modelUsage?.[0]?.model ?? "unknown"
|
|
678
|
-
}).catch(() => {
|
|
679
|
-
});
|
|
680
|
-
}
|
|
681
682
|
emitRateLimitPause(resetsAt) {
|
|
682
683
|
this.sendEvent({ type: "rate_limit_update", resetsAt });
|
|
683
684
|
}
|
|
@@ -722,9 +723,6 @@ ${q.question}${q.options.length ? "\n" + q.options.map((o) => `- ${o.label}: ${o
|
|
|
722
723
|
triggerIdentification() {
|
|
723
724
|
return this.call("triggerIdentification", { sessionId: this.config.sessionId });
|
|
724
725
|
}
|
|
725
|
-
getCumulativeSpending() {
|
|
726
|
-
return this.call("getCumulativeSpending", { sessionId: this.config.sessionId });
|
|
727
|
-
}
|
|
728
726
|
async refreshAuthToken() {
|
|
729
727
|
const result = await this.refreshFromBootstrap();
|
|
730
728
|
return result.refreshedClaude;
|
|
@@ -3274,6 +3272,21 @@ var PtySession = class {
|
|
|
3274
3272
|
} catch {
|
|
3275
3273
|
}
|
|
3276
3274
|
}
|
|
3275
|
+
/**
|
|
3276
|
+
* Force the CLI to repaint its full screen by wiggling the pty size
|
|
3277
|
+
* (SIGWINCH). Used after a socket reconnect: the server's scrollback ring is
|
|
3278
|
+
* per-process and starts empty on a new instance, so without a repaint a
|
|
3279
|
+
* quiet TUI would leave the Connected-TUI terminal blank (and hidden) until
|
|
3280
|
+
* the CLI next draws on its own.
|
|
3281
|
+
*/
|
|
3282
|
+
forceRepaint() {
|
|
3283
|
+
if (!this.pty) return;
|
|
3284
|
+
try {
|
|
3285
|
+
this.pty.resize(this.cols, Math.max(1, this.rows - 1));
|
|
3286
|
+
this.pty.resize(this.cols, this.rows);
|
|
3287
|
+
} catch {
|
|
3288
|
+
}
|
|
3289
|
+
}
|
|
3277
3290
|
async teardown() {
|
|
3278
3291
|
if (this._toreDown) return;
|
|
3279
3292
|
this._toreDown = true;
|
|
@@ -3693,6 +3706,17 @@ var PtyHarness = class {
|
|
|
3693
3706
|
this.bridge = bridge;
|
|
3694
3707
|
}
|
|
3695
3708
|
bridge;
|
|
3709
|
+
/** The session currently streaming events, if any — repaint target. */
|
|
3710
|
+
activeSession = null;
|
|
3711
|
+
/**
|
|
3712
|
+
* Wiggle the live pty's size so the CLI repaints its whole screen. No-op
|
|
3713
|
+
* between queries or on the SDK harness. Called after a socket reconnect so
|
|
3714
|
+
* the server's (per-process, possibly brand-new) scrollback ring re-seeds
|
|
3715
|
+
* and the Connected-TUI terminal reappears.
|
|
3716
|
+
*/
|
|
3717
|
+
forceRepaint() {
|
|
3718
|
+
this.activeSession?.forceRepaint();
|
|
3719
|
+
}
|
|
3696
3720
|
async *executeQuery(opts) {
|
|
3697
3721
|
const session = new PtySession(
|
|
3698
3722
|
opts.prompt,
|
|
@@ -3703,11 +3727,13 @@ var PtyHarness = class {
|
|
|
3703
3727
|
await ensureClaudeCredentials();
|
|
3704
3728
|
await ensureClaudeOnboarding(process.env, opts.options.cwd);
|
|
3705
3729
|
await session.start();
|
|
3730
|
+
this.activeSession = session;
|
|
3706
3731
|
try {
|
|
3707
3732
|
for await (const event of session.events()) {
|
|
3708
3733
|
yield event;
|
|
3709
3734
|
}
|
|
3710
3735
|
} finally {
|
|
3736
|
+
if (this.activeSession === session) this.activeSession = null;
|
|
3711
3737
|
await session.teardown();
|
|
3712
3738
|
}
|
|
3713
3739
|
}
|
|
@@ -5062,7 +5088,7 @@ var cliEventFormatters = {
|
|
|
5062
5088
|
tool_result: (e) => `${e.tool} \u2192 ${e.output?.slice(0, 500) ?? ""}${e.isError ? " [ERROR]" : ""}`,
|
|
5063
5089
|
message: (e) => e.content ?? "",
|
|
5064
5090
|
error: (e) => `ERROR: ${e.message ?? ""}`,
|
|
5065
|
-
completed: (e) => `Completed: ${e.summary ?? ""} (
|
|
5091
|
+
completed: (e) => `Completed: ${e.summary ?? ""} (duration: ${e.durationMs ?? "?"}ms)`,
|
|
5066
5092
|
setup_output: (e) => `[${e.stream ?? "stdout"}] ${e.data ?? ""}`,
|
|
5067
5093
|
start_command_output: (e) => `[${e.stream ?? "stdout"}] ${e.data ?? ""}`,
|
|
5068
5094
|
turn_end: (e) => `Turn complete (${e.toolCalls?.length ?? 0} tool calls)`
|
|
@@ -6326,35 +6352,16 @@ function emitContextUpdate(modelUsage, host, context, lastAssistantUsage) {
|
|
|
6326
6352
|
});
|
|
6327
6353
|
}
|
|
6328
6354
|
}
|
|
6329
|
-
function trackCostSpending(host, context, cumulativeTotal) {
|
|
6330
|
-
if (cumulativeTotal > 0 && context.agentId && context._runnerSessionId) {
|
|
6331
|
-
const breakdown = host.costTracker.modelBreakdown;
|
|
6332
|
-
host.connection.trackSpending({
|
|
6333
|
-
agentId: context.agentId,
|
|
6334
|
-
sessionId: context._runnerSessionId,
|
|
6335
|
-
totalCostUsd: cumulativeTotal,
|
|
6336
|
-
onSubscription: host.config.mode === "pm" || !!process.env.CLAUDE_CODE_OAUTH_TOKEN,
|
|
6337
|
-
modelUsage: breakdown.length > 0 ? breakdown : void 0
|
|
6338
|
-
});
|
|
6339
|
-
}
|
|
6340
|
-
}
|
|
6341
6355
|
function handleSuccessResult(event, host, context, startTime, lastAssistantUsage) {
|
|
6342
6356
|
const durationMs = Date.now() - startTime;
|
|
6343
6357
|
const summary = event.result || "Task completed.";
|
|
6344
6358
|
const retriable = isRetriableMessage(summary);
|
|
6345
|
-
|
|
6359
|
+
host.connection.sendEvent({ type: "completed", summary, durationMs });
|
|
6346
6360
|
const { modelUsage } = event;
|
|
6347
|
-
if (modelUsage && typeof modelUsage === "object") {
|
|
6348
|
-
host.costTracker.addModelUsage(
|
|
6349
|
-
modelUsage
|
|
6350
|
-
);
|
|
6351
|
-
}
|
|
6352
|
-
host.connection.sendEvent({ type: "completed", summary, costUsd: cumulativeTotal, durationMs });
|
|
6353
6361
|
if (modelUsage && typeof modelUsage === "object") {
|
|
6354
6362
|
emitContextUpdate(modelUsage, host, context, lastAssistantUsage);
|
|
6355
6363
|
}
|
|
6356
|
-
|
|
6357
|
-
return { totalCostUsd: cumulativeTotal, retriable };
|
|
6364
|
+
return { retriable };
|
|
6358
6365
|
}
|
|
6359
6366
|
function handleErrorResult(event, host) {
|
|
6360
6367
|
const errorMsg = event.errors.length > 0 ? event.errors.join(", ") : `Agent stopped: ${event.subtype}`;
|
|
@@ -6383,7 +6390,7 @@ function handleResultEvent(event, host, context, startTime, lastAssistantUsage)
|
|
|
6383
6390
|
return { ...result2, resultSummary };
|
|
6384
6391
|
}
|
|
6385
6392
|
const result = handleErrorResult(event, host);
|
|
6386
|
-
return {
|
|
6393
|
+
return { ...result, resultSummary };
|
|
6387
6394
|
}
|
|
6388
6395
|
async function emitResultEvent(event, host, context, startTime, lastAssistantUsage) {
|
|
6389
6396
|
const result = handleResultEvent(event, host, context, startTime, lastAssistantUsage);
|
|
@@ -6394,7 +6401,6 @@ async function emitResultEvent(event, host, context, startTime, lastAssistantUsa
|
|
|
6394
6401
|
await host.callbacks.onEvent({
|
|
6395
6402
|
type: "completed",
|
|
6396
6403
|
summary,
|
|
6397
|
-
costUsd: result.totalCostUsd,
|
|
6398
6404
|
durationMs
|
|
6399
6405
|
});
|
|
6400
6406
|
} else if (!result.staleSession) {
|
|
@@ -7149,7 +7155,6 @@ function buildQueryOptions(host, context) {
|
|
|
7149
7155
|
effort: settings.effort,
|
|
7150
7156
|
thinking: settings.thinking,
|
|
7151
7157
|
betas: settings.betas,
|
|
7152
|
-
maxBudgetUsd: settings.maxBudgetUsd ?? 50,
|
|
7153
7158
|
abortController: host.abortController ?? void 0,
|
|
7154
7159
|
disallowedTools: buildDisallowedTools(settings, mode, host.hasExitedPlanMode),
|
|
7155
7160
|
enableFileCheckpointing: settings.enableFileCheckpointing,
|
|
@@ -7548,58 +7553,6 @@ async function runWithRetry(initialQuery, context, host, options) {
|
|
|
7548
7553
|
}
|
|
7549
7554
|
}
|
|
7550
7555
|
|
|
7551
|
-
// src/execution/cost-tracker.ts
|
|
7552
|
-
var CostTracker = class {
|
|
7553
|
-
cumulativeCostUsd = 0;
|
|
7554
|
-
modelUsage = /* @__PURE__ */ new Map();
|
|
7555
|
-
seeded = false;
|
|
7556
|
-
/**
|
|
7557
|
-
* Rehydrate cumulative spend from the server so `maxBudgetUsd` enforcement
|
|
7558
|
-
* accounts for costs incurred by prior agent runs on the same task. Must be
|
|
7559
|
-
* called before any `addQueryCost` / `addModelUsage` — re-seeding after
|
|
7560
|
-
* costs have accumulated would clobber in-process totals.
|
|
7561
|
-
*/
|
|
7562
|
-
seed(totalCostUsd, modelUsage) {
|
|
7563
|
-
if (this.seeded) return;
|
|
7564
|
-
if (this.cumulativeCostUsd > 0 || this.modelUsage.size > 0) return;
|
|
7565
|
-
this.cumulativeCostUsd = totalCostUsd;
|
|
7566
|
-
for (const entry of modelUsage) {
|
|
7567
|
-
this.modelUsage.set(entry.model, { ...entry });
|
|
7568
|
-
}
|
|
7569
|
-
this.seeded = true;
|
|
7570
|
-
}
|
|
7571
|
-
/** Add cost from a completed query and return the running total */
|
|
7572
|
-
addQueryCost(queryCostUsd) {
|
|
7573
|
-
this.cumulativeCostUsd += queryCostUsd;
|
|
7574
|
-
return this.cumulativeCostUsd;
|
|
7575
|
-
}
|
|
7576
|
-
/** Merge per-model usage from a completed query */
|
|
7577
|
-
addModelUsage(usage) {
|
|
7578
|
-
for (const [model, data] of Object.entries(usage)) {
|
|
7579
|
-
const existing = this.modelUsage.get(model) ?? {
|
|
7580
|
-
model,
|
|
7581
|
-
inputTokens: 0,
|
|
7582
|
-
outputTokens: 0,
|
|
7583
|
-
cacheReadInputTokens: 0,
|
|
7584
|
-
cacheCreationInputTokens: 0,
|
|
7585
|
-
costUSD: 0
|
|
7586
|
-
};
|
|
7587
|
-
existing.inputTokens += data.inputTokens ?? 0;
|
|
7588
|
-
existing.outputTokens += data.outputTokens ?? 0;
|
|
7589
|
-
existing.cacheReadInputTokens += data.cacheReadInputTokens ?? 0;
|
|
7590
|
-
existing.cacheCreationInputTokens += data.cacheCreationInputTokens ?? 0;
|
|
7591
|
-
existing.costUSD += data.costUSD ?? 0;
|
|
7592
|
-
this.modelUsage.set(model, existing);
|
|
7593
|
-
}
|
|
7594
|
-
}
|
|
7595
|
-
get totalCostUsd() {
|
|
7596
|
-
return this.cumulativeCostUsd;
|
|
7597
|
-
}
|
|
7598
|
-
get modelBreakdown() {
|
|
7599
|
-
return [...this.modelUsage.values()];
|
|
7600
|
-
}
|
|
7601
|
-
};
|
|
7602
|
-
|
|
7603
7556
|
// src/execution/exploration-tracker.ts
|
|
7604
7557
|
var FILE_REREAD_NUDGE_L1 = 3;
|
|
7605
7558
|
var FILE_REREAD_NUDGE_L2 = 5;
|
|
@@ -7726,7 +7679,6 @@ var QueryBridge = class {
|
|
|
7726
7679
|
harnessKind,
|
|
7727
7680
|
harnessKind === "pty" ? buildPtyBridge(connection) : void 0
|
|
7728
7681
|
);
|
|
7729
|
-
this.costTracker = new CostTracker();
|
|
7730
7682
|
this.planSync = new PlanSync(workspaceDir, connection);
|
|
7731
7683
|
}
|
|
7732
7684
|
connection;
|
|
@@ -7737,7 +7689,6 @@ var QueryBridge = class {
|
|
|
7737
7689
|
/** Which harness drives this bridge ("pty" task chat; "sdk" only under the
|
|
7738
7690
|
* CONVEYOR_FORCE_SDK_CARDS maintainer override). */
|
|
7739
7691
|
harnessKind;
|
|
7740
|
-
costTracker;
|
|
7741
7692
|
planSync;
|
|
7742
7693
|
sessionIds = /* @__PURE__ */ new Map();
|
|
7743
7694
|
activeQuery = null;
|
|
@@ -7769,6 +7720,13 @@ var QueryBridge = class {
|
|
|
7769
7720
|
get wasRateLimited() {
|
|
7770
7721
|
return this._wasRateLimited;
|
|
7771
7722
|
}
|
|
7723
|
+
/**
|
|
7724
|
+
* Ask the live terminal (PTY harness only) to redraw its full screen.
|
|
7725
|
+
* Safe no-op on the SDK harness or between queries.
|
|
7726
|
+
*/
|
|
7727
|
+
forceRepaint() {
|
|
7728
|
+
this.harness.forceRepaint?.();
|
|
7729
|
+
}
|
|
7772
7730
|
stop() {
|
|
7773
7731
|
this._stopped = true;
|
|
7774
7732
|
this._abortController?.abort();
|
|
@@ -7776,10 +7734,6 @@ var QueryBridge = class {
|
|
|
7776
7734
|
resume() {
|
|
7777
7735
|
this._stopped = false;
|
|
7778
7736
|
}
|
|
7779
|
-
/** Rehydrate CostTracker from server-side cumulative spend on agent boot. */
|
|
7780
|
-
seedCostTracker(totalCostUsd, modelUsage) {
|
|
7781
|
-
this.costTracker.seed(totalCostUsd, modelUsage);
|
|
7782
|
-
}
|
|
7783
7737
|
/**
|
|
7784
7738
|
* How the INITIAL instructions for this task would be delivered — "prefill"
|
|
7785
7739
|
* means the TUI input is pre-filled but unsubmitted, awaiting the human.
|
|
@@ -7838,7 +7792,6 @@ var QueryBridge = class {
|
|
|
7838
7792
|
harness: this.harness,
|
|
7839
7793
|
harnessKind: this.harnessKind,
|
|
7840
7794
|
setupLog: [],
|
|
7841
|
-
costTracker: this.costTracker,
|
|
7842
7795
|
explorationTracker: bridge.mode.effectiveMode === "discovery" || bridge.mode.effectiveMode === "auto" && !bridge.mode.hasExitedPlanMode ? new ExplorationTracker(bridge._isParentTask) : null,
|
|
7843
7796
|
sessionIds: this.sessionIds,
|
|
7844
7797
|
pendingToolOutputs: this.pendingToolOutputs,
|
|
@@ -8148,7 +8101,6 @@ var SessionRunner = class _SessionRunner {
|
|
|
8148
8101
|
});
|
|
8149
8102
|
}
|
|
8150
8103
|
this.queryBridge = this.createQueryBridge();
|
|
8151
|
-
await this.seedCostTrackerFromServer();
|
|
8152
8104
|
this.logInitialization();
|
|
8153
8105
|
const staleBatch = [...this.pendingMessages];
|
|
8154
8106
|
const didExecuteInitialQuery = await this.executeInitialMode();
|
|
@@ -8700,6 +8652,7 @@ var SessionRunner = class _SessionRunner {
|
|
|
8700
8652
|
this.connection.onMessage((msg) => this.injectMessage(msg));
|
|
8701
8653
|
this.connection.onStop(() => this.stop());
|
|
8702
8654
|
this.connection.onSoftStop(() => this.softStop());
|
|
8655
|
+
this.connection.onReconnected = () => this.queryBridge?.forceRepaint();
|
|
8703
8656
|
this.connection.onModeChange((data) => {
|
|
8704
8657
|
const action = this.mode.handleModeChange(data.agentMode);
|
|
8705
8658
|
if (action.type === "start_auto") {
|
|
@@ -8732,36 +8685,6 @@ var SessionRunner = class _SessionRunner {
|
|
|
8732
8685
|
handlePullBranch(this.config.workspaceDir, branch);
|
|
8733
8686
|
});
|
|
8734
8687
|
}
|
|
8735
|
-
/**
|
|
8736
|
-
* Rehydrate CostTracker from server. Caps at 3s so a slow API call never
|
|
8737
|
-
* blocks agent startup — on timeout/error we fall through with a $0 tracker
|
|
8738
|
-
* (the existing behavior before this rehydration path was added).
|
|
8739
|
-
*/
|
|
8740
|
-
async seedCostTrackerFromServer() {
|
|
8741
|
-
if (!this.queryBridge) return;
|
|
8742
|
-
const TIMEOUT_MS = 3e3;
|
|
8743
|
-
try {
|
|
8744
|
-
const timeout = new Promise((resolve) => {
|
|
8745
|
-
setTimeout(() => resolve(null), TIMEOUT_MS);
|
|
8746
|
-
});
|
|
8747
|
-
const fetched = await Promise.race([this.connection.getCumulativeSpending(), timeout]);
|
|
8748
|
-
if (fetched) {
|
|
8749
|
-
this.queryBridge.seedCostTracker(fetched.totalCostUsd, fetched.modelUsage);
|
|
8750
|
-
process.stderr.write(
|
|
8751
|
-
`[conveyor-agent] CostTracker seeded: $${fetched.totalCostUsd.toFixed(4)} across ${fetched.modelUsage.length} model(s)
|
|
8752
|
-
`
|
|
8753
|
-
);
|
|
8754
|
-
} else {
|
|
8755
|
-
process.stderr.write(
|
|
8756
|
-
"[conveyor-agent] CostTracker seed timed out after 3s \u2014 starting at $0\n"
|
|
8757
|
-
);
|
|
8758
|
-
}
|
|
8759
|
-
} catch (err) {
|
|
8760
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
8761
|
-
process.stderr.write(`[conveyor-agent] CostTracker seed failed: ${msg} \u2014 starting at $0
|
|
8762
|
-
`);
|
|
8763
|
-
}
|
|
8764
|
-
}
|
|
8765
8688
|
/** Proactively refresh the GitHub token before the 1-hour expiry. */
|
|
8766
8689
|
async refreshGithubToken() {
|
|
8767
8690
|
try {
|
|
@@ -8991,4 +8914,4 @@ export {
|
|
|
8991
8914
|
runStartCommand,
|
|
8992
8915
|
unshallowRepo
|
|
8993
8916
|
};
|
|
8994
|
-
//# sourceMappingURL=chunk-
|
|
8917
|
+
//# sourceMappingURL=chunk-34NA4BCK.js.map
|