@contractspec/module.ai-chat 4.1.4 → 4.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.
Files changed (30) hide show
  1. package/README.md +29 -3
  2. package/dist/browser/core/index.js +53 -17
  3. package/dist/browser/index.js +982 -426
  4. package/dist/browser/presentation/components/index.js +975 -419
  5. package/dist/browser/presentation/hooks/index.js +8 -1
  6. package/dist/browser/presentation/index.js +983 -427
  7. package/dist/core/create-chat-route.d.ts +14 -3
  8. package/dist/core/index.js +53 -17
  9. package/dist/core/message-types.d.ts +4 -0
  10. package/dist/index.js +982 -426
  11. package/dist/node/core/index.js +53 -17
  12. package/dist/node/index.js +982 -426
  13. package/dist/node/presentation/components/index.js +975 -419
  14. package/dist/node/presentation/hooks/index.js +8 -1
  15. package/dist/node/presentation/index.js +983 -427
  16. package/dist/presentation/components/ChainOfThought.d.ts +30 -0
  17. package/dist/presentation/components/ChatInput.d.ts +3 -4
  18. package/dist/presentation/components/ChatMessage.d.ts +6 -4
  19. package/dist/presentation/components/ChatWithExport.d.ts +14 -1
  20. package/dist/presentation/components/ChatWithSidebar.d.ts +12 -1
  21. package/dist/presentation/components/Reasoning.d.ts +24 -0
  22. package/dist/presentation/components/Sources.d.ts +22 -0
  23. package/dist/presentation/components/Suggestion.d.ts +12 -0
  24. package/dist/presentation/components/ToolResultRenderer.d.ts +20 -3
  25. package/dist/presentation/components/component-types.d.ts +52 -0
  26. package/dist/presentation/components/index.d.ts +6 -1
  27. package/dist/presentation/components/index.js +975 -419
  28. package/dist/presentation/hooks/index.js +8 -1
  29. package/dist/presentation/index.js +983 -427
  30. package/package.json +13 -13
@@ -6,16 +6,19 @@
6
6
  * @example
7
7
  * ```ts
8
8
  * // app/api/chat/route.ts (Next.js App Router)
9
- * import { createChatRoute } from '@contractspec/module.ai-chat/core';
9
+ * import { createChatRoute, CHAT_ROUTE_MAX_DURATION } from '@contractspec/module.ai-chat/core';
10
10
  * import { createProvider } from '@contractspec/lib.ai-providers';
11
11
  *
12
12
  * const provider = createProvider({ provider: 'openai', apiKey: process.env.OPENAI_API_KEY });
13
13
  * export const POST = createChatRoute({ provider });
14
+ * export const maxDuration = CHAT_ROUTE_MAX_DURATION;
14
15
  * ```
15
16
  */
16
- import { type ToolSet } from 'ai';
17
+ import { type LanguageModel, type ToolSet } from 'ai';
17
18
  import type { Provider as ChatProvider } from '@contractspec/lib.ai-providers';
18
19
  import type { ThinkingLevel } from './thinking-levels';
