n8n-nodes-coding-stream 0.0.0-stage → 0.1.2
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 +39 -2
- package/dist/nodes/CodingStreamChatModel/CodingStreamChatModel.node.d.ts +5 -0
- package/dist/nodes/CodingStreamChatModel/CodingStreamChatModel.node.js +94 -0
- package/dist/nodes/CodingStreamChatModel/chat.svg +1 -0
- package/dist/nodes/PackageCheck/PackageCheck.node.d.ts +5 -0
- package/dist/nodes/PackageCheck/PackageCheck.node.js +23 -0
- package/package.json +38 -4
package/README.md
CHANGED
|
@@ -1,3 +1,40 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Coding Stream Chat Model for n8n
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A separate community node, based on the ChatOpenAI approach of Glashkoff/n8n-nodes-llm-chat. Does NOT alter that installed package. Provides a standard `AiLanguageModel` for n8n AI Agent with native LangChain/OpenAI SDK streaming (no n8n Webhook SSE JSONL envelopes).
|
|
4
|
+
|
|
5
|
+
## Two headers
|
|
6
|
+
|
|
7
|
+
- `Authorization: Bearer <token>` is provided automatically by OpenAI SDK using its `apiKey` setting. Supply dynamic token from your existing n8n token-fetch nodes.
|
|
8
|
+
- `X-Request-By: system` is passed through OpenAI SDK `configuration.defaultHeaders`.
|
|
9
|
+
|
|
10
|
+
## Requirements
|
|
11
|
+
|
|
12
|
+
Node.js/npm for packaging; a self-hosted n8n version compatible with the pinned `@n8n/ai-utilities` dependency (`0.27.3`), e.g. check your n8n's versions. Build requires Internet for npm dependencies.
|
|
13
|
+
|
|
14
|
+
## Build
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install
|
|
18
|
+
npm run build
|
|
19
|
+
npm pack
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Publish under your own npm account after changing `name` in package.json to an available `n8n-nodes-*` name; then install via n8n **Settings → Community Nodes**. Local tarball installation may not be supported in Community Nodes UI.
|
|
23
|
+
|
|
24
|
+
## Setup
|
|
25
|
+
|
|
26
|
+
1. In main workflow, ensure Get Token completes before AI Agent.
|
|
27
|
+
2. Replace existing LLM Chat Model with `Coding Stream Chat Model` and attach via **Model** connector.
|
|
28
|
+
3. Set Gateway Base URL: `https://external-ai-gateway.sovcombank.group/llm/v1`.
|
|
29
|
+
4. Set Model: `coding-ultima`.
|
|
30
|
+
5. Set Bearer Token expression referencing the node that holds your valid token, e.g. `{{ $('Get Token').first().json.access_token }}` (change node name/path to match your own main workflow).
|
|
31
|
+
6. Keep `X-Request-By` as `system`.
|
|
32
|
+
7. To **see** output streaming to a chat/webhook client, your trigger and agent must also use n8n streaming response mode. The Chat Model supplies native streaming but cannot force the top-level response to stream.
|
|
33
|
+
|
|
34
|
+
## Tests
|
|
35
|
+
|
|
36
|
+
Test short content, longer streaming response, tool calls, token error, and tracing callbacks. This package is source-complete but **not yet built or runtime-tested** against your n8n and protected gateway.
|
|
37
|
+
|
|
38
|
+
## Design note
|
|
39
|
+
|
|
40
|
+
There is intentionally no Keycloak, Redis, or Valkey inside the model node. Token retrieval is external to this model. If an AI Agent does multiple LLM calls after token expiry during one execution, refresh token before the model supplyData call or shorten agent run; the node does not auto-refresh it.
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { type INodeType, type INodeTypeDescription, type ISupplyDataFunctions, type SupplyData } from 'n8n-workflow';
|
|
2
|
+
export declare class CodingStreamChatModel implements INodeType {
|
|
3
|
+
description: INodeTypeDescription;
|
|
4
|
+
supplyData(this: ISupplyDataFunctions, itemIndex: number): Promise<SupplyData>;
|
|
5
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CodingStreamChatModel = void 0;
|
|
4
|
+
const openai_1 = require("@langchain/openai");
|
|
5
|
+
const ai_utilities_1 = require("@n8n/ai-utilities");
|
|
6
|
+
const n8n_workflow_1 = require("n8n-workflow");
|
|
7
|
+
class CodingStreamChatModel {
|
|
8
|
+
constructor() {
|
|
9
|
+
this.description = {
|
|
10
|
+
displayName: 'Coding Stream Chat Model',
|
|
11
|
+
name: 'codingStreamChatModel',
|
|
12
|
+
icon: 'file:chat.svg',
|
|
13
|
+
group: ['transform'],
|
|
14
|
+
version: 1,
|
|
15
|
+
description: 'Native LangChain streaming with dynamic Bearer token and X-Request-By header',
|
|
16
|
+
defaults: { name: 'Coding Stream Chat Model' },
|
|
17
|
+
inputs: [],
|
|
18
|
+
outputs: [n8n_workflow_1.NodeConnectionTypes.AiLanguageModel],
|
|
19
|
+
outputNames: ['Model'],
|
|
20
|
+
properties: [
|
|
21
|
+
{
|
|
22
|
+
displayName: 'Gateway Base URL',
|
|
23
|
+
name: 'baseURL',
|
|
24
|
+
type: 'string',
|
|
25
|
+
required: true,
|
|
26
|
+
default: 'https://external-ai-gateway.sovcombank.group/llm/v1',
|
|
27
|
+
description: 'Base URL that ends in /v1 (the SDK adds /chat/completions)',
|
|
28
|
+
},
|
|
29
|
+
{ displayName: 'Model', name: 'model', type: 'string', required: true, default: 'coding-ultima' },
|
|
30
|
+
{
|
|
31
|
+
displayName: 'Bearer Token',
|
|
32
|
+
name: 'bearerToken',
|
|
33
|
+
type: 'string',
|
|
34
|
+
required: true,
|
|
35
|
+
typeOptions: { password: true },
|
|
36
|
+
default: '',
|
|
37
|
+
description: 'Use an n8n expression referring to your existing Get Token node; accepts raw token or Bearer token',
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
displayName: 'X-Request-By',
|
|
41
|
+
name: 'requestBy',
|
|
42
|
+
type: 'string',
|
|
43
|
+
default: 'system',
|
|
44
|
+
required: true,
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
displayName: 'Options', name: 'options', type: 'collection', placeholder: 'Add Option', default: {},
|
|
48
|
+
options: [
|
|
49
|
+
{ displayName: 'Temperature', name: 'temperature', type: 'number', typeOptions: { minValue: 0, maxValue: 2 }, default: 0.3 },
|
|
50
|
+
{ displayName: 'Max Tokens', name: 'maxTokens', type: 'number', typeOptions: { minValue: 1 }, default: 4096 },
|
|
51
|
+
{ displayName: 'Top P', name: 'topP', type: 'number', typeOptions: { minValue: 0, maxValue: 1 }, default: 0.6 },
|
|
52
|
+
{ displayName: 'Timeout (ms)', name: 'timeout', type: 'number', typeOptions: { minValue: 1000 }, default: 120000 },
|
|
53
|
+
],
|
|
54
|
+
},
|
|
55
|
+
],
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
async supplyData(itemIndex) {
|
|
59
|
+
const baseURL = String(this.getNodeParameter('baseURL', itemIndex)).trim().replace(/\/+$/, '');
|
|
60
|
+
const modelName = String(this.getNodeParameter('model', itemIndex)).trim();
|
|
61
|
+
const rawToken = String(this.getNodeParameter('bearerToken', itemIndex)).trim();
|
|
62
|
+
const token = rawToken.replace(/^Bearer\s+/i, '');
|
|
63
|
+
const requestBy = String(this.getNodeParameter('requestBy', itemIndex)).trim();
|
|
64
|
+
const options = this.getNodeParameter('options', itemIndex, {});
|
|
65
|
+
if (!token) {
|
|
66
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Bearer Token is empty. Check the Get Token expression.');
|
|
67
|
+
}
|
|
68
|
+
if (!baseURL.endsWith('/v1')) {
|
|
69
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Gateway Base URL must end in /v1.');
|
|
70
|
+
}
|
|
71
|
+
if (!requestBy) {
|
|
72
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'X-Request-By cannot be empty.');
|
|
73
|
+
}
|
|
74
|
+
// OpenAI SDK itself creates Authorization: Bearer <apiKey> for every request.
|
|
75
|
+
// No manual SSE parsing and no workflow-to-workflow proxying.
|
|
76
|
+
const model = new openai_1.ChatOpenAI({
|
|
77
|
+
model: modelName,
|
|
78
|
+
apiKey: token,
|
|
79
|
+
configuration: {
|
|
80
|
+
baseURL,
|
|
81
|
+
defaultHeaders: { 'X-Request-By': requestBy },
|
|
82
|
+
},
|
|
83
|
+
temperature: options.temperature ?? 0.3,
|
|
84
|
+
maxTokens: options.maxTokens ?? 4096,
|
|
85
|
+
topP: options.topP ?? 0.6,
|
|
86
|
+
timeout: options.timeout ?? 120000,
|
|
87
|
+
maxRetries: 0,
|
|
88
|
+
supportsStrictToolCalling: false,
|
|
89
|
+
callbacks: [new ai_utilities_1.N8nLlmTracing(this)],
|
|
90
|
+
});
|
|
91
|
+
return { response: model };
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
exports.CodingStreamChatModel = CodingStreamChatModel;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48"><rect x="4" y="4" width="40" height="40" rx="10" fill="#2563eb"/><path d="m17 17-7 7 7 7m14-14 7 7-7 7M27 13l-6 22" stroke="white" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" fill="none"/></svg>
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { type INodeType, type INodeTypeDescription, type IExecuteFunctions, type INodeExecutionData } from 'n8n-workflow';
|
|
2
|
+
export declare class PackageCheck implements INodeType {
|
|
3
|
+
description: INodeTypeDescription;
|
|
4
|
+
execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
|
|
5
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PackageCheck = void 0;
|
|
4
|
+
const n8n_workflow_1 = require("n8n-workflow");
|
|
5
|
+
class PackageCheck {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.description = {
|
|
8
|
+
displayName: 'Coding Stream Package Check',
|
|
9
|
+
name: 'codingStreamPackageCheck',
|
|
10
|
+
group: ['transform'],
|
|
11
|
+
version: 1,
|
|
12
|
+
description: 'Diagnostic node to verify community package loading',
|
|
13
|
+
defaults: { name: 'Coding Stream Package Check' },
|
|
14
|
+
inputs: [n8n_workflow_1.NodeConnectionTypes.Main],
|
|
15
|
+
outputs: [n8n_workflow_1.NodeConnectionTypes.Main],
|
|
16
|
+
properties: [],
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
async execute() {
|
|
20
|
+
return [this.getInputData()];
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
exports.PackageCheck = PackageCheck;
|
package/package.json
CHANGED
|
@@ -1,6 +1,40 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "n8n-nodes-coding-stream",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"description": "
|
|
6
|
-
|
|
3
|
+
"version": "0.1.2",
|
|
4
|
+
"private": false,
|
|
5
|
+
"description": "OpenAI-compatible n8n Chat Model with native SSE streaming and dynamic Bearer + X-Request-By",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"n8n-community-node-package",
|
|
9
|
+
"n8n",
|
|
10
|
+
"langchain",
|
|
11
|
+
"streaming",
|
|
12
|
+
"openai"
|
|
13
|
+
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsc && cp nodes/CodingStreamChatModel/chat.svg dist/nodes/CodingStreamChatModel/chat.svg",
|
|
16
|
+
"prepublishOnly": "npm run build"
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"dist"
|
|
20
|
+
],
|
|
21
|
+
"n8n": {
|
|
22
|
+
"n8nNodesApiVersion": 1,
|
|
23
|
+
"credentials": [],
|
|
24
|
+
"nodes": [
|
|
25
|
+
"dist/nodes/CodingStreamChatModel/CodingStreamChatModel.node.js",
|
|
26
|
+
"dist/nodes/PackageCheck/PackageCheck.node.js"
|
|
27
|
+
]
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@langchain/openai": "^1.4.6",
|
|
31
|
+
"@n8n/ai-utilities": "0.27.3"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"n8n-workflow": "^2.16.0",
|
|
35
|
+
"typescript": "^6.0.3"
|
|
36
|
+
},
|
|
37
|
+
"peerDependencies": {
|
|
38
|
+
"n8n-workflow": "*"
|
|
39
|
+
}
|
|
40
|
+
}
|