openreport 0.1.0 → 0.1.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openreport",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "packageManager": "bun@1.3.9",
5
5
  "description": "A modern TUI to generate detailed AI-powered reports on software projects",
6
6
  "type": "module",
@@ -73,21 +73,23 @@ export const AgentStatusItem = React.memo(function AgentStatusItem({
73
73
  </Text>
74
74
  </Box>
75
75
 
76
- {/* Duration */}
77
- {duration > 0 && (
78
- <Box width={timeWidth} justifyContent="flex-end">
76
+ {/* Duration — always rendered to keep columns aligned with header */}
77
+ <Box width={timeWidth} justifyContent="flex-end">
78
+ {duration > 0 && (
79
79
  <Text color="gray" dimColor>
80
80
  {formatDuration(duration)}
81
81
  </Text>
82
- </Box>
83
- )}
82
+ )}
83
+ </Box>
84
84
 
85
- {/* Tokens (hidden in compact mode) */}
86
- {tokenStr && !isCompact && (
85
+ {/* Tokens — always rendered (when not compact) to keep columns aligned */}
86
+ {!isCompact && (
87
87
  <Box width={tokenWidth} justifyContent="flex-end">
88
- <Text color="gray" dimColor>
89
- {tokenStr}
90
- </Text>
88
+ {tokenStr ? (
89
+ <Text color="gray" dimColor>
90
+ {tokenStr}
91
+ </Text>
92
+ ) : null}
91
93
  </Box>
92
94
  )}
93
95
  </Box>
@@ -8,6 +8,7 @@ import { createBaseTools, createExtendedTools, type BaseTools, type ExtendedTool
8
8
  import { getRelevantFilePaths } from "../ingestion/context-selector.js";
9
9
  import { debugLog } from "../utils/debug.js";
10
10
  import { getErrorMessage } from "../utils/format.js";
11
+ import { estimateTokens } from "../ingestion/token-budget.js";
11
12
  import type { AgentId, AgentDefinition, SubReport } from "../types/index.js";
12
13
  import type { OpenReportConfig } from "../config/schema.js";
13
14
 
@@ -187,6 +188,8 @@ ${fileContentBlock}
187
188
  Produce your project overview now.`;
188
189
 
189
190
  try {
191
+ const estimatedInputTokens = estimateTokens(prompt);
192
+
190
193
  const fullText = await withRetry(async () => {
191
194
  const result = await streamText({
192
195
  model,
@@ -197,14 +200,27 @@ Produce your project overview now.`;
197
200
  abortSignal: signal,
198
201
  });
199
202
 
203
+ let outputCharCount = 0;
200
204
  const throttle = createStreamThrottle((preview) => {
201
205
  progress.setPhaseDetail(preview);
206
+ progress.setBaseTokens({
207
+ input: estimatedInputTokens,
208
+ output: Math.ceil(outputCharCount / 4),
209
+ });
202
210
  });
203
211
 
204
212
  for await (const chunk of result.textStream) {
213
+ outputCharCount += chunk.length;
205
214
  throttle.push(chunk);
206
215
  }
207
216
 
217
+ // Set final token count from actual usage
218
+ const usage = await result.usage;
219
+ progress.setBaseTokens({
220
+ input: usage.promptTokens || estimatedInputTokens,
221
+ output: usage.completionTokens || Math.ceil(outputCharCount / 4),
222
+ });
223
+
208
224
  return throttle.getFullText();
209
225
  });
210
226
 
@@ -322,13 +338,20 @@ ${buildAnalysisPrompt(agentId, agentDef.name, "")}`;
322
338
  });
323
339
 
324
340
  const pendingChunks: string[] = [];
341
+ const estimatedInputTokens = estimateTokens(prompt);
342
+ let outputCharCount = 0;
325
343
  const throttle = createStreamThrottle((preview) => {
326
344
  progress.updateAgentStatus(agentId, "running", preview);
327
345
  progress.addStreamText(pendingChunks.join(""), agentId);
346
+ progress.updateAgentTokens(agentId, {
347
+ input: estimatedInputTokens,
348
+ output: Math.ceil(outputCharCount / 4),
349
+ });
328
350
  pendingChunks.length = 0;
329
351
  });
330
352
 
331
353
  for await (const chunk of result.textStream) {
354
+ outputCharCount += chunk.length;
332
355
  pendingChunks.push(chunk);
333
356
  throttle.push(chunk);
334
357
  }
@@ -72,7 +72,7 @@ export class ProgressTracker extends TypedEventEmitter<ProgressEventMap> {
72
72
  status: "pending",
73
73
  };
74
74
  this.agents.set(agentId, status);
75
- this.emit("agentStatusChange", status);
75
+ this.emit("agentStatusChange", { ...status });
76
76
  }
77
77
 
78
78
  updateAgentStatus(
@@ -125,6 +125,13 @@ export class ProgressTracker extends TypedEventEmitter<ProgressEventMap> {
125
125
  this.previousTokens.set(agentId, { input: tokens.input, output: tokens.output });
126
126
 
127
127
  this.emit("tokenUpdate", { ...this.totalTokens });
128
+ this.emit("agentStatusChange", { ...agent });
129
+ }
130
+
131
+ /** Set base token count (e.g. from orchestrator) before agents run. Agent deltas add on top. */
132
+ setBaseTokens(tokens: { input: number; output: number }): void {
133
+ this.totalTokens = { ...tokens };
134
+ this.emit("tokenUpdate", { ...this.totalTokens });
128
135
  }
129
136
 
130
137
  addStreamText(delta: string, agentId: AgentId): void {