20
+ /** Recommended maxDuration for Next.js route handlers (Vercel/serverless). */
21
+ export declare const CHAT_ROUTE_MAX_DURATION = 30;
19
22
  export interface CreateChatRouteOptions {
20
23
  /** LLM provider (from createProvider) */
21
24
  provider: ChatProvider;
@@ -25,6 +28,14 @@ export interface CreateChatRouteOptions {
25
28
  tools?: ToolSet;
26
29
  /** Default thinking level (can be overridden by request body) */
27
30
  thinkingLevel?: ThinkingLevel;
31
+ /** Send source citations to client (e.g. Perplexity). Default: true when thinkingLevel is set. */
32
+ sendSources?: boolean;
33
+ /** Send reasoning parts to client (extended thinking). Default: true when thinkingLevel is set and not instant. */
34
+ sendReasoning?: boolean;
35
+ /** Resolve model from request body (for model picker). If not provided, uses provider.getModel(). */
36
+ getModel?: (body: {
37
+ model?: string;
38
+ }) => LanguageModel;
28
39
  }
29
40
  /**
30
41
  * Create a route handler that streams chat using streamText + toUIMessageStreamResponse.
@@ -32,7 +43,7 @@ export interface CreateChatRouteOptions {
32
43
  * Compatible with @ai-sdk/react useChat when used as the API endpoint.
33
44
  * Supports tool approval when tools have needsApproval.
34
45
  *
35
- * @param options - Provider, system prompt, and optional tools
46
+ * @param options - Provider, system prompt, optional tools, sendSources, sendReasoning
36
47
  * @returns A function (req: Request) => Promise<Response> suitable for Next.js route handlers
37
48
  */
38
49
  export declare function createChatRoute(options: CreateChatRouteOptions): (req: Request) => Promise<Response>;
@@ -1084,39 +1084,74 @@ import {
1084
1084
  convertToModelMessages,
1085
1085
  streamText as streamText2
1086
1086
  } from "ai";
1087
+ import { z as z4 } from "zod";
1088
+ var CHAT_ROUTE_MAX_DURATION = 30;
1089
+ var REQUEST_BODY_SCHEMA = z4.object({
1090
+ messages: z4.array(z4.unknown()).min(1, "messages array required"),
1091
+ thinkingLevel: z4.enum(["instant", "thinking", "extra_thinking", "max"]).optional(),
1092
+ model: z4.string().optional()
1093
+ });
1087
1094
  var DEFAULT_SYSTEM_PROMPT2 = `You are a helpful AI assistant.`;
1095
+ function defaultSendReasoning(thinkingLevel) {
1096
+ return Boolean(thinkingLevel && thinkingLevel !== "instant");
1097
+ }
1098
+ function defaultSendSources() {
1099
+ return true;
1100
+ }
1088
1101
  function createChatRoute(options) {
1089
1102
  const {
1090
1103
  provider,
1091
1104
  systemPrompt = DEFAULT_SYSTEM_PROMPT2,
1092
1105
  tools,
1093
- thinkingLevel: defaultThinkingLevel
1106
+ thinkingLevel: defaultThinkingLevel,
1107
+ sendSources = defaultSendSources(),
1108
+ sendReasoning = defaultSendReasoning(defaultThinkingLevel),
1109
+ getModel
1094
1110
  } = options;
1095
1111
  return async (req) => {
1096
1112
  if (req.method !== "POST") {
1097
1113
  return new Response("Method not allowed", { status: 405 });
1098
1114
  }
1099
- let body;
1115
+ let rawBody;
1100
1116
  try {
1101
- body = await req.json();
1117
+ rawBody = await req.json();
1102
1118
  } catch {
1103
- return new Response("Invalid JSON body", { status: 400 });
1119
+ return new Response(JSON.stringify({ error: "Invalid JSON body" }), {
1120
+ status: 400,
1121
+ headers: { "Content-Type": "application/json" }
1122
+ });
1104
1123
  }
1105
- const messages = body.messages ?? [];
1106
- if (!Array.isArray(messages) || messages.length === 0) {
1107
- return new Response("messages array required", { status: 400 });
1124
+ const parsed = REQUEST_BODY_SCHEMA.safeParse(rawBody);
1125
+ if (!parsed.success) {
1126
+ const message = parsed.error.issues[0]?.message ?? "Invalid request body";
1127
+ return new Response(JSON.stringify({ error: message }), {
1128
+ status: 400,
1129
+ headers: { "Content-Type": "application/json" }
1130
+ });
1108
1131
  }
1132
+ const body = parsed.data;
1109
1133
  const thinkingLevel = body.thinkingLevel ?? defaultThinkingLevel;
1110
1134
  const providerOptions = getProviderOptions(thinkingLevel, provider.name);
1111
- const model = provider.getModel();
1112
- const result = streamText2({
1113
- model,
1114
- messages: await convertToModelMessages(messages),
1115
- system: systemPrompt,
1116
- tools,
1117
- providerOptions: Object.keys(providerOptions).length > 0 ? providerOptions : undefined
1118
- });
1119
- return result.toUIMessageStreamResponse();
1135
+ const model = getModel ? getModel(body) : provider.getModel();
1136
+ try {
1137
+ const result = streamText2({
1138
+ model,
1139
+ messages: await convertToModelMessages(body.messages),
1140
+ system: systemPrompt,
1141
+ tools,
1142
+ providerOptions: Object.keys(providerOptions).length > 0 ? providerOptions : undefined
1143
+ });
1144
+ return result.toUIMessageStreamResponse({
1145
+ sendSources,
1146
+ sendReasoning
1147
+ });
1148
+ } catch (error) {
1149
+ const message = error instanceof Error ? error.message : "An error occurred";
1150
+ return new Response(JSON.stringify({ error: message }), {
1151
+ status: 500,
1152
+ headers: { "Content-Type": "application/json" }
1153
+ });
1154
+ }
1120
1155
  };
1121
1156
  }
1122
1157
  // src/core/create-completion-route.ts
@@ -1609,5 +1644,6 @@ export {
1609
1644
  THINKING_LEVEL_DESCRIPTIONS,
1610
1645
  LocalStorageConversationStore,
1611
1646
  InMemoryConversationStore,
1612
- ChatService
1647
+ ChatService,
1648
+ CHAT_ROUTE_MAX_DURATION
1613
1649
  };
@@ -42,6 +42,10 @@ export interface ChatToolCall {
42
42
  result?: unknown;
43
43
  status: 'pending' | 'running' | 'completed' | 'error';
44
44
  error?: string;
45
+ /** When true, result is streaming (preliminary) */
46
+ preliminary?: boolean;
47
+ /** Nested UIMessage parts (subagent output) */
48
+ nestedParts?: unknown[];
45
49
  }
46
50
  /**
47
51
  * Source/citation in a message