Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ venice chat -t calculator,weather "What's 25 * 4.5?"
# JSON output for scripting
venice chat -f json "List 3 colors" | jq '.content'

# Use piped context plus an instruction
cat error.log | venice chat "find the root cause"

# Disable streaming
venice chat --no-stream "Quick question"
```
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 23 additions & 0 deletions src/commands/chat.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import assert from 'node:assert/strict';
import test from 'node:test';
import { buildChatUserMessage } from './chat.js';

test('buildChatUserMessage uses prompt when only args are provided', () => {
const message = buildChatUserMessage('find the root cause');
assert.deepEqual(message, { role: 'user', content: 'find the root cause' });
});

test('buildChatUserMessage uses stdin when prompt is empty', () => {
const message = buildChatUserMessage('', 'error line 1\nerror line 2');
assert.deepEqual(message, { role: 'user', content: 'error line 1\nerror line 2' });
});

test('buildChatUserMessage merges stdin and prompt into one message', () => {
const message = buildChatUserMessage('find the root cause', 'stack trace...');
assert.deepEqual(message, { role: 'user', content: 'stack trace...\n\nfind the root cause' });
});

test('buildChatUserMessage returns null when both inputs are empty', () => {
const message = buildChatUserMessage('', '');
assert.equal(message, null);
});
31 changes: 23 additions & 8 deletions src/commands/chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,15 +56,16 @@ export function registerChatCommand(program: Command): void {
return;
}

// Get prompt from args or stdin
// Get prompt from args and optionally stdin
let prompt = promptParts.join(' ');

if (!prompt && !process.stdin.isTTY) {
// Read from stdin
prompt = await readStdin();
let pipedInput = '';

if (!process.stdin.isTTY) {
pipedInput = await readStdin();
}

if (!prompt) {
const userMessage = buildChatUserMessage(prompt, pipedInput);
if (!userMessage) {
console.error(formatError('No prompt provided. Usage: venice chat "Your message"'));
process.exit(1);
}
Expand Down Expand Up @@ -100,8 +101,8 @@ export function registerChatCommand(program: Command): void {
}
}

// Add user message
messages.push({ role: 'user', content: prompt });
// Add user message from stdin/args
messages.push(userMessage);

// Get tool definitions
const toolNames = options.tools?.split(',').map((t: string) => t.trim()) || [];
Expand Down Expand Up @@ -418,6 +419,20 @@ async function readStdin(): Promise<string> {
return Buffer.concat(chunks).toString('utf-8').trim();
}

export function buildChatUserMessage(prompt: string, pipedInput?: string): Message | null {
if (pipedInput && prompt) {
return { role: 'user', content: `${pipedInput}\n\n${prompt}` };
}
if (pipedInput) {
return { role: 'user', content: pipedInput };
}
if (prompt) {
return { role: 'user', content: prompt };
}

return null;
}

// Character prompts
const CHARACTER_PROMPTS: Record<string, string> = {
pirate: 'You are a pirate captain. Respond in pirate speak with nautical terms, "arr"s, and maritime metaphors. Be adventurous and bold.',
Expand Down