@chat-js/cli 0.1.4 → 0.2.1

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.
Files changed (160) hide show
  1. package/dist/index.js +394 -247
  2. package/package.json +48 -48
  3. package/templates/chat-app/.claude/skiller.toml +18 -0
  4. package/templates/chat-app/.claude/skills/chat-context/SKILL.md +6 -0
  5. package/templates/chat-app/.claude/skills/chat-context/chat-context.mdc +36 -0
  6. package/templates/chat-app/.claude/skills/lazy-prefetch-pattern/lazy-prefetch-pattern.mdc +27 -0
  7. package/templates/chat-app/.claude/skills/react/react.mdc +29 -0
  8. package/templates/chat-app/.claude/skills/trpc-patterns/trpc-patterns.mdc +77 -0
  9. package/templates/chat-app/.claude/skills/typescript/typescript.mdc +53 -0
  10. package/templates/chat-app/.claude/skills/ultracite/ultracite.mdc +129 -0
  11. package/templates/chat-app/.cursor/skills/chat-context/SKILL.md +37 -0
  12. package/templates/chat-app/.cursor/skills/lazy-prefetch-pattern/SKILL.md +26 -0
  13. package/templates/chat-app/.cursor/skills/react/SKILL.md +28 -0
  14. package/templates/chat-app/.cursor/skills/trpc-patterns/SKILL.md +76 -0
  15. package/templates/chat-app/.cursor/skills/typescript/SKILL.md +52 -0
  16. package/templates/chat-app/.cursor/skills/ultracite/SKILL.md +128 -0
  17. package/templates/chat-app/app/(chat)/actions.ts +17 -13
  18. package/templates/chat-app/app/(chat)/api/chat/[id]/stream/route.ts +6 -5
  19. package/templates/chat-app/app/(chat)/api/chat/route.ts +14 -15
  20. package/templates/chat-app/app/(chat)/chat-providers.tsx +2 -2
  21. package/templates/chat-app/app/(chat)/layout.tsx +7 -6
  22. package/templates/chat-app/app/api/cron/cleanup/route.ts +4 -3
  23. package/templates/chat-app/app/globals.css +23 -23
  24. package/templates/chat-app/app/layout.tsx +1 -1
  25. package/templates/chat-app/biome.jsonc +3 -3
  26. package/templates/chat-app/chat.config.ts +48 -21
  27. package/templates/chat-app/components/anonymous-session-init.tsx +4 -12
  28. package/templates/chat-app/components/artifact-actions.tsx +5 -5
  29. package/templates/chat-app/components/artifact-panel.tsx +6 -6
  30. package/templates/chat-app/components/assistant-message.tsx +1 -1
  31. package/templates/chat-app/components/chat/chat-layout.tsx +2 -2
  32. package/templates/chat-app/components/chat/chat-welcome.tsx +1 -0
  33. package/templates/chat-app/components/chat-features-definitions.ts +11 -8
  34. package/templates/chat-app/components/chat-menu-items.tsx +4 -4
  35. package/templates/chat-app/components/chat-sync.tsx +1 -1
  36. package/templates/chat-app/components/clone-chat-button.tsx +2 -2
  37. package/templates/chat-app/components/code-editor.tsx +5 -5
  38. package/templates/chat-app/components/connectors-dropdown.tsx +2 -2
  39. package/templates/chat-app/components/console.tsx +5 -5
  40. package/templates/chat-app/components/create-artifact.tsx +28 -28
  41. package/templates/chat-app/components/data-stream-provider.tsx +2 -2
  42. package/templates/chat-app/components/deep-research-progress.tsx +2 -2
  43. package/templates/chat-app/components/delete-chat-dialog.tsx +3 -3
  44. package/templates/chat-app/components/delete-project-dialog.tsx +3 -3
  45. package/templates/chat-app/components/diffview.tsx +3 -3
  46. package/templates/chat-app/components/favicon-group.tsx +7 -7
  47. package/templates/chat-app/components/header-breadcrumb.tsx +11 -11
  48. package/templates/chat-app/components/image-editor.tsx +5 -5
  49. package/templates/chat-app/components/image-modal.tsx +4 -4
  50. package/templates/chat-app/components/interactive-chart-impl.tsx +269 -0
  51. package/templates/chat-app/components/interactive-charts.tsx +18 -246
  52. package/templates/chat-app/components/lexical-chat-input.tsx +10 -10
  53. package/templates/chat-app/components/message-editor.tsx +3 -3
  54. package/templates/chat-app/components/message-parts.tsx +8 -3
  55. package/templates/chat-app/components/messages-pane.tsx +4 -4
  56. package/templates/chat-app/components/messages.tsx +5 -5
  57. package/templates/chat-app/components/model-selector.tsx +4 -1
  58. package/templates/chat-app/components/multimodal-input.tsx +14 -5
  59. package/templates/chat-app/components/part/code-execution.tsx +4 -1
  60. package/templates/chat-app/components/part/document-common.tsx +8 -8
  61. package/templates/chat-app/components/part/document-preview.tsx +34 -16
  62. package/templates/chat-app/components/part/document-tool.tsx +3 -3
  63. package/templates/chat-app/components/part/dynamic-tool.tsx +3 -3
  64. package/templates/chat-app/components/part/generate-video.tsx +54 -0
  65. package/templates/chat-app/components/part/message-reasoning.tsx +3 -3
  66. package/templates/chat-app/components/project-details-dialog.tsx +4 -4
  67. package/templates/chat-app/components/project-home.tsx +1 -0
  68. package/templates/chat-app/components/project-icon-picker.tsx +5 -5
  69. package/templates/chat-app/components/project-icon.tsx +4 -4
  70. package/templates/chat-app/components/project-menu-items.tsx +3 -3
  71. package/templates/chat-app/components/research-tasks.tsx +3 -3
  72. package/templates/chat-app/components/sandbox.tsx +4 -4
  73. package/templates/chat-app/components/search-chats-dialog.tsx +11 -11
  74. package/templates/chat-app/components/settings/connectors-settings.tsx +1 -1
  75. package/templates/chat-app/components/settings/settings-nav.tsx +1 -1
  76. package/templates/chat-app/components/sheet-editor.tsx +5 -5
  77. package/templates/chat-app/components/sidebar-chats-list.tsx +5 -5
  78. package/templates/chat-app/components/suggested-actions.tsx +3 -3
  79. package/templates/chat-app/components/text-editor.tsx +5 -5
  80. package/templates/chat-app/components/toolbar.tsx +6 -6
  81. package/templates/chat-app/components/upgrade-cta/login-cta-banner.tsx +5 -5
  82. package/templates/chat-app/components/upgrade-cta/login-prompt.tsx +4 -4
  83. package/templates/chat-app/components/upgrade-cta/share-menu-item.tsx +3 -3
  84. package/templates/chat-app/components/user-message.tsx +3 -3
  85. package/templates/chat-app/components/version-footer.tsx +4 -4
  86. package/templates/chat-app/hooks/chat-sync-hooks.ts +0 -55
  87. package/templates/chat-app/hooks/use-artifact.tsx +3 -3
  88. package/templates/chat-app/hooks/use-auto-focus.ts +37 -7
  89. package/templates/chat-app/hooks/use-media-query.tsx +2 -4
  90. package/templates/chat-app/lib/ai/active-gateway.ts +1 -1
  91. package/templates/chat-app/lib/ai/ai-gateway-models-schemas.ts +30 -6
  92. package/templates/chat-app/lib/ai/app-model-id.ts +1 -1
  93. package/templates/chat-app/lib/ai/app-models.ts +4 -4
  94. package/templates/chat-app/lib/ai/eval-agent.ts +5 -5
  95. package/templates/chat-app/lib/ai/followup-suggestions.ts +5 -2
  96. package/templates/chat-app/lib/ai/gateway-model-defaults.ts +131 -41
  97. package/templates/chat-app/lib/ai/gateways/gateway-provider.ts +10 -6
  98. package/templates/chat-app/lib/ai/gateways/openai-compatible-gateway.ts +9 -4
  99. package/templates/chat-app/lib/ai/gateways/openai-gateway.ts +9 -4
  100. package/templates/chat-app/lib/ai/gateways/openrouter-gateway.ts +17 -12
  101. package/templates/chat-app/lib/ai/gateways/registry.ts +9 -0
  102. package/templates/chat-app/lib/ai/gateways/vercel-gateway.ts +36 -4
  103. package/templates/chat-app/lib/ai/mcp/cache.ts +13 -13
  104. package/templates/chat-app/lib/ai/model-data.ts +21 -20
  105. package/templates/chat-app/lib/ai/models.generated.ts +4397 -3592
  106. package/templates/chat-app/lib/ai/models.ts +1 -1
  107. package/templates/chat-app/lib/ai/providers.ts +10 -0
  108. package/templates/chat-app/lib/ai/text-splitter.ts +3 -4
  109. package/templates/chat-app/lib/ai/to-model-data.ts +1 -0
  110. package/templates/chat-app/lib/ai/tools/code-execution.ts +122 -53
  111. package/templates/chat-app/lib/ai/tools/deep-research/configuration.ts +35 -32
  112. package/templates/chat-app/lib/ai/tools/deep-research/pipeline.ts +2 -2
  113. package/templates/chat-app/lib/ai/tools/deep-research/types.ts +9 -9
  114. package/templates/chat-app/lib/ai/tools/documents/types.ts +4 -4
  115. package/templates/chat-app/lib/ai/tools/generate-image.ts +42 -20
  116. package/templates/chat-app/lib/ai/tools/generate-video.ts +166 -0
  117. package/templates/chat-app/lib/ai/tools/get-weather.ts +20 -20
  118. package/templates/chat-app/lib/ai/tools/read-document.ts +3 -3
  119. package/templates/chat-app/lib/ai/tools/steps/multi-query-web-search.ts +11 -11
  120. package/templates/chat-app/lib/ai/tools/steps/web-search.ts +6 -6
  121. package/templates/chat-app/lib/ai/tools/tools-definitions.ts +10 -5
  122. package/templates/chat-app/lib/ai/tools/tools.ts +15 -6
  123. package/templates/chat-app/lib/ai/tools/types.ts +2 -2
  124. package/templates/chat-app/lib/ai/types.ts +22 -13
  125. package/templates/chat-app/lib/artifacts/code/client.tsx +5 -5
  126. package/templates/chat-app/lib/artifacts/sheet/client.tsx +2 -2
  127. package/templates/chat-app/lib/artifacts/text/client.tsx +18 -3
  128. package/templates/chat-app/lib/clone-messages.test.ts +6 -1
  129. package/templates/chat-app/lib/config-requirements.ts +19 -10
  130. package/templates/chat-app/lib/config-schema.ts +189 -103
  131. package/templates/chat-app/lib/config.ts +4 -4
  132. package/templates/chat-app/lib/credits/cost-accumulator.ts +11 -8
  133. package/templates/chat-app/lib/env-schema.ts +1 -1
  134. package/templates/chat-app/lib/features-config.ts +6 -6
  135. package/templates/chat-app/lib/stores/with-threads.ts +3 -3
  136. package/templates/chat-app/lib/thread-utils.ts +2 -2
  137. package/templates/chat-app/lib/types/anonymous.ts +4 -4
  138. package/templates/chat-app/lib/types/ui-chat.ts +7 -7
  139. package/templates/chat-app/lib/utils/download-assets.ts +3 -3
  140. package/templates/chat-app/lib/utils/rate-limit.ts +8 -8
  141. package/templates/chat-app/next.config.ts +0 -25
  142. package/templates/chat-app/package.json +16 -16
  143. package/templates/chat-app/playwright.config.ts +5 -5
  144. package/templates/chat-app/providers/chat-id-provider.tsx +5 -5
  145. package/templates/chat-app/providers/chat-input-provider.tsx +15 -15
  146. package/templates/chat-app/providers/chat-models-provider.tsx +3 -3
  147. package/templates/chat-app/providers/default-model-provider.tsx +5 -5
  148. package/templates/chat-app/providers/parse-chat-id-from-pathname.test.ts +16 -0
  149. package/templates/chat-app/providers/session-provider.tsx +2 -2
  150. package/templates/chat-app/scripts/check-env.ts +36 -4
  151. package/templates/chat-app/tests/artifacts.e2e.ts +7 -0
  152. package/templates/chat-app/tests/auth.setup.e2e.ts +10 -0
  153. package/templates/chat-app/tests/chat.e2e.ts +7 -0
  154. package/templates/chat-app/tests/reasoning.e2e.ts +7 -0
  155. package/templates/chat-app/tests/reasoning.setup.e2e.ts +10 -0
  156. package/templates/chat-app/trpc/routers/chat.router.ts +1 -1
  157. package/templates/chat-app/trpc/routers/mcp.router.ts +3 -3
  158. package/templates/chat-app/vitest.config.ts +7 -0
  159. package/templates/chat-app/next-env.d.ts +0 -6
  160. package/templates/chat-app/tsconfig.tsbuildinfo +0 -1
