@llmindset/hf-mcp 0.2.54 → 0.2.56
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/space/utils/gradio-caller.d.ts +1 -0
- package/dist/space/utils/gradio-caller.d.ts.map +1 -1
- package/dist/space/utils/gradio-caller.js +30 -9
- package/dist/space/utils/gradio-caller.js.map +1 -1
- package/package.json +1 -1
- package/src/space/utils/gradio-caller.ts +40 -9
- package/test/gradio-progress-relay.test.ts +81 -0
|
@@ -7,6 +7,7 @@ export interface GradioCallResult {
|
|
|
7
7
|
export interface GradioCallOptions {
|
|
8
8
|
onHeaders?: (headers: Headers) => void;
|
|
9
9
|
logProxiedReplica?: boolean;
|
|
10
|
+
onProgressRelayFailure?: () => void;
|
|
10
11
|
}
|
|
11
12
|
export declare function extractReplicaId(headerValue: string | undefined): string | null;
|
|
12
13
|
export declare function rewriteReplicaUrlsInResult(result: typeof CallToolResultSchema._type, proxiedReplicaHeader: string | undefined): typeof CallToolResultSchema._type;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gradio-caller.d.ts","sourceRoot":"","sources":["../../../src/space/utils/gradio-caller.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,oBAAoB,EAAE,KAAK,kBAAkB,EAAE,KAAK,aAAa,EAAE,MAAM,oCAAoC,CAAC;AACvH,OAAO,KAAK,EAAE,mBAAmB,EAAkB,MAAM,8CAA8C,CAAC;AAExG,MAAM,WAAW,gBAAgB;IAChC,MAAM,EAAE,OAAO,oBAAoB,CAAC,KAAK,CAAC;IAC1C,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACxC;AAED,MAAM,WAAW,iBAAiB;IAEjC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IAEvC,iBAAiB,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"gradio-caller.d.ts","sourceRoot":"","sources":["../../../src/space/utils/gradio-caller.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,oBAAoB,EAAE,KAAK,kBAAkB,EAAE,KAAK,aAAa,EAAE,MAAM,oCAAoC,CAAC;AACvH,OAAO,KAAK,EAAE,mBAAmB,EAAkB,MAAM,8CAA8C,CAAC;AAExG,MAAM,WAAW,gBAAgB;IAChC,MAAM,EAAE,OAAO,oBAAoB,CAAC,KAAK,CAAC;IAC1C,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACxC;AAED,MAAM,WAAW,iBAAiB;IAEjC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IAEvC,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAE5B,sBAAsB,CAAC,EAAE,MAAM,IAAI,CAAC;CACpC;AAMD,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAO/E;AAOD,wBAAgB,0BAA0B,CACzC,MAAM,EAAE,OAAO,oBAAoB,CAAC,KAAK,EACzC,oBAAoB,EAAE,MAAM,GAAG,SAAS,GACtC,OAAO,oBAAoB,CAAC,KAAK,CAuCnC;AAMD,wBAAsB,yBAAyB,CAC9C,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACnC,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,KAAK,EAAE,mBAAmB,CAAC,aAAa,EAAE,kBAAkB,CAAC,GAAG,SAAS,EACzE,OAAO,GAAE,iBAAsB,GAC7B,OAAO,CAAC,gBAAgB,CAAC,CA8I3B"}
|
|
@@ -104,18 +104,39 @@ export async function callGradioToolWithHeaders(sseUrl, toolName, parameters, hf
|
|
|
104
104
|
await remoteClient.connect(transport);
|
|
105
105
|
try {
|
|
106
106
|
const progressToken = extra?._meta?.progressToken;
|
|
107
|
+
let progressRelayDisabled = false;
|
|
108
|
+
const sendProgressNotification = async (progress) => {
|
|
109
|
+
if (!extra || progressRelayDisabled)
|
|
110
|
+
return;
|
|
111
|
+
if (extra.signal?.aborted) {
|
|
112
|
+
progressRelayDisabled = true;
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
try {
|
|
116
|
+
const params = {
|
|
117
|
+
progressToken: progressToken,
|
|
118
|
+
progress: progress.progress ?? 0,
|
|
119
|
+
};
|
|
120
|
+
if (progress.total !== undefined) {
|
|
121
|
+
params.total = progress.total;
|
|
122
|
+
}
|
|
123
|
+
if (progress.message !== undefined) {
|
|
124
|
+
params.message = progress.message;
|
|
125
|
+
}
|
|
126
|
+
await extra.sendNotification({
|
|
127
|
+
method: 'notifications/progress',
|
|
128
|
+
params,
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
progressRelayDisabled = true;
|
|
133
|
+
options.onProgressRelayFailure?.();
|
|
134
|
+
}
|
|
135
|
+
};
|
|
107
136
|
const requestOptions = {};
|
|
108
137
|
if (progressToken !== undefined && extra) {
|
|
109
138
|
requestOptions.onprogress = (progress) => {
|
|
110
|
-
void
|
|
111
|
-
method: 'notifications/progress',
|
|
112
|
-
params: {
|
|
113
|
-
progressToken,
|
|
114
|
-
progress: progress.progress,
|
|
115
|
-
total: progress.total,
|
|
116
|
-
message: progress.message,
|
|
117
|
-
},
|
|
118
|
-
});
|
|
139
|
+
void sendProgressNotification(progress);
|
|
119
140
|
};
|
|
120
141
|
requestOptions.resetTimeoutOnProgress = true;
|
|
121
142
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gradio-caller.js","sourceRoot":"","sources":["../../../src/space/utils/gradio-caller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACnE,OAAO,EAAE,kBAAkB,EAAkC,MAAM,yCAAyC,CAAC;AAC7G,OAAO,EAAE,oBAAoB,EAA+C,MAAM,oCAAoC,CAAC;
|
|
1
|
+
{"version":3,"file":"gradio-caller.js","sourceRoot":"","sources":["../../../src/space/utils/gradio-caller.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -13,6 +13,8 @@ export interface GradioCallOptions {
|
|
|
13
13
|
onHeaders?: (headers: Headers) => void;
|
|
14
14
|
/** Log the X-Proxied-Replica header to stderr once */
|
|
15
15
|
logProxiedReplica?: boolean;
|
|
16
|
+
/** Optional hook for when progress relay fails (e.g., client disconnected) */
|
|
17
|
+
onProgressRelayFailure?: () => void;
|
|
16
18
|
}
|
|
17
19
|
|
|
18
20
|
/**
|
|
@@ -163,20 +165,49 @@ export async function callGradioToolWithHeaders(
|
|
|
163
165
|
try {
|
|
164
166
|
// Check if the client is requesting progress notifications
|
|
165
167
|
const progressToken = extra?._meta?.progressToken;
|
|
168
|
+
|
|
169
|
+
// Track whether we've seen a transport closure to avoid noisy retries
|
|
170
|
+
let progressRelayDisabled = false;
|
|
171
|
+
|
|
172
|
+
const sendProgressNotification = async (progress: { progress?: number; total?: number; message?: string }) => {
|
|
173
|
+
if (!extra || progressRelayDisabled) return;
|
|
174
|
+
if (extra.signal?.aborted) {
|
|
175
|
+
progressRelayDisabled = true;
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
try {
|
|
179
|
+
const params: {
|
|
180
|
+
progressToken: number;
|
|
181
|
+
progress: number;
|
|
182
|
+
total?: number;
|
|
183
|
+
message?: string;
|
|
184
|
+
} = {
|
|
185
|
+
progressToken: progressToken as number,
|
|
186
|
+
progress: progress.progress ?? 0,
|
|
187
|
+
};
|
|
188
|
+
if (progress.total !== undefined) {
|
|
189
|
+
params.total = progress.total;
|
|
190
|
+
}
|
|
191
|
+
if (progress.message !== undefined) {
|
|
192
|
+
params.message = progress.message;
|
|
193
|
+
}
|
|
194
|
+
await extra.sendNotification({
|
|
195
|
+
method: 'notifications/progress',
|
|
196
|
+
params,
|
|
197
|
+
});
|
|
198
|
+
} catch {
|
|
199
|
+
// The underlying transport has likely closed (e.g., client disconnected); disable further relays.
|
|
200
|
+
progressRelayDisabled = true;
|
|
201
|
+
options.onProgressRelayFailure?.();
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
|
|
166
205
|
const requestOptions: RequestOptions = {};
|
|
167
206
|
|
|
168
207
|
if (progressToken !== undefined && extra) {
|
|
169
208
|
// Fire-and-forget; best-effort relay
|
|
170
209
|
requestOptions.onprogress = (progress) => {
|
|
171
|
-
void
|
|
172
|
-
method: 'notifications/progress',
|
|
173
|
-
params: {
|
|
174
|
-
progressToken,
|
|
175
|
-
progress: progress.progress,
|
|
176
|
-
total: progress.total,
|
|
177
|
-
message: progress.message,
|
|
178
|
-
},
|
|
179
|
-
});
|
|
210
|
+
void sendProgressNotification(progress);
|
|
180
211
|
};
|
|
181
212
|
requestOptions.resetTimeoutOnProgress = true;
|
|
182
213
|
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeAll } from 'vitest';
|
|
2
|
+
|
|
3
|
+
// Stub out the SSE transport to simulate progress + response without network.
|
|
4
|
+
vi.mock('@modelcontextprotocol/sdk/client/sse.js', () => {
|
|
5
|
+
class FakeSSEClientTransport {
|
|
6
|
+
onmessage?: (msg: unknown) => void;
|
|
7
|
+
onclose?: () => void;
|
|
8
|
+
onerror?: (err: unknown) => void;
|
|
9
|
+
sessionId = 'fake';
|
|
10
|
+
|
|
11
|
+
constructor(_url: URL, _options: unknown) {}
|
|
12
|
+
|
|
13
|
+
async start() {
|
|
14
|
+
/* no-op */
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async close() {
|
|
18
|
+
this.onclose?.();
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async send(message: any) {
|
|
22
|
+
// Simulate two progress notifications followed by a result.
|
|
23
|
+
const progressToken = message?.id ?? message?.params?._meta?.progressToken ?? 0;
|
|
24
|
+
queueMicrotask(() => {
|
|
25
|
+
this.onmessage?.({
|
|
26
|
+
jsonrpc: '2.0',
|
|
27
|
+
method: 'notifications/progress',
|
|
28
|
+
params: { progressToken, progress: 1, total: 10, message: 'first' },
|
|
29
|
+
});
|
|
30
|
+
this.onmessage?.({
|
|
31
|
+
jsonrpc: '2.0',
|
|
32
|
+
method: 'notifications/progress',
|
|
33
|
+
params: { progressToken, progress: 2, total: 10, message: 'second' },
|
|
34
|
+
});
|
|
35
|
+
this.onmessage?.({
|
|
36
|
+
jsonrpc: '2.0',
|
|
37
|
+
id: message.id,
|
|
38
|
+
result: { isError: false, content: [{ type: 'text', text: 'ok' }] },
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return { SSEClientTransport: FakeSSEClientTransport };
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
let callGradioToolWithHeaders: typeof import('../src/space/utils/gradio-caller.js').callGradioToolWithHeaders;
|
|
48
|
+
|
|
49
|
+
beforeAll(async () => {
|
|
50
|
+
({ callGradioToolWithHeaders } = await import('../src/space/utils/gradio-caller.js'));
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
describe('callGradioToolWithHeaders progress relay', () => {
|
|
54
|
+
it('swallows progress send failures after disconnect', async () => {
|
|
55
|
+
let attempts = 0;
|
|
56
|
+
const extra = {
|
|
57
|
+
_meta: { progressToken: 42 },
|
|
58
|
+
sendNotification: vi.fn().mockImplementation(async () => {
|
|
59
|
+
attempts += 1;
|
|
60
|
+
throw new Error('Not connected');
|
|
61
|
+
}),
|
|
62
|
+
signal: new AbortController().signal,
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const { result } = await callGradioToolWithHeaders(
|
|
66
|
+
'http://fake-sse.local/gradio_api/mcp/sse',
|
|
67
|
+
'tools/call',
|
|
68
|
+
{},
|
|
69
|
+
undefined,
|
|
70
|
+
extra as any
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
// Allow pending microtasks (progress relay) to flush
|
|
74
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
75
|
+
|
|
76
|
+
expect(result.isError).toBe(false);
|
|
77
|
+
// Progress relay should never crash and should not spam after failure.
|
|
78
|
+
expect(attempts).toBeLessThanOrEqual(1);
|
|
79
|
+
expect(extra.sendNotification.mock.calls.length).toBeLessThanOrEqual(1);
|
|
80
|
+
});
|
|
81
|
+
});
|