@nextclaw/nextclaw-ncp-runtime-adapter-hermes-http 0.2.16 → 0.3.0
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/hermes-http-adapter-events.utils.js +88 -0
- package/dist/hermes-http-adapter-events.utils.js.map +1 -0
- package/dist/hermes-http-adapter-message.utils.d.ts.map +1 -1
- package/dist/hermes-http-adapter-message.utils.js +28 -50
- package/dist/hermes-http-adapter-message.utils.js.map +1 -1
- package/dist/hermes-http-adapter.service.d.ts.map +1 -1
- package/dist/hermes-http-adapter.service.js +46 -80
- package/dist/hermes-http-adapter.service.js.map +1 -1
- package/dist/hermes-inline-tool-trace.utils.js +29 -0
- package/dist/hermes-inline-tool-trace.utils.js.map +1 -0
- package/package.json +4 -4
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { NcpEventType, createNcpEndpointEvent } from "@nextclaw/ncp";
|
|
2
|
+
//#region src/hermes-http-adapter-events.utils.ts
|
|
3
|
+
function createHermesRunHandle(run) {
|
|
4
|
+
const handle = {
|
|
5
|
+
sessionId: run.envelope.sessionId,
|
|
6
|
+
userMessageId: run.envelope.message.id,
|
|
7
|
+
assistantMessageId: run.messageId,
|
|
8
|
+
runId: run.runId
|
|
9
|
+
};
|
|
10
|
+
if (run.envelope.correlationId) handle.correlationId = run.envelope.correlationId;
|
|
11
|
+
return handle;
|
|
12
|
+
}
|
|
13
|
+
function createHermesMessageAcceptedEvent(run) {
|
|
14
|
+
return createNcpEndpointEvent({
|
|
15
|
+
type: NcpEventType.MessageAccepted,
|
|
16
|
+
payload: {
|
|
17
|
+
messageId: run.messageId,
|
|
18
|
+
correlationId: run.envelope.correlationId
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
function createHermesRunStartedEvent(params) {
|
|
23
|
+
const { run, startedAt } = params;
|
|
24
|
+
return createNcpEndpointEvent({
|
|
25
|
+
type: NcpEventType.RunStarted,
|
|
26
|
+
payload: {
|
|
27
|
+
sessionId: run.envelope.sessionId,
|
|
28
|
+
messageId: run.messageId,
|
|
29
|
+
runId: run.runId,
|
|
30
|
+
startedAt
|
|
31
|
+
}
|
|
32
|
+
}, startedAt);
|
|
33
|
+
}
|
|
34
|
+
function createHermesMessageCompletedEvent(params) {
|
|
35
|
+
const { message, metadata, run } = params;
|
|
36
|
+
return createNcpEndpointEvent({
|
|
37
|
+
type: NcpEventType.MessageCompleted,
|
|
38
|
+
payload: {
|
|
39
|
+
sessionId: run.envelope.sessionId,
|
|
40
|
+
message,
|
|
41
|
+
correlationId: run.envelope.correlationId,
|
|
42
|
+
metadata
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
function createHermesRunFinishedEvent(params) {
|
|
47
|
+
const { endedAt, run, startedAt } = params;
|
|
48
|
+
return createNcpEndpointEvent({
|
|
49
|
+
type: NcpEventType.RunFinished,
|
|
50
|
+
payload: {
|
|
51
|
+
sessionId: run.envelope.sessionId,
|
|
52
|
+
messageId: run.messageId,
|
|
53
|
+
runId: run.runId,
|
|
54
|
+
startedAt,
|
|
55
|
+
endedAt
|
|
56
|
+
}
|
|
57
|
+
}, endedAt);
|
|
58
|
+
}
|
|
59
|
+
function createHermesMessageFailedEvent(params) {
|
|
60
|
+
const { error, run } = params;
|
|
61
|
+
return createNcpEndpointEvent({
|
|
62
|
+
type: NcpEventType.MessageFailed,
|
|
63
|
+
payload: {
|
|
64
|
+
sessionId: run.envelope.sessionId,
|
|
65
|
+
messageId: run.messageId,
|
|
66
|
+
correlationId: run.envelope.correlationId,
|
|
67
|
+
error
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
function createHermesRunErrorEvent(params) {
|
|
72
|
+
const { endedAt, error, run, startedAt } = params;
|
|
73
|
+
return createNcpEndpointEvent({
|
|
74
|
+
type: NcpEventType.RunError,
|
|
75
|
+
payload: {
|
|
76
|
+
sessionId: run.envelope.sessionId,
|
|
77
|
+
messageId: run.messageId,
|
|
78
|
+
runId: run.runId,
|
|
79
|
+
error: error.message,
|
|
80
|
+
startedAt,
|
|
81
|
+
endedAt
|
|
82
|
+
}
|
|
83
|
+
}, endedAt);
|
|
84
|
+
}
|
|
85
|
+
//#endregion
|
|
86
|
+
export { createHermesMessageAcceptedEvent, createHermesMessageCompletedEvent, createHermesMessageFailedEvent, createHermesRunErrorEvent, createHermesRunFinishedEvent, createHermesRunHandle, createHermesRunStartedEvent };
|
|
87
|
+
|
|
88
|
+
//# sourceMappingURL=hermes-http-adapter-events.utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hermes-http-adapter-events.utils.js","names":[],"sources":["../src/hermes-http-adapter-events.utils.ts"],"sourcesContent":["import {\n createNcpEndpointEvent,\n NcpEventType,\n type NcpEndpointEvent,\n type NcpError,\n type NcpMessage,\n type NcpRunHandle,\n} from \"@nextclaw/ncp\";\nimport type { HermesHttpAdapterRun } from \"./hermes-http-adapter.types.js\";\n\nexport function createHermesRunHandle(run: HermesHttpAdapterRun): NcpRunHandle {\n const handle: NcpRunHandle = {\n sessionId: run.envelope.sessionId,\n userMessageId: run.envelope.message.id,\n assistantMessageId: run.messageId,\n runId: run.runId,\n };\n if (run.envelope.correlationId) {\n handle.correlationId = run.envelope.correlationId;\n }\n return handle;\n}\n\nexport function createHermesMessageAcceptedEvent(run: HermesHttpAdapterRun): NcpEndpointEvent {\n return createNcpEndpointEvent({\n type: NcpEventType.MessageAccepted,\n payload: {\n messageId: run.messageId,\n correlationId: run.envelope.correlationId,\n },\n });\n}\n\nexport function createHermesRunStartedEvent(params: {\n run: HermesHttpAdapterRun;\n startedAt: string;\n}): NcpEndpointEvent {\n const { run, startedAt } = params;\n return createNcpEndpointEvent({\n type: NcpEventType.RunStarted,\n payload: {\n sessionId: run.envelope.sessionId,\n messageId: run.messageId,\n runId: run.runId,\n startedAt,\n },\n }, startedAt);\n}\n\nexport function createHermesMessageCompletedEvent(params: {\n message: NcpMessage;\n metadata: Record<string, unknown>;\n run: HermesHttpAdapterRun;\n}): NcpEndpointEvent {\n const { message, metadata, run } = params;\n return createNcpEndpointEvent({\n type: NcpEventType.MessageCompleted,\n payload: {\n sessionId: run.envelope.sessionId,\n message,\n correlationId: run.envelope.correlationId,\n metadata,\n },\n });\n}\n\nexport function createHermesRunFinishedEvent(params: {\n endedAt: string;\n run: HermesHttpAdapterRun;\n startedAt: string;\n}): NcpEndpointEvent {\n const { endedAt, run, startedAt } = params;\n return createNcpEndpointEvent({\n type: NcpEventType.RunFinished,\n payload: {\n sessionId: run.envelope.sessionId,\n messageId: run.messageId,\n runId: run.runId,\n startedAt,\n endedAt,\n },\n }, endedAt);\n}\n\nexport function createHermesMessageFailedEvent(params: {\n error: NcpError;\n run: HermesHttpAdapterRun;\n}): NcpEndpointEvent {\n const { error, run } = params;\n return createNcpEndpointEvent({\n type: NcpEventType.MessageFailed,\n payload: {\n sessionId: run.envelope.sessionId,\n messageId: run.messageId,\n correlationId: run.envelope.correlationId,\n error,\n },\n });\n}\n\nexport function createHermesRunErrorEvent(params: {\n endedAt: string;\n error: NcpError;\n run: HermesHttpAdapterRun;\n startedAt: string;\n}): NcpEndpointEvent {\n const { endedAt, error, run, startedAt } = params;\n return createNcpEndpointEvent({\n type: NcpEventType.RunError,\n payload: {\n sessionId: run.envelope.sessionId,\n messageId: run.messageId,\n runId: run.runId,\n error: error.message,\n startedAt,\n endedAt,\n },\n }, endedAt);\n}\n"],"mappings":";;AAUA,SAAgB,sBAAsB,KAAyC;CAC7E,MAAM,SAAuB;EAC3B,WAAW,IAAI,SAAS;EACxB,eAAe,IAAI,SAAS,QAAQ;EACpC,oBAAoB,IAAI;EACxB,OAAO,IAAI;EACZ;AACD,KAAI,IAAI,SAAS,cACf,QAAO,gBAAgB,IAAI,SAAS;AAEtC,QAAO;;AAGT,SAAgB,iCAAiC,KAA6C;AAC5F,QAAO,uBAAuB;EAC5B,MAAM,aAAa;EACnB,SAAS;GACP,WAAW,IAAI;GACf,eAAe,IAAI,SAAS;GAC7B;EACF,CAAC;;AAGJ,SAAgB,4BAA4B,QAGvB;CACnB,MAAM,EAAE,KAAK,cAAc;AAC3B,QAAO,uBAAuB;EAC5B,MAAM,aAAa;EACnB,SAAS;GACP,WAAW,IAAI,SAAS;GACxB,WAAW,IAAI;GACf,OAAO,IAAI;GACX;GACD;EACF,EAAE,UAAU;;AAGf,SAAgB,kCAAkC,QAI7B;CACnB,MAAM,EAAE,SAAS,UAAU,QAAQ;AACnC,QAAO,uBAAuB;EAC5B,MAAM,aAAa;EACnB,SAAS;GACP,WAAW,IAAI,SAAS;GACxB;GACA,eAAe,IAAI,SAAS;GAC5B;GACD;EACF,CAAC;;AAGJ,SAAgB,6BAA6B,QAIxB;CACnB,MAAM,EAAE,SAAS,KAAK,cAAc;AACpC,QAAO,uBAAuB;EAC5B,MAAM,aAAa;EACnB,SAAS;GACP,WAAW,IAAI,SAAS;GACxB,WAAW,IAAI;GACf,OAAO,IAAI;GACX;GACA;GACD;EACF,EAAE,QAAQ;;AAGb,SAAgB,+BAA+B,QAG1B;CACnB,MAAM,EAAE,OAAO,QAAQ;AACvB,QAAO,uBAAuB;EAC5B,MAAM,aAAa;EACnB,SAAS;GACP,WAAW,IAAI,SAAS;GACxB,WAAW,IAAI;GACf,eAAe,IAAI,SAAS;GAC5B;GACD;EACF,CAAC;;AAGJ,SAAgB,0BAA0B,QAKrB;CACnB,MAAM,EAAE,SAAS,OAAO,KAAK,cAAc;AAC3C,QAAO,uBAAuB;EAC5B,MAAM,aAAa;EACnB,SAAS;GACP,WAAW,IAAI,SAAS;GACxB,WAAW,IAAI;GACf,OAAO,IAAI;GACX,OAAO,MAAM;GACb;GACA;GACD;EACF,EAAE,QAAQ"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hermes-http-adapter-message.utils.d.ts","names":[],"sources":["../src/hermes-http-adapter-message.utils.ts"],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"hermes-http-adapter-message.utils.d.ts","names":[],"sources":["../src/hermes-http-adapter-message.utils.ts"],"mappings":";;;;KA4CY,mBAAA;EACV,KAAA;EACA,MAAA;EACA,OAAA;EACA,OAAA,EAAS,MAAA;EACT,OAAA;AAAA;AAAA,iBAKc,uBAAA,CACd,QAAA,EAAU,kBAAA,GACT,mBAAA;AAAA,iBA0Ba,mBAAA,CAAoB,MAAA;EAClC,QAAA,EAAU,kBAAA;EACV,YAAA;AAAA,IACE,mBAAA;AAAA,iBAiBY,sBAAA,CAAuB,MAAA;EACrC,SAAA;EACA,SAAA;EACA,IAAA;EACA,SAAA;EACA,QAAA,GAAW,MAAA;AAAA,IACT,UAAA;AAAA,iBAkBY,+BAAA,CAAgC,MAAA;EAC9C,SAAA;EACA,SAAA;EACA,KAAA,EAAO,cAAA;EACP,SAAA;EACA,QAAA,GAAW,MAAA;AAAA,IACT,UAAA;AAAA,cAaS,6BAAA;EAAA,iBACM,KAAA;EAAA,iBACA,qBAAA;EAEjB,UAAA,GAAc,KAAA,EAAO,gBAAA;EA8CrB,QAAA;EAEA,UAAA,QAAiB,cAAA;EAAA,QAET,cAAA;EAAA,QAeA,mBAAA;EAAA,QAeA,sBAAA;EAAA,QAWA,wBAAA;EAAA,QAkCA,YAAA;EAAA,QAUA,YAAA;EAAA,QAKA,YAAA;AAAA;AAAA,cAYG,+BAAA;EAAA,QACH,iBAAA;EAAA,QACA,qBAAA;EAAA,QACA,aAAA;EAER,SAAA,GACE,IAAA,EAAM,+BAAA,EACN,MAAA,EAAQ,aAAA,CAAc,gBAAA,MACrB,cAAA,CAAe,gBAAA;EAAA,QAyCV,gBAAA;EAAA,QAwEA,sBAAA;EAAA,QAOA,yBAAA;EAAA,QAOA,kBAAA;EAAA,QASA,kBAAA;AAAA;AAAA,cAUG,8BAAA;EAAA,iBACM,UAAA;EAEjB,SAAA,GACE,IAAA,EAAM,8BAAA,EACN,MAAA,EAAQ,aAAA,CAAc,gBAAA,MACrB,cAAA,CAAe,gBAAA;EAAA,QAiBV,uBAAA;EAAA,QA+BA,gBAAA;EAAA,QAsCA,aAAA;EAAA,QAIA,sBAAA;EAAA,QAOA,kBAAA;EAAA,QASA,kBAAA;AAAA;AAAA,iBAUM,kBAAA,CAAmB,MAAA;EACjC,QAAA,EAAU,kBAAA;EACV,aAAA;AAAA;AAAA,iBAoBc,6BAAA,CAA8B,KAAA;AAAA,iBAuB9B,mBAAA,CAAoB,MAAA;EAClC,KAAA;EACA,OAAA;EACA,OAAA,GAAU,mBAAA;AAAA;AAAA,iBAcI,UAAA,CACd,KAAA,WACA,IAAA,EAAM,QAAA,WACL,QAAA;AAAA,iBAOa,aAAA,CAAc,KAAA,EAAO,gBAAA;AAAA,iBAIrB,eAAA,CAAgB,KAAA;EAAS,IAAA;EAAc,OAAA;AAAA"}
|
|
@@ -1,14 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { matchHermesInlineToolTrace } from "./hermes-inline-tool-trace.utils.js";
|
|
2
|
+
import { NcpAssistantTextStreamNormalizer, NcpEventType, createNcpEndpointEvent } from "@nextclaw/ncp";
|
|
2
3
|
//#region src/hermes-http-adapter-message.utils.ts
|
|
3
|
-
const HERMES_INLINE_TOOL_TRACE_PATTERNS = [{
|
|
4
|
-
icon: "🔎",
|
|
5
|
-
toolName: "search_files",
|
|
6
|
-
buildArgs: (rawArgs) => JSON.stringify({ pattern: rawArgs })
|
|
7
|
-
}, {
|
|
8
|
-
icon: "💻",
|
|
9
|
-
toolName: "terminal",
|
|
10
|
-
buildArgs: (rawArgs) => JSON.stringify({ command: rawArgs })
|
|
11
|
-
}];
|
|
12
4
|
function readMetadataString(metadata, key) {
|
|
13
5
|
const value = metadata?.[key];
|
|
14
6
|
if (typeof value !== "string") return;
|
|
@@ -236,49 +228,50 @@ var HermesInlineToolTraceTranslator = class {
|
|
|
236
228
|
};
|
|
237
229
|
flushPendingText = function* (params) {
|
|
238
230
|
if (!this.pendingTextBuffer) return;
|
|
231
|
+
const { flush, messageId, sessionId } = params;
|
|
239
232
|
const lastNewlineIndex = this.pendingTextBuffer.lastIndexOf("\n");
|
|
240
|
-
const flushableText =
|
|
233
|
+
const flushableText = flush ? this.pendingTextBuffer : lastNewlineIndex >= 0 ? this.pendingTextBuffer.slice(0, lastNewlineIndex + 1) : this.pendingTextBuffer.includes("`") ? "" : this.pendingTextBuffer;
|
|
241
234
|
if (!flushableText) return;
|
|
242
235
|
this.pendingTextBuffer = this.pendingTextBuffer.slice(flushableText.length);
|
|
243
236
|
for (const segment of splitIntoLineSegments(flushableText)) {
|
|
244
237
|
const inlineToolTrace = matchHermesInlineToolTrace(segment);
|
|
245
|
-
if (inlineToolTrace &&
|
|
238
|
+
if (inlineToolTrace && sessionId) {
|
|
246
239
|
const toolCallId = `hermes-inline-tool-${++this.toolCallCount}`;
|
|
247
|
-
yield {
|
|
240
|
+
yield createNcpEndpointEvent({
|
|
248
241
|
type: NcpEventType.MessageToolCallStart,
|
|
249
242
|
payload: {
|
|
250
|
-
sessionId
|
|
251
|
-
|
|
243
|
+
sessionId,
|
|
244
|
+
messageId,
|
|
252
245
|
toolCallId,
|
|
253
246
|
toolName: inlineToolTrace.toolName
|
|
254
247
|
}
|
|
255
|
-
};
|
|
256
|
-
yield {
|
|
248
|
+
});
|
|
249
|
+
yield createNcpEndpointEvent({
|
|
257
250
|
type: NcpEventType.MessageToolCallArgs,
|
|
258
251
|
payload: {
|
|
259
|
-
sessionId
|
|
252
|
+
sessionId,
|
|
260
253
|
toolCallId,
|
|
261
254
|
args: inlineToolTrace.args
|
|
262
255
|
}
|
|
263
|
-
};
|
|
264
|
-
yield {
|
|
256
|
+
});
|
|
257
|
+
yield createNcpEndpointEvent({
|
|
265
258
|
type: NcpEventType.MessageToolCallEnd,
|
|
266
259
|
payload: {
|
|
267
|
-
sessionId
|
|
260
|
+
sessionId,
|
|
268
261
|
toolCallId
|
|
269
262
|
}
|
|
270
|
-
};
|
|
263
|
+
});
|
|
271
264
|
continue;
|
|
272
265
|
}
|
|
273
|
-
if (!segment || !
|
|
274
|
-
yield {
|
|
266
|
+
if (!segment || !sessionId || !messageId) continue;
|
|
267
|
+
yield createNcpEndpointEvent({
|
|
275
268
|
type: NcpEventType.MessageTextDelta,
|
|
276
269
|
payload: {
|
|
277
|
-
sessionId
|
|
278
|
-
messageId
|
|
270
|
+
sessionId,
|
|
271
|
+
messageId,
|
|
279
272
|
delta: segment
|
|
280
273
|
}
|
|
281
|
-
};
|
|
274
|
+
});
|
|
282
275
|
}
|
|
283
276
|
};
|
|
284
277
|
shouldFlushPendingText = (event) => event.type === NcpEventType.MessageTextEnd || event.type === NcpEventType.MessageCompleted || event.type === NcpEventType.MessageFailed || event.type === NcpEventType.RunFinished || event.type === NcpEventType.RunError;
|
|
@@ -310,24 +303,24 @@ var HermesReasoningDeltaTranslator = class {
|
|
|
310
303
|
for (const segment of segments) {
|
|
311
304
|
if (!segment.text) continue;
|
|
312
305
|
if (segment.type === "reasoning") {
|
|
313
|
-
yield {
|
|
306
|
+
yield createNcpEndpointEvent({
|
|
314
307
|
type: NcpEventType.MessageReasoningDelta,
|
|
315
308
|
payload: {
|
|
316
309
|
sessionId: event.payload.sessionId,
|
|
317
310
|
messageId: event.payload.messageId,
|
|
318
311
|
delta: segment.text
|
|
319
312
|
}
|
|
320
|
-
};
|
|
313
|
+
});
|
|
321
314
|
continue;
|
|
322
315
|
}
|
|
323
|
-
yield {
|
|
316
|
+
yield createNcpEndpointEvent({
|
|
324
317
|
type: NcpEventType.MessageTextDelta,
|
|
325
318
|
payload: {
|
|
326
319
|
sessionId: event.payload.sessionId,
|
|
327
320
|
messageId: event.payload.messageId,
|
|
328
321
|
delta: segment.text
|
|
329
322
|
}
|
|
330
|
-
};
|
|
323
|
+
});
|
|
331
324
|
}
|
|
332
325
|
};
|
|
333
326
|
flushPendingText = function* (event) {
|
|
@@ -341,24 +334,24 @@ var HermesReasoningDeltaTranslator = class {
|
|
|
341
334
|
for (const segment of segments) {
|
|
342
335
|
if (!segment.text) continue;
|
|
343
336
|
if (segment.type === "reasoning") {
|
|
344
|
-
yield {
|
|
337
|
+
yield createNcpEndpointEvent({
|
|
345
338
|
type: NcpEventType.MessageReasoningDelta,
|
|
346
339
|
payload: {
|
|
347
340
|
sessionId,
|
|
348
341
|
messageId,
|
|
349
342
|
delta: segment.text
|
|
350
343
|
}
|
|
351
|
-
};
|
|
344
|
+
});
|
|
352
345
|
continue;
|
|
353
346
|
}
|
|
354
|
-
yield {
|
|
347
|
+
yield createNcpEndpointEvent({
|
|
355
348
|
type: NcpEventType.MessageTextDelta,
|
|
356
349
|
payload: {
|
|
357
350
|
sessionId,
|
|
358
351
|
messageId,
|
|
359
352
|
delta: segment.text
|
|
360
353
|
}
|
|
361
|
-
};
|
|
354
|
+
});
|
|
362
355
|
}
|
|
363
356
|
};
|
|
364
357
|
flushSegments = () => {
|
|
@@ -435,21 +428,6 @@ function extractMessageText(message) {
|
|
|
435
428
|
function splitIntoLineSegments(text) {
|
|
436
429
|
return text.match(/[^\n]*\n|[^\n]+$/gu) ?? [];
|
|
437
430
|
}
|
|
438
|
-
function matchHermesInlineToolTrace(segment) {
|
|
439
|
-
const trimmed = segment.trim();
|
|
440
|
-
if (!trimmed.startsWith("`") || !trimmed.endsWith("`")) return null;
|
|
441
|
-
const body = trimmed.slice(1, -1).trim();
|
|
442
|
-
for (const candidate of HERMES_INLINE_TOOL_TRACE_PATTERNS) {
|
|
443
|
-
if (!body.startsWith(candidate.icon)) continue;
|
|
444
|
-
const rawArgs = body.slice(candidate.icon.length).trim();
|
|
445
|
-
if (!rawArgs) return null;
|
|
446
|
-
return {
|
|
447
|
-
toolName: candidate.toolName,
|
|
448
|
-
args: candidate.buildArgs(rawArgs)
|
|
449
|
-
};
|
|
450
|
-
}
|
|
451
|
-
return null;
|
|
452
|
-
}
|
|
453
431
|
function normalizeRole(role) {
|
|
454
432
|
if (role === "assistant" || role === "system") return role;
|
|
455
433
|
return "user";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hermes-http-adapter-message.utils.js","names":[],"sources":["../src/hermes-http-adapter-message.utils.ts"],"sourcesContent":["import {\n NcpAssistantTextStreamNormalizer,\n type NcpEndpointEvent,\n type NcpError,\n type NcpMessage,\n type NcpMessagePart,\n type NcpRequestEnvelope,\n type NcpToolInvocationPart,\n NcpEventType,\n} from \"@nextclaw/ncp\";\nimport type { HermesOpenAIMessage } from \"./hermes-http-adapter.types.js\";\n\ntype HermesInlineToolTrace = {\n toolName: string;\n args: string;\n};\n\nconst HERMES_INLINE_TOOL_TRACE_PATTERNS: Array<{\n icon: string;\n toolName: string;\n buildArgs: (rawArgs: string) => string;\n}> = [\n {\n icon: \"🔎\",\n toolName: \"search_files\",\n buildArgs: (rawArgs) => JSON.stringify({ pattern: rawArgs }),\n },\n {\n icon: \"💻\",\n toolName: \"terminal\",\n buildArgs: (rawArgs) => JSON.stringify({ command: rawArgs }),\n },\n];\n\nfunction readMetadataString(\n metadata: Record<string, unknown> | undefined,\n key: string,\n): string | undefined {\n const value = metadata?.[key];\n if (typeof value !== \"string\") {\n return undefined;\n }\n const trimmed = value.trim();\n return trimmed.length > 0 ? trimmed : undefined;\n}\n\nfunction readStringRecord(value: unknown): Record<string, string> | undefined {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return undefined;\n }\n const out: Record<string, string> = {};\n for (const [entryKey, entryValue] of Object.entries(value)) {\n if (typeof entryValue !== \"string\") {\n continue;\n }\n const normalized = entryValue.trim();\n if (!normalized) {\n continue;\n }\n out[entryKey] = normalized;\n }\n return Object.keys(out).length > 0 ? out : undefined;\n}\n\nexport type HermesProviderRoute = {\n model: string;\n apiKey?: string;\n apiBase?: string;\n headers: Record<string, string>;\n apiMode?: \"chat_completions\" | \"codex_responses\" | \"anthropic_messages\";\n};\n\nconst NARP_API_MODE_HEADER = \"x-nextclaw-narp-api-mode\";\n\nexport function readHermesProviderRoute(\n envelope: NcpRequestEnvelope,\n): HermesProviderRoute | undefined {\n const route = envelope.providerRoute;\n if (!route || typeof route !== \"object\" || Array.isArray(route)) {\n return undefined;\n }\n const routeRecord = route as Record<string, unknown>;\n\n const model =\n readMetadataString(routeRecord, \"model\") ??\n readMetadataString(routeRecord, \"providerLocalModel\");\n if (!model) {\n return undefined;\n }\n\n return {\n model,\n apiKey: readMetadataString(routeRecord, \"apiKey\"),\n apiBase: readMetadataString(routeRecord, \"apiBase\"),\n ...extractRuntimeHeaders(\n readStringRecord(routeRecord.headers) ??\n readStringRecord(routeRecord.extraHeaders) ??\n {},\n ),\n };\n}\n\nexport function buildHermesMessages(params: {\n envelope: NcpRequestEnvelope;\n systemPrompt?: string;\n}): HermesOpenAIMessage[] {\n const { envelope, systemPrompt } = params;\n const messages: HermesOpenAIMessage[] = [];\n if (systemPrompt) {\n messages.push({\n role: \"system\",\n content: systemPrompt,\n });\n }\n const content = extractMessageText(envelope.message);\n messages.push({\n role: normalizeRole(envelope.message.role),\n content,\n });\n return messages;\n}\n\nexport function createAssistantMessage(params: {\n sessionId: string;\n messageId: string;\n text: string;\n timestamp: string;\n metadata?: Record<string, unknown>;\n}): NcpMessage {\n const { sessionId, messageId, text, timestamp, metadata } = params;\n return {\n id: messageId,\n sessionId,\n role: \"assistant\",\n status: \"final\",\n parts: [\n {\n type: \"text\",\n text,\n },\n ],\n timestamp,\n ...(metadata ? { metadata } : {}),\n };\n}\n\nexport function createAssistantMessageFromParts(params: {\n sessionId: string;\n messageId: string;\n parts: NcpMessagePart[];\n timestamp: string;\n metadata?: Record<string, unknown>;\n}): NcpMessage {\n const { sessionId, messageId, parts, timestamp, metadata } = params;\n return {\n id: messageId,\n sessionId,\n role: \"assistant\",\n status: \"final\",\n parts: structuredClone(parts),\n timestamp,\n ...(metadata ? { metadata } : {}),\n };\n}\n\nexport class HermesAssistantEventCollector {\n private readonly parts: NcpMessagePart[] = [];\n private readonly toolPartIndexByCallId = new Map<string, number>();\n\n applyEvent = (event: NcpEndpointEvent): void => {\n switch (event.type) {\n case NcpEventType.MessageTextDelta:\n this.appendTextPart(event.payload.delta);\n return;\n case NcpEventType.MessageReasoningDelta:\n this.appendReasoningPart(event.payload.delta);\n return;\n case NcpEventType.MessageToolCallStart:\n this.upsertToolInvocationPart({\n type: \"tool-invocation\",\n toolCallId: event.payload.toolCallId,\n toolName: event.payload.toolName,\n state: \"partial-call\",\n args: \"\",\n });\n return;\n case NcpEventType.MessageToolCallArgsDelta:\n this.applyToolCallArgsDelta(\n event.payload.toolCallId,\n event.payload.delta,\n );\n return;\n case NcpEventType.MessageToolCallArgs:\n this.upsertToolInvocationPart({\n type: \"tool-invocation\",\n toolCallId: event.payload.toolCallId,\n toolName: this.readToolName(event.payload.toolCallId),\n state: \"partial-call\",\n args: event.payload.args,\n });\n return;\n case NcpEventType.MessageToolCallEnd:\n this.upsertToolInvocationPart({\n type: \"tool-invocation\",\n toolCallId: event.payload.toolCallId,\n toolName: this.readToolName(event.payload.toolCallId),\n state: \"call\",\n args: this.readToolArgs(event.payload.toolCallId),\n });\n return;\n default:\n return;\n }\n };\n\n hasParts = (): boolean => this.parts.length > 0;\n\n buildParts = (): NcpMessagePart[] => structuredClone(this.parts);\n\n private appendTextPart = (delta: string): void => {\n if (!delta) {\n return;\n }\n const lastPart = this.parts.at(-1);\n if (lastPart?.type === \"text\") {\n lastPart.text = `${lastPart.text}${delta}`;\n return;\n }\n this.parts.push({\n type: \"text\",\n text: delta,\n });\n };\n\n private appendReasoningPart = (delta: string): void => {\n if (!delta) {\n return;\n }\n const lastPart = this.parts.at(-1);\n if (lastPart?.type === \"reasoning\") {\n lastPart.text = `${lastPart.text}${delta}`;\n return;\n }\n this.parts.push({\n type: \"reasoning\",\n text: delta,\n });\n };\n\n private applyToolCallArgsDelta = (toolCallId: string, delta: string): void => {\n const currentArgs = this.readToolArgs(toolCallId);\n this.upsertToolInvocationPart({\n type: \"tool-invocation\",\n toolCallId,\n toolName: this.readToolName(toolCallId),\n state: \"partial-call\",\n args: `${currentArgs}${delta}`,\n });\n };\n\n private upsertToolInvocationPart = (\n nextPart: NcpToolInvocationPart,\n ): void => {\n const normalizedToolCallId = nextPart.toolCallId?.trim();\n if (!normalizedToolCallId) {\n this.parts.push({\n ...nextPart,\n });\n return;\n }\n\n const existingIndex = this.toolPartIndexByCallId.get(normalizedToolCallId);\n if (typeof existingIndex === \"number\") {\n const existingPart = this.parts[existingIndex];\n if (existingPart?.type !== \"tool-invocation\") {\n return;\n }\n this.parts[existingIndex] = {\n ...existingPart,\n ...nextPart,\n toolCallId: normalizedToolCallId,\n toolName: nextPart.toolName || existingPart.toolName,\n args: nextPart.args ?? existingPart.args,\n };\n return;\n }\n\n this.toolPartIndexByCallId.set(normalizedToolCallId, this.parts.length);\n this.parts.push({\n ...nextPart,\n toolCallId: normalizedToolCallId,\n });\n };\n\n private readToolArgs = (toolCallId: string): string => {\n const part = this.findToolPart(toolCallId);\n if (!part) {\n return \"\";\n }\n return typeof part.args === \"string\"\n ? part.args\n : JSON.stringify(part.args ?? \"\");\n };\n\n private readToolName = (toolCallId: string): string => {\n const part = this.findToolPart(toolCallId);\n return part?.toolName ?? \"unknown\";\n };\n\n private findToolPart = (\n toolCallId: string,\n ): NcpToolInvocationPart | null => {\n const existingIndex = this.toolPartIndexByCallId.get(toolCallId);\n if (typeof existingIndex !== \"number\") {\n return null;\n }\n const part = this.parts[existingIndex];\n return part?.type === \"tool-invocation\" ? part : null;\n };\n}\n\nexport class HermesInlineToolTraceTranslator {\n private pendingTextBuffer = \"\";\n private sawStructuredToolCall = false;\n private toolCallCount = 0;\n\n translate = async function* (\n this: HermesInlineToolTraceTranslator,\n events: AsyncIterable<NcpEndpointEvent>,\n ): AsyncGenerator<NcpEndpointEvent> {\n for await (const event of events) {\n if (this.isStructuredToolCallEvent(event)) {\n this.sawStructuredToolCall = true;\n yield* this.flushPendingText({\n sessionId: this.readEventSessionId(event),\n messageId: this.readEventMessageId(event),\n flush: true,\n });\n yield event;\n continue;\n }\n\n if (\n !this.sawStructuredToolCall &&\n event.type === NcpEventType.MessageTextDelta\n ) {\n this.pendingTextBuffer += event.payload.delta;\n yield* this.flushPendingText({\n sessionId: event.payload.sessionId,\n messageId: event.payload.messageId,\n flush: false,\n });\n continue;\n }\n\n if (\n !this.sawStructuredToolCall &&\n this.shouldFlushPendingText(event)\n ) {\n yield* this.flushPendingText({\n sessionId: this.readEventSessionId(event),\n messageId: this.readEventMessageId(event),\n flush: true,\n });\n }\n\n yield event;\n }\n };\n\n private flushPendingText = function* (\n this: HermesInlineToolTraceTranslator,\n params: {\n sessionId?: string;\n messageId?: string;\n flush: boolean;\n },\n ): Generator<NcpEndpointEvent> {\n if (!this.pendingTextBuffer) {\n return;\n }\n\n const lastNewlineIndex = this.pendingTextBuffer.lastIndexOf(\"\\n\");\n const flushableText =\n params.flush\n ? this.pendingTextBuffer\n : lastNewlineIndex >= 0\n ? this.pendingTextBuffer.slice(0, lastNewlineIndex + 1)\n : this.pendingTextBuffer.includes(\"`\")\n ? \"\"\n : this.pendingTextBuffer;\n if (!flushableText) {\n return;\n }\n\n this.pendingTextBuffer = this.pendingTextBuffer.slice(flushableText.length);\n for (const segment of splitIntoLineSegments(flushableText)) {\n const inlineToolTrace = matchHermesInlineToolTrace(segment);\n if (inlineToolTrace && params.sessionId) {\n const toolCallId = `hermes-inline-tool-${++this.toolCallCount}`;\n yield {\n type: NcpEventType.MessageToolCallStart,\n payload: {\n sessionId: params.sessionId,\n ...(params.messageId ? { messageId: params.messageId } : {}),\n toolCallId,\n toolName: inlineToolTrace.toolName,\n },\n };\n yield {\n type: NcpEventType.MessageToolCallArgs,\n payload: {\n sessionId: params.sessionId,\n toolCallId,\n args: inlineToolTrace.args,\n },\n };\n yield {\n type: NcpEventType.MessageToolCallEnd,\n payload: {\n sessionId: params.sessionId,\n toolCallId,\n },\n };\n continue;\n }\n\n if (!segment || !params.sessionId || !params.messageId) {\n continue;\n }\n yield {\n type: NcpEventType.MessageTextDelta,\n payload: {\n sessionId: params.sessionId,\n messageId: params.messageId,\n delta: segment,\n },\n };\n }\n };\n\n private shouldFlushPendingText = (event: NcpEndpointEvent): boolean =>\n event.type === NcpEventType.MessageTextEnd ||\n event.type === NcpEventType.MessageCompleted ||\n event.type === NcpEventType.MessageFailed ||\n event.type === NcpEventType.RunFinished ||\n event.type === NcpEventType.RunError;\n\n private isStructuredToolCallEvent = (event: NcpEndpointEvent): boolean =>\n event.type === NcpEventType.MessageToolCallStart ||\n event.type === NcpEventType.MessageToolCallArgs ||\n event.type === NcpEventType.MessageToolCallArgsDelta ||\n event.type === NcpEventType.MessageToolCallEnd ||\n event.type === NcpEventType.MessageToolCallResult;\n\n private readEventSessionId = (event: NcpEndpointEvent): string | undefined => {\n if (!(\"payload\" in event) || !event.payload || typeof event.payload !== \"object\") {\n return undefined;\n }\n return \"sessionId\" in event.payload && typeof event.payload.sessionId === \"string\"\n ? event.payload.sessionId\n : undefined;\n };\n\n private readEventMessageId = (event: NcpEndpointEvent): string | undefined => {\n if (!(\"payload\" in event) || !event.payload || typeof event.payload !== \"object\") {\n return undefined;\n }\n return \"messageId\" in event.payload && typeof event.payload.messageId === \"string\"\n ? event.payload.messageId\n : undefined;\n };\n}\n\nexport class HermesReasoningDeltaTranslator {\n private readonly normalizer = new NcpAssistantTextStreamNormalizer(\"think-tags\");\n\n translate = async function* (\n this: HermesReasoningDeltaTranslator,\n events: AsyncIterable<NcpEndpointEvent>,\n ): AsyncGenerator<NcpEndpointEvent> {\n for await (const event of events) {\n if (event.type === NcpEventType.MessageTextDelta) {\n yield* this.emitNormalizedTextDelta(event);\n continue;\n }\n\n if (this.shouldFlushPendingText(event)) {\n yield* this.flushPendingText(event);\n }\n\n yield event;\n }\n\n this.flushSegments();\n };\n\n private emitNormalizedTextDelta = function* (\n this: HermesReasoningDeltaTranslator,\n event: Extract<NcpEndpointEvent, { type: NcpEventType.MessageTextDelta }>,\n ): Generator<NcpEndpointEvent> {\n const segments = this.normalizer.push(event.payload.delta);\n for (const segment of segments) {\n if (!segment.text) {\n continue;\n }\n if (segment.type === \"reasoning\") {\n yield {\n type: NcpEventType.MessageReasoningDelta,\n payload: {\n sessionId: event.payload.sessionId,\n messageId: event.payload.messageId,\n delta: segment.text,\n },\n };\n continue;\n }\n yield {\n type: NcpEventType.MessageTextDelta,\n payload: {\n sessionId: event.payload.sessionId,\n messageId: event.payload.messageId,\n delta: segment.text,\n },\n };\n }\n };\n\n private flushPendingText = function* (\n this: HermesReasoningDeltaTranslator,\n event: NcpEndpointEvent,\n ): Generator<NcpEndpointEvent> {\n const sessionId = this.readEventSessionId(event);\n const messageId = this.readEventMessageId(event);\n if (!sessionId || !messageId) {\n this.flushSegments();\n return;\n }\n\n const segments = this.normalizer.finish();\n for (const segment of segments) {\n if (!segment.text) {\n continue;\n }\n if (segment.type === \"reasoning\") {\n yield {\n type: NcpEventType.MessageReasoningDelta,\n payload: {\n sessionId,\n messageId,\n delta: segment.text,\n },\n };\n continue;\n }\n yield {\n type: NcpEventType.MessageTextDelta,\n payload: {\n sessionId,\n messageId,\n delta: segment.text,\n },\n };\n }\n };\n\n private flushSegments = (): void => {\n this.normalizer.finish();\n };\n\n private shouldFlushPendingText = (event: NcpEndpointEvent): boolean =>\n event.type === NcpEventType.MessageTextEnd ||\n event.type === NcpEventType.MessageCompleted ||\n event.type === NcpEventType.MessageFailed ||\n event.type === NcpEventType.RunFinished ||\n event.type === NcpEventType.RunError;\n\n private readEventSessionId = (event: NcpEndpointEvent): string | undefined => {\n if (!(\"payload\" in event) || !event.payload || typeof event.payload !== \"object\") {\n return undefined;\n }\n return \"sessionId\" in event.payload && typeof event.payload.sessionId === \"string\"\n ? event.payload.sessionId\n : undefined;\n };\n\n private readEventMessageId = (event: NcpEndpointEvent): string | undefined => {\n if (!(\"payload\" in event) || !event.payload || typeof event.payload !== \"object\") {\n return undefined;\n }\n return \"messageId\" in event.payload && typeof event.payload.messageId === \"string\"\n ? event.payload.messageId\n : undefined;\n };\n}\n\nexport function resolveHermesModel(params: {\n envelope: NcpRequestEnvelope;\n fallbackModel: string;\n}): string {\n const { envelope, fallbackModel } = params;\n const providerRoute = readHermesProviderRoute(envelope);\n const metadata =\n envelope.metadata &&\n typeof envelope.metadata === \"object\" &&\n !Array.isArray(envelope.metadata)\n ? (envelope.metadata as Record<string, unknown>)\n : undefined;\n\n return (\n providerRoute?.model ??\n readMetadataString(metadata, \"preferred_model\") ??\n readMetadataString(metadata, \"preferredModel\") ??\n readMetadataString(metadata, \"model\") ??\n fallbackModel\n );\n}\n\nexport function normalizeHermesRequestedModel(model: string): string {\n const trimmed = model.trim();\n if (!trimmed) {\n return trimmed;\n }\n\n const slashIndex = trimmed.indexOf(\"/\");\n if (slashIndex <= 0) {\n return trimmed;\n }\n\n const suffix = trimmed.slice(slashIndex + 1).trim();\n if (!suffix) {\n return trimmed;\n }\n\n if (suffix.includes(\":\")) {\n return suffix;\n }\n\n return trimmed;\n}\n\nexport function inferHermesProvider(params: {\n model: string;\n apiBase?: string | null;\n apiMode?: HermesProviderRoute[\"apiMode\"];\n}): string | undefined {\n if (params.apiMode === \"anthropic_messages\") {\n return \"anthropic\";\n }\n const model = params.model.trim().toLowerCase();\n const hostname = readHostname(params.apiBase);\n\n if (hostname.includes(\"anthropic.com\") || model.startsWith(\"claude\")) {\n return \"anthropic\";\n }\n return \"openai\";\n}\n\nexport function toNcpError(\n error: unknown,\n code: NcpError[\"code\"],\n): NcpError {\n return {\n code,\n message: error instanceof Error ? error.message : String(error),\n };\n}\n\nexport function toNcpSseFrame(event: NcpEndpointEvent): string {\n return `event: ncp-event\\ndata: ${JSON.stringify(event)}\\n\\n`;\n}\n\nexport function toErrorSseFrame(error: { code: string; message: string }): string {\n return `event: error\\ndata: ${JSON.stringify(error)}\\n\\n`;\n}\n\nfunction readHostname(value: string | null | undefined): string {\n if (!value) {\n return \"\";\n }\n try {\n return new URL(value).hostname.trim().toLowerCase();\n } catch {\n return \"\";\n }\n}\n\nfunction extractRuntimeHeaders(\n headers: Record<string, string>,\n): Pick<HermesProviderRoute, \"headers\" | \"apiMode\"> {\n const nextHeaders = { ...headers };\n const apiMode = nextHeaders[NARP_API_MODE_HEADER] as HermesProviderRoute[\"apiMode\"] | undefined;\n delete nextHeaders[NARP_API_MODE_HEADER];\n return {\n headers: nextHeaders,\n ...(apiMode ? { apiMode } : {}),\n };\n}\n\nfunction extractMessageText(message: NcpMessage): string {\n const text = message.parts\n .map((part) => {\n if (part.type === \"text\" || part.type === \"reasoning\" || part.type === \"rich-text\") {\n return part.text;\n }\n return \"\";\n })\n .join(\"\\n\")\n .trim();\n return text.length > 0 ? text : \"[empty message]\";\n}\n\nfunction splitIntoLineSegments(text: string): string[] {\n return text.match(/[^\\n]*\\n|[^\\n]+$/gu) ?? [];\n}\n\nfunction matchHermesInlineToolTrace(segment: string): HermesInlineToolTrace | null {\n const trimmed = segment.trim();\n if (!trimmed.startsWith(\"`\") || !trimmed.endsWith(\"`\")) {\n return null;\n }\n\n const body = trimmed.slice(1, -1).trim();\n for (const candidate of HERMES_INLINE_TOOL_TRACE_PATTERNS) {\n if (!body.startsWith(candidate.icon)) {\n continue;\n }\n const rawArgs = body.slice(candidate.icon.length).trim();\n if (!rawArgs) {\n return null;\n }\n return {\n toolName: candidate.toolName,\n args: candidate.buildArgs(rawArgs),\n };\n }\n\n return null;\n}\n\nfunction normalizeRole(role: NcpMessage[\"role\"]): HermesOpenAIMessage[\"role\"] {\n if (role === \"assistant\" || role === \"system\") {\n return role;\n }\n return \"user\";\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"hermes-http-adapter-message.utils.js","names":[],"sources":["../src/hermes-http-adapter-message.utils.ts"],"sourcesContent":["import {\n createNcpEndpointEvent,\n NcpAssistantTextStreamNormalizer,\n type NcpEndpointEvent,\n type NcpError,\n type NcpMessage,\n type NcpMessagePart,\n type NcpRequestEnvelope,\n type NcpToolInvocationPart,\n NcpEventType,\n} from \"@nextclaw/ncp\";\nimport type { HermesOpenAIMessage } from \"./hermes-http-adapter.types.js\";\nimport { matchHermesInlineToolTrace } from \"./hermes-inline-tool-trace.utils.js\";\n\nfunction readMetadataString(\n metadata: Record<string, unknown> | undefined,\n key: string,\n): string | undefined {\n const value = metadata?.[key];\n if (typeof value !== \"string\") {\n return undefined;\n }\n const trimmed = value.trim();\n return trimmed.length > 0 ? trimmed : undefined;\n}\n\nfunction readStringRecord(value: unknown): Record<string, string> | undefined {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return undefined;\n }\n const out: Record<string, string> = {};\n for (const [entryKey, entryValue] of Object.entries(value)) {\n if (typeof entryValue !== \"string\") {\n continue;\n }\n const normalized = entryValue.trim();\n if (!normalized) {\n continue;\n }\n out[entryKey] = normalized;\n }\n return Object.keys(out).length > 0 ? out : undefined;\n}\n\nexport type HermesProviderRoute = {\n model: string;\n apiKey?: string;\n apiBase?: string;\n headers: Record<string, string>;\n apiMode?: \"chat_completions\" | \"codex_responses\" | \"anthropic_messages\";\n};\n\nconst NARP_API_MODE_HEADER = \"x-nextclaw-narp-api-mode\";\n\nexport function readHermesProviderRoute(\n envelope: NcpRequestEnvelope,\n): HermesProviderRoute | undefined {\n const route = envelope.providerRoute;\n if (!route || typeof route !== \"object\" || Array.isArray(route)) {\n return undefined;\n }\n const routeRecord = route as Record<string, unknown>;\n\n const model =\n readMetadataString(routeRecord, \"model\") ??\n readMetadataString(routeRecord, \"providerLocalModel\");\n if (!model) {\n return undefined;\n }\n\n return {\n model,\n apiKey: readMetadataString(routeRecord, \"apiKey\"),\n apiBase: readMetadataString(routeRecord, \"apiBase\"),\n ...extractRuntimeHeaders(\n readStringRecord(routeRecord.headers) ??\n readStringRecord(routeRecord.extraHeaders) ??\n {},\n ),\n };\n}\n\nexport function buildHermesMessages(params: {\n envelope: NcpRequestEnvelope;\n systemPrompt?: string;\n}): HermesOpenAIMessage[] {\n const { envelope, systemPrompt } = params;\n const messages: HermesOpenAIMessage[] = [];\n if (systemPrompt) {\n messages.push({\n role: \"system\",\n content: systemPrompt,\n });\n }\n const content = extractMessageText(envelope.message);\n messages.push({\n role: normalizeRole(envelope.message.role),\n content,\n });\n return messages;\n}\n\nexport function createAssistantMessage(params: {\n sessionId: string;\n messageId: string;\n text: string;\n timestamp: string;\n metadata?: Record<string, unknown>;\n}): NcpMessage {\n const { sessionId, messageId, text, timestamp, metadata } = params;\n return {\n id: messageId,\n sessionId,\n role: \"assistant\",\n status: \"final\",\n parts: [\n {\n type: \"text\",\n text,\n },\n ],\n timestamp,\n ...(metadata ? { metadata } : {}),\n };\n}\n\nexport function createAssistantMessageFromParts(params: {\n sessionId: string;\n messageId: string;\n parts: NcpMessagePart[];\n timestamp: string;\n metadata?: Record<string, unknown>;\n}): NcpMessage {\n const { sessionId, messageId, parts, timestamp, metadata } = params;\n return {\n id: messageId,\n sessionId,\n role: \"assistant\",\n status: \"final\",\n parts: structuredClone(parts),\n timestamp,\n ...(metadata ? { metadata } : {}),\n };\n}\n\nexport class HermesAssistantEventCollector {\n private readonly parts: NcpMessagePart[] = [];\n private readonly toolPartIndexByCallId = new Map<string, number>();\n\n applyEvent = (event: NcpEndpointEvent): void => {\n switch (event.type) {\n case NcpEventType.MessageTextDelta:\n this.appendTextPart(event.payload.delta);\n return;\n case NcpEventType.MessageReasoningDelta:\n this.appendReasoningPart(event.payload.delta);\n return;\n case NcpEventType.MessageToolCallStart:\n this.upsertToolInvocationPart({\n type: \"tool-invocation\",\n toolCallId: event.payload.toolCallId,\n toolName: event.payload.toolName,\n state: \"partial-call\",\n args: \"\",\n });\n return;\n case NcpEventType.MessageToolCallArgsDelta:\n this.applyToolCallArgsDelta(\n event.payload.toolCallId,\n event.payload.delta,\n );\n return;\n case NcpEventType.MessageToolCallArgs:\n this.upsertToolInvocationPart({\n type: \"tool-invocation\",\n toolCallId: event.payload.toolCallId,\n toolName: this.readToolName(event.payload.toolCallId),\n state: \"partial-call\",\n args: event.payload.args,\n });\n return;\n case NcpEventType.MessageToolCallEnd:\n this.upsertToolInvocationPart({\n type: \"tool-invocation\",\n toolCallId: event.payload.toolCallId,\n toolName: this.readToolName(event.payload.toolCallId),\n state: \"call\",\n args: this.readToolArgs(event.payload.toolCallId),\n });\n return;\n default:\n return;\n }\n };\n\n hasParts = (): boolean => this.parts.length > 0;\n\n buildParts = (): NcpMessagePart[] => structuredClone(this.parts);\n\n private appendTextPart = (delta: string): void => {\n if (!delta) {\n return;\n }\n const lastPart = this.parts.at(-1);\n if (lastPart?.type === \"text\") {\n lastPart.text = `${lastPart.text}${delta}`;\n return;\n }\n this.parts.push({\n type: \"text\",\n text: delta,\n });\n };\n\n private appendReasoningPart = (delta: string): void => {\n if (!delta) {\n return;\n }\n const lastPart = this.parts.at(-1);\n if (lastPart?.type === \"reasoning\") {\n lastPart.text = `${lastPart.text}${delta}`;\n return;\n }\n this.parts.push({\n type: \"reasoning\",\n text: delta,\n });\n };\n\n private applyToolCallArgsDelta = (toolCallId: string, delta: string): void => {\n const currentArgs = this.readToolArgs(toolCallId);\n this.upsertToolInvocationPart({\n type: \"tool-invocation\",\n toolCallId,\n toolName: this.readToolName(toolCallId),\n state: \"partial-call\",\n args: `${currentArgs}${delta}`,\n });\n };\n\n private upsertToolInvocationPart = (\n nextPart: NcpToolInvocationPart,\n ): void => {\n const normalizedToolCallId = nextPart.toolCallId?.trim();\n if (!normalizedToolCallId) {\n this.parts.push({\n ...nextPart,\n });\n return;\n }\n\n const existingIndex = this.toolPartIndexByCallId.get(normalizedToolCallId);\n if (typeof existingIndex === \"number\") {\n const existingPart = this.parts[existingIndex];\n if (existingPart?.type !== \"tool-invocation\") {\n return;\n }\n this.parts[existingIndex] = {\n ...existingPart,\n ...nextPart,\n toolCallId: normalizedToolCallId,\n toolName: nextPart.toolName || existingPart.toolName,\n args: nextPart.args ?? existingPart.args,\n };\n return;\n }\n\n this.toolPartIndexByCallId.set(normalizedToolCallId, this.parts.length);\n this.parts.push({\n ...nextPart,\n toolCallId: normalizedToolCallId,\n });\n };\n\n private readToolArgs = (toolCallId: string): string => {\n const part = this.findToolPart(toolCallId);\n if (!part) {\n return \"\";\n }\n return typeof part.args === \"string\"\n ? part.args\n : JSON.stringify(part.args ?? \"\");\n };\n\n private readToolName = (toolCallId: string): string => {\n const part = this.findToolPart(toolCallId);\n return part?.toolName ?? \"unknown\";\n };\n\n private findToolPart = (\n toolCallId: string,\n ): NcpToolInvocationPart | null => {\n const existingIndex = this.toolPartIndexByCallId.get(toolCallId);\n if (typeof existingIndex !== \"number\") {\n return null;\n }\n const part = this.parts[existingIndex];\n return part?.type === \"tool-invocation\" ? part : null;\n };\n}\n\nexport class HermesInlineToolTraceTranslator {\n private pendingTextBuffer = \"\";\n private sawStructuredToolCall = false;\n private toolCallCount = 0;\n\n translate = async function* (\n this: HermesInlineToolTraceTranslator,\n events: AsyncIterable<NcpEndpointEvent>,\n ): AsyncGenerator<NcpEndpointEvent> {\n for await (const event of events) {\n if (this.isStructuredToolCallEvent(event)) {\n this.sawStructuredToolCall = true;\n yield* this.flushPendingText({\n sessionId: this.readEventSessionId(event),\n messageId: this.readEventMessageId(event),\n flush: true,\n });\n yield event;\n continue;\n }\n\n if (\n !this.sawStructuredToolCall &&\n event.type === NcpEventType.MessageTextDelta\n ) {\n this.pendingTextBuffer += event.payload.delta;\n yield* this.flushPendingText({\n sessionId: event.payload.sessionId,\n messageId: event.payload.messageId,\n flush: false,\n });\n continue;\n }\n\n if (\n !this.sawStructuredToolCall &&\n this.shouldFlushPendingText(event)\n ) {\n yield* this.flushPendingText({\n sessionId: this.readEventSessionId(event),\n messageId: this.readEventMessageId(event),\n flush: true,\n });\n }\n\n yield event;\n }\n };\n\n private flushPendingText = function* (\n this: HermesInlineToolTraceTranslator,\n params: {\n sessionId?: string;\n messageId?: string;\n flush: boolean;\n },\n ): Generator<NcpEndpointEvent> {\n if (!this.pendingTextBuffer) {\n return;\n }\n\n const { flush, messageId, sessionId } = params;\n const lastNewlineIndex = this.pendingTextBuffer.lastIndexOf(\"\\n\");\n const flushableText =\n flush\n ? this.pendingTextBuffer\n : lastNewlineIndex >= 0\n ? this.pendingTextBuffer.slice(0, lastNewlineIndex + 1)\n : this.pendingTextBuffer.includes(\"`\")\n ? \"\"\n : this.pendingTextBuffer;\n if (!flushableText) {\n return;\n }\n\n this.pendingTextBuffer = this.pendingTextBuffer.slice(flushableText.length);\n for (const segment of splitIntoLineSegments(flushableText)) {\n const inlineToolTrace = matchHermesInlineToolTrace(segment);\n if (inlineToolTrace && sessionId) {\n const toolCallId = `hermes-inline-tool-${++this.toolCallCount}`;\n yield createNcpEndpointEvent({\n type: NcpEventType.MessageToolCallStart,\n payload: {\n sessionId,\n messageId,\n toolCallId,\n toolName: inlineToolTrace.toolName,\n },\n });\n yield createNcpEndpointEvent({\n type: NcpEventType.MessageToolCallArgs,\n payload: {\n sessionId,\n toolCallId,\n args: inlineToolTrace.args,\n },\n });\n yield createNcpEndpointEvent({\n type: NcpEventType.MessageToolCallEnd,\n payload: {\n sessionId,\n toolCallId,\n },\n });\n continue;\n }\n\n if (!segment || !sessionId || !messageId) {\n continue;\n }\n yield createNcpEndpointEvent({\n type: NcpEventType.MessageTextDelta,\n payload: {\n sessionId,\n messageId,\n delta: segment,\n },\n });\n }\n };\n\n private shouldFlushPendingText = (event: NcpEndpointEvent): boolean =>\n event.type === NcpEventType.MessageTextEnd ||\n event.type === NcpEventType.MessageCompleted ||\n event.type === NcpEventType.MessageFailed ||\n event.type === NcpEventType.RunFinished ||\n event.type === NcpEventType.RunError;\n\n private isStructuredToolCallEvent = (event: NcpEndpointEvent): boolean =>\n event.type === NcpEventType.MessageToolCallStart ||\n event.type === NcpEventType.MessageToolCallArgs ||\n event.type === NcpEventType.MessageToolCallArgsDelta ||\n event.type === NcpEventType.MessageToolCallEnd ||\n event.type === NcpEventType.MessageToolCallResult;\n\n private readEventSessionId = (event: NcpEndpointEvent): string | undefined => {\n if (!(\"payload\" in event) || !event.payload || typeof event.payload !== \"object\") {\n return undefined;\n }\n return \"sessionId\" in event.payload && typeof event.payload.sessionId === \"string\"\n ? event.payload.sessionId\n : undefined;\n };\n\n private readEventMessageId = (event: NcpEndpointEvent): string | undefined => {\n if (!(\"payload\" in event) || !event.payload || typeof event.payload !== \"object\") {\n return undefined;\n }\n return \"messageId\" in event.payload && typeof event.payload.messageId === \"string\"\n ? event.payload.messageId\n : undefined;\n };\n}\n\nexport class HermesReasoningDeltaTranslator {\n private readonly normalizer = new NcpAssistantTextStreamNormalizer(\"think-tags\");\n\n translate = async function* (\n this: HermesReasoningDeltaTranslator,\n events: AsyncIterable<NcpEndpointEvent>,\n ): AsyncGenerator<NcpEndpointEvent> {\n for await (const event of events) {\n if (event.type === NcpEventType.MessageTextDelta) {\n yield* this.emitNormalizedTextDelta(event);\n continue;\n }\n\n if (this.shouldFlushPendingText(event)) {\n yield* this.flushPendingText(event);\n }\n\n yield event;\n }\n\n this.flushSegments();\n };\n\n private emitNormalizedTextDelta = function* (\n this: HermesReasoningDeltaTranslator,\n event: Extract<NcpEndpointEvent, { type: NcpEventType.MessageTextDelta }>,\n ): Generator<NcpEndpointEvent> {\n const segments = this.normalizer.push(event.payload.delta);\n for (const segment of segments) {\n if (!segment.text) {\n continue;\n }\n if (segment.type === \"reasoning\") {\n yield createNcpEndpointEvent({\n type: NcpEventType.MessageReasoningDelta,\n payload: {\n sessionId: event.payload.sessionId,\n messageId: event.payload.messageId,\n delta: segment.text,\n },\n });\n continue;\n }\n yield createNcpEndpointEvent({\n type: NcpEventType.MessageTextDelta,\n payload: {\n sessionId: event.payload.sessionId,\n messageId: event.payload.messageId,\n delta: segment.text,\n },\n });\n }\n };\n\n private flushPendingText = function* (\n this: HermesReasoningDeltaTranslator,\n event: NcpEndpointEvent,\n ): Generator<NcpEndpointEvent> {\n const sessionId = this.readEventSessionId(event);\n const messageId = this.readEventMessageId(event);\n if (!sessionId || !messageId) {\n this.flushSegments();\n return;\n }\n\n const segments = this.normalizer.finish();\n for (const segment of segments) {\n if (!segment.text) {\n continue;\n }\n if (segment.type === \"reasoning\") {\n yield createNcpEndpointEvent({\n type: NcpEventType.MessageReasoningDelta,\n payload: {\n sessionId,\n messageId,\n delta: segment.text,\n },\n });\n continue;\n }\n yield createNcpEndpointEvent({\n type: NcpEventType.MessageTextDelta,\n payload: {\n sessionId,\n messageId,\n delta: segment.text,\n },\n });\n }\n };\n\n private flushSegments = (): void => {\n this.normalizer.finish();\n };\n\n private shouldFlushPendingText = (event: NcpEndpointEvent): boolean =>\n event.type === NcpEventType.MessageTextEnd ||\n event.type === NcpEventType.MessageCompleted ||\n event.type === NcpEventType.MessageFailed ||\n event.type === NcpEventType.RunFinished ||\n event.type === NcpEventType.RunError;\n\n private readEventSessionId = (event: NcpEndpointEvent): string | undefined => {\n if (!(\"payload\" in event) || !event.payload || typeof event.payload !== \"object\") {\n return undefined;\n }\n return \"sessionId\" in event.payload && typeof event.payload.sessionId === \"string\"\n ? event.payload.sessionId\n : undefined;\n };\n\n private readEventMessageId = (event: NcpEndpointEvent): string | undefined => {\n if (!(\"payload\" in event) || !event.payload || typeof event.payload !== \"object\") {\n return undefined;\n }\n return \"messageId\" in event.payload && typeof event.payload.messageId === \"string\"\n ? event.payload.messageId\n : undefined;\n };\n}\n\nexport function resolveHermesModel(params: {\n envelope: NcpRequestEnvelope;\n fallbackModel: string;\n}): string {\n const { envelope, fallbackModel } = params;\n const providerRoute = readHermesProviderRoute(envelope);\n const metadata =\n envelope.metadata &&\n typeof envelope.metadata === \"object\" &&\n !Array.isArray(envelope.metadata)\n ? (envelope.metadata as Record<string, unknown>)\n : undefined;\n\n return (\n providerRoute?.model ??\n readMetadataString(metadata, \"preferred_model\") ??\n readMetadataString(metadata, \"preferredModel\") ??\n readMetadataString(metadata, \"model\") ??\n fallbackModel\n );\n}\n\nexport function normalizeHermesRequestedModel(model: string): string {\n const trimmed = model.trim();\n if (!trimmed) {\n return trimmed;\n }\n\n const slashIndex = trimmed.indexOf(\"/\");\n if (slashIndex <= 0) {\n return trimmed;\n }\n\n const suffix = trimmed.slice(slashIndex + 1).trim();\n if (!suffix) {\n return trimmed;\n }\n\n if (suffix.includes(\":\")) {\n return suffix;\n }\n\n return trimmed;\n}\n\nexport function inferHermesProvider(params: {\n model: string;\n apiBase?: string | null;\n apiMode?: HermesProviderRoute[\"apiMode\"];\n}): string | undefined {\n if (params.apiMode === \"anthropic_messages\") {\n return \"anthropic\";\n }\n const model = params.model.trim().toLowerCase();\n const hostname = readHostname(params.apiBase);\n\n if (hostname.includes(\"anthropic.com\") || model.startsWith(\"claude\")) {\n return \"anthropic\";\n }\n return \"openai\";\n}\n\nexport function toNcpError(\n error: unknown,\n code: NcpError[\"code\"],\n): NcpError {\n return {\n code,\n message: error instanceof Error ? error.message : String(error),\n };\n}\n\nexport function toNcpSseFrame(event: NcpEndpointEvent): string {\n return `event: ncp-event\\ndata: ${JSON.stringify(event)}\\n\\n`;\n}\n\nexport function toErrorSseFrame(error: { code: string; message: string }): string {\n return `event: error\\ndata: ${JSON.stringify(error)}\\n\\n`;\n}\n\nfunction readHostname(value: string | null | undefined): string {\n if (!value) {\n return \"\";\n }\n try {\n return new URL(value).hostname.trim().toLowerCase();\n } catch {\n return \"\";\n }\n}\n\nfunction extractRuntimeHeaders(\n headers: Record<string, string>,\n): Pick<HermesProviderRoute, \"headers\" | \"apiMode\"> {\n const nextHeaders = { ...headers };\n const apiMode = nextHeaders[NARP_API_MODE_HEADER] as HermesProviderRoute[\"apiMode\"] | undefined;\n delete nextHeaders[NARP_API_MODE_HEADER];\n return {\n headers: nextHeaders,\n ...(apiMode ? { apiMode } : {}),\n };\n}\n\nfunction extractMessageText(message: NcpMessage): string {\n const text = message.parts\n .map((part) => {\n if (part.type === \"text\" || part.type === \"reasoning\" || part.type === \"rich-text\") {\n return part.text;\n }\n return \"\";\n })\n .join(\"\\n\")\n .trim();\n return text.length > 0 ? text : \"[empty message]\";\n}\n\nfunction splitIntoLineSegments(text: string): string[] {\n return text.match(/[^\\n]*\\n|[^\\n]+$/gu) ?? [];\n}\n\nfunction normalizeRole(role: NcpMessage[\"role\"]): HermesOpenAIMessage[\"role\"] {\n if (role === \"assistant\" || role === \"system\") {\n return role;\n }\n return \"user\";\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hermes-http-adapter.service.d.ts","names":[],"sources":["../src/hermes-http-adapter.service.ts"],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"hermes-http-adapter.service.d.ts","names":[],"sources":["../src/hermes-http-adapter.service.ts"],"mappings":";;;;cA4jBa,uBAAA;EAAA,SACF,MAAA,EAAQ,+BAAA;EAAA,iBAEA,YAAA;EAAA,QACT,MAAA;cAEI,WAAA,GAAa,4BAAA;EAKzB,KAAA,QAAkB,OAAA;EAiBlB,IAAA,QAAiB,OAAA;AAAA"}
|
|
@@ -2,10 +2,11 @@ import { HermesHttpAdapterConfigResolver } from "./hermes-http-adapter-config.ut
|
|
|
2
2
|
import { HermesAssistantEventCollector, HermesInlineToolTraceTranslator, HermesReasoningDeltaTranslator, buildHermesMessages, createAssistantMessageFromParts, inferHermesProvider, normalizeHermesRequestedModel, readHermesProviderRoute, resolveHermesModel, toErrorSseFrame, toNcpError, toNcpSseFrame } from "./hermes-http-adapter-message.utils.js";
|
|
3
3
|
import { parseHermesOpenAIChatStream } from "./hermes-openai-stream-parser.utils.js";
|
|
4
4
|
import { HermesHttpAdapterSessionStore } from "./hermes-http-adapter-session-store.service.js";
|
|
5
|
+
import { createHermesMessageAcceptedEvent, createHermesMessageCompletedEvent, createHermesMessageFailedEvent, createHermesRunErrorEvent, createHermesRunFinishedEvent, createHermesRunHandle, createHermesRunStartedEvent } from "./hermes-http-adapter-events.utils.js";
|
|
5
6
|
import { createServer } from "node:http";
|
|
6
7
|
import { randomUUID } from "node:crypto";
|
|
7
8
|
import { DefaultNcpStreamEncoder } from "@nextclaw/ncp-agent-runtime";
|
|
8
|
-
import
|
|
9
|
+
import "@nextclaw/ncp";
|
|
9
10
|
//#region src/hermes-http-adapter.service.ts
|
|
10
11
|
function isUserVisibleAssistantEvent(event) {
|
|
11
12
|
const eventType = event.type;
|
|
@@ -109,7 +110,10 @@ var HermesHttpAdapterRouteService = class {
|
|
|
109
110
|
runId: randomUUID()
|
|
110
111
|
};
|
|
111
112
|
this.sessions.setPendingRun(run);
|
|
112
|
-
this.writeJson(response, 200, {
|
|
113
|
+
this.writeJson(response, 200, {
|
|
114
|
+
ok: true,
|
|
115
|
+
data: createHermesRunHandle(run)
|
|
116
|
+
});
|
|
113
117
|
} catch (error) {
|
|
114
118
|
this.writeJson(response, 409, {
|
|
115
119
|
ok: false,
|
|
@@ -237,21 +241,12 @@ var HermesHttpAdapterRouteService = class {
|
|
|
237
241
|
const messageCollector = new HermesAssistantEventCollector();
|
|
238
242
|
const inlineToolTraceTranslator = new HermesInlineToolTraceTranslator();
|
|
239
243
|
const reasoningDeltaTranslator = new HermesReasoningDeltaTranslator();
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
};
|
|
247
|
-
yield {
|
|
248
|
-
type: NcpEventType.RunStarted,
|
|
249
|
-
payload: {
|
|
250
|
-
sessionId,
|
|
251
|
-
messageId: run.messageId,
|
|
252
|
-
runId: run.runId
|
|
253
|
-
}
|
|
254
|
-
};
|
|
244
|
+
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
245
|
+
yield createHermesMessageAcceptedEvent(run);
|
|
246
|
+
yield createHermesRunStartedEvent({
|
|
247
|
+
run,
|
|
248
|
+
startedAt
|
|
249
|
+
});
|
|
255
250
|
try {
|
|
256
251
|
for await (const event of reasoningDeltaTranslator.translate(inlineToolTraceTranslator.translate(this.streamEncoder.encode(parseHermesOpenAIChatStream(response.body), {
|
|
257
252
|
sessionId,
|
|
@@ -264,74 +259,45 @@ var HermesHttpAdapterRouteService = class {
|
|
|
264
259
|
yield event;
|
|
265
260
|
}
|
|
266
261
|
if (!emittedUserVisibleAssistantEvent || !messageCollector.hasParts()) throw new Error(`[hermes-http-adapter] Hermes completed without any assistant content for session ${sessionId}.`);
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
messageId: run.messageId,
|
|
270
|
-
parts: messageCollector.buildParts(),
|
|
271
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
272
|
-
metadata
|
|
273
|
-
});
|
|
274
|
-
yield {
|
|
275
|
-
type: NcpEventType.MessageCompleted,
|
|
276
|
-
payload: {
|
|
277
|
-
sessionId,
|
|
278
|
-
message,
|
|
279
|
-
correlationId: run.envelope.correlationId,
|
|
280
|
-
metadata
|
|
281
|
-
}
|
|
282
|
-
};
|
|
283
|
-
yield {
|
|
284
|
-
type: NcpEventType.RunFinished,
|
|
285
|
-
payload: {
|
|
262
|
+
yield createHermesMessageCompletedEvent({
|
|
263
|
+
message: this.buildAssistantMessage({
|
|
286
264
|
sessionId,
|
|
287
265
|
messageId: run.messageId,
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
266
|
+
parts: messageCollector.buildParts(),
|
|
267
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
268
|
+
metadata
|
|
269
|
+
}),
|
|
270
|
+
metadata,
|
|
271
|
+
run
|
|
272
|
+
});
|
|
273
|
+
yield createHermesRunFinishedEvent({
|
|
274
|
+
endedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
275
|
+
run,
|
|
276
|
+
startedAt
|
|
277
|
+
});
|
|
291
278
|
} catch (error) {
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
messageId: run.messageId,
|
|
299
|
-
correlationId: run.envelope.correlationId,
|
|
300
|
-
error: abortError
|
|
301
|
-
}
|
|
302
|
-
};
|
|
303
|
-
yield {
|
|
304
|
-
type: NcpEventType.RunError,
|
|
305
|
-
payload: {
|
|
306
|
-
sessionId,
|
|
307
|
-
messageId: run.messageId,
|
|
308
|
-
runId: run.runId,
|
|
309
|
-
error: abortError.message
|
|
310
|
-
}
|
|
311
|
-
};
|
|
312
|
-
return;
|
|
313
|
-
}
|
|
314
|
-
const runtimeError = toNcpError(error, "runtime-error");
|
|
315
|
-
yield {
|
|
316
|
-
type: NcpEventType.MessageFailed,
|
|
317
|
-
payload: {
|
|
318
|
-
sessionId,
|
|
319
|
-
messageId: run.messageId,
|
|
320
|
-
correlationId: run.envelope.correlationId,
|
|
321
|
-
error: runtimeError
|
|
322
|
-
}
|
|
323
|
-
};
|
|
324
|
-
yield {
|
|
325
|
-
type: NcpEventType.RunError,
|
|
326
|
-
payload: {
|
|
327
|
-
sessionId,
|
|
328
|
-
messageId: run.messageId,
|
|
329
|
-
runId: run.runId,
|
|
330
|
-
error: runtimeError.message
|
|
331
|
-
}
|
|
332
|
-
};
|
|
279
|
+
yield* this.createRunErrorEvents({
|
|
280
|
+
error,
|
|
281
|
+
run,
|
|
282
|
+
startedAt,
|
|
283
|
+
fallbackCode: signal.aborted ? "abort-error" : "runtime-error"
|
|
284
|
+
});
|
|
333
285
|
}
|
|
334
286
|
};
|
|
287
|
+
createRunErrorEvents = function* (params) {
|
|
288
|
+
const { error, fallbackCode, run, startedAt } = params;
|
|
289
|
+
const ncpError = toNcpError(error, fallbackCode);
|
|
290
|
+
yield createHermesMessageFailedEvent({
|
|
291
|
+
error: ncpError,
|
|
292
|
+
run
|
|
293
|
+
});
|
|
294
|
+
yield createHermesRunErrorEvent({
|
|
295
|
+
endedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
296
|
+
error: ncpError,
|
|
297
|
+
run,
|
|
298
|
+
startedAt
|
|
299
|
+
});
|
|
300
|
+
};
|
|
335
301
|
ensureHermesSessionModel = async (params) => {
|
|
336
302
|
const { requestedModel, sessionId, signal } = params;
|
|
337
303
|
if ((this.sessions.readSelectedModel(sessionId) ?? this.config.model) === requestedModel) return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hermes-http-adapter.service.js","names":[],"sources":["../src/hermes-http-adapter.service.ts"],"sourcesContent":["import { createServer, type IncomingMessage, type Server, type ServerResponse } from \"node:http\";\nimport { randomUUID } from \"node:crypto\";\nimport { DefaultNcpStreamEncoder } from \"@nextclaw/ncp-agent-runtime\";\nimport {\n NcpEventType,\n type NcpEndpointEvent,\n type NcpRequestEnvelope,\n type OpenAITool,\n} from \"@nextclaw/ncp\";\nimport { HermesHttpAdapterConfigResolver } from \"./hermes-http-adapter-config.utils.js\";\nimport {\n buildHermesMessages,\n createAssistantMessageFromParts,\n HermesAssistantEventCollector,\n HermesInlineToolTraceTranslator,\n HermesReasoningDeltaTranslator,\n inferHermesProvider,\n normalizeHermesRequestedModel,\n readHermesProviderRoute,\n resolveHermesModel,\n type HermesProviderRoute,\n toErrorSseFrame,\n toNcpError,\n toNcpSseFrame,\n} from \"./hermes-http-adapter-message.utils.js\";\nimport { parseHermesOpenAIChatStream } from \"./hermes-openai-stream-parser.utils.js\";\nimport { HermesHttpAdapterSessionStore } from \"./hermes-http-adapter-session-store.service.js\";\nimport type {\n HermesAdapterAssistantMessageFactory,\n HermesHttpAdapterResolvedConfig,\n HermesHttpAdapterRun,\n HermesHttpAdapterRunResult,\n} from \"./hermes-http-adapter.types.js\";\nimport type { HermesHttpAdapterConfigInput } from \"./hermes-http-adapter-config.utils.js\";\n\nfunction isUserVisibleAssistantEvent(event: NcpEndpointEvent): boolean {\n const eventType = event.type;\n return (\n eventType.startsWith(\"message.text-\") ||\n eventType.startsWith(\"message.reasoning-\") ||\n eventType.startsWith(\"message.tool-call-\")\n );\n}\n\nclass HermesHttpAdapterRouteService {\n private readonly sessions = new HermesHttpAdapterSessionStore();\n private readonly streamEncoder = new DefaultNcpStreamEncoder({\n reasoningNormalizationMode: \"think-tags\",\n });\n private readonly fetchImpl: typeof fetch;\n\n constructor(\n private readonly config: HermesHttpAdapterResolvedConfig,\n private readonly buildAssistantMessage: HermesAdapterAssistantMessageFactory = createAssistantMessageFromParts,\n ) {\n this.fetchImpl = config.fetchImpl ?? fetch;\n }\n\n handle = async (\n request: IncomingMessage,\n response: ServerResponse,\n ): Promise<void> => {\n const requestUrl = new URL(request.url ?? \"/\", this.baseOrigin);\n const normalizedPath = requestUrl.pathname;\n\n if (request.method === \"GET\" && normalizedPath === \"/health\") {\n await this.handleHealth(response);\n return;\n }\n\n if (request.method === \"POST\" && normalizedPath === `${this.config.basePath}/send`) {\n await this.handleSend(request, response);\n return;\n }\n\n if (request.method === \"GET\" && normalizedPath === `${this.config.basePath}/stream`) {\n await this.handleStream(request, response, requestUrl);\n return;\n }\n\n if (request.method === \"POST\" && normalizedPath === `${this.config.basePath}/abort`) {\n await this.handleAbort(request, response);\n return;\n }\n\n this.writeJson(response, 404, {\n ok: false,\n error: {\n code: \"NOT_FOUND\",\n message: `Unknown path: ${normalizedPath}`,\n },\n });\n };\n\n dispose = (): void => {\n this.sessions.dispose();\n };\n\n private get baseOrigin(): string {\n return `http://${this.config.host}:${this.config.port}`;\n }\n\n private handleHealth = async (response: ServerResponse): Promise<void> => {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), this.config.healthcheckTimeoutMs);\n\n try {\n const upstream = await this.fetchImpl(this.config.healthcheckUrl, {\n method: \"GET\",\n signal: controller.signal,\n });\n if (!upstream.ok) {\n this.writeJson(response, 503, {\n status: \"degraded\",\n adapter: \"ok\",\n upstream: {\n status: \"error\",\n httpStatus: upstream.status,\n },\n });\n return;\n }\n this.writeJson(response, 200, {\n status: \"ok\",\n adapter: \"ok\",\n upstream: \"ok\",\n });\n } catch (error) {\n this.writeJson(response, 503, {\n status: \"degraded\",\n adapter: \"ok\",\n upstream: {\n status: \"unreachable\",\n message: error instanceof Error ? error.message : String(error),\n },\n });\n } finally {\n clearTimeout(timeout);\n }\n };\n\n private handleSend = async (\n request: IncomingMessage,\n response: ServerResponse,\n ): Promise<void> => {\n try {\n const envelope = await this.readJsonBody<NcpRequestEnvelope>(request);\n if (!envelope?.sessionId || !envelope.message) {\n this.writeJson(response, 400, {\n ok: false,\n error: {\n code: \"INVALID_BODY\",\n message: \"sessionId and message are required.\",\n },\n });\n return;\n }\n\n const run: HermesHttpAdapterRun = {\n envelope,\n messageId: randomUUID(),\n runId: randomUUID(),\n };\n this.sessions.setPendingRun(run);\n this.writeJson(response, 200, { ok: true });\n } catch (error) {\n this.writeJson(response, 409, {\n ok: false,\n error: {\n code: \"RUN_CONFLICT\",\n message: error instanceof Error ? error.message : String(error),\n },\n });\n }\n };\n\n private handleAbort = async (\n request: IncomingMessage,\n response: ServerResponse,\n ): Promise<void> => {\n try {\n const payload = await this.readJsonBody<{ sessionId?: string }>(request);\n const sessionId = typeof payload?.sessionId === \"string\" ? payload.sessionId : \"\";\n if (!sessionId.trim()) {\n this.writeJson(response, 400, {\n ok: false,\n error: {\n code: \"INVALID_BODY\",\n message: \"sessionId is required.\",\n },\n });\n return;\n }\n const aborted = this.sessions.abortSession(sessionId);\n this.writeJson(response, 200, { ok: true, aborted });\n } catch (error) {\n this.writeJson(response, 500, {\n ok: false,\n error: {\n code: \"ABORT_FAILED\",\n message: error instanceof Error ? error.message : String(error),\n },\n });\n }\n };\n\n private handleStream = async (\n request: IncomingMessage,\n response: ServerResponse,\n requestUrl: URL,\n ): Promise<void> => {\n const sessionId = requestUrl.searchParams.get(\"sessionId\")?.trim();\n if (!sessionId) {\n this.writeJson(response, 400, {\n ok: false,\n error: {\n code: \"INVALID_QUERY\",\n message: \"sessionId is required.\",\n },\n });\n return;\n }\n\n const connectionController = new AbortController();\n const runController = new AbortController();\n response.once(\"close\", () => {\n connectionController.abort(\"client disconnected\");\n runController.abort(\"client disconnected\");\n });\n\n response.writeHead(200, {\n \"content-type\": \"text/event-stream; charset=utf-8\",\n \"cache-control\": \"no-cache, no-transform\",\n connection: \"keep-alive\",\n \"x-accel-buffering\": \"no\",\n });\n\n try {\n const run = await this.sessions.waitForPendingRun(\n sessionId,\n connectionController.signal,\n this.config.streamWaitTimeoutMs,\n );\n this.sessions.setActiveAbortController(sessionId, runController);\n\n const streamResult = await this.startRun({\n run,\n signal: runController.signal,\n });\n\n for await (const event of streamResult.events) {\n if (connectionController.signal.aborted) {\n break;\n }\n response.write(toNcpSseFrame(event));\n }\n } catch (error) {\n if (!connectionController.signal.aborted) {\n response.write(\n toErrorSseFrame({\n code: \"STREAM_FAILED\",\n message: error instanceof Error ? error.message : String(error),\n }),\n );\n }\n } finally {\n this.sessions.clearActiveAbortController(sessionId);\n response.end();\n }\n };\n\n private startRun = async (params: {\n run: HermesHttpAdapterRun;\n signal: AbortSignal;\n }): Promise<HermesHttpAdapterRunResult> => {\n const { run, signal } = params;\n const providerRoute = this.readProviderRoute(run.envelope);\n const requestedModel = normalizeHermesRequestedModel(resolveHermesModel({\n envelope: run.envelope,\n fallbackModel: this.config.model,\n }));\n if (!providerRoute) {\n await this.ensureHermesSessionModel({\n sessionId: run.envelope.sessionId,\n requestedModel,\n signal,\n });\n }\n\n const response = await this.fetchHermesChatCompletion({\n sessionId: run.envelope.sessionId,\n signal,\n stream: true,\n model: requestedModel,\n providerRoute,\n messages: buildHermesMessages({\n envelope: run.envelope,\n systemPrompt: this.config.systemPrompt,\n }),\n tools: run.envelope.tools,\n });\n if (!response.body) {\n throw new Error(\"[hermes-http-adapter] Hermes stream response body is missing.\");\n }\n this.sessions.setSelectedModel(run.envelope.sessionId, requestedModel);\n\n return {\n events: this.createRunEvents({\n response,\n run,\n signal,\n }),\n };\n };\n\n private createRunEvents = async function* (\n this: HermesHttpAdapterRouteService,\n params: {\n response: Response;\n run: HermesHttpAdapterRun;\n signal: AbortSignal;\n },\n ): AsyncGenerator<NcpEndpointEvent> {\n const { response, run, signal } = params;\n const sessionId = run.envelope.sessionId;\n const requestedModel = normalizeHermesRequestedModel(resolveHermesModel({\n envelope: run.envelope,\n fallbackModel: this.config.model,\n }));\n const metadata = {\n hermesModel: requestedModel,\n };\n let emittedUserVisibleAssistantEvent = false;\n const messageCollector = new HermesAssistantEventCollector();\n const inlineToolTraceTranslator = new HermesInlineToolTraceTranslator();\n const reasoningDeltaTranslator = new HermesReasoningDeltaTranslator();\n\n yield {\n type: NcpEventType.MessageAccepted,\n payload: {\n messageId: run.messageId,\n correlationId: run.envelope.correlationId,\n },\n };\n yield {\n type: NcpEventType.RunStarted,\n payload: {\n sessionId,\n messageId: run.messageId,\n runId: run.runId,\n },\n };\n\n try {\n for await (const event of reasoningDeltaTranslator.translate(\n inlineToolTraceTranslator.translate(\n this.streamEncoder.encode(\n parseHermesOpenAIChatStream(response.body as ReadableStream<Uint8Array>),\n {\n sessionId,\n messageId: run.messageId,\n runId: run.runId,\n correlationId: run.envelope.correlationId,\n },\n ),\n ),\n )) {\n messageCollector.applyEvent(event);\n if (isUserVisibleAssistantEvent(event)) {\n emittedUserVisibleAssistantEvent = true;\n }\n yield event;\n }\n\n if (!emittedUserVisibleAssistantEvent || !messageCollector.hasParts()) {\n throw new Error(\n `[hermes-http-adapter] Hermes completed without any assistant content for session ${sessionId}.`,\n );\n }\n\n const message = this.buildAssistantMessage({\n sessionId,\n messageId: run.messageId,\n parts: messageCollector.buildParts(),\n timestamp: new Date().toISOString(),\n metadata,\n });\n yield {\n type: NcpEventType.MessageCompleted,\n payload: {\n sessionId,\n message,\n correlationId: run.envelope.correlationId,\n metadata,\n },\n };\n yield {\n type: NcpEventType.RunFinished,\n payload: {\n sessionId,\n messageId: run.messageId,\n runId: run.runId,\n },\n };\n } catch (error) {\n if (signal.aborted) {\n const abortError = toNcpError(error, \"abort-error\");\n yield {\n type: NcpEventType.MessageFailed,\n payload: {\n sessionId,\n messageId: run.messageId,\n correlationId: run.envelope.correlationId,\n error: abortError,\n },\n };\n yield {\n type: NcpEventType.RunError,\n payload: {\n sessionId,\n messageId: run.messageId,\n runId: run.runId,\n error: abortError.message,\n },\n };\n return;\n }\n\n const runtimeError = toNcpError(error, \"runtime-error\");\n yield {\n type: NcpEventType.MessageFailed,\n payload: {\n sessionId,\n messageId: run.messageId,\n correlationId: run.envelope.correlationId,\n error: runtimeError,\n },\n };\n yield {\n type: NcpEventType.RunError,\n payload: {\n sessionId,\n messageId: run.messageId,\n runId: run.runId,\n error: runtimeError.message,\n },\n };\n }\n };\n\n private ensureHermesSessionModel = async (params: {\n sessionId: string;\n requestedModel: string;\n signal: AbortSignal;\n }): Promise<void> => {\n const { requestedModel, sessionId, signal } = params;\n const selectedModel = this.sessions.readSelectedModel(sessionId) ?? this.config.model;\n if (selectedModel === requestedModel) {\n return;\n }\n\n const response = await this.fetchHermesChatCompletion({\n sessionId,\n signal,\n stream: false,\n model: requestedModel,\n messages: [\n {\n role: \"user\",\n content: `/model ${requestedModel}`,\n },\n ],\n });\n\n const payload = await this.readJsonResponse<{\n choices?: Array<{\n message?: {\n content?: unknown;\n };\n }>;\n }>(response);\n const content = payload.choices?.[0]?.message?.content;\n if (typeof content === \"string\" && content.trim().startsWith(\"Error:\")) {\n throw new Error(\n `[hermes-http-adapter] failed to switch Hermes model to ${requestedModel}: ${content.trim()}`,\n );\n }\n\n this.sessions.setSelectedModel(sessionId, requestedModel);\n };\n\n private fetchHermesChatCompletion = async (params: {\n sessionId: string;\n signal: AbortSignal;\n stream: boolean;\n model: string;\n providerRoute?: HermesProviderRoute;\n messages: Array<{ role: \"system\" | \"user\" | \"assistant\"; content: string }>;\n tools?: ReadonlyArray<OpenAITool>;\n }): Promise<Response> => {\n const { messages, model, providerRoute, sessionId, signal, stream, tools } = params;\n const headers = new Headers({\n \"content-type\": \"application/json\",\n accept: stream ? \"text/event-stream\" : \"application/json\",\n });\n if (this.config.hermesApiKey) {\n headers.set(\"authorization\", `Bearer ${this.config.hermesApiKey}`);\n }\n\n const hermesSessionId = this.sessions.readHermesSessionId(sessionId);\n if (hermesSessionId) {\n headers.set(\"x-hermes-session-id\", hermesSessionId);\n }\n\n const response = await this.fetchImpl(this.config.chatCompletionsUrl, {\n method: \"POST\",\n headers,\n signal,\n body: JSON.stringify({\n model,\n stream,\n messages,\n ...(providerRoute\n ? {\n nextclaw_provider_route:\n this.toHermesProviderRoutePayload(providerRoute),\n }\n : {}),\n ...(tools && tools.length > 0 ? { tools } : {}),\n }),\n });\n if (!response.ok) {\n throw new Error(\n `[hermes-http-adapter] Hermes request failed with HTTP ${response.status}.`,\n );\n }\n\n const returnedSessionId = response.headers.get(\"x-hermes-session-id\")?.trim();\n if (returnedSessionId) {\n this.sessions.setHermesSessionId(sessionId, returnedSessionId);\n }\n\n return response;\n };\n\n private readProviderRoute = (\n envelope: NcpRequestEnvelope,\n ): HermesProviderRoute | undefined => {\n const providerRoute = readHermesProviderRoute(envelope);\n if (!providerRoute) {\n return undefined;\n }\n if (!providerRoute.apiBase) {\n throw new Error(\n `[hermes-http-adapter] missing provider apiBase for model \"${providerRoute.model}\". Configure the selected NextClaw provider before using Hermes.`,\n );\n }\n return providerRoute;\n };\n\n private toHermesProviderRoutePayload = (\n providerRoute: HermesProviderRoute,\n ): Record<string, unknown> => {\n const inferredProvider = inferHermesProvider(providerRoute);\n return {\n model: providerRoute.model,\n ...(inferredProvider ? { provider: inferredProvider } : {}),\n ...(providerRoute.apiKey ? { api_key: providerRoute.apiKey } : {}),\n ...(providerRoute.apiBase ? { base_url: providerRoute.apiBase } : {}),\n ...(providerRoute.apiMode ? { api_mode: providerRoute.apiMode } : {}),\n ...(Object.keys(providerRoute.headers).length > 0\n ? { extra_headers: providerRoute.headers }\n : {}),\n };\n };\n\n private readJsonResponse = async <T>(response: Response): Promise<T> => {\n try {\n return (await response.json()) as T;\n } catch (error) {\n throw new Error(\n `[hermes-http-adapter] expected JSON response from Hermes: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n };\n\n private readJsonBody = async <T>(request: IncomingMessage): Promise<T> => {\n const chunks: Buffer[] = [];\n for await (const chunk of request) {\n chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));\n }\n const body = Buffer.concat(chunks).toString(\"utf8\");\n if (!body.trim()) {\n throw new Error(\"request body is empty\");\n }\n return JSON.parse(body) as T;\n };\n\n private writeJson = (\n response: ServerResponse,\n statusCode: number,\n payload: unknown,\n ): void => {\n response.writeHead(statusCode, {\n \"content-type\": \"application/json; charset=utf-8\",\n });\n response.end(JSON.stringify(payload));\n };\n}\n\nexport class HermesHttpAdapterServer {\n readonly config: HermesHttpAdapterResolvedConfig;\n\n private readonly routeService: HermesHttpAdapterRouteService;\n private server: Server | null = null;\n\n constructor(configInput: HermesHttpAdapterConfigInput = {}) {\n this.config = new HermesHttpAdapterConfigResolver(configInput).resolve();\n this.routeService = new HermesHttpAdapterRouteService(this.config);\n }\n\n start = async (): Promise<void> => {\n if (this.server) {\n return;\n }\n const nextServer = createServer((request, response) => {\n void this.routeService.handle(request, response);\n });\n await new Promise<void>((resolve, reject) => {\n nextServer.once(\"error\", reject);\n nextServer.listen(this.config.port, this.config.host, () => {\n nextServer.off(\"error\", reject);\n resolve();\n });\n });\n this.server = nextServer;\n };\n\n stop = async (): Promise<void> => {\n this.routeService.dispose();\n const activeServer = this.server;\n if (!activeServer) {\n return;\n }\n await new Promise<void>((resolve, reject) => {\n activeServer.close((error) => {\n if (error) {\n reject(error);\n return;\n }\n resolve();\n });\n });\n this.server = null;\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"hermes-http-adapter.service.js","names":[],"sources":["../src/hermes-http-adapter.service.ts"],"sourcesContent":["import { createServer, type IncomingMessage, type Server, type ServerResponse } from \"node:http\";\nimport { randomUUID } from \"node:crypto\";\nimport { DefaultNcpStreamEncoder } from \"@nextclaw/ncp-agent-runtime\";\nimport {\n type NcpEndpointEvent,\n type NcpRequestEnvelope,\n type OpenAITool,\n} from \"@nextclaw/ncp\";\nimport { HermesHttpAdapterConfigResolver } from \"./hermes-http-adapter-config.utils.js\";\nimport {\n buildHermesMessages,\n createAssistantMessageFromParts,\n HermesAssistantEventCollector,\n HermesInlineToolTraceTranslator,\n HermesReasoningDeltaTranslator,\n inferHermesProvider,\n normalizeHermesRequestedModel,\n readHermesProviderRoute,\n resolveHermesModel,\n type HermesProviderRoute,\n toErrorSseFrame,\n toNcpError,\n toNcpSseFrame,\n} from \"./hermes-http-adapter-message.utils.js\";\nimport { parseHermesOpenAIChatStream } from \"./hermes-openai-stream-parser.utils.js\";\nimport { HermesHttpAdapterSessionStore } from \"./hermes-http-adapter-session-store.service.js\";\nimport {\n createHermesMessageAcceptedEvent,\n createHermesMessageCompletedEvent,\n createHermesMessageFailedEvent,\n createHermesRunErrorEvent,\n createHermesRunFinishedEvent,\n createHermesRunHandle,\n createHermesRunStartedEvent,\n} from \"./hermes-http-adapter-events.utils.js\";\nimport type {\n HermesAdapterAssistantMessageFactory,\n HermesHttpAdapterResolvedConfig,\n HermesHttpAdapterRun,\n HermesHttpAdapterRunResult,\n} from \"./hermes-http-adapter.types.js\";\nimport type { HermesHttpAdapterConfigInput } from \"./hermes-http-adapter-config.utils.js\";\n\nfunction isUserVisibleAssistantEvent(event: NcpEndpointEvent): boolean {\n const eventType = event.type;\n return (\n eventType.startsWith(\"message.text-\") ||\n eventType.startsWith(\"message.reasoning-\") ||\n eventType.startsWith(\"message.tool-call-\")\n );\n}\n\nclass HermesHttpAdapterRouteService {\n private readonly sessions = new HermesHttpAdapterSessionStore();\n private readonly streamEncoder = new DefaultNcpStreamEncoder({\n reasoningNormalizationMode: \"think-tags\",\n });\n private readonly fetchImpl: typeof fetch;\n\n constructor(\n private readonly config: HermesHttpAdapterResolvedConfig,\n private readonly buildAssistantMessage: HermesAdapterAssistantMessageFactory = createAssistantMessageFromParts,\n ) {\n this.fetchImpl = config.fetchImpl ?? fetch;\n }\n\n handle = async (\n request: IncomingMessage,\n response: ServerResponse,\n ): Promise<void> => {\n const requestUrl = new URL(request.url ?? \"/\", this.baseOrigin);\n const normalizedPath = requestUrl.pathname;\n\n if (request.method === \"GET\" && normalizedPath === \"/health\") {\n await this.handleHealth(response);\n return;\n }\n\n if (request.method === \"POST\" && normalizedPath === `${this.config.basePath}/send`) {\n await this.handleSend(request, response);\n return;\n }\n\n if (request.method === \"GET\" && normalizedPath === `${this.config.basePath}/stream`) {\n await this.handleStream(request, response, requestUrl);\n return;\n }\n\n if (request.method === \"POST\" && normalizedPath === `${this.config.basePath}/abort`) {\n await this.handleAbort(request, response);\n return;\n }\n\n this.writeJson(response, 404, {\n ok: false,\n error: {\n code: \"NOT_FOUND\",\n message: `Unknown path: ${normalizedPath}`,\n },\n });\n };\n\n dispose = (): void => {\n this.sessions.dispose();\n };\n\n private get baseOrigin(): string {\n return `http://${this.config.host}:${this.config.port}`;\n }\n\n private handleHealth = async (response: ServerResponse): Promise<void> => {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), this.config.healthcheckTimeoutMs);\n\n try {\n const upstream = await this.fetchImpl(this.config.healthcheckUrl, {\n method: \"GET\",\n signal: controller.signal,\n });\n if (!upstream.ok) {\n this.writeJson(response, 503, {\n status: \"degraded\",\n adapter: \"ok\",\n upstream: {\n status: \"error\",\n httpStatus: upstream.status,\n },\n });\n return;\n }\n this.writeJson(response, 200, {\n status: \"ok\",\n adapter: \"ok\",\n upstream: \"ok\",\n });\n } catch (error) {\n this.writeJson(response, 503, {\n status: \"degraded\",\n adapter: \"ok\",\n upstream: {\n status: \"unreachable\",\n message: error instanceof Error ? error.message : String(error),\n },\n });\n } finally {\n clearTimeout(timeout);\n }\n };\n\n private handleSend = async (\n request: IncomingMessage,\n response: ServerResponse,\n ): Promise<void> => {\n try {\n const envelope = await this.readJsonBody<NcpRequestEnvelope>(request);\n if (!envelope?.sessionId || !envelope.message) {\n this.writeJson(response, 400, {\n ok: false,\n error: {\n code: \"INVALID_BODY\",\n message: \"sessionId and message are required.\",\n },\n });\n return;\n }\n\n const run: HermesHttpAdapterRun = {\n envelope,\n messageId: randomUUID(),\n runId: randomUUID(),\n };\n this.sessions.setPendingRun(run);\n this.writeJson(response, 200, { ok: true, data: createHermesRunHandle(run) });\n } catch (error) {\n this.writeJson(response, 409, {\n ok: false,\n error: {\n code: \"RUN_CONFLICT\",\n message: error instanceof Error ? error.message : String(error),\n },\n });\n }\n };\n\n private handleAbort = async (\n request: IncomingMessage,\n response: ServerResponse,\n ): Promise<void> => {\n try {\n const payload = await this.readJsonBody<{ sessionId?: string }>(request);\n const sessionId = typeof payload?.sessionId === \"string\" ? payload.sessionId : \"\";\n if (!sessionId.trim()) {\n this.writeJson(response, 400, {\n ok: false,\n error: {\n code: \"INVALID_BODY\",\n message: \"sessionId is required.\",\n },\n });\n return;\n }\n const aborted = this.sessions.abortSession(sessionId);\n this.writeJson(response, 200, { ok: true, aborted });\n } catch (error) {\n this.writeJson(response, 500, {\n ok: false,\n error: {\n code: \"ABORT_FAILED\",\n message: error instanceof Error ? error.message : String(error),\n },\n });\n }\n };\n\n private handleStream = async (\n request: IncomingMessage,\n response: ServerResponse,\n requestUrl: URL,\n ): Promise<void> => {\n const sessionId = requestUrl.searchParams.get(\"sessionId\")?.trim();\n if (!sessionId) {\n this.writeJson(response, 400, {\n ok: false,\n error: {\n code: \"INVALID_QUERY\",\n message: \"sessionId is required.\",\n },\n });\n return;\n }\n\n const connectionController = new AbortController();\n const runController = new AbortController();\n response.once(\"close\", () => {\n connectionController.abort(\"client disconnected\");\n runController.abort(\"client disconnected\");\n });\n\n response.writeHead(200, {\n \"content-type\": \"text/event-stream; charset=utf-8\",\n \"cache-control\": \"no-cache, no-transform\",\n connection: \"keep-alive\",\n \"x-accel-buffering\": \"no\",\n });\n\n try {\n const run = await this.sessions.waitForPendingRun(\n sessionId,\n connectionController.signal,\n this.config.streamWaitTimeoutMs,\n );\n this.sessions.setActiveAbortController(sessionId, runController);\n\n const streamResult = await this.startRun({\n run,\n signal: runController.signal,\n });\n\n for await (const event of streamResult.events) {\n if (connectionController.signal.aborted) {\n break;\n }\n response.write(toNcpSseFrame(event));\n }\n } catch (error) {\n if (!connectionController.signal.aborted) {\n response.write(\n toErrorSseFrame({\n code: \"STREAM_FAILED\",\n message: error instanceof Error ? error.message : String(error),\n }),\n );\n }\n } finally {\n this.sessions.clearActiveAbortController(sessionId);\n response.end();\n }\n };\n\n private startRun = async (params: {\n run: HermesHttpAdapterRun;\n signal: AbortSignal;\n }): Promise<HermesHttpAdapterRunResult> => {\n const { run, signal } = params;\n const providerRoute = this.readProviderRoute(run.envelope);\n const requestedModel = normalizeHermesRequestedModel(resolveHermesModel({\n envelope: run.envelope,\n fallbackModel: this.config.model,\n }));\n if (!providerRoute) {\n await this.ensureHermesSessionModel({\n sessionId: run.envelope.sessionId,\n requestedModel,\n signal,\n });\n }\n\n const response = await this.fetchHermesChatCompletion({\n sessionId: run.envelope.sessionId,\n signal,\n stream: true,\n model: requestedModel,\n providerRoute,\n messages: buildHermesMessages({\n envelope: run.envelope,\n systemPrompt: this.config.systemPrompt,\n }),\n tools: run.envelope.tools,\n });\n if (!response.body) {\n throw new Error(\"[hermes-http-adapter] Hermes stream response body is missing.\");\n }\n this.sessions.setSelectedModel(run.envelope.sessionId, requestedModel);\n\n return {\n events: this.createRunEvents({\n response,\n run,\n signal,\n }),\n };\n };\n\n private createRunEvents = async function* (\n this: HermesHttpAdapterRouteService,\n params: {\n response: Response;\n run: HermesHttpAdapterRun;\n signal: AbortSignal;\n },\n ): AsyncGenerator<NcpEndpointEvent> {\n const { response, run, signal } = params;\n const sessionId = run.envelope.sessionId;\n const requestedModel = normalizeHermesRequestedModel(resolveHermesModel({\n envelope: run.envelope,\n fallbackModel: this.config.model,\n }));\n const metadata = {\n hermesModel: requestedModel,\n };\n let emittedUserVisibleAssistantEvent = false;\n const messageCollector = new HermesAssistantEventCollector();\n const inlineToolTraceTranslator = new HermesInlineToolTraceTranslator();\n const reasoningDeltaTranslator = new HermesReasoningDeltaTranslator();\n const startedAt = new Date().toISOString();\n\n yield createHermesMessageAcceptedEvent(run);\n yield createHermesRunStartedEvent({ run, startedAt });\n\n try {\n for await (const event of reasoningDeltaTranslator.translate(\n inlineToolTraceTranslator.translate(\n this.streamEncoder.encode(\n parseHermesOpenAIChatStream(response.body as ReadableStream<Uint8Array>),\n {\n sessionId,\n messageId: run.messageId,\n runId: run.runId,\n correlationId: run.envelope.correlationId,\n },\n ),\n ),\n )) {\n messageCollector.applyEvent(event);\n if (isUserVisibleAssistantEvent(event)) {\n emittedUserVisibleAssistantEvent = true;\n }\n yield event;\n }\n\n if (!emittedUserVisibleAssistantEvent || !messageCollector.hasParts()) {\n throw new Error(\n `[hermes-http-adapter] Hermes completed without any assistant content for session ${sessionId}.`,\n );\n }\n\n const message = this.buildAssistantMessage({\n sessionId,\n messageId: run.messageId,\n parts: messageCollector.buildParts(),\n timestamp: new Date().toISOString(),\n metadata,\n });\n yield createHermesMessageCompletedEvent({ message, metadata, run });\n const endedAt = new Date().toISOString();\n yield createHermesRunFinishedEvent({ endedAt, run, startedAt });\n } catch (error) {\n yield* this.createRunErrorEvents({\n error,\n run,\n startedAt,\n fallbackCode: signal.aborted ? \"abort-error\" : \"runtime-error\",\n });\n }\n };\n\n private createRunErrorEvents = function* (\n this: HermesHttpAdapterRouteService,\n params: {\n error: unknown;\n fallbackCode: \"abort-error\" | \"runtime-error\";\n run: HermesHttpAdapterRun;\n startedAt: string;\n },\n ): Generator<NcpEndpointEvent> {\n const { error, fallbackCode, run, startedAt } = params;\n const ncpError = toNcpError(error, fallbackCode);\n yield createHermesMessageFailedEvent({ error: ncpError, run });\n const endedAt = new Date().toISOString();\n yield createHermesRunErrorEvent({ endedAt, error: ncpError, run, startedAt });\n };\n\n private ensureHermesSessionModel = async (params: {\n sessionId: string;\n requestedModel: string;\n signal: AbortSignal;\n }): Promise<void> => {\n const { requestedModel, sessionId, signal } = params;\n const selectedModel = this.sessions.readSelectedModel(sessionId) ?? this.config.model;\n if (selectedModel === requestedModel) {\n return;\n }\n\n const response = await this.fetchHermesChatCompletion({\n sessionId,\n signal,\n stream: false,\n model: requestedModel,\n messages: [\n {\n role: \"user\",\n content: `/model ${requestedModel}`,\n },\n ],\n });\n\n const payload = await this.readJsonResponse<{\n choices?: Array<{\n message?: {\n content?: unknown;\n };\n }>;\n }>(response);\n const content = payload.choices?.[0]?.message?.content;\n if (typeof content === \"string\" && content.trim().startsWith(\"Error:\")) {\n throw new Error(\n `[hermes-http-adapter] failed to switch Hermes model to ${requestedModel}: ${content.trim()}`,\n );\n }\n\n this.sessions.setSelectedModel(sessionId, requestedModel);\n };\n\n private fetchHermesChatCompletion = async (params: {\n sessionId: string;\n signal: AbortSignal;\n stream: boolean;\n model: string;\n providerRoute?: HermesProviderRoute;\n messages: Array<{ role: \"system\" | \"user\" | \"assistant\"; content: string }>;\n tools?: ReadonlyArray<OpenAITool>;\n }): Promise<Response> => {\n const { messages, model, providerRoute, sessionId, signal, stream, tools } = params;\n const headers = new Headers({\n \"content-type\": \"application/json\",\n accept: stream ? \"text/event-stream\" : \"application/json\",\n });\n if (this.config.hermesApiKey) {\n headers.set(\"authorization\", `Bearer ${this.config.hermesApiKey}`);\n }\n\n const hermesSessionId = this.sessions.readHermesSessionId(sessionId);\n if (hermesSessionId) {\n headers.set(\"x-hermes-session-id\", hermesSessionId);\n }\n\n const response = await this.fetchImpl(this.config.chatCompletionsUrl, {\n method: \"POST\",\n headers,\n signal,\n body: JSON.stringify({\n model,\n stream,\n messages,\n ...(providerRoute\n ? {\n nextclaw_provider_route:\n this.toHermesProviderRoutePayload(providerRoute),\n }\n : {}),\n ...(tools && tools.length > 0 ? { tools } : {}),\n }),\n });\n if (!response.ok) {\n throw new Error(\n `[hermes-http-adapter] Hermes request failed with HTTP ${response.status}.`,\n );\n }\n\n const returnedSessionId = response.headers.get(\"x-hermes-session-id\")?.trim();\n if (returnedSessionId) {\n this.sessions.setHermesSessionId(sessionId, returnedSessionId);\n }\n\n return response;\n };\n\n private readProviderRoute = (\n envelope: NcpRequestEnvelope,\n ): HermesProviderRoute | undefined => {\n const providerRoute = readHermesProviderRoute(envelope);\n if (!providerRoute) {\n return undefined;\n }\n if (!providerRoute.apiBase) {\n throw new Error(\n `[hermes-http-adapter] missing provider apiBase for model \"${providerRoute.model}\". Configure the selected NextClaw provider before using Hermes.`,\n );\n }\n return providerRoute;\n };\n\n private toHermesProviderRoutePayload = (\n providerRoute: HermesProviderRoute,\n ): Record<string, unknown> => {\n const inferredProvider = inferHermesProvider(providerRoute);\n return {\n model: providerRoute.model,\n ...(inferredProvider ? { provider: inferredProvider } : {}),\n ...(providerRoute.apiKey ? { api_key: providerRoute.apiKey } : {}),\n ...(providerRoute.apiBase ? { base_url: providerRoute.apiBase } : {}),\n ...(providerRoute.apiMode ? { api_mode: providerRoute.apiMode } : {}),\n ...(Object.keys(providerRoute.headers).length > 0\n ? { extra_headers: providerRoute.headers }\n : {}),\n };\n };\n\n private readJsonResponse = async <T>(response: Response): Promise<T> => {\n try {\n return (await response.json()) as T;\n } catch (error) {\n throw new Error(\n `[hermes-http-adapter] expected JSON response from Hermes: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n };\n\n private readJsonBody = async <T>(request: IncomingMessage): Promise<T> => {\n const chunks: Buffer[] = [];\n for await (const chunk of request) {\n chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));\n }\n const body = Buffer.concat(chunks).toString(\"utf8\");\n if (!body.trim()) {\n throw new Error(\"request body is empty\");\n }\n return JSON.parse(body) as T;\n };\n\n private writeJson = (\n response: ServerResponse,\n statusCode: number,\n payload: unknown,\n ): void => {\n response.writeHead(statusCode, {\n \"content-type\": \"application/json; charset=utf-8\",\n });\n response.end(JSON.stringify(payload));\n };\n}\n\nexport class HermesHttpAdapterServer {\n readonly config: HermesHttpAdapterResolvedConfig;\n\n private readonly routeService: HermesHttpAdapterRouteService;\n private server: Server | null = null;\n\n constructor(configInput: HermesHttpAdapterConfigInput = {}) {\n this.config = new HermesHttpAdapterConfigResolver(configInput).resolve();\n this.routeService = new HermesHttpAdapterRouteService(this.config);\n }\n\n start = async (): Promise<void> => {\n if (this.server) {\n return;\n }\n const nextServer = createServer((request, response) => {\n void this.routeService.handle(request, response);\n });\n await new Promise<void>((resolve, reject) => {\n nextServer.once(\"error\", reject);\n nextServer.listen(this.config.port, this.config.host, () => {\n nextServer.off(\"error\", reject);\n resolve();\n });\n });\n this.server = nextServer;\n };\n\n stop = async (): Promise<void> => {\n this.routeService.dispose();\n const activeServer = this.server;\n if (!activeServer) {\n return;\n }\n await new Promise<void>((resolve, reject) => {\n activeServer.close((error) => {\n if (error) {\n reject(error);\n return;\n }\n resolve();\n });\n });\n this.server = null;\n };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
//#region src/hermes-inline-tool-trace.utils.ts
|
|
2
|
+
const HERMES_INLINE_TOOL_TRACE_PATTERNS = [{
|
|
3
|
+
icon: "🔎",
|
|
4
|
+
toolName: "search_files",
|
|
5
|
+
buildArgs: (rawArgs) => JSON.stringify({ pattern: rawArgs })
|
|
6
|
+
}, {
|
|
7
|
+
icon: "💻",
|
|
8
|
+
toolName: "terminal",
|
|
9
|
+
buildArgs: (rawArgs) => JSON.stringify({ command: rawArgs })
|
|
10
|
+
}];
|
|
11
|
+
function matchHermesInlineToolTrace(segment) {
|
|
12
|
+
const trimmed = segment.trim();
|
|
13
|
+
if (!trimmed.startsWith("`") || !trimmed.endsWith("`")) return null;
|
|
14
|
+
const body = trimmed.slice(1, -1).trim();
|
|
15
|
+
for (const candidate of HERMES_INLINE_TOOL_TRACE_PATTERNS) {
|
|
16
|
+
if (!body.startsWith(candidate.icon)) continue;
|
|
17
|
+
const rawArgs = body.slice(candidate.icon.length).trim();
|
|
18
|
+
if (!rawArgs) return null;
|
|
19
|
+
return {
|
|
20
|
+
toolName: candidate.toolName,
|
|
21
|
+
args: candidate.buildArgs(rawArgs)
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
//#endregion
|
|
27
|
+
export { matchHermesInlineToolTrace };
|
|
28
|
+
|
|
29
|
+
//# sourceMappingURL=hermes-inline-tool-trace.utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hermes-inline-tool-trace.utils.js","names":[],"sources":["../src/hermes-inline-tool-trace.utils.ts"],"sourcesContent":["export type HermesInlineToolTrace = {\n toolName: string;\n args: string;\n};\n\nconst HERMES_INLINE_TOOL_TRACE_PATTERNS: Array<{\n icon: string;\n toolName: string;\n buildArgs: (rawArgs: string) => string;\n}> = [\n {\n icon: \"🔎\",\n toolName: \"search_files\",\n buildArgs: (rawArgs) => JSON.stringify({ pattern: rawArgs }),\n },\n {\n icon: \"💻\",\n toolName: \"terminal\",\n buildArgs: (rawArgs) => JSON.stringify({ command: rawArgs }),\n },\n];\n\nexport function matchHermesInlineToolTrace(segment: string): HermesInlineToolTrace | null {\n const trimmed = segment.trim();\n if (!trimmed.startsWith(\"`\") || !trimmed.endsWith(\"`\")) {\n return null;\n }\n\n const body = trimmed.slice(1, -1).trim();\n for (const candidate of HERMES_INLINE_TOOL_TRACE_PATTERNS) {\n if (!body.startsWith(candidate.icon)) {\n continue;\n }\n const rawArgs = body.slice(candidate.icon.length).trim();\n if (!rawArgs) {\n return null;\n }\n return {\n toolName: candidate.toolName,\n args: candidate.buildArgs(rawArgs),\n };\n }\n\n return null;\n}\n"],"mappings":";AAKA,MAAM,oCAID,CACH;CACE,MAAM;CACN,UAAU;CACV,YAAY,YAAY,KAAK,UAAU,EAAE,SAAS,SAAS,CAAC;CAC7D,EACD;CACE,MAAM;CACN,UAAU;CACV,YAAY,YAAY,KAAK,UAAU,EAAE,SAAS,SAAS,CAAC;CAC7D,CACF;AAED,SAAgB,2BAA2B,SAA+C;CACxF,MAAM,UAAU,QAAQ,MAAM;AAC9B,KAAI,CAAC,QAAQ,WAAW,IAAI,IAAI,CAAC,QAAQ,SAAS,IAAI,CACpD,QAAO;CAGT,MAAM,OAAO,QAAQ,MAAM,GAAG,GAAG,CAAC,MAAM;AACxC,MAAK,MAAM,aAAa,mCAAmC;AACzD,MAAI,CAAC,KAAK,WAAW,UAAU,KAAK,CAClC;EAEF,MAAM,UAAU,KAAK,MAAM,UAAU,KAAK,OAAO,CAAC,MAAM;AACxD,MAAI,CAAC,QACH,QAAO;AAET,SAAO;GACL,UAAU,UAAU;GACpB,MAAM,UAAU,UAAU,QAAQ;GACnC;;AAGH,QAAO"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nextclaw/nextclaw-ncp-runtime-adapter-hermes-http",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Standalone NCP HTTP adapter server that bridges NextClaw http-runtime sessions to Hermes API Server.",
|
|
6
6
|
"type": "module",
|
|
@@ -19,9 +19,9 @@
|
|
|
19
19
|
"README.md"
|
|
20
20
|
],
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@nextclaw/ncp-agent-runtime": "0.
|
|
23
|
-
"@nextclaw/ncp": "0.
|
|
24
|
-
"@nextclaw/ncp
|
|
22
|
+
"@nextclaw/ncp-agent-runtime": "0.4.0",
|
|
23
|
+
"@nextclaw/ncp-http-agent-client": "0.4.0",
|
|
24
|
+
"@nextclaw/ncp": "0.7.0"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
27
|
"@types/node": "^20.17.6",
|