adds eslint

This commit is contained in:
geoffsee
2025-06-24 17:29:52 -04:00
committed by Geoff Seemueller
parent 9698fc6f3b
commit 02c3253343
169 changed files with 4896 additions and 4804 deletions

View File

@@ -1,4 +1,5 @@
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import { AssistantSdk } from '../assistant-sdk.ts';
import { Utils } from '../utils.ts';
@@ -6,17 +7,17 @@ import { Utils } from '../utils.ts';
vi.mock('../utils', () => ({
Utils: {
selectEquitably: vi.fn(),
getCurrentDate: vi.fn()
}
getCurrentDate: vi.fn(),
},
}));
vi.mock('../prompts/few_shots', () => ({
default: {
'a': 'A1',
'question1': 'answer1',
'question2': 'answer2',
'question3': 'answer3'
}
a: 'A1',
question1: 'answer1',
question2: 'answer2',
question3: 'answer3',
},
}));
describe('AssistantSdk', () => {
@@ -37,63 +38,62 @@ describe('AssistantSdk', () => {
it('should return a prompt with default values when minimal params are provided', () => {
// Mock dependencies
vi.mocked(Utils.selectEquitably).mockReturnValue({
'question1': 'answer1',
'question2': 'answer2'
question1: 'answer1',
question2: 'answer2',
});
vi.mocked(Utils.getCurrentDate).mockReturnValue('2023-01-01T12:30:45Z');
const prompt = AssistantSdk.getAssistantPrompt({});
expect(prompt).toContain('# Assistant Knowledge');
expect(prompt).toContain('2023-01-01');
expect(prompt).toContain('- **Web Host**: geoff.seemueller.io');
expect(prompt).toContain('- **User Location**: Unknown');
expect(prompt).toContain('- **Timezone**: UTC');
expect(prompt).not.toContain('- **Response Limit**:');
expect(prompt).toContain('### Date: ');
expect(prompt).toContain('### Web Host: ');
expect(prompt).toContain('### User Location: ');
expect(prompt).toContain('### Timezone: ');
});
it('should include maxTokens when provided', () => {
// Mock dependencies
vi.mocked(Utils.selectEquitably).mockReturnValue({
'question1': 'answer1',
'question2': 'answer2'
question1: 'answer1',
question2: 'answer2',
});
vi.mocked(Utils.getCurrentDate).mockReturnValue('2023-01-01T12:30:45Z');
const prompt = AssistantSdk.getAssistantPrompt({ maxTokens: 1000 });
expect(prompt).toContain('- **Response Limit**: 1000 tokens (maximum)');
expect(prompt).toContain('Max Response Length: 1000 tokens (maximum)');
});
it('should use provided userTimezone and userLocation', () => {
// Mock dependencies
vi.mocked(Utils.selectEquitably).mockReturnValue({
'question1': 'answer1',
'question2': 'answer2'
question1: 'answer1',
question2: 'answer2',
});
vi.mocked(Utils.getCurrentDate).mockReturnValue('2023-01-01T12:30:45Z');
const prompt = AssistantSdk.getAssistantPrompt({
userTimezone: 'America/New_York',
userLocation: 'New York, USA'
userLocation: 'New York, USA',
});
expect(prompt).toContain('- **User Location**: New York, USA');
expect(prompt).toContain('- **Timezone**: America/New_York');
expect(prompt).toContain('### User Location: New York, USA');
expect(prompt).toContain('### Timezone: America/New_York');
});
it('should use current date when Utils.getCurrentDate is not available', () => {
// Mock dependencies
vi.mocked(Utils.selectEquitably).mockReturnValue({
'question1': 'answer1',
'question2': 'answer2'
question1: 'answer1',
question2: 'answer2',
});
vi.mocked(Utils.getCurrentDate).mockReturnValue(undefined);
const prompt = AssistantSdk.getAssistantPrompt({});
// Instead of checking for a specific date, just verify that a date is included
expect(prompt).toMatch(/- \*\*Date\*\*: \d{4}-\d{2}-\d{2} \d{1,2}:\d{2} \d{1,2}s/);
expect(prompt).toMatch(/### Date: \d{4}-\d{2}-\d{2} \d{1,2}:\d{2} \d{1,2}s/);
});
it('should use few_shots directly when Utils.selectEquitably is not available', () => {
@@ -114,7 +114,7 @@ describe('AssistantSdk', () => {
it('should format fewshots correctly', () => {
const fewshots = {
'What is the capital of France?': 'Paris is the capital of France.',
'How do I make pasta?': 'Boil water, add pasta, cook until al dente.'
'How do I make pasta?': 'Boil water, add pasta, cook until al dente.',
};
const result = AssistantSdk.useFewshots(fewshots);
@@ -129,12 +129,12 @@ describe('AssistantSdk', () => {
it('should respect the limit parameter', () => {
const fewshots = {
'Q1': 'A1',
'Q2': 'A2',
'Q3': 'A3',
'Q4': 'A4',
'Q5': 'A5',
'Q6': 'A6'
Q1: 'A1',
Q2: 'A2',
Q3: 'A3',
Q4: 'A4',
Q5: 'A5',
Q6: 'A6',
};
const result = AssistantSdk.useFewshots(fewshots, 3);

View File

@@ -1,26 +1,27 @@
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { ChatSdk } from '../chat-sdk.ts';
import { AssistantSdk } from '../assistant-sdk.ts';
import Message from '../../models/Message.ts';
import { ProviderRepository } from '../../providers/_ProviderRepository';
import { AssistantSdk } from '../assistant-sdk.ts';
import { ChatSdk } from '../chat-sdk.ts';
// Mock dependencies
vi.mock('../assistant-sdk', () => ({
AssistantSdk: {
getAssistantPrompt: vi.fn()
}
getAssistantPrompt: vi.fn(),
},
}));
vi.mock('../../models/Message', () => ({
default: {
create: vi.fn((message) => message)
}
create: vi.fn(message => message),
},
}));
vi.mock('../../providers/_ProviderRepository', () => ({
ProviderRepository: {
getModelFamily: vi.fn()
}
getModelFamily: vi.fn(),
},
}));
describe('ChatSdk', () => {
@@ -37,11 +38,11 @@ describe('ChatSdk', () => {
expect(Message.create).toHaveBeenCalledWith({
role: 'assistant',
content: ''
content: '',
});
expect(result).toEqual({
role: 'assistant',
content: ''
content: '',
});
});
});
@@ -49,7 +50,7 @@ describe('ChatSdk', () => {
describe('handleChatRequest', () => {
it('should return a 400 response if no messages are provided', async () => {
const request = {
json: vi.fn().mockResolvedValue({ messages: [] })
json: vi.fn().mockResolvedValue({ messages: [] }),
};
const ctx = {
openai: {},
@@ -58,9 +59,9 @@ describe('ChatSdk', () => {
env: {
SERVER_COORDINATOR: {
idFromName: vi.fn(),
get: vi.fn()
}
}
get: vi.fn(),
},
},
};
const response = await ChatSdk.handleChatRequest(request as any, ctx as any);
@@ -72,7 +73,7 @@ describe('ChatSdk', () => {
it('should save stream data and return a response with streamUrl', async () => {
const streamId = 'test-uuid';
vi.stubGlobal('crypto', {
randomUUID: vi.fn().mockReturnValue(streamId)
randomUUID: vi.fn().mockReturnValue(streamId),
});
const messages = [{ role: 'user', content: 'Hello' }];
@@ -80,12 +81,12 @@ describe('ChatSdk', () => {
const conversationId = 'conv-123';
const request = {
json: vi.fn().mockResolvedValue({ messages, model, conversationId })
json: vi.fn().mockResolvedValue({ messages, model, conversationId }),
};
const saveStreamData = vi.fn();
const durableObject = {
saveStreamData
saveStreamData,
};
const ctx = {
@@ -95,9 +96,9 @@ describe('ChatSdk', () => {
env: {
SERVER_COORDINATOR: {
idFromName: vi.fn().mockReturnValue('object-id'),
get: vi.fn().mockReturnValue(durableObject)
}
}
get: vi.fn().mockReturnValue(durableObject),
},
},
};
const response = await ChatSdk.handleChatRequest(request as any, ctx as any);
@@ -105,12 +106,9 @@ describe('ChatSdk', () => {
expect(ctx.env.SERVER_COORDINATOR.idFromName).toHaveBeenCalledWith('stream-index');
expect(ctx.env.SERVER_COORDINATOR.get).toHaveBeenCalledWith('object-id');
expect(saveStreamData).toHaveBeenCalledWith(
streamId,
expect.stringContaining(model)
);
expect(saveStreamData).toHaveBeenCalledWith(streamId, expect.stringContaining(model));
expect(responseBody).toEqual({
streamUrl: `/api/streams/${streamId}`
streamUrl: `/api/streams/${streamId}`,
});
});
});
@@ -120,7 +118,7 @@ describe('ChatSdk', () => {
const messages = [{ role: 'user', content: 'Hello' }];
const dynamicMaxTokens = vi.fn().mockResolvedValue(500);
const durableObject = {
dynamicMaxTokens
dynamicMaxTokens,
};
const ctx = {
@@ -128,9 +126,9 @@ describe('ChatSdk', () => {
env: {
SERVER_COORDINATOR: {
idFromName: vi.fn().mockReturnValue('object-id'),
get: vi.fn().mockReturnValue(durableObject)
}
}
get: vi.fn().mockReturnValue(durableObject),
},
},
};
await ChatSdk.calculateMaxTokens(messages, ctx as any);
@@ -150,7 +148,7 @@ describe('ChatSdk', () => {
expect(AssistantSdk.getAssistantPrompt).toHaveBeenCalledWith({
maxTokens: 1000,
userTimezone: 'UTC',
userLocation: 'USA/unknown'
userLocation: 'USA/unknown',
});
expect(result).toBe('Assistant prompt');
});
@@ -160,15 +158,13 @@ describe('ChatSdk', () => {
it('should build a message chain with system role for most models', async () => {
vi.mocked(ProviderRepository.getModelFamily).mockResolvedValue('openai');
const messages = [
{role: 'user', content: 'Hello'}
];
const messages = [{ role: 'user', content: 'Hello' }];
const opts = {
systemPrompt: 'System prompt',
assistantPrompt: 'Assistant prompt',
toolResults: {role: 'tool', content: 'Tool result'},
model: 'gpt-4'
toolResults: { role: 'tool', content: 'Tool result' },
model: 'gpt-4',
};
const result = await ChatSdk.buildMessageChain(messages, opts as any);
@@ -177,30 +173,28 @@ describe('ChatSdk', () => {
expect(Message.create).toHaveBeenCalledTimes(3);
expect(Message.create).toHaveBeenNthCalledWith(1, {
role: 'system',
content: 'System prompt'
content: 'System prompt',
});
expect(Message.create).toHaveBeenNthCalledWith(2, {
role: 'assistant',
content: 'Assistant prompt'
content: 'Assistant prompt',
});
expect(Message.create).toHaveBeenNthCalledWith(3, {
role: 'user',
content: 'Hello'
content: 'Hello',
});
});
it('should build a message chain with assistant role for o1, gemma, claude, or google models', async () => {
vi.mocked(ProviderRepository.getModelFamily).mockResolvedValue('claude');
const messages = [
{ role: 'user', content: 'Hello' }
];
const messages = [{ role: 'user', content: 'Hello' }];
const opts = {
systemPrompt: 'System prompt',
assistantPrompt: 'Assistant prompt',
toolResults: { role: 'tool', content: 'Tool result' },
model: 'claude-3'
model: 'claude-3',
};
const result = await ChatSdk.buildMessageChain(messages, opts as any);
@@ -209,7 +203,7 @@ describe('ChatSdk', () => {
expect(Message.create).toHaveBeenCalledTimes(3);
expect(Message.create).toHaveBeenNthCalledWith(1, {
role: 'assistant',
content: 'System prompt'
content: 'System prompt',
});
});
@@ -220,14 +214,14 @@ describe('ChatSdk', () => {
{ role: 'user', content: 'Hello' },
{ role: 'user', content: '' },
{ role: 'user', content: ' ' },
{ role: 'user', content: 'World' }
{ role: 'user', content: 'World' },
];
const opts = {
systemPrompt: 'System prompt',
assistantPrompt: 'Assistant prompt',
toolResults: { role: 'tool', content: 'Tool result' },
model: 'gpt-4'
model: 'gpt-4',
};
const result = await ChatSdk.buildMessageChain(messages, opts as any);

View File

@@ -1,4 +1,5 @@
import { describe, it, expect } from 'vitest';
import { Utils } from '../utils.ts';
describe('Debug Utils.getSeason', () => {

View File

@@ -1,13 +1,14 @@
import { describe, it, expect, vi, beforeEach } from 'vitest';
import handleStreamData from '../handleStreamData.ts';
describe('handleStreamData', () => {
// Setup mocks
const mockController = {
enqueue: vi.fn()
enqueue: vi.fn(),
};
const mockEncoder = {
encode: vi.fn((str) => str)
encode: vi.fn(str => str),
};
beforeEach(() => {
@@ -16,75 +17,75 @@ describe('handleStreamData', () => {
it('should return early if data type is not "chat"', () => {
const handler = handleStreamData(mockController as any, mockEncoder as any);
handler({ type: 'not-chat', data: {} });
expect(mockController.enqueue).not.toHaveBeenCalled();
expect(mockEncoder.encode).not.toHaveBeenCalled();
});
it('should return early if data is undefined', () => {
const handler = handleStreamData(mockController as any, mockEncoder as any);
handler(undefined as any);
expect(mockController.enqueue).not.toHaveBeenCalled();
expect(mockEncoder.encode).not.toHaveBeenCalled();
});
it('should handle content_block_start type data', () => {
const handler = handleStreamData(mockController as any, mockEncoder as any);
const data = {
type: 'chat',
data: {
type: 'content_block_start',
content_block: {
type: 'text',
text: 'Hello world'
}
}
text: 'Hello world',
},
},
};
handler(data);
expect(mockController.enqueue).toHaveBeenCalledTimes(1);
expect(mockEncoder.encode).toHaveBeenCalledWith(expect.stringContaining('Hello world'));
const encodedData = mockEncoder.encode.mock.calls[0][0];
const parsedData = JSON.parse(encodedData.split('data: ')[1]);
expect(parsedData.type).toBe('chat');
expect(parsedData.data.choices[0].delta.content).toBe('Hello world');
});
it('should handle delta.text type data', () => {
const handler = handleStreamData(mockController as any, mockEncoder as any);
const data = {
type: 'chat',
data: {
delta: {
text: 'Hello world'
}
}
text: 'Hello world',
},
},
};
handler(data);
expect(mockController.enqueue).toHaveBeenCalledTimes(1);
expect(mockEncoder.encode).toHaveBeenCalledWith(expect.stringContaining('Hello world'));
const encodedData = mockEncoder.encode.mock.calls[0][0];
const parsedData = JSON.parse(encodedData.split('data: ')[1]);
expect(parsedData.type).toBe('chat');
expect(parsedData.data.choices[0].delta.content).toBe('Hello world');
});
it('should handle choices[0].delta.content type data', () => {
const handler = handleStreamData(mockController as any, mockEncoder as any);
const data = {
type: 'chat',
data: {
@@ -92,23 +93,23 @@ describe('handleStreamData', () => {
{
index: 0,
delta: {
content: 'Hello world'
content: 'Hello world',
},
logprobs: null,
finish_reason: null
}
]
}
finish_reason: null,
},
],
},
};
handler(data);
expect(mockController.enqueue).toHaveBeenCalledTimes(1);
expect(mockEncoder.encode).toHaveBeenCalledWith(expect.stringContaining('Hello world'));
const encodedData = mockEncoder.encode.mock.calls[0][0];
const parsedData = JSON.parse(encodedData.split('data: ')[1]);
expect(parsedData.type).toBe('chat');
expect(parsedData.data.choices[0].delta.content).toBe('Hello world');
expect(parsedData.data.choices[0].finish_reason).toBe(null);
@@ -116,7 +117,7 @@ describe('handleStreamData', () => {
it('should pass through data with choices but no delta.content', () => {
const handler = handleStreamData(mockController as any, mockEncoder as any);
const data = {
type: 'chat',
data: {
@@ -125,64 +126,66 @@ describe('handleStreamData', () => {
index: 0,
delta: {},
logprobs: null,
finish_reason: 'stop'
}
]
}
finish_reason: 'stop',
},
],
},
};
handler(data);
expect(mockController.enqueue).toHaveBeenCalledTimes(1);
expect(mockEncoder.encode).toHaveBeenCalledWith(expect.stringContaining('"finish_reason":"stop"'));
expect(mockEncoder.encode).toHaveBeenCalledWith(
expect.stringContaining('"finish_reason":"stop"'),
);
});
it('should return early for unrecognized data format', () => {
const handler = handleStreamData(mockController as any, mockEncoder as any);
const data = {
type: 'chat',
data: {
// No recognized properties
unrecognized: 'property'
}
unrecognized: 'property',
},
};
handler(data);
expect(mockController.enqueue).not.toHaveBeenCalled();
expect(mockEncoder.encode).not.toHaveBeenCalled();
});
it('should use custom transform function if provided', () => {
const handler = handleStreamData(mockController as any, mockEncoder as any);
const data = {
type: 'chat',
data: {
original: 'data'
}
original: 'data',
},
};
const transformFn = vi.fn().mockReturnValue({
type: 'chat',
data: {
choices: [
{
delta: {
content: 'Transformed content'
content: 'Transformed content',
},
logprobs: null,
finish_reason: null
}
]
}
finish_reason: null,
},
],
},
});
handler(data, transformFn);
expect(transformFn).toHaveBeenCalledWith(data);
expect(mockController.enqueue).toHaveBeenCalledTimes(1);
expect(mockEncoder.encode).toHaveBeenCalledWith(expect.stringContaining('Transformed content'));
});
});
});

View File

@@ -1,4 +1,5 @@
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import { Utils } from '../utils.ts';
describe('Utils', () => {
@@ -44,8 +45,8 @@ describe('Utils', () => {
// Mock Intl.DateTimeFormat
global.Intl.DateTimeFormat = vi.fn().mockReturnValue({
resolvedOptions: vi.fn().mockReturnValue({
timeZone: 'America/New_York'
})
timeZone: 'America/New_York',
}),
});
});
@@ -102,10 +103,10 @@ describe('Utils', () => {
it('should select items equitably from multiple sources', () => {
const sources = {
a: { 'key1': 'value1', 'key2': 'value2' },
b: { 'key3': 'value3', 'key4': 'value4' },
c: { 'key5': 'value5', 'key6': 'value6' },
d: { 'key7': 'value7', 'key8': 'value8' }
a: { key1: 'value1', key2: 'value2' },
b: { key3: 'value3', key4: 'value4' },
c: { key5: 'value5', key6: 'value6' },
d: { key7: 'value7', key8: 'value8' },
};
const result = Utils.selectEquitably(sources, 4);
@@ -117,10 +118,10 @@ describe('Utils', () => {
it('should handle itemCount greater than available items', () => {
const sources = {
a: { 'key1': 'value1' },
b: { 'key2': 'value2' },
a: { key1: 'value1' },
b: { key2: 'value2' },
c: {},
d: {}
d: {},
};
const result = Utils.selectEquitably(sources, 5);
@@ -135,7 +136,7 @@ describe('Utils', () => {
a: {},
b: {},
c: {},
d: {}
d: {},
};
const result = Utils.selectEquitably(sources, 5);
@@ -148,7 +149,7 @@ describe('Utils', () => {
it('should insert blank messages to maintain user/assistant alternation', () => {
const messages = [
{ role: 'user', content: 'Hello' },
{ role: 'user', content: 'How are you?' }
{ role: 'user', content: 'How are you?' },
];
const result = Utils.normalizeWithBlanks(messages);
@@ -160,9 +161,7 @@ describe('Utils', () => {
});
it('should insert blank user message if first message is assistant', () => {
const messages = [
{ role: 'assistant', content: 'Hello, how can I help?' }
];
const messages = [{ role: 'assistant', content: 'Hello, how can I help?' }];
const result = Utils.normalizeWithBlanks(messages);
@@ -183,7 +182,7 @@ describe('Utils', () => {
const messages = [
{ role: 'user', content: 'Hello' },
{ role: 'assistant', content: 'Hi there' },
{ role: 'user', content: 'How are you?' }
{ role: 'user', content: 'How are you?' },
];
const result = Utils.normalizeWithBlanks(messages);