ydc-mcp-server 1.7.0 → 1.7.10
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/lib/anthropic-mapper.js +21 -14
- package/lib/request-logger.js +115 -0
- package/lib/routes/anthropic-messages.js +125 -52
- package/lib/routes/chat.js +58 -8
- package/package.json +1 -1
package/lib/anthropic-mapper.js
CHANGED
|
@@ -165,22 +165,29 @@ export function createAnthropicStreamEvent(eventType, data) {
|
|
|
165
165
|
/**
|
|
166
166
|
* Create message_start event
|
|
167
167
|
*/
|
|
168
|
-
export function createMessageStartEvent(model) {
|
|
168
|
+
export function createMessageStartEvent(model, conversationId = null) {
|
|
169
|
+
const message = {
|
|
170
|
+
id: `msg_${Date.now()}`,
|
|
171
|
+
type: 'message',
|
|
172
|
+
role: 'assistant',
|
|
173
|
+
content: [],
|
|
174
|
+
model: model,
|
|
175
|
+
stop_reason: null,
|
|
176
|
+
stop_sequence: null,
|
|
177
|
+
usage: {
|
|
178
|
+
input_tokens: 0,
|
|
179
|
+
output_tokens: 0
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
// Add conversation_id in metadata if provided
|
|
184
|
+
if (conversationId) {
|
|
185
|
+
message.metadata = { conversation_id: conversationId };
|
|
186
|
+
}
|
|
187
|
+
|
|
169
188
|
return createAnthropicStreamEvent('message_start', {
|
|
170
189
|
type: 'message_start',
|
|
171
|
-
message
|
|
172
|
-
id: `msg_${Date.now()}`,
|
|
173
|
-
type: 'message',
|
|
174
|
-
role: 'assistant',
|
|
175
|
-
content: [],
|
|
176
|
-
model: model,
|
|
177
|
-
stop_reason: null,
|
|
178
|
-
stop_sequence: null,
|
|
179
|
-
usage: {
|
|
180
|
-
input_tokens: 0,
|
|
181
|
-
output_tokens: 0
|
|
182
|
-
}
|
|
183
|
-
}
|
|
190
|
+
message
|
|
184
191
|
});
|
|
185
192
|
}
|
|
186
193
|
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Request Logger Module
|
|
3
|
+
* Pretty prints request/response info using cli-table3
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
let Table;
|
|
7
|
+
let tableAvailable = false;
|
|
8
|
+
|
|
9
|
+
// Try to load cli-table3 (optional dependency)
|
|
10
|
+
try {
|
|
11
|
+
Table = (await import('cli-table3')).default;
|
|
12
|
+
tableAvailable = true;
|
|
13
|
+
} catch (e) {
|
|
14
|
+
// cli-table3 not available, use simple logging
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Track last request ID for comparison
|
|
18
|
+
let lastRequestId = null;
|
|
19
|
+
|
|
20
|
+
// Helper to create table
|
|
21
|
+
function createTable() {
|
|
22
|
+
return new Table({
|
|
23
|
+
colWidths: [4, 12, 60],
|
|
24
|
+
wordWrap: true,
|
|
25
|
+
chars: {
|
|
26
|
+
'top': '─', 'top-mid': '┬', 'top-left': '┌', 'top-right': '┐',
|
|
27
|
+
'bottom': '─', 'bottom-mid': '┴', 'bottom-left': '└', 'bottom-right': '┘',
|
|
28
|
+
'left': '│', 'left-mid': '├', 'mid': '─', 'mid-mid': '┼',
|
|
29
|
+
'right': '│', 'right-mid': '┤', 'middle': '│'
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Helper to print history
|
|
35
|
+
function printHistory(history, label) {
|
|
36
|
+
if (history.length === 0) return;
|
|
37
|
+
|
|
38
|
+
if (tableAvailable) {
|
|
39
|
+
const table = createTable();
|
|
40
|
+
history.forEach((item, index) => {
|
|
41
|
+
const content = item.content || '';
|
|
42
|
+
const preview = content.length > 80 ? content.substring(0, 80) + '...' : content;
|
|
43
|
+
table.push([index + 1, item.role, preview]);
|
|
44
|
+
});
|
|
45
|
+
console.log(` ${label}:`);
|
|
46
|
+
console.log(table.toString());
|
|
47
|
+
} else {
|
|
48
|
+
console.log(` ${label}:`);
|
|
49
|
+
history.forEach((item, index) => {
|
|
50
|
+
const content = item.content || '';
|
|
51
|
+
const preview = content.length > 50 ? content.substring(0, 50) + '...' : content;
|
|
52
|
+
console.log(` ${index + 1}. [${item.role}] ${preview}`);
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Log request with history
|
|
59
|
+
*/
|
|
60
|
+
export function logRequest(info) {
|
|
61
|
+
const {
|
|
62
|
+
conversationId,
|
|
63
|
+
agent = 'unknown',
|
|
64
|
+
stream = false,
|
|
65
|
+
messageCount = 0,
|
|
66
|
+
inputMessages = []
|
|
67
|
+
} = info;
|
|
68
|
+
|
|
69
|
+
const shortId = conversationId ? conversationId.split('-')[0] : 'new';
|
|
70
|
+
lastRequestId = shortId;
|
|
71
|
+
const streamMode = stream ? 'stream' : 'sync';
|
|
72
|
+
|
|
73
|
+
console.log(`📤 Request: ${shortId}, Messages: ${messageCount}`);
|
|
74
|
+
console.log(` ${agent}(${streamMode})`);
|
|
75
|
+
|
|
76
|
+
printHistory(inputMessages, 'History');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Log stream complete with history
|
|
81
|
+
*/
|
|
82
|
+
export function logStreamComplete(info) {
|
|
83
|
+
const {
|
|
84
|
+
conversationId,
|
|
85
|
+
contentLength = 0,
|
|
86
|
+
messageCount = 0,
|
|
87
|
+
agent = 'unknown',
|
|
88
|
+
stream = true,
|
|
89
|
+
inputMessages = []
|
|
90
|
+
} = info;
|
|
91
|
+
|
|
92
|
+
const streamMode = stream ? 'stream' : 'sync';
|
|
93
|
+
const shortId = conversationId ? conversationId.split('-')[0] : 'new';
|
|
94
|
+
|
|
95
|
+
// 如果 Complete ID 和 Request ID 不同,顯示括號
|
|
96
|
+
let idDisplay;
|
|
97
|
+
if (lastRequestId && lastRequestId !== shortId) {
|
|
98
|
+
idDisplay = `(${shortId})`;
|
|
99
|
+
} else {
|
|
100
|
+
idDisplay = shortId;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
console.log(`📥 Complete: ${idDisplay}, ${contentLength} chars, Messages: ${messageCount}`);
|
|
104
|
+
console.log(` ${agent}(${streamMode})`);
|
|
105
|
+
|
|
106
|
+
printHistory(inputMessages, 'History');
|
|
107
|
+
console.log('');
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Log response (for non-streaming)
|
|
112
|
+
*/
|
|
113
|
+
export function logResponse(info) {
|
|
114
|
+
logStreamComplete(info);
|
|
115
|
+
}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { Router } from 'express';
|
|
7
|
-
import { callYouApi
|
|
7
|
+
import { callYouApi } from '../api-client.js';
|
|
8
8
|
import {
|
|
9
9
|
mapAnthropicToYouParams,
|
|
10
10
|
convertToAnthropicResponse,
|
|
@@ -19,8 +19,9 @@ import {
|
|
|
19
19
|
getConversation,
|
|
20
20
|
createConversation,
|
|
21
21
|
addMessageToConversation,
|
|
22
|
-
generateConversationId
|
|
22
|
+
generateConversationId
|
|
23
23
|
} from '../conversation-store.js';
|
|
24
|
+
import { logRequest, logStreamComplete, logResponse } from '../request-logger.js';
|
|
24
25
|
|
|
25
26
|
const router = Router();
|
|
26
27
|
|
|
@@ -56,13 +57,11 @@ router.post('/v1/messages', async (req, res) => {
|
|
|
56
57
|
|
|
57
58
|
const apiKey = getApiKey();
|
|
58
59
|
|
|
59
|
-
// Handle conversation persistence via metadata
|
|
60
|
-
let conversationId = metadata?.conversation_id;
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
createConversation(conversationId);
|
|
65
|
-
}
|
|
60
|
+
// Handle conversation persistence via metadata or generate new one
|
|
61
|
+
let conversationId = metadata?.conversation_id || generateConversationId();
|
|
62
|
+
const existingConv = getConversation(conversationId);
|
|
63
|
+
if (!existingConv) {
|
|
64
|
+
createConversation(conversationId);
|
|
66
65
|
}
|
|
67
66
|
|
|
68
67
|
// Map to You.com parameters
|
|
@@ -75,6 +74,35 @@ router.post('/v1/messages', async (req, res) => {
|
|
|
75
74
|
stream
|
|
76
75
|
});
|
|
77
76
|
|
|
77
|
+
// Get current user input for logging
|
|
78
|
+
const lastUserMsg = messages.filter(m => m.role === 'user').pop();
|
|
79
|
+
const currentInput = typeof lastUserMsg?.content === 'string'
|
|
80
|
+
? lastUserMsg.content
|
|
81
|
+
: lastUserMsg?.content?.filter(c => c.type === 'text').map(c => c.text).join('\n') || '';
|
|
82
|
+
|
|
83
|
+
// Build full messages for logging (including system prompt)
|
|
84
|
+
const fullMessages = [];
|
|
85
|
+
if (system) {
|
|
86
|
+
fullMessages.push({ role: 'system', content: system });
|
|
87
|
+
}
|
|
88
|
+
messages.forEach(m => {
|
|
89
|
+
const content = typeof m.content === 'string'
|
|
90
|
+
? m.content
|
|
91
|
+
: m.content?.filter(c => c.type === 'text').map(c => c.text).join('\n') || '';
|
|
92
|
+
fullMessages.push({ role: m.role, content });
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
logRequest({
|
|
96
|
+
endpoint: '/v1/messages (Anthropic)',
|
|
97
|
+
agent: youParams.agent,
|
|
98
|
+
model,
|
|
99
|
+
stream,
|
|
100
|
+
conversationId,
|
|
101
|
+
messageCount: fullMessages.length,
|
|
102
|
+
input: currentInput,
|
|
103
|
+
inputMessages: fullMessages
|
|
104
|
+
});
|
|
105
|
+
|
|
78
106
|
// Store user message
|
|
79
107
|
if (conversationId) {
|
|
80
108
|
const lastUserMsg = messages.filter(m => m.role === 'user').pop();
|
|
@@ -92,8 +120,8 @@ router.post('/v1/messages', async (req, res) => {
|
|
|
92
120
|
res.setHeader('Cache-Control', 'no-cache');
|
|
93
121
|
res.setHeader('Connection', 'keep-alive');
|
|
94
122
|
|
|
95
|
-
// Send message_start
|
|
96
|
-
res.write(createMessageStartEvent(model));
|
|
123
|
+
// Send message_start with conversation_id
|
|
124
|
+
res.write(createMessageStartEvent(model, conversationId));
|
|
97
125
|
|
|
98
126
|
// Send content_block_start
|
|
99
127
|
res.write(createContentBlockStartEvent(0));
|
|
@@ -104,53 +132,89 @@ router.post('/v1/messages', async (req, res) => {
|
|
|
104
132
|
let fullContent = '';
|
|
105
133
|
let buffer = '';
|
|
106
134
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
const
|
|
115
|
-
if (
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
135
|
+
// Use Web Streams API (ReadableStream)
|
|
136
|
+
const reader = response.body.getReader();
|
|
137
|
+
const decoder = new TextDecoder();
|
|
138
|
+
|
|
139
|
+
const processStream = async () => {
|
|
140
|
+
try {
|
|
141
|
+
while (true) {
|
|
142
|
+
const { done, value } = await reader.read();
|
|
143
|
+
if (done) break;
|
|
144
|
+
|
|
145
|
+
buffer += decoder.decode(value, { stream: true });
|
|
146
|
+
const lines = buffer.split('\n');
|
|
147
|
+
buffer = lines.pop() || '';
|
|
148
|
+
|
|
149
|
+
for (const line of lines) {
|
|
150
|
+
if (line.startsWith('data: ')) {
|
|
151
|
+
const data = line.slice(6);
|
|
152
|
+
if (data === '[DONE]') continue;
|
|
153
|
+
|
|
154
|
+
try {
|
|
155
|
+
const parsed = JSON.parse(data);
|
|
156
|
+
|
|
157
|
+
// Handle streaming delta format
|
|
158
|
+
if (parsed.type === 'response.output_text.delta' &&
|
|
159
|
+
parsed.response?.type === 'message.answer' &&
|
|
160
|
+
parsed.response?.delta) {
|
|
161
|
+
const newText = parsed.response.delta;
|
|
123
162
|
if (newText) {
|
|
124
|
-
fullContent
|
|
163
|
+
fullContent += newText;
|
|
125
164
|
res.write(createContentBlockDeltaEvent(newText, 0));
|
|
126
165
|
}
|
|
127
166
|
}
|
|
167
|
+
|
|
168
|
+
// Also handle full output format (non-streaming fallback)
|
|
169
|
+
if (parsed.output) {
|
|
170
|
+
for (const item of parsed.output) {
|
|
171
|
+
if (item.type === 'message.answer' && item.text) {
|
|
172
|
+
const newText = item.text.slice(fullContent.length);
|
|
173
|
+
if (newText) {
|
|
174
|
+
fullContent = item.text;
|
|
175
|
+
res.write(createContentBlockDeltaEvent(newText, 0));
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
} catch (e) {
|
|
181
|
+
// Skip invalid JSON
|
|
128
182
|
}
|
|
129
183
|
}
|
|
130
|
-
} catch (e) {
|
|
131
|
-
// Skip invalid JSON
|
|
132
184
|
}
|
|
133
185
|
}
|
|
134
|
-
}
|
|
135
|
-
});
|
|
136
186
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
}
|
|
187
|
+
// Store assistant response
|
|
188
|
+
if (conversationId && fullContent) {
|
|
189
|
+
addMessageToConversation(conversationId, 'assistant', fullContent);
|
|
190
|
+
}
|
|
142
191
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
192
|
+
logStreamComplete({
|
|
193
|
+
conversationId,
|
|
194
|
+
contentLength: fullContent.length,
|
|
195
|
+
messageCount: fullMessages.length + 1,
|
|
196
|
+
agent: youParams.agent,
|
|
197
|
+
stream: true,
|
|
198
|
+
responsePreview: fullContent,
|
|
199
|
+
inputMessages: [...fullMessages, { role: 'assistant', content: fullContent }]
|
|
200
|
+
});
|
|
149
201
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
202
|
+
// Send closing events
|
|
203
|
+
res.write(createContentBlockStopEvent(0));
|
|
204
|
+
res.write(createMessageDeltaEvent(Math.floor(fullContent.length / 4)));
|
|
205
|
+
res.write(createMessageStopEvent());
|
|
206
|
+
res.end();
|
|
207
|
+
} catch (error) {
|
|
208
|
+
console.error('Stream processing error:', error);
|
|
209
|
+
res.write(createContentBlockDeltaEvent(`Error: ${error.message}`, 0));
|
|
210
|
+
res.write(createContentBlockStopEvent(0));
|
|
211
|
+
res.write(createMessageDeltaEvent(0));
|
|
212
|
+
res.write(createMessageStopEvent());
|
|
213
|
+
res.end();
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
processStream();
|
|
154
218
|
|
|
155
219
|
} catch (error) {
|
|
156
220
|
console.error('Streaming error:', error);
|
|
@@ -166,18 +230,27 @@ router.post('/v1/messages', async (req, res) => {
|
|
|
166
230
|
const response = await callYouApi(apiKey, youParams);
|
|
167
231
|
const data = await response.json();
|
|
168
232
|
|
|
233
|
+
console.log('📥 You.com response received');
|
|
234
|
+
|
|
169
235
|
const anthropicResponse = convertToAnthropicResponse(data, model);
|
|
170
236
|
|
|
171
237
|
// Store assistant response
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
addMessageToConversation(conversationId, 'assistant', content);
|
|
176
|
-
}
|
|
238
|
+
const assistantContent = anthropicResponse.content[0]?.text || '';
|
|
239
|
+
if (conversationId && assistantContent) {
|
|
240
|
+
addMessageToConversation(conversationId, 'assistant', assistantContent);
|
|
177
241
|
// Add conversation_id to response
|
|
178
242
|
anthropicResponse.metadata = { conversation_id: conversationId };
|
|
179
243
|
}
|
|
180
244
|
|
|
245
|
+
logStreamComplete({
|
|
246
|
+
conversationId,
|
|
247
|
+
contentLength: assistantContent.length,
|
|
248
|
+
messageCount: fullMessages.length + 1,
|
|
249
|
+
agent: youParams.agent,
|
|
250
|
+
stream: false,
|
|
251
|
+
inputMessages: [...fullMessages, { role: 'assistant', content: assistantContent }]
|
|
252
|
+
});
|
|
253
|
+
|
|
181
254
|
res.json(anthropicResponse);
|
|
182
255
|
}
|
|
183
256
|
|
package/lib/routes/chat.js
CHANGED
|
@@ -5,19 +5,27 @@
|
|
|
5
5
|
import { Router } from 'express';
|
|
6
6
|
import { authenticate } from '../auth-middleware.js';
|
|
7
7
|
import { mapOpenAIToYouParams, convertToOpenAIResponse, createStreamChunk } from '../openai-mapper.js';
|
|
8
|
-
import { callYouApi
|
|
8
|
+
import { callYouApi } from '../api-client.js';
|
|
9
9
|
import {
|
|
10
10
|
getConversation,
|
|
11
|
-
createConversation,
|
|
12
11
|
addMessageToConversation,
|
|
13
12
|
generateConversationId
|
|
14
13
|
} from '../conversation-store.js';
|
|
14
|
+
import { logRequest, logStreamComplete } from '../request-logger.js';
|
|
15
15
|
|
|
16
16
|
const router = Router();
|
|
17
17
|
const API_KEY = process.env.YDC_API_KEY;
|
|
18
18
|
|
|
19
19
|
router.post('/v1/chat/completions', authenticate, async (req, res) => {
|
|
20
20
|
try {
|
|
21
|
+
// Debug: log raw request
|
|
22
|
+
console.log('📨 Raw request body:', JSON.stringify({
|
|
23
|
+
conversation_id: req.body.conversation_id,
|
|
24
|
+
model: req.body.model,
|
|
25
|
+
messages_count: req.body.messages?.length,
|
|
26
|
+
messages: req.body.messages?.map(m => ({ role: m.role, content: m.content?.substring(0, 50) }))
|
|
27
|
+
}, null, 2));
|
|
28
|
+
|
|
21
29
|
if (!API_KEY) {
|
|
22
30
|
return res.status(500).json({
|
|
23
31
|
error: {
|
|
@@ -69,17 +77,29 @@ router.post('/v1/chat/completions', authenticate, async (req, res) => {
|
|
|
69
77
|
|
|
70
78
|
const youParams = mapOpenAIToYouParams({ ...req.body, messages: fullMessages });
|
|
71
79
|
|
|
72
|
-
|
|
73
|
-
|
|
80
|
+
// Get current user input for logging
|
|
81
|
+
const currentUserMsg = fullMessages.filter(m => m.role === 'user').pop();
|
|
82
|
+
const currentInput = currentUserMsg?.content || '';
|
|
83
|
+
|
|
84
|
+
logRequest({
|
|
85
|
+
endpoint: '/v1/chat/completions (OpenAI)',
|
|
86
|
+
agent: youParams.agent,
|
|
87
|
+
model: req.body.model,
|
|
88
|
+
stream: req.body.stream || false,
|
|
89
|
+
conversationId,
|
|
90
|
+
messageCount: fullMessages.length,
|
|
91
|
+
input: currentInput,
|
|
92
|
+
inputMessages: fullMessages
|
|
93
|
+
});
|
|
74
94
|
|
|
75
95
|
const timeoutMs = youParams.timeout || (youParams.agent === 'advanced' ? 3000000 : 300000);
|
|
76
96
|
|
|
77
97
|
if (req.body.stream) {
|
|
78
98
|
const response = await callYouApi(API_KEY, { ...youParams, stream: true }, { timeout: timeoutMs });
|
|
79
|
-
await handleStreamingResponse(req, res, response, youParams, conversationId);
|
|
99
|
+
await handleStreamingResponse(req, res, response, youParams, conversationId, fullMessages);
|
|
80
100
|
} else {
|
|
81
101
|
const response = await callYouApi(API_KEY, youParams, { timeout: timeoutMs });
|
|
82
|
-
await handleNonStreamingResponse(req, res, response, conversationId);
|
|
102
|
+
await handleNonStreamingResponse(req, res, response, conversationId, fullMessages);
|
|
83
103
|
}
|
|
84
104
|
|
|
85
105
|
} catch (error) {
|
|
@@ -105,7 +125,7 @@ router.post('/v1/chat/completions', authenticate, async (req, res) => {
|
|
|
105
125
|
}
|
|
106
126
|
});
|
|
107
127
|
|
|
108
|
-
async function handleStreamingResponse(req, res, response, youParams, conversationId) {
|
|
128
|
+
async function handleStreamingResponse(req, res, response, youParams, conversationId, inputMessages = []) {
|
|
109
129
|
res.setHeader('Content-Type', 'text/event-stream');
|
|
110
130
|
res.setHeader('Cache-Control', 'no-cache');
|
|
111
131
|
res.setHeader('Connection', 'keep-alive');
|
|
@@ -120,7 +140,9 @@ async function handleStreamingResponse(req, res, response, youParams, conversati
|
|
|
120
140
|
const reader = response.body.getReader();
|
|
121
141
|
const decoder = new TextDecoder();
|
|
122
142
|
let buffer = '';
|
|
143
|
+
let fullContent = '';
|
|
123
144
|
const model = req.body.model || 'advanced';
|
|
145
|
+
const messageCount = req.body.messages?.length || 0;
|
|
124
146
|
const STREAM_TIMEOUT = youParams.timeout || (youParams.agent === 'advanced' ? 3000000 : 300000);
|
|
125
147
|
|
|
126
148
|
try {
|
|
@@ -159,6 +181,7 @@ async function handleStreamingResponse(req, res, response, youParams, conversati
|
|
|
159
181
|
res.end();
|
|
160
182
|
}, STREAM_TIMEOUT);
|
|
161
183
|
|
|
184
|
+
fullContent += data.response.delta;
|
|
162
185
|
const chunk = createStreamChunk(model, data.response.delta);
|
|
163
186
|
res.write(`data: ${JSON.stringify(chunk)}\n\n`);
|
|
164
187
|
}
|
|
@@ -170,6 +193,23 @@ async function handleStreamingResponse(req, res, response, youParams, conversati
|
|
|
170
193
|
}
|
|
171
194
|
|
|
172
195
|
clearTimeout(streamTimeout);
|
|
196
|
+
|
|
197
|
+
// Store assistant response
|
|
198
|
+
if (conversationId && fullContent) {
|
|
199
|
+
addMessageToConversation(conversationId, 'assistant', fullContent);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Log completion
|
|
203
|
+
logStreamComplete({
|
|
204
|
+
conversationId,
|
|
205
|
+
contentLength: fullContent.length,
|
|
206
|
+
messageCount: messageCount + 1,
|
|
207
|
+
agent: youParams.agent,
|
|
208
|
+
stream: true,
|
|
209
|
+
responsePreview: fullContent,
|
|
210
|
+
inputMessages: inputMessages
|
|
211
|
+
});
|
|
212
|
+
|
|
173
213
|
} catch (streamError) {
|
|
174
214
|
console.error('❌ Streaming error:', streamError);
|
|
175
215
|
res.write(`data: {"error": "Streaming error: ${streamError.message}"}\n\n`);
|
|
@@ -181,7 +221,7 @@ async function handleStreamingResponse(req, res, response, youParams, conversati
|
|
|
181
221
|
}
|
|
182
222
|
}
|
|
183
223
|
|
|
184
|
-
async function handleNonStreamingResponse(req, res, response, conversationId) {
|
|
224
|
+
async function handleNonStreamingResponse(req, res, response, conversationId, inputMessages = []) {
|
|
185
225
|
const data = await response.json();
|
|
186
226
|
console.log('📥 You.com response:', JSON.stringify(data, null, 2));
|
|
187
227
|
|
|
@@ -192,6 +232,16 @@ async function handleNonStreamingResponse(req, res, response, conversationId) {
|
|
|
192
232
|
addMessageToConversation(conversationId, 'assistant', assistantContent);
|
|
193
233
|
}
|
|
194
234
|
|
|
235
|
+
// Log completion
|
|
236
|
+
logStreamComplete({
|
|
237
|
+
conversationId,
|
|
238
|
+
contentLength: assistantContent?.length || 0,
|
|
239
|
+
messageCount: inputMessages.length + 1,
|
|
240
|
+
agent: req.body.model || 'advanced',
|
|
241
|
+
stream: false,
|
|
242
|
+
inputMessages: inputMessages
|
|
243
|
+
});
|
|
244
|
+
|
|
195
245
|
openaiResponse.conversation_id = conversationId;
|
|
196
246
|
res.json(openaiResponse);
|
|
197
247
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ydc-mcp-server",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.10",
|
|
4
4
|
"description": "MCP server for You.com Agents API - Express, Research, Advanced agents with multi-turn conversations, streaming, OpenAI and Anthropic/Claude API compatibility",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|