@cargo-ai/cli 1.0.126 → 1.0.128
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/build/commands/ai/prompt.d.ts.map +1 -1
- package/build/commands/ai/prompt.js +2 -2
- package/build/commands/ask/harness/bridgeOutput.d.ts +19 -0
- package/build/commands/ask/harness/bridgeOutput.d.ts.map +1 -0
- package/build/commands/ask/harness/bridgeOutput.js +42 -0
- package/build/commands/ask/harness/index.d.ts +3 -2
- package/build/commands/ask/harness/index.d.ts.map +1 -1
- package/build/commands/ask/harness/index.js +2 -1
- package/build/commands/ask/harness/turn.d.ts +17 -0
- package/build/commands/ask/harness/turn.d.ts.map +1 -1
- package/build/commands/ask/harness/turn.js +85 -3
- package/build/commands/ask/harness/usage.d.ts +19 -0
- package/build/commands/ask/harness/usage.d.ts.map +1 -1
- package/build/commands/ask/harness/usage.js +46 -0
- package/build/commands/ask/input/completer.d.ts +1 -1
- package/build/commands/ask/input/completer.d.ts.map +1 -1
- package/build/commands/ask/input/completer.js +2 -0
- package/build/commands/ask/input/prompt.d.ts.map +1 -1
- package/build/commands/ask/input/prompt.js +54 -8
- package/build/commands/ask/input/slash.d.ts +7 -1
- package/build/commands/ask/input/slash.d.ts.map +1 -1
- package/build/commands/ask/input/slash.js +10 -0
- package/build/commands/ask/session/index.d.ts +2 -1
- package/build/commands/ask/session/index.d.ts.map +1 -1
- package/build/commands/ask/session/index.js +2 -1
- package/build/commands/ask/session/markdown.d.ts +20 -0
- package/build/commands/ask/session/markdown.d.ts.map +1 -0
- package/build/commands/ask/session/markdown.js +451 -0
- package/build/commands/ask/session/run.d.ts.map +1 -1
- package/build/commands/ask/session/run.js +194 -12
- package/build/commands/ask/session/tree.d.ts +81 -0
- package/build/commands/ask/session/tree.d.ts.map +1 -1
- package/build/commands/ask/session/tree.js +322 -51
- package/build/commands/auth/index.js +1 -1
- package/build/commands/connection/connector.d.ts.map +1 -1
- package/build/commands/connection/connector.js +1 -1
- package/build/commands/hosting/envVar.d.ts.map +1 -1
- package/build/commands/hosting/envVar.js +15 -6
- package/build/commands/orchestration/span.js +2 -2
- package/build/commands/orchestration/trace.js +2 -2
- package/build/commands/runHandler.d.ts +1 -0
- package/build/commands/runHandler.d.ts.map +1 -1
- package/build/commands/runHandler.js +6 -3
- package/build/commands/segmentation/change.js +1 -1
- package/build/commands/workspaceManagement/user.d.ts.map +1 -1
- package/build/commands/workspaceManagement/user.js +8 -5
- package/build/utils/textWidth.d.ts +25 -0
- package/build/utils/textWidth.d.ts.map +1 -0
- package/build/utils/textWidth.js +147 -0
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../../../src/commands/ai/prompt.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEzC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAGxC,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,OAAO,EACf,MAAM,EAAE,MAAM,GAAG,GAChB,IAAI,
|
|
1
|
+
{"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../../../src/commands/ai/prompt.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEzC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAGxC,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,OAAO,EACf,MAAM,EAAE,MAAM,GAAG,GAChB,IAAI,CAqFN"}
|
|
@@ -2,7 +2,7 @@ import { handleApiCall, outputJson, parseJson } from "../runHandler.js";
|
|
|
2
2
|
export function registerPromptCommands(parent, getApi) {
|
|
3
3
|
const prompt = parent
|
|
4
4
|
.command("prompt")
|
|
5
|
-
.description("Optimize and
|
|
5
|
+
.description("Optimize and render AI prompts");
|
|
6
6
|
prompt
|
|
7
7
|
.command("optimize")
|
|
8
8
|
.description("Optimize a prompt for better AI performance")
|
|
@@ -17,7 +17,7 @@ Example:
|
|
|
17
17
|
});
|
|
18
18
|
prompt
|
|
19
19
|
.command("evaluate")
|
|
20
|
-
.description("
|
|
20
|
+
.description("Render a prompt's template expressions against the variables its actions, resources and capabilities provide — the prompt the agent will actually see. It does not score the prompt")
|
|
21
21
|
.requiredOption("--prompt <text>", "Prompt text to evaluate (string, required)")
|
|
22
22
|
.option("--actions <json>", "Available actions context (JSON array of action objects, default: [])")
|
|
23
23
|
.option("--resources <json>", "Available resources context (JSON array of resource objects, default: [])")
|
|
@@ -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,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
8
|
export { replayKnownToolCalls, routeSessionEvents, 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";
|
|
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,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
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";
|
|
@@ -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":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,IAAI,CAAC;AAa/C,OAAO,EAGL,KAAK,oBAAoB,
|
|
1
|
+
{"version":3,"file":"turn.d.ts","sourceRoot":"","sources":["../../../../src/commands/ask/harness/turn.ts"],"names":[],"mappings":"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"}
|
|
@@ -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
|
|
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":"
|
|
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,
|
|
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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../../../../src/commands/ask/input/prompt.ts"],"names":[],"mappings":";
|
|
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"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as readline from "node:readline";
|
|
2
|
-
import {
|
|
2
|
+
import { cellWidth, textCells } from "../../../utils/textWidth.js";
|
|
3
|
+
import { clipToWidth, colors } from "../../runHandler.js";
|
|
3
4
|
import { applyCompletion, ASK_COMPLETION_MENU_LIMIT, listCompletions, } from "./completer.js";
|
|
4
5
|
/**
|
|
5
6
|
* Ctrl-C on the Ask line.
|
|
@@ -37,6 +38,9 @@ initialLine = "") {
|
|
|
37
38
|
let cursor = initialLine.length;
|
|
38
39
|
let selected = 0;
|
|
39
40
|
let painted = false;
|
|
41
|
+
// Rows between the ◆ row and the cursor. A line longer than the terminal
|
|
42
|
+
// wraps, and the next clear has to start from the ◆ row, not the cursor's.
|
|
43
|
+
let cursorRow = 0;
|
|
40
44
|
let finished = false;
|
|
41
45
|
const wasRaw = isTTYStream(input) ? input.isRaw === true : false;
|
|
42
46
|
if (isTTYStream(input) === true) {
|
|
@@ -171,9 +175,13 @@ initialLine = "") {
|
|
|
171
175
|
if (painted === false || process.stderr.isTTY !== true) {
|
|
172
176
|
return;
|
|
173
177
|
}
|
|
174
|
-
//
|
|
178
|
+
// Back up to the ◆ row; wipe from there through the menu below.
|
|
179
|
+
if (cursorRow > 0) {
|
|
180
|
+
process.stderr.write(`\x1B[${String(cursorRow)}A`);
|
|
181
|
+
}
|
|
175
182
|
process.stderr.write("\r\x1B[J");
|
|
176
183
|
painted = false;
|
|
184
|
+
cursorRow = 0;
|
|
177
185
|
}
|
|
178
186
|
function paint() {
|
|
179
187
|
const matches = visibleMatches();
|
|
@@ -181,7 +189,16 @@ initialLine = "") {
|
|
|
181
189
|
selected = matches.length === 0 ? 0 : matches.length - 1;
|
|
182
190
|
}
|
|
183
191
|
clearFrame();
|
|
192
|
+
const columns = process.stderr.columns === undefined ? 80 : process.stderr.columns;
|
|
193
|
+
// The terminal wraps the line itself; this says where it ends up.
|
|
194
|
+
const end = layoutCells(`◆ ${line}`, columns);
|
|
184
195
|
process.stderr.write(`${colors.cyan("◆")} ${line}`);
|
|
196
|
+
// Text ending exactly at the edge leaves the cursor parked on that row
|
|
197
|
+
// until something is written. Step onto the next row so the count holds.
|
|
198
|
+
if (line.length > 0 && end.column === columns) {
|
|
199
|
+
process.stderr.write("\r\n");
|
|
200
|
+
}
|
|
201
|
+
let row = end.column === columns ? end.row + 1 : end.row;
|
|
185
202
|
if (matches.length > 0) {
|
|
186
203
|
process.stderr.write("\n");
|
|
187
204
|
for (let index = 0; index < matches.length; index += 1) {
|
|
@@ -191,18 +208,25 @@ initialLine = "") {
|
|
|
191
208
|
}
|
|
192
209
|
const active = index === selected;
|
|
193
210
|
const bullet = active === true ? colors.cyan("●") : colors.dim("○");
|
|
194
|
-
|
|
211
|
+
// One row each, or the count of rows to climb back is off.
|
|
212
|
+
const text = clipToWidth(hit, columns - 5);
|
|
213
|
+
const label = active === true ? colors.cyan(text) : colors.dim(text);
|
|
195
214
|
process.stderr.write(`${colors.dim("│")} ${bullet} ${label}`);
|
|
196
215
|
if (index < matches.length - 1) {
|
|
197
216
|
process.stderr.write("\n");
|
|
198
217
|
}
|
|
199
218
|
}
|
|
200
|
-
|
|
201
|
-
|
|
219
|
+
row += matches.length;
|
|
220
|
+
}
|
|
221
|
+
// Back to the cursor's cell inside the (possibly wrapped) line.
|
|
222
|
+
const at = layoutCells(`◆ ${line.slice(0, cursor)}`, columns);
|
|
223
|
+
const targetRow = at.column === columns ? at.row + 1 : at.row;
|
|
224
|
+
const targetColumn = (at.column === columns ? 0 : at.column) + 1;
|
|
225
|
+
if (row > targetRow) {
|
|
226
|
+
process.stderr.write(`\x1B[${String(row - targetRow)}A`);
|
|
202
227
|
}
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
process.stderr.write(`\r\x1B[${String(column)}G`);
|
|
228
|
+
process.stderr.write(`\r\x1B[${String(targetColumn)}G`);
|
|
229
|
+
cursorRow = targetRow;
|
|
206
230
|
painted = true;
|
|
207
231
|
}
|
|
208
232
|
function cleanup() {
|
|
@@ -232,3 +256,25 @@ initialLine = "") {
|
|
|
232
256
|
}
|
|
233
257
|
});
|
|
234
258
|
}
|
|
259
|
+
/**
|
|
260
|
+
* Where the terminal leaves the cursor after writing `text` from the start of
|
|
261
|
+
* a row: the row it is on, and how many columns of it are filled. A filled
|
|
262
|
+
* row stays the cursor's row until the next character, which is why `column`
|
|
263
|
+
* can equal `columns`.
|
|
264
|
+
*
|
|
265
|
+
* Walked character by character rather than divided out: an emoji or a CJK
|
|
266
|
+
* character takes two columns, and one that does not fit in the last column
|
|
267
|
+
* starts the next row and leaves that column empty.
|
|
268
|
+
*/
|
|
269
|
+
function layoutCells(text, columns) {
|
|
270
|
+
const position = { row: 0, column: 0 };
|
|
271
|
+
for (const cell of textCells(text)) {
|
|
272
|
+
const width = cellWidth(cell);
|
|
273
|
+
if (position.column + width > columns) {
|
|
274
|
+
position.row += 1;
|
|
275
|
+
position.column = 0;
|
|
276
|
+
}
|
|
277
|
+
position.column += width;
|
|
278
|
+
}
|
|
279
|
+
return position;
|
|
280
|
+
}
|
|
@@ -6,7 +6,13 @@ export type SlashAction = {
|
|
|
6
6
|
kind: "action";
|
|
7
7
|
action: "exit" | "new" | "clear" | "pick-agent" | "cancel";
|
|
8
8
|
};
|
|
9
|
-
|
|
9
|
+
/** `/tools` or `/reasoning`, with the display asked for if one was given. */
|
|
10
|
+
export type SlashDisplay = {
|
|
11
|
+
kind: "display";
|
|
12
|
+
setting: "tools" | "reasoning";
|
|
13
|
+
value: string | undefined;
|
|
14
|
+
};
|
|
15
|
+
export type SlashResult = SlashCard | SlashAction | SlashDisplay;
|
|
10
16
|
/**
|
|
11
17
|
* Parse a user line that starts with `/`. Anything else is prose for the agent.
|
|
12
18
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"slash.d.ts","sourceRoot":"","sources":["../../../../src/commands/ask/input/slash.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,SAAS,GAAG;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,QAAQ,CAAC;IACf,MAAM,EAAE,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,YAAY,GAAG,QAAQ,CAAC;CAC5D,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"slash.d.ts","sourceRoot":"","sources":["../../../../src/commands/ask/input/slash.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,SAAS,GAAG;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,QAAQ,CAAC;IACf,MAAM,EAAE,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,YAAY,GAAG,QAAQ,CAAC;CAC5D,CAAC;AAEF,6EAA6E;AAC7E,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,EAAE,OAAO,GAAG,WAAW,CAAC;IAC/B,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,WAAW,GAAG,YAAY,CAAC;AAqBjE;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,CA+DhE;AAED,qBAAa,iBAAkB,SAAQ,KAAK;IAC1C,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC,QAAQ,CAAC,CAAC;gBAE3B,MAAM,EAAE,WAAW,CAAC,QAAQ,CAAC;CAK1C"}
|
|
@@ -6,6 +6,8 @@ const HELP_TEXT = [
|
|
|
6
6
|
"/clear Start a fresh local session (no agent)",
|
|
7
7
|
"/new Same as /clear",
|
|
8
8
|
"/agent Pick a workspace agent, or Local workspace (default). Stays on this machine.",
|
|
9
|
+
"/tools How tool calls show: full, collapsed (default), hidden",
|
|
10
|
+
"/reasoning How thinking shows: full, auto-collapsed (default), collapsed, hidden",
|
|
9
11
|
"/cancel Explain how to stop a turn (press Ctrl-C while it runs)",
|
|
10
12
|
"/exit Leave without asking (same as an empty line)",
|
|
11
13
|
"",
|
|
@@ -52,6 +54,14 @@ export function parseSlash(text) {
|
|
|
52
54
|
if (command === "agent") {
|
|
53
55
|
return { kind: "action", action: "pick-agent" };
|
|
54
56
|
}
|
|
57
|
+
if (command === "tools" || command === "reasoning") {
|
|
58
|
+
const value = trimmed.split(/\s+/)[1];
|
|
59
|
+
return {
|
|
60
|
+
kind: "display",
|
|
61
|
+
setting: command,
|
|
62
|
+
value: value === undefined ? undefined : value.toLowerCase(),
|
|
63
|
+
};
|
|
64
|
+
}
|
|
55
65
|
if (command === "cancel") {
|
|
56
66
|
return { kind: "action", action: "cancel" };
|
|
57
67
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { type ChatTurnClaim, claimChatTurn, proxyTokenDeadlineMs, } from "./claim.js";
|
|
2
|
+
export { renderMarkdown } from "./markdown.js";
|
|
2
3
|
export { type AskSessionOptions, doesChatExist, runAskPrint, runAskSession, } from "./run.js";
|
|
3
4
|
export { ASK_THINKING_WORDS, pickThinkingWord } from "./thinking.js";
|
|
4
|
-
export { displayPath, wrapLine } from "./tree.js";
|
|
5
|
+
export { displayPath, showTurnStats, wrapLine } from "./tree.js";
|
|
5
6
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/commands/ask/session/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,aAAa,EAClB,aAAa,EACb,oBAAoB,GACrB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,KAAK,iBAAiB,EACtB,aAAa,EACb,WAAW,EACX,aAAa,GACd,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACrE,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/commands/ask/session/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,aAAa,EAClB,aAAa,EACb,oBAAoB,GACrB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EACL,KAAK,iBAAiB,EACtB,aAAa,EACb,WAAW,EACX,aAAa,GACd,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACrE,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { claimChatTurn, proxyTokenDeadlineMs, } from "./claim.js";
|
|
2
|
+
export { renderMarkdown } from "./markdown.js";
|
|
2
3
|
export { doesChatExist, runAskPrint, runAskSession, } from "./run.js";
|
|
3
4
|
export { ASK_THINKING_WORDS, pickThinkingWord } from "./thinking.js";
|
|
4
|
-
export { displayPath, wrapLine } from "./tree.js";
|
|
5
|
+
export { displayPath, showTurnStats, wrapLine } from "./tree.js";
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The model's markdown, drawn for the tree: headings, lists, quotes, code
|
|
3
|
+
* fences, rules and tables, with bold, italic, code and links inline.
|
|
4
|
+
*
|
|
5
|
+
* The block and table handling follows `@ai-sdk/tui`'s renderer
|
|
6
|
+
* (`src/tui/markdown.ts`). It is not exported from that package, and its
|
|
7
|
+
* output assumes it owns the whole width, so it is redone here around the
|
|
8
|
+
* rail: every line comes back already wrapped to `width`, because a line the
|
|
9
|
+
* terminal soft-wraps starts its next row at column zero, outside the tree.
|
|
10
|
+
*
|
|
11
|
+
* Styles are applied word by word rather than across a span. A colour code
|
|
12
|
+
* here ends with a full reset, so a bold phrase that wraps would lose its
|
|
13
|
+
* bold at the rail drawn in between.
|
|
14
|
+
*
|
|
15
|
+
* Exported for tests.
|
|
16
|
+
*/
|
|
17
|
+
export declare function renderMarkdown(text: string, width: number, tone?: MarkdownTone): string[];
|
|
18
|
+
/** `dim` is for text that is not the answer, such as the model's reasoning. */
|
|
19
|
+
export type MarkdownTone = "normal" | "dim";
|
|
20
|
+
//# sourceMappingURL=markdown.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../../../src/commands/ask/session/markdown.ts"],"names":[],"mappings":"AAQA;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,IAAI,GAAE,YAAuB,GAC5B,MAAM,EAAE,CA6CV;AAED,+EAA+E;AAC/E,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,KAAK,CAAC"}
|