@probelabs/probe 0.6.0-rc138 → 0.6.0-rc140
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/agent/index.js +101 -47
- package/build/extract.js +142 -59
- package/cjs/agent/ProbeAgent.cjs +375 -315
- package/cjs/index.cjs +375 -315
- package/index.d.ts +10 -2
- package/package.json +1 -1
- package/src/extract.js +142 -59
package/build/agent/index.js
CHANGED
|
@@ -2689,21 +2689,26 @@ var init_query = __esm({
|
|
|
2689
2689
|
});
|
|
2690
2690
|
|
|
2691
2691
|
// src/extract.js
|
|
2692
|
-
import { exec as exec4 } from "child_process";
|
|
2692
|
+
import { exec as exec4, spawn } from "child_process";
|
|
2693
2693
|
import { promisify as promisify4 } from "util";
|
|
2694
2694
|
async function extract(options) {
|
|
2695
2695
|
if (!options) {
|
|
2696
2696
|
throw new Error("Options object is required");
|
|
2697
2697
|
}
|
|
2698
|
-
|
|
2699
|
-
|
|
2698
|
+
const hasFiles = options.files && Array.isArray(options.files) && options.files.length > 0;
|
|
2699
|
+
const hasInputFile = !!options.inputFile;
|
|
2700
|
+
const hasContent = options.content !== void 0 && options.content !== null;
|
|
2701
|
+
if (!hasFiles && !hasInputFile && !hasContent) {
|
|
2702
|
+
throw new Error("Either files array, inputFile, or content must be provided");
|
|
2700
2703
|
}
|
|
2701
2704
|
const binaryPath = await getBinaryPath(options.binaryOptions || {});
|
|
2702
|
-
const
|
|
2705
|
+
const filteredOptions = { ...options };
|
|
2706
|
+
delete filteredOptions.content;
|
|
2707
|
+
const cliArgs = buildCliArgs(filteredOptions, EXTRACT_FLAG_MAP);
|
|
2703
2708
|
if (options.json && !options.format) {
|
|
2704
2709
|
cliArgs.push("--format", "json");
|
|
2705
2710
|
}
|
|
2706
|
-
if (
|
|
2711
|
+
if (hasFiles) {
|
|
2707
2712
|
for (const file of options.files) {
|
|
2708
2713
|
cliArgs.push(escapeString(file));
|
|
2709
2714
|
}
|
|
@@ -2715,66 +2720,115 @@ Extract:`;
|
|
|
2715
2720
|
logMessage += ` files="${options.files.join(", ")}"`;
|
|
2716
2721
|
}
|
|
2717
2722
|
if (options.inputFile) logMessage += ` inputFile="${options.inputFile}"`;
|
|
2723
|
+
if (options.content) logMessage += ` content=(${typeof options.content === "string" ? options.content.length : options.content.byteLength} bytes)`;
|
|
2718
2724
|
if (options.allowTests) logMessage += " allowTests=true";
|
|
2719
2725
|
if (options.contextLines) logMessage += ` contextLines=${options.contextLines}`;
|
|
2720
2726
|
if (options.format) logMessage += ` format=${options.format}`;
|
|
2721
2727
|
if (options.json) logMessage += " json=true";
|
|
2722
2728
|
console.error(logMessage);
|
|
2723
2729
|
}
|
|
2730
|
+
if (hasContent) {
|
|
2731
|
+
return extractWithStdin(binaryPath, cliArgs, options.content, options);
|
|
2732
|
+
}
|
|
2724
2733
|
const command = `${binaryPath} extract ${cliArgs.join(" ")}`;
|
|
2725
2734
|
try {
|
|
2726
2735
|
const { stdout, stderr } = await execAsync3(command);
|
|
2727
2736
|
if (stderr) {
|
|
2728
2737
|
console.error(`stderr: ${stderr}`);
|
|
2729
2738
|
}
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2739
|
+
return processExtractOutput(stdout, options);
|
|
2740
|
+
} catch (error) {
|
|
2741
|
+
const errorMessage = `Error executing extract command: ${error.message}
|
|
2742
|
+
Command: ${command}`;
|
|
2743
|
+
throw new Error(errorMessage);
|
|
2744
|
+
}
|
|
2745
|
+
}
|
|
2746
|
+
function extractWithStdin(binaryPath, cliArgs, content, options) {
|
|
2747
|
+
return new Promise((resolve5, reject2) => {
|
|
2748
|
+
const childProcess = spawn(binaryPath, ["extract", ...cliArgs], {
|
|
2749
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
2750
|
+
});
|
|
2751
|
+
let stdout = "";
|
|
2752
|
+
let stderr = "";
|
|
2753
|
+
childProcess.stdout.on("data", (data) => {
|
|
2754
|
+
stdout += data.toString();
|
|
2755
|
+
});
|
|
2756
|
+
childProcess.stderr.on("data", (data) => {
|
|
2757
|
+
stderr += data.toString();
|
|
2758
|
+
});
|
|
2759
|
+
childProcess.on("close", (code) => {
|
|
2760
|
+
if (stderr && process.env.DEBUG === "1") {
|
|
2761
|
+
console.error(`stderr: ${stderr}`);
|
|
2762
|
+
}
|
|
2763
|
+
if (code !== 0) {
|
|
2764
|
+
reject2(new Error(`Extract command failed with exit code ${code}: ${stderr}`));
|
|
2765
|
+
return;
|
|
2745
2766
|
}
|
|
2767
|
+
try {
|
|
2768
|
+
const result = processExtractOutput(stdout, options);
|
|
2769
|
+
resolve5(result);
|
|
2770
|
+
} catch (error) {
|
|
2771
|
+
reject2(error);
|
|
2772
|
+
}
|
|
2773
|
+
});
|
|
2774
|
+
childProcess.on("error", (error) => {
|
|
2775
|
+
reject2(new Error(`Failed to spawn extract process: ${error.message}`));
|
|
2776
|
+
});
|
|
2777
|
+
if (typeof content === "string") {
|
|
2778
|
+
childProcess.stdin.write(content);
|
|
2779
|
+
} else {
|
|
2780
|
+
childProcess.stdin.write(content);
|
|
2746
2781
|
}
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2782
|
+
childProcess.stdin.end();
|
|
2783
|
+
});
|
|
2784
|
+
}
|
|
2785
|
+
function processExtractOutput(stdout, options) {
|
|
2786
|
+
let tokenUsage = {
|
|
2787
|
+
requestTokens: 0,
|
|
2788
|
+
responseTokens: 0,
|
|
2789
|
+
totalTokens: 0
|
|
2790
|
+
};
|
|
2791
|
+
if (options.files && Array.isArray(options.files)) {
|
|
2792
|
+
tokenUsage.requestTokens = options.files.join(" ").length / 4;
|
|
2793
|
+
} else if (options.inputFile) {
|
|
2794
|
+
tokenUsage.requestTokens = options.inputFile.length / 4;
|
|
2795
|
+
} else if (options.content) {
|
|
2796
|
+
const contentLength = typeof options.content === "string" ? options.content.length : options.content.byteLength;
|
|
2797
|
+
tokenUsage.requestTokens = contentLength / 4;
|
|
2798
|
+
}
|
|
2799
|
+
if (stdout.includes("Total tokens returned:")) {
|
|
2800
|
+
const tokenMatch = stdout.match(/Total tokens returned: (\d+)/);
|
|
2801
|
+
if (tokenMatch && tokenMatch[1]) {
|
|
2802
|
+
tokenUsage.responseTokens = parseInt(tokenMatch[1], 10);
|
|
2803
|
+
tokenUsage.totalTokens = tokenUsage.requestTokens + tokenUsage.responseTokens;
|
|
2804
|
+
}
|
|
2805
|
+
}
|
|
2806
|
+
let output = stdout;
|
|
2807
|
+
if (!output.includes("Token Usage:")) {
|
|
2808
|
+
output += `
|
|
2750
2809
|
Token Usage:
|
|
2751
2810
|
Request tokens: ${tokenUsage.requestTokens}
|
|
2752
2811
|
Response tokens: ${tokenUsage.responseTokens}
|
|
2753
2812
|
Total tokens: ${tokenUsage.totalTokens}
|
|
2754
2813
|
`;
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
}
|
|
2766
|
-
return jsonOutput;
|
|
2767
|
-
} catch (error) {
|
|
2768
|
-
console.error("Error parsing JSON output:", error);
|
|
2769
|
-
return output;
|
|
2814
|
+
}
|
|
2815
|
+
if (options.json || options.format === "json") {
|
|
2816
|
+
try {
|
|
2817
|
+
const jsonOutput = JSON.parse(stdout);
|
|
2818
|
+
if (!jsonOutput.token_usage) {
|
|
2819
|
+
jsonOutput.token_usage = {
|
|
2820
|
+
request_tokens: tokenUsage.requestTokens,
|
|
2821
|
+
response_tokens: tokenUsage.responseTokens,
|
|
2822
|
+
total_tokens: tokenUsage.totalTokens
|
|
2823
|
+
};
|
|
2770
2824
|
}
|
|
2825
|
+
return jsonOutput;
|
|
2826
|
+
} catch (error) {
|
|
2827
|
+
console.error("Error parsing JSON output:", error);
|
|
2828
|
+
return output;
|
|
2771
2829
|
}
|
|
2772
|
-
return output;
|
|
2773
|
-
} catch (error) {
|
|
2774
|
-
const errorMessage = `Error executing extract command: ${error.message}
|
|
2775
|
-
Command: ${command}`;
|
|
2776
|
-
throw new Error(errorMessage);
|
|
2777
2830
|
}
|
|
2831
|
+
return output;
|
|
2778
2832
|
}
|
|
2779
2833
|
var execAsync3, EXTRACT_FLAG_MAP;
|
|
2780
2834
|
var init_extract = __esm({
|
|
@@ -7275,7 +7329,7 @@ I have refactored the search module according to the requirements and verified t
|
|
|
7275
7329
|
});
|
|
7276
7330
|
|
|
7277
7331
|
// src/delegate.js
|
|
7278
|
-
import { spawn } from "child_process";
|
|
7332
|
+
import { spawn as spawn2 } from "child_process";
|
|
7279
7333
|
import { randomUUID } from "crypto";
|
|
7280
7334
|
async function delegate({ task, timeout = 300, debug = false, currentIteration = 0, maxIterations = 30, tracer = null }) {
|
|
7281
7335
|
if (!task || typeof task !== "string") {
|
|
@@ -7318,7 +7372,7 @@ async function delegate({ task, timeout = 300, debug = false, currentIteration =
|
|
|
7318
7372
|
}
|
|
7319
7373
|
return new Promise((resolve5, reject2) => {
|
|
7320
7374
|
const delegationSpan = tracer ? tracer.createDelegationSpan(sessionId, task) : null;
|
|
7321
|
-
const process2 =
|
|
7375
|
+
const process2 = spawn2(binaryPath, args, {
|
|
7322
7376
|
stdio: ["pipe", "pipe", "pipe"],
|
|
7323
7377
|
timeout: timeout * 1e3
|
|
7324
7378
|
});
|
|
@@ -8476,7 +8530,7 @@ var init_bashPermissions = __esm({
|
|
|
8476
8530
|
});
|
|
8477
8531
|
|
|
8478
8532
|
// src/agent/bashExecutor.js
|
|
8479
|
-
import { spawn as
|
|
8533
|
+
import { spawn as spawn3 } from "child_process";
|
|
8480
8534
|
import { resolve, join } from "path";
|
|
8481
8535
|
import { existsSync } from "fs";
|
|
8482
8536
|
async function executeBashCommand(command, options = {}) {
|
|
@@ -8533,7 +8587,7 @@ async function executeBashCommand(command, options = {}) {
|
|
|
8533
8587
|
return;
|
|
8534
8588
|
}
|
|
8535
8589
|
const [cmd, ...cmdArgs] = args;
|
|
8536
|
-
const child =
|
|
8590
|
+
const child = spawn3(cmd, cmdArgs, {
|
|
8537
8591
|
cwd,
|
|
8538
8592
|
env: processEnv,
|
|
8539
8593
|
stdio: ["ignore", "pipe", "pipe"],
|
package/build/extract.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* @module extract
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { exec } from 'child_process';
|
|
6
|
+
import { exec, spawn } from 'child_process';
|
|
7
7
|
import { promisify } from 'util';
|
|
8
8
|
import { getBinaryPath, buildCliArgs, escapeString } from './utils.js';
|
|
9
9
|
|
|
@@ -22,13 +22,14 @@ const EXTRACT_FLAG_MAP = {
|
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
24
|
* Extract code blocks from files
|
|
25
|
-
*
|
|
25
|
+
*
|
|
26
26
|
* @param {Object} options - Extract options
|
|
27
27
|
* @param {string[]} [options.files] - Files to extract from (can include line numbers with colon, e.g., "/path/to/file.rs:10")
|
|
28
28
|
* @param {string} [options.inputFile] - Path to a file containing unstructured text to extract file paths from
|
|
29
|
+
* @param {string|Buffer} [options.content] - Content to pipe to stdin (e.g., git diff output). Alternative to inputFile.
|
|
29
30
|
* @param {boolean} [options.allowTests] - Include test files
|
|
30
31
|
* @param {number} [options.contextLines] - Number of context lines to include
|
|
31
|
-
* @param {string} [options.format] - Output format ('markdown', 'plain', 'json')
|
|
32
|
+
* @param {string} [options.format] - Output format ('markdown', 'plain', 'json', 'xml', 'color', 'outline-xml', 'outline-diff')
|
|
32
33
|
* @param {Object} [options.binaryOptions] - Options for getting the binary
|
|
33
34
|
* @param {boolean} [options.binaryOptions.forceDownload] - Force download even if binary exists
|
|
34
35
|
* @param {string} [options.binaryOptions.version] - Specific version to download
|
|
@@ -41,16 +42,22 @@ export async function extract(options) {
|
|
|
41
42
|
throw new Error('Options object is required');
|
|
42
43
|
}
|
|
43
44
|
|
|
44
|
-
// Either files or
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
// Either files, inputFile, or content must be provided
|
|
46
|
+
const hasFiles = options.files && Array.isArray(options.files) && options.files.length > 0;
|
|
47
|
+
const hasInputFile = !!options.inputFile;
|
|
48
|
+
const hasContent = options.content !== undefined && options.content !== null;
|
|
49
|
+
|
|
50
|
+
if (!hasFiles && !hasInputFile && !hasContent) {
|
|
51
|
+
throw new Error('Either files array, inputFile, or content must be provided');
|
|
47
52
|
}
|
|
48
53
|
|
|
49
54
|
// Get the binary path
|
|
50
55
|
const binaryPath = await getBinaryPath(options.binaryOptions || {});
|
|
51
56
|
|
|
52
|
-
// Build CLI arguments from options
|
|
53
|
-
const
|
|
57
|
+
// Build CLI arguments from options (excluding content which goes via stdin)
|
|
58
|
+
const filteredOptions = { ...options };
|
|
59
|
+
delete filteredOptions.content;
|
|
60
|
+
const cliArgs = buildCliArgs(filteredOptions, EXTRACT_FLAG_MAP);
|
|
54
61
|
|
|
55
62
|
// If json option is true, override format to json
|
|
56
63
|
if (options.json && !options.format) {
|
|
@@ -58,7 +65,7 @@ export async function extract(options) {
|
|
|
58
65
|
}
|
|
59
66
|
|
|
60
67
|
// Add files as positional arguments if provided
|
|
61
|
-
if (
|
|
68
|
+
if (hasFiles) {
|
|
62
69
|
for (const file of options.files) {
|
|
63
70
|
cliArgs.push(escapeString(file));
|
|
64
71
|
}
|
|
@@ -71,6 +78,7 @@ export async function extract(options) {
|
|
|
71
78
|
logMessage += ` files="${options.files.join(', ')}"`;
|
|
72
79
|
}
|
|
73
80
|
if (options.inputFile) logMessage += ` inputFile="${options.inputFile}"`;
|
|
81
|
+
if (options.content) logMessage += ` content=(${typeof options.content === 'string' ? options.content.length : options.content.byteLength} bytes)`;
|
|
74
82
|
if (options.allowTests) logMessage += " allowTests=true";
|
|
75
83
|
if (options.contextLines) logMessage += ` contextLines=${options.contextLines}`;
|
|
76
84
|
if (options.format) logMessage += ` format=${options.format}`;
|
|
@@ -78,7 +86,12 @@ export async function extract(options) {
|
|
|
78
86
|
console.error(logMessage);
|
|
79
87
|
}
|
|
80
88
|
|
|
81
|
-
//
|
|
89
|
+
// If content is provided, use spawn with stdin piping
|
|
90
|
+
if (hasContent) {
|
|
91
|
+
return extractWithStdin(binaryPath, cliArgs, options.content, options);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Otherwise use exec for simple command execution
|
|
82
95
|
const command = `${binaryPath} extract ${cliArgs.join(' ')}`;
|
|
83
96
|
|
|
84
97
|
try {
|
|
@@ -88,62 +101,132 @@ export async function extract(options) {
|
|
|
88
101
|
console.error(`stderr: ${stderr}`);
|
|
89
102
|
}
|
|
90
103
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
// Calculate approximate request tokens
|
|
99
|
-
if (options.files && Array.isArray(options.files)) {
|
|
100
|
-
tokenUsage.requestTokens = options.files.join(' ').length / 4;
|
|
101
|
-
} else if (options.inputFile) {
|
|
102
|
-
tokenUsage.requestTokens = options.inputFile.length / 4;
|
|
103
|
-
}
|
|
104
|
+
return processExtractOutput(stdout, options);
|
|
105
|
+
} catch (error) {
|
|
106
|
+
// Enhance error message with command details
|
|
107
|
+
const errorMessage = `Error executing extract command: ${error.message}\nCommand: ${command}`;
|
|
108
|
+
throw new Error(errorMessage);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
104
111
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
112
|
+
/**
|
|
113
|
+
* Extract with content piped to stdin
|
|
114
|
+
* @private
|
|
115
|
+
*/
|
|
116
|
+
function extractWithStdin(binaryPath, cliArgs, content, options) {
|
|
117
|
+
return new Promise((resolve, reject) => {
|
|
118
|
+
const childProcess = spawn(binaryPath, ['extract', ...cliArgs], {
|
|
119
|
+
stdio: ['pipe', 'pipe', 'pipe']
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
let stdout = '';
|
|
123
|
+
let stderr = '';
|
|
124
|
+
|
|
125
|
+
// Collect stdout
|
|
126
|
+
childProcess.stdout.on('data', (data) => {
|
|
127
|
+
stdout += data.toString();
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
// Collect stderr
|
|
131
|
+
childProcess.stderr.on('data', (data) => {
|
|
132
|
+
stderr += data.toString();
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
// Handle process exit
|
|
136
|
+
childProcess.on('close', (code) => {
|
|
137
|
+
if (stderr && process.env.DEBUG === '1') {
|
|
138
|
+
console.error(`stderr: ${stderr}`);
|
|
111
139
|
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// Add token usage information to the output
|
|
115
|
-
let output = stdout;
|
|
116
140
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
141
|
+
if (code !== 0) {
|
|
142
|
+
reject(new Error(`Extract command failed with exit code ${code}: ${stderr}`));
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
121
145
|
|
|
122
|
-
// Parse JSON if requested or if format is json
|
|
123
|
-
if (options.json || options.format === 'json') {
|
|
124
146
|
try {
|
|
125
|
-
const
|
|
126
|
-
|
|
127
|
-
// Add token usage to JSON output
|
|
128
|
-
if (!jsonOutput.token_usage) {
|
|
129
|
-
jsonOutput.token_usage = {
|
|
130
|
-
request_tokens: tokenUsage.requestTokens,
|
|
131
|
-
response_tokens: tokenUsage.responseTokens,
|
|
132
|
-
total_tokens: tokenUsage.totalTokens
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
return jsonOutput;
|
|
147
|
+
const result = processExtractOutput(stdout, options);
|
|
148
|
+
resolve(result);
|
|
137
149
|
} catch (error) {
|
|
138
|
-
|
|
139
|
-
return output; // Fall back to string output with token usage
|
|
150
|
+
reject(error);
|
|
140
151
|
}
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
// Handle errors
|
|
155
|
+
childProcess.on('error', (error) => {
|
|
156
|
+
reject(new Error(`Failed to spawn extract process: ${error.message}`));
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
// Write content to stdin and close
|
|
160
|
+
if (typeof content === 'string') {
|
|
161
|
+
childProcess.stdin.write(content);
|
|
162
|
+
} else {
|
|
163
|
+
childProcess.stdin.write(content);
|
|
141
164
|
}
|
|
165
|
+
childProcess.stdin.end();
|
|
166
|
+
});
|
|
167
|
+
}
|
|
142
168
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
169
|
+
/**
|
|
170
|
+
* Process extract output and add token usage information
|
|
171
|
+
* @private
|
|
172
|
+
*/
|
|
173
|
+
function processExtractOutput(stdout, options) {
|
|
174
|
+
// Parse the output to extract token usage information
|
|
175
|
+
let tokenUsage = {
|
|
176
|
+
requestTokens: 0,
|
|
177
|
+
responseTokens: 0,
|
|
178
|
+
totalTokens: 0
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
// Calculate approximate request tokens
|
|
182
|
+
if (options.files && Array.isArray(options.files)) {
|
|
183
|
+
tokenUsage.requestTokens = options.files.join(' ').length / 4;
|
|
184
|
+
} else if (options.inputFile) {
|
|
185
|
+
tokenUsage.requestTokens = options.inputFile.length / 4;
|
|
186
|
+
} else if (options.content) {
|
|
187
|
+
const contentLength = typeof options.content === 'string'
|
|
188
|
+
? options.content.length
|
|
189
|
+
: options.content.byteLength;
|
|
190
|
+
tokenUsage.requestTokens = contentLength / 4;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Try to extract token information from the output
|
|
194
|
+
if (stdout.includes('Total tokens returned:')) {
|
|
195
|
+
const tokenMatch = stdout.match(/Total tokens returned: (\d+)/);
|
|
196
|
+
if (tokenMatch && tokenMatch[1]) {
|
|
197
|
+
tokenUsage.responseTokens = parseInt(tokenMatch[1], 10);
|
|
198
|
+
tokenUsage.totalTokens = tokenUsage.requestTokens + tokenUsage.responseTokens;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Add token usage information to the output
|
|
203
|
+
let output = stdout;
|
|
204
|
+
|
|
205
|
+
// Add token usage information at the end if not already present
|
|
206
|
+
if (!output.includes('Token Usage:')) {
|
|
207
|
+
output += `\nToken Usage:\n Request tokens: ${tokenUsage.requestTokens}\n Response tokens: ${tokenUsage.responseTokens}\n Total tokens: ${tokenUsage.totalTokens}\n`;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Parse JSON if requested or if format is json
|
|
211
|
+
if (options.json || options.format === 'json') {
|
|
212
|
+
try {
|
|
213
|
+
const jsonOutput = JSON.parse(stdout);
|
|
214
|
+
|
|
215
|
+
// Add token usage to JSON output
|
|
216
|
+
if (!jsonOutput.token_usage) {
|
|
217
|
+
jsonOutput.token_usage = {
|
|
218
|
+
request_tokens: tokenUsage.requestTokens,
|
|
219
|
+
response_tokens: tokenUsage.responseTokens,
|
|
220
|
+
total_tokens: tokenUsage.totalTokens
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
return jsonOutput;
|
|
225
|
+
} catch (error) {
|
|
226
|
+
console.error('Error parsing JSON output:', error);
|
|
227
|
+
return output; // Fall back to string output with token usage
|
|
228
|
+
}
|
|
148
229
|
}
|
|
149
|
-
|
|
230
|
+
|
|
231
|
+
return output;
|
|
232
|
+
}
|