@cargo-ai/cli 1.0.125 → 1.0.127

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 (43) hide show
  1. package/build/commands/ask/harness/bridgeOutput.d.ts +19 -0
  2. package/build/commands/ask/harness/bridgeOutput.d.ts.map +1 -0
  3. package/build/commands/ask/harness/bridgeOutput.js +42 -0
  4. package/build/commands/ask/harness/create.d.ts.map +1 -1
  5. package/build/commands/ask/harness/create.js +2 -1
  6. package/build/commands/ask/harness/index.d.ts +4 -3
  7. package/build/commands/ask/harness/index.d.ts.map +1 -1
  8. package/build/commands/ask/harness/index.js +3 -2
  9. package/build/commands/ask/harness/toolCallReplay.d.ts +31 -0
  10. package/build/commands/ask/harness/toolCallReplay.d.ts.map +1 -1
  11. package/build/commands/ask/harness/toolCallReplay.js +89 -8
  12. package/build/commands/ask/harness/turn.d.ts +17 -0
  13. package/build/commands/ask/harness/turn.d.ts.map +1 -1
  14. package/build/commands/ask/harness/turn.js +85 -3
  15. package/build/commands/ask/harness/usage.d.ts +19 -0
  16. package/build/commands/ask/harness/usage.d.ts.map +1 -1
  17. package/build/commands/ask/harness/usage.js +46 -0
  18. package/build/commands/ask/input/completer.d.ts +1 -1
  19. package/build/commands/ask/input/completer.d.ts.map +1 -1
  20. package/build/commands/ask/input/completer.js +2 -0
  21. package/build/commands/ask/input/prompt.d.ts.map +1 -1
  22. package/build/commands/ask/input/prompt.js +54 -8
  23. package/build/commands/ask/input/slash.d.ts +7 -1
  24. package/build/commands/ask/input/slash.d.ts.map +1 -1
  25. package/build/commands/ask/input/slash.js +10 -0
  26. package/build/commands/ask/session/index.d.ts +2 -1
  27. package/build/commands/ask/session/index.d.ts.map +1 -1
  28. package/build/commands/ask/session/index.js +2 -1
  29. package/build/commands/ask/session/markdown.d.ts +20 -0
  30. package/build/commands/ask/session/markdown.d.ts.map +1 -0
  31. package/build/commands/ask/session/markdown.js +451 -0
  32. package/build/commands/ask/session/run.d.ts.map +1 -1
  33. package/build/commands/ask/session/run.js +194 -12
  34. package/build/commands/ask/session/tree.d.ts +81 -0
  35. package/build/commands/ask/session/tree.d.ts.map +1 -1
  36. package/build/commands/ask/session/tree.js +322 -51
  37. package/build/commands/runHandler.d.ts +1 -0
  38. package/build/commands/runHandler.d.ts.map +1 -1
  39. package/build/commands/runHandler.js +6 -3
  40. package/build/utils/textWidth.d.ts +25 -0
  41. package/build/utils/textWidth.d.ts.map +1 -0
  42. package/build/utils/textWidth.js +147 -0
  43. package/package.json +3 -3
