@steipete/oracle 1.0.8 → 1.2.0
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/README.md +32 -4
- package/assets-oracle-icon.png +0 -0
- package/dist/bin/oracle-cli.js +178 -21
- package/dist/bin/oracle-mcp.js +6 -0
- package/dist/markdansi/types/index.js +4 -0
- package/dist/oracle/bin/oracle-cli.js +472 -0
- package/dist/oracle/src/browser/actions/assistantResponse.js +471 -0
- package/dist/oracle/src/browser/actions/attachments.js +82 -0
- package/dist/oracle/src/browser/actions/modelSelection.js +190 -0
- package/dist/oracle/src/browser/actions/navigation.js +75 -0
- package/dist/oracle/src/browser/actions/promptComposer.js +167 -0
- package/dist/oracle/src/browser/chromeLifecycle.js +104 -0
- package/dist/oracle/src/browser/config.js +33 -0
- package/dist/oracle/src/browser/constants.js +40 -0
- package/dist/oracle/src/browser/cookies.js +210 -0
- package/dist/oracle/src/browser/domDebug.js +36 -0
- package/dist/oracle/src/browser/index.js +331 -0
- package/dist/oracle/src/browser/pageActions.js +5 -0
- package/dist/oracle/src/browser/prompt.js +88 -0
- package/dist/oracle/src/browser/promptSummary.js +20 -0
- package/dist/oracle/src/browser/sessionRunner.js +80 -0
- package/dist/oracle/src/browser/types.js +1 -0
- package/dist/oracle/src/browser/utils.js +62 -0
- package/dist/oracle/src/browserMode.js +1 -0
- package/dist/oracle/src/cli/browserConfig.js +44 -0
- package/dist/oracle/src/cli/dryRun.js +59 -0
- package/dist/oracle/src/cli/engine.js +17 -0
- package/dist/oracle/src/cli/errorUtils.js +9 -0
- package/dist/oracle/src/cli/help.js +70 -0
- package/dist/oracle/src/cli/markdownRenderer.js +15 -0
- package/dist/oracle/src/cli/options.js +103 -0
- package/dist/oracle/src/cli/promptRequirement.js +14 -0
- package/dist/oracle/src/cli/rootAlias.js +30 -0
- package/dist/oracle/src/cli/sessionCommand.js +77 -0
- package/dist/oracle/src/cli/sessionDisplay.js +270 -0
- package/dist/oracle/src/cli/sessionRunner.js +94 -0
- package/dist/oracle/src/heartbeat.js +43 -0
- package/dist/oracle/src/oracle/client.js +48 -0
- package/dist/oracle/src/oracle/config.js +29 -0
- package/dist/oracle/src/oracle/errors.js +101 -0
- package/dist/oracle/src/oracle/files.js +220 -0
- package/dist/oracle/src/oracle/format.js +33 -0
- package/dist/oracle/src/oracle/fsAdapter.js +7 -0
- package/dist/oracle/src/oracle/oscProgress.js +60 -0
- package/dist/oracle/src/oracle/request.js +48 -0
- package/dist/oracle/src/oracle/run.js +444 -0
- package/dist/oracle/src/oracle/tokenStats.js +39 -0
- package/dist/oracle/src/oracle/types.js +1 -0
- package/dist/oracle/src/oracle.js +9 -0
- package/dist/oracle/src/sessionManager.js +205 -0
- package/dist/oracle/src/version.js +39 -0
- package/dist/src/browser/actions/modelSelection.js +117 -29
- package/dist/src/browser/cookies.js +1 -1
- package/dist/src/browser/index.js +2 -1
- package/dist/src/browser/prompt.js +6 -5
- package/dist/src/browser/sessionRunner.js +4 -2
- package/dist/src/cli/dryRun.js +41 -5
- package/dist/src/cli/engine.js +7 -0
- package/dist/src/cli/help.js +1 -1
- package/dist/src/cli/hiddenAliases.js +17 -0
- package/dist/src/cli/markdownRenderer.js +97 -0
- package/dist/src/cli/notifier.js +223 -0
- package/dist/src/cli/promptRequirement.js +3 -0
- package/dist/src/cli/rootAlias.js +14 -0
- package/dist/src/cli/runOptions.js +29 -0
- package/dist/src/cli/sessionCommand.js +60 -2
- package/dist/src/cli/sessionDisplay.js +222 -10
- package/dist/src/cli/sessionRunner.js +21 -2
- package/dist/src/cli/tui/index.js +436 -0
- package/dist/src/config.js +27 -0
- package/dist/src/mcp/server.js +36 -0
- package/dist/src/mcp/tools/consult.js +158 -0
- package/dist/src/mcp/tools/sessionResources.js +64 -0
- package/dist/src/mcp/tools/sessions.js +106 -0
- package/dist/src/mcp/types.js +17 -0
- package/dist/src/mcp/utils.js +24 -0
- package/dist/src/oracle/files.js +143 -6
- package/dist/src/oracle/oscProgress.js +60 -0
- package/dist/src/oracle/run.js +104 -71
- package/dist/src/oracle/tokenEstimate.js +34 -0
- package/dist/src/sessionManager.js +65 -3
- package/dist/vendor/oracle-notifier/OracleNotifier.app/Contents/CodeResources +0 -0
- package/dist/vendor/oracle-notifier/OracleNotifier.app/Contents/Info.plist +20 -0
- package/dist/vendor/oracle-notifier/OracleNotifier.app/Contents/MacOS/OracleNotifier +0 -0
- package/dist/vendor/oracle-notifier/OracleNotifier.app/Contents/Resources/OracleIcon.icns +0 -0
- package/dist/vendor/oracle-notifier/OracleNotifier.app/Contents/_CodeSignature/CodeResources +128 -0
- package/dist/vendor/oracle-notifier/OracleNotifier.swift +45 -0
- package/dist/vendor/oracle-notifier/README.md +24 -0
- package/dist/vendor/oracle-notifier/build-notifier.sh +93 -0
- package/dist/vendor/oracle-notifier/oracle-notifier/OracleNotifier.app/Contents/CodeResources +0 -0
- package/dist/vendor/oracle-notifier/oracle-notifier/OracleNotifier.app/Contents/Info.plist +20 -0
- package/dist/vendor/oracle-notifier/oracle-notifier/OracleNotifier.app/Contents/MacOS/OracleNotifier +0 -0
- package/dist/vendor/oracle-notifier/oracle-notifier/OracleNotifier.app/Contents/Resources/OracleIcon.icns +0 -0
- package/dist/vendor/oracle-notifier/oracle-notifier/OracleNotifier.app/Contents/_CodeSignature/CodeResources +128 -0
- package/dist/vendor/oracle-notifier/oracle-notifier/OracleNotifier.swift +45 -0
- package/dist/vendor/oracle-notifier/oracle-notifier/README.md +24 -0
- package/dist/vendor/oracle-notifier/oracle-notifier/build-notifier.sh +93 -0
- package/package.json +27 -9
- package/vendor/oracle-notifier/OracleNotifier.app/Contents/CodeResources +0 -0
- package/vendor/oracle-notifier/OracleNotifier.app/Contents/Info.plist +20 -0
- package/vendor/oracle-notifier/OracleNotifier.app/Contents/MacOS/OracleNotifier +0 -0
- package/vendor/oracle-notifier/OracleNotifier.app/Contents/Resources/OracleIcon.icns +0 -0
- package/vendor/oracle-notifier/OracleNotifier.app/Contents/_CodeSignature/CodeResources +128 -0
- package/vendor/oracle-notifier/OracleNotifier.swift +45 -0
- package/vendor/oracle-notifier/README.md +24 -0
- package/vendor/oracle-notifier/build-notifier.sh +93 -0
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import kleur from 'kleur';
|
|
3
|
-
import { filterSessionsByRange, listSessionsMetadata, readSessionLog, readSessionMetadata, SESSIONS_DIR, wait, } from '../sessionManager.js';
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
import { filterSessionsByRange, listSessionsMetadata, readSessionLog, readSessionMetadata, readSessionRequest, SESSIONS_DIR, wait, } from '../sessionManager.js';
|
|
4
|
+
import { renderMarkdownAnsi } from './markdownRenderer.js';
|
|
5
|
+
import { formatElapsed, formatUSD } from '../oracle/format.js';
|
|
6
|
+
import { MODEL_CONFIGS } from '../oracle.js';
|
|
7
|
+
const isTty = () => Boolean(process.stdout.isTTY);
|
|
8
|
+
const dim = (text) => (isTty() ? kleur.dim(text) : text);
|
|
9
|
+
export const MAX_RENDER_BYTES = 200_000;
|
|
6
10
|
const CLEANUP_TIP = 'Tip: Run "oracle session --clear --hours 24" to prune cached runs (add --all to wipe everything).';
|
|
7
11
|
export async function showStatus({ hours, includeAll, limit, showExamples = false }) {
|
|
8
12
|
const metas = await listSessionsMetadata();
|
|
@@ -16,12 +20,17 @@ export async function showStatus({ hours, includeAll, limit, showExamples = fals
|
|
|
16
20
|
return;
|
|
17
21
|
}
|
|
18
22
|
console.log(chalk.bold('Recent Sessions'));
|
|
23
|
+
console.log(chalk.dim('Timestamp Chars Cost Status Model ID'));
|
|
19
24
|
for (const entry of entries) {
|
|
20
25
|
const statusRaw = (entry.status || 'unknown').padEnd(9);
|
|
21
26
|
const status = richTty ? colorStatus(entry.status ?? 'unknown', statusRaw) : statusRaw;
|
|
22
27
|
const model = (entry.model || 'n/a').padEnd(9);
|
|
23
|
-
const created = entry.createdAt
|
|
24
|
-
|
|
28
|
+
const created = formatTimestamp(entry.createdAt);
|
|
29
|
+
const chars = entry.options?.prompt?.length ?? entry.promptPreview?.length ?? 0;
|
|
30
|
+
const charLabel = chars > 0 ? String(chars).padStart(5) : ' -';
|
|
31
|
+
const costValue = resolveCost(entry);
|
|
32
|
+
const costLabel = costValue != null ? formatCostTable(costValue) : ' -';
|
|
33
|
+
console.log(`${created} | ${charLabel} | ${costLabel} | ${status} | ${model} | ${entry.id}`);
|
|
25
34
|
}
|
|
26
35
|
if (truncated) {
|
|
27
36
|
console.log(chalk.yellow(`Showing ${entries.length} of ${total} sessions from the requested range. Run "oracle session --clear" or delete entries in ${SESSIONS_DIR} to free space, or rerun with --status-limit/--status-all.`));
|
|
@@ -50,6 +59,8 @@ export async function attachSession(sessionId, options) {
|
|
|
50
59
|
return;
|
|
51
60
|
}
|
|
52
61
|
const initialStatus = metadata.status;
|
|
62
|
+
const wantsRender = Boolean(options?.renderMarkdown);
|
|
63
|
+
const isVerbose = Boolean(process.env.ORACLE_VERBOSE_RENDER);
|
|
53
64
|
if (!options?.suppressMetadata) {
|
|
54
65
|
const reattachLine = buildReattachLine(metadata);
|
|
55
66
|
if (reattachLine) {
|
|
@@ -72,18 +83,111 @@ export async function attachSession(sessionId, options) {
|
|
|
72
83
|
}
|
|
73
84
|
}
|
|
74
85
|
const shouldTrimIntro = initialStatus === 'completed' || initialStatus === 'error';
|
|
86
|
+
if (options?.renderPrompt !== false) {
|
|
87
|
+
const prompt = await readStoredPrompt(sessionId);
|
|
88
|
+
if (prompt) {
|
|
89
|
+
console.log(chalk.bold('Prompt:'));
|
|
90
|
+
console.log(renderMarkdownAnsi(prompt));
|
|
91
|
+
console.log(dim('---'));
|
|
92
|
+
}
|
|
93
|
+
}
|
|
75
94
|
if (shouldTrimIntro) {
|
|
76
95
|
const fullLog = await readSessionLog(sessionId);
|
|
77
96
|
const trimmed = trimBeforeFirstAnswer(fullLog);
|
|
78
|
-
|
|
97
|
+
const size = Buffer.byteLength(trimmed, 'utf8');
|
|
98
|
+
const canRender = wantsRender && isTty() && size <= MAX_RENDER_BYTES;
|
|
99
|
+
if (wantsRender && size > MAX_RENDER_BYTES) {
|
|
100
|
+
const msg = `Render skipped (log too large: ${size} bytes > ${MAX_RENDER_BYTES}). Showing raw text.`;
|
|
101
|
+
console.log(dim(msg));
|
|
102
|
+
if (isVerbose) {
|
|
103
|
+
console.log(dim(`Verbose: renderMarkdown=true tty=${isTty()} size=${size}`));
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
else if (wantsRender && !isTty()) {
|
|
107
|
+
const msg = 'Render requested but stdout is not a TTY; showing raw text.';
|
|
108
|
+
console.log(dim(msg));
|
|
109
|
+
if (isVerbose) {
|
|
110
|
+
console.log(dim(`Verbose: renderMarkdown=true tty=${isTty()} size=${size}`));
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
if (canRender) {
|
|
114
|
+
if (isVerbose) {
|
|
115
|
+
console.log(dim(`Verbose: rendering markdown (size=${size}, tty=${isTty()})`));
|
|
116
|
+
}
|
|
117
|
+
process.stdout.write(renderMarkdownAnsi(trimmed));
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
process.stdout.write(trimmed);
|
|
121
|
+
}
|
|
122
|
+
const summary = formatCompletionSummary(metadata, { includeSlug: true });
|
|
123
|
+
if (summary) {
|
|
124
|
+
console.log(`\n${chalk.green.bold(summary)}`);
|
|
125
|
+
}
|
|
79
126
|
return;
|
|
80
127
|
}
|
|
128
|
+
if (wantsRender) {
|
|
129
|
+
console.log(dim('Render will apply after completion; streaming raw text meanwhile...'));
|
|
130
|
+
if (isVerbose) {
|
|
131
|
+
console.log(dim(`Verbose: streaming phase renderMarkdown=true tty=${isTty()}`));
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
const liveRenderState = wantsRender && isTty()
|
|
135
|
+
? { pending: '', inFence: false, inTable: false, renderedBytes: 0, fallback: false, noticedFallback: false }
|
|
136
|
+
: null;
|
|
81
137
|
let lastLength = 0;
|
|
138
|
+
const renderLiveChunk = (chunk) => {
|
|
139
|
+
if (!liveRenderState || chunk.length === 0) {
|
|
140
|
+
process.stdout.write(chunk);
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
if (liveRenderState.fallback) {
|
|
144
|
+
process.stdout.write(chunk);
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
liveRenderState.pending += chunk;
|
|
148
|
+
const { chunks, remainder } = extractRenderableChunks(liveRenderState.pending, liveRenderState);
|
|
149
|
+
liveRenderState.pending = remainder;
|
|
150
|
+
for (const candidate of chunks) {
|
|
151
|
+
const projected = liveRenderState.renderedBytes + Buffer.byteLength(candidate, 'utf8');
|
|
152
|
+
if (projected > MAX_RENDER_BYTES) {
|
|
153
|
+
if (!liveRenderState.noticedFallback) {
|
|
154
|
+
console.log(dim(`Render skipped (log too large: > ${MAX_RENDER_BYTES} bytes). Showing raw text.`));
|
|
155
|
+
liveRenderState.noticedFallback = true;
|
|
156
|
+
}
|
|
157
|
+
liveRenderState.fallback = true;
|
|
158
|
+
process.stdout.write(candidate + liveRenderState.pending);
|
|
159
|
+
liveRenderState.pending = '';
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
process.stdout.write(renderMarkdownAnsi(candidate));
|
|
163
|
+
liveRenderState.renderedBytes += Buffer.byteLength(candidate, 'utf8');
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
const flushRemainder = () => {
|
|
167
|
+
if (!liveRenderState || liveRenderState.fallback) {
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
if (liveRenderState.pending.length === 0) {
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
const text = liveRenderState.pending;
|
|
174
|
+
liveRenderState.pending = '';
|
|
175
|
+
const projected = liveRenderState.renderedBytes + Buffer.byteLength(text, 'utf8');
|
|
176
|
+
if (projected > MAX_RENDER_BYTES) {
|
|
177
|
+
if (!liveRenderState.noticedFallback) {
|
|
178
|
+
console.log(dim(`Render skipped (log too large: > ${MAX_RENDER_BYTES} bytes). Showing raw text.`));
|
|
179
|
+
}
|
|
180
|
+
process.stdout.write(text);
|
|
181
|
+
liveRenderState.fallback = true;
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
process.stdout.write(renderMarkdownAnsi(text));
|
|
185
|
+
};
|
|
82
186
|
const printNew = async () => {
|
|
83
187
|
const text = await readSessionLog(sessionId);
|
|
84
188
|
const nextChunk = text.slice(lastLength);
|
|
85
189
|
if (nextChunk.length > 0) {
|
|
86
|
-
|
|
190
|
+
renderLiveChunk(nextChunk);
|
|
87
191
|
lastLength = text.length;
|
|
88
192
|
}
|
|
89
193
|
};
|
|
@@ -96,14 +200,21 @@ export async function attachSession(sessionId, options) {
|
|
|
96
200
|
}
|
|
97
201
|
if (latest.status === 'completed' || latest.status === 'error') {
|
|
98
202
|
await printNew();
|
|
203
|
+
flushRemainder();
|
|
99
204
|
if (!options?.suppressMetadata) {
|
|
100
205
|
if (latest.status === 'error' && latest.errorMessage) {
|
|
101
206
|
console.log('\nResult:');
|
|
102
207
|
console.log(`Session failed: ${latest.errorMessage}`);
|
|
103
208
|
}
|
|
104
|
-
if (latest.
|
|
105
|
-
const
|
|
106
|
-
|
|
209
|
+
if (latest.status === 'completed' && latest.usage) {
|
|
210
|
+
const summary = formatCompletionSummary(latest, { includeSlug: true });
|
|
211
|
+
if (summary) {
|
|
212
|
+
console.log(`\n${chalk.green.bold(summary)}`);
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
const usage = latest.usage;
|
|
216
|
+
console.log(`\nFinished (tok i/o/r/t: ${usage.inputTokens}/${usage.outputTokens}/${usage.reasoningTokens}/${usage.totalTokens})`);
|
|
217
|
+
}
|
|
107
218
|
}
|
|
108
219
|
}
|
|
109
220
|
break;
|
|
@@ -234,3 +345,104 @@ function printStatusExamples() {
|
|
|
234
345
|
console.log(dim(' Attach to a specific running/completed session to stream its output.'));
|
|
235
346
|
console.log(dim(CLEANUP_TIP));
|
|
236
347
|
}
|
|
348
|
+
function extractRenderableChunks(text, state) {
|
|
349
|
+
const chunks = [];
|
|
350
|
+
let buffer = '';
|
|
351
|
+
const lines = text.split(/(\n)/);
|
|
352
|
+
for (let i = 0; i < lines.length; i += 1) {
|
|
353
|
+
const segment = lines[i];
|
|
354
|
+
if (segment === '\n') {
|
|
355
|
+
buffer += segment;
|
|
356
|
+
// Detect code fences
|
|
357
|
+
const prev = lines[i - 1] ?? '';
|
|
358
|
+
const fenceMatch = prev.match(/^(\s*)(`{3,}|~{3,})(.*)$/);
|
|
359
|
+
if (!state.inFence && fenceMatch) {
|
|
360
|
+
state.inFence = true;
|
|
361
|
+
state.fenceDelimiter = fenceMatch[2];
|
|
362
|
+
}
|
|
363
|
+
else if (state.inFence && state.fenceDelimiter && prev.startsWith(state.fenceDelimiter)) {
|
|
364
|
+
state.inFence = false;
|
|
365
|
+
state.fenceDelimiter = undefined;
|
|
366
|
+
}
|
|
367
|
+
const trimmed = prev.trim();
|
|
368
|
+
if (!state.inFence) {
|
|
369
|
+
if (!state.inTable && trimmed.startsWith('|') && trimmed.includes('|')) {
|
|
370
|
+
state.inTable = true;
|
|
371
|
+
}
|
|
372
|
+
if (state.inTable && trimmed === '') {
|
|
373
|
+
state.inTable = false;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
const safeBreak = !state.inFence && !state.inTable && trimmed === '';
|
|
377
|
+
if (safeBreak) {
|
|
378
|
+
chunks.push(buffer);
|
|
379
|
+
buffer = '';
|
|
380
|
+
}
|
|
381
|
+
continue;
|
|
382
|
+
}
|
|
383
|
+
buffer += segment;
|
|
384
|
+
}
|
|
385
|
+
return { chunks, remainder: buffer };
|
|
386
|
+
}
|
|
387
|
+
function formatTimestamp(iso) {
|
|
388
|
+
const date = new Date(iso);
|
|
389
|
+
const locale = 'en-US';
|
|
390
|
+
const opts = {
|
|
391
|
+
year: 'numeric',
|
|
392
|
+
month: '2-digit',
|
|
393
|
+
day: '2-digit',
|
|
394
|
+
hour: 'numeric',
|
|
395
|
+
minute: '2-digit',
|
|
396
|
+
second: undefined,
|
|
397
|
+
hour12: true,
|
|
398
|
+
};
|
|
399
|
+
const formatted = date.toLocaleString(locale, opts);
|
|
400
|
+
return formatted.replace(/(, )(\d:)/, '$1 $2');
|
|
401
|
+
}
|
|
402
|
+
export function formatCompletionSummary(metadata, options = {}) {
|
|
403
|
+
if (!metadata.usage || metadata.elapsedMs == null) {
|
|
404
|
+
return null;
|
|
405
|
+
}
|
|
406
|
+
const modeLabel = metadata.mode === 'browser' ? `${metadata.model ?? 'n/a'}[browser]` : metadata.model ?? 'n/a';
|
|
407
|
+
const usage = metadata.usage;
|
|
408
|
+
const cost = metadata.mode === 'browser' ? null : resolveCost(metadata);
|
|
409
|
+
const costPart = cost != null ? ` | ${formatUSD(cost)}` : '';
|
|
410
|
+
const tokensDisplay = `${usage.inputTokens}/${usage.outputTokens}/${usage.reasoningTokens}/${usage.totalTokens}`;
|
|
411
|
+
const filesCount = metadata.options?.file?.length ?? 0;
|
|
412
|
+
const filesPart = filesCount > 0 ? ` | files=${filesCount}` : '';
|
|
413
|
+
const slugPart = options.includeSlug ? ` | slug=${metadata.id}` : '';
|
|
414
|
+
return `Finished in ${formatElapsed(metadata.elapsedMs)} (${modeLabel}${costPart} | tok(i/o/r/t)=${tokensDisplay}${filesPart}${slugPart})`;
|
|
415
|
+
}
|
|
416
|
+
function resolveCost(metadata) {
|
|
417
|
+
if (metadata.mode === 'browser') {
|
|
418
|
+
return null;
|
|
419
|
+
}
|
|
420
|
+
if (metadata.usage?.cost != null) {
|
|
421
|
+
return metadata.usage.cost;
|
|
422
|
+
}
|
|
423
|
+
if (!metadata.model || !metadata.usage) {
|
|
424
|
+
return null;
|
|
425
|
+
}
|
|
426
|
+
const pricing = MODEL_CONFIGS[metadata.model]?.pricing;
|
|
427
|
+
if (!pricing) {
|
|
428
|
+
return null;
|
|
429
|
+
}
|
|
430
|
+
const input = metadata.usage.inputTokens ?? 0;
|
|
431
|
+
const output = metadata.usage.outputTokens ?? 0;
|
|
432
|
+
const cost = input * pricing.inputPerToken + output * pricing.outputPerToken;
|
|
433
|
+
return cost > 0 ? cost : null;
|
|
434
|
+
}
|
|
435
|
+
function formatCostTable(cost) {
|
|
436
|
+
return `$${cost.toFixed(3)}`.padStart(7);
|
|
437
|
+
}
|
|
438
|
+
async function readStoredPrompt(sessionId) {
|
|
439
|
+
const request = await readSessionRequest(sessionId);
|
|
440
|
+
if (request?.prompt && request.prompt.trim().length > 0) {
|
|
441
|
+
return request.prompt;
|
|
442
|
+
}
|
|
443
|
+
const meta = await readSessionMetadata(sessionId);
|
|
444
|
+
if (meta?.options?.prompt && meta.options.prompt.trim().length > 0) {
|
|
445
|
+
return meta.options.prompt;
|
|
446
|
+
}
|
|
447
|
+
return null;
|
|
448
|
+
}
|
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
import kleur from 'kleur';
|
|
2
2
|
import { updateSessionMetadata } from '../sessionManager.js';
|
|
3
|
-
import { runOracle, OracleResponseError, OracleTransportError, extractResponseMetadata, asOracleUserError, } from '../oracle.js';
|
|
3
|
+
import { runOracle, OracleResponseError, OracleTransportError, extractResponseMetadata, asOracleUserError, extractTextOutput, } from '../oracle.js';
|
|
4
4
|
import { runBrowserSessionExecution } from '../browser/sessionRunner.js';
|
|
5
5
|
import { formatResponseMetadata, formatTransportMetadata } from './sessionDisplay.js';
|
|
6
6
|
import { markErrorLogged } from './errorUtils.js';
|
|
7
|
+
import { sendSessionNotification, deriveNotificationSettingsFromMetadata, } from './notifier.js';
|
|
7
8
|
const isTty = process.stdout.isTTY;
|
|
8
9
|
const dim = (text) => (isTty ? kleur.dim(text) : text);
|
|
9
|
-
export async function performSessionRun({ sessionMeta, runOptions, mode, browserConfig, cwd, log, write, version, }) {
|
|
10
|
+
export async function performSessionRun({ sessionMeta, runOptions, mode, browserConfig, cwd, log, write, version, notifications, }) {
|
|
10
11
|
await updateSessionMetadata(sessionMeta.id, {
|
|
11
12
|
status: 'running',
|
|
12
13
|
startedAt: new Date().toISOString(),
|
|
13
14
|
mode,
|
|
14
15
|
...(browserConfig ? { browser: { config: browserConfig } } : {}),
|
|
15
16
|
});
|
|
17
|
+
const notificationSettings = notifications ?? deriveNotificationSettingsFromMetadata(sessionMeta, process.env);
|
|
16
18
|
try {
|
|
17
19
|
if (mode === 'browser') {
|
|
18
20
|
if (!browserConfig) {
|
|
@@ -32,6 +34,14 @@ export async function performSessionRun({ sessionMeta, runOptions, mode, browser
|
|
|
32
34
|
transport: undefined,
|
|
33
35
|
error: undefined,
|
|
34
36
|
});
|
|
37
|
+
await sendSessionNotification({
|
|
38
|
+
sessionId: sessionMeta.id,
|
|
39
|
+
sessionName: sessionMeta.options?.slug ?? sessionMeta.id,
|
|
40
|
+
mode,
|
|
41
|
+
model: sessionMeta.model,
|
|
42
|
+
usage: result.usage,
|
|
43
|
+
characters: result.answerText?.length,
|
|
44
|
+
}, notificationSettings, log, result.answerText?.slice(0, 140));
|
|
35
45
|
return;
|
|
36
46
|
}
|
|
37
47
|
const result = await runOracle(runOptions, {
|
|
@@ -51,6 +61,15 @@ export async function performSessionRun({ sessionMeta, runOptions, mode, browser
|
|
|
51
61
|
transport: undefined,
|
|
52
62
|
error: undefined,
|
|
53
63
|
});
|
|
64
|
+
const answerText = extractTextOutput(result.response);
|
|
65
|
+
await sendSessionNotification({
|
|
66
|
+
sessionId: sessionMeta.id,
|
|
67
|
+
sessionName: sessionMeta.options?.slug ?? sessionMeta.id,
|
|
68
|
+
mode,
|
|
69
|
+
model: sessionMeta.model ?? runOptions.model,
|
|
70
|
+
usage: result.usage,
|
|
71
|
+
characters: answerText.length,
|
|
72
|
+
}, notificationSettings, log, answerText.slice(0, 140));
|
|
54
73
|
}
|
|
55
74
|
catch (error) {
|
|
56
75
|
const message = formatError(error);
|