@@ -11,8 +11,8 @@
11
11
  "analyze": "next experimental-analyze",
12
12
  "start": "next start",
13
13
  "prod": "bun run build && bun run start",
14
- "lint": "bunx ultracite@6.3.3 check",
15
- "format": "bunx ultracite@6.3.3 fix",
14
+ "lint": "bunx ultracite@7.2.3 check",
15
+ "format": "bunx ultracite@7.2.3 fix",
16
16
  "check-env": "bun scripts/check-env.ts",
17
17
  "db:generate": "drizzle-kit generate",
18
18
  "db:migrate": "export VERCEL_ENV=production && bash scripts/with-db.sh bunx tsx lib/db/migrate.ts",
@@ -31,8 +31,8 @@
31
31
  "eval:dev": "evalite watch",
32
32
  "eval:serve": "evalite serve",
33
33
  "skiller:apply": "bunx skiller@latest apply",
34
- "test": "bun test:playwright && bun test:unit",
35
- "test:playwright": "export PLAYWRIGHT=True && bunx playwright test --workers=4",
34
+ "test": "bun test:e2e && bun test:unit",
35
+ "test:e2e": "export PLAYWRIGHT=True && bunx playwright test --workers=4",
36
36
  "test:unit": "vitest run",
37
37
  "test:types": "rm -rf .next/dev/types && next typegen . && tsc --noEmit",
