@xpert-ai/xpert-sdk 0.16.0 → 0.18.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/client.d.ts +11 -1
- package/dist/client.js +35 -2
- package/dist/client.js.map +1 -1
- package/dist/client.mjs +35 -2
- package/dist/client.mjs.map +1 -1
- package/dist/content.d.ts +117 -0
- package/dist/content.js +26 -0
- package/dist/content.js.map +1 -0
- package/dist/content.mjs +26 -0
- package/dist/content.mjs.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2 -0
- package/dist/index.mjs.map +1 -1
- package/dist/schema.d.ts +6 -1
- package/dist/schema.js.map +1 -1
- package/dist/schema.mjs.map +1 -1
- package/dist/tests/content.test.d.ts +1 -0
- package/dist/tests/content.test.js +50 -0
- package/dist/tests/content.test.js.map +1 -0
- package/dist/tests/content.test.mjs +50 -0
- package/dist/tests/content.test.mjs.map +1 -0
- package/dist/tests/run-status.test.d.ts +1 -0
- package/dist/tests/run-status.test.js +13 -0
- package/dist/tests/run-status.test.js.map +1 -0
- package/dist/tests/run-status.test.mjs +13 -0
- package/dist/tests/run-status.test.mjs.map +1 -0
- package/dist/tests/thread-control-view.test.d.ts +1 -0
- package/dist/tests/thread-control-view.test.js +62 -0
- package/dist/tests/thread-control-view.test.js.map +1 -0
- package/dist/tests/thread-control-view.test.mjs +62 -0
- package/dist/tests/thread-control-view.test.mjs.map +1 -0
- package/dist/tests/view-file-preview.test.d.ts +1 -0
- package/dist/tests/view-file-preview.test.js +86 -0
- package/dist/tests/view-file-preview.test.js.map +1 -0
- package/dist/tests/view-file-preview.test.mjs +86 -0
- package/dist/tests/view-file-preview.test.mjs.map +1 -0
- package/dist/thread-activity.d.ts +2 -0
- package/dist/thread-activity.js +3 -0
- package/dist/thread-activity.js.map +1 -1
- package/dist/thread-activity.mjs +3 -0
- package/dist/thread-activity.mjs.map +1 -1
- package/dist/thread-control-view.d.ts +23 -0
- package/dist/thread-control-view.js +57 -0
- package/dist/thread-control-view.js.map +1 -0
- package/dist/thread-control-view.mjs +57 -0
- package/dist/thread-control-view.mjs.map +1 -0
- package/dist/types.stream.d.ts +10 -1
- package/dist/view-extension.d.ts +2 -0
- package/dist/view-extension.js.map +1 -1
- package/dist/view-extension.mjs.map +1 -1
- package/dist/view-file-preview.d.ts +11 -0
- package/dist/view-file-preview.js +16 -0
- package/dist/view-file-preview.js.map +1 -0
- package/dist/view-file-preview.mjs +16 -0
- package/dist/view-file-preview.mjs.map +1 -0
- package/package.json +3 -3
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import { Client } from "../index.js";
|
|
3
|
+
describe('ContentClient', () => {
|
|
4
|
+
it('uses the configured SDK transport and scoped credentials for every operation', async () => {
|
|
5
|
+
const fetch = vi
|
|
6
|
+
.fn()
|
|
7
|
+
.mockImplementation(async () => new Response('{}', { headers: { 'content-type': 'application/json' } }));
|
|
8
|
+
const client = new Client({
|
|
9
|
+
apiUrl: 'https://example.test/api/ai',
|
|
10
|
+
callerOptions: { fetch },
|
|
11
|
+
onRequest: (_url, init) => ({
|
|
12
|
+
...init,
|
|
13
|
+
headers: { ...init.headers, 'x-client-secret': 'test-secret', 'organization-id': 'org' },
|
|
14
|
+
}),
|
|
15
|
+
});
|
|
16
|
+
const scope = { assistantId: 'a/1', projectId: 'p' };
|
|
17
|
+
const abort = new AbortController();
|
|
18
|
+
await client.content.resolve(scope, { resourceId: 'r', providerKey: 'files' }, { signal: abort.signal });
|
|
19
|
+
await client.content.review(scope, 'r');
|
|
20
|
+
await client.content.preview(scope, 'r', 'rev');
|
|
21
|
+
await client.content.mutate(scope, 'r', {
|
|
22
|
+
operation: 'restore',
|
|
23
|
+
revisionId: 'rev',
|
|
24
|
+
epoch: 2,
|
|
25
|
+
expectedSequence: 4,
|
|
26
|
+
});
|
|
27
|
+
expect(fetch.mock.calls.map(([url]) => new URL(String(url)).pathname)).toEqual(['open', 'review', 'preview', 'restore'].map((operation) => `/api/ai/assistants/a%2F1/projects/p/content/r/${operation}`));
|
|
28
|
+
expect(fetch.mock.calls[0][1]?.signal).toBe(abort.signal);
|
|
29
|
+
expect(JSON.parse(String(fetch.mock.calls[0][1]?.body))).toEqual({ providerKey: 'files' });
|
|
30
|
+
expect(JSON.parse(String(fetch.mock.calls[3][1]?.body))).toEqual({
|
|
31
|
+
revisionId: 'rev',
|
|
32
|
+
epoch: 2,
|
|
33
|
+
expectedSequence: 4,
|
|
34
|
+
});
|
|
35
|
+
for (const [, init] of fetch.mock.calls)
|
|
36
|
+
expect(new Headers(init?.headers).get('x-client-secret')).toBe('test-secret');
|
|
37
|
+
});
|
|
38
|
+
it('does not bypass a server authorization rejection', async () => {
|
|
39
|
+
const fetch = vi
|
|
40
|
+
.fn()
|
|
41
|
+
.mockImplementation(async () => new Response('Forbidden', { status: 403 }));
|
|
42
|
+
const client = new Client({
|
|
43
|
+
apiUrl: 'https://example.test/api/ai',
|
|
44
|
+
callerOptions: { fetch, maxRetries: 0 },
|
|
45
|
+
});
|
|
46
|
+
await expect(client.content.resolve({ assistantId: 'a', projectId: 'p' }, { resourceId: 'r' })).rejects.toThrow();
|
|
47
|
+
expect(fetch).toHaveBeenCalledOnce();
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
//# sourceMappingURL=content.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content.test.js","sourceRoot":"","sources":["../../src/tests/content.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import { Client } from "../index.mjs";
|
|
3
|
+
describe('ContentClient', () => {
|
|
4
|
+
it('uses the configured SDK transport and scoped credentials for every operation', async () => {
|
|
5
|
+
const fetch = vi
|
|
6
|
+
.fn()
|
|
7
|
+
.mockImplementation(async () => new Response('{}', { headers: { 'content-type': 'application/json' } }));
|
|
8
|
+
const client = new Client({
|
|
9
|
+
apiUrl: 'https://example.test/api/ai',
|
|
10
|
+
callerOptions: { fetch },
|
|
11
|
+
onRequest: (_url, init) => ({
|
|
12
|
+
...init,
|
|
13
|
+
headers: { ...init.headers, 'x-client-secret': 'test-secret', 'organization-id': 'org' },
|
|
14
|
+
}),
|
|
15
|
+
});
|
|
16
|
+
const scope = { assistantId: 'a/1', projectId: 'p' };
|
|
17
|
+
const abort = new AbortController();
|
|
18
|
+
await client.content.resolve(scope, { resourceId: 'r', providerKey: 'files' }, { signal: abort.signal });
|
|
19
|
+
await client.content.review(scope, 'r');
|
|
20
|
+
await client.content.preview(scope, 'r', 'rev');
|
|
21
|
+
await client.content.mutate(scope, 'r', {
|
|
22
|
+
operation: 'restore',
|
|
23
|
+
revisionId: 'rev',
|
|
24
|
+
epoch: 2,
|
|
25
|
+
expectedSequence: 4,
|
|
26
|
+
});
|
|
27
|
+
expect(fetch.mock.calls.map(([url]) => new URL(String(url)).pathname)).toEqual(['open', 'review', 'preview', 'restore'].map((operation) => `/api/ai/assistants/a%2F1/projects/p/content/r/${operation}`));
|
|
28
|
+
expect(fetch.mock.calls[0][1]?.signal).toBe(abort.signal);
|
|
29
|
+
expect(JSON.parse(String(fetch.mock.calls[0][1]?.body))).toEqual({ providerKey: 'files' });
|
|
30
|
+
expect(JSON.parse(String(fetch.mock.calls[3][1]?.body))).toEqual({
|
|
31
|
+
revisionId: 'rev',
|
|
32
|
+
epoch: 2,
|
|
33
|
+
expectedSequence: 4,
|
|
34
|
+
});
|
|
35
|
+
for (const [, init] of fetch.mock.calls)
|
|
36
|
+
expect(new Headers(init?.headers).get('x-client-secret')).toBe('test-secret');
|
|
37
|
+
});
|
|
38
|
+
it('does not bypass a server authorization rejection', async () => {
|
|
39
|
+
const fetch = vi
|
|
40
|
+
.fn()
|
|
41
|
+
.mockImplementation(async () => new Response('Forbidden', { status: 403 }));
|
|
42
|
+
const client = new Client({
|
|
43
|
+
apiUrl: 'https://example.test/api/ai',
|
|
44
|
+
callerOptions: { fetch, maxRetries: 0 },
|
|
45
|
+
});
|
|
46
|
+
await expect(client.content.resolve({ assistantId: 'a', projectId: 'p' }, { resourceId: 'r' })).rejects.toThrow();
|
|
47
|
+
expect(fetch).toHaveBeenCalledOnce();
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
//# sourceMappingURL=content.test.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content.test.mjs","sourceRoot":"","sources":["../../src/tests/content.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
+
import { Client } from "../client.js";
|
|
3
|
+
describe('compact run status', () => {
|
|
4
|
+
it('uses the lifecycle endpoint without changing full get()', async () => {
|
|
5
|
+
const fetch = vi.fn().mockImplementation(async () => new Response(JSON.stringify({ run_id: 'run', status: 'running' }), { headers: { 'Content-Type': 'application/json' } }));
|
|
6
|
+
const client = new Client({ apiUrl: 'https://example.test/api/ai', callerOptions: { fetch } });
|
|
7
|
+
expect((await client.runs.getStatus('thread', 'run')).status).toBe('running');
|
|
8
|
+
await client.runs.get('thread', 'run');
|
|
9
|
+
expect(String(fetch.mock.calls[0][0])).toContain('/threads/thread/runs/run/status');
|
|
10
|
+
expect(String(fetch.mock.calls[1][0])).toMatch(/\/threads\/thread\/runs\/run$/);
|
|
11
|
+
});
|
|
12
|
+
});
|
|
13
|
+
//# sourceMappingURL=run-status.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-status.test.js","sourceRoot":"","sources":["../../src/tests/run-status.test.ts"],"names":[],"mappings":"OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ;OAC1C,EAAE,MAAM,EAAE;AAEjB,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;IAClC,EAAE,CAAC,yDAAyD,EAAE,KAAK,IAAI,EAAE;QACvE,MAAM,KAAK,GAAG,EAAE,CAAC,EAAE,EAA2B,CAAC,kBAAkB,CAAC,KAAK,IAAI,EAAE,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,EAAE,EAAE,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,EAAE,CAAC,CAAC,CAAA;QACtM,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,EAAE,MAAM,EAAE,6BAA6B,EAAE,aAAa,EAAE,EAAE,KAAK,EAAE,EAAE,CAAC,CAAA;QAC9F,MAAM,CAAC,CAAC,MAAM,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;QAC7E,MAAM,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAA;QACtC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,iCAAiC,CAAC,CAAA;QACnF,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,+BAA+B,CAAC,CAAA;IACjF,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
+
import { Client } from "../client.mjs";
|
|
3
|
+
describe('compact run status', () => {
|
|
4
|
+
it('uses the lifecycle endpoint without changing full get()', async () => {
|
|
5
|
+
const fetch = vi.fn().mockImplementation(async () => new Response(JSON.stringify({ run_id: 'run', status: 'running' }), { headers: { 'Content-Type': 'application/json' } }));
|
|
6
|
+
const client = new Client({ apiUrl: 'https://example.test/api/ai', callerOptions: { fetch } });
|
|
7
|
+
expect((await client.runs.getStatus('thread', 'run')).status).toBe('running');
|
|
8
|
+
await client.runs.get('thread', 'run');
|
|
9
|
+
expect(String(fetch.mock.calls[0][0])).toContain('/threads/thread/runs/run/status');
|
|
10
|
+
expect(String(fetch.mock.calls[1][0])).toMatch(/\/threads\/thread\/runs\/run$/);
|
|
11
|
+
});
|
|
12
|
+
});
|
|
13
|
+
//# sourceMappingURL=run-status.test.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-status.test.mjs","sourceRoot":"","sources":["../../src/tests/run-status.test.ts"],"names":[],"mappings":"OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ;OAC1C,EAAE,MAAM,EAAE;AAEjB,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;IAClC,EAAE,CAAC,yDAAyD,EAAE,KAAK,IAAI,EAAE;QACvE,MAAM,KAAK,GAAG,EAAE,CAAC,EAAE,EAA2B,CAAC,kBAAkB,CAAC,KAAK,IAAI,EAAE,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,EAAE,EAAE,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,EAAE,CAAC,CAAC,CAAA;QACtM,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,EAAE,MAAM,EAAE,6BAA6B,EAAE,aAAa,EAAE,EAAE,KAAK,EAAE,EAAE,CAAC,CAAA;QAC9F,MAAM,CAAC,CAAC,MAAM,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;QAC7E,MAAM,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAA;QACtC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,iCAAiC,CAAC,CAAA;QACnF,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,+BAA+B,CAAC,CAAA;IACjF,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import { Client, isThreadControlView, mergeThreadControlView, } from "../index.js";
|
|
3
|
+
const view = {
|
|
4
|
+
version: 1,
|
|
5
|
+
threadId: 'thread/id',
|
|
6
|
+
runId: 'run',
|
|
7
|
+
revision: '9007199254740993',
|
|
8
|
+
state: 'stopping',
|
|
9
|
+
actions: {
|
|
10
|
+
canPause: false,
|
|
11
|
+
canResume: false,
|
|
12
|
+
canTerminate: false,
|
|
13
|
+
canSend: false,
|
|
14
|
+
canQueue: false,
|
|
15
|
+
canRetry: false,
|
|
16
|
+
canRespond: false,
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
describe('public control view', () => {
|
|
20
|
+
it('uses an abortable SDK GET without sending business input', async () => {
|
|
21
|
+
const fetch = vi
|
|
22
|
+
.fn()
|
|
23
|
+
.mockResolvedValue(new Response(JSON.stringify(view)));
|
|
24
|
+
const client = new Client({ apiUrl: 'https://xpert.example/api/ai', callerOptions: { fetch } });
|
|
25
|
+
const signal = new AbortController().signal;
|
|
26
|
+
expect(await client.threads.getControlView(view.threadId, { signal })).toEqual(view);
|
|
27
|
+
expect(fetch).toHaveBeenCalledTimes(1);
|
|
28
|
+
expect(fetch.mock.calls[0][0].pathname).toBe('/api/ai/threads/thread%2Fid/control-view');
|
|
29
|
+
expect(fetch.mock.calls[0][1]).toMatchObject({ signal });
|
|
30
|
+
expect(fetch.mock.calls[0][1]?.body).toBeUndefined();
|
|
31
|
+
});
|
|
32
|
+
it.each([
|
|
33
|
+
null,
|
|
34
|
+
{ ...view, version: 2 },
|
|
35
|
+
{ ...view, revision: '0' },
|
|
36
|
+
{ ...view, revision: '1.1' },
|
|
37
|
+
{ ...view, actions: { canResume: true } },
|
|
38
|
+
{ ...view, state: 'cancel-accepted' },
|
|
39
|
+
])('rejects incomplete or invalid response %j', (invalid) => {
|
|
40
|
+
expect(isThreadControlView(invalid)).toBe(false);
|
|
41
|
+
});
|
|
42
|
+
it('rejects a response for another thread', async () => {
|
|
43
|
+
const fetch = vi
|
|
44
|
+
.fn()
|
|
45
|
+
.mockResolvedValue(new Response(JSON.stringify(view)));
|
|
46
|
+
const client = new Client({ apiUrl: 'https://xpert.example/api/ai', callerOptions: { fetch } });
|
|
47
|
+
await expect(client.threads.getControlView('other')).rejects.toThrow();
|
|
48
|
+
});
|
|
49
|
+
it('orders whole-thread revisions above JS integer precision across replacement runs', () => {
|
|
50
|
+
const newer = {
|
|
51
|
+
...view,
|
|
52
|
+
runId: 'new',
|
|
53
|
+
revision: '9007199254740994',
|
|
54
|
+
state: 'running',
|
|
55
|
+
};
|
|
56
|
+
expect(mergeThreadControlView(newer, view)).toBe(newer);
|
|
57
|
+
expect(mergeThreadControlView(view, newer)).toBe(newer);
|
|
58
|
+
expect(mergeThreadControlView(view, { ...view, actions: { ...view.actions, canTerminate: true } })
|
|
59
|
+
.actions.canTerminate).toBe(true);
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
//# sourceMappingURL=thread-control-view.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"thread-control-view.test.js","sourceRoot":"","sources":["../../src/tests/thread-control-view.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import { Client, isThreadControlView, mergeThreadControlView, } from "../index.mjs";
|
|
3
|
+
const view = {
|
|
4
|
+
version: 1,
|
|
5
|
+
threadId: 'thread/id',
|
|
6
|
+
runId: 'run',
|
|
7
|
+
revision: '9007199254740993',
|
|
8
|
+
state: 'stopping',
|
|
9
|
+
actions: {
|
|
10
|
+
canPause: false,
|
|
11
|
+
canResume: false,
|
|
12
|
+
canTerminate: false,
|
|
13
|
+
canSend: false,
|
|
14
|
+
canQueue: false,
|
|
15
|
+
canRetry: false,
|
|
16
|
+
canRespond: false,
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
describe('public control view', () => {
|
|
20
|
+
it('uses an abortable SDK GET without sending business input', async () => {
|
|
21
|
+
const fetch = vi
|
|
22
|
+
.fn()
|
|
23
|
+
.mockResolvedValue(new Response(JSON.stringify(view)));
|
|
24
|
+
const client = new Client({ apiUrl: 'https://xpert.example/api/ai', callerOptions: { fetch } });
|
|
25
|
+
const signal = new AbortController().signal;
|
|
26
|
+
expect(await client.threads.getControlView(view.threadId, { signal })).toEqual(view);
|
|
27
|
+
expect(fetch).toHaveBeenCalledTimes(1);
|
|
28
|
+
expect(fetch.mock.calls[0][0].pathname).toBe('/api/ai/threads/thread%2Fid/control-view');
|
|
29
|
+
expect(fetch.mock.calls[0][1]).toMatchObject({ signal });
|
|
30
|
+
expect(fetch.mock.calls[0][1]?.body).toBeUndefined();
|
|
31
|
+
});
|
|
32
|
+
it.each([
|
|
33
|
+
null,
|
|
34
|
+
{ ...view, version: 2 },
|
|
35
|
+
{ ...view, revision: '0' },
|
|
36
|
+
{ ...view, revision: '1.1' },
|
|
37
|
+
{ ...view, actions: { canResume: true } },
|
|
38
|
+
{ ...view, state: 'cancel-accepted' },
|
|
39
|
+
])('rejects incomplete or invalid response %j', (invalid) => {
|
|
40
|
+
expect(isThreadControlView(invalid)).toBe(false);
|
|
41
|
+
});
|
|
42
|
+
it('rejects a response for another thread', async () => {
|
|
43
|
+
const fetch = vi
|
|
44
|
+
.fn()
|
|
45
|
+
.mockResolvedValue(new Response(JSON.stringify(view)));
|
|
46
|
+
const client = new Client({ apiUrl: 'https://xpert.example/api/ai', callerOptions: { fetch } });
|
|
47
|
+
await expect(client.threads.getControlView('other')).rejects.toThrow();
|
|
48
|
+
});
|
|
49
|
+
it('orders whole-thread revisions above JS integer precision across replacement runs', () => {
|
|
50
|
+
const newer = {
|
|
51
|
+
...view,
|
|
52
|
+
runId: 'new',
|
|
53
|
+
revision: '9007199254740994',
|
|
54
|
+
state: 'running',
|
|
55
|
+
};
|
|
56
|
+
expect(mergeThreadControlView(newer, view)).toBe(newer);
|
|
57
|
+
expect(mergeThreadControlView(view, newer)).toBe(newer);
|
|
58
|
+
expect(mergeThreadControlView(view, { ...view, actions: { ...view.actions, canTerminate: true } })
|
|
59
|
+
.actions.canTerminate).toBe(true);
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
//# sourceMappingURL=thread-control-view.test.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"thread-control-view.test.mjs","sourceRoot":"","sources":["../../src/tests/thread-control-view.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import { Client } from "../client.js";
|
|
3
|
+
describe('authenticated image previews', () => {
|
|
4
|
+
it.each([false, true])('reads one binary response with the full request context (group=%s)', async (group) => {
|
|
5
|
+
const bytes = new Uint8Array([82, 73, 70, 70, 0, 255]);
|
|
6
|
+
const fetch = vi.fn().mockImplementation(async () => new Response(bytes, {
|
|
7
|
+
headers: {
|
|
8
|
+
'content-type': 'image/webp',
|
|
9
|
+
'content-disposition': "inline; filename*=UTF-8''%E5%9B%BE.webp",
|
|
10
|
+
},
|
|
11
|
+
}));
|
|
12
|
+
const onRequest = vi.fn((_url, init) => ({
|
|
13
|
+
...init,
|
|
14
|
+
headers: { ...init.headers, 'x-context': 'current' },
|
|
15
|
+
}));
|
|
16
|
+
const client = new Client({
|
|
17
|
+
apiUrl: 'https://example.test/proxy/api/ai/',
|
|
18
|
+
apiKey: 'test',
|
|
19
|
+
defaultHeaders: { 'organization-id': 'org' },
|
|
20
|
+
callerOptions: { fetch, maxRetries: 0 },
|
|
21
|
+
onRequest,
|
|
22
|
+
});
|
|
23
|
+
const view = group ? client.forGroupWorkbench('group/1').viewHosts : client.viewHosts;
|
|
24
|
+
const signal = new AbortController().signal;
|
|
25
|
+
const runtimeScope = { projectId: 'project', conversationId: 'conversation' };
|
|
26
|
+
const result = await view.readFilePreview('agent', 'assistant', 'view', { fileKey: 'file', targetId: 'version', variant: 'thumbnail' }, { runtimeScope, signal });
|
|
27
|
+
expect(result.fileName).toBe('图.webp');
|
|
28
|
+
expect(new Uint8Array(await result.blob.arrayBuffer())).toEqual(bytes);
|
|
29
|
+
expect(result.blob.type).toBe('image/webp');
|
|
30
|
+
expect(fetch).toHaveBeenCalledTimes(1);
|
|
31
|
+
const [url, init] = fetch.mock.calls[0];
|
|
32
|
+
expect(String(url)).toBe(`https://example.test/proxy/api/ai/${group ? 'groups/group%2F1/workbench/' : ''}workspace-files/view-sessions/preview`);
|
|
33
|
+
expect(init).toMatchObject({
|
|
34
|
+
method: 'POST',
|
|
35
|
+
signal,
|
|
36
|
+
credentials: 'omit',
|
|
37
|
+
redirect: 'error',
|
|
38
|
+
headers: {
|
|
39
|
+
'x-context': 'current',
|
|
40
|
+
'organization-id': 'org',
|
|
41
|
+
'x-xpert-view-project-id': 'project',
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
expect(JSON.parse(String(init?.body))).toEqual({
|
|
45
|
+
hostType: 'agent',
|
|
46
|
+
hostId: 'assistant',
|
|
47
|
+
viewKey: 'view',
|
|
48
|
+
fileKey: 'file',
|
|
49
|
+
targetId: 'version',
|
|
50
|
+
variant: 'thumbnail',
|
|
51
|
+
runtimeScope,
|
|
52
|
+
});
|
|
53
|
+
expect(onRequest).toHaveBeenCalledOnce();
|
|
54
|
+
});
|
|
55
|
+
it.each([401, 403, 404, 415])('preserves HTTP %s without returning an error body as an image', async (status) => {
|
|
56
|
+
const fetch = vi
|
|
57
|
+
.fn()
|
|
58
|
+
.mockImplementation(async () => new Response('Denied', { status }));
|
|
59
|
+
const client = new Client({
|
|
60
|
+
apiUrl: 'https://example.test/api/ai',
|
|
61
|
+
callerOptions: { fetch, maxRetries: 0 },
|
|
62
|
+
});
|
|
63
|
+
await expect(client.viewHosts.readFilePreview('agent', 'assistant', 'view', {
|
|
64
|
+
fileKey: 'file',
|
|
65
|
+
variant: 'original',
|
|
66
|
+
})).rejects.toMatchObject({ status });
|
|
67
|
+
expect(fetch).toHaveBeenCalledOnce();
|
|
68
|
+
});
|
|
69
|
+
it.each([
|
|
70
|
+
['text/html', 'inline; filename="image.png"'],
|
|
71
|
+
['image/png', ''],
|
|
72
|
+
['image/png', "inline; filename*=UTF-8''..%2Fimage.png"],
|
|
73
|
+
])('rejects invalid binary metadata: %s %s', async (type, disposition) => {
|
|
74
|
+
const client = new Client({
|
|
75
|
+
apiUrl: 'https://example.test/api/ai',
|
|
76
|
+
callerOptions: {
|
|
77
|
+
fetch: async () => new Response('data', {
|
|
78
|
+
headers: { 'content-type': type, 'content-disposition': disposition },
|
|
79
|
+
}),
|
|
80
|
+
maxRetries: 0,
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
await expect(client.viewHosts.readFilePreview('agent', 'assistant', 'view', { fileKey: 'file' })).rejects.toThrow();
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
//# sourceMappingURL=view-file-preview.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"view-file-preview.test.js","sourceRoot":"","sources":["../../src/tests/view-file-preview.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import { Client } from "../client.mjs";
|
|
3
|
+
describe('authenticated image previews', () => {
|
|
4
|
+
it.each([false, true])('reads one binary response with the full request context (group=%s)', async (group) => {
|
|
5
|
+
const bytes = new Uint8Array([82, 73, 70, 70, 0, 255]);
|
|
6
|
+
const fetch = vi.fn().mockImplementation(async () => new Response(bytes, {
|
|
7
|
+
headers: {
|
|
8
|
+
'content-type': 'image/webp',
|
|
9
|
+
'content-disposition': "inline; filename*=UTF-8''%E5%9B%BE.webp",
|
|
10
|
+
},
|
|
11
|
+
}));
|
|
12
|
+
const onRequest = vi.fn((_url, init) => ({
|
|
13
|
+
...init,
|
|
14
|
+
headers: { ...init.headers, 'x-context': 'current' },
|
|
15
|
+
}));
|
|
16
|
+
const client = new Client({
|
|
17
|
+
apiUrl: 'https://example.test/proxy/api/ai/',
|
|
18
|
+
apiKey: 'test',
|
|
19
|
+
defaultHeaders: { 'organization-id': 'org' },
|
|
20
|
+
callerOptions: { fetch, maxRetries: 0 },
|
|
21
|
+
onRequest,
|
|
22
|
+
});
|
|
23
|
+
const view = group ? client.forGroupWorkbench('group/1').viewHosts : client.viewHosts;
|
|
24
|
+
const signal = new AbortController().signal;
|
|
25
|
+
const runtimeScope = { projectId: 'project', conversationId: 'conversation' };
|
|
26
|
+
const result = await view.readFilePreview('agent', 'assistant', 'view', { fileKey: 'file', targetId: 'version', variant: 'thumbnail' }, { runtimeScope, signal });
|
|
27
|
+
expect(result.fileName).toBe('图.webp');
|
|
28
|
+
expect(new Uint8Array(await result.blob.arrayBuffer())).toEqual(bytes);
|
|
29
|
+
expect(result.blob.type).toBe('image/webp');
|
|
30
|
+
expect(fetch).toHaveBeenCalledTimes(1);
|
|
31
|
+
const [url, init] = fetch.mock.calls[0];
|
|
32
|
+
expect(String(url)).toBe(`https://example.test/proxy/api/ai/${group ? 'groups/group%2F1/workbench/' : ''}workspace-files/view-sessions/preview`);
|
|
33
|
+
expect(init).toMatchObject({
|
|
34
|
+
method: 'POST',
|
|
35
|
+
signal,
|
|
36
|
+
credentials: 'omit',
|
|
37
|
+
redirect: 'error',
|
|
38
|
+
headers: {
|
|
39
|
+
'x-context': 'current',
|
|
40
|
+
'organization-id': 'org',
|
|
41
|
+
'x-xpert-view-project-id': 'project',
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
expect(JSON.parse(String(init?.body))).toEqual({
|
|
45
|
+
hostType: 'agent',
|
|
46
|
+
hostId: 'assistant',
|
|
47
|
+
viewKey: 'view',
|
|
48
|
+
fileKey: 'file',
|
|
49
|
+
targetId: 'version',
|
|
50
|
+
variant: 'thumbnail',
|
|
51
|
+
runtimeScope,
|
|
52
|
+
});
|
|
53
|
+
expect(onRequest).toHaveBeenCalledOnce();
|
|
54
|
+
});
|
|
55
|
+
it.each([401, 403, 404, 415])('preserves HTTP %s without returning an error body as an image', async (status) => {
|
|
56
|
+
const fetch = vi
|
|
57
|
+
.fn()
|
|
58
|
+
.mockImplementation(async () => new Response('Denied', { status }));
|
|
59
|
+
const client = new Client({
|
|
60
|
+
apiUrl: 'https://example.test/api/ai',
|
|
61
|
+
callerOptions: { fetch, maxRetries: 0 },
|
|
62
|
+
});
|
|
63
|
+
await expect(client.viewHosts.readFilePreview('agent', 'assistant', 'view', {
|
|
64
|
+
fileKey: 'file',
|
|
65
|
+
variant: 'original',
|
|
66
|
+
})).rejects.toMatchObject({ status });
|
|
67
|
+
expect(fetch).toHaveBeenCalledOnce();
|
|
68
|
+
});
|
|
69
|
+
it.each([
|
|
70
|
+
['text/html', 'inline; filename="image.png"'],
|
|
71
|
+
['image/png', ''],
|
|
72
|
+
['image/png', "inline; filename*=UTF-8''..%2Fimage.png"],
|
|
73
|
+
])('rejects invalid binary metadata: %s %s', async (type, disposition) => {
|
|
74
|
+
const client = new Client({
|
|
75
|
+
apiUrl: 'https://example.test/api/ai',
|
|
76
|
+
callerOptions: {
|
|
77
|
+
fetch: async () => new Response('data', {
|
|
78
|
+
headers: { 'content-type': type, 'content-disposition': disposition },
|
|
79
|
+
}),
|
|
80
|
+
maxRetries: 0,
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
await expect(client.viewHosts.readFilePreview('agent', 'assistant', 'view', { fileKey: 'file' })).rejects.toThrow();
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
//# sourceMappingURL=view-file-preview.test.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"view-file-preview.test.mjs","sourceRoot":"","sources":["../../src/tests/view-file-preview.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import { type ThreadControlView } from './thread-control-view.js';
|
|
1
2
|
import type { TMessageContentResourceCard } from './resource-card.js';
|
|
2
3
|
/** Complete discovery snapshot. Reconnect replaces discovery state; tokens use runs.joinStream. */
|
|
3
4
|
export interface ThreadActivitySnapshot {
|
|
4
5
|
version: 1;
|
|
5
6
|
threadId: string;
|
|
7
|
+
controlView?: ThreadControlView;
|
|
6
8
|
runs: Array<{
|
|
7
9
|
id: string;
|
|
8
10
|
status: string;
|
package/dist/thread-activity.js
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
|
+
import { isThreadControlView } from "./thread-control-view.js";
|
|
1
2
|
export function isThreadActivitySnapshot(value) {
|
|
2
3
|
if (!value || typeof value !== 'object' || !('version' in value) || value.version !== 1 ||
|
|
3
4
|
!('threadId' in value) || typeof value.threadId !== 'string' ||
|
|
4
5
|
!('runs' in value) || !Array.isArray(value.runs) ||
|
|
5
6
|
!('cards' in value) || !Array.isArray(value.cards))
|
|
6
7
|
return false;
|
|
8
|
+
if ('controlView' in value && value.controlView !== undefined && !isThreadControlView(value.controlView))
|
|
9
|
+
return false;
|
|
7
10
|
// Card payloads use the shared resource-card parser at the rendering boundary.
|
|
8
11
|
return value.runs.every((run) => !!run && typeof run === 'object' &&
|
|
9
12
|
'id' in run && typeof run.id === 'string' &&
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"thread-activity.js","sourceRoot":"","sources":["../src/thread-activity.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"thread-activity.js","sourceRoot":"","sources":["../src/thread-activity.ts"],"names":[],"mappings":"OAAO,EAAE,mBAAmB,EAA0B;AAYtD,MAAM,UAAU,wBAAwB,CAAC,KAAc;IACrD,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,CAAC,SAAS,IAAI,KAAK,CAAC,IAAI,KAAK,CAAC,OAAO,KAAK,CAAC;QACnF,CAAC,CAAC,UAAU,IAAI,KAAK,CAAC,IAAI,OAAO,KAAK,CAAC,QAAQ,KAAK,QAAQ;QAC5D,CAAC,CAAC,MAAM,IAAI,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC;QAChD,CAAC,CAAC,OAAO,IAAI,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACrE,IAAI,aAAa,IAAI,KAAK,IAAI,KAAK,CAAC,WAAW,KAAK,SAAS,IAAI,CAAC,mBAAmB,CAAC,KAAK,CAAC,WAAW,CAAC;QAAE,OAAO,KAAK,CAAC;IACvH,+EAA+E;IAC/E,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ;QACxE,IAAI,IAAI,GAAG,IAAI,OAAO,GAAG,CAAC,EAAE,KAAK,QAAQ;QACzC,QAAQ,IAAI,GAAG,IAAI,OAAO,GAAG,CAAC,MAAM,KAAK,QAAQ;QACjD,WAAW,IAAI,GAAG,IAAI,OAAO,GAAG,CAAC,SAAS,KAAK,QAAQ;QACvD,WAAW,IAAI,GAAG,IAAI,OAAO,GAAG,CAAC,SAAS,KAAK,QAAQ;QACvD,iBAAiB,IAAI,GAAG,IAAI,OAAO,GAAG,CAAC,eAAe,KAAK,QAAQ,CAAC,CAAC;AACzE,CAAC"}
|
package/dist/thread-activity.mjs
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
|
+
import { isThreadControlView } from "./thread-control-view.mjs";
|
|
1
2
|
export function isThreadActivitySnapshot(value) {
|
|
2
3
|
if (!value || typeof value !== 'object' || !('version' in value) || value.version !== 1 ||
|
|
3
4
|
!('threadId' in value) || typeof value.threadId !== 'string' ||
|
|
4
5
|
!('runs' in value) || !Array.isArray(value.runs) ||
|
|
5
6
|
!('cards' in value) || !Array.isArray(value.cards))
|
|
6
7
|
return false;
|
|
8
|
+
if ('controlView' in value && value.controlView !== undefined && !isThreadControlView(value.controlView))
|
|
9
|
+
return false;
|
|
7
10
|
// Card payloads use the shared resource-card parser at the rendering boundary.
|
|
8
11
|
return value.runs.every((run) => !!run && typeof run === 'object' &&
|
|
9
12
|
'id' in run && typeof run.id === 'string' &&
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"thread-activity.mjs","sourceRoot":"","sources":["../src/thread-activity.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"thread-activity.mjs","sourceRoot":"","sources":["../src/thread-activity.ts"],"names":[],"mappings":"OAAO,EAAE,mBAAmB,EAA0B;AAYtD,MAAM,UAAU,wBAAwB,CAAC,KAAc;IACrD,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,CAAC,SAAS,IAAI,KAAK,CAAC,IAAI,KAAK,CAAC,OAAO,KAAK,CAAC;QACnF,CAAC,CAAC,UAAU,IAAI,KAAK,CAAC,IAAI,OAAO,KAAK,CAAC,QAAQ,KAAK,QAAQ;QAC5D,CAAC,CAAC,MAAM,IAAI,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC;QAChD,CAAC,CAAC,OAAO,IAAI,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACrE,IAAI,aAAa,IAAI,KAAK,IAAI,KAAK,CAAC,WAAW,KAAK,SAAS,IAAI,CAAC,mBAAmB,CAAC,KAAK,CAAC,WAAW,CAAC;QAAE,OAAO,KAAK,CAAC;IACvH,+EAA+E;IAC/E,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ;QACxE,IAAI,IAAI,GAAG,IAAI,OAAO,GAAG,CAAC,EAAE,KAAK,QAAQ;QACzC,QAAQ,IAAI,GAAG,IAAI,OAAO,GAAG,CAAC,MAAM,KAAK,QAAQ;QACjD,WAAW,IAAI,GAAG,IAAI,OAAO,GAAG,CAAC,SAAS,KAAK,QAAQ;QACvD,WAAW,IAAI,GAAG,IAAI,OAAO,GAAG,CAAC,SAAS,KAAK,QAAQ;QACvD,iBAAiB,IAAI,GAAG,IAAI,OAAO,GAAG,CAAC,eAAe,KAAK,QAAQ,CAAC,CAAC;AACzE,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** Public hints only. The host revalidates every action against its durable execution state. */
|
|
2
|
+
export type ThreadControlActions = {
|
|
3
|
+
canPause: boolean;
|
|
4
|
+
canResume: boolean;
|
|
5
|
+
canTerminate: boolean;
|
|
6
|
+
canSend: boolean;
|
|
7
|
+
canQueue: boolean;
|
|
8
|
+
canRetry: boolean;
|
|
9
|
+
canRespond: boolean;
|
|
10
|
+
};
|
|
11
|
+
export type ThreadControlView = {
|
|
12
|
+
version: 1;
|
|
13
|
+
threadId: string;
|
|
14
|
+
runId: string | null;
|
|
15
|
+
/** Decimal durable clock; do not compare revisions as strings or timestamps. */
|
|
16
|
+
revision: string;
|
|
17
|
+
state: 'idle' | 'running' | 'pausing' | 'paused' | 'stopping' | 'settling' | 'input_required' | 'confirming' | 'completed' | 'stopped' | 'failed';
|
|
18
|
+
actions: ThreadControlActions;
|
|
19
|
+
pauseId?: string;
|
|
20
|
+
};
|
|
21
|
+
export declare function isThreadControlView(value: unknown): value is ThreadControlView;
|
|
22
|
+
/** Revisions order the whole thread, including replacement runs. Never let an old response restore controls. */
|
|
23
|
+
export declare function mergeThreadControlView(previous: ThreadControlView | undefined, incoming: ThreadControlView): ThreadControlView;
|