diff --git a/index.ts b/index.ts index 4a88d6f..d8431c1 100644 --- a/index.ts +++ b/index.ts @@ -63,14 +63,12 @@ async function main() { messages: convo.messages, }); - const start = Date.now(); await renderer.renderStream(fullStream); - const stop = Date.now(); convo.messages.push({ role: "assistant", content: await text }); await convo.save(); - await renderer.renderStats(totalUsage, start, stop); + await renderer.renderStats(totalUsage); } await main(); diff --git a/src/render/index.ts b/src/render/index.ts index edc8fe1..4d1028c 100644 --- a/src/render/index.ts +++ b/src/render/index.ts @@ -16,6 +16,8 @@ export default class Renderer { private memOk = true; private buffer = ""; private unsafeIndex = 0; + private start = 0; + private stop = 0; constructor( private isPlain = false, @@ -88,8 +90,6 @@ export default class Renderer { async renderStream(stream: AsyncIterableStream>) { this.resetCounts(); - let reasonStart = 0; - const spin = spinner({ withGuide: false, indicator: "timer" }); if (!this.isPlain) { spin.start("Waiting for response"); @@ -98,7 +98,7 @@ export default class Renderer { for await (const part of stream) { switch (part.type) { case "reasoning-start": { - reasonStart = Date.now(); + this.start = Date.now(); spin.clear(); if (supportsColorStderr) this.write( @@ -121,7 +121,7 @@ export default class Renderer { } else { this.write("\n--- Done Thinking ---\n", process.stderr); } - const time = (Date.now() - reasonStart) / 1000; + const time = (Date.now() - this.start) / 1000; this.write(`Thought for ${time.toFixed(2)}s\n`, process.stderr); if (supportsColorStderr) @@ -133,6 +133,7 @@ export default class Renderer { break; } case "text-start": { + if (this.start === 0) this.start = Date.now(); spin.clear(); this.write("\n"); break; @@ -146,6 +147,7 @@ export default class Renderer { break; } case "text-end": { + this.stop = Date.now(); if (this.buffer) { await this.render(this.buffer); this.buffer = ""; @@ -160,16 +162,12 @@ export default class Renderer { } } - async renderStats( - usage: PromiseLike, - start: number, - stop: number, - ) { + async renderStats(usage: PromiseLike) { const { inputTokens, outputTokens } = await usage; const context = (inputTokens ?? 0) / 1000; const output = (outputTokens ?? 0) / 1000; - const time = (stop - start) / 1000; - const template = `Context: ${context.toFixed(1)}k, Output: ${output.toFixed(1)}k, Time: ${time.toFixed(2)}s\n`; + const toks = (outputTokens ?? 0) / ((this.stop - this.start) / 1000); + const template = `Context: ${context.toFixed(1)}k, Output: ${output.toFixed(1)}k, Toks: ${toks.toFixed(2)}/s\n`; this.write(chalkStderr.dim(template), process.stderr); } } diff --git a/src/render/markdown.ts b/src/render/markdown.ts index 565193b..d3d1354 100644 --- a/src/render/markdown.ts +++ b/src/render/markdown.ts @@ -83,7 +83,7 @@ export async function renderMarkdown( return `\`\`\`${chalk.blue(meta?.language ?? "")}\n${toRender}\`\`\`\n`; }, list: (children, { depth }) => { - const trimmed = children.replaceAll("\n\n", "\n"); + const trimmed = children.replace(/\n+/g, "\n"); return depth === 0 ? `${trimmed}\n` : `\n${trimmed}`; }, listItem: (children, { index, depth, ordered, start, checked }) => { @@ -132,7 +132,11 @@ export async function renderMarkdown( link: (children, { href }) => chalk.blueBright.underline(terminalLink(children, href)), image: () => chalk.red("Images are unsupported (for now)\n"), - text: (children) => children, + text: (children) => + children + .replaceAll("$\\rightarrow$", "->") + .replaceAll("$\\leftarrow$", "<-") + .replaceAll("$\\to$", "->"), html: () => chalk.red("HTML is unsupported\n"), });