Skip to content

Commit 099cf48

Browse files
authored
feat: add CometAPI integration with ChatCometAPI node (#5160)
* feat: add CometAPI integration with ChatCometAPI node and credential support * feat: remove timeout and stop sequence parameters from ChatCometAPI node
1 parent 113086a commit 099cf48

File tree

4 files changed

+208
-1
lines changed

4 files changed

+208
-1
lines changed
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { INodeCredential, INodeParams } from '../src/Interface'
2+
3+
class CometApi implements INodeCredential {
4+
label: string
5+
name: string
6+
version: number
7+
inputs: INodeParams[]
8+
9+
constructor() {
10+
this.label = 'Comet API'
11+
this.name = 'cometApi'
12+
this.version = 1.0
13+
this.inputs = [
14+
{
15+
label: 'Comet API Key',
16+
name: 'cometApiKey',
17+
type: 'password'
18+
}
19+
]
20+
}
21+
}
22+
23+
module.exports = { credClass: CometApi }
Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
import { BaseCache } from '@langchain/core/caches'
2+
import { ChatOpenAI, ChatOpenAIFields } from '@langchain/openai'
3+
import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface'
4+
import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils'
5+
6+
class ChatCometAPI_ChatModels implements INode {
7+
readonly baseURL: string = 'https://api.cometapi.com/v1'
8+
label: string
9+
name: string
10+
version: number
11+
type: string
12+
icon: string
13+
category: string
14+
description: string
15+
baseClasses: string[]
16+
credential: INodeParams
17+
inputs: INodeParams[]
18+
19+
constructor() {
20+
this.label = 'ChatCometAPI'
21+
this.name = 'chatCometAPI'
22+
this.version = 1.0
23+
this.type = 'ChatCometAPI'
24+
this.icon = 'cometapi.svg'
25+
this.category = 'Chat Models'
26+
this.description = 'Wrapper around CometAPI large language models that use the Chat endpoint'
27+
this.baseClasses = [this.type, ...getBaseClasses(ChatOpenAI)]
28+
this.credential = {
29+
label: 'Connect Credential',
30+
name: 'credential',
31+
type: 'credential',
32+
credentialNames: ['cometApi']
33+
}
34+
this.inputs = [
35+
{
36+
label: 'Cache',
37+
name: 'cache',
38+
type: 'BaseCache',
39+
optional: true
40+
},
41+
{
42+
label: 'Model Name',
43+
name: 'modelName',
44+
type: 'string',
45+
default: 'gpt-5-mini',
46+
description: 'Enter the model name (e.g., gpt-5-mini, claude-sonnet-4-20250514, gemini-2.0-flash)'
47+
},
48+
{
49+
label: 'Temperature',
50+
name: 'temperature',
51+
type: 'number',
52+
step: 0.1,
53+
default: 0.7,
54+
optional: true
55+
},
56+
{
57+
label: 'Streaming',
58+
name: 'streaming',
59+
type: 'boolean',
60+
default: true,
61+
optional: true,
62+
additionalParams: true
63+
},
64+
{
65+
label: 'Max Tokens',
66+
name: 'maxTokens',
67+
type: 'number',
68+
step: 1,
69+
optional: true,
70+
additionalParams: true
71+
},
72+
{
73+
label: 'Top Probability',
74+
name: 'topP',
75+
type: 'number',
76+
step: 0.1,
77+
optional: true,
78+
additionalParams: true
79+
},
80+
{
81+
label: 'Frequency Penalty',
82+
name: 'frequencyPenalty',
83+
type: 'number',
84+
step: 0.1,
85+
optional: true,
86+
additionalParams: true
87+
},
88+
{
89+
label: 'Presence Penalty',
90+
name: 'presencePenalty',
91+
type: 'number',
92+
step: 0.1,
93+
optional: true,
94+
additionalParams: true
95+
},
96+
{
97+
label: 'Base Options',
98+
name: 'baseOptions',
99+
type: 'json',
100+
optional: true,
101+
additionalParams: true,
102+
description: 'Additional options to pass to the CometAPI client. This should be a JSON object.'
103+
}
104+
]
105+
}
106+
107+
async init(nodeData: INodeData, _: string, options: ICommonObject): Promise<any> {
108+
const temperature = nodeData.inputs?.temperature as string
109+
const modelName = nodeData.inputs?.modelName as string
110+
const maxTokens = nodeData.inputs?.maxTokens as string
111+
const topP = nodeData.inputs?.topP as string
112+
const frequencyPenalty = nodeData.inputs?.frequencyPenalty as string
113+
const presencePenalty = nodeData.inputs?.presencePenalty as string
114+
const streaming = nodeData.inputs?.streaming as boolean
115+
const baseOptions = nodeData.inputs?.baseOptions
116+
117+
if (nodeData.inputs?.credentialId) {
118+
nodeData.credential = nodeData.inputs?.credentialId
119+
}
120+
const credentialData = await getCredentialData(nodeData.credential ?? '', options)
121+
const openAIApiKey = getCredentialParam('cometApiKey', credentialData, nodeData)
122+
123+
// Custom error handling for missing API key
124+
if (!openAIApiKey || openAIApiKey.trim() === '') {
125+
throw new Error(
126+
'CometAPI API Key is missing or empty. Please provide a valid CometAPI API key in the credential configuration.'
127+
)
128+
}
129+
130+
// Custom error handling for missing model name
131+
if (!modelName || modelName.trim() === '') {
132+
throw new Error('Model Name is required. Please enter a valid model name (e.g., gpt-5-mini, claude-sonnet-4-20250514).')
133+
}
134+
135+
const cache = nodeData.inputs?.cache as BaseCache
136+
137+
const obj: ChatOpenAIFields = {
138+
temperature: parseFloat(temperature),
139+
modelName,
140+
openAIApiKey,
141+
apiKey: openAIApiKey,
142+
streaming: streaming ?? true
143+
}
144+
145+
if (maxTokens) obj.maxTokens = parseInt(maxTokens, 10)
146+
if (topP) obj.topP = parseFloat(topP)
147+
if (frequencyPenalty) obj.frequencyPenalty = parseFloat(frequencyPenalty)
148+
if (presencePenalty) obj.presencePenalty = parseFloat(presencePenalty)
149+
if (cache) obj.cache = cache
150+
151+
let parsedBaseOptions: any | undefined = undefined
152+
153+
if (baseOptions) {
154+
try {
155+
parsedBaseOptions = typeof baseOptions === 'object' ? baseOptions : JSON.parse(baseOptions)
156+
if (parsedBaseOptions.baseURL) {
157+
console.warn("The 'baseURL' parameter is not allowed when using the ChatCometAPI node.")
158+
parsedBaseOptions.baseURL = undefined
159+
}
160+
} catch (exception) {
161+
throw new Error('Invalid JSON in the BaseOptions: ' + exception)
162+
}
163+
}
164+
165+
const model = new ChatOpenAI({
166+
...obj,
167+
configuration: {
168+
baseURL: this.baseURL,
169+
...parsedBaseOptions
170+
}
171+
})
172+
return model
173+
}
174+
}
175+
176+
module.exports = { nodeClass: ChatCometAPI_ChatModels }
Lines changed: 7 additions & 0 deletions
Loading

packages/server/src/utils/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1491,7 +1491,8 @@ export const isFlowValidForStream = (reactFlowNodes: IReactFlowNode[], endingNod
14911491
'chatTogetherAI_LlamaIndex',
14921492
'chatFireworks',
14931493
'ChatSambanova',
1494-
'chatBaiduWenxin'
1494+
'chatBaiduWenxin',
1495+
'chatCometAPI'
14951496
],
14961497
LLMs: ['azureOpenAI', 'openAI', 'ollama']
14971498
}

0 commit comments

Comments
 (0)