@n8n/ai-utilities 0.3.0 → 0.4.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.
- package/README.md +9 -462
- package/dist/{adapters → cjs/adapters}/langchain-chat-model.d.ts +1 -1
- package/dist/cjs/adapters/langchain-chat-model.js +201 -0
- package/dist/cjs/adapters/langchain-chat-model.js.map +1 -0
- package/dist/cjs/adapters/langchain-history.js +37 -0
- package/dist/cjs/adapters/langchain-history.js.map +1 -0
- package/dist/cjs/adapters/langchain-memory.js +46 -0
- package/dist/cjs/adapters/langchain-memory.js.map +1 -0
- package/dist/cjs/ai-node-sdk-version.d.ts +1 -0
- package/dist/cjs/ai-node-sdk-version.js +15 -0
- package/dist/cjs/ai-node-sdk-version.js.map +1 -0
- package/dist/cjs/chat-model/base.js +35 -0
- package/dist/cjs/chat-model/base.js.map +1 -0
- package/dist/{converters → cjs/converters}/message.d.ts +1 -0
- package/dist/cjs/converters/message.js +388 -0
- package/dist/cjs/converters/message.js.map +1 -0
- package/dist/cjs/converters/tool.js +69 -0
- package/dist/cjs/converters/tool.js.map +1 -0
- package/dist/cjs/guards.js +37 -0
- package/dist/cjs/guards.js.map +1 -0
- package/dist/{index.d.ts → cjs/index.d.ts} +7 -5
- package/dist/cjs/index.js +73 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/memory/base-chat-history.js +22 -0
- package/dist/cjs/memory/base-chat-history.js.map +1 -0
- package/dist/cjs/memory/base-chat-memory.js +17 -0
- package/dist/cjs/memory/base-chat-memory.js.map +1 -0
- package/dist/cjs/memory/windowed-chat-memory.js +48 -0
- package/dist/cjs/memory/windowed-chat-memory.js.map +1 -0
- package/dist/cjs/suppliers/supplyMemory.js +24 -0
- package/dist/cjs/suppliers/supplyMemory.js.map +1 -0
- package/dist/cjs/suppliers/supplyModel.d.ts +8 -0
- package/dist/cjs/suppliers/supplyModel.js +89 -0
- package/dist/cjs/suppliers/supplyModel.js.map +1 -0
- package/dist/cjs/typecheck.tsbuildinfo +1 -0
- package/dist/cjs/types/chat-model.js +13 -0
- package/dist/{types → cjs/types}/chat-model.js.map +1 -1
- package/dist/cjs/types/json.js +13 -0
- package/dist/{types → cjs/types}/json.js.map +1 -1
- package/dist/cjs/types/memory.js +13 -0
- package/dist/{types → cjs/types}/memory.js.map +1 -1
- package/dist/{types → cjs/types}/message.d.ts +8 -1
- package/dist/cjs/types/message.js +13 -0
- package/dist/{types → cjs/types}/message.js.map +1 -1
- package/dist/cjs/types/openai.js +13 -0
- package/dist/{types → cjs/types}/openai.js.map +1 -1
- package/dist/cjs/types/output.js +13 -0
- package/dist/{types → cjs/types}/output.js.map +1 -1
- package/dist/cjs/types/tool.js +13 -0
- package/dist/{types → cjs/types}/tool.js.map +1 -1
- package/dist/cjs/utils/embeddings-input-validation.js +38 -0
- package/dist/cjs/utils/embeddings-input-validation.js.map +1 -0
- package/dist/cjs/utils/failed-attempt-handler/n8nDefaultFailedAttemptHandler.js +40 -0
- package/dist/cjs/utils/failed-attempt-handler/n8nDefaultFailedAttemptHandler.js.map +1 -0
- package/dist/cjs/utils/failed-attempt-handler/n8nLlmFailedAttemptHandler.js +38 -0
- package/dist/cjs/utils/failed-attempt-handler/n8nLlmFailedAttemptHandler.js.map +1 -0
- package/dist/cjs/utils/helpers.js +63 -0
- package/dist/cjs/utils/helpers.js.map +1 -0
- package/dist/cjs/utils/http-proxy-agent.js +58 -0
- package/dist/cjs/utils/http-proxy-agent.js.map +1 -0
- package/dist/cjs/utils/log-ai-event.js +23 -0
- package/dist/cjs/utils/log-ai-event.js.map +1 -0
- package/dist/cjs/utils/log-wrapper.js +339 -0
- package/dist/cjs/utils/log-wrapper.js.map +1 -0
- package/dist/cjs/utils/n8n-binary-loader.js +169 -0
- package/dist/cjs/utils/n8n-binary-loader.js.map +1 -0
- package/dist/cjs/utils/n8n-json-loader.js +76 -0
- package/dist/cjs/utils/n8n-json-loader.js.map +1 -0
- package/dist/cjs/utils/n8n-llm-tracing.js +167 -0
- package/dist/cjs/utils/n8n-llm-tracing.js.map +1 -0
- package/dist/{utils → cjs/utils}/sse.d.ts +1 -1
- package/dist/cjs/utils/sse.js +107 -0
- package/dist/cjs/utils/sse.js.map +1 -0
- package/dist/cjs/utils/tokenizer/tiktoken.js +50 -0
- package/dist/cjs/utils/tokenizer/tiktoken.js.map +1 -0
- package/dist/cjs/utils/tokenizer/token-estimator.js +108 -0
- package/dist/cjs/utils/tokenizer/token-estimator.js.map +1 -0
- package/dist/esm/adapters/langchain-chat-model.d.ts +20 -0
- package/dist/{adapters → esm/adapters}/langchain-chat-model.js +4 -4
- package/dist/esm/adapters/langchain-chat-model.js.map +1 -0
- package/dist/esm/adapters/langchain-history.d.ts +12 -0
- package/dist/esm/adapters/langchain-history.js.map +1 -0
- package/dist/esm/adapters/langchain-memory.d.ts +11 -0
- package/dist/esm/adapters/langchain-memory.js.map +1 -0
- package/dist/esm/ai-node-sdk-version.d.ts +1 -0
- package/dist/esm/ai-node-sdk-version.js +5 -0
- package/dist/esm/ai-node-sdk-version.js.map +1 -0
- package/dist/esm/chat-model/base.d.ts +15 -0
- package/dist/esm/chat-model/base.js.map +1 -0
- package/dist/esm/converters/message.d.ts +7 -0
- package/dist/{converters → esm/converters}/message.js +24 -13
- package/dist/esm/converters/message.js.map +1 -0
- package/dist/esm/converters/tool.d.ts +5 -0
- package/dist/esm/converters/tool.js.map +1 -0
- package/dist/esm/guards.d.ts +8 -0
- package/dist/esm/guards.js.map +1 -0
- package/dist/esm/index.d.ts +30 -0
- package/dist/{index.js → esm/index.js} +13 -6
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/memory/base-chat-history.d.ts +8 -0
- package/dist/esm/memory/base-chat-history.js.map +1 -0
- package/dist/esm/memory/base-chat-memory.d.ts +8 -0
- package/dist/esm/memory/base-chat-memory.js.map +1 -0
- package/dist/esm/memory/windowed-chat-memory.d.ts +14 -0
- package/dist/esm/memory/windowed-chat-memory.js.map +1 -0
- package/dist/esm/suppliers/supplyMemory.d.ts +6 -0
- package/dist/esm/suppliers/supplyMemory.js.map +1 -0
- package/dist/esm/suppliers/supplyModel.d.ts +8 -0
- package/dist/{suppliers → esm/suppliers}/supplyModel.js +1 -1
- package/dist/esm/suppliers/supplyModel.js.map +1 -0
- package/dist/esm/typecheck.tsbuildinfo +1 -0
- package/dist/esm/types/chat-model.d.ts +26 -0
- package/dist/esm/types/chat-model.js.map +1 -0
- package/dist/esm/types/json.d.ts +5 -0
- package/dist/esm/types/json.js.map +1 -0
- package/dist/esm/types/memory.d.ts +13 -0
- package/dist/esm/types/memory.js.map +1 -0
- package/dist/esm/types/message.d.ts +56 -0
- package/dist/esm/types/message.js.map +1 -0
- package/dist/esm/types/openai.d.ts +39 -0
- package/dist/esm/types/openai.js.map +1 -0
- package/dist/esm/types/output.d.ts +47 -0
- package/dist/esm/types/output.js.map +1 -0
- package/dist/esm/types/tool.d.ts +28 -0
- package/dist/esm/types/tool.js.map +1 -0
- package/dist/esm/utils/embeddings-input-validation.d.ts +3 -0
- package/dist/esm/utils/embeddings-input-validation.js.map +1 -0
- package/dist/esm/utils/failed-attempt-handler/n8nDefaultFailedAttemptHandler.d.ts +1 -0
- package/dist/esm/utils/failed-attempt-handler/n8nDefaultFailedAttemptHandler.js.map +1 -0
- package/dist/esm/utils/failed-attempt-handler/n8nLlmFailedAttemptHandler.d.ts +3 -0
- package/dist/esm/utils/failed-attempt-handler/n8nLlmFailedAttemptHandler.js.map +1 -0
- package/dist/esm/utils/helpers.d.ts +3 -0
- package/dist/esm/utils/helpers.js.map +1 -0
- package/dist/esm/utils/http-proxy-agent.d.ts +10 -0
- package/dist/esm/utils/http-proxy-agent.js.map +1 -0
- package/dist/esm/utils/log-ai-event.d.ts +2 -0
- package/dist/esm/utils/log-ai-event.js.map +1 -0
- package/dist/esm/utils/log-wrapper.d.ts +28 -0
- package/dist/esm/utils/log-wrapper.js.map +1 -0
- package/dist/esm/utils/n8n-binary-loader.d.ts +18 -0
- package/dist/esm/utils/n8n-binary-loader.js.map +1 -0
- package/dist/esm/utils/n8n-json-loader.d.ts +11 -0
- package/dist/esm/utils/n8n-json-loader.js.map +1 -0
- package/dist/esm/utils/n8n-llm-tracing.d.ts +46 -0
- package/dist/esm/utils/n8n-llm-tracing.js.map +1 -0
- package/dist/esm/utils/sse.d.ts +8 -0
- package/dist/{utils → esm/utils}/sse.js +17 -27
- package/dist/esm/utils/sse.js.map +1 -0
- package/dist/esm/utils/tokenizer/cl100k_base.json +1 -0
- package/dist/esm/utils/tokenizer/o200k_base.json +1 -0
- package/dist/esm/utils/tokenizer/tiktoken.d.ts +4 -0
- package/dist/esm/utils/tokenizer/tiktoken.js.map +1 -0
- package/dist/esm/utils/tokenizer/token-estimator.d.ts +4 -0
- package/dist/esm/utils/tokenizer/token-estimator.js.map +1 -0
- package/package.json +19 -12
- package/dist/adapters/langchain-chat-model.js.map +0 -1
- package/dist/adapters/langchain-history.js.map +0 -1
- package/dist/adapters/langchain-memory.js.map +0 -1
- package/dist/build.tsbuildinfo +0 -1
- package/dist/chat-model/base.js.map +0 -1
- package/dist/converters/message.js.map +0 -1
- package/dist/converters/tool.js.map +0 -1
- package/dist/guards.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/memory/base-chat-history.js.map +0 -1
- package/dist/memory/base-chat-memory.js.map +0 -1
- package/dist/memory/windowed-chat-memory.js.map +0 -1
- package/dist/suppliers/supplyMemory.js.map +0 -1
- package/dist/suppliers/supplyModel.d.ts +0 -15
- package/dist/suppliers/supplyModel.js.map +0 -1
- package/dist/utils/embeddings-input-validation.js.map +0 -1
- package/dist/utils/failed-attempt-handler/n8nDefaultFailedAttemptHandler.js.map +0 -1
- package/dist/utils/failed-attempt-handler/n8nLlmFailedAttemptHandler.js.map +0 -1
- package/dist/utils/helpers.js.map +0 -1
- package/dist/utils/http-proxy-agent.js.map +0 -1
- package/dist/utils/log-ai-event.js.map +0 -1
- package/dist/utils/log-wrapper.js.map +0 -1
- package/dist/utils/n8n-binary-loader.js.map +0 -1
- package/dist/utils/n8n-json-loader.js.map +0 -1
- package/dist/utils/n8n-llm-tracing.js.map +0 -1
- package/dist/utils/sse.js.map +0 -1
- package/dist/utils/tokenizer/tiktoken.js.map +0 -1
- package/dist/utils/tokenizer/token-estimator.js.map +0 -1
- /package/dist/{adapters → cjs/adapters}/langchain-history.d.ts +0 -0
- /package/dist/{adapters → cjs/adapters}/langchain-memory.d.ts +0 -0
- /package/dist/{chat-model → cjs/chat-model}/base.d.ts +0 -0
- /package/dist/{converters → cjs/converters}/tool.d.ts +0 -0
- /package/dist/{guards.d.ts → cjs/guards.d.ts} +0 -0
- /package/dist/{memory → cjs/memory}/base-chat-history.d.ts +0 -0
- /package/dist/{memory → cjs/memory}/base-chat-memory.d.ts +0 -0
- /package/dist/{memory → cjs/memory}/windowed-chat-memory.d.ts +0 -0
- /package/dist/{suppliers → cjs/suppliers}/supplyMemory.d.ts +0 -0
- /package/dist/{types → cjs/types}/chat-model.d.ts +0 -0
- /package/dist/{types → cjs/types}/json.d.ts +0 -0
- /package/dist/{types → cjs/types}/memory.d.ts +0 -0
- /package/dist/{types → cjs/types}/openai.d.ts +0 -0
- /package/dist/{types → cjs/types}/output.d.ts +0 -0
- /package/dist/{types → cjs/types}/tool.d.ts +0 -0
- /package/dist/{utils → cjs/utils}/embeddings-input-validation.d.ts +0 -0
- /package/dist/{utils → cjs/utils}/failed-attempt-handler/n8nDefaultFailedAttemptHandler.d.ts +0 -0
- /package/dist/{utils → cjs/utils}/failed-attempt-handler/n8nLlmFailedAttemptHandler.d.ts +0 -0
- /package/dist/{utils → cjs/utils}/helpers.d.ts +0 -0
- /package/dist/{utils → cjs/utils}/http-proxy-agent.d.ts +0 -0
- /package/dist/{utils → cjs/utils}/log-ai-event.d.ts +0 -0
- /package/dist/{utils → cjs/utils}/log-wrapper.d.ts +0 -0
- /package/dist/{utils → cjs/utils}/n8n-binary-loader.d.ts +0 -0
- /package/dist/{utils → cjs/utils}/n8n-json-loader.d.ts +0 -0
- /package/dist/{utils → cjs/utils}/n8n-llm-tracing.d.ts +0 -0
- /package/dist/{utils → cjs/utils}/tokenizer/cl100k_base.json +0 -0
- /package/dist/{utils → cjs/utils}/tokenizer/o200k_base.json +0 -0
- /package/dist/{utils → cjs/utils}/tokenizer/tiktoken.d.ts +0 -0
- /package/dist/{utils → cjs/utils}/tokenizer/token-estimator.d.ts +0 -0
- /package/dist/{adapters → esm/adapters}/langchain-history.js +0 -0
- /package/dist/{adapters → esm/adapters}/langchain-memory.js +0 -0
- /package/dist/{chat-model → esm/chat-model}/base.js +0 -0
- /package/dist/{converters → esm/converters}/tool.js +0 -0
- /package/dist/{guards.js → esm/guards.js} +0 -0
- /package/dist/{memory → esm/memory}/base-chat-history.js +0 -0
- /package/dist/{memory → esm/memory}/base-chat-memory.js +0 -0
- /package/dist/{memory → esm/memory}/windowed-chat-memory.js +0 -0
- /package/dist/{suppliers → esm/suppliers}/supplyMemory.js +0 -0
- /package/dist/{types → esm/types}/chat-model.js +0 -0
- /package/dist/{types → esm/types}/json.js +0 -0
- /package/dist/{types → esm/types}/memory.js +0 -0
- /package/dist/{types → esm/types}/message.js +0 -0
- /package/dist/{types → esm/types}/openai.js +0 -0
- /package/dist/{types → esm/types}/output.js +0 -0
- /package/dist/{types → esm/types}/tool.js +0 -0
- /package/dist/{utils → esm/utils}/embeddings-input-validation.js +0 -0
- /package/dist/{utils → esm/utils}/failed-attempt-handler/n8nDefaultFailedAttemptHandler.js +0 -0
- /package/dist/{utils → esm/utils}/failed-attempt-handler/n8nLlmFailedAttemptHandler.js +0 -0
- /package/dist/{utils → esm/utils}/helpers.js +0 -0
- /package/dist/{utils → esm/utils}/http-proxy-agent.js +0 -0
- /package/dist/{utils → esm/utils}/log-ai-event.js +0 -0
- /package/dist/{utils → esm/utils}/log-wrapper.js +0 -0
- /package/dist/{utils → esm/utils}/n8n-binary-loader.js +0 -0
- /package/dist/{utils → esm/utils}/n8n-json-loader.js +0 -0
- /package/dist/{utils → esm/utils}/n8n-llm-tracing.js +0 -0
- /package/dist/{utils → esm/utils}/tokenizer/tiktoken.js +0 -0
- /package/dist/{utils → esm/utils}/tokenizer/token-estimator.js +0 -0
package/README.md
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
# @n8n/ai-utilities
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Core utilities and abstractions for AI functionality in n8n. This package provides the foundational building blocks used internally by the n8n platform.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
This package is reexported from @n8n/ai-node-sdk, that exposes methods and types for public usage.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
When changing logic in this package, make sure your changes are backwards compatible. What that means:
|
|
8
|
+
- don't remove existing interfaces or properties in them
|
|
9
|
+
- make new properties optional or create new versions of interfaces
|
|
10
|
+
- publicly exposed methods should handle both old and new interfaces
|
|
11
|
+
- when making a breaking change or adding a new public helper function that is exported in `@n8n/ai-node-sdk`, make sure to update `AI_NODE_SDK_VERSION` in `ai-node-sdk-version.ts`
|
|
8
12
|
|
|
9
13
|
## Development
|
|
10
14
|
|
|
@@ -19,464 +23,7 @@ pnpm test
|
|
|
19
23
|
pnpm dev
|
|
20
24
|
```
|
|
21
25
|
|
|
22
|
-
## Running examples
|
|
23
26
|
|
|
24
|
-
|
|
25
|
-
pnpm build:examples
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
Update your env file with:
|
|
29
|
-
|
|
30
|
-
```bash
|
|
31
|
-
N8N_CUSTOM_EXTENSIONS="<PATH_TO_N8N>/packages/@n8n/ai-utilities/dist_examples/examples/nodes"
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
Start n8n and add "OpenAI Simple" or "OpenAI Custom" to workflows
|
|
35
|
-
|
|
36
|
-
# Chat model SDK
|
|
37
|
-
|
|
38
|
-
## Core Pattern
|
|
39
|
-
|
|
40
|
-
### Option A: OpenAI-Compatible APIs (easiest)
|
|
41
|
-
|
|
42
|
-
Pass config directly to `supplyModel` for providers that follow the OpenAI API format:
|
|
43
|
-
|
|
44
|
-
```typescript
|
|
45
|
-
import { supplyModel } from '@n8n/ai-utilities';
|
|
46
|
-
|
|
47
|
-
return supplyModel(this, {
|
|
48
|
-
type: 'openai',
|
|
49
|
-
modelId: 'model-name',
|
|
50
|
-
apiKey: 'your-api-key',
|
|
51
|
-
baseURL: 'https://api.provider.com/v1', // OpenRouter, DeepSeek, etc.
|
|
52
|
-
});
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
### Option B: Custom API (full control)
|
|
56
|
-
|
|
57
|
-
Extend `BaseChatModel` and implement `generate()` + `stream()`:
|
|
58
|
-
|
|
59
|
-
```typescript
|
|
60
|
-
import { BaseChatModel, supplyModel, type Message, type GenerateResult, type StreamChunk } from '@n8n/ai-utilities';
|
|
61
|
-
|
|
62
|
-
class MyChatModel extends BaseChatModel {
|
|
63
|
-
async generate(messages: Message[]): Promise<GenerateResult> {
|
|
64
|
-
// Call your API, convert messages to provider format...
|
|
65
|
-
return { text: '...', toolCalls: [...] };
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
async *stream(messages: Message[]): AsyncIterable<StreamChunk> {
|
|
69
|
-
// Stream from your API...
|
|
70
|
-
yield { type: 'text-delta', textDelta: '...' };
|
|
71
|
-
yield { type: 'finish', finishReason: 'stop' };
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
const model = new MyChatModel('my-provider', 'model-id', { apiKey: '...' });
|
|
76
|
-
return supplyModel(this, model);
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
---
|
|
80
|
-
|
|
81
|
-
## Before/After Examples
|
|
82
|
-
|
|
83
|
-
### Example 1: LmChatOpenRouter
|
|
84
|
-
|
|
85
|
-
**Before (LangChain):**
|
|
86
|
-
|
|
87
|
-
```typescript
|
|
88
|
-
import { ChatOpenAI } from '@langchain/openai';
|
|
89
|
-
import { N8nLlmTracing } from '../N8nLlmTracing';
|
|
90
|
-
|
|
91
|
-
async supplyData(this: ISupplyDataFunctions, itemIndex: number): Promise<SupplyData> {
|
|
92
|
-
const credentials = await this.getCredentials<OpenAICompatibleCredential>('openRouterApi');
|
|
93
|
-
const modelName = this.getNodeParameter('model', itemIndex) as string;
|
|
94
|
-
const options = this.getNodeParameter('options', itemIndex, {}) as { ... };
|
|
95
|
-
|
|
96
|
-
const model = new ChatOpenAI({
|
|
97
|
-
apiKey: credentials.apiKey,
|
|
98
|
-
model: modelName,
|
|
99
|
-
...options,
|
|
100
|
-
configuration: { baseURL: credentials.url, ... },
|
|
101
|
-
callbacks: [new N8nLlmTracing(this)],
|
|
102
|
-
onFailedAttempt: makeN8nLlmFailedAttemptHandler(this, openAiFailedAttemptHandler),
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
return { response: model };
|
|
106
|
-
}
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
**After (SDK):**
|
|
110
|
-
|
|
111
|
-
```typescript
|
|
112
|
-
import { supplyModel } from '@n8n/ai-utilities';
|
|
113
|
-
|
|
114
|
-
async supplyData(this: ISupplyDataFunctions, itemIndex: number): Promise<SupplyData> {
|
|
115
|
-
const credentials = await this.getCredentials<{ url: string; apiKey: string }>('openRouterApi');
|
|
116
|
-
const modelName = this.getNodeParameter('model', itemIndex) as string;
|
|
117
|
-
const options = this.getNodeParameter('options', itemIndex, {}) as { temperature?: number };
|
|
118
|
-
|
|
119
|
-
return supplyModel(this, {
|
|
120
|
-
type: 'openai',
|
|
121
|
-
modelId: modelName,
|
|
122
|
-
apiKey: credentials.apiKey,
|
|
123
|
-
baseURL: credentials.url,
|
|
124
|
-
...options,
|
|
125
|
-
});
|
|
126
|
-
}
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
> **Note:** `type: 'openai'` uses the SDK's built-in OpenAI-compatible implementation.
|
|
130
|
-
> Works with OpenRouter, DeepSeek, Azure OpenAI, and any provider following the OpenAI API format.
|
|
131
|
-
|
|
132
|
-
---
|
|
133
|
-
|
|
134
|
-
## Community Node Examples
|
|
135
|
-
|
|
136
|
-
### ImaginaryLLM Chat Model
|
|
137
|
-
|
|
138
|
-
```typescript
|
|
139
|
-
import {
|
|
140
|
-
BaseChatModel,
|
|
141
|
-
supplyModel,
|
|
142
|
-
type Message,
|
|
143
|
-
type GenerateResult,
|
|
144
|
-
type StreamChunk,
|
|
145
|
-
type ChatModelConfig,
|
|
146
|
-
} from '@n8n/ai-utilities';
|
|
147
|
-
import { NodeConnectionTypes, type INodeType, type ISupplyDataFunctions, type SupplyData } from 'n8n-workflow';
|
|
148
|
-
|
|
149
|
-
// Custom chat model extending BaseChatModel
|
|
150
|
-
class ImaginaryLlmChatModel extends BaseChatModel {
|
|
151
|
-
constructor(
|
|
152
|
-
private apiKey: string,
|
|
153
|
-
modelId: string,
|
|
154
|
-
config?: ChatModelConfig,
|
|
155
|
-
) {
|
|
156
|
-
super('imaginary-llm', modelId, config);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
async generate(messages: Message[], config?: ChatModelConfig): Promise<GenerateResult> {
|
|
160
|
-
// Convert n8n messages to provider format
|
|
161
|
-
const providerMessages = messages.map(m => ({
|
|
162
|
-
speaker: m.role === 'user' ? 'user' : m.role === 'assistant' ? 'bot' : m.role,
|
|
163
|
-
text: m.content.find(c => c.type === 'text')?.text ?? '',
|
|
164
|
-
}));
|
|
165
|
-
|
|
166
|
-
// Call the API
|
|
167
|
-
const response = await fetch('https://api.imaginary-llm.example.com/v1/generate', {
|
|
168
|
-
method: 'POST',
|
|
169
|
-
headers: {
|
|
170
|
-
'Authorization': `Bearer ${this.apiKey}`,
|
|
171
|
-
'Content-Type': 'application/json',
|
|
172
|
-
},
|
|
173
|
-
body: JSON.stringify({
|
|
174
|
-
model: this.modelId,
|
|
175
|
-
conversation: providerMessages,
|
|
176
|
-
settings: {
|
|
177
|
-
creativity: config?.temperature ?? 0.7,
|
|
178
|
-
max_length: config?.maxTokens,
|
|
179
|
-
},
|
|
180
|
-
}),
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
const data = await response.json();
|
|
184
|
-
|
|
185
|
-
return {
|
|
186
|
-
text: data.reply.text,
|
|
187
|
-
toolCalls: data.reply.actions?.map((a: any) => ({
|
|
188
|
-
id: a.id,
|
|
189
|
-
name: a.name,
|
|
190
|
-
arguments: a.params,
|
|
191
|
-
})),
|
|
192
|
-
usage: data.metrics ? {
|
|
193
|
-
promptTokens: data.metrics.input_tokens,
|
|
194
|
-
completionTokens: data.metrics.output_tokens,
|
|
195
|
-
totalTokens: data.metrics.input_tokens + data.metrics.output_tokens,
|
|
196
|
-
} : undefined,
|
|
197
|
-
};
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
async *stream(messages: Message[], config?: ChatModelConfig): AsyncIterable<StreamChunk> {
|
|
201
|
-
// Streaming implementation...
|
|
202
|
-
yield { type: 'text-delta', textDelta: '...' };
|
|
203
|
-
yield { type: 'finish', finishReason: 'stop' };
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
// The n8n node
|
|
208
|
-
export class LmChatImaginaryLlm implements INodeType {
|
|
209
|
-
description = {
|
|
210
|
-
displayName: 'ImaginaryLLM Chat Model',
|
|
211
|
-
name: 'lmChatImaginaryLlm',
|
|
212
|
-
outputs: [NodeConnectionTypes.AiLanguageModel],
|
|
213
|
-
credentials: [{ name: 'imaginaryLlmApi', required: true }],
|
|
214
|
-
properties: [
|
|
215
|
-
{ displayName: 'Model', name: 'model', type: 'options', options: [
|
|
216
|
-
{ name: 'Imaginary Pro', value: 'imaginary-pro' },
|
|
217
|
-
{ name: 'Imaginary Fast', value: 'imaginary-fast' },
|
|
218
|
-
], default: 'imaginary-pro' },
|
|
219
|
-
{ displayName: 'Temperature', name: 'temperature', type: 'number', default: 0.7 },
|
|
220
|
-
],
|
|
221
|
-
};
|
|
222
|
-
|
|
223
|
-
async supplyData(this: ISupplyDataFunctions, itemIndex: number): Promise<SupplyData> {
|
|
224
|
-
const credentials = await this.getCredentials<{ apiKey: string }>('imaginaryLlmApi');
|
|
225
|
-
const modelName = this.getNodeParameter('model', itemIndex) as string;
|
|
226
|
-
const temperature = this.getNodeParameter('temperature', itemIndex) as number;
|
|
227
|
-
|
|
228
|
-
const model = new ImaginaryLlmChatModel(credentials.apiKey, modelName, { temperature });
|
|
229
|
-
|
|
230
|
-
return supplyModel(this, model);
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
```
|
|
234
|
-
|
|
235
|
-
---
|
|
236
|
-
|
|
237
|
-
# Memory SDK
|
|
238
|
-
|
|
239
|
-
The Memory SDK provides abstractions for building conversation memory nodes without LangChain dependencies.
|
|
240
|
-
|
|
241
|
-
## Architecture
|
|
242
|
-
|
|
243
|
-
Memory uses a **two-layer design**:
|
|
244
|
-
|
|
245
|
-
1. **ChatHistory** (Storage Layer) - Where messages are stored (your custom implementation)
|
|
246
|
-
2. **ChatMemory** (Logic Layer) - How messages are managed (windowing, session scoping)
|
|
247
|
-
|
|
248
|
-
### Naming Convention
|
|
249
|
-
|
|
250
|
-
The SDK uses n8n-specific naming to avoid confusion with LangChain classes:
|
|
251
|
-
|
|
252
|
-
| n8n SDK | LangChain Equivalent |
|
|
253
|
-
|---------|---------------------|
|
|
254
|
-
| `ChatHistory` (interface) | `BaseChatMessageHistory` |
|
|
255
|
-
| `BaseChatHistory` (base class) | `BaseChatMessageHistory` |
|
|
256
|
-
| `ChatMemory` (interface) | `BaseChatMemory` |
|
|
257
|
-
| `BaseChatMemory` (base class) | `BaseChatMemory` |
|
|
258
|
-
| `WindowedChatMemory` | `BufferWindowMemory` |
|
|
259
|
-
|
|
260
|
-
## Core Pattern
|
|
261
|
-
|
|
262
|
-
### Option A: Custom Storage
|
|
263
|
-
|
|
264
|
-
For exotic databases not covered by the SDK, extend `BaseChatHistory`:
|
|
265
|
-
|
|
266
|
-
```typescript
|
|
267
|
-
import {
|
|
268
|
-
BaseChatHistory,
|
|
269
|
-
WindowedChatMemory,
|
|
270
|
-
supplyMemory,
|
|
271
|
-
type Message,
|
|
272
|
-
} from '@n8n/ai-utilities';
|
|
273
|
-
|
|
274
|
-
class MyChatHistory extends BaseChatHistory {
|
|
275
|
-
constructor(private sessionId: string) {
|
|
276
|
-
super();
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
async getMessages(): Promise<Message[]> {
|
|
280
|
-
// Read from your storage...
|
|
281
|
-
return [];
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
async addMessage(message: Message): Promise<void> {
|
|
285
|
-
// Write to your storage...
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
async clear(): Promise<void> {
|
|
289
|
-
// Clear your storage...
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
const history = new MyChatHistory(sessionId);
|
|
294
|
-
const memory = new WindowedChatMemory(history, { windowSize: 10 });
|
|
295
|
-
return supplyMemory(this, memory);
|
|
296
|
-
```
|
|
297
|
-
|
|
298
|
-
### Option B: Custom Memory Logic
|
|
299
|
-
|
|
300
|
-
For custom memory behavior (not just storage), extend `BaseChatMemory`:
|
|
301
|
-
|
|
302
|
-
```typescript
|
|
303
|
-
import {
|
|
304
|
-
BaseChatMemory,
|
|
305
|
-
supplyMemory,
|
|
306
|
-
type Message,
|
|
307
|
-
type ChatHistory,
|
|
308
|
-
type ChatMemory,
|
|
309
|
-
} from '@n8n/ai-utilities';
|
|
310
|
-
|
|
311
|
-
class MyCustomChatMemory extends BaseChatMemory {
|
|
312
|
-
readonly chatHistory: ChatHistory;
|
|
313
|
-
|
|
314
|
-
constructor(chatHistory: ChatHistory) {
|
|
315
|
-
super();
|
|
316
|
-
this.chatHistory = chatHistory;
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
async loadMessages(): Promise<Message[]> {
|
|
320
|
-
const messages = await this.chatHistory.getMessages();
|
|
321
|
-
// Apply your custom logic here...
|
|
322
|
-
return messages;
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
async saveTurn(input: string, output: string): Promise<void> {
|
|
326
|
-
await this.chatHistory.addMessages([
|
|
327
|
-
{ role: 'user', content: [{ type: 'text', text: input }] },
|
|
328
|
-
{ role: 'assistant', content: [{ type: 'text', text: output }] },
|
|
329
|
-
]);
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
async clear(): Promise<void> {
|
|
333
|
-
await this.chatHistory.clear();
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
const history = new MyChatHistory(sessionId);
|
|
338
|
-
const memory = new MyCustomChatMemory(history);
|
|
339
|
-
return supplyMemory(this, memory);
|
|
340
|
-
```
|
|
341
|
-
|
|
342
|
-
---
|
|
343
|
-
|
|
344
|
-
## Community Node Examples
|
|
345
|
-
|
|
346
|
-
### ImaginaryDB Memory Node
|
|
347
|
-
|
|
348
|
-
```typescript
|
|
349
|
-
import {
|
|
350
|
-
BaseChatHistory,
|
|
351
|
-
WindowedChatMemory,
|
|
352
|
-
supplyMemory,
|
|
353
|
-
type Message,
|
|
354
|
-
} from '@n8n/ai-utilities';
|
|
355
|
-
import {
|
|
356
|
-
NodeConnectionTypes,
|
|
357
|
-
type INodeType,
|
|
358
|
-
type ISupplyDataFunctions,
|
|
359
|
-
type SupplyData,
|
|
360
|
-
type IHttpRequestMethods,
|
|
361
|
-
} from 'n8n-workflow';
|
|
362
|
-
|
|
363
|
-
// Custom storage implementation using n8n's HTTP helpers
|
|
364
|
-
class ImaginaryDbChatHistory extends BaseChatHistory {
|
|
365
|
-
constructor(
|
|
366
|
-
private sessionId: string,
|
|
367
|
-
private baseUrl: string,
|
|
368
|
-
private apiKey: string,
|
|
369
|
-
private httpRequest: ISupplyDataFunctions['helpers']['httpRequest'],
|
|
370
|
-
) {
|
|
371
|
-
super();
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
async getMessages(): Promise<Message[]> {
|
|
375
|
-
const data = await this.httpRequest({
|
|
376
|
-
method: 'GET',
|
|
377
|
-
url: `${this.baseUrl}/sessions/${this.sessionId}/messages`,
|
|
378
|
-
headers: { Authorization: `Bearer ${this.apiKey}` },
|
|
379
|
-
json: true,
|
|
380
|
-
});
|
|
381
|
-
|
|
382
|
-
// Convert from provider format to n8n Message format
|
|
383
|
-
return data.messages.map((m: any) => ({
|
|
384
|
-
role: m.speaker === 'user' ? 'user' : m.speaker === 'bot' ? 'assistant' : m.speaker,
|
|
385
|
-
content: [{ type: 'text', text: m.text }],
|
|
386
|
-
}));
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
async addMessage(message: Message): Promise<void> {
|
|
390
|
-
const text = message.content.find((c) => c.type === 'text')?.text ?? '';
|
|
391
|
-
await this.httpRequest({
|
|
392
|
-
method: 'POST',
|
|
393
|
-
url: `${this.baseUrl}/sessions/${this.sessionId}/messages`,
|
|
394
|
-
headers: { Authorization: `Bearer ${this.apiKey}` },
|
|
395
|
-
body: {
|
|
396
|
-
speaker: message.role === 'user' ? 'user' : message.role === 'assistant' ? 'bot' : message.role,
|
|
397
|
-
text,
|
|
398
|
-
},
|
|
399
|
-
json: true,
|
|
400
|
-
});
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
async clear(): Promise<void> {
|
|
404
|
-
await this.httpRequest({
|
|
405
|
-
method: 'DELETE',
|
|
406
|
-
url: `${this.baseUrl}/sessions/${this.sessionId}`,
|
|
407
|
-
headers: { Authorization: `Bearer ${this.apiKey}` },
|
|
408
|
-
});
|
|
409
|
-
}
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
// The n8n node
|
|
413
|
-
export class MemoryImaginaryDb implements INodeType {
|
|
414
|
-
description = {
|
|
415
|
-
displayName: 'ImaginaryDB Memory',
|
|
416
|
-
name: 'memoryImaginaryDb',
|
|
417
|
-
icon: 'file:imaginarydb.svg',
|
|
418
|
-
group: ['transform'],
|
|
419
|
-
version: 1,
|
|
420
|
-
description: 'Use ImaginaryDB for chat memory storage',
|
|
421
|
-
defaults: { name: 'ImaginaryDB Memory' },
|
|
422
|
-
codex: { categories: ['assistant'], subcategories: { AI: ['Memory'] } },
|
|
423
|
-
inputs: [],
|
|
424
|
-
outputs: [NodeConnectionTypes.AiMemory],
|
|
425
|
-
outputNames: ['Memory'],
|
|
426
|
-
credentials: [{ name: 'imaginaryDbApi', required: true }],
|
|
427
|
-
properties: [
|
|
428
|
-
{
|
|
429
|
-
displayName: 'Session ID',
|
|
430
|
-
name: 'sessionId',
|
|
431
|
-
type: 'string',
|
|
432
|
-
default: '={{ $json.sessionId }}',
|
|
433
|
-
description: 'Unique identifier for the conversation session',
|
|
434
|
-
},
|
|
435
|
-
{
|
|
436
|
-
displayName: 'Window Size',
|
|
437
|
-
name: 'windowSize',
|
|
438
|
-
type: 'number',
|
|
439
|
-
default: 10,
|
|
440
|
-
description: 'Number of recent message pairs to keep in context',
|
|
441
|
-
},
|
|
442
|
-
],
|
|
443
|
-
};
|
|
444
|
-
|
|
445
|
-
async supplyData(this: ISupplyDataFunctions, itemIndex: number): Promise<SupplyData> {
|
|
446
|
-
const credentials = await this.getCredentials<{ apiKey: string; baseUrl: string }>('imaginaryDbApi');
|
|
447
|
-
const sessionId = this.getNodeParameter('sessionId', itemIndex) as string;
|
|
448
|
-
const windowSize = this.getNodeParameter('windowSize', itemIndex) as number;
|
|
449
|
-
|
|
450
|
-
// Pass n8n's HTTP request helper directly
|
|
451
|
-
const history = new ImaginaryDbChatHistory(
|
|
452
|
-
sessionId,
|
|
453
|
-
credentials.baseUrl,
|
|
454
|
-
credentials.apiKey,
|
|
455
|
-
this.helpers.httpRequest,
|
|
456
|
-
);
|
|
457
|
-
const memory = new WindowedChatMemory(history, { windowSize });
|
|
458
|
-
|
|
459
|
-
return supplyMemory(this, memory);
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
```
|
|
463
|
-
|
|
464
|
-
> **Note:** Community nodes must use `this.helpers.httpRequest` or `this.helpers.httpRequestWithAuthentication`
|
|
465
|
-
> for HTTP calls. Direct `fetch` or other global APIs are not allowed.
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
---
|
|
469
|
-
|
|
470
|
-
## Summary
|
|
27
|
+
## Usage
|
|
471
28
|
|
|
472
|
-
|
|
473
|
-
|--------------------|-------------|
|
|
474
|
-
| `import { ChatOpenAI } from '@langchain/openai'` | `import { supplyModel } from '@n8n/ai-utilities'` |
|
|
475
|
-
| `new ChatOpenAI({ ... })` | `supplyModel(this, { type: 'openai', ... })` |
|
|
476
|
-
| Custom model provider | `class MyModel extends BaseChatModel { ... }` |
|
|
477
|
-
| `return { response: model }` | `return supplyModel(this, model)` |
|
|
478
|
-
| `import { BufferWindowMemory } from '@langchain/classic/memory'` | `import { WindowedChatMemory } from '@n8n/ai-utilities'` |
|
|
479
|
-
| Custom storage backend | `class MyHistory extends BaseChatHistory { ... }` |
|
|
480
|
-
| `return { response: logWrapper(memory, this) }` | `return supplyMemory(this, memory)` |
|
|
481
|
-
| LangChain message types | `Message` with roles: `system`, `human`, `ai`, `tool` |
|
|
482
|
-
| `tool_calls[].args` | `toolCalls[].arguments` |
|
|
29
|
+
For public SDK documentation see `@n8n/ai-node-sdk`.
|
|
@@ -9,7 +9,7 @@ import { ChatGenerationChunk } from '@langchain/core/outputs';
|
|
|
9
9
|
import type { Runnable } from '@langchain/core/runnables';
|
|
10
10
|
import type { ISupplyDataFunctions } from 'n8n-workflow';
|
|
11
11
|
import type { ChatModel, ChatModelConfig } from '../types/chat-model';
|
|
12
|
-
export declare class
|
|
12
|
+
export declare class LangchainChatModelAdapter<CallOptions extends ChatModelConfig = ChatModelConfig> extends BaseChatModel<CallOptions> {
|
|
13
13
|
private chatModel;
|
|
14
14
|
private ctx?;
|
|
15
15
|
constructor(chatModel: ChatModel, ctx?: ISupplyDataFunctions | undefined);
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
(function (factory) {
|
|
2
|
+
if (typeof module === "object" && typeof module.exports === "object") {
|
|
3
|
+
var v = factory(require, exports);
|
|
4
|
+
if (v !== undefined) module.exports = v;
|
|
5
|
+
}
|
|
6
|
+
else if (typeof define === "function" && define.amd) {
|
|
7
|
+
define(["require", "exports", "@langchain/core/language_models/chat_models", "@langchain/core/messages", "@langchain/core/outputs", "../converters/message", "../converters/tool", "../utils/failed-attempt-handler/n8nLlmFailedAttemptHandler", "../utils/n8n-llm-tracing"], factory);
|
|
8
|
+
}
|
|
9
|
+
})(function (require, exports) {
|
|
10
|
+
"use strict";
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.LangchainChatModelAdapter = void 0;
|
|
13
|
+
const chat_models_1 = require("@langchain/core/language_models/chat_models");
|
|
14
|
+
const messages_1 = require("@langchain/core/messages");
|
|
15
|
+
const outputs_1 = require("@langchain/core/outputs");
|
|
16
|
+
const message_1 = require("../converters/message");
|
|
17
|
+
const tool_1 = require("../converters/tool");
|
|
18
|
+
const n8nLlmFailedAttemptHandler_1 = require("../utils/failed-attempt-handler/n8nLlmFailedAttemptHandler");
|
|
19
|
+
const n8n_llm_tracing_1 = require("../utils/n8n-llm-tracing");
|
|
20
|
+
class LangchainChatModelAdapter extends chat_models_1.BaseChatModel {
|
|
21
|
+
constructor(chatModel, ctx) {
|
|
22
|
+
const params = {
|
|
23
|
+
...(ctx
|
|
24
|
+
? {
|
|
25
|
+
callbacks: [
|
|
26
|
+
new n8n_llm_tracing_1.N8nLlmTracing(ctx, {
|
|
27
|
+
tokensUsageParser: (result) => {
|
|
28
|
+
const tokenUsage = result?.llmOutput?.tokenUsage;
|
|
29
|
+
const completionTokens = tokenUsage?.output_tokens ?? 0;
|
|
30
|
+
const promptTokens = tokenUsage?.input_tokens ?? 0;
|
|
31
|
+
return {
|
|
32
|
+
completionTokens,
|
|
33
|
+
promptTokens,
|
|
34
|
+
totalTokens: completionTokens + promptTokens,
|
|
35
|
+
};
|
|
36
|
+
},
|
|
37
|
+
}),
|
|
38
|
+
],
|
|
39
|
+
onFailedAttempt: (0, n8nLlmFailedAttemptHandler_1.makeN8nLlmFailedAttemptHandler)(ctx),
|
|
40
|
+
}
|
|
41
|
+
: {}),
|
|
42
|
+
};
|
|
43
|
+
super(params);
|
|
44
|
+
this.chatModel = chatModel;
|
|
45
|
+
this.ctx = ctx;
|
|
46
|
+
}
|
|
47
|
+
_llmType() {
|
|
48
|
+
return 'n8n-chat-model';
|
|
49
|
+
}
|
|
50
|
+
async _generate(messages, options) {
|
|
51
|
+
const transformedMessages = messages.map(message_1.fromLcMessage);
|
|
52
|
+
const result = await this.chatModel.generate(transformedMessages, options);
|
|
53
|
+
const lcMessage = (0, message_1.toLcMessage)(result.message);
|
|
54
|
+
const usage_metadata = result.usage
|
|
55
|
+
? {
|
|
56
|
+
input_tokens: result.usage.promptTokens ?? 0,
|
|
57
|
+
output_tokens: result.usage.completionTokens ?? 0,
|
|
58
|
+
total_tokens: result.usage.totalTokens ?? 0,
|
|
59
|
+
input_token_details: result.usage.inputTokenDetails
|
|
60
|
+
? {
|
|
61
|
+
cache_read: result.usage.inputTokenDetails.cacheRead,
|
|
62
|
+
}
|
|
63
|
+
: undefined,
|
|
64
|
+
output_token_details: result.usage.outputTokenDetails
|
|
65
|
+
? {
|
|
66
|
+
reasoning: result.usage.outputTokenDetails.reasoning,
|
|
67
|
+
}
|
|
68
|
+
: undefined,
|
|
69
|
+
}
|
|
70
|
+
: undefined;
|
|
71
|
+
if (messages_1.AIMessage.isInstance(lcMessage)) {
|
|
72
|
+
lcMessage.usage_metadata = usage_metadata;
|
|
73
|
+
}
|
|
74
|
+
lcMessage.response_metadata = {
|
|
75
|
+
...result.providerMetadata,
|
|
76
|
+
model: this.chatModel.modelId,
|
|
77
|
+
provider: this.chatModel.provider,
|
|
78
|
+
};
|
|
79
|
+
return {
|
|
80
|
+
generations: [
|
|
81
|
+
{
|
|
82
|
+
text: lcMessage.text,
|
|
83
|
+
message: lcMessage,
|
|
84
|
+
},
|
|
85
|
+
],
|
|
86
|
+
llmOutput: {
|
|
87
|
+
id: result.id,
|
|
88
|
+
tokenUsage: usage_metadata,
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
async *_streamResponseChunks(messages, options, runManager) {
|
|
93
|
+
const genericMessages = messages.map(message_1.fromLcMessage);
|
|
94
|
+
const stream = this.chatModel.stream(genericMessages, options);
|
|
95
|
+
for await (const chunk of stream) {
|
|
96
|
+
let lcChunk = undefined;
|
|
97
|
+
if (chunk.type === 'text-delta') {
|
|
98
|
+
const content = [
|
|
99
|
+
{
|
|
100
|
+
type: 'text',
|
|
101
|
+
text: chunk.delta,
|
|
102
|
+
},
|
|
103
|
+
];
|
|
104
|
+
lcChunk = new outputs_1.ChatGenerationChunk({
|
|
105
|
+
message: new messages_1.AIMessageChunk({
|
|
106
|
+
content,
|
|
107
|
+
}),
|
|
108
|
+
text: chunk.delta,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
else if (chunk.type === 'tool-call-delta') {
|
|
112
|
+
const tool_call_chunks = [
|
|
113
|
+
{
|
|
114
|
+
type: 'tool_call_chunk',
|
|
115
|
+
id: chunk.id,
|
|
116
|
+
name: chunk.name,
|
|
117
|
+
args: chunk.argumentsDelta,
|
|
118
|
+
index: 0,
|
|
119
|
+
},
|
|
120
|
+
];
|
|
121
|
+
lcChunk = new outputs_1.ChatGenerationChunk({
|
|
122
|
+
message: new messages_1.AIMessageChunk({
|
|
123
|
+
content: '',
|
|
124
|
+
tool_call_chunks,
|
|
125
|
+
}),
|
|
126
|
+
text: '',
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
else if (chunk.type === 'finish') {
|
|
130
|
+
const usage_metadata = chunk.usage
|
|
131
|
+
? {
|
|
132
|
+
input_tokens: chunk.usage.promptTokens ?? 0,
|
|
133
|
+
output_tokens: chunk.usage.completionTokens ?? 0,
|
|
134
|
+
total_tokens: chunk.usage.totalTokens ?? 0,
|
|
135
|
+
}
|
|
136
|
+
: undefined;
|
|
137
|
+
lcChunk = new outputs_1.ChatGenerationChunk({
|
|
138
|
+
message: new messages_1.AIMessageChunk({
|
|
139
|
+
content: '',
|
|
140
|
+
usage_metadata,
|
|
141
|
+
response_metadata: {
|
|
142
|
+
finish_reason: chunk.finishReason,
|
|
143
|
+
},
|
|
144
|
+
}),
|
|
145
|
+
text: '',
|
|
146
|
+
generationInfo: {
|
|
147
|
+
finish_reason: chunk.finishReason,
|
|
148
|
+
},
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
else if (chunk.type === 'error') {
|
|
152
|
+
lcChunk = new outputs_1.ChatGenerationChunk({
|
|
153
|
+
message: new messages_1.AIMessageChunk({
|
|
154
|
+
content: '',
|
|
155
|
+
response_metadata: {
|
|
156
|
+
finish_reason: 'error',
|
|
157
|
+
error: chunk.error,
|
|
158
|
+
},
|
|
159
|
+
}),
|
|
160
|
+
text: '',
|
|
161
|
+
generationInfo: {
|
|
162
|
+
finish_reason: 'error',
|
|
163
|
+
error: chunk.error,
|
|
164
|
+
},
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
else if (chunk.type === 'content') {
|
|
168
|
+
const lcMessage = (0, message_1.toLcMessage)({
|
|
169
|
+
role: 'assistant',
|
|
170
|
+
content: [chunk.content],
|
|
171
|
+
id: chunk.id,
|
|
172
|
+
});
|
|
173
|
+
const lcMessageChunk = new messages_1.AIMessageChunk({
|
|
174
|
+
content: lcMessage.content,
|
|
175
|
+
id: lcMessage.id,
|
|
176
|
+
name: lcMessage.name,
|
|
177
|
+
});
|
|
178
|
+
lcChunk = new outputs_1.ChatGenerationChunk({
|
|
179
|
+
message: lcMessageChunk,
|
|
180
|
+
text: lcMessage.text,
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
if (lcChunk) {
|
|
184
|
+
yield lcChunk;
|
|
185
|
+
await runManager?.handleLLMNewToken(lcChunk.text ?? '', {
|
|
186
|
+
prompt: 0,
|
|
187
|
+
completion: 0,
|
|
188
|
+
}, undefined, undefined, undefined, { chunk: lcChunk });
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
bindTools(tools) {
|
|
193
|
+
const genericTools = tools.map(tool_1.fromLcTool);
|
|
194
|
+
const newModel = this.chatModel.withTools(genericTools);
|
|
195
|
+
const newAdapter = new LangchainChatModelAdapter(newModel, this.ctx);
|
|
196
|
+
return newAdapter;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
exports.LangchainChatModelAdapter = LangchainChatModelAdapter;
|
|
200
|
+
});
|
|
201
|
+
//# sourceMappingURL=langchain-chat-model.js.map
|