@@ -0,0 +1,19 @@
1
+ /**
2
+ * `@ai-sdk/harness` copies every line the Claude Code bridge writes to its
3
+ * stderr onto ours, as `[harness:claude-code:stderr] …`, with no option to
4
+ * turn it off. In the middle of a session that lands on the spinner row and
5
+ * breaks the tree: an API retry warning is the usual one.
6
+ *
7
+ * So while a session runs, those lines are taken off stderr and handed to
8
+ * `onLine` instead. `CARGO_ASK_TIMING` leaves them alone, since that is when
9
+ * someone wants to read them. Returns the function that puts stderr back.
10
+ */
11
+ export declare function interceptBridgeOutput(onLine: (line: string) => void): () => void;
12
+ /**
13
+ * A spinner label for Claude Code retrying a failed API call, or undefined
14
+ * for any other bridge line.
15
+ *
16
+ * Exported for tests.
17
+ */
18
+ export declare function describeBridgeRetry(line: string): string | undefined;
19
+ //# sourceMappingURL=bridgeOutput.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bridgeOutput.d.ts","sourceRoot":"","sources":["../../../../src/commands/ask/harness/bridgeOutput.ts"],"names":[],"mappings":"AAEA;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAC7B,MAAM,IAAI,CAoBZ;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAQpE"}
@@ -0,0 +1,42 @@
1
+ import { ASK_TIMING_ENABLED } from "./timing.js";
2
+ /**
3
+ * `@ai-sdk/harness` copies every line the Claude Code bridge writes to its
4
+ * stderr onto ours, as `[harness:claude-code:stderr] …`, with no option to
5
+ * turn it off. In the middle of a session that lands on the spinner row and
6
+ * breaks the tree: an API retry warning is the usual one.
7
+ *
8
+ * So while a session runs, those lines are taken off stderr and handed to
9
+ * `onLine` instead. `CARGO_ASK_TIMING` leaves them alone, since that is when
10
+ * someone wants to read them. Returns the function that puts stderr back.
11
+ */
12
+ export function interceptBridgeOutput(onLine) {
13
+ if (ASK_TIMING_ENABLED === true) {
14
+ return () => undefined;
15
+ }
16
+ const write = process.stderr.write;
17
+ // The harness writes each forwarded line in a single call, prefix first.
18
+ process.stderr.write = ((chunk, ...rest) => {
19
+ if (typeof chunk === "string" && chunk.startsWith(BRIDGE_PREFIX) === true) {
20
+ onLine(chunk.trimEnd());
21
+ return true;
22
+ }
23
+ return Reflect.apply(write, process.stderr, [chunk, ...rest]);
24
+ });
25
+ return () => {
26
+ process.stderr.write = write;
27
+ };
28
+ }
29
+ /**
30
+ * A spinner label for Claude Code retrying a failed API call, or undefined
31
+ * for any other bridge line.
32
+ *
33
+ * Exported for tests.
34
+ */
35
+ export function describeBridgeRetry(line) {
36
+ const match = line.match(/API retry: attempt (\d+)\/(\d+)/);
37
+ if (match === null || match[1] === undefined || match[2] === undefined) {
38
+ return undefined;
39
+ }
40
+ return `Retrying the API (${match[1]}/${match[2]})`;
41
+ }
42
+ const BRIDGE_PREFIX = "[harness:";
@@ -1 +1 @@
1
- {"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../../../src/commands/ask/harness/create.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,eAAe,CAAC;AAIxC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AAwB3C,OAAO,EAEL,KAAK,kBAAkB,EAKxB,MAAM,WAAW,CAAC;AAGnB,MAAM,MAAM,YAAY,GAAG;IACzB,YAAY,EAAE,CACZ,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,kBAAkB,KACzB,OAAO,CAAC,MAAM,CAAC,CAAC;IACrB;;;;OAIG;IACH,iBAAiB,EAAE,MAAM,MAAM,GAAG,SAAS,CAAC;IAC5C,sEAAsE;IACtE,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5B,CAAC;AAcF,wBAAsB,kBAAkB,CAAC,KAAK,EAAE;IAC9C,GAAG,EAAE,GAAG,CAAC;IACT;;;;OAIG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,OAAO,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,iBAAiB,EAAE,MAAM,CAAC;IAC1B;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,uBAAuB,EAAE,OAAO,CAAC;CAClC,GAAG,OAAO,CAAC,YAAY,CAAC,CAgVxB"}
1
+ {"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../../../src/commands/ask/harness/create.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,eAAe,CAAC;AAIxC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AAwB3C,OAAO,EAEL,KAAK,kBAAkB,EAKxB,MAAM,WAAW,CAAC;AAGnB,MAAM,MAAM,YAAY,GAAG;IACzB,YAAY,EAAE,CACZ,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,kBAAkB,KACzB,OAAO,CAAC,MAAM,CAAC,CAAC;IACrB;;;;OAIG;IACH,iBAAiB,EAAE,MAAM,MAAM,GAAG,SAAS,CAAC;IAC5C,sEAAsE;IACtE,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5B,CAAC;AAcF,wBAAsB,kBAAkB,CAAC,KAAK,EAAE;IAC9C,GAAG,EAAE,GAAG,CAAC;IACT;;;;OAIG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,OAAO,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,iBAAiB,EAAE,MAAM,CAAC;IAC1B;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,uBAAuB,EAAE,OAAO,CAAC;CAClC,GAAG,OAAO,CAAC,YAAY,CAAC,CAiVxB"}
@@ -64,7 +64,8 @@ export async function createLocalHarness(input) {
64
64
  // createClaudeCode auto-detect AI Gateway from the host process and ignore
65
65
  // the Cargo proxy.
66
66
  // Wrapped so a batched tool call stays known to the stream that is asked to
67
- // approve it (see `toolCallReplay.ts`).
67
+ // approve it, and a second approval asked at the same time reaches the next
68
+ // stream instead of one nobody reads (see `toolCallReplay.ts`).
68
69
  const claudeCode = withToolCallReplay(createClaudeCode({
69
70
  auth: {
70
71
  ANTHROPIC_BASE_URL: anthropicBaseUrl,
@@ -1,10 +1,11 @@
1
1
  export { isAlwaysDenied, isAutoApproved } from "./approvals.js";
2
2
  export { ASK_USER_QUESTION_DENIED_REASON, ASK_USER_QUESTION_MISSING_INPUT_REASON, ASK_USER_QUESTION_TOOL_NAME, buildAskUserQuestionHostTool, denyNativeAskUserQuestion, formatAskUserQuestionAnswers, readAskUserQuestions, summarizeAskUserQuestion, } from "./askUserQuestion.js";
3
+ export { describeBridgeRetry, interceptBridgeOutput } from "./bridgeOutput.js";
3
4
  export { createLocalHarness, type LocalHarness } from "./create.js";
4
5
  export { localHarnessInstructions, localHarnessSkills, } from "./instructions.js";
5
6
  export { resolveWorkspaceLayout } from "./layout.js";
6
7
  export { CARGO_MCP_SERVER_NAME } from "./mcp.js";
7
- export { replayKnownToolCalls, withToolCallReplay, wrapSession, } from "./toolCallReplay.js";
8
- export { HarnessTurnStalled, HarnessTurnStuck, isBridgeClosedError, type LocalStreamHandlers, type LocalStreamOptions, type LocalToolActivity, type LocalToolApproval, runPromptTurn, settleWithin, type StreamLike, type TurnDriver, } from "./turn.js";
9
- export { createTurnAccumulator, type LocalTurnAccumulator, type LocalTurnUsage, readClaudeCodeCostUsd, } from "./usage.js";
8
+ export { replayKnownToolCalls, routeSessionEvents, withToolCallReplay, wrapSession, } from "./toolCallReplay.js";
9
+ export { HarnessTurnStalled, HarnessTurnStuck, isBridgeClosedError, type LocalStreamHandlers, type LocalStreamOptions, type LocalToolActivity, type LocalToolApproval, type LocalUsageUpdate, runPromptTurn, settleWithin, type StreamLike, type TurnDriver, } from "./turn.js";
10
+ export { createTurnAccumulator, creditsForStep, type LocalTurnAccumulator, type LocalTurnUsage, readClaudeCodeCostUsd, } from "./usage.js";
10
11
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/commands/ask/harness/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChE,OAAO,EACL,+BAA+B,EAC/B,sCAAsC,EACtC,2BAA2B,EAC3B,4BAA4B,EAC5B,yBAAyB,EACzB,4BAA4B,EAC5B,oBAAoB,EACpB,wBAAwB,GACzB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,kBAAkB,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AACpE,OAAO,EACL,wBAAwB,EACxB,kBAAkB,GACnB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AACjD,OAAO,EACL,oBAAoB,EACpB,kBAAkB,EAClB,WAAW,GACZ,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,mBAAmB,EACnB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACtB,aAAa,EACb,YAAY,EACZ,KAAK,UAAU,EACf,KAAK,UAAU,GAChB,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,qBAAqB,EACrB,KAAK,oBAAoB,EACzB,KAAK,cAAc,EACnB,qBAAqB,GACtB,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/commands/ask/harness/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChE,OAAO,EACL,+BAA+B,EAC/B,sCAAsC,EACtC,2BAA2B,EAC3B,4BAA4B,EAC5B,yBAAyB,EACzB,4BAA4B,EAC5B,oBAAoB,EACpB,wBAAwB,GACzB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAC/E,OAAO,EAAE,kBAAkB,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AACpE,OAAO,EACL,wBAAwB,EACxB,kBAAkB,GACnB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AACjD,OAAO,EACL,oBAAoB,EACpB,kBAAkB,EAClB,kBAAkB,EAClB,WAAW,GACZ,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,mBAAmB,EACnB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,aAAa,EACb,YAAY,EACZ,KAAK,UAAU,EACf,KAAK,UAAU,GAChB,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,qBAAqB,EACrB,cAAc,EACd,KAAK,oBAAoB,EACzB,KAAK,cAAc,EACnB,qBAAqB,GACtB,MAAM,YAAY,CAAC"}
@@ -1,9 +1,10 @@
1
1
  export { isAlwaysDenied, isAutoApproved } from "./approvals.js";
2
2
  export { ASK_USER_QUESTION_DENIED_REASON, ASK_USER_QUESTION_MISSING_INPUT_REASON, ASK_USER_QUESTION_TOOL_NAME, buildAskUserQuestionHostTool, denyNativeAskUserQuestion, formatAskUserQuestionAnswers, readAskUserQuestions, summarizeAskUserQuestion, } from "./askUserQuestion.js";
3
+ export { describeBridgeRetry, interceptBridgeOutput } from "./bridgeOutput.js";
3
4
  export { createLocalHarness } from "./create.js";
4
5
  export { localHarnessInstructions, localHarnessSkills, } from "./instructions.js";
5
6
  export { resolveWorkspaceLayout } from "./layout.js";
6
7
  export { CARGO_MCP_SERVER_NAME } from "./mcp.js";
7
- export { replayKnownToolCalls, withToolCallReplay, wrapSession, } from "./toolCallReplay.js";
8
+ export { replayKnownToolCalls, routeSessionEvents, withToolCallReplay, wrapSession, } from "./toolCallReplay.js";
8
9
  export { HarnessTurnStalled, HarnessTurnStuck, isBridgeClosedError, runPromptTurn, settleWithin, } from "./turn.js";
9
- export { createTurnAccumulator, readClaudeCodeCostUsd, } from "./usage.js";
10
+ export { createTurnAccumulator, creditsForStep, readClaudeCodeCostUsd, } from "./usage.js";
@@ -15,11 +15,42 @@
15
15
  * own `emit`, so the session remembers every tool call and replays one into a
16
16
  * stream that is about to receive an approval for a call it never saw. Remove
17
17
  * this once the agent keeps tool calls for the session.
18
+ *
19
+ * The same batch also loses events outright, which is the stall
20
+ * `HarnessTurnStalled` reports. The agent stops reading a stream at the first
21
+ * approval request in it, but the adapter keeps that stream's listener on the
22
+ * bridge until the turn's `finish`, so whatever the bridge says next goes into
23
+ * a stream nobody reads. When Claude Code asks about two tools at once, the
24
+ * second request lands there: the next stream never hears of it, Claude Code
25
+ * waits for an answer, and the turn waits for output. `routeSessionEvents`
26
+ * holds those events and hands them to the next stream instead.
18
27
  */
19
28
  import type { HarnessV1, HarnessV1Session, HarnessV1StreamPart } from "@ai-sdk/harness";
20
29
  type Emit = (event: HarnessV1StreamPart) => void;
21
30
  /** Exported for tests: one stream's `emit`, fed from a session-wide memory. */
22
31
  export declare function replayKnownToolCalls(known: Map<string, HarnessV1StreamPart>, emit: Emit): Emit;
32
+ /**
33
+ * Exported for tests: delivers every bridge event of a session once, to the
34
+ * stream the agent is still reading.
35
+ *
36
+ * Each stream's listener stays on the bridge after the agent is done with it,
37
+ * so one event reaches every listener still attached — the same object each
38
+ * time, which is what lets it be delivered once. It goes to the stream opened
39
+ * last. Once that stream has carried an approval request the agent has
40
+ * stopped reading it, so the rest is also held, in order, and opening the next
41
+ * stream hands it over.
42
+ *
43
+ * Held events are still delivered to the stopped stream, so if the agent ever
44
+ * does read past an approval, it misses nothing; it would see them twice.
45
+ */
46
+ export declare function routeSessionEvents(): {
47
+ /** The `emit` every stream hands the bridge, current or not. */
48
+ listen: () => Emit;
49
+ /** A new stream is about to be read: send it everything held. */
50
+ open: (emit: Emit, options: {
51
+ freshTurn: boolean;
52
+ }) => void;
53
+ };
23
54
  /** Exported for tests. */
24
55
  export declare function wrapSession(session: HarnessV1Session): HarnessV1Session;
25
56
  /** The harness, with every session it starts keeping its tool calls. */
@@ -1 +1 @@
1
- {"version":3,"file":"toolCallReplay.d.ts","sourceRoot":"","sources":["../../../../src/commands/ask/harness/toolCallReplay.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EACV,SAAS,EACT,gBAAgB,EAChB,mBAAmB,EACpB,MAAM,iBAAiB,CAAC;AAEzB,KAAK,IAAI,GAAG,CAAC,KAAK,EAAE,mBAAmB,KAAK,IAAI,CAAC;AAEjD,+EAA+E;AAC/E,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,mBAAmB,CAAC,EACvC,IAAI,EAAE,IAAI,GACT,IAAI,CAqBN;AAED,0BAA0B;AAC1B,wBAAgB,WAAW,CAAC,OAAO,EAAE,gBAAgB,GAAG,gBAAgB,CA+BvE;AAED,wEAAwE;AACxE,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,SAAS,GAAG,SAAS,CAKhE"}
1
+ {"version":3,"file":"toolCallReplay.d.ts","sourceRoot":"","sources":["../../../../src/commands/ask/harness/toolCallReplay.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,KAAK,EACV,SAAS,EACT,gBAAgB,EAChB,mBAAmB,EACpB,MAAM,iBAAiB,CAAC;AAEzB,KAAK,IAAI,GAAG,CAAC,KAAK,EAAE,mBAAmB,KAAK,IAAI,CAAC;AAEjD,+EAA+E;AAC/E,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,mBAAmB,CAAC,EACvC,IAAI,EAAE,IAAI,GACT,IAAI,CAqBN;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,IAAI;IACpC,gEAAgE;IAChE,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,iEAAiE;IACjE,IAAI,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE;QAAE,SAAS,EAAE,OAAO,CAAA;KAAE,KAAK,IAAI,CAAC;CAC7D,CAsDA;AAED,0BAA0B;AAC1B,wBAAgB,WAAW,CAAC,OAAO,EAAE,gBAAgB,GAAG,gBAAgB,CA4CvE;AAED,wEAAwE;AACxE,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,SAAS,GAAG,SAAS,CAKhE"}
@@ -15,6 +15,15 @@
15
15
  * own `emit`, so the session remembers every tool call and replays one into a
16
16
  * stream that is about to receive an approval for a call it never saw. Remove
17
17
  * this once the agent keeps tool calls for the session.
18
+ *
19
+ * The same batch also loses events outright, which is the stall
20
+ * `HarnessTurnStalled` reports. The agent stops reading a stream at the first
21
+ * approval request in it, but the adapter keeps that stream's listener on the
22
+ * bridge until the turn's `finish`, so whatever the bridge says next goes into
23
+ * a stream nobody reads. When Claude Code asks about two tools at once, the
24
+ * second request lands there: the next stream never hears of it, Claude Code
25
+ * waits for an answer, and the turn waits for output. `routeSessionEvents`
26
+ * holds those events and hands them to the next stream instead.
18
27
  */
19
28
  /** Exported for tests: one stream's `emit`, fed from a session-wide memory. */
20
29
  export function replayKnownToolCalls(known, emit) {
@@ -35,17 +44,89 @@ export function replayKnownToolCalls(known, emit) {
35
44
  emit(event);
36
45
  };
37
46
  }
47
+ /**
48
+ * Exported for tests: delivers every bridge event of a session once, to the
49
+ * stream the agent is still reading.
50
+ *
51
+ * Each stream's listener stays on the bridge after the agent is done with it,
52
+ * so one event reaches every listener still attached — the same object each
53
+ * time, which is what lets it be delivered once. It goes to the stream opened
54
+ * last. Once that stream has carried an approval request the agent has
55
+ * stopped reading it, so the rest is also held, in order, and opening the next
56
+ * stream hands it over.
57
+ *
58
+ * Held events are still delivered to the stopped stream, so if the agent ever
59
+ * does read past an approval, it misses nothing; it would see them twice.
60
+ */
61
+ export function routeSessionEvents() {
62
+ const delivered = new WeakSet();
63
+ const held = [];
64
+ const current = {
65
+ emit: undefined,
66
+ stopped: false,
67
+ };
68
+ const deliver = (event) => {
69
+ if (current.emit === undefined) {
70
+ held.push(event);
71
+ return;
72
+ }
73
+ if (current.stopped === true) {
74
+ held.push(event);
75
+ }
76
+ current.emit(event);
77
+ // The agent ends the stream right here to ask; nothing after this in
78
+ // the same stream is read.
79
+ if (event.type === "tool-approval-request") {
80
+ current.stopped = true;
81
+ }
82
+ };
83
+ return {
84
+ listen: () => (event) => {
85
+ if (delivered.has(event) === true) {
86
+ return;
87
+ }
88
+ delivered.add(event);
89
+ deliver(event);
90
+ },
91
+ open: (emit, options) => {
92
+ current.emit = emit;
93
+ current.stopped = false;
94
+ const backlog = held.splice(0, held.length);
95
+ // A new prompt replaces whatever the bridge was still doing, so what
96
+ // the last turn left behind belongs to nobody.
97
+ if (options.freshTurn === true) {
98
+ return;
99
+ }
100
+ for (const event of backlog) {
101
+ deliver(event);
102
+ }
103
+ },
104
+ };
105
+ }
38
106
  /** Exported for tests. */
39
107
  export function wrapSession(session) {
40
108
  const known = new Map();
41
- const doPromptTurn = (options) => session.doPromptTurn({
42
- ...options,
43
- emit: replayKnownToolCalls(known, options.emit),
44
- });
45
- const doContinueTurn = (options) => session.doContinueTurn({
46
- ...options,
47
- emit: replayKnownToolCalls(known, options.emit),
48
- });
109
+ const router = routeSessionEvents();
110
+ const doPromptTurn = (options) => {
111
+ router.open(replayKnownToolCalls(known, options.emit), {
112
+ freshTurn: true,
113
+ });
114
+ return session.doPromptTurn({
115
+ ...options,
116
+ emit: router.listen(),
117
+ });
118
+ };
119
+ const doContinueTurn = (options) => {
120
+ // Opened before the adapter wires the stream: its emit already queues,
121
+ // and anything the bridge says in between belongs to this stream too.
122
+ router.open(replayKnownToolCalls(known, options.emit), {
123
+ freshTurn: false,
124
+ });
125
+ return session.doContinueTurn({
126
+ ...options,
127
+ emit: router.listen(),
128
+ });
129
+ };
49
130
  // A proxy rather than a spread or a prototype: a session may be a class
50
131
  // with private state, so every other member is read from it and its methods
51
132
  // run bound to it.
@@ -23,6 +23,8 @@ export type LocalToolActivity = {
23
23
  toolCallId: string;
24
24
  toolName: string;
25
25
  isError: boolean;
26
+ /** What the tool returned, or its error, as text. Capped in length. */
27
+ output: string;
26
28
  }
27
29
  /**
28
30
  * Announced, then never run — a tool whose input stopped mid-stream, one
@@ -36,8 +38,23 @@ export type LocalToolActivity = {
36
38
  toolCallId: string;
37
39
  toolName: string;
38
40
  };
41
+ /**
42
+ * Tokens one model call used (`step`) or one stream used in total (`stream`).
43
+ * A step's input is the whole context it was sent, which is how full the
44
+ * window is.
45
+ */
46
+ export type LocalUsageUpdate = {
47
+ scope: "step" | "stream";
48
+ inputTokens: number;
49
+ /** The part of `inputTokens` served from the prompt cache. */
50
+ cacheReadTokens: number;
51
+ outputTokens: number;
52
+ };
39
53
  export type LocalStreamHandlers = {
40
54
  onTextDelta?: (delta: string) => void;
55
+ /** Claude Code's summarized thinking, as it streams. */
56
+ onReasoningDelta?: (delta: string) => void;
57
+ onUsage?: (usage: LocalUsageUpdate) => void;
41
58
  /**
42
59
  * Decide whether the tool may run. Omitted (`--print`, non-interactive)
43
60
  * means deny — the turn continues and the model reports what it could not
@@ -1 +1 @@
1
- {"version":3,"file":"turn.d.ts","sourceRoot":"","sources":["../../../../src/commands/ask/harness/turn.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"turn.d.ts","sourceRoot":"","sources":["../../../../src/commands/ask/harness/turn.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,IAAI,CAAC;AAa/C,OAAO,EAGL,KAAK,oBAAoB,EAE1B,MAAM,YAAY,CAAC;AAEpB;;;GAGG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,oEAAoE;IACpE,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF,8EAA8E;AAC9E,MAAM,MAAM,iBAAiB,GACzB;IACE,IAAI,EAAE,OAAO,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB,GACD;IACE,IAAI,EAAE,KAAK,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB,uEAAuE;IACvE,MAAM,EAAE,MAAM,CAAC;CAChB;AACH;;;;;;GAMG;GACD;IACE,IAAI,EAAE,SAAS,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEN;;;;GAIG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,EAAE,MAAM,GAAG,QAAQ,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,8DAA8D;IAC9D,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,wDAAwD;IACxD,gBAAgB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3C,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAC5C;;;;OAIG;IACH,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,iBAAiB,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/D;;;;;OAKG;IACH,cAAc,CAAC,EAAE,CACf,KAAK,EAAE,OAAO,KACX,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAC,CAAC;IACjD,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,iBAAiB,KAAK,IAAI,CAAC;IACnD,qEAAqE;IACrE,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACtC,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG,mBAAmB,GAAG;IACrD,sEAAsE;IACtE,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,UAAU,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;IACnC,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CAC3B,CAAC;AAEF,4EAA4E;AAC5E,MAAM,MAAM,UAAU,GAAG;IACvB,KAAK,EAAE,MAAM,OAAO,CAAC,UAAU,CAAC,CAAC;IACjC,qBAAqB,EAAE,CACrB,aAAa,EAAE,SAAS,oBAAoB,EAAE,KAC3C,OAAO,CAAC,UAAU,CAAC,CAAC;CAC1B,CAAC;AA8DF;;;;;;GAMG;AACH,wBAAsB,aAAa,CAAC,KAAK,EAAE;IACzC,MAAM,EAAE,UAAU,CAAC;IACnB,QAAQ,EAAE,mBAAmB,GAAG,SAAS,CAAC;IAC1C,WAAW,CAAC,EAAE,oBAAoB,CAAC;IACnC;;;;OAIG;IACH,UAAU,CAAC,EAAE,iBAAiB,EAAE,CAAC;IACjC,qDAAqD;IACrD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,0DAA0D;IAC1D,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB,GAAG,OAAO,CAAC,MAAM,CAAC,CAyIlB;AAgGD;;;;;;;GAOG;AACH,qBAAa,gBAAiB,SAAQ,KAAK;;CAO1C;AAED;;;;;GAKG;AACH,qBAAa,kBAAmB,SAAQ,KAAK;gBAC/B,SAAS,EAAE,MAAM,EAAE,gBAAgB,UAAQ;CAUxD;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAK3D;AAsDD;;;;;;GAMG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,EAAE,SAAS,EAAE,MAAM,iBAe3E"}
@@ -1,6 +1,6 @@
1
1
  import { DENIED_TOOL_REASON, isAlwaysDenied, isAutoApproved, } from "./approvals.js";
2
2
  import { ASK_USER_QUESTION_DENIED_REASON, ASK_USER_QUESTION_TOOL_NAME, formatAskUserQuestionAnswers, summarizeAskUserQuestion, } from "./askUserQuestion.js";
3
- import { addTurnUsage, createTurnAccumulator, } from "./usage.js";
3
+ import { addTurnUsage, createTurnAccumulator, readUsageTokens, } from "./usage.js";
4
4
  /**
5
5
  * How many times one turn may suspend for approvals. Each round trip is a
6
6
  * decision the user made, so this is only a stop for a harness that keeps
@@ -464,6 +464,7 @@ async function consumeTurn(input) {
464
464
  toolCallId,
465
465
  toolName: recorded === undefined ? "tool" : recorded.toolName,
466
466
  isError,
467
+ output: readToolOutputText(part),
467
468
  });
468
469
  }
469
470
  if (typeof toolCallId === "string" && preliminary === false) {
@@ -487,9 +488,33 @@ async function consumeTurn(input) {
487
488
  }
488
489
  if (part["type"] === "finish") {
489
490
  // One suspended turn is several streams, each ending with its own
490
- // `finish` — all of them count. Per-step parts are ignored so the same
491
- // tokens are not counted twice.
491
+ // `finish` — all of them count. Per-step parts stay out of the turn's
492
+ // usage so the same tokens are not counted twice.
492
493
  addTurnUsage(input.accumulator, part);
494
+ const totals = readUsageTokens(part["totalUsage"]);
495
+ if (totals !== undefined && handlers.onUsage !== undefined) {
496
+ handlers.onUsage({ scope: "stream", ...totals });
497
+ }
498
+ continue;
499
+ }
500
+ if (part["type"] === "finish-step") {
501
+ const step = readUsageTokens(part["usage"]);
502
+ if (step !== undefined && handlers.onUsage !== undefined) {
503
+ handlers.onUsage({ scope: "step", ...step });
504
+ }
505
+ continue;
506
+ }
507
+ if (part["type"] === "reasoning-delta") {
508
+ const text = typeof part["text"] === "string"
509
+ ? part["text"]
510
+ : typeof part["delta"] === "string"
511
+ ? part["delta"]
512
+ : undefined;
513
+ if (text !== undefined &&
514
+ text.length > 0 &&
515
+ handlers.onReasoningDelta !== undefined) {
516
+ handlers.onReasoningDelta(text);
517
+ }
493
518
  continue;
494
519
  }
495
520
  if (part["type"] === "tool-approval-request") {
@@ -666,3 +691,60 @@ function isToolErrorPart(part) {
666
691
  part["type"] === "tool-output-error" ||
667
692
  part["type"] === "tool-output-denied");
668
693
  }
694
+ /** Where a finished tool part may carry its result, most specific first. */
695
+ const TOOL_OUTPUT_FIELDS = ["errorText", "error", "output", "result"];
696
+ /** Enough of a tool's output to preview; the rest is never shown. */
697
+ const TOOL_OUTPUT_MAX_LENGTH = 4_000;
698
+ /**
699
+ * A finished tool's result as text, for the transcript. Built-in tools return
700
+ * a string; MCP tools return content blocks; a failure carries an error.
701
+ */
702
+ function readToolOutputText(part) {
703
+ if (part["type"] === "tool-output-denied") {
704
+ return "Denied.";
705
+ }
706
+ // The first field with something in it. The UI stream spells the error
707
+ // `errorText`; older AI SDK parts used `result` for `output`. Presence is
708
+ // not enough: an empty `error` must not hide a real `output`.
709
+ const text = TOOL_OUTPUT_FIELDS.map((field) => toolValueText(part[field])).find((candidate) => candidate.trim() !== "");
710
+ if (text === undefined) {
711
+ return "";
712
+ }
713
+ return text.length > TOOL_OUTPUT_MAX_LENGTH
714
+ ? `${text.slice(0, TOOL_OUTPUT_MAX_LENGTH)}…`
715
+ : text;
716
+ }
717
+ function toolValueText(value) {
718
+ if (value === undefined || value === null) {
719
+ return "";
720
+ }
721
+ if (typeof value === "string") {
722
+ return value;
723
+ }
724
+ if (value instanceof Error) {
725
+ return value.message;
726
+ }
727
+ if (Array.isArray(value)) {
728
+ return value.map(toolValueText).join("\n");
729
+ }
730
+ if (typeof value === "object") {
731
+ const record = value;
732
+ // `{ type: "text", text }` content blocks, and the AI SDK's
733
+ // `{ type: "text", value }` tool output.
734
+ if (typeof record["text"] === "string") {
735
+ return record["text"];
736
+ }
737
+ if (record["type"] === "text" && typeof record["value"] === "string") {
738
+ return record["value"];
739
+ }
740
+ if (Array.isArray(record["content"])) {
741
+ return toolValueText(record["content"]);
742
+ }
743
+ }
744
+ try {
745
+ return JSON.stringify(value, null, 2);
746
+ }
747
+ catch {
748
+ return "";
749
+ }
750
+ }
@@ -1,3 +1,13 @@
1
+ /**
2
+ * Credits the proxy bills for one model call, rounded up to the hundredth
3
+ * per call as it does. `inputTokens` is the whole prompt; cache writes are
4
+ * charged as plain input.
5
+ */
6
+ export declare function creditsForStep(tokens: {
7
+ inputTokens: number;
8
+ cacheReadTokens: number;
9
+ outputTokens: number;
10
+ }): number;
1
11
  /**
2
12
  * What one turn spent upstream, summed over the streams a suspended turn is
3
13
  * made of. `costUsd` is Claude Code's own accounting; the API stores it on
@@ -41,6 +51,15 @@ export declare function didReachAnthropic(usage: LocalTurnUsage): boolean;
41
51
  * cost is stored on the ingested message.
42
52
  */
43
53
  export declare function addTurnUsage(accumulator: LocalTurnAccumulator, part: Record<string, unknown>): void;
54
+ /**
55
+ * Input and output tokens off an AI SDK usage object, or undefined when the
56
+ * part carries none. Input is the whole prompt, cached or not.
57
+ */
58
+ export declare function readUsageTokens(value: unknown): {
59
+ inputTokens: number;
60
+ cacheReadTokens: number;
61
+ outputTokens: number;
62
+ } | undefined;
44
63
  /**
45
64
  * What Claude Code says the turn cost, off the `finish` part.
46
65
  *
@@ -1 +1 @@
1
- {"version":3,"file":"usage.d.ts","sourceRoot":"","sources":["../../../../src/commands/ask/harness/usage.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,oBAAoB,GAAG;IACjC,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,KAAK,EAAE,cAAc,CAAC;IACtB;;;OAGG;IACH,eAAe,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,wBAAgB,qBAAqB,CACnC,mBAAmB,EAAE,MAAM,GAC1B,oBAAoB,CActB;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAEhE;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,WAAW,EAAE,oBAAoB,EACjC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,IAAI,CAwCN;AAQD;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,MAAM,GAAG,SAAS,CA0BpB"}
1
+ {"version":3,"file":"usage.d.ts","sourceRoot":"","sources":["../../../../src/commands/ask/harness/usage.ts"],"names":[],"mappings":"AAeA;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE;IACrC,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;CACtB,GAAG,MAAM,CAWT;AAED;;;;;GAKG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,oBAAoB,GAAG;IACjC,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,KAAK,EAAE,cAAc,CAAC;IACtB;;;OAGG;IACH,eAAe,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,wBAAgB,qBAAqB,CACnC,mBAAmB,EAAE,MAAM,GAC1B,oBAAoB,CActB;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAEhE;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,WAAW,EAAE,oBAAoB,EACjC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,IAAI,CAwCN;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,OAAO,GAEZ;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GACtE,SAAS,CAkBZ;AAQD;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,MAAM,GAAG,SAAS,CA0BpB"}
@@ -1,3 +1,31 @@
1
+ /**
2
+ * What one Cargo credit is worth, and what the sandbox proxy charges per
3
+ * million tokens. Mirrors `USD_PER_CREDIT` and
4
+ * `ANTHROPIC_FALLBACK_RATES_USD_PER_MILLION` in the backend's harness usage:
5
+ * the proxy prices each request from these, not from Claude Code's own cost,
6
+ * so the credits shown after a turn have to use them too.
7
+ */
8
+ const USD_PER_CREDIT = 0.04;
9
+ const PROXY_RATES_USD_PER_MILLION = {
10
+ input: 3,
11
+ output: 15,
12
+ cacheRead: 0.3,
13
+ };
14
+ /**
15
+ * Credits the proxy bills for one model call, rounded up to the hundredth
16
+ * per call as it does. `inputTokens` is the whole prompt; cache writes are
17
+ * charged as plain input.
18
+ */
19
+ export function creditsForStep(tokens) {
20
+ const usdPerMillion = Math.max(tokens.inputTokens - tokens.cacheReadTokens, 0) *
21
+ PROXY_RATES_USD_PER_MILLION.input +
22
+ tokens.cacheReadTokens * PROXY_RATES_USD_PER_MILLION.cacheRead +
23
+ tokens.outputTokens * PROXY_RATES_USD_PER_MILLION.output;
24
+ const credits = usdPerMillion / 1_000_000 / USD_PER_CREDIT;
25
+ // `toFixed` first, as the backend does, so float noise cannot round an
26
+ // exact hundredth up by one.
27
+ return Math.ceil(Number((credits * 100).toFixed(6))) / 100;
28
+ }
1
29
  export function createTurnAccumulator(lastReportedCostUsd) {
2
30
  return {
3
31
  chunks: [],
@@ -57,6 +85,24 @@ export function addTurnUsage(accumulator, part) {
57
85
  usage.reasoningTokens += readCount(details["reasoningTokens"]);
58
86
  }
59
87
  }
88
+ /**
89
+ * Input and output tokens off an AI SDK usage object, or undefined when the
90
+ * part carries none. Input is the whole prompt, cached or not.
91
+ */
92
+ export function readUsageTokens(value) {
93
+ if (typeof value !== "object" || value === null) {
94
+ return undefined;
95
+ }
96
+ const usage = value;
97
+ const inputDetails = usage["inputTokenDetails"];
98
+ return {
99
+ inputTokens: readCount(usage["inputTokens"]),
100
+ cacheReadTokens: typeof inputDetails === "object" && inputDetails !== null
101
+ ? readCount(inputDetails["cacheReadTokens"])
102
+ : 0,
103
+ outputTokens: readCount(usage["outputTokens"]),
104
+ };
105
+ }
60
106
  function readCount(value) {
61
107
  return typeof value === "number" && Number.isFinite(value) && value > 0
62
108
  ? value
@@ -1,5 +1,5 @@
1
1
  /** Chat slash commands offered on Tab when the line is `/…`. */
2
- export declare const ASK_SLASH_COMMANDS: readonly ["/help", "/clear", "/new", "/agent", "/cancel", "/exit"];
2
+ export declare const ASK_SLASH_COMMANDS: readonly ["/help", "/clear", "/new", "/agent", "/tools", "/reasoning", "/cancel", "/exit"];
3
3
  export type AskCompleter = (line: string) => [string[], string];
4
4
  /** What a `/…` token turned out to be. */
5
5
  export type SlashTokenKind = "command" | "path" | "unknown";
@@ -1 +1 @@
1
- {"version":3,"file":"completer.d.ts","sourceRoot":"","sources":["../../../../src/commands/ask/input/completer.ts"],"names":[],"mappings":"AAYA,gEAAgE;AAChE,eAAO,MAAM,kBAAkB,oEAOrB,CAAC;AAEX,MAAM,MAAM,YAAY,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,CAAC,MAAM,EAAE,EAAE,MAAM,CAAC,CAAC;AAEhE,0CAA0C;AAC1C,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAAC;AAE5D;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,cAAc,CAgBhE;AAED,sDAAsD;AACtD,eAAO,MAAM,yBAAyB,IAAI,CAAC;AAE3C;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY,CAU5D;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CASnE;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAYxE;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,EAAE,MAAM,CAAC,GAAG,SAAS,CAY1E;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,EAAE,MAAM,CAAC,CAwE1E"}
1
+ {"version":3,"file":"completer.d.ts","sourceRoot":"","sources":["../../../../src/commands/ask/input/completer.ts"],"names":[],"mappings":"AAYA,gEAAgE;AAChE,eAAO,MAAM,kBAAkB,4FASrB,CAAC;AAEX,MAAM,MAAM,YAAY,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,CAAC,MAAM,EAAE,EAAE,MAAM,CAAC,CAAC;AAEhE,0CAA0C;AAC1C,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAAC;AAE5D;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,cAAc,CAgBhE;AAED,sDAAsD;AACtD,eAAO,MAAM,yBAAyB,IAAI,CAAC;AAE3C;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY,CAU5D;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CASnE;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAYxE;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,EAAE,MAAM,CAAC,GAAG,SAAS,CAY1E;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,EAAE,MAAM,CAAC,CAwE1E"}
@@ -7,6 +7,8 @@ export const ASK_SLASH_COMMANDS = [
7
7
  "/clear",
8
8
  "/new",
9
9
  "/agent",
10
+ "/tools",
11
+ "/reasoning",
10
12
  "/cancel",
11
13
  "/exit",
12
14
  ];
@@ -1 +1 @@
1
- {"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../../../../src/commands/ask/input/prompt.ts"],"names":[],"mappings":";AAiBA;;;;;;GAMG;AACH,qBAAa,cAAe,SAAQ,KAAK;;CAKxC;AASD;;;;;;GAMG;AACH,wBAAsB,WAAW,CAC/B,KAAK,EAAE,MAAM,CAAC,cAAc,EAC5B,GAAG,EAAE,MAAM;AACX;;;;GAIG;AACH,WAAW,SAAK,GACf,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAiQ7B"}
1
+ {"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../../../../src/commands/ask/input/prompt.ts"],"names":[],"mappings":";AAkBA;;;;;;GAMG;AACH,qBAAa,cAAe,SAAQ,KAAK;;CAKxC;AASD;;;;;;GAMG;AACH,wBAAsB,WAAW,CAC/B,KAAK,EAAE,MAAM,CAAC,cAAc,EAC5B,GAAG,EAAE,MAAM;AACX;;;;GAIG;AACH,WAAW,SAAK,GACf,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CA+R7B"}