use-acp 0.1.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/LICENSE +202 -0
- package/README.md +110 -0
- package/dist/client/acp-client.d.ts +40 -0
- package/dist/client/acp-client.d.ts.map +1 -0
- package/dist/client/acp-client.js +88 -0
- package/dist/client/acp-client.js.map +1 -0
- package/dist/client/types.d.ts +25 -0
- package/dist/client/types.d.ts.map +1 -0
- package/dist/client/types.js +2 -0
- package/dist/client/types.js.map +1 -0
- package/dist/components/diff-viewer.d.ts +2 -0
- package/dist/components/diff-viewer.d.ts.map +1 -0
- package/dist/components/diff-viewer.js +2 -0
- package/dist/components/diff-viewer.js.map +1 -0
- package/dist/components/request-perms.d.ts +2 -0
- package/dist/components/request-perms.d.ts.map +1 -0
- package/dist/components/request-perms.js +2 -0
- package/dist/components/request-perms.js.map +1 -0
- package/dist/components/streams.d.ts +25 -0
- package/dist/components/streams.d.ts.map +1 -0
- package/dist/components/streams.js +74 -0
- package/dist/components/streams.js.map +1 -0
- package/dist/connection/websocket-manager.d.ts +27 -0
- package/dist/connection/websocket-manager.d.ts.map +1 -0
- package/dist/connection/websocket-manager.js +109 -0
- package/dist/connection/websocket-manager.js.map +1 -0
- package/dist/hooks/use-acp-client.d.ts +23 -0
- package/dist/hooks/use-acp-client.d.ts.map +1 -0
- package/dist/hooks/use-acp-client.js +146 -0
- package/dist/hooks/use-acp-client.js.map +1 -0
- package/dist/hooks/use-event-callback.d.ts +3 -0
- package/dist/hooks/use-event-callback.d.ts.map +1 -0
- package/dist/hooks/use-event-callback.js +13 -0
- package/dist/hooks/use-event-callback.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/state/atoms.d.ts +14 -0
- package/dist/state/atoms.d.ts.map +1 -0
- package/dist/state/atoms.js +48 -0
- package/dist/state/atoms.js.map +1 -0
- package/dist/state/types.d.ts +21 -0
- package/dist/state/types.d.ts.map +1 -0
- package/dist/state/types.js +2 -0
- package/dist/state/types.js.map +1 -0
- package/dist/state/utils.d.ts +8 -0
- package/dist/state/utils.d.ts.map +1 -0
- package/dist/state/utils.js +53 -0
- package/dist/state/utils.js.map +1 -0
- package/dist/utils/deferred.d.ts +7 -0
- package/dist/utils/deferred.d.ts.map +1 -0
- package/dist/utils/deferred.js +12 -0
- package/dist/utils/deferred.js.map +1 -0
- package/dist/utils/never.d.ts +3 -0
- package/dist/utils/never.d.ts.map +1 -0
- package/dist/utils/never.js +9 -0
- package/dist/utils/never.js.map +1 -0
- package/package.json +79 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { type NodeReadableStream } from "../components/streams.js";
|
|
2
|
+
import type { ConnectionState } from "../state/types.js";
|
|
3
|
+
export interface WebSocketManagerOptions {
|
|
4
|
+
url: string;
|
|
5
|
+
onConnectionStateChange: (state: ConnectionState) => void;
|
|
6
|
+
onError: (error: Error) => void;
|
|
7
|
+
reconnectAttempts?: number;
|
|
8
|
+
reconnectDelay?: number;
|
|
9
|
+
}
|
|
10
|
+
export declare class WebSocketManager {
|
|
11
|
+
private ws;
|
|
12
|
+
private options;
|
|
13
|
+
private reconnectCount;
|
|
14
|
+
private reconnectTimer;
|
|
15
|
+
private readableStream;
|
|
16
|
+
private writableStream;
|
|
17
|
+
constructor(options: WebSocketManagerOptions);
|
|
18
|
+
connect(): Promise<{
|
|
19
|
+
readable: NodeReadableStream;
|
|
20
|
+
writable: WritableStream<Uint8Array>;
|
|
21
|
+
}>;
|
|
22
|
+
disconnect(): void;
|
|
23
|
+
private attemptReconnect;
|
|
24
|
+
private updateConnectionState;
|
|
25
|
+
getConnectionState(): ConnectionState["status"];
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=websocket-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"websocket-manager.d.ts","sourceRoot":"","sources":["../../src/connection/websocket-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,kBAAkB,EACxB,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEzD,MAAM,WAAW,uBAAuB;IACtC,GAAG,EAAE,MAAM,CAAC;IACZ,uBAAuB,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,CAAC;IAC1D,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAChC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,EAAE,CAA0B;IACpC,OAAO,CAAC,OAAO,CAA0B;IACzC,OAAO,CAAC,cAAc,CAAK;IAC3B,OAAO,CAAC,cAAc,CAA+B;IACrD,OAAO,CAAC,cAAc,CAAmC;IACzD,OAAO,CAAC,cAAc,CAA2C;gBAErD,OAAO,EAAE,uBAAuB;IAQtC,OAAO,IAAI,OAAO,CAAC;QAAE,QAAQ,EAAE,kBAAkB,CAAC;QAAC,QAAQ,EAAE,cAAc,CAAC,UAAU,CAAC,CAAA;KAAE,CAAC;IAuDhG,UAAU;IAgBV,OAAO,CAAC,gBAAgB;IAaxB,OAAO,CAAC,qBAAqB;IAI7B,kBAAkB,IAAI,eAAe,CAAC,QAAQ,CAAC;CAehD"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { createWebSocketReadableStream, createWebSocketWritableStream, } from "../components/streams.js";
|
|
2
|
+
export class WebSocketManager {
|
|
3
|
+
ws = null;
|
|
4
|
+
options;
|
|
5
|
+
reconnectCount = 0;
|
|
6
|
+
reconnectTimer = null;
|
|
7
|
+
readableStream = null;
|
|
8
|
+
writableStream = null;
|
|
9
|
+
constructor(options) {
|
|
10
|
+
this.options = {
|
|
11
|
+
reconnectAttempts: 3,
|
|
12
|
+
reconnectDelay: 1000,
|
|
13
|
+
...options,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
async connect() {
|
|
17
|
+
this.updateConnectionState({ status: "connecting", url: this.options.url });
|
|
18
|
+
try {
|
|
19
|
+
this.ws = new WebSocket(this.options.url);
|
|
20
|
+
return new Promise((resolve, reject) => {
|
|
21
|
+
if (!this.ws) {
|
|
22
|
+
reject(new Error("WebSocket not initialized"));
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
this.ws.onopen = () => {
|
|
26
|
+
this.reconnectCount = 0;
|
|
27
|
+
this.updateConnectionState({ status: "connected", url: this.options.url });
|
|
28
|
+
if (this.ws) {
|
|
29
|
+
this.readableStream = createWebSocketReadableStream(this.ws);
|
|
30
|
+
this.writableStream = createWebSocketWritableStream(this.ws);
|
|
31
|
+
resolve({
|
|
32
|
+
readable: this.readableStream,
|
|
33
|
+
writable: this.writableStream,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
this.ws.onerror = (_event) => {
|
|
38
|
+
const error = new Error("WebSocket connection error");
|
|
39
|
+
this.options.onError(error);
|
|
40
|
+
this.updateConnectionState({
|
|
41
|
+
status: "error",
|
|
42
|
+
error: error.message,
|
|
43
|
+
url: this.options.url,
|
|
44
|
+
});
|
|
45
|
+
reject(error);
|
|
46
|
+
};
|
|
47
|
+
this.ws.onclose = () => {
|
|
48
|
+
this.updateConnectionState({ status: "disconnected", url: this.options.url });
|
|
49
|
+
this.attemptReconnect();
|
|
50
|
+
};
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
const errorObj = error instanceof Error ? error : new Error(String(error));
|
|
55
|
+
this.options.onError(errorObj);
|
|
56
|
+
this.updateConnectionState({
|
|
57
|
+
status: "error",
|
|
58
|
+
error: errorObj.message,
|
|
59
|
+
url: this.options.url,
|
|
60
|
+
});
|
|
61
|
+
throw errorObj;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
disconnect() {
|
|
65
|
+
if (this.reconnectTimer) {
|
|
66
|
+
clearTimeout(this.reconnectTimer);
|
|
67
|
+
this.reconnectTimer = null;
|
|
68
|
+
}
|
|
69
|
+
if (this.ws) {
|
|
70
|
+
this.ws.close();
|
|
71
|
+
this.ws = null;
|
|
72
|
+
}
|
|
73
|
+
this.readableStream = null;
|
|
74
|
+
this.writableStream = null;
|
|
75
|
+
this.updateConnectionState({ status: "disconnected" });
|
|
76
|
+
}
|
|
77
|
+
attemptReconnect() {
|
|
78
|
+
if (this.reconnectCount < (this.options.reconnectAttempts || 3)) {
|
|
79
|
+
this.reconnectCount++;
|
|
80
|
+
this.reconnectTimer = setTimeout(async () => {
|
|
81
|
+
try {
|
|
82
|
+
await this.connect();
|
|
83
|
+
}
|
|
84
|
+
catch (_error) {
|
|
85
|
+
// Error is already handled in connect method
|
|
86
|
+
}
|
|
87
|
+
}, this.options.reconnectDelay);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
updateConnectionState(state) {
|
|
91
|
+
this.options.onConnectionStateChange(state);
|
|
92
|
+
}
|
|
93
|
+
getConnectionState() {
|
|
94
|
+
if (!this.ws)
|
|
95
|
+
return "disconnected";
|
|
96
|
+
switch (this.ws.readyState) {
|
|
97
|
+
case WebSocket.CONNECTING:
|
|
98
|
+
return "connecting";
|
|
99
|
+
case WebSocket.OPEN:
|
|
100
|
+
return "connected";
|
|
101
|
+
case WebSocket.CLOSING:
|
|
102
|
+
case WebSocket.CLOSED:
|
|
103
|
+
return "disconnected";
|
|
104
|
+
default:
|
|
105
|
+
return "error";
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=websocket-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"websocket-manager.js","sourceRoot":"","sources":["../../src/connection/websocket-manager.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n createWebSocketReadableStream,\n createWebSocketWritableStream,\n type NodeReadableStream,\n} from \"../components/streams.js\";\nimport type { ConnectionState } from \"../state/types.js\";\n\nexport interface WebSocketManagerOptions {\n url: string;\n onConnectionStateChange: (state: ConnectionState) => void;\n onError: (error: Error) => void;\n reconnectAttempts?: number;\n reconnectDelay?: number;\n}\n\nexport class WebSocketManager {\n private ws: WebSocket | null = null;\n private options: WebSocketManagerOptions;\n private reconnectCount = 0;\n private reconnectTimer: NodeJS.Timeout | null = null;\n private readableStream: NodeReadableStream | null = null;\n private writableStream: WritableStream<Uint8Array> | null = null;\n\n constructor(options: WebSocketManagerOptions) {\n this.options = {\n reconnectAttempts: 3,\n reconnectDelay: 1000,\n ...options,\n };\n }\n\n async connect(): Promise<{ readable: NodeReadableStream; writable: WritableStream<Uint8Array> }> {\n this.updateConnectionState({ status: \"connecting\", url: this.options.url });\n\n try {\n this.ws = new WebSocket(this.options.url);\n\n return new Promise((resolve, reject) => {\n if (!this.ws) {\n reject(new Error(\"WebSocket not initialized\"));\n return;\n }\n\n this.ws.onopen = () => {\n this.reconnectCount = 0;\n this.updateConnectionState({ status: \"connected\", url: this.options.url });\n\n if (this.ws) {\n this.readableStream = createWebSocketReadableStream(this.ws);\n this.writableStream = createWebSocketWritableStream(this.ws);\n\n resolve({\n readable: this.readableStream,\n writable: this.writableStream,\n });\n }\n };\n\n this.ws.onerror = (_event) => {\n const error = new Error(\"WebSocket connection error\");\n this.options.onError(error);\n this.updateConnectionState({\n status: \"error\",\n error: error.message,\n url: this.options.url,\n });\n reject(error);\n };\n\n this.ws.onclose = () => {\n this.updateConnectionState({ status: \"disconnected\", url: this.options.url });\n this.attemptReconnect();\n };\n });\n } catch (error) {\n const errorObj = error instanceof Error ? error : new Error(String(error));\n this.options.onError(errorObj);\n this.updateConnectionState({\n status: \"error\",\n error: errorObj.message,\n url: this.options.url,\n });\n throw errorObj;\n }\n }\n\n disconnect() {\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n\n if (this.ws) {\n this.ws.close();\n this.ws = null;\n }\n\n this.readableStream = null;\n this.writableStream = null;\n this.updateConnectionState({ status: \"disconnected\" });\n }\n\n private attemptReconnect() {\n if (this.reconnectCount < (this.options.reconnectAttempts || 3)) {\n this.reconnectCount++;\n this.reconnectTimer = setTimeout(async () => {\n try {\n await this.connect();\n } catch (_error) {\n // Error is already handled in connect method\n }\n }, this.options.reconnectDelay);\n }\n }\n\n private updateConnectionState(state: ConnectionState) {\n this.options.onConnectionStateChange(state);\n }\n\n getConnectionState(): ConnectionState[\"status\"] {\n if (!this.ws) return \"disconnected\";\n\n switch (this.ws.readyState) {\n case WebSocket.CONNECTING:\n return \"connecting\";\n case WebSocket.OPEN:\n return \"connected\";\n case WebSocket.CLOSING:\n case WebSocket.CLOSED:\n return \"disconnected\";\n default:\n return \"error\";\n }\n }\n}\n"]}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type Agent, type RequestPermissionResponse } from "@zed-industries/agent-client-protocol";
|
|
2
|
+
import { type IdentifiedPermissionRequest } from "../client/acp-client.js";
|
|
3
|
+
import type { ConnectionState, NotificationEvent } from "../state/types.js";
|
|
4
|
+
export interface UseAcpClientOptions {
|
|
5
|
+
wsUrl: string;
|
|
6
|
+
autoConnect?: boolean;
|
|
7
|
+
reconnectAttempts?: number;
|
|
8
|
+
reconnectDelay?: number;
|
|
9
|
+
initialSessionId?: string | null;
|
|
10
|
+
}
|
|
11
|
+
export interface UseAcpClientReturn {
|
|
12
|
+
connect: () => Promise<void>;
|
|
13
|
+
disconnect: () => void;
|
|
14
|
+
connectionState: ConnectionState;
|
|
15
|
+
notifications: NotificationEvent[];
|
|
16
|
+
clearNotifications: () => void;
|
|
17
|
+
pendingPermission: IdentifiedPermissionRequest | null;
|
|
18
|
+
resolvePermission: (response: RequestPermissionResponse) => void;
|
|
19
|
+
rejectPermission: (error: Error) => void;
|
|
20
|
+
agent: Agent | null;
|
|
21
|
+
}
|
|
22
|
+
export declare function useAcpClient(options: UseAcpClientOptions): UseAcpClientReturn;
|
|
23
|
+
//# sourceMappingURL=use-acp-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-acp-client.d.ts","sourceRoot":"","sources":["../../src/hooks/use-acp-client.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,KAAK,EAEV,KAAK,yBAAyB,EAE/B,MAAM,uCAAuC,CAAC;AAE/C,OAAO,EAEL,KAAK,2BAA2B,EAEjC,MAAM,yBAAyB,CAAC;AAGjC,OAAO,KAAK,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAG5E,MAAM,WAAW,mBAAmB;IAElC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;IAGxB,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC;AAED,MAAM,WAAW,kBAAkB;IAEjC,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,eAAe,EAAE,eAAe,CAAC;IAGjC,aAAa,EAAE,iBAAiB,EAAE,CAAC;IACnC,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAG/B,iBAAiB,EAAE,2BAA2B,GAAG,IAAI,CAAC;IACtD,iBAAiB,EAAE,CAAC,QAAQ,EAAE,yBAAyB,KAAK,IAAI,CAAC;IACjE,gBAAgB,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAGzC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;CACrB;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,kBAAkB,CA+K7E"}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { ClientSideConnection, } from "@zed-industries/agent-client-protocol";
|
|
2
|
+
import { useEffect, useRef, useState } from "react";
|
|
3
|
+
import { AcpClient, ListeningAgent, } from "../client/acp-client.js";
|
|
4
|
+
import { WebSocketManager } from "../connection/websocket-manager.js";
|
|
5
|
+
import { useAcpStore } from "../state/atoms.js";
|
|
6
|
+
import { useEventCallback } from "./use-event-callback.js";
|
|
7
|
+
export function useAcpClient(options) {
|
|
8
|
+
const { connectionState, notifications, activeSessionId, setActiveSessionId, setConnectionState, addNotification, clearNotifications, } = useAcpStore();
|
|
9
|
+
// State
|
|
10
|
+
const [pendingPermission, setPendingPermission] = useState(null);
|
|
11
|
+
const [agent, setAgent] = useState(null);
|
|
12
|
+
// Refs
|
|
13
|
+
const wsManagerRef = useRef(null);
|
|
14
|
+
const acpClientRef = useRef(null);
|
|
15
|
+
// Handlers
|
|
16
|
+
const handleConnectionStateChange = useEventCallback((state) => {
|
|
17
|
+
setConnectionState(state);
|
|
18
|
+
addNotification({
|
|
19
|
+
type: "connection_change",
|
|
20
|
+
data: state,
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
const handleError = useEventCallback((error) => {
|
|
24
|
+
addNotification({
|
|
25
|
+
type: "error",
|
|
26
|
+
data: error,
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
const handleSessionNotification = useEventCallback((notification) => {
|
|
30
|
+
addNotification({
|
|
31
|
+
type: "session_notification",
|
|
32
|
+
data: notification,
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
const handleRequestPermission = useEventCallback((params) => {
|
|
36
|
+
setPendingPermission(params);
|
|
37
|
+
});
|
|
38
|
+
const connect = useEventCallback(async () => {
|
|
39
|
+
if (wsManagerRef.current ||
|
|
40
|
+
connectionState.status === "connecting" ||
|
|
41
|
+
connectionState.status === "connected") {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const wsManager = new WebSocketManager({
|
|
45
|
+
url: options.wsUrl,
|
|
46
|
+
onConnectionStateChange: handleConnectionStateChange,
|
|
47
|
+
onError: handleError,
|
|
48
|
+
reconnectAttempts: options.reconnectAttempts,
|
|
49
|
+
reconnectDelay: options.reconnectDelay,
|
|
50
|
+
});
|
|
51
|
+
wsManagerRef.current = wsManager;
|
|
52
|
+
try {
|
|
53
|
+
const { readable, writable } = await wsManager.connect();
|
|
54
|
+
// Initialize the connection
|
|
55
|
+
const agent = new ClientSideConnection((agent) => {
|
|
56
|
+
// Initialize the ACP client
|
|
57
|
+
const acpClient = new AcpClient(agent, {
|
|
58
|
+
onRequestPermission: handleRequestPermission,
|
|
59
|
+
onSessionNotification: handleSessionNotification,
|
|
60
|
+
});
|
|
61
|
+
acpClientRef.current = acpClient;
|
|
62
|
+
return acpClient;
|
|
63
|
+
}, writable, readable);
|
|
64
|
+
const listeningAgent = new ListeningAgent(agent, {
|
|
65
|
+
on_newSession_response: (response) => {
|
|
66
|
+
setActiveSessionId(response.sessionId);
|
|
67
|
+
},
|
|
68
|
+
on_prompt_start: (params) => {
|
|
69
|
+
for (const prompt of params.prompt) {
|
|
70
|
+
addNotification({
|
|
71
|
+
type: "session_notification",
|
|
72
|
+
data: {
|
|
73
|
+
sessionId: params.sessionId,
|
|
74
|
+
update: {
|
|
75
|
+
sessionUpdate: "user_message_chunk",
|
|
76
|
+
content: prompt,
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
setAgent(listeningAgent);
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
wsManagerRef.current = null;
|
|
87
|
+
throw error;
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
const disconnect = useEventCallback(() => {
|
|
91
|
+
if (wsManagerRef.current) {
|
|
92
|
+
wsManagerRef.current.disconnect();
|
|
93
|
+
wsManagerRef.current = null;
|
|
94
|
+
}
|
|
95
|
+
acpClientRef.current = null;
|
|
96
|
+
setAgent(null);
|
|
97
|
+
setPendingPermission(null);
|
|
98
|
+
});
|
|
99
|
+
const resolvePermission = useEventCallback((response) => {
|
|
100
|
+
if (pendingPermission && acpClientRef.current) {
|
|
101
|
+
const permissionId = pendingPermission.id;
|
|
102
|
+
if (permissionId) {
|
|
103
|
+
acpClientRef.current.resolvePermission(permissionId, response);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
setPendingPermission(null);
|
|
107
|
+
});
|
|
108
|
+
const rejectPermissionCallback = useEventCallback((error) => {
|
|
109
|
+
if (pendingPermission && acpClientRef.current) {
|
|
110
|
+
const permissionId = pendingPermission.id;
|
|
111
|
+
if (permissionId) {
|
|
112
|
+
acpClientRef.current.rejectPermission(permissionId, error);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
setPendingPermission(null);
|
|
116
|
+
});
|
|
117
|
+
// Effects
|
|
118
|
+
// Update active session id if it changes externally
|
|
119
|
+
useEffect(() => {
|
|
120
|
+
if (options.initialSessionId) {
|
|
121
|
+
setActiveSessionId(options.initialSessionId);
|
|
122
|
+
}
|
|
123
|
+
}, [options.initialSessionId, setActiveSessionId]);
|
|
124
|
+
// Auto-connect on mount if specified
|
|
125
|
+
// biome-ignore lint/correctness/useExhaustiveDependencies: Don't include connect/disconnect to avoid re-connecting on every render
|
|
126
|
+
useEffect(() => {
|
|
127
|
+
if (options.autoConnect) {
|
|
128
|
+
connect().catch(console.error);
|
|
129
|
+
}
|
|
130
|
+
return () => {
|
|
131
|
+
disconnect();
|
|
132
|
+
};
|
|
133
|
+
}, [options.autoConnect]);
|
|
134
|
+
return {
|
|
135
|
+
connect,
|
|
136
|
+
disconnect,
|
|
137
|
+
connectionState,
|
|
138
|
+
notifications: activeSessionId ? notifications[activeSessionId] || [] : [],
|
|
139
|
+
clearNotifications,
|
|
140
|
+
pendingPermission,
|
|
141
|
+
resolvePermission,
|
|
142
|
+
rejectPermission: rejectPermissionCallback,
|
|
143
|
+
agent: agent,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
//# sourceMappingURL=use-acp-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-acp-client.js","sourceRoot":"","sources":["../../src/hooks/use-acp-client.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type Agent,\n ClientSideConnection,\n type RequestPermissionResponse,\n type SessionNotification,\n} from \"@zed-industries/agent-client-protocol\";\nimport { useEffect, useRef, useState } from \"react\";\nimport {\n AcpClient,\n type IdentifiedPermissionRequest,\n ListeningAgent,\n} from \"../client/acp-client.js\";\nimport { WebSocketManager } from \"../connection/websocket-manager.js\";\nimport { useAcpStore } from \"../state/atoms.js\";\nimport type { ConnectionState, NotificationEvent } from \"../state/types.js\";\nimport { useEventCallback } from \"./use-event-callback.js\";\n\nexport interface UseAcpClientOptions {\n // Connection management\n wsUrl: string;\n autoConnect?: boolean;\n reconnectAttempts?: number;\n reconnectDelay?: number;\n\n // Defaults\n initialSessionId?: string | null;\n}\n\nexport interface UseAcpClientReturn {\n // Connection management\n connect: () => Promise<void>;\n disconnect: () => void;\n connectionState: ConnectionState;\n\n // State management\n notifications: NotificationEvent[];\n clearNotifications: () => void;\n\n // Permission handling\n pendingPermission: IdentifiedPermissionRequest | null;\n resolvePermission: (response: RequestPermissionResponse) => void;\n rejectPermission: (error: Error) => void;\n\n // ACP connection\n agent: Agent | null;\n}\n\nexport function useAcpClient(options: UseAcpClientOptions): UseAcpClientReturn {\n const {\n connectionState,\n notifications,\n activeSessionId,\n setActiveSessionId,\n setConnectionState,\n addNotification,\n clearNotifications,\n } = useAcpStore();\n\n // State\n const [pendingPermission, setPendingPermission] = useState<IdentifiedPermissionRequest | null>(\n null,\n );\n const [agent, setAgent] = useState<Agent | null>(null);\n\n // Refs\n const wsManagerRef = useRef<WebSocketManager | null>(null);\n const acpClientRef = useRef<AcpClient | null>(null);\n\n // Handlers\n const handleConnectionStateChange = useEventCallback((state: ConnectionState) => {\n setConnectionState(state);\n addNotification({\n type: \"connection_change\",\n data: state,\n });\n });\n\n const handleError = useEventCallback((error: Error) => {\n addNotification({\n type: \"error\",\n data: error,\n });\n });\n\n const handleSessionNotification = useEventCallback((notification: SessionNotification) => {\n addNotification({\n type: \"session_notification\",\n data: notification,\n });\n });\n\n const handleRequestPermission = useEventCallback((params: IdentifiedPermissionRequest) => {\n setPendingPermission(params);\n });\n\n const connect = useEventCallback(async () => {\n if (\n wsManagerRef.current ||\n connectionState.status === \"connecting\" ||\n connectionState.status === \"connected\"\n ) {\n return;\n }\n\n const wsManager = new WebSocketManager({\n url: options.wsUrl,\n onConnectionStateChange: handleConnectionStateChange,\n onError: handleError,\n reconnectAttempts: options.reconnectAttempts,\n reconnectDelay: options.reconnectDelay,\n });\n\n wsManagerRef.current = wsManager;\n\n try {\n const { readable, writable } = await wsManager.connect();\n\n // Initialize the connection\n const agent = new ClientSideConnection(\n (agent) => {\n // Initialize the ACP client\n const acpClient = new AcpClient(agent, {\n onRequestPermission: handleRequestPermission,\n onSessionNotification: handleSessionNotification,\n });\n acpClientRef.current = acpClient;\n return acpClient;\n },\n writable,\n readable,\n );\n\n const listeningAgent: Agent = new ListeningAgent(agent, {\n on_newSession_response: (response) => {\n setActiveSessionId(response.sessionId);\n },\n on_prompt_start: (params) => {\n for (const prompt of params.prompt) {\n addNotification({\n type: \"session_notification\",\n data: {\n sessionId: params.sessionId,\n update: {\n sessionUpdate: \"user_message_chunk\",\n content: prompt,\n },\n },\n });\n }\n },\n });\n\n setAgent(listeningAgent);\n } catch (error) {\n wsManagerRef.current = null;\n throw error;\n }\n });\n\n const disconnect = useEventCallback(() => {\n if (wsManagerRef.current) {\n wsManagerRef.current.disconnect();\n wsManagerRef.current = null;\n }\n\n acpClientRef.current = null;\n setAgent(null);\n setPendingPermission(null);\n });\n\n const resolvePermission = useEventCallback((response: RequestPermissionResponse) => {\n if (pendingPermission && acpClientRef.current) {\n const permissionId = pendingPermission.id;\n if (permissionId) {\n acpClientRef.current.resolvePermission(permissionId, response);\n }\n }\n setPendingPermission(null);\n });\n\n const rejectPermissionCallback = useEventCallback((error: Error) => {\n if (pendingPermission && acpClientRef.current) {\n const permissionId = pendingPermission.id;\n if (permissionId) {\n acpClientRef.current.rejectPermission(permissionId, error);\n }\n }\n setPendingPermission(null);\n });\n\n // Effects\n\n // Update active session id if it changes externally\n useEffect(() => {\n if (options.initialSessionId) {\n setActiveSessionId(options.initialSessionId);\n }\n }, [options.initialSessionId, setActiveSessionId]);\n\n // Auto-connect on mount if specified\n // biome-ignore lint/correctness/useExhaustiveDependencies: Don't include connect/disconnect to avoid re-connecting on every render\n useEffect(() => {\n if (options.autoConnect) {\n connect().catch(console.error);\n }\n\n return () => {\n disconnect();\n };\n }, [options.autoConnect]);\n\n return {\n connect,\n disconnect,\n connectionState,\n notifications: activeSessionId ? notifications[activeSessionId] || [] : [],\n clearNotifications,\n pendingPermission,\n resolvePermission,\n rejectPermission: rejectPermissionCallback,\n agent: agent,\n };\n}\n"]}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export declare function useEventCallback<Args extends unknown[], R>(fn: (...args: Args) => R): (...args: Args) => R;
|
|
2
|
+
export declare function useEventCallback<Args extends unknown[], R>(fn: ((...args: Args) => R) | undefined): ((...args: Args) => R) | undefined;
|
|
3
|
+
//# sourceMappingURL=use-event-callback.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-event-callback.d.ts","sourceRoot":"","sources":["../../src/hooks/use-event-callback.ts"],"names":[],"mappings":"AAIA,wBAAgB,gBAAgB,CAAC,IAAI,SAAS,OAAO,EAAE,EAAE,CAAC,EACxD,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,IAAI,KAAK,CAAC,GACvB,CAAC,GAAG,IAAI,EAAE,IAAI,KAAK,CAAC,CAAC;AACxB,wBAAgB,gBAAgB,CAAC,IAAI,SAAS,OAAO,EAAE,EAAE,CAAC,EACxD,EAAE,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,IAAI,KAAK,CAAC,CAAC,GAAG,SAAS,GACrC,CAAC,CAAC,GAAG,IAAI,EAAE,IAAI,KAAK,CAAC,CAAC,GAAG,SAAS,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { useCallback, useEffect, useLayoutEffect, useRef } from "react";
|
|
2
|
+
const useIsomorphicLayoutEffect = typeof window !== "undefined" ? useLayoutEffect : useEffect;
|
|
3
|
+
export function useEventCallback(fn) {
|
|
4
|
+
const ref = useRef(() => {
|
|
5
|
+
throw new Error("Cannot call an event handler while rendering.");
|
|
6
|
+
});
|
|
7
|
+
useIsomorphicLayoutEffect(() => {
|
|
8
|
+
ref.current = fn;
|
|
9
|
+
}, [fn]);
|
|
10
|
+
// biome-ignore lint/correctness/useExhaustiveDependencies: ref should not change
|
|
11
|
+
return useCallback((...args) => ref.current?.(...args), [ref]);
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=use-event-callback.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-event-callback.js","sourceRoot":"","sources":["../../src/hooks/use-event-callback.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAExE,MAAM,yBAAyB,GAAG,OAAO,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,SAAS,CAAC;AAQ9F,MAAM,UAAU,gBAAgB,CAC9B,EAAsC;IAEtC,MAAM,GAAG,GAAG,MAAM,CAAY,GAAG,EAAE;QACjC,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;IACnE,CAAC,CAAC,CAAC;IAEH,yBAAyB,CAAC,GAAG,EAAE;QAC7B,GAAG,CAAC,OAAO,GAAG,EAAE,CAAC;IACnB,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IAET,iFAAiF;IACjF,OAAO,WAAW,CAAC,CAAC,GAAG,IAAU,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,CAAyB,CAAC;AAC/F,CAAC","sourcesContent":["import { useCallback, useEffect, useLayoutEffect, useRef } from \"react\";\n\nconst useIsomorphicLayoutEffect = typeof window !== \"undefined\" ? useLayoutEffect : useEffect;\n\nexport function useEventCallback<Args extends unknown[], R>(\n fn: (...args: Args) => R,\n): (...args: Args) => R;\nexport function useEventCallback<Args extends unknown[], R>(\n fn: ((...args: Args) => R) | undefined,\n): ((...args: Args) => R) | undefined;\nexport function useEventCallback<Args extends unknown[], R>(\n fn: ((...args: Args) => R) | undefined,\n): ((...args: Args) => R) | undefined {\n const ref = useRef<typeof fn>(() => {\n throw new Error(\"Cannot call an event handler while rendering.\");\n });\n\n useIsomorphicLayoutEffect(() => {\n ref.current = fn;\n }, [fn]);\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: ref should not change\n return useCallback((...args: Args) => ref.current?.(...args), [ref]) as (...args: Args) => R;\n}\n"]}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,2BAA2B,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EACL,kBAAkB,EAClB,cAAc,GACf,MAAM,kBAAkB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,2BAA2B,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EACL,kBAAkB,EAClB,cAAc,GACf,MAAM,kBAAkB,CAAC","sourcesContent":["export * from \"./hooks/use-acp-client.js\";\nexport { useAcpStore } from \"./state/atoms.js\";\nexport {\n groupNotifications,\n mergeToolCalls,\n} from \"./state/utils.js\";\n"]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ConnectionState, NotificationEvent, NotificationEventData } from "./types.js";
|
|
2
|
+
interface AcpState {
|
|
3
|
+
connectionState: ConnectionState;
|
|
4
|
+
activeSessionId: string | null;
|
|
5
|
+
notifications: Record<string, NotificationEvent[]>;
|
|
6
|
+
setConnectionState: (state: ConnectionState) => void;
|
|
7
|
+
setActiveSessionId: (sessionId: string | null) => void;
|
|
8
|
+
addNotification: (notification: NotificationEventData) => void;
|
|
9
|
+
clearNotifications: (sessionId?: string) => void;
|
|
10
|
+
getActiveNotifications: () => NotificationEvent[];
|
|
11
|
+
}
|
|
12
|
+
export declare const useAcpStore: import("zustand").UseBoundStore<import("zustand").StoreApi<AcpState>>;
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=atoms.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"atoms.d.ts","sourceRoot":"","sources":["../../src/state/atoms.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAE5F,UAAU,QAAQ;IAChB,eAAe,EAAE,eAAe,CAAC;IACjC,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,EAAE,CAAC,CAAC;IACnD,kBAAkB,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,CAAC;IACrD,kBAAkB,EAAE,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IACvD,eAAe,EAAE,CAAC,YAAY,EAAE,qBAAqB,KAAK,IAAI,CAAC;IAC/D,kBAAkB,EAAE,CAAC,SAAS,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACjD,sBAAsB,EAAE,MAAM,iBAAiB,EAAE,CAAC;CACnD;AAED,eAAO,MAAM,WAAW,uEAkDrB,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { create } from "zustand";
|
|
2
|
+
export const useAcpStore = create((set, get) => ({
|
|
3
|
+
connectionState: {
|
|
4
|
+
status: "disconnected",
|
|
5
|
+
},
|
|
6
|
+
activeSessionId: null,
|
|
7
|
+
notifications: {},
|
|
8
|
+
setConnectionState: (connectionState) => {
|
|
9
|
+
set({ connectionState });
|
|
10
|
+
},
|
|
11
|
+
setActiveSessionId: (sessionId) => {
|
|
12
|
+
set({ activeSessionId: sessionId });
|
|
13
|
+
},
|
|
14
|
+
addNotification: (notification) => {
|
|
15
|
+
const current = get().notifications;
|
|
16
|
+
const sessionId = get().activeSessionId;
|
|
17
|
+
if (!sessionId) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
const newNotification = {
|
|
21
|
+
...notification,
|
|
22
|
+
id: `${Date.now()}-${Math.random()}`,
|
|
23
|
+
timestamp: Date.now(),
|
|
24
|
+
};
|
|
25
|
+
const sessionNotifications = current[sessionId] || [];
|
|
26
|
+
const updated = {
|
|
27
|
+
...current,
|
|
28
|
+
[sessionId]: [...sessionNotifications, newNotification],
|
|
29
|
+
};
|
|
30
|
+
set({ notifications: updated });
|
|
31
|
+
},
|
|
32
|
+
clearNotifications: (sessionId) => {
|
|
33
|
+
if (sessionId) {
|
|
34
|
+
const current = get().notifications;
|
|
35
|
+
const updated = { ...current };
|
|
36
|
+
delete updated[sessionId];
|
|
37
|
+
set({ notifications: updated });
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
set({ notifications: {} });
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
getActiveNotifications: () => {
|
|
44
|
+
const { activeSessionId, notifications } = get();
|
|
45
|
+
return activeSessionId ? notifications[activeSessionId] || [] : [];
|
|
46
|
+
},
|
|
47
|
+
}));
|
|
48
|
+
//# sourceMappingURL=atoms.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"atoms.js","sourceRoot":"","sources":["../../src/state/atoms.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAcjC,MAAM,CAAC,MAAM,WAAW,GAAG,MAAM,CAAW,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;IACzD,eAAe,EAAE;QACf,MAAM,EAAE,cAAc;KACvB;IACD,eAAe,EAAE,IAAI;IACrB,aAAa,EAAE,EAAE;IAEjB,kBAAkB,EAAE,CAAC,eAAgC,EAAE,EAAE;QACvD,GAAG,CAAC,EAAE,eAAe,EAAE,CAAC,CAAC;IAC3B,CAAC;IAED,kBAAkB,EAAE,CAAC,SAAwB,EAAE,EAAE;QAC/C,GAAG,CAAC,EAAE,eAAe,EAAE,SAAS,EAAE,CAAC,CAAC;IACtC,CAAC;IAED,eAAe,EAAE,CAAC,YAAmC,EAAE,EAAE;QACvD,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,aAAa,CAAC;QACpC,MAAM,SAAS,GAAG,GAAG,EAAE,CAAC,eAAe,CAAC;QACxC,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,OAAO;QACT,CAAC;QACD,MAAM,eAAe,GAAsB;YACzC,GAAG,YAAY;YACf,EAAE,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,EAAE;YACpC,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;SACtB,CAAC;QAEF,MAAM,oBAAoB,GAAG,OAAO,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;QACtD,MAAM,OAAO,GAAG;YACd,GAAG,OAAO;YACV,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,oBAAoB,EAAE,eAAe,CAAC;SACxD,CAAC;QACF,GAAG,CAAC,EAAE,aAAa,EAAE,OAAO,EAAE,CAAC,CAAC;IAClC,CAAC;IAED,kBAAkB,EAAE,CAAC,SAAkB,EAAE,EAAE;QACzC,IAAI,SAAS,EAAE,CAAC;YACd,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,aAAa,CAAC;YACpC,MAAM,OAAO,GAAG,EAAE,GAAG,OAAO,EAAE,CAAC;YAC/B,OAAO,OAAO,CAAC,SAAS,CAAC,CAAC;YAC1B,GAAG,CAAC,EAAE,aAAa,EAAE,OAAO,EAAE,CAAC,CAAC;QAClC,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,EAAE,aAAa,EAAE,EAAE,EAAE,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC;IAED,sBAAsB,EAAE,GAAG,EAAE;QAC3B,MAAM,EAAE,eAAe,EAAE,aAAa,EAAE,GAAG,GAAG,EAAE,CAAC;QACjD,OAAO,eAAe,CAAC,CAAC,CAAC,aAAa,CAAC,eAAe,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACrE,CAAC;CACF,CAAC,CAAC,CAAC","sourcesContent":["import { create } from \"zustand\";\nimport type { ConnectionState, NotificationEvent, NotificationEventData } from \"./types.js\";\n\ninterface AcpState {\n connectionState: ConnectionState;\n activeSessionId: string | null;\n notifications: Record<string, NotificationEvent[]>;\n setConnectionState: (state: ConnectionState) => void;\n setActiveSessionId: (sessionId: string | null) => void;\n addNotification: (notification: NotificationEventData) => void;\n clearNotifications: (sessionId?: string) => void;\n getActiveNotifications: () => NotificationEvent[];\n}\n\nexport const useAcpStore = create<AcpState>((set, get) => ({\n connectionState: {\n status: \"disconnected\",\n },\n activeSessionId: null,\n notifications: {},\n\n setConnectionState: (connectionState: ConnectionState) => {\n set({ connectionState });\n },\n\n setActiveSessionId: (sessionId: string | null) => {\n set({ activeSessionId: sessionId });\n },\n\n addNotification: (notification: NotificationEventData) => {\n const current = get().notifications;\n const sessionId = get().activeSessionId;\n if (!sessionId) {\n return;\n }\n const newNotification: NotificationEvent = {\n ...notification,\n id: `${Date.now()}-${Math.random()}`,\n timestamp: Date.now(),\n };\n\n const sessionNotifications = current[sessionId] || [];\n const updated = {\n ...current,\n [sessionId]: [...sessionNotifications, newNotification],\n };\n set({ notifications: updated });\n },\n\n clearNotifications: (sessionId?: string) => {\n if (sessionId) {\n const current = get().notifications;\n const updated = { ...current };\n delete updated[sessionId];\n set({ notifications: updated });\n } else {\n set({ notifications: {} });\n }\n },\n\n getActiveNotifications: () => {\n const { activeSessionId, notifications } = get();\n return activeSessionId ? notifications[activeSessionId] || [] : [];\n },\n}));\n"]}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { SessionNotification } from "@zed-industries/agent-client-protocol";
|
|
2
|
+
export interface ConnectionState {
|
|
3
|
+
status: "disconnected" | "connecting" | "connected" | "error";
|
|
4
|
+
error?: string;
|
|
5
|
+
url?: string;
|
|
6
|
+
}
|
|
7
|
+
export type NotificationEventData = {
|
|
8
|
+
type: "session_notification";
|
|
9
|
+
data: SessionNotification;
|
|
10
|
+
} | {
|
|
11
|
+
type: "connection_change";
|
|
12
|
+
data: ConnectionState;
|
|
13
|
+
} | {
|
|
14
|
+
type: "error";
|
|
15
|
+
data: Error;
|
|
16
|
+
};
|
|
17
|
+
export type NotificationEvent = {
|
|
18
|
+
id: string;
|
|
19
|
+
timestamp: number;
|
|
20
|
+
} & NotificationEventData;
|
|
21
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/state/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,uCAAuC,CAAC;AAEjF,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,cAAc,GAAG,YAAY,GAAG,WAAW,GAAG,OAAO,CAAC;IAC9D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,MAAM,qBAAqB,GAC7B;IACE,IAAI,EAAE,sBAAsB,CAAC;IAC7B,IAAI,EAAE,mBAAmB,CAAC;CAC3B,GACD;IACE,IAAI,EAAE,mBAAmB,CAAC;IAC1B,IAAI,EAAE,eAAe,CAAC;CACvB,GACD;IACE,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,KAAK,CAAC;CACb,CAAC;AAEN,MAAM,MAAM,iBAAiB,GAAG;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;CACnB,GAAG,qBAAqB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/state/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { SessionNotification } from \"@zed-industries/agent-client-protocol\";\n\nexport interface ConnectionState {\n status: \"disconnected\" | \"connecting\" | \"connected\" | \"error\";\n error?: string;\n url?: string;\n}\n\nexport type NotificationEventData =\n | {\n type: \"session_notification\";\n data: SessionNotification;\n }\n | {\n type: \"connection_change\";\n data: ConnectionState;\n }\n | {\n type: \"error\";\n data: Error;\n };\n\nexport type NotificationEvent = {\n id: string;\n timestamp: number;\n} & NotificationEventData;\n"]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ToolCallUpdate } from "@zed-industries/agent-client-protocol";
|
|
2
|
+
import type { NotificationEvent } from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Group notifications by their type
|
|
5
|
+
*/
|
|
6
|
+
export declare function groupNotifications(notifications: NotificationEvent[]): NotificationEvent[][];
|
|
7
|
+
export declare function mergeToolCalls(calls: ToolCallUpdate[]): ToolCallUpdate[];
|
|
8
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/state/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAG5E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEpD;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,aAAa,EAAE,iBAAiB,EAAE,GAAG,iBAAiB,EAAE,EAAE,CAW5F;AAmBD,wBAAgB,cAAc,CAAC,KAAK,EAAE,cAAc,EAAE,GAAG,cAAc,EAAE,CAoBxE"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { invariant } from "../utils/never.js";
|
|
2
|
+
/**
|
|
3
|
+
* Group notifications by their type
|
|
4
|
+
*/
|
|
5
|
+
export function groupNotifications(notifications) {
|
|
6
|
+
const result = [];
|
|
7
|
+
for (const notification of notifications) {
|
|
8
|
+
const lastGroup = result[result.length - 1];
|
|
9
|
+
if (lastGroup && isSameType(lastGroup.at(0), notification)) {
|
|
10
|
+
lastGroup.push(notification);
|
|
11
|
+
}
|
|
12
|
+
else {
|
|
13
|
+
result.push([notification]);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return result;
|
|
17
|
+
}
|
|
18
|
+
const TOOL_TYPES = ["tool_call", "tool_call_update"];
|
|
19
|
+
function isSameType(a, b) {
|
|
20
|
+
if (!a)
|
|
21
|
+
return false;
|
|
22
|
+
if (a.type === "session_notification" && b.type === "session_notification") {
|
|
23
|
+
// Group tool calls together (may have multiple tool-ids)
|
|
24
|
+
if (TOOL_TYPES.includes(a.data.update.sessionUpdate) &&
|
|
25
|
+
TOOL_TYPES.includes(b.data.update.sessionUpdate)) {
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
return a.data.update.sessionUpdate === b.data.update.sessionUpdate;
|
|
29
|
+
}
|
|
30
|
+
return a.type === b.type;
|
|
31
|
+
}
|
|
32
|
+
export function mergeToolCalls(calls) {
|
|
33
|
+
const map = new Map();
|
|
34
|
+
for (const call of calls) {
|
|
35
|
+
if (!map.has(call.toolCallId)) {
|
|
36
|
+
map.set(call.toolCallId, []);
|
|
37
|
+
}
|
|
38
|
+
map.get(call.toolCallId)?.push(call);
|
|
39
|
+
}
|
|
40
|
+
return Array.from(map.values()).map((calls) => {
|
|
41
|
+
const first = calls.at(0);
|
|
42
|
+
invariant(!!first?.toolCallId, "Tool call ID is required");
|
|
43
|
+
return {
|
|
44
|
+
...first,
|
|
45
|
+
toolCallId: first.toolCallId,
|
|
46
|
+
status: calls.at(-1)?.status,
|
|
47
|
+
rawOutput: Object.assign({}, ...calls.map((call) => call.rawOutput)),
|
|
48
|
+
locations: calls.flatMap((call) => call.locations || []),
|
|
49
|
+
content: calls.flatMap((call) => call.content || []),
|
|
50
|
+
};
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/state/utils.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ToolCallUpdate } from \"@zed-industries/agent-client-protocol\";\nimport type { SessionUpdate } from \"../client/types.js\";\nimport { invariant } from \"../utils/never.js\";\nimport type { NotificationEvent } from \"./types.js\";\n\n/**\n * Group notifications by their type\n */\nexport function groupNotifications(notifications: NotificationEvent[]): NotificationEvent[][] {\n const result: NotificationEvent[][] = [];\n for (const notification of notifications) {\n const lastGroup = result[result.length - 1];\n if (lastGroup && isSameType(lastGroup.at(0), notification)) {\n lastGroup.push(notification);\n } else {\n result.push([notification]);\n }\n }\n return result;\n}\n\nconst TOOL_TYPES: SessionUpdate[\"sessionUpdate\"][] = [\"tool_call\", \"tool_call_update\"];\n\nfunction isSameType(a: NotificationEvent | undefined, b: NotificationEvent): boolean {\n if (!a) return false;\n if (a.type === \"session_notification\" && b.type === \"session_notification\") {\n // Group tool calls together (may have multiple tool-ids)\n if (\n TOOL_TYPES.includes(a.data.update.sessionUpdate) &&\n TOOL_TYPES.includes(b.data.update.sessionUpdate)\n ) {\n return true;\n }\n return a.data.update.sessionUpdate === b.data.update.sessionUpdate;\n }\n return a.type === b.type;\n}\n\nexport function mergeToolCalls(calls: ToolCallUpdate[]): ToolCallUpdate[] {\n const map = new Map<string, ToolCallUpdate[]>();\n for (const call of calls) {\n if (!map.has(call.toolCallId)) {\n map.set(call.toolCallId, []);\n }\n map.get(call.toolCallId)?.push(call);\n }\n return Array.from(map.values()).map((calls) => {\n const first = calls.at(0);\n invariant(!!first?.toolCallId, \"Tool call ID is required\");\n return {\n ...first,\n toolCallId: first.toolCallId,\n status: calls.at(-1)?.status,\n rawOutput: Object.assign({}, ...calls.map((call) => call.rawOutput)),\n locations: calls.flatMap((call) => call.locations || []),\n content: calls.flatMap((call) => call.content || []),\n } satisfies ToolCallUpdate;\n });\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deferred.d.ts","sourceRoot":"","sources":["../../src/utils/deferred.ts"],"names":[],"mappings":"AAAA,qBAAa,QAAQ,CAAC,CAAC;IACrB,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IACpB,OAAO,EAAG,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;IAC7B,MAAM,EAAG,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;;CAQjC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deferred.js","sourceRoot":"","sources":["../../src/utils/deferred.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,QAAQ;IACnB,OAAO,CAAa;IACpB,OAAO,CAAsB;IAC7B,MAAM,CAA0B;IAEhC;QACE,IAAI,CAAC,OAAO,GAAG,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAC7C,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;YACvB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACvB,CAAC,CAAC,CAAC;IACL,CAAC;CACF","sourcesContent":["export class Deferred<T> {\n promise: Promise<T>;\n resolve!: (value: T) => void;\n reject!: (error: Error) => void;\n\n constructor() {\n this.promise = new Promise((resolve, reject) => {\n this.resolve = resolve;\n this.reject = reject;\n });\n }\n}\n"]}
|