@nextclaw/ncp-react 0.2.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +3 -2
- package/dist/index.js +67 -14
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import { NcpAgentConversationSnapshot, NcpMessage, NcpAgentClientEndpoint } from '@nextclaw/ncp';
|
|
1
|
+
import { NcpAgentConversationSnapshot, NcpMessage, NcpRequestEnvelope, NcpAgentClientEndpoint } from '@nextclaw/ncp';
|
|
2
2
|
|
|
3
|
+
type NcpAgentSendInput = string | NcpRequestEnvelope;
|
|
3
4
|
type UseNcpAgentResult = {
|
|
4
5
|
snapshot: NcpAgentConversationSnapshot;
|
|
5
6
|
visibleMessages: readonly NcpMessage[];
|
|
6
7
|
activeRunId: string | null;
|
|
7
8
|
isRunning: boolean;
|
|
8
9
|
isSending: boolean;
|
|
9
|
-
send: (
|
|
10
|
+
send: (input: NcpAgentSendInput) => Promise<void>;
|
|
10
11
|
abort: () => Promise<void>;
|
|
11
12
|
streamRun: () => Promise<void>;
|
|
12
13
|
};
|
package/dist/index.js
CHANGED
|
@@ -4,7 +4,9 @@ import { useCallback, useEffect as useEffect2, useRef as useRef2, useState as us
|
|
|
4
4
|
// src/hooks/use-ncp-agent-runtime.ts
|
|
5
5
|
import { useEffect, useRef, useState, useSyncExternalStore } from "react";
|
|
6
6
|
import { DefaultNcpAgentConversationStateManager } from "@nextclaw/ncp-toolkit";
|
|
7
|
-
import
|
|
7
|
+
import {
|
|
8
|
+
NcpEventType
|
|
9
|
+
} from "@nextclaw/ncp";
|
|
8
10
|
function shouldDispatchEventToSession(event, sessionId) {
|
|
9
11
|
const payload = "payload" in event ? event.payload : null;
|
|
10
12
|
if (!payload || typeof payload !== "object") {
|
|
@@ -15,6 +17,51 @@ function shouldDispatchEventToSession(event, sessionId) {
|
|
|
15
17
|
}
|
|
16
18
|
return payload.sessionId === sessionId;
|
|
17
19
|
}
|
|
20
|
+
function hasMessageContent(message) {
|
|
21
|
+
return message.parts.some((part) => {
|
|
22
|
+
if (part.type === "text" || part.type === "rich-text" || part.type === "reasoning") {
|
|
23
|
+
return part.text.trim().length > 0;
|
|
24
|
+
}
|
|
25
|
+
return true;
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
function normalizeSendEnvelope(input, sessionId) {
|
|
29
|
+
if (typeof input === "string") {
|
|
30
|
+
const content = input.trim();
|
|
31
|
+
if (!content) {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
sessionId,
|
|
36
|
+
message: {
|
|
37
|
+
id: `user-${Date.now().toString(36)}`,
|
|
38
|
+
sessionId,
|
|
39
|
+
role: "user",
|
|
40
|
+
status: "final",
|
|
41
|
+
parts: [{ type: "text", text: content }],
|
|
42
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
if (!hasMessageContent(input.message)) {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
return {
|
|
50
|
+
...input,
|
|
51
|
+
sessionId: input.sessionId,
|
|
52
|
+
message: {
|
|
53
|
+
...input.message,
|
|
54
|
+
sessionId: input.message.sessionId || input.sessionId
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
function toHydrationPayload(sessionId, snapshot) {
|
|
59
|
+
return {
|
|
60
|
+
sessionId,
|
|
61
|
+
messages: snapshot.messages,
|
|
62
|
+
activeRun: snapshot.activeRun
|
|
63
|
+
};
|
|
64
|
+
}
|
|
18
65
|
function useScopedAgentManager(sessionId) {
|
|
19
66
|
const managerRef = useRef();
|
|
20
67
|
if (!managerRef.current || managerRef.current.sessionId !== sessionId) {
|
|
@@ -54,23 +101,29 @@ function useNcpAgentRuntime({
|
|
|
54
101
|
const visibleMessages = snapshot.streamingMessage ? [...snapshot.messages, snapshot.streamingMessage] : snapshot.messages;
|
|
55
102
|
const activeRunId = snapshot.activeRun?.runId ?? null;
|
|
56
103
|
const isRunning = !!snapshot.activeRun;
|
|
57
|
-
const send = async (
|
|
58
|
-
if (
|
|
104
|
+
const send = async (input) => {
|
|
105
|
+
if (isSending || isRunning) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
const envelope = normalizeSendEnvelope(input, sessionId);
|
|
109
|
+
if (!envelope) {
|
|
59
110
|
return;
|
|
60
111
|
}
|
|
61
112
|
setIsSending(true);
|
|
62
|
-
|
|
63
|
-
|
|
113
|
+
const previousSnapshot = manager.getSnapshot();
|
|
114
|
+
await manager.dispatch({
|
|
115
|
+
type: NcpEventType.MessageSent,
|
|
116
|
+
payload: {
|
|
64
117
|
sessionId,
|
|
65
|
-
message:
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
118
|
+
message: envelope.message,
|
|
119
|
+
metadata: envelope.metadata
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
try {
|
|
123
|
+
await client.send(envelope);
|
|
124
|
+
} catch (error) {
|
|
125
|
+
manager.hydrate(toHydrationPayload(sessionId, previousSnapshot));
|
|
126
|
+
throw error;
|
|
74
127
|
} finally {
|
|
75
128
|
setIsSending(false);
|
|
76
129
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nextclaw/ncp-react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "React bindings for building NCP-based agent applications.",
|
|
6
6
|
"type": "module",
|
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
"dist"
|
|
16
16
|
],
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@nextclaw/ncp
|
|
19
|
-
"@nextclaw/ncp": "0.
|
|
18
|
+
"@nextclaw/ncp": "0.3.0",
|
|
19
|
+
"@nextclaw/ncp-toolkit": "0.4.0"
|
|
20
20
|
},
|
|
21
21
|
"peerDependencies": {
|
|
22
22
|
"react": "^18.0.0 || ^19.0.0"
|