Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add categoriser to fixtures in tests, fix streaming bugs (WIP) #323

Draft
wants to merge 121 commits into
base: fix/dropdown_sections
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
121 commits
Select commit Hold shift + click to select a range
8a49562
feat: add categoriser to fixtures in tests, fix streaming bugs
stefl Oct 30, 2024
09b96c9
Typescript import issue using @utils
stefl Oct 30, 2024
4c346d0
chore: add expired exports cron job to public routes (#358)
JBR90 Nov 11, 2024
fba6c1c
Merge pull request #360 from oaknational/rc-20241111-1
mikeritson-oak Nov 12, 2024
4a9d4fb
build(release v1.14.2): See CHANGE_LOG.md
semantic-release-bot Nov 12, 2024
854950d
feat: prisma health check - AI-625 (#356)
JBR90 Nov 12, 2024
d0fe2d0
feat: add additional materials button - AI-539 [migration] (#255)
JBR90 Nov 12, 2024
646b419
Merge pull request #363 from oaknational/main
mikeritson-oak Nov 13, 2024
713f18c
build(release v1.15.0): See CHANGE_LOG.md
semantic-release-bot Nov 13, 2024
1d4995e
feat: add FeatureFlagProvider (#353)
codeincontext Nov 14, 2024
05ccce6
feat: link to hubspot form from requests for full access and higher r…
JBR90 Nov 14, 2024
33df453
test: add storybook stories for public pages (#365)
codeincontext Nov 15, 2024
72d381f
test: add stories for header and footer (#368)
codeincontext Nov 15, 2024
c1eff88
fix: add types for SVG imports, remove unused (#318)
stefl Nov 18, 2024
a78bcd0
chore: remove example_lesson.json (#366)
JBR90 Nov 18, 2024
2085398
Merge pull request #370 from oaknational/rc-20241118-1
mikeritson-oak Nov 18, 2024
00b681b
chore: camel case imports in a single file (#309)
stefl Nov 18, 2024
937194e
build(release v1.16.0): See CHANGE_LOG.md
semantic-release-bot Nov 18, 2024
a128d8c
Merge remote-tracking branch 'origin/production'
actions-user Nov 18, 2024
8162e39
refactor: adjust all dialogs to use oak components (#335)
tomwisecodes Nov 19, 2024
27cb19b
test: stories for aila routes (#371)
codeincontext Nov 19, 2024
ba5618e
chore: change text to sentence case - AI-237 (#355)
JBR90 Nov 20, 2024
3e18b44
fix: streaming JSON types and error reporting tests (#315)
stefl Nov 20, 2024
75e64b9
refactor: add more granular logging to cron job (#373)
JBR90 Nov 20, 2024
20f956e
fix: handle aborts and add logging to the stream handler (#350)
stefl Nov 20, 2024
d992b6c
chore: experimental properties on lesson plan [AI-608] (#362)
mantagen Nov 21, 2024
03df2c3
test: stories for dialogs (#372)
codeincontext Nov 21, 2024
964f2b8
Merge pull request #374 from oaknational/rc-20241120-1
mikeritson-oak Nov 21, 2024
ee17558
build(release v1.16.1): See CHANGE_LOG.md
semantic-release-bot Nov 21, 2024
1cc8ce5
Merge remote-tracking branch 'origin/production'
actions-user Nov 21, 2024
c298b10
fix: hook error on sign-in page (#208)
stefl Nov 21, 2024
871c23f
fix: add missing dependencies to Analytics Provider (#306)
stefl Nov 21, 2024
cf48fdf
test: stories for right hand side of lesson planner (#377)
codeincontext Nov 22, 2024
81fc31c
fix(sec): bump next to 14.2.18 (#242)
johnrobeds Nov 22, 2024
3b529a9
Merge pull request #380 from oaknational/rc-20241125-1
mikeritson-oak Nov 25, 2024
58cedeb
build(release v1.16.2): See CHANGE_LOG.md
semantic-release-bot Nov 25, 2024
cd88576
fix: assert readonly props (#381)
stefl Nov 26, 2024
69b2371
feat: move delete all button and restyle side menu (#375)
tomwisecodes Nov 26, 2024
6af7fad
chore: add rag table migrations (#385)
mantagen Nov 26, 2024
610d8c8
fix: svg clip-rule should be clipRule in JSX (#382)
stefl Nov 26, 2024
ec4ce6e
fix: minor linting (#384)
stefl Nov 26, 2024
844ed48
chore: copy updates for help page - AI-492 (#367)
JBR90 Nov 26, 2024
015cd25
fix: minor sonar issues (#390)
stefl Nov 26, 2024
7b4d5bc
fix: readonly props for icons.tsx (#389)
stefl Nov 26, 2024
02cc4db
chore: add Jest code coverage to Sonar, fix minor Sonar errors (#387)
stefl Nov 27, 2024
b40def9
fix: prefer nullish coalescing (#391)
stefl Nov 27, 2024
4cb2e45
refactor: cron job gd exports error after update (#378)
JBR90 Nov 27, 2024
d2177d5
fix: add linting command to db package (#392)
stefl Nov 27, 2024
fb0258e
fix: high and medium severity bugs on sonar cloud - AI-637 (#379)
JBR90 Nov 27, 2024
202a21f
fix: address sonar major issues (#393)
stefl Nov 27, 2024
9700214
fix: icons in dialogs (#398)
tomwisecodes Nov 27, 2024
f6262f2
fix: help page cloudflare email (#399)
codeincontext Nov 27, 2024
daa7efe
fix: sonar maintain linting #3 (#403)
stefl Nov 27, 2024
391b67c
fix: help page cloudflare email (#399)
codeincontext Nov 27, 2024
ac72713
fix: revert tabindex change (#404)
stefl Nov 28, 2024
7ec8444
chore: add check for cyclic dependencies (#396)
stefl Nov 28, 2024
1ed9d60
fix: sonar maintain linting #2 (#395)
stefl Nov 28, 2024
f4d95fc
fix: sonar maintain linting #1 (#394)
stefl Nov 28, 2024
7e45ac1
Merge pull request #388 from oaknational/rc-20241126-1
mikeritson-oak Nov 28, 2024
c373a6e
build(release v1.17.0): See CHANGE_LOG.md
semantic-release-bot Nov 28, 2024
044ac16
Merge remote-tracking branch 'origin/production'
actions-user Nov 28, 2024
65d1c5f
fix: intentionality of async / promise code for question generation (…
stefl Nov 28, 2024
dbe04fd
chore: maths rec-sys feature flag, fixes, and images in exports [AI-6…
mantagen Nov 28, 2024
60ee010
fix: memoize the sidebar context provider's value (#408)
stefl Nov 28, 2024
eca0019
fix: sonar maintain issues #4 (#405)
stefl Nov 28, 2024
abda175
fix: do not define components inline (#413)
stefl Nov 28, 2024
91e2291
test: stories for supplementary chat messages (#401)
codeincontext Nov 28, 2024
65f4a4a
test: add stories for chat messages and parts (#407)
codeincontext Nov 28, 2024
44b5961
fix: do not use array index for key / use void for onSubmit (#409)
stefl Nov 28, 2024
628f9b1
chore: remove old migration scripts (#412)
stefl Nov 28, 2024
5f749f4
fix: sonar minors #5 (#414)
stefl Nov 28, 2024
abbff85
fix: more flexible and efficient solution for images in docs (#411)
mantagen Dec 2, 2024
c27c76d
Merge pull request #416 from oaknational/rc-20241202-1
mikeritson-oak Dec 3, 2024
b5060c7
build(release v1.17.1): See CHANGE_LOG.md
semantic-release-bot Dec 3, 2024
122bc4e
Merge remote-tracking branch 'origin/production'
actions-user Dec 3, 2024
701ff65
chore: set sonar languages (#415)
JBR90 Dec 3, 2024
00767a0
feat: test coverage (#406)
JBR90 Dec 3, 2024
7539661
fix: moderation persist scores [AI-696] (#418)
mantagen Dec 3, 2024
e36841e
test: add stories for onboarding (#423)
codeincontext Dec 3, 2024
edce949
test: add story for chat lhs header (#420)
codeincontext Dec 3, 2024
d40af98
test: chat quick buttons stories (#417)
codeincontext Dec 3, 2024
e6a0afb
test: add chat panel stories (#421)
codeincontext Dec 3, 2024
1f4aa9d
fix: upgrade typescript + prettier + eslint with a single shared lint…
stefl Dec 4, 2024
a0cb485
feat: report google drive storage quota (#425)
JBR90 Dec 6, 2024
34774b5
fix: update eslint config and lint errors (#422)
JBR90 Dec 6, 2024
af9645d
chore: remove stories files from code duplication calculations (#426)
stefl Dec 6, 2024
b7972ba
chore: add additional logging to the aila package (#430)
stefl Dec 9, 2024
c1c812f
chore: use LessonPlanSectionWhileStreaming type (#434)
stefl Dec 9, 2024
a8ada5d
fix: temporarily disable no unsafe rules (#429)
stefl Dec 9, 2024
f011694
test: add responsive modes to chromatic (#427)
codeincontext Dec 10, 2024
1200b1f
test: mobile snapshots for page stories (#436)
codeincontext Dec 10, 2024
53fc941
test: add stories for chat header (#437)
codeincontext Dec 10, 2024
071d2d1
test: remove legacy chromatic mode and use desktop as default (#439)
codeincontext Dec 10, 2024
56f6d23
Merge pull request #428 from oaknational/rc-20241206-1
mikeritson-oak Dec 11, 2024
a0d7c11
build: fix release config cjs
codeincontext Dec 11, 2024
8c0fa5e
Merge pull request #442 from oaknational/rc-20241126-1
oak-machine-user Dec 11, 2024
09646c7
build(release v1.18.0): See CHANGE_LOG.md
semantic-release-bot Dec 11, 2024
8b4e32a
Merge remote-tracking branch 'origin/production'
actions-user Dec 11, 2024
c91c5fb
chore: specify types for useProgressForDownloads (#433)
stefl Dec 11, 2024
35141b3
fix: remove key from chat provider (#431)
stefl Dec 11, 2024
392b422
chore: add dependency cruiser (#438)
stefl Dec 11, 2024
0e43509
chore: reinstate react hooks linting, fix linting issues (#441)
stefl Dec 11, 2024
4955a1e
fix: improve chances of showing 5 relevant plans (#444)
mantagen Dec 12, 2024
7c24485
fix: posthog consistent event properties (#440)
mantagen Dec 12, 2024
35e25fc
test: storybook decorators (#443)
codeincontext Dec 12, 2024
125a274
Merge pull request #453 from oaknational/rc-20241216-2
mikeritson-oak Dec 16, 2024
bf3c502
build(release v1.18.1): See CHANGE_LOG.md
semantic-release-bot Dec 16, 2024
b114694
chore: update posthog (#454)
codeincontext Dec 16, 2024
61ccbb6
chore: update posthog (#454)
codeincontext Dec 16, 2024
dea3106
fix: sonar duplication (#397)
JBR90 Dec 17, 2024
9dee4ad
feat: soft delete (#383)
tomwisecodes Dec 17, 2024
0e8e48a
Merge pull request #455 from oaknational/rc-20241216-3
oak-machine-user Dec 17, 2024
82d4c37
build(release v1.18.2): See CHANGE_LOG.md
semantic-release-bot Dec 17, 2024
a842173
Merge remote-tracking branch 'origin/production'
actions-user Dec 17, 2024
36a533d
test: use tighter "satisfies" typing in storybook (#456)
codeincontext Dec 17, 2024
4f2211e
Merge pull request #458 from oaknational/rc-20241218-1
mikeritson-oak Dec 18, 2024
a0999c1
build(release v1.19.0): See CHANGE_LOG.md
semantic-release-bot Dec 18, 2024
8c07138
Merge branch 'main' into fix/no_live_openai
JBR90 Dec 18, 2024
2f255b3
feat: react scan (#445)
JBR90 Dec 19, 2024
d4b3d82
fix: missing object fixture in replay
JBR90 Dec 20, 2024
392317f
Merge branch 'main' into fix/no_live_openai
JBR90 Dec 20, 2024
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
52 changes: 34 additions & 18 deletions apps/nextjs/src/app/api/chat/chatHandler.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
import type { Aila } from "@oakai/aila/src/core/Aila";
import type { AilaServices } from "@oakai/aila/src/core/AilaServices";
import type { Message } from "@oakai/aila/src/core/chat";
import type { AilaInitializationOptions } from "@oakai/aila/src/core/types";
import type {
AilaOptions,
AilaPublicChatOptions,
import { MessageSchema } from "@oakai/aila/src/core/chat/types";
import { OpenAIService } from "@oakai/aila/src/core/llm/OpenAIService";
import {
AilaOptionsSchema,
type AilaInitializationOptions,
} from "@oakai/aila/src/core/types";
import type { AilaOptions } from "@oakai/aila/src/core/types";
import { AilaAmericanisms } from "@oakai/aila/src/features/americanisms/AilaAmericanisms";
import {
DatadogAnalyticsAdapter,
PosthogAnalyticsAdapter,
} from "@oakai/aila/src/features/analytics";
import { AilaCategorisation } from "@oakai/aila/src/features/categorisation/categorisers/AilaCategorisation";
import { AilaRag } from "@oakai/aila/src/features/rag/AilaRag";
import type { LooseLessonPlan } from "@oakai/aila/src/protocol/schema";
import {
LessonPlanSchemaWhilstStreaming,
type LooseLessonPlan,
} from "@oakai/aila/src/protocol/schema";
import type { TracingSpan } from "@oakai/core/src/tracing/serverTracing";
import { withTelemetry } from "@oakai/core/src/tracing/serverTracing";
import type { PrismaClientWithAccelerate } from "@oakai/db";
Expand All @@ -24,6 +30,7 @@ import { aiLogger } from "@oakai/logger";
import { StreamingTextResponse } from "ai";
import type { NextRequest } from "next/server";
import invariant from "tiny-invariant";
import { z } from "zod";

import type { Config } from "./config";
import { handleChatException } from "./errorHandling";
Expand All @@ -40,26 +47,30 @@ export const maxDuration = 300;
const prisma: PrismaClientWithAccelerate = globalPrisma;

export async function GET() {
return new Response("Chat API is working", { status: 200 });
return new Promise((resolve) => {
resolve(new Response("Chat API is working", { status: 200 }));
});
}

async function setupChatHandler(req: NextRequest) {
return await withTelemetry(
"chat-setup-chat-handler",
{},
async (span: TracingSpan) => {
const json = await req.json();
const json = (await req.json()) as unknown;
const chatRequestSchema = z.object({
id: z.string(),
messages: MessageSchema.array(),
lessonPlan: LessonPlanSchemaWhilstStreaming,
options: AilaOptionsSchema,
});

const {
id: chatId,
messages,
lessonPlan = {},
options: chatOptions = {},
}: {
id: string;
messages: Message[];
lessonPlan?: LooseLessonPlan;
options?: AilaPublicChatOptions;
} = json;
lessonPlan,
options: chatOptions,
} = chatRequestSchema.parse(json);

const options: AilaOptions = {
useRag: chatOptions.useRag ?? true,
Expand All @@ -69,6 +80,8 @@ async function setupChatHandler(req: NextRequest) {
useModeration: true,
};

invariant(chatId, "Chat ID is required");

const llmService = getFixtureLLMService(req.headers, chatId);
const moderationAiClient = getFixtureModerationOpenAiClient(
req.headers,
Expand Down Expand Up @@ -180,9 +193,12 @@ export async function handleChatPostRequest(
messages,
},
services: {
chatLlmService: llmService,
chatLlmService: () =>
llmService ?? new OpenAIService({ userId, chatId }),
moderationAiClient,
ragService: (aila: AilaServices) => new AilaRag({ aila }),
chatCategoriser: (aila: AilaServices) =>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pass in the categoriser at initialisation, in the same way we do with the other features

new AilaCategorisation({ aila }),
americanismsService: () => new AilaAmericanisms(),
analyticsAdapters: (aila: AilaServices) => [
new PosthogAnalyticsAdapter(aila),
Expand All @@ -191,8 +207,8 @@ export async function handleChatPostRequest(
},
lessonPlan: lessonPlan ?? {},
};
const result = await config.createAila(ailaOptions);
return result;
const aila = await config.createAila(ailaOptions);
return aila;
},
);
invariant(aila, "Aila instance is required");
Expand Down
4 changes: 3 additions & 1 deletion apps/nextjs/src/app/api/chat/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export const defaultConfig: Config = {
prisma: globalPrisma,
createAila: async (options) => {
const webActionsPlugin = createWebActionsPlugin(globalPrisma);
return new Aila({
const createdAila = new Aila({
...options,
plugins: [...(options.plugins || []), webActionsPlugin],
prisma: options.prisma ?? globalPrisma,
Expand All @@ -26,5 +26,7 @@ export const defaultConfig: Config = {
userId: undefined,
},
});
await createdAila.initialise();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ensure that the Aila instance is initialised

return createdAila;
},
};
33 changes: 32 additions & 1 deletion apps/nextjs/src/app/api/chat/fixtures/FixtureRecordLLMService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import type { ZodSchema } from "zod";
const log = aiLogger("fixtures");

export class FixtureRecordLLMService implements LLMService {
name = "FixureRecordLLM";
name = "FixtureRecordLLM";
private _openAIService: OpenAIService;

constructor(
Expand All @@ -23,6 +23,11 @@ export class FixtureRecordLLMService implements LLMService {
messages: Message[];
temperature: number;
}): Promise<ReadableStreamDefaultReader<string>> {
log.info(
"Creating chat completion from OpenAI",
this.name,
this.fixtureName,
);
return this._openAIService.createChatCompletionStream(params);
}

Expand All @@ -33,6 +38,11 @@ export class FixtureRecordLLMService implements LLMService {
messages: Message[];
temperature: number;
}): Promise<ReadableStreamDefaultReader<string>> {
log.info(
"Creating chat completion object stream",
this.name,
this.fixtureName,
);
const upstreamReader =
await this._openAIService.createChatCompletionObjectStream(params);

Expand Down Expand Up @@ -76,4 +86,25 @@ export class FixtureRecordLLMService implements LLMService {

return s.getReader();
}

async generateObject<T>(params: {
model: string;
schema: ZodSchema<T>;
schemaName: string;
messages: Message[];
temperature: number;
}): Promise<T | undefined> {
const result = await this._openAIService.generateObject(params);

try {
const formattedUrl = `${process.cwd()}/tests-e2e/recordings/${this.fixtureName}.generateObject.formatted.json`;
const formatted = JSON.stringify(result, null, 2);
log.info("Writing generateObject formatted to", formattedUrl);
await fs.writeFile(formattedUrl, formatted);
} catch (e) {
log.error("Error writing generateObject formatted file", e);
}

return result;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ import fs from "fs";
const log = aiLogger("fixtures");

export class FixtureReplayLLMService extends MockLLMService {
name = "FixureReplayLLM";
name = "FixtureReplayLLM";

constructor(fixtureName: string) {
log.info("Setting up fixture", fixtureName);
const fileUrl = `${process.cwd()}/tests-e2e/recordings/${fixtureName}.chunks.txt`;
log.info("Loading chunks from", fileUrl);
const fixture = fs.readFileSync(fileUrl, "utf8");
Expand Down
1 change: 1 addition & 0 deletions apps/nextjs/src/app/api/chat/fixtures/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export function getFixtureLLMService(headers: Headers, chatId: string) {
const fixtureName = headers.get("x-e2e-fixture-name");

if (!fixtureName) {
log.info("Not using fixtures");
return undefined;
}

Expand Down
58 changes: 34 additions & 24 deletions apps/nextjs/src/app/api/chat/route.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,30 +36,36 @@ describe("Chat API Route", () => {
jest.spyOn(mockLLMService, "createChatCompletionObjectStream");

testConfig = {
createAila: jest.fn().mockImplementation(async (options) => {
const ailaConfig: AilaInitializationOptions = {
options: {
usePersistence: false,
useRag: false,
useAnalytics: false,
useModeration: false,
useErrorReporting: false,
useThreatDetection: false,
createAila: jest
.fn()
.mockImplementation(
async (options: Partial<AilaInitializationOptions>) => {
return new Promise<Aila>((resolve) => {
const ailaConfig: AilaInitializationOptions = {
options: {
usePersistence: false,
useRag: false,
useAnalytics: false,
useModeration: false,
useErrorReporting: false,
useThreatDetection: false,
},
chat: {
id: chatId,
userId,
messages: options.chat?.messages ?? [],
},
plugins: [],
services: {
chatLlmService: () => mockLLMService,
chatCategoriser: () => mockChatCategoriser,
},
};
resolve(new Aila(ailaConfig));
});
},
chat: {
id: chatId,
userId,
messages: options.chat.messages ?? [],
},
plugins: [],
services: {
chatLlmService: mockLLMService,
chatCategoriser: mockChatCategoriser,
},
};
return new Aila(ailaConfig);
}),
// eslint-disable-next-line @typescript-eslint/no-explicit-any
),
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment
prisma: {} as any,
};
}, 60000);
Expand All @@ -70,7 +76,11 @@ describe("Chat API Route", () => {
body: JSON.stringify({
id: "test-chat-id",
messages: [
{ role: "user", content: "Create a lesson about Glaciation" },
{
id: "1",
role: "user",
content: "Create a lesson about Glaciation",
},
],
lessonPlan: {},
options: {},
Expand Down
Loading
Loading