@peam-ai/server 0.1.4 → 0.1.5
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.
- package/dist/index.d.mts +105 -33
- package/dist/index.d.ts +105 -33
- package/dist/index.js +190 -79
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +189 -79
- package/dist/index.mjs.map +1 -1
- package/package.json +7 -6
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,33 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
1
|
+
import { SearchEngine, SearchIndexStore } from '@peam-ai/search';
|
|
2
|
+
import * as ai from 'ai';
|
|
3
|
+
import { LanguageModel, UIMessage, InferUIMessageChunk } from 'ai';
|
|
4
|
+
|
|
5
|
+
interface Summary {
|
|
6
|
+
text: string;
|
|
7
|
+
lastSummarizedMessageId: string;
|
|
8
|
+
}
|
|
9
|
+
interface SummarizationOptions {
|
|
10
|
+
/**
|
|
11
|
+
* The language model to use for summarization.
|
|
12
|
+
*/
|
|
13
|
+
model: LanguageModel;
|
|
14
|
+
/**
|
|
15
|
+
* The maximum number of messages to retain before summarization is triggered.
|
|
16
|
+
* @default 10
|
|
17
|
+
*/
|
|
18
|
+
maxMessages?: number;
|
|
19
|
+
}
|
|
20
|
+
interface SummarizerInput {
|
|
21
|
+
messages: UIMessage[];
|
|
22
|
+
previousSummary?: Summary;
|
|
23
|
+
}
|
|
24
|
+
interface SummaryUpdate {
|
|
25
|
+
text: string;
|
|
26
|
+
lastSummarizedMessageId: string;
|
|
27
|
+
}
|
|
28
|
+
interface ConversationSummarizer {
|
|
29
|
+
summarize(input: SummarizerInput): Promise<SummaryUpdate | null>;
|
|
30
|
+
}
|
|
3
31
|
|
|
4
32
|
/**
|
|
5
33
|
* Metadata about the current page the user is on.
|
|
@@ -18,55 +46,99 @@ interface CurrentPageMetadata {
|
|
|
18
46
|
*/
|
|
19
47
|
path: string;
|
|
20
48
|
}
|
|
49
|
+
|
|
50
|
+
interface ChatExecutionContext {
|
|
51
|
+
searchEngine: SearchEngine;
|
|
52
|
+
}
|
|
53
|
+
interface ChatStreamInput {
|
|
54
|
+
messages: UIMessage[];
|
|
55
|
+
summary?: Summary;
|
|
56
|
+
currentPage?: CurrentPageMetadata;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* ChatRuntime defines the interface for handling chat interactions,
|
|
60
|
+
* including streaming responses and handling HTTP requests.
|
|
61
|
+
*/
|
|
62
|
+
interface ChatRuntime {
|
|
63
|
+
/**
|
|
64
|
+
* Streams chat responses based on the provided input and context.
|
|
65
|
+
* @param input Chat stream input containing messages, summary, and current page metadata
|
|
66
|
+
* @param context ChatRuntime execution context
|
|
67
|
+
*/
|
|
68
|
+
stream(input: ChatStreamInput, context: ChatExecutionContext): ReadableStream<InferUIMessageChunk<UIMessage>>;
|
|
69
|
+
/**
|
|
70
|
+
* Handles an incoming HTTP request for the chat API.
|
|
71
|
+
* @param request Incoming HTTP request or an object containing the request
|
|
72
|
+
*/
|
|
73
|
+
handler(request: Request): Promise<Response>;
|
|
74
|
+
}
|
|
75
|
+
|
|
21
76
|
/**
|
|
22
|
-
* Options for creating
|
|
77
|
+
* Options for creating ChatRuntime.
|
|
23
78
|
*/
|
|
24
|
-
interface
|
|
79
|
+
interface ChatRuntimeOptions {
|
|
25
80
|
/**
|
|
26
81
|
* The language model to use for generating responses and summarization.
|
|
27
82
|
* Defaults to OpenAI GPT-4o if not provided.
|
|
28
83
|
*/
|
|
29
84
|
model?: LanguageModel;
|
|
30
85
|
/**
|
|
31
|
-
*
|
|
32
|
-
*
|
|
86
|
+
* Maximum allowed length for a single message.
|
|
87
|
+
* @default 30000
|
|
88
|
+
*/
|
|
89
|
+
maxMessageLength?: number;
|
|
90
|
+
/**
|
|
91
|
+
* Search index store to use for loading the search index.
|
|
33
92
|
*/
|
|
34
|
-
|
|
93
|
+
searchIndexStore?: SearchIndexStore;
|
|
94
|
+
/**
|
|
95
|
+
* SearchEngine to use for retrieving relevant documents.
|
|
96
|
+
*/
|
|
97
|
+
searchEngine?: SearchEngine;
|
|
98
|
+
/**
|
|
99
|
+
* Options for message summarization.
|
|
100
|
+
*/
|
|
101
|
+
summarization?: SummarizationOptions | false;
|
|
102
|
+
/**
|
|
103
|
+
* Custom summarizer implementation.
|
|
104
|
+
*/
|
|
105
|
+
summarizer?: ConversationSummarizer;
|
|
35
106
|
}
|
|
36
107
|
/**
|
|
37
108
|
* Request body structure for chat API.
|
|
38
109
|
*/
|
|
39
110
|
interface ChatRequestBody {
|
|
40
|
-
mode?: 'chat';
|
|
41
111
|
messages: UIMessage[];
|
|
42
|
-
summary?:
|
|
112
|
+
summary?: Summary;
|
|
113
|
+
}
|
|
114
|
+
declare class DefaultChatRuntime implements ChatRuntime {
|
|
115
|
+
private readonly model;
|
|
116
|
+
private readonly summarizer;
|
|
117
|
+
private readonly searchIndexStore;
|
|
118
|
+
private readonly maxMessageLength;
|
|
119
|
+
private readonly searchEngine?;
|
|
120
|
+
constructor(options?: ChatRuntimeOptions);
|
|
121
|
+
stream({ messages, summary, currentPage }: ChatStreamInput, { searchEngine }: ChatExecutionContext): ReadableStream<ai.InferUIMessageChunk<UIMessage<unknown, ai.UIDataTypes, ai.UITools>>>;
|
|
122
|
+
private resolveExecutionContext;
|
|
123
|
+
handler: (request: Request) => Promise<Response>;
|
|
124
|
+
}
|
|
125
|
+
declare function createChat(options?: ChatRuntimeOptions): DefaultChatRuntime;
|
|
126
|
+
|
|
127
|
+
declare class WindowedConversationSummarizer implements ConversationSummarizer {
|
|
128
|
+
private readonly options;
|
|
129
|
+
constructor(options: SummarizationOptions);
|
|
130
|
+
summarize({ messages, previousSummary }: SummarizerInput): Promise<SummaryUpdate | null>;
|
|
131
|
+
private shouldSummarize;
|
|
132
|
+
private getMessagesToSummarize;
|
|
43
133
|
}
|
|
44
134
|
|
|
45
135
|
/**
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
* @param options - Configuration options for the handler
|
|
50
|
-
* @param options.model - The language model to use (default: GPT-4o)
|
|
51
|
-
* @param options.searchIndexExporter - The search index exporter to use for loading the search index (required)
|
|
52
|
-
* @returns An async function that handles HTTP requests
|
|
53
|
-
*
|
|
54
|
-
* @example
|
|
55
|
-
* ```typescript
|
|
56
|
-
* import { createHandler } from 'peam/server';
|
|
57
|
-
* import { openai } from '@ai-sdk/openai';
|
|
58
|
-
* import { FileBasedSearchIndexExporter } from '@peam-ai/search';
|
|
59
|
-
*
|
|
60
|
-
* export const POST = createHandler({
|
|
61
|
-
* model: openai('gpt-4o'),
|
|
62
|
-
* searchIndexExporter: new FileBasedSearchIndexExporter({
|
|
63
|
-
* indexPath: 'generated/index.json'
|
|
64
|
-
* }),
|
|
65
|
-
* });
|
|
66
|
-
* ```
|
|
136
|
+
* Retrieves the SearchEngine instance, loading it from the provided store if necessary.
|
|
137
|
+
* @param store The SearchIndexStore to load the index from.
|
|
138
|
+
* @returns The SearchEngine instance or undefined if loading failed.
|
|
67
139
|
*/
|
|
68
|
-
declare function
|
|
140
|
+
declare function getSearchEngine(store: SearchIndexStore): Promise<SearchEngine | undefined>;
|
|
69
141
|
|
|
70
|
-
declare
|
|
142
|
+
declare const POST: (request: Request) => Promise<Response>;
|
|
71
143
|
|
|
72
|
-
export { type ChatRequestBody, type
|
|
144
|
+
export { type ChatExecutionContext, type ChatRequestBody, type ChatRuntime, type ChatRuntimeOptions, type ChatStreamInput, type ConversationSummarizer, DefaultChatRuntime, POST, type SummarizationOptions, type SummarizerInput, type Summary, type SummaryUpdate, WindowedConversationSummarizer, createChat, getSearchEngine };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,33 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
1
|
+
import { SearchEngine, SearchIndexStore } from '@peam-ai/search';
|
|
2
|
+
import * as ai from 'ai';
|
|
3
|
+
import { LanguageModel, UIMessage, InferUIMessageChunk } from 'ai';
|
|
4
|
+
|
|
5
|
+
interface Summary {
|
|
6
|
+
text: string;
|
|
7
|
+
lastSummarizedMessageId: string;
|
|
8
|
+
}
|
|
9
|
+
interface SummarizationOptions {
|
|
10
|
+
/**
|
|
11
|
+
* The language model to use for summarization.
|
|
12
|
+
*/
|
|
13
|
+
model: LanguageModel;
|
|
14
|
+
/**
|
|
15
|
+
* The maximum number of messages to retain before summarization is triggered.
|
|
16
|
+
* @default 10
|
|
17
|
+
*/
|
|
18
|
+
maxMessages?: number;
|
|
19
|
+
}
|
|
20
|
+
interface SummarizerInput {
|
|
21
|
+
messages: UIMessage[];
|
|
22
|
+
previousSummary?: Summary;
|
|
23
|
+
}
|
|
24
|
+
interface SummaryUpdate {
|
|
25
|
+
text: string;
|
|
26
|
+
lastSummarizedMessageId: string;
|
|
27
|
+
}
|
|
28
|
+
interface ConversationSummarizer {
|
|
29
|
+
summarize(input: SummarizerInput): Promise<SummaryUpdate | null>;
|
|
30
|
+
}
|
|
3
31
|
|
|
4
32
|
/**
|
|
5
33
|
* Metadata about the current page the user is on.
|
|
@@ -18,55 +46,99 @@ interface CurrentPageMetadata {
|
|
|
18
46
|
*/
|
|
19
47
|
path: string;
|
|
20
48
|
}
|
|
49
|
+
|
|
50
|
+
interface ChatExecutionContext {
|
|
51
|
+
searchEngine: SearchEngine;
|
|
52
|
+
}
|
|
53
|
+
interface ChatStreamInput {
|
|
54
|
+
messages: UIMessage[];
|
|
55
|
+
summary?: Summary;
|
|
56
|
+
currentPage?: CurrentPageMetadata;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* ChatRuntime defines the interface for handling chat interactions,
|
|
60
|
+
* including streaming responses and handling HTTP requests.
|
|
61
|
+
*/
|
|
62
|
+
interface ChatRuntime {
|
|
63
|
+
/**
|
|
64
|
+
* Streams chat responses based on the provided input and context.
|
|
65
|
+
* @param input Chat stream input containing messages, summary, and current page metadata
|
|
66
|
+
* @param context ChatRuntime execution context
|
|
67
|
+
*/
|
|
68
|
+
stream(input: ChatStreamInput, context: ChatExecutionContext): ReadableStream<InferUIMessageChunk<UIMessage>>;
|
|
69
|
+
/**
|
|
70
|
+
* Handles an incoming HTTP request for the chat API.
|
|
71
|
+
* @param request Incoming HTTP request or an object containing the request
|
|
72
|
+
*/
|
|
73
|
+
handler(request: Request): Promise<Response>;
|
|
74
|
+
}
|
|
75
|
+
|
|
21
76
|
/**
|
|
22
|
-
* Options for creating
|
|
77
|
+
* Options for creating ChatRuntime.
|
|
23
78
|
*/
|
|
24
|
-
interface
|
|
79
|
+
interface ChatRuntimeOptions {
|
|
25
80
|
/**
|
|
26
81
|
* The language model to use for generating responses and summarization.
|
|
27
82
|
* Defaults to OpenAI GPT-4o if not provided.
|
|
28
83
|
*/
|
|
29
84
|
model?: LanguageModel;
|
|
30
85
|
/**
|
|
31
|
-
*
|
|
32
|
-
*
|
|
86
|
+
* Maximum allowed length for a single message.
|
|
87
|
+
* @default 30000
|
|
88
|
+
*/
|
|
89
|
+
maxMessageLength?: number;
|
|
90
|
+
/**
|
|
91
|
+
* Search index store to use for loading the search index.
|
|
33
92
|
*/
|
|
34
|
-
|
|
93
|
+
searchIndexStore?: SearchIndexStore;
|
|
94
|
+
/**
|
|
95
|
+
* SearchEngine to use for retrieving relevant documents.
|
|
96
|
+
*/
|
|
97
|
+
searchEngine?: SearchEngine;
|
|
98
|
+
/**
|
|
99
|
+
* Options for message summarization.
|
|
100
|
+
*/
|
|
101
|
+
summarization?: SummarizationOptions | false;
|
|
102
|
+
/**
|
|
103
|
+
* Custom summarizer implementation.
|
|
104
|
+
*/
|
|
105
|
+
summarizer?: ConversationSummarizer;
|
|
35
106
|
}
|
|
36
107
|
/**
|
|
37
108
|
* Request body structure for chat API.
|
|
38
109
|
*/
|
|
39
110
|
interface ChatRequestBody {
|
|
40
|
-
mode?: 'chat';
|
|
41
111
|
messages: UIMessage[];
|
|
42
|
-
summary?:
|
|
112
|
+
summary?: Summary;
|
|
113
|
+
}
|
|
114
|
+
declare class DefaultChatRuntime implements ChatRuntime {
|
|
115
|
+
private readonly model;
|
|
116
|
+
private readonly summarizer;
|
|
117
|
+
private readonly searchIndexStore;
|
|
118
|
+
private readonly maxMessageLength;
|
|
119
|
+
private readonly searchEngine?;
|
|
120
|
+
constructor(options?: ChatRuntimeOptions);
|
|
121
|
+
stream({ messages, summary, currentPage }: ChatStreamInput, { searchEngine }: ChatExecutionContext): ReadableStream<ai.InferUIMessageChunk<UIMessage<unknown, ai.UIDataTypes, ai.UITools>>>;
|
|
122
|
+
private resolveExecutionContext;
|
|
123
|
+
handler: (request: Request) => Promise<Response>;
|
|
124
|
+
}
|
|
125
|
+
declare function createChat(options?: ChatRuntimeOptions): DefaultChatRuntime;
|
|
126
|
+
|
|
127
|
+
declare class WindowedConversationSummarizer implements ConversationSummarizer {
|
|
128
|
+
private readonly options;
|
|
129
|
+
constructor(options: SummarizationOptions);
|
|
130
|
+
summarize({ messages, previousSummary }: SummarizerInput): Promise<SummaryUpdate | null>;
|
|
131
|
+
private shouldSummarize;
|
|
132
|
+
private getMessagesToSummarize;
|
|
43
133
|
}
|
|
44
134
|
|
|
45
135
|
/**
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
* @param options - Configuration options for the handler
|
|
50
|
-
* @param options.model - The language model to use (default: GPT-4o)
|
|
51
|
-
* @param options.searchIndexExporter - The search index exporter to use for loading the search index (required)
|
|
52
|
-
* @returns An async function that handles HTTP requests
|
|
53
|
-
*
|
|
54
|
-
* @example
|
|
55
|
-
* ```typescript
|
|
56
|
-
* import { createHandler } from 'peam/server';
|
|
57
|
-
* import { openai } from '@ai-sdk/openai';
|
|
58
|
-
* import { FileBasedSearchIndexExporter } from '@peam-ai/search';
|
|
59
|
-
*
|
|
60
|
-
* export const POST = createHandler({
|
|
61
|
-
* model: openai('gpt-4o'),
|
|
62
|
-
* searchIndexExporter: new FileBasedSearchIndexExporter({
|
|
63
|
-
* indexPath: 'generated/index.json'
|
|
64
|
-
* }),
|
|
65
|
-
* });
|
|
66
|
-
* ```
|
|
136
|
+
* Retrieves the SearchEngine instance, loading it from the provided store if necessary.
|
|
137
|
+
* @param store The SearchIndexStore to load the index from.
|
|
138
|
+
* @returns The SearchEngine instance or undefined if loading failed.
|
|
67
139
|
*/
|
|
68
|
-
declare function
|
|
140
|
+
declare function getSearchEngine(store: SearchIndexStore): Promise<SearchEngine | undefined>;
|
|
69
141
|
|
|
70
|
-
declare
|
|
142
|
+
declare const POST: (request: Request) => Promise<Response>;
|
|
71
143
|
|
|
72
|
-
export { type ChatRequestBody, type
|
|
144
|
+
export { type ChatExecutionContext, type ChatRequestBody, type ChatRuntime, type ChatRuntimeOptions, type ChatStreamInput, type ConversationSummarizer, DefaultChatRuntime, POST, type SummarizationOptions, type SummarizerInput, type Summary, type SummaryUpdate, WindowedConversationSummarizer, createChat, getSearchEngine };
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,21 @@
|
|
|
2
2
|
var __defProp = Object.defineProperty;
|
|
3
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
5
6
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
8
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
9
|
+
var __spreadValues = (a, b) => {
|
|
10
|
+
for (var prop in b || (b = {}))
|
|
11
|
+
if (__hasOwnProp.call(b, prop))
|
|
12
|
+
__defNormalProp(a, prop, b[prop]);
|
|
13
|
+
if (__getOwnPropSymbols)
|
|
14
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
15
|
+
if (__propIsEnum.call(b, prop))
|
|
16
|
+
__defNormalProp(a, prop, b[prop]);
|
|
17
|
+
}
|
|
18
|
+
return a;
|
|
19
|
+
};
|
|
6
20
|
var __export = (target, all) => {
|
|
7
21
|
for (var name in all)
|
|
8
22
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
@@ -40,23 +54,90 @@ var __async = (__this, __arguments, generator) => {
|
|
|
40
54
|
// src/index.ts
|
|
41
55
|
var index_exports = {};
|
|
42
56
|
__export(index_exports, {
|
|
43
|
-
|
|
57
|
+
DefaultChatRuntime: () => DefaultChatRuntime,
|
|
58
|
+
POST: () => POST,
|
|
59
|
+
WindowedConversationSummarizer: () => WindowedConversationSummarizer,
|
|
60
|
+
createChat: () => createChat,
|
|
44
61
|
getSearchEngine: () => getSearchEngine
|
|
45
62
|
});
|
|
46
63
|
module.exports = __toCommonJS(index_exports);
|
|
47
64
|
|
|
48
|
-
// src/
|
|
65
|
+
// src/chat/DefaultChatRuntime.ts
|
|
49
66
|
var import_openai = require("@ai-sdk/openai");
|
|
50
|
-
var
|
|
67
|
+
var import_ai2 = require("@peam-ai/ai");
|
|
51
68
|
var import_logger2 = require("@peam-ai/logger");
|
|
52
|
-
var
|
|
69
|
+
var import_search2 = require("@peam-ai/search");
|
|
70
|
+
var import_ai3 = require("ai");
|
|
71
|
+
|
|
72
|
+
// src/summarization/WindowedConversationSummarizer.ts
|
|
73
|
+
var import_ai = require("@peam-ai/ai");
|
|
74
|
+
var WindowedConversationSummarizer = class {
|
|
75
|
+
constructor(options) {
|
|
76
|
+
var _a;
|
|
77
|
+
this.options = {
|
|
78
|
+
model: options.model,
|
|
79
|
+
maxMessages: (_a = options.maxMessages) != null ? _a : 10
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
summarize(_0) {
|
|
83
|
+
return __async(this, arguments, function* ({ messages, previousSummary }) {
|
|
84
|
+
var _a;
|
|
85
|
+
if (!this.shouldSummarize(messages, previousSummary)) {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
const messagesToSummarize = this.getMessagesToSummarize(messages, previousSummary);
|
|
89
|
+
if (messagesToSummarize.length === 0) {
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
const updatedSummaryText = yield (0, import_ai.summarizeMessages)({
|
|
93
|
+
model: this.options.model,
|
|
94
|
+
messages: messagesToSummarize,
|
|
95
|
+
previousSummary: previousSummary == null ? void 0 : previousSummary.text
|
|
96
|
+
});
|
|
97
|
+
const lastMessageId = (_a = messagesToSummarize[messagesToSummarize.length - 1]) == null ? void 0 : _a.id;
|
|
98
|
+
if (!updatedSummaryText || !lastMessageId) {
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
return {
|
|
102
|
+
text: updatedSummaryText,
|
|
103
|
+
lastSummarizedMessageId: lastMessageId
|
|
104
|
+
};
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
shouldSummarize(messages, previousSummary) {
|
|
108
|
+
const lastSummarizedMessageId = previousSummary == null ? void 0 : previousSummary.lastSummarizedMessageId;
|
|
109
|
+
const maxMessages = this.options.maxMessages;
|
|
110
|
+
if (!lastSummarizedMessageId) {
|
|
111
|
+
return messages.length >= maxMessages;
|
|
112
|
+
}
|
|
113
|
+
const lastSummarizedIndex = messages.findIndex((message) => message.id === lastSummarizedMessageId);
|
|
114
|
+
if (lastSummarizedIndex === -1) {
|
|
115
|
+
return messages.length >= maxMessages;
|
|
116
|
+
}
|
|
117
|
+
const messagesSinceLastSummary = messages.length - lastSummarizedIndex - 1;
|
|
118
|
+
return messagesSinceLastSummary >= maxMessages;
|
|
119
|
+
}
|
|
120
|
+
getMessagesToSummarize(messages, previousSummary) {
|
|
121
|
+
const lastSummarizedMessageId = previousSummary == null ? void 0 : previousSummary.lastSummarizedMessageId;
|
|
122
|
+
const maxMessages = this.options.maxMessages;
|
|
123
|
+
if (!lastSummarizedMessageId) {
|
|
124
|
+
return messages.slice(-maxMessages);
|
|
125
|
+
}
|
|
126
|
+
const lastSummarizedIndex = messages.findIndex((message) => message.id === lastSummarizedMessageId);
|
|
127
|
+
if (lastSummarizedIndex === -1) {
|
|
128
|
+
return messages.slice(-maxMessages);
|
|
129
|
+
}
|
|
130
|
+
return messages.slice(lastSummarizedIndex + 1);
|
|
131
|
+
}
|
|
132
|
+
};
|
|
53
133
|
|
|
54
134
|
// src/utils/getCurrentPage.ts
|
|
55
135
|
var getCurrentPage = ({
|
|
56
136
|
request,
|
|
57
137
|
message
|
|
58
138
|
}) => {
|
|
59
|
-
|
|
139
|
+
var _a;
|
|
140
|
+
const messageMetadata = (_a = message.metadata) != null ? _a : {};
|
|
60
141
|
const messageCurrentPage = messageMetadata.currentPage;
|
|
61
142
|
if (messageCurrentPage && messageCurrentPage.path && messageCurrentPage.origin) {
|
|
62
143
|
return {
|
|
@@ -83,16 +164,16 @@ var import_logger = require("@peam-ai/logger");
|
|
|
83
164
|
var import_search = require("@peam-ai/search");
|
|
84
165
|
var log = import_logger.loggers.server;
|
|
85
166
|
var searchEngine = null;
|
|
86
|
-
function getSearchEngine(
|
|
167
|
+
function getSearchEngine(store) {
|
|
87
168
|
return __async(this, null, function* () {
|
|
88
169
|
if (searchEngine) return searchEngine;
|
|
89
170
|
try {
|
|
90
|
-
const indexData = yield
|
|
171
|
+
const indexData = yield store.import();
|
|
91
172
|
if (!indexData || !indexData.keys || indexData.keys.length === 0) {
|
|
92
173
|
log.debug("Search index not yet generated. Run build first to generate the index.");
|
|
93
174
|
return void 0;
|
|
94
175
|
}
|
|
95
|
-
searchEngine = new import_search.
|
|
176
|
+
searchEngine = new import_search.TextBasedSearchEngine();
|
|
96
177
|
yield searchEngine.import((key) => __async(null, null, function* () {
|
|
97
178
|
return indexData.data[key];
|
|
98
179
|
}), indexData.keys);
|
|
@@ -106,32 +187,30 @@ function getSearchEngine(exporter) {
|
|
|
106
187
|
});
|
|
107
188
|
}
|
|
108
189
|
|
|
109
|
-
// src/
|
|
110
|
-
var MAX_MESSAGE_LENGTH = 3e4;
|
|
190
|
+
// src/chat/DefaultChatRuntime.ts
|
|
111
191
|
var log2 = import_logger2.loggers.server;
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
if (!messages || messages.length === 0) {
|
|
119
|
-
return new Response(
|
|
120
|
-
JSON.stringify({
|
|
121
|
-
error: "No messages provided"
|
|
122
|
-
}),
|
|
123
|
-
{
|
|
124
|
-
status: 400,
|
|
125
|
-
headers: { "Content-Type": "application/json" }
|
|
126
|
-
}
|
|
127
|
-
);
|
|
128
|
-
}
|
|
129
|
-
for (const message of messages) {
|
|
130
|
-
const messageContent = message.parts.filter((part) => part.type === "text").map((part) => "text" in part ? part.text : "").join("");
|
|
131
|
-
if (messageContent.length > MAX_MESSAGE_LENGTH) {
|
|
192
|
+
var DefaultChatRuntime = class {
|
|
193
|
+
constructor(options = {}) {
|
|
194
|
+
this.handler = (request) => __async(this, null, function* () {
|
|
195
|
+
try {
|
|
196
|
+
const req = "request" in request && request.request instanceof Request ? request.request : request;
|
|
197
|
+
if (req.method !== "POST") {
|
|
132
198
|
return new Response(
|
|
133
199
|
JSON.stringify({
|
|
134
|
-
error:
|
|
200
|
+
error: "Method not allowed"
|
|
201
|
+
}),
|
|
202
|
+
{
|
|
203
|
+
status: 405,
|
|
204
|
+
headers: { "Content-Type": "application/json" }
|
|
205
|
+
}
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
const body = yield req.json();
|
|
209
|
+
const { messages } = body;
|
|
210
|
+
if (!messages || messages.length === 0) {
|
|
211
|
+
return new Response(
|
|
212
|
+
JSON.stringify({
|
|
213
|
+
error: "No messages provided"
|
|
135
214
|
}),
|
|
136
215
|
{
|
|
137
216
|
status: 400,
|
|
@@ -139,35 +218,31 @@ function createHandler(options = {}) {
|
|
|
139
218
|
}
|
|
140
219
|
);
|
|
141
220
|
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
const currentPage = getCurrentPage({ request: req, message: lastMessage });
|
|
155
|
-
if (!options.searchIndexExporter) {
|
|
156
|
-
return new Response(
|
|
157
|
-
JSON.stringify({
|
|
158
|
-
error: "Search index exporter not configured"
|
|
159
|
-
}),
|
|
160
|
-
{
|
|
161
|
-
status: 500,
|
|
162
|
-
headers: { "Content-Type": "application/json" }
|
|
221
|
+
for (const message of messages) {
|
|
222
|
+
const messageContent = message.parts.filter((part) => part.type === "text").map((part) => "text" in part ? part.text : "").join("");
|
|
223
|
+
if (messageContent.length > this.maxMessageLength) {
|
|
224
|
+
return new Response(
|
|
225
|
+
JSON.stringify({
|
|
226
|
+
error: `Message exceeds maximum length of ${this.maxMessageLength} characters`
|
|
227
|
+
}),
|
|
228
|
+
{
|
|
229
|
+
status: 400,
|
|
230
|
+
headers: { "Content-Type": "application/json" }
|
|
231
|
+
}
|
|
232
|
+
);
|
|
163
233
|
}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
234
|
+
}
|
|
235
|
+
const lastMessage = messages[messages.length - 1];
|
|
236
|
+
const currentPage = getCurrentPage({ request: req, message: lastMessage });
|
|
237
|
+
const summary = body.summary;
|
|
238
|
+
const executionContext = yield this.resolveExecutionContext();
|
|
239
|
+
const stream = this.stream({ messages, summary, currentPage }, executionContext);
|
|
240
|
+
return (0, import_ai3.createUIMessageStreamResponse)({ stream });
|
|
241
|
+
} catch (error) {
|
|
242
|
+
log2.error("Error in the chat route:", error);
|
|
168
243
|
return new Response(
|
|
169
244
|
JSON.stringify({
|
|
170
|
-
error: "
|
|
245
|
+
error: "Error while processing the chat request"
|
|
171
246
|
}),
|
|
172
247
|
{
|
|
173
248
|
status: 500,
|
|
@@ -175,32 +250,68 @@ function createHandler(options = {}) {
|
|
|
175
250
|
}
|
|
176
251
|
);
|
|
177
252
|
}
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
253
|
+
});
|
|
254
|
+
var _a, _b, _c;
|
|
255
|
+
this.model = options.model || (0, import_openai.openai)("gpt-4o");
|
|
256
|
+
this.maxMessageLength = (_a = options.maxMessageLength) != null ? _a : 3e4;
|
|
257
|
+
this.summarizer = options.summarization === false ? null : (_b = options.summarizer) != null ? _b : new WindowedConversationSummarizer(__spreadValues({
|
|
258
|
+
model: this.model
|
|
259
|
+
}, options.summarization));
|
|
260
|
+
this.searchIndexStore = (_c = options.searchIndexStore) != null ? _c : new import_search2.FileBasedSearchIndexStore({
|
|
261
|
+
indexPath: ".peam/index.json"
|
|
262
|
+
});
|
|
263
|
+
this.searchEngine = options.searchEngine;
|
|
264
|
+
}
|
|
265
|
+
stream({ messages, summary, currentPage }, { searchEngine: searchEngine2 }) {
|
|
266
|
+
const previousSummary = summary == null ? void 0 : summary.text;
|
|
267
|
+
return (0, import_ai3.createUIMessageStream)({
|
|
268
|
+
originalMessages: messages,
|
|
269
|
+
execute: (_0) => __async(this, [_0], function* ({ writer }) {
|
|
270
|
+
var _a;
|
|
271
|
+
const chatStream = (0, import_ai2.streamSearchText)({
|
|
272
|
+
model: this.model,
|
|
273
|
+
searchEngine: searchEngine2,
|
|
274
|
+
messages,
|
|
275
|
+
currentPage,
|
|
276
|
+
summary: previousSummary
|
|
277
|
+
});
|
|
278
|
+
writer.merge(chatStream);
|
|
279
|
+
const summaryUpdate = yield (_a = this.summarizer) == null ? void 0 : _a.summarize({
|
|
280
|
+
messages,
|
|
281
|
+
previousSummary: summary
|
|
282
|
+
});
|
|
283
|
+
if (summaryUpdate) {
|
|
284
|
+
writer.write({
|
|
285
|
+
type: "data-summary",
|
|
286
|
+
data: summaryUpdate
|
|
287
|
+
});
|
|
195
288
|
}
|
|
196
|
-
)
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
|
|
289
|
+
})
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
resolveExecutionContext() {
|
|
293
|
+
return __async(this, null, function* () {
|
|
294
|
+
var _a;
|
|
295
|
+
const searchEngine2 = (_a = this.searchEngine) != null ? _a : yield getSearchEngine(this.searchIndexStore);
|
|
296
|
+
if (!searchEngine2) {
|
|
297
|
+
throw new Error("Search engine not available");
|
|
298
|
+
}
|
|
299
|
+
return { searchEngine: searchEngine2 };
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
};
|
|
303
|
+
function createChat(options = {}) {
|
|
304
|
+
return new DefaultChatRuntime(options);
|
|
200
305
|
}
|
|
306
|
+
|
|
307
|
+
// src/index.ts
|
|
308
|
+
var POST = createChat().handler;
|
|
201
309
|
// Annotate the CommonJS export names for ESM import in node:
|
|
202
310
|
0 && (module.exports = {
|
|
203
|
-
|
|
311
|
+
DefaultChatRuntime,
|
|
312
|
+
POST,
|
|
313
|
+
WindowedConversationSummarizer,
|
|
314
|
+
createChat,
|
|
204
315
|
getSearchEngine
|
|
205
316
|
});
|
|
206
317
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/createHandler.ts","../src/utils/getCurrentPage.ts","../src/utils/getSearchEngine.ts"],"sourcesContent":["export { createHandler } from './createHandler';\nexport type { ChatRequestBody, CreateHandlerOptions, CurrentPageMetadata } from './types';\nexport { getSearchEngine } from './utils/getSearchEngine';\n","import { openai } from '@ai-sdk/openai';\nimport { streamSearchText, streamSummarize } from '@peam-ai/ai';\nimport { loggers } from '@peam-ai/logger';\nimport { createUIMessageStreamResponse } from 'ai';\nimport { type CreateHandlerOptions, type HandlerRequestBody } from './types';\nimport { getCurrentPage } from './utils/getCurrentPage';\nimport { getSearchEngine } from './utils/getSearchEngine';\n\nconst MAX_MESSAGE_LENGTH = 30000;\nconst log = loggers.server;\n\n/**\n * Creates a HTTP handler for the chat API.\n * This handler processes incoming chat messages and streams responses back to the client.\n *\n * @param options - Configuration options for the handler\n * @param options.model - The language model to use (default: GPT-4o)\n * @param options.searchIndexExporter - The search index exporter to use for loading the search index (required)\n * @returns An async function that handles HTTP requests\n *\n * @example\n * ```typescript\n * import { createHandler } from 'peam/server';\n * import { openai } from '@ai-sdk/openai';\n * import { FileBasedSearchIndexExporter } from '@peam-ai/search';\n *\n * export const POST = createHandler({\n * model: openai('gpt-4o'),\n * searchIndexExporter: new FileBasedSearchIndexExporter({\n * indexPath: 'generated/index.json'\n * }),\n * });\n * ```\n */\nexport function createHandler(options: CreateHandlerOptions = {}) {\n const model = options.model || openai('gpt-4o');\n\n const handler = async (req: Request): Promise<Response> => {\n try {\n const body = (await req.json()) as HandlerRequestBody;\n const { messages, mode } = body;\n\n if (!messages || messages.length === 0) {\n return new Response(\n JSON.stringify({\n error: 'No messages provided',\n }),\n {\n status: 400,\n headers: { 'Content-Type': 'application/json' },\n }\n );\n }\n\n // Validate message length\n for (const message of messages) {\n const messageContent = message.parts\n .filter((part) => part.type === 'text')\n .map((part) => ('text' in part ? part.text : ''))\n .join('');\n\n if (messageContent.length > MAX_MESSAGE_LENGTH) {\n return new Response(\n JSON.stringify({\n error: `Message exceeds maximum length of ${MAX_MESSAGE_LENGTH} characters`,\n }),\n {\n status: 400,\n headers: { 'Content-Type': 'application/json' },\n }\n );\n }\n }\n\n // Handle summarization\n if (mode === 'summarize') {\n const { previousSummary } = body;\n const stream = streamSummarize({\n model,\n messages,\n previousSummary,\n });\n\n return createUIMessageStreamResponse({ stream });\n }\n\n // Handle chat\n const { summary } = body;\n const lastMessage = messages[messages.length - 1];\n const currentPage = getCurrentPage({ request: req, message: lastMessage });\n\n if (!options.searchIndexExporter) {\n return new Response(\n JSON.stringify({\n error: 'Search index exporter not configured',\n }),\n {\n status: 500,\n headers: { 'Content-Type': 'application/json' },\n }\n );\n }\n\n const searchEngine = await getSearchEngine(options.searchIndexExporter);\n\n if (!searchEngine) {\n return new Response(\n JSON.stringify({\n error: 'Search engine not available',\n }),\n {\n status: 500,\n headers: { 'Content-Type': 'application/json' },\n }\n );\n }\n\n const stream = streamSearchText({\n model,\n searchEngine,\n messages,\n currentPage,\n summary,\n });\n\n return createUIMessageStreamResponse({ stream });\n } catch (error) {\n log.error('Error in the chat route:', error);\n\n return new Response(\n JSON.stringify({\n error: 'Error while processing the chat request',\n }),\n {\n status: 500,\n headers: { 'Content-Type': 'application/json' },\n }\n );\n }\n };\n\n return handler;\n}\n","import { UIMessage } from 'ai';\nimport { type CurrentPageMetadata } from '../types';\n\n/**\n * Extracts the current page metadata from the request and message.\n */\nexport const getCurrentPage = ({\n request,\n message,\n}: {\n request: Request;\n message: UIMessage;\n}): CurrentPageMetadata | undefined => {\n const messageMetadata = message.metadata as { currentPage?: { title: string; origin: string; path: string } };\n const messageCurrentPage = messageMetadata.currentPage;\n\n if (messageCurrentPage && messageCurrentPage.path && messageCurrentPage.origin) {\n return {\n title: messageCurrentPage.title,\n origin: messageCurrentPage.origin,\n path: messageCurrentPage.path,\n };\n }\n\n try {\n if (request.headers.has('referer')) {\n const refererUrl = new URL(request.headers.get('referer') || '');\n return {\n path: refererUrl.pathname,\n origin: refererUrl.origin,\n };\n }\n } catch {\n // Invalid referer URL\n }\n\n return undefined;\n};\n","import { loggers } from '@peam-ai/logger';\nimport { SearchEngine, type SearchIndexExporter } from '@peam-ai/search';\n\nconst log = loggers.server;\nlet searchEngine: SearchEngine | null = null;\n\nexport async function getSearchEngine(exporter: SearchIndexExporter): Promise<SearchEngine | undefined> {\n if (searchEngine) return searchEngine;\n\n try {\n const indexData = await exporter.import();\n\n if (!indexData || !indexData.keys || indexData.keys.length === 0) {\n log.debug('Search index not yet generated. Run build first to generate the index.');\n return undefined;\n }\n\n searchEngine = new SearchEngine();\n await searchEngine.import(async (key: string) => {\n return indexData.data[key];\n }, indexData.keys);\n\n const totalDocs = searchEngine.count();\n log.debug('Index loaded successfully with', totalDocs, 'documents');\n return searchEngine;\n } catch (error) {\n log.error('Failed to load search index:', error);\n }\n\n return undefined;\n}\n"],"mappings":"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","names":["import_logger","import_ai","log","stream","searchEngine"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/chat/DefaultChatRuntime.ts","../src/summarization/WindowedConversationSummarizer.ts","../src/utils/getCurrentPage.ts","../src/utils/getSearchEngine.ts"],"sourcesContent":["import { createChat } from './chat/DefaultChatRuntime';\n\nexport { type ChatExecutionContext, type ChatRuntime, type ChatStreamInput } from './chat/ChatRuntime';\nexport {\n createChat,\n DefaultChatRuntime,\n type ChatRequestBody,\n type ChatRuntimeOptions,\n} from './chat/DefaultChatRuntime';\nexport {\n type ConversationSummarizer,\n type SummarizationOptions,\n type SummarizerInput,\n type Summary,\n type SummaryUpdate,\n} from './summarization/ConversationSummarizer';\nexport { WindowedConversationSummarizer } from './summarization/WindowedConversationSummarizer';\nexport { getSearchEngine } from './utils/getSearchEngine';\n\nexport const POST = createChat().handler;\n","import { openai } from '@ai-sdk/openai';\nimport { streamSearchText } from '@peam-ai/ai';\nimport { loggers } from '@peam-ai/logger';\nimport { FileBasedSearchIndexStore, type SearchEngine, type SearchIndexStore } from '@peam-ai/search';\nimport { createUIMessageStream, createUIMessageStreamResponse, LanguageModel, UIMessage } from 'ai';\nimport {\n ConversationSummarizer,\n type SummarizationOptions,\n type Summary,\n} from '../summarization/ConversationSummarizer';\nimport { WindowedConversationSummarizer } from '../summarization/WindowedConversationSummarizer';\nimport { getCurrentPage } from '../utils/getCurrentPage';\nimport { getSearchEngine } from '../utils/getSearchEngine';\nimport type { ChatExecutionContext, ChatRuntime, ChatStreamInput } from './ChatRuntime';\n\nconst log = loggers.server;\n\n/**\n * Options for creating ChatRuntime.\n */\nexport interface ChatRuntimeOptions {\n /**\n * The language model to use for generating responses and summarization.\n * Defaults to OpenAI GPT-4o if not provided.\n */\n model?: LanguageModel;\n\n /**\n * Maximum allowed length for a single message.\n * @default 30000\n */\n maxMessageLength?: number;\n\n /**\n * Search index store to use for loading the search index.\n */\n searchIndexStore?: SearchIndexStore;\n\n /**\n * SearchEngine to use for retrieving relevant documents.\n */\n searchEngine?: SearchEngine;\n\n /**\n * Options for message summarization.\n */\n summarization?: SummarizationOptions | false;\n\n /**\n * Custom summarizer implementation.\n */\n summarizer?: ConversationSummarizer;\n}\n\n/**\n * Request body structure for chat API.\n */\nexport interface ChatRequestBody {\n messages: UIMessage[];\n summary?: Summary;\n}\n\nexport class DefaultChatRuntime implements ChatRuntime {\n private readonly model;\n private readonly summarizer;\n private readonly searchIndexStore;\n private readonly maxMessageLength;\n private readonly searchEngine?;\n\n constructor(options: ChatRuntimeOptions = {}) {\n this.model = options.model || openai('gpt-4o');\n this.maxMessageLength = options.maxMessageLength ?? 30000;\n this.summarizer =\n options.summarization === false\n ? null\n : (options.summarizer ??\n new WindowedConversationSummarizer({\n model: this.model,\n ...options.summarization,\n }));\n\n this.searchIndexStore =\n options.searchIndexStore ??\n new FileBasedSearchIndexStore({\n indexPath: '.peam/index.json',\n });\n\n this.searchEngine = options.searchEngine;\n }\n\n stream({ messages, summary, currentPage }: ChatStreamInput, { searchEngine }: ChatExecutionContext) {\n const previousSummary = summary?.text;\n\n return createUIMessageStream({\n originalMessages: messages,\n execute: async ({ writer }) => {\n const chatStream = streamSearchText({\n model: this.model,\n searchEngine,\n messages,\n currentPage,\n summary: previousSummary,\n });\n\n writer.merge(chatStream);\n\n const summaryUpdate = await this.summarizer?.summarize({\n messages,\n previousSummary: summary,\n });\n\n if (summaryUpdate) {\n writer.write({\n type: 'data-summary',\n data: summaryUpdate,\n });\n }\n },\n });\n }\n\n private async resolveExecutionContext() {\n const searchEngine = this.searchEngine ?? (await getSearchEngine(this.searchIndexStore));\n\n if (!searchEngine) {\n throw new Error('Search engine not available');\n }\n\n return { searchEngine };\n }\n\n handler = async (request: Request): Promise<Response> => {\n try {\n // Take care of nested request object (e.g. from Astro)\n const req = 'request' in request && request.request instanceof Request ? request.request : request;\n\n if (req.method !== 'POST') {\n return new Response(\n JSON.stringify({\n error: 'Method not allowed',\n }),\n {\n status: 405,\n headers: { 'Content-Type': 'application/json' },\n }\n );\n }\n\n const body = (await req.json()) as ChatRequestBody;\n const { messages } = body;\n\n if (!messages || messages.length === 0) {\n return new Response(\n JSON.stringify({\n error: 'No messages provided',\n }),\n {\n status: 400,\n headers: { 'Content-Type': 'application/json' },\n }\n );\n }\n\n // Validate message length\n for (const message of messages) {\n const messageContent = message.parts\n .filter((part) => part.type === 'text')\n .map((part) => ('text' in part ? part.text : ''))\n .join('');\n\n if (messageContent.length > this.maxMessageLength) {\n return new Response(\n JSON.stringify({\n error: `Message exceeds maximum length of ${this.maxMessageLength} characters`,\n }),\n {\n status: 400,\n headers: { 'Content-Type': 'application/json' },\n }\n );\n }\n }\n\n const lastMessage = messages[messages.length - 1];\n const currentPage = getCurrentPage({ request: req, message: lastMessage });\n const summary = body.summary;\n const executionContext = await this.resolveExecutionContext();\n\n const stream = this.stream({ messages, summary, currentPage }, executionContext);\n\n return createUIMessageStreamResponse({ stream });\n } catch (error) {\n log.error('Error in the chat route:', error);\n\n return new Response(\n JSON.stringify({\n error: 'Error while processing the chat request',\n }),\n {\n status: 500,\n headers: { 'Content-Type': 'application/json' },\n }\n );\n }\n };\n}\n\nexport function createChat(options: ChatRuntimeOptions = {}) {\n return new DefaultChatRuntime(options);\n}\n","import { summarizeMessages } from '@peam-ai/ai';\nimport type { UIMessage } from 'ai';\nimport type {\n ConversationSummarizer,\n SummarizationOptions,\n SummarizerInput,\n Summary,\n SummaryUpdate,\n} from './ConversationSummarizer';\n\nexport class WindowedConversationSummarizer implements ConversationSummarizer {\n private readonly options: Required<SummarizationOptions>;\n\n constructor(options: SummarizationOptions) {\n this.options = {\n model: options.model,\n maxMessages: options.maxMessages ?? 10,\n };\n }\n\n async summarize({ messages, previousSummary }: SummarizerInput): Promise<SummaryUpdate | null> {\n if (!this.shouldSummarize(messages, previousSummary)) {\n return null;\n }\n\n const messagesToSummarize = this.getMessagesToSummarize(messages, previousSummary);\n\n if (messagesToSummarize.length === 0) {\n return null;\n }\n\n const updatedSummaryText = await summarizeMessages({\n model: this.options.model,\n messages: messagesToSummarize,\n previousSummary: previousSummary?.text,\n });\n\n const lastMessageId = messagesToSummarize[messagesToSummarize.length - 1]?.id;\n\n if (!updatedSummaryText || !lastMessageId) {\n return null;\n }\n\n return {\n text: updatedSummaryText,\n lastSummarizedMessageId: lastMessageId,\n };\n }\n\n private shouldSummarize(messages: UIMessage[], previousSummary?: Summary): boolean {\n const lastSummarizedMessageId = previousSummary?.lastSummarizedMessageId;\n const maxMessages = this.options.maxMessages;\n\n if (!lastSummarizedMessageId) {\n return messages.length >= maxMessages;\n }\n\n const lastSummarizedIndex = messages.findIndex((message) => message.id === lastSummarizedMessageId);\n\n if (lastSummarizedIndex === -1) {\n return messages.length >= maxMessages;\n }\n\n const messagesSinceLastSummary = messages.length - lastSummarizedIndex - 1;\n return messagesSinceLastSummary >= maxMessages;\n }\n\n private getMessagesToSummarize(messages: UIMessage[], previousSummary?: Summary): UIMessage[] {\n const lastSummarizedMessageId = previousSummary?.lastSummarizedMessageId;\n const maxMessages = this.options.maxMessages;\n\n if (!lastSummarizedMessageId) {\n return messages.slice(-maxMessages);\n }\n\n const lastSummarizedIndex = messages.findIndex((message) => message.id === lastSummarizedMessageId);\n\n if (lastSummarizedIndex === -1) {\n return messages.slice(-maxMessages);\n }\n\n return messages.slice(lastSummarizedIndex + 1);\n }\n}\n","import { UIMessage } from 'ai';\n\n/**\n * Metadata about the current page the user is on.\n */\nexport interface CurrentPageMetadata {\n /**\n * The title of the page (optional).\n */\n title?: string;\n /**\n * The origin of the page.\n */\n origin: string;\n /**\n * The path of the page (e.g., \"/about\").\n */\n path: string;\n}\n\n/**\n * Extracts the current page metadata from the request and message.\n */\nexport const getCurrentPage = ({\n request,\n message,\n}: {\n request: Request;\n message: UIMessage;\n}): CurrentPageMetadata | undefined => {\n const messageMetadata = (message.metadata ?? {}) as {\n currentPage?: CurrentPageMetadata;\n };\n const messageCurrentPage = messageMetadata.currentPage;\n\n if (messageCurrentPage && messageCurrentPage.path && messageCurrentPage.origin) {\n return {\n title: messageCurrentPage.title,\n origin: messageCurrentPage.origin,\n path: messageCurrentPage.path,\n };\n }\n\n try {\n if (request.headers.has('referer')) {\n const refererUrl = new URL(request.headers.get('referer') || '');\n return {\n path: refererUrl.pathname,\n origin: refererUrl.origin,\n };\n }\n } catch {\n // Invalid referer URL\n }\n\n return undefined;\n};\n","import { loggers } from '@peam-ai/logger';\nimport { TextBasedSearchEngine, type SearchEngine, type SearchIndexStore } from '@peam-ai/search';\n\nconst log = loggers.server;\nlet searchEngine: SearchEngine | null = null;\n\n/**\n * Retrieves the SearchEngine instance, loading it from the provided store if necessary.\n * @param store The SearchIndexStore to load the index from.\n * @returns The SearchEngine instance or undefined if loading failed.\n */\nexport async function getSearchEngine(store: SearchIndexStore): Promise<SearchEngine | undefined> {\n if (searchEngine) return searchEngine;\n\n try {\n const indexData = await store.import();\n\n if (!indexData || !indexData.keys || indexData.keys.length === 0) {\n log.debug('Search index not yet generated. Run build first to generate the index.');\n return undefined;\n }\n\n searchEngine = new TextBasedSearchEngine();\n await searchEngine.import(async (key: string) => {\n return indexData.data[key];\n }, indexData.keys);\n\n const totalDocs = searchEngine.count();\n log.debug('Index loaded successfully with', totalDocs, 'documents');\n return searchEngine;\n } catch (error) {\n log.error('Failed to load search index:', error);\n }\n\n return undefined;\n}\n"],"mappings":"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","names":["import_ai","import_logger","import_search","log","searchEngine"]}
|
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,19 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
3
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
4
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
5
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
6
|
+
var __spreadValues = (a, b) => {
|
|
7
|
+
for (var prop in b || (b = {}))
|
|
8
|
+
if (__hasOwnProp.call(b, prop))
|
|
9
|
+
__defNormalProp(a, prop, b[prop]);
|
|
10
|
+
if (__getOwnPropSymbols)
|
|
11
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
12
|
+
if (__propIsEnum.call(b, prop))
|
|
13
|
+
__defNormalProp(a, prop, b[prop]);
|
|
14
|
+
}
|
|
15
|
+
return a;
|
|
16
|
+
};
|
|
1
17
|
var __async = (__this, __arguments, generator) => {
|
|
2
18
|
return new Promise((resolve, reject) => {
|
|
3
19
|
var fulfilled = (value) => {
|
|
@@ -19,18 +35,82 @@ var __async = (__this, __arguments, generator) => {
|
|
|
19
35
|
});
|
|
20
36
|
};
|
|
21
37
|
|
|
22
|
-
// src/
|
|
38
|
+
// src/chat/DefaultChatRuntime.ts
|
|
23
39
|
import { openai } from "@ai-sdk/openai";
|
|
24
|
-
import { streamSearchText
|
|
40
|
+
import { streamSearchText } from "@peam-ai/ai";
|
|
25
41
|
import { loggers as loggers2 } from "@peam-ai/logger";
|
|
26
|
-
import {
|
|
42
|
+
import { FileBasedSearchIndexStore } from "@peam-ai/search";
|
|
43
|
+
import { createUIMessageStream, createUIMessageStreamResponse } from "ai";
|
|
44
|
+
|
|
45
|
+
// src/summarization/WindowedConversationSummarizer.ts
|
|
46
|
+
import { summarizeMessages } from "@peam-ai/ai";
|
|
47
|
+
var WindowedConversationSummarizer = class {
|
|
48
|
+
constructor(options) {
|
|
49
|
+
var _a;
|
|
50
|
+
this.options = {
|
|
51
|
+
model: options.model,
|
|
52
|
+
maxMessages: (_a = options.maxMessages) != null ? _a : 10
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
summarize(_0) {
|
|
56
|
+
return __async(this, arguments, function* ({ messages, previousSummary }) {
|
|
57
|
+
var _a;
|
|
58
|
+
if (!this.shouldSummarize(messages, previousSummary)) {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
const messagesToSummarize = this.getMessagesToSummarize(messages, previousSummary);
|
|
62
|
+
if (messagesToSummarize.length === 0) {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
const updatedSummaryText = yield summarizeMessages({
|
|
66
|
+
model: this.options.model,
|
|
67
|
+
messages: messagesToSummarize,
|
|
68
|
+
previousSummary: previousSummary == null ? void 0 : previousSummary.text
|
|
69
|
+
});
|
|
70
|
+
const lastMessageId = (_a = messagesToSummarize[messagesToSummarize.length - 1]) == null ? void 0 : _a.id;
|
|
71
|
+
if (!updatedSummaryText || !lastMessageId) {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
return {
|
|
75
|
+
text: updatedSummaryText,
|
|
76
|
+
lastSummarizedMessageId: lastMessageId
|
|
77
|
+
};
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
shouldSummarize(messages, previousSummary) {
|
|
81
|
+
const lastSummarizedMessageId = previousSummary == null ? void 0 : previousSummary.lastSummarizedMessageId;
|
|
82
|
+
const maxMessages = this.options.maxMessages;
|
|
83
|
+
if (!lastSummarizedMessageId) {
|
|
84
|
+
return messages.length >= maxMessages;
|
|
85
|
+
}
|
|
86
|
+
const lastSummarizedIndex = messages.findIndex((message) => message.id === lastSummarizedMessageId);
|
|
87
|
+
if (lastSummarizedIndex === -1) {
|
|
88
|
+
return messages.length >= maxMessages;
|
|
89
|
+
}
|
|
90
|
+
const messagesSinceLastSummary = messages.length - lastSummarizedIndex - 1;
|
|
91
|
+
return messagesSinceLastSummary >= maxMessages;
|
|
92
|
+
}
|
|
93
|
+
getMessagesToSummarize(messages, previousSummary) {
|
|
94
|
+
const lastSummarizedMessageId = previousSummary == null ? void 0 : previousSummary.lastSummarizedMessageId;
|
|
95
|
+
const maxMessages = this.options.maxMessages;
|
|
96
|
+
if (!lastSummarizedMessageId) {
|
|
97
|
+
return messages.slice(-maxMessages);
|
|
98
|
+
}
|
|
99
|
+
const lastSummarizedIndex = messages.findIndex((message) => message.id === lastSummarizedMessageId);
|
|
100
|
+
if (lastSummarizedIndex === -1) {
|
|
101
|
+
return messages.slice(-maxMessages);
|
|
102
|
+
}
|
|
103
|
+
return messages.slice(lastSummarizedIndex + 1);
|
|
104
|
+
}
|
|
105
|
+
};
|
|
27
106
|
|
|
28
107
|
// src/utils/getCurrentPage.ts
|
|
29
108
|
var getCurrentPage = ({
|
|
30
109
|
request,
|
|
31
110
|
message
|
|
32
111
|
}) => {
|
|
33
|
-
|
|
112
|
+
var _a;
|
|
113
|
+
const messageMetadata = (_a = message.metadata) != null ? _a : {};
|
|
34
114
|
const messageCurrentPage = messageMetadata.currentPage;
|
|
35
115
|
if (messageCurrentPage && messageCurrentPage.path && messageCurrentPage.origin) {
|
|
36
116
|
return {
|
|
@@ -54,19 +134,19 @@ var getCurrentPage = ({
|
|
|
54
134
|
|
|
55
135
|
// src/utils/getSearchEngine.ts
|
|
56
136
|
import { loggers } from "@peam-ai/logger";
|
|
57
|
-
import {
|
|
137
|
+
import { TextBasedSearchEngine } from "@peam-ai/search";
|
|
58
138
|
var log = loggers.server;
|
|
59
139
|
var searchEngine = null;
|
|
60
|
-
function getSearchEngine(
|
|
140
|
+
function getSearchEngine(store) {
|
|
61
141
|
return __async(this, null, function* () {
|
|
62
142
|
if (searchEngine) return searchEngine;
|
|
63
143
|
try {
|
|
64
|
-
const indexData = yield
|
|
144
|
+
const indexData = yield store.import();
|
|
65
145
|
if (!indexData || !indexData.keys || indexData.keys.length === 0) {
|
|
66
146
|
log.debug("Search index not yet generated. Run build first to generate the index.");
|
|
67
147
|
return void 0;
|
|
68
148
|
}
|
|
69
|
-
searchEngine = new
|
|
149
|
+
searchEngine = new TextBasedSearchEngine();
|
|
70
150
|
yield searchEngine.import((key) => __async(null, null, function* () {
|
|
71
151
|
return indexData.data[key];
|
|
72
152
|
}), indexData.keys);
|
|
@@ -80,32 +160,30 @@ function getSearchEngine(exporter) {
|
|
|
80
160
|
});
|
|
81
161
|
}
|
|
82
162
|
|
|
83
|
-
// src/
|
|
84
|
-
var MAX_MESSAGE_LENGTH = 3e4;
|
|
163
|
+
// src/chat/DefaultChatRuntime.ts
|
|
85
164
|
var log2 = loggers2.server;
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
if (messageContent.length > MAX_MESSAGE_LENGTH) {
|
|
165
|
+
var DefaultChatRuntime = class {
|
|
166
|
+
constructor(options = {}) {
|
|
167
|
+
this.handler = (request) => __async(this, null, function* () {
|
|
168
|
+
try {
|
|
169
|
+
const req = "request" in request && request.request instanceof Request ? request.request : request;
|
|
170
|
+
if (req.method !== "POST") {
|
|
171
|
+
return new Response(
|
|
172
|
+
JSON.stringify({
|
|
173
|
+
error: "Method not allowed"
|
|
174
|
+
}),
|
|
175
|
+
{
|
|
176
|
+
status: 405,
|
|
177
|
+
headers: { "Content-Type": "application/json" }
|
|
178
|
+
}
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
const body = yield req.json();
|
|
182
|
+
const { messages } = body;
|
|
183
|
+
if (!messages || messages.length === 0) {
|
|
106
184
|
return new Response(
|
|
107
185
|
JSON.stringify({
|
|
108
|
-
error:
|
|
186
|
+
error: "No messages provided"
|
|
109
187
|
}),
|
|
110
188
|
{
|
|
111
189
|
status: 400,
|
|
@@ -113,35 +191,31 @@ function createHandler(options = {}) {
|
|
|
113
191
|
}
|
|
114
192
|
);
|
|
115
193
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
const currentPage = getCurrentPage({ request: req, message: lastMessage });
|
|
129
|
-
if (!options.searchIndexExporter) {
|
|
130
|
-
return new Response(
|
|
131
|
-
JSON.stringify({
|
|
132
|
-
error: "Search index exporter not configured"
|
|
133
|
-
}),
|
|
134
|
-
{
|
|
135
|
-
status: 500,
|
|
136
|
-
headers: { "Content-Type": "application/json" }
|
|
194
|
+
for (const message of messages) {
|
|
195
|
+
const messageContent = message.parts.filter((part) => part.type === "text").map((part) => "text" in part ? part.text : "").join("");
|
|
196
|
+
if (messageContent.length > this.maxMessageLength) {
|
|
197
|
+
return new Response(
|
|
198
|
+
JSON.stringify({
|
|
199
|
+
error: `Message exceeds maximum length of ${this.maxMessageLength} characters`
|
|
200
|
+
}),
|
|
201
|
+
{
|
|
202
|
+
status: 400,
|
|
203
|
+
headers: { "Content-Type": "application/json" }
|
|
204
|
+
}
|
|
205
|
+
);
|
|
137
206
|
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
207
|
+
}
|
|
208
|
+
const lastMessage = messages[messages.length - 1];
|
|
209
|
+
const currentPage = getCurrentPage({ request: req, message: lastMessage });
|
|
210
|
+
const summary = body.summary;
|
|
211
|
+
const executionContext = yield this.resolveExecutionContext();
|
|
212
|
+
const stream = this.stream({ messages, summary, currentPage }, executionContext);
|
|
213
|
+
return createUIMessageStreamResponse({ stream });
|
|
214
|
+
} catch (error) {
|
|
215
|
+
log2.error("Error in the chat route:", error);
|
|
142
216
|
return new Response(
|
|
143
217
|
JSON.stringify({
|
|
144
|
-
error: "
|
|
218
|
+
error: "Error while processing the chat request"
|
|
145
219
|
}),
|
|
146
220
|
{
|
|
147
221
|
status: 500,
|
|
@@ -149,31 +223,67 @@ function createHandler(options = {}) {
|
|
|
149
223
|
}
|
|
150
224
|
);
|
|
151
225
|
}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
226
|
+
});
|
|
227
|
+
var _a, _b, _c;
|
|
228
|
+
this.model = options.model || openai("gpt-4o");
|
|
229
|
+
this.maxMessageLength = (_a = options.maxMessageLength) != null ? _a : 3e4;
|
|
230
|
+
this.summarizer = options.summarization === false ? null : (_b = options.summarizer) != null ? _b : new WindowedConversationSummarizer(__spreadValues({
|
|
231
|
+
model: this.model
|
|
232
|
+
}, options.summarization));
|
|
233
|
+
this.searchIndexStore = (_c = options.searchIndexStore) != null ? _c : new FileBasedSearchIndexStore({
|
|
234
|
+
indexPath: ".peam/index.json"
|
|
235
|
+
});
|
|
236
|
+
this.searchEngine = options.searchEngine;
|
|
237
|
+
}
|
|
238
|
+
stream({ messages, summary, currentPage }, { searchEngine: searchEngine2 }) {
|
|
239
|
+
const previousSummary = summary == null ? void 0 : summary.text;
|
|
240
|
+
return createUIMessageStream({
|
|
241
|
+
originalMessages: messages,
|
|
242
|
+
execute: (_0) => __async(this, [_0], function* ({ writer }) {
|
|
243
|
+
var _a;
|
|
244
|
+
const chatStream = streamSearchText({
|
|
245
|
+
model: this.model,
|
|
246
|
+
searchEngine: searchEngine2,
|
|
247
|
+
messages,
|
|
248
|
+
currentPage,
|
|
249
|
+
summary: previousSummary
|
|
250
|
+
});
|
|
251
|
+
writer.merge(chatStream);
|
|
252
|
+
const summaryUpdate = yield (_a = this.summarizer) == null ? void 0 : _a.summarize({
|
|
253
|
+
messages,
|
|
254
|
+
previousSummary: summary
|
|
255
|
+
});
|
|
256
|
+
if (summaryUpdate) {
|
|
257
|
+
writer.write({
|
|
258
|
+
type: "data-summary",
|
|
259
|
+
data: summaryUpdate
|
|
260
|
+
});
|
|
169
261
|
}
|
|
170
|
-
)
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
|
|
262
|
+
})
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
resolveExecutionContext() {
|
|
266
|
+
return __async(this, null, function* () {
|
|
267
|
+
var _a;
|
|
268
|
+
const searchEngine2 = (_a = this.searchEngine) != null ? _a : yield getSearchEngine(this.searchIndexStore);
|
|
269
|
+
if (!searchEngine2) {
|
|
270
|
+
throw new Error("Search engine not available");
|
|
271
|
+
}
|
|
272
|
+
return { searchEngine: searchEngine2 };
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
};
|
|
276
|
+
function createChat(options = {}) {
|
|
277
|
+
return new DefaultChatRuntime(options);
|
|
174
278
|
}
|
|
279
|
+
|
|
280
|
+
// src/index.ts
|
|
281
|
+
var POST = createChat().handler;
|
|
175
282
|
export {
|
|
176
|
-
|
|
283
|
+
DefaultChatRuntime,
|
|
284
|
+
POST,
|
|
285
|
+
WindowedConversationSummarizer,
|
|
286
|
+
createChat,
|
|
177
287
|
getSearchEngine
|
|
178
288
|
};
|
|
179
289
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/createHandler.ts","../src/utils/getCurrentPage.ts","../src/utils/getSearchEngine.ts"],"sourcesContent":["import { openai } from '@ai-sdk/openai';\nimport { streamSearchText, streamSummarize } from '@peam-ai/ai';\nimport { loggers } from '@peam-ai/logger';\nimport { createUIMessageStreamResponse } from 'ai';\nimport { type CreateHandlerOptions, type HandlerRequestBody } from './types';\nimport { getCurrentPage } from './utils/getCurrentPage';\nimport { getSearchEngine } from './utils/getSearchEngine';\n\nconst MAX_MESSAGE_LENGTH = 30000;\nconst log = loggers.server;\n\n/**\n * Creates a HTTP handler for the chat API.\n * This handler processes incoming chat messages and streams responses back to the client.\n *\n * @param options - Configuration options for the handler\n * @param options.model - The language model to use (default: GPT-4o)\n * @param options.searchIndexExporter - The search index exporter to use for loading the search index (required)\n * @returns An async function that handles HTTP requests\n *\n * @example\n * ```typescript\n * import { createHandler } from 'peam/server';\n * import { openai } from '@ai-sdk/openai';\n * import { FileBasedSearchIndexExporter } from '@peam-ai/search';\n *\n * export const POST = createHandler({\n * model: openai('gpt-4o'),\n * searchIndexExporter: new FileBasedSearchIndexExporter({\n * indexPath: 'generated/index.json'\n * }),\n * });\n * ```\n */\nexport function createHandler(options: CreateHandlerOptions = {}) {\n const model = options.model || openai('gpt-4o');\n\n const handler = async (req: Request): Promise<Response> => {\n try {\n const body = (await req.json()) as HandlerRequestBody;\n const { messages, mode } = body;\n\n if (!messages || messages.length === 0) {\n return new Response(\n JSON.stringify({\n error: 'No messages provided',\n }),\n {\n status: 400,\n headers: { 'Content-Type': 'application/json' },\n }\n );\n }\n\n // Validate message length\n for (const message of messages) {\n const messageContent = message.parts\n .filter((part) => part.type === 'text')\n .map((part) => ('text' in part ? part.text : ''))\n .join('');\n\n if (messageContent.length > MAX_MESSAGE_LENGTH) {\n return new Response(\n JSON.stringify({\n error: `Message exceeds maximum length of ${MAX_MESSAGE_LENGTH} characters`,\n }),\n {\n status: 400,\n headers: { 'Content-Type': 'application/json' },\n }\n );\n }\n }\n\n // Handle summarization\n if (mode === 'summarize') {\n const { previousSummary } = body;\n const stream = streamSummarize({\n model,\n messages,\n previousSummary,\n });\n\n return createUIMessageStreamResponse({ stream });\n }\n\n // Handle chat\n const { summary } = body;\n const lastMessage = messages[messages.length - 1];\n const currentPage = getCurrentPage({ request: req, message: lastMessage });\n\n if (!options.searchIndexExporter) {\n return new Response(\n JSON.stringify({\n error: 'Search index exporter not configured',\n }),\n {\n status: 500,\n headers: { 'Content-Type': 'application/json' },\n }\n );\n }\n\n const searchEngine = await getSearchEngine(options.searchIndexExporter);\n\n if (!searchEngine) {\n return new Response(\n JSON.stringify({\n error: 'Search engine not available',\n }),\n {\n status: 500,\n headers: { 'Content-Type': 'application/json' },\n }\n );\n }\n\n const stream = streamSearchText({\n model,\n searchEngine,\n messages,\n currentPage,\n summary,\n });\n\n return createUIMessageStreamResponse({ stream });\n } catch (error) {\n log.error('Error in the chat route:', error);\n\n return new Response(\n JSON.stringify({\n error: 'Error while processing the chat request',\n }),\n {\n status: 500,\n headers: { 'Content-Type': 'application/json' },\n }\n );\n }\n };\n\n return handler;\n}\n","import { UIMessage } from 'ai';\nimport { type CurrentPageMetadata } from '../types';\n\n/**\n * Extracts the current page metadata from the request and message.\n */\nexport const getCurrentPage = ({\n request,\n message,\n}: {\n request: Request;\n message: UIMessage;\n}): CurrentPageMetadata | undefined => {\n const messageMetadata = message.metadata as { currentPage?: { title: string; origin: string; path: string } };\n const messageCurrentPage = messageMetadata.currentPage;\n\n if (messageCurrentPage && messageCurrentPage.path && messageCurrentPage.origin) {\n return {\n title: messageCurrentPage.title,\n origin: messageCurrentPage.origin,\n path: messageCurrentPage.path,\n };\n }\n\n try {\n if (request.headers.has('referer')) {\n const refererUrl = new URL(request.headers.get('referer') || '');\n return {\n path: refererUrl.pathname,\n origin: refererUrl.origin,\n };\n }\n } catch {\n // Invalid referer URL\n }\n\n return undefined;\n};\n","import { loggers } from '@peam-ai/logger';\nimport { SearchEngine, type SearchIndexExporter } from '@peam-ai/search';\n\nconst log = loggers.server;\nlet searchEngine: SearchEngine | null = null;\n\nexport async function getSearchEngine(exporter: SearchIndexExporter): Promise<SearchEngine | undefined> {\n if (searchEngine) return searchEngine;\n\n try {\n const indexData = await exporter.import();\n\n if (!indexData || !indexData.keys || indexData.keys.length === 0) {\n log.debug('Search index not yet generated. Run build first to generate the index.');\n return undefined;\n }\n\n searchEngine = new SearchEngine();\n await searchEngine.import(async (key: string) => {\n return indexData.data[key];\n }, indexData.keys);\n\n const totalDocs = searchEngine.count();\n log.debug('Index loaded successfully with', totalDocs, 'documents');\n return searchEngine;\n } catch (error) {\n log.error('Failed to load search index:', error);\n }\n\n return undefined;\n}\n"],"mappings":"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","names":["loggers","log","loggers","stream","searchEngine"]}
|
|
1
|
+
{"version":3,"sources":["../src/chat/DefaultChatRuntime.ts","../src/summarization/WindowedConversationSummarizer.ts","../src/utils/getCurrentPage.ts","../src/utils/getSearchEngine.ts","../src/index.ts"],"sourcesContent":["import { openai } from '@ai-sdk/openai';\nimport { streamSearchText } from '@peam-ai/ai';\nimport { loggers } from '@peam-ai/logger';\nimport { FileBasedSearchIndexStore, type SearchEngine, type SearchIndexStore } from '@peam-ai/search';\nimport { createUIMessageStream, createUIMessageStreamResponse, LanguageModel, UIMessage } from 'ai';\nimport {\n ConversationSummarizer,\n type SummarizationOptions,\n type Summary,\n} from '../summarization/ConversationSummarizer';\nimport { WindowedConversationSummarizer } from '../summarization/WindowedConversationSummarizer';\nimport { getCurrentPage } from '../utils/getCurrentPage';\nimport { getSearchEngine } from '../utils/getSearchEngine';\nimport type { ChatExecutionContext, ChatRuntime, ChatStreamInput } from './ChatRuntime';\n\nconst log = loggers.server;\n\n/**\n * Options for creating ChatRuntime.\n */\nexport interface ChatRuntimeOptions {\n /**\n * The language model to use for generating responses and summarization.\n * Defaults to OpenAI GPT-4o if not provided.\n */\n model?: LanguageModel;\n\n /**\n * Maximum allowed length for a single message.\n * @default 30000\n */\n maxMessageLength?: number;\n\n /**\n * Search index store to use for loading the search index.\n */\n searchIndexStore?: SearchIndexStore;\n\n /**\n * SearchEngine to use for retrieving relevant documents.\n */\n searchEngine?: SearchEngine;\n\n /**\n * Options for message summarization.\n */\n summarization?: SummarizationOptions | false;\n\n /**\n * Custom summarizer implementation.\n */\n summarizer?: ConversationSummarizer;\n}\n\n/**\n * Request body structure for chat API.\n */\nexport interface ChatRequestBody {\n messages: UIMessage[];\n summary?: Summary;\n}\n\nexport class DefaultChatRuntime implements ChatRuntime {\n private readonly model;\n private readonly summarizer;\n private readonly searchIndexStore;\n private readonly maxMessageLength;\n private readonly searchEngine?;\n\n constructor(options: ChatRuntimeOptions = {}) {\n this.model = options.model || openai('gpt-4o');\n this.maxMessageLength = options.maxMessageLength ?? 30000;\n this.summarizer =\n options.summarization === false\n ? null\n : (options.summarizer ??\n new WindowedConversationSummarizer({\n model: this.model,\n ...options.summarization,\n }));\n\n this.searchIndexStore =\n options.searchIndexStore ??\n new FileBasedSearchIndexStore({\n indexPath: '.peam/index.json',\n });\n\n this.searchEngine = options.searchEngine;\n }\n\n stream({ messages, summary, currentPage }: ChatStreamInput, { searchEngine }: ChatExecutionContext) {\n const previousSummary = summary?.text;\n\n return createUIMessageStream({\n originalMessages: messages,\n execute: async ({ writer }) => {\n const chatStream = streamSearchText({\n model: this.model,\n searchEngine,\n messages,\n currentPage,\n summary: previousSummary,\n });\n\n writer.merge(chatStream);\n\n const summaryUpdate = await this.summarizer?.summarize({\n messages,\n previousSummary: summary,\n });\n\n if (summaryUpdate) {\n writer.write({\n type: 'data-summary',\n data: summaryUpdate,\n });\n }\n },\n });\n }\n\n private async resolveExecutionContext() {\n const searchEngine = this.searchEngine ?? (await getSearchEngine(this.searchIndexStore));\n\n if (!searchEngine) {\n throw new Error('Search engine not available');\n }\n\n return { searchEngine };\n }\n\n handler = async (request: Request): Promise<Response> => {\n try {\n // Take care of nested request object (e.g. from Astro)\n const req = 'request' in request && request.request instanceof Request ? request.request : request;\n\n if (req.method !== 'POST') {\n return new Response(\n JSON.stringify({\n error: 'Method not allowed',\n }),\n {\n status: 405,\n headers: { 'Content-Type': 'application/json' },\n }\n );\n }\n\n const body = (await req.json()) as ChatRequestBody;\n const { messages } = body;\n\n if (!messages || messages.length === 0) {\n return new Response(\n JSON.stringify({\n error: 'No messages provided',\n }),\n {\n status: 400,\n headers: { 'Content-Type': 'application/json' },\n }\n );\n }\n\n // Validate message length\n for (const message of messages) {\n const messageContent = message.parts\n .filter((part) => part.type === 'text')\n .map((part) => ('text' in part ? part.text : ''))\n .join('');\n\n if (messageContent.length > this.maxMessageLength) {\n return new Response(\n JSON.stringify({\n error: `Message exceeds maximum length of ${this.maxMessageLength} characters`,\n }),\n {\n status: 400,\n headers: { 'Content-Type': 'application/json' },\n }\n );\n }\n }\n\n const lastMessage = messages[messages.length - 1];\n const currentPage = getCurrentPage({ request: req, message: lastMessage });\n const summary = body.summary;\n const executionContext = await this.resolveExecutionContext();\n\n const stream = this.stream({ messages, summary, currentPage }, executionContext);\n\n return createUIMessageStreamResponse({ stream });\n } catch (error) {\n log.error('Error in the chat route:', error);\n\n return new Response(\n JSON.stringify({\n error: 'Error while processing the chat request',\n }),\n {\n status: 500,\n headers: { 'Content-Type': 'application/json' },\n }\n );\n }\n };\n}\n\nexport function createChat(options: ChatRuntimeOptions = {}) {\n return new DefaultChatRuntime(options);\n}\n","import { summarizeMessages } from '@peam-ai/ai';\nimport type { UIMessage } from 'ai';\nimport type {\n ConversationSummarizer,\n SummarizationOptions,\n SummarizerInput,\n Summary,\n SummaryUpdate,\n} from './ConversationSummarizer';\n\nexport class WindowedConversationSummarizer implements ConversationSummarizer {\n private readonly options: Required<SummarizationOptions>;\n\n constructor(options: SummarizationOptions) {\n this.options = {\n model: options.model,\n maxMessages: options.maxMessages ?? 10,\n };\n }\n\n async summarize({ messages, previousSummary }: SummarizerInput): Promise<SummaryUpdate | null> {\n if (!this.shouldSummarize(messages, previousSummary)) {\n return null;\n }\n\n const messagesToSummarize = this.getMessagesToSummarize(messages, previousSummary);\n\n if (messagesToSummarize.length === 0) {\n return null;\n }\n\n const updatedSummaryText = await summarizeMessages({\n model: this.options.model,\n messages: messagesToSummarize,\n previousSummary: previousSummary?.text,\n });\n\n const lastMessageId = messagesToSummarize[messagesToSummarize.length - 1]?.id;\n\n if (!updatedSummaryText || !lastMessageId) {\n return null;\n }\n\n return {\n text: updatedSummaryText,\n lastSummarizedMessageId: lastMessageId,\n };\n }\n\n private shouldSummarize(messages: UIMessage[], previousSummary?: Summary): boolean {\n const lastSummarizedMessageId = previousSummary?.lastSummarizedMessageId;\n const maxMessages = this.options.maxMessages;\n\n if (!lastSummarizedMessageId) {\n return messages.length >= maxMessages;\n }\n\n const lastSummarizedIndex = messages.findIndex((message) => message.id === lastSummarizedMessageId);\n\n if (lastSummarizedIndex === -1) {\n return messages.length >= maxMessages;\n }\n\n const messagesSinceLastSummary = messages.length - lastSummarizedIndex - 1;\n return messagesSinceLastSummary >= maxMessages;\n }\n\n private getMessagesToSummarize(messages: UIMessage[], previousSummary?: Summary): UIMessage[] {\n const lastSummarizedMessageId = previousSummary?.lastSummarizedMessageId;\n const maxMessages = this.options.maxMessages;\n\n if (!lastSummarizedMessageId) {\n return messages.slice(-maxMessages);\n }\n\n const lastSummarizedIndex = messages.findIndex((message) => message.id === lastSummarizedMessageId);\n\n if (lastSummarizedIndex === -1) {\n return messages.slice(-maxMessages);\n }\n\n return messages.slice(lastSummarizedIndex + 1);\n }\n}\n","import { UIMessage } from 'ai';\n\n/**\n * Metadata about the current page the user is on.\n */\nexport interface CurrentPageMetadata {\n /**\n * The title of the page (optional).\n */\n title?: string;\n /**\n * The origin of the page.\n */\n origin: string;\n /**\n * The path of the page (e.g., \"/about\").\n */\n path: string;\n}\n\n/**\n * Extracts the current page metadata from the request and message.\n */\nexport const getCurrentPage = ({\n request,\n message,\n}: {\n request: Request;\n message: UIMessage;\n}): CurrentPageMetadata | undefined => {\n const messageMetadata = (message.metadata ?? {}) as {\n currentPage?: CurrentPageMetadata;\n };\n const messageCurrentPage = messageMetadata.currentPage;\n\n if (messageCurrentPage && messageCurrentPage.path && messageCurrentPage.origin) {\n return {\n title: messageCurrentPage.title,\n origin: messageCurrentPage.origin,\n path: messageCurrentPage.path,\n };\n }\n\n try {\n if (request.headers.has('referer')) {\n const refererUrl = new URL(request.headers.get('referer') || '');\n return {\n path: refererUrl.pathname,\n origin: refererUrl.origin,\n };\n }\n } catch {\n // Invalid referer URL\n }\n\n return undefined;\n};\n","import { loggers } from '@peam-ai/logger';\nimport { TextBasedSearchEngine, type SearchEngine, type SearchIndexStore } from '@peam-ai/search';\n\nconst log = loggers.server;\nlet searchEngine: SearchEngine | null = null;\n\n/**\n * Retrieves the SearchEngine instance, loading it from the provided store if necessary.\n * @param store The SearchIndexStore to load the index from.\n * @returns The SearchEngine instance or undefined if loading failed.\n */\nexport async function getSearchEngine(store: SearchIndexStore): Promise<SearchEngine | undefined> {\n if (searchEngine) return searchEngine;\n\n try {\n const indexData = await store.import();\n\n if (!indexData || !indexData.keys || indexData.keys.length === 0) {\n log.debug('Search index not yet generated. Run build first to generate the index.');\n return undefined;\n }\n\n searchEngine = new TextBasedSearchEngine();\n await searchEngine.import(async (key: string) => {\n return indexData.data[key];\n }, indexData.keys);\n\n const totalDocs = searchEngine.count();\n log.debug('Index loaded successfully with', totalDocs, 'documents');\n return searchEngine;\n } catch (error) {\n log.error('Failed to load search index:', error);\n }\n\n return undefined;\n}\n","import { createChat } from './chat/DefaultChatRuntime';\n\nexport { type ChatExecutionContext, type ChatRuntime, type ChatStreamInput } from './chat/ChatRuntime';\nexport {\n createChat,\n DefaultChatRuntime,\n type ChatRequestBody,\n type ChatRuntimeOptions,\n} from './chat/DefaultChatRuntime';\nexport {\n type ConversationSummarizer,\n type SummarizationOptions,\n type SummarizerInput,\n type Summary,\n type SummaryUpdate,\n} from './summarization/ConversationSummarizer';\nexport { WindowedConversationSummarizer } from './summarization/WindowedConversationSummarizer';\nexport { getSearchEngine } from './utils/getSearchEngine';\n\nexport const POST = createChat().handler;\n"],"mappings":"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","names":["loggers","log","loggers","searchEngine"]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@peam-ai/server",
|
|
3
3
|
"description": "Server handler for Peam",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.5",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
@@ -30,9 +30,9 @@
|
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"@ai-sdk/openai": "^3.0.0",
|
|
32
32
|
"ai": "^6.0.1",
|
|
33
|
-
"@peam-ai/
|
|
34
|
-
"@peam-ai/
|
|
35
|
-
"@peam-ai/search": "0.1.
|
|
33
|
+
"@peam-ai/logger": "0.1.5",
|
|
34
|
+
"@peam-ai/ai": "0.1.5",
|
|
35
|
+
"@peam-ai/search": "0.1.5"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
38
|
"tsup": "^8.2.4",
|
|
@@ -40,10 +40,11 @@
|
|
|
40
40
|
},
|
|
41
41
|
"scripts": {
|
|
42
42
|
"build": "tsup",
|
|
43
|
+
"build:watch": "tsup --watch",
|
|
43
44
|
"clean": "rm -rf dist",
|
|
44
|
-
"
|
|
45
|
+
"format": "prettier --write \"src/**/*.ts*\"",
|
|
45
46
|
"test:lint": "eslint \"src/**/*.ts*\"",
|
|
46
|
-
"test:
|
|
47
|
+
"test:format": "prettier --check \"src/**/*.ts*\"",
|
|
47
48
|
"test:unit": "vitest run"
|
|
48
49
|
}
|
|
49
50
|
}
|