38
38
  "ai:devtools": "bunx @ai-sdk/devtools",
@@ -40,15 +40,15 @@
40
40
  },
41
41
  "dependencies": {
42
42
  "@ai-sdk-tools/store": "1.2.0",
43
- "@ai-sdk/anthropic": "3.0.0",
44
- "@ai-sdk/devtools": "0.0.1",
45
- "@ai-sdk/gateway": "3.0.39",
46
- "@ai-sdk/google": "3.0.0",
47
- "@ai-sdk/mcp": "1.0.0",
48
- "@ai-sdk/openai": "3.0.0",
49
- "@ai-sdk/openai-compatible": "^2.0.28",
50
- "@ai-sdk/provider": "3.0.0",
51
- "@ai-sdk/react": "3.0.1",
43
+ "@ai-sdk/anthropic": "^3.0.46",
44
+ "@ai-sdk/devtools": "^0.0.15",
45
+ "@ai-sdk/gateway": "3.0.53",
46
+ "@ai-sdk/google": "^3.0.30",
47
+ "@ai-sdk/mcp": "^1.0.21",
48
+ "@ai-sdk/openai": "^3.0.30",
49
+ "@ai-sdk/openai-compatible": "^2.0.30",
50
+ "@ai-sdk/provider": "3.0.8",
51
+ "@ai-sdk/react": "^3.0.99",
52
52
  "@codemirror/lang-javascript": "^6.2.2",
53
53
  "@codemirror/lang-python": "^6.1.6",
54
54
  "@codemirror/state": "^6.5.0",
@@ -88,7 +88,7 @@
88
88
  "@radix-ui/react-toggle": "^1.1.10",
89
89
  "@radix-ui/react-tooltip": "^1.2.8",
90
90
  "@radix-ui/react-use-controllable-state": "^1.2.2",
91
- "@streamdown/code": "^1.0.2",
91
+ "@streamdown/code": "^1.0.3",
92
92
  "@streamdown/math": "^1.0.2",
93
93
  "@streamdown/mermaid": "^1.0.2",
94
94
  "@t3-oss/env-nextjs": "^0.13.8",
@@ -104,7 +104,7 @@
104
104
  "@vercel/otel": "^2.1.0",
105
105
  "@vercel/sandbox": "^1.0.2",
106
106
  "@vercel/speed-insights": "^1.3.1",
107
- "ai": "6.0.1",
107
+ "ai": "6.0.97",
108
108
  "better-auth": "^1.4.3",
109
109
  "browser-image-compression": "^2.0.2",
110
110
  "class-variance-authority": "^0.7.1",
@@ -179,7 +179,7 @@
179
179
  "tsx": "^4.19.1",
180
180
  "tw-animate-css": "^1.3.7",
181
181
  "typescript": "5.8.3",
182
- "ultracite": "6.3.3",
182
+ "ultracite": "7.2.3",
183
183
  "vite-tsconfig-paths": "^6.1.1",
184
184
  "vitest": "^4.0.0"
185
185
  }
@@ -53,11 +53,11 @@ export default defineConfig({
53
53
  projects: [
54
54
  {
55
55
  name: "setup:auth",
56
- testMatch: /auth.setup.ts/,
56
+ testMatch: /auth.setup.e2e.ts/,
57
57
  },
58
58
  {
59
59
  name: "setup:reasoning",
60
- testMatch: /reasoning.setup.ts/,
60
+ testMatch: /reasoning.setup.e2e.ts/,
61
61
  dependencies: ["setup:auth"],
62
62
  use: {
63
63
  ...devices["Desktop Chrome"],
@@ -66,7 +66,7 @@ export default defineConfig({
66
66
  },
67
67
  {
68
68
  name: "chat",
69
- testMatch: /chat.test.ts/,
69
+ testMatch: /chat.e2e.ts/,
70
70
  dependencies: ["setup:auth"],
71
71
  use: {
72
72
  ...devices["Desktop Chrome"],
@@ -75,7 +75,7 @@ export default defineConfig({
75
75
  },
76
76
  {
77
77
  name: "reasoning",
78
- testMatch: /reasoning.test.ts/,
78
+ testMatch: /reasoning.e2e.ts/,
79
79
  dependencies: ["setup:reasoning"],
80
80
  use: {
81
81
  ...devices["Desktop Chrome"],
@@ -84,7 +84,7 @@ export default defineConfig({
84
84
  },
85
85
  {
86
86
  name: "artifacts",
87
- testMatch: /artifacts.test.ts/,
87
+ testMatch: /artifacts.e2e.ts/,
88
88
  dependencies: ["setup:auth"],
89
89
  use: {
90
90
  ...devices["Desktop Chrome"],
@@ -16,14 +16,14 @@ import {
16
16
  parseChatIdFromPathname,
17
17
  } from "./parse-chat-id-from-pathname";
18
18
 
19
- type ChatIdContextType = {
19
+ interface ChatIdContextType {
20
+ confirmChatId: (chatId: string) => void;
20
21
  id: string;
21
- type: ChatIdType;
22
- source: ParsedChatIdFromPathname["source"];
23
22
  isPersisted: boolean;
24
- confirmChatId: (chatId: string) => void;
25
23
  refreshChatID: () => void;
26
- };
24
+ source: ParsedChatIdFromPathname["source"];
25
+ type: ChatIdType;
26
+ }
27
27
 
28
28
  const ChatIdContext = createContext<ChatIdContextType | undefined>(undefined);
29
29
 
@@ -17,35 +17,35 @@ import type { Attachment, UiToolName } from "@/lib/ai/types";
17
17
  import { useChatModels } from "./chat-models-provider";
18
18
  import { useDefaultModel, useModelChange } from "./default-model-provider";
19
19
 
20
- type ChatInputContextType = {
21
- editorRef: React.RefObject<LexicalChatInputRef | null>;
22
- selectedTool: UiToolName | null;
23
- setSelectedTool: Dispatch<SetStateAction<UiToolName | null>>;
20
+ interface ChatInputContextType {
24
21
  attachments: Attachment[];
25
- setAttachments: Dispatch<SetStateAction<Attachment[]>>;
26
- selectedModelId: AppModelId;
27
- handleModelChange: (modelId: AppModelId) => Promise<void>;
22
+ editorRef: React.RefObject<LexicalChatInputRef | null>;
23
+ getInitialInput: () => string;
28
24
  getInputValue: () => string;
29
25
  handleInputChange: (value: string) => void;
30
- getInitialInput: () => string;
31
- isEmpty: boolean;
26
+ handleModelChange: (modelId: AppModelId) => Promise<void>;
32
27
  handleSubmit: (submitFn: () => void, isEditMode?: boolean) => void;
28
+ isEmpty: boolean;
33
29
  isProjectContext: boolean;
34
- };
30
+ selectedModelId: AppModelId;
31
+ selectedTool: UiToolName | null;
32
+ setAttachments: Dispatch<SetStateAction<Attachment[]>>;
33
+ setSelectedTool: Dispatch<SetStateAction<UiToolName | null>>;
34
+ }
35
35
 
36
36
  const ChatInputContext = createContext<ChatInputContextType | undefined>(
37
37
  undefined
38
38
  );
39
39
 
40
- type ChatInputProviderProps = {
40
+ interface ChatInputProviderProps {
41
41
  children: ReactNode;
42
+ initialAttachments?: Attachment[];
42
43
  initialInput?: string;
43
44
  initialTool?: UiToolName | null;
44
- initialAttachments?: Attachment[];
45
- overrideModelId?: AppModelId; // For message editing where we want to use the original model
46
- localStorageEnabled?: boolean;
47
45
  isProjectContext?: boolean;
48
- };
46
+ localStorageEnabled?: boolean;
47
+ overrideModelId?: AppModelId; // For message editing where we want to use the original model
48
+ }
49
49
 
50
50
  export function ChatInputProvider({
51
51
  children,
@@ -16,11 +16,11 @@ import {
16
16
  import { useSession } from "@/providers/session-provider";
17
17
  import { useTRPC } from "@/trpc/react";
18
18
 
19
- type ChatModelsContextType = {
20
- models: AppModelDefinition[];
19
+ interface ChatModelsContextType {
21
20
  allModels: AppModelDefinition[];
22
21
  getModelById: (modelId: string) => AppModelDefinition | undefined;
23
- };
22
+ models: AppModelDefinition[];
23
+ }
24
24
 
25
25
  const ChatModelsContext = createContext<ChatModelsContextType | undefined>(
26
26
  undefined
@@ -11,19 +11,19 @@ import {
11
11
  import { toast } from "sonner";
12
12
  import type { AppModelId } from "@/lib/ai/app-models";
13
13
 
14
- type DefaultModelContextType = {
15
- defaultModel: AppModelId;
14
+ interface DefaultModelContextType {
16
15
  changeModel: (modelId: AppModelId) => Promise<void>;
17
- };
16
+ defaultModel: AppModelId;
17
+ }
18
18
 
19
19
  const DefaultModelContext = createContext<DefaultModelContextType | undefined>(
20
20
  undefined
21
21
  );
22
22
 
23
- type DefaultModelClientProviderProps = {
23
+ interface DefaultModelClientProviderProps {
24
24
  children: ReactNode;
25
25
  defaultModel: AppModelId;
26
- };
26
+ }
27
27
 
28
28
  export function DefaultModelProvider({
29
29
  children,
@@ -7,6 +7,8 @@ describe("parseChatIdFromPathname", () => {
7
7
  expect(parseChatIdFromPathname("/share/abc-123")).toEqual({
8
8
  type: "chat",
9
9
  id: "abc-123",
10
+ source: "share",
11
+ projectId: null,
10
12
  });
11
13
  });
12
14
 
@@ -14,6 +16,8 @@ describe("parseChatIdFromPathname", () => {
14
16
  expect(parseChatIdFromPathname("/share/abc-123-def-456")).toEqual({
15
17
  type: "chat",
16
18
  id: "abc-123-def-456",
19
+ source: "share",
20
+ projectId: null,
17
21
  });
18
22
  });
19
23
  });
@@ -23,6 +27,8 @@ describe("parseChatIdFromPathname", () => {
23
27
  expect(parseChatIdFromPathname("/project/proj-123")).toEqual({
24
28
  type: "provisional",
25
29
  id: null,
30
+ source: "project",
31
+ projectId: "proj-123",
26
32
  });
27
33
  });
28
34
 
@@ -32,6 +38,8 @@ describe("parseChatIdFromPathname", () => {
32
38
  ).toEqual({
33
39
  type: "chat",
34
40
  id: "chat-456",
41
+ source: "project",
42
+ projectId: "proj-123",
35
43
  });
36
44
  });
37
45
  });
@@ -41,6 +49,8 @@ describe("parseChatIdFromPathname", () => {
41
49
  expect(parseChatIdFromPathname("/chat/chat-789")).toEqual({
42
50
  type: "chat",
43
51
  id: "chat-789",
52
+ source: "chat",
53
+ projectId: null,
44
54
  });
45
55
  });
46
56
  });
@@ -50,6 +60,8 @@ describe("parseChatIdFromPathname", () => {
50
60
  expect(parseChatIdFromPathname("/")).toEqual({
51
61
  type: "provisional",
52
62
  id: null,
63
+ source: "home",
64
+ projectId: null,
53
65
  });
54
66
  });
55
67
 
@@ -57,6 +69,8 @@ describe("parseChatIdFromPathname", () => {
57
69
  expect(parseChatIdFromPathname(null)).toEqual({
58
70
  type: "provisional",
59
71
  id: null,
72
+ source: "home",
73
+ projectId: null,
60
74
  });
61
75
  });
62
76
 
@@ -64,6 +78,8 @@ describe("parseChatIdFromPathname", () => {
64
78
  expect(parseChatIdFromPathname("/settings")).toEqual({
65
79
  type: "provisional",
66
80
  id: null,
81
+ source: "home",
82
+ projectId: null,
67
83
  });
68
84
  });
69
85
  });
@@ -4,10 +4,10 @@ import { createContext, useContext, useMemo } from "react";
4
4
  import type { Session } from "@/lib/auth";
5
5
  import authClient from "@/lib/auth-client";
6
6
 
7
- type SessionContextValue = {
7
+ interface SessionContextValue {
8
8
  data: Session | null;
9
9
  isPending: boolean;
10
- };
10
+ }
11
11
 
12
12
  const SessionContext = createContext<SessionContextValue | undefined>(
13
13
  undefined
@@ -9,6 +9,7 @@ import type { GatewayType } from "../lib/ai/gateways/registry";
9
9
  import { generatedForGateway } from "../lib/ai/models.generated";
10
10
  import { config } from "../lib/config";
11
11
  import {
12
+ aiToolEnvRequirements,
12
13
  authEnvRequirements,
13
14
  featureEnvRequirements,
14
15
  gatewayEnvRequirements,
@@ -16,11 +17,14 @@ import {
16
17
  isRequirementSatisfied,
17
18
  } from "../lib/config-requirements";
18
19
 
19
- type ValidationError = { feature: string; missing: string[] };
20
+ interface ValidationError {
21
+ feature: string;
22
+ missing: string[];
23
+ }
20
24
 
21
25
  function validateGatewayKey(env: NodeJS.ProcessEnv): ValidationError | null {
22
26
  // Prevent TS from narrowing to the current literal config value.
23
- const gateway = (() => config.models.gateway as GatewayType)();
27
+ const gateway = (() => config.ai.gateway as GatewayType)();
24
28
  const requirement = gatewayEnvRequirements[gateway];
25
29
  const missing = getMissingRequirement(requirement, env);
26
30
  if (!missing) {
@@ -62,6 +66,33 @@ function validateFeatures(env: NodeJS.ProcessEnv): ValidationError[] {
62
66
  return errors;
63
67
  }
64
68
 
69
+ function validateAiTools(env: NodeJS.ProcessEnv): ValidationError[] {
70
+ const errors: ValidationError[] = [];
71
+
72
+ const toolEntries = Object.entries(aiToolEnvRequirements) as [
73
+ keyof typeof aiToolEnvRequirements,
74
+ NonNullable<
75
+ (typeof aiToolEnvRequirements)[keyof typeof aiToolEnvRequirements]
76
+ >,
77
+ ][];
78
+
79
+ for (const [tool, requirement] of toolEntries) {
80
+ const toolConfig = config.ai.tools[tool];
81
+ if (!(requirement && "enabled" in toolConfig && toolConfig.enabled)) {
82
+ continue;
83
+ }
84
+ const missing = getMissingRequirement(requirement, env);
85
+ if (missing) {
86
+ errors.push({
87
+ feature: `ai.tools.${tool}`,
88
+ missing: [missing],
89
+ });
90
+ }
91
+ }
92
+
93
+ return errors;
94
+ }
95
+
65
96
  function validateAuthentication(env: NodeJS.ProcessEnv): ValidationError[] {
66
97
  const errors: ValidationError[] = [];
67
98
 
@@ -119,10 +150,10 @@ function validateBaseUrl(env: NodeJS.ProcessEnv): ValidationError | null {
119
150
  }
120
151
 
121
152
  function checkGatewaySnapshot(): string | null {
122
- if (config.models.gateway === generatedForGateway) {
153
+ if (config.ai.gateway === generatedForGateway) {
123
154
  return null;
124
155
  }
125
- return `models.generated.ts was built for "${generatedForGateway}" but config uses "${config.models.gateway}". Run \`bun fetch:models\` to update the fallback snapshot.`;
156
+ return `models.generated.ts was built for "${generatedForGateway}" but config uses "${config.ai.gateway}". Run \`bun fetch:models\` to update the fallback snapshot.`;
126
157
  }
127
158
 
128
159
  function checkEnv(): void {
@@ -131,6 +162,7 @@ function checkEnv(): void {
131
162
  const errors = [
132
163
  ...(baseUrlError ? [baseUrlError] : []),
133
164
  ...validateFeatures(env),
165
+ ...validateAiTools(env),
134
166
  ...validateAuthentication(env),
135
167
  ];
136
168
 
@@ -0,0 +1,7 @@
1
+ import { expect, test } from "@playwright/test";
2
+
3
+ test("chat page loads for artifacts session", async ({ page }) => {
4
+ await page.goto("/");
5
+ await expect(page).toHaveURL("/");
6
+ await expect(page.getByRole("textbox")).toBeVisible();
7
+ });
@@ -0,0 +1,10 @@
1
+ import path from "node:path";
2
+ import { test as setup } from "@playwright/test";
3
+
4
+ const authFile = path.resolve("playwright/.auth/session.json");
5
+
6
+ setup("authenticate", async ({ page }) => {
7
+ await page.goto("/api/dev-login");
8
+ await page.waitForURL("/");
9
+ await page.context().storageState({ path: authFile });
10
+ });
@@ -0,0 +1,7 @@
1
+ import { expect, test } from "@playwright/test";
2
+
3
+ test("chat page loads", async ({ page }) => {
4
+ await page.goto("/");
5
+ await expect(page).toHaveURL("/");
6
+ await expect(page.getByRole("textbox")).toBeVisible();
7
+ });
@@ -0,0 +1,7 @@
1
+ import { expect, test } from "@playwright/test";
2
+
3
+ test("chat page loads for reasoning session", async ({ page }) => {
4
+ await page.goto("/");
5
+ await expect(page).toHaveURL("/");
6
+ await expect(page.getByRole("textbox")).toBeVisible();
7
+ });
@@ -0,0 +1,10 @@
1
+ import path from "node:path";
2
+ import { test as setup } from "@playwright/test";
3
+
4
+ const reasoningFile = path.resolve("playwright/.reasoning/session.json");
5
+
6
+ setup("authenticate for reasoning", async ({ page }) => {
7
+ await page.goto("/api/dev-login");
8
+ await page.waitForURL("/");
9
+ await page.context().storageState({ path: reasoningFile });
10
+ });
@@ -295,7 +295,7 @@ export const chatRouter = createTRPCRouter({
295
295
  )
296
296
  .mutation(async ({ input }) => {
297
297
  const { text: title } = await generateText({
298
- model: await getLanguageModel(config.models.defaults.title),
298
+ model: await getLanguageModel(config.ai.workflows.title),
299
299
  system: `\n
300
300
  - you will generate a short title based on the first message a user begins a conversation with
301
301
  - ensure it is not more than 80 characters long
@@ -26,7 +26,7 @@ import { createTRPCRouter, protectedProcedure } from "@/trpc/init";
26
26
  const log = createModuleLogger("mcp.router");
27
27
 
28
28
  function assertMcpEnabled() {
29
- if (!config.features.mcp) {
29
+ if (!config.ai.tools.mcp.enabled) {
30
30
  throw new TRPCError({
31
31
  code: "PRECONDITION_FAILED",
32
32
  message: "MCP integration disabled",
@@ -113,7 +113,7 @@ async function getConnectorWithPermission({
113
113
 
114
114
  export const mcpRouter = createTRPCRouter({
115
115
  list: protectedProcedure.query(async ({ ctx }) => {
116
- if (!config.features.mcp) {
116
+ if (!config.ai.tools.mcp.enabled) {
117
117
  return [];
118
118
  }
119
119
  return await getMcpConnectorsByUserId({ userId: ctx.user.id });
@@ -125,7 +125,7 @@ export const mcpRouter = createTRPCRouter({
125
125
  * Still includes enabled/disabled state so UI can show toggles.
126
126
  */
127
127
  listConnected: protectedProcedure.query(async ({ ctx }) => {
128
- if (!config.features.mcp) {
128
+ if (!config.ai.tools.mcp.enabled) {
129
129
  return [];
130
130
  }
131
131
  const connectors = await getMcpConnectorsByUserId({ userId: ctx.user.id });
@@ -0,0 +1,7 @@
1
+ import { defineConfig } from "vitest/config";
2
+
3
+ export default defineConfig({
4
+ test: {
5
+ exclude: ["**/node_modules/**", "**/*.e2e.ts"],
6
+ },
7
+ });
@@ -1,6 +0,0 @@
1
- /// <reference types="next" />
2
- /// <reference types="next/image-types/global" />
3
- import "./.next/types/routes.d.ts";
4
-
5
- // NOTE: This file should not be edited
6
- // see https://nextjs.org/docs/app/api-reference/config/typescript for more information.