@lifebyte-systems-sa/wuyong-client 0.1.3

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/README.md ADDED
@@ -0,0 +1,129 @@
1
+ # @lifebyte-systems-sa/wuyong-client
2
+
3
+ TypeScript client for the Wuyong Orchestrator `/chat` API.
4
+
5
+ The SDK is framework-agnostic and works with any frontend that can provide:
6
+
7
+ - an Auth0 access token
8
+ - one or more selected trading logins
9
+ - a Wuyong Orchestrator base URL
10
+
11
+ ## Install
12
+
13
+ From this monorepo workspace:
14
+
15
+ ```bash
16
+ npm install
17
+ npm test --workspace @lifebyte-systems-sa/wuyong-client
18
+ npm run build --workspace @lifebyte-systems-sa/wuyong-client
19
+ ```
20
+
21
+ In a frontend application, install the public package from the npm registry:
22
+
23
+ ```bash
24
+ npm install @lifebyte-systems-sa/wuyong-client
25
+ ```
26
+
27
+ ```ts
28
+ import { WuyongClient, WuyongError } from "@lifebyte-systems-sa/wuyong-client";
29
+ ```
30
+
31
+ ## Basic usage
32
+
33
+ ```ts
34
+ const client = new WuyongClient({
35
+ baseUrl: "https://orchestrator-sa.example.com",
36
+ getAccessToken: () => getAccessTokenSilently(),
37
+ getLogins: () => selectedTradingLogins,
38
+ });
39
+
40
+ const result = await client.chat({
41
+ threadId: "conversation-123",
42
+ message: "我的账户现在风险怎么样?",
43
+ });
44
+
45
+ console.log(result.answer);
46
+ ```
47
+
48
+ The SDK sends:
49
+
50
+ - `POST /chat`
51
+ - `Authorization: Bearer <Auth0 JWT>`
52
+ - `x-wuyong-logins: 100003,100004`
53
+ - `mode: "member"`
54
+ - `capability: "readonly"`
55
+
56
+ ## Auth0
57
+
58
+ `getAccessToken` should return an Auth0 JWT that the Orchestrator can validate.
59
+
60
+ The token should include `user_id` or `sub`. If Member Portal tools are needed, it should also include:
61
+
62
+ ```json
63
+ {
64
+ "app_metadata": {
65
+ "php_access_token": "<member-portal-token>"
66
+ }
67
+ }
68
+ ```
69
+
70
+ Do not expose or send `php_refresh_token` to Wuyong.
71
+
72
+ ## Trading logins
73
+
74
+ `getLogins` returns the selected trading account logins:
75
+
76
+ ```ts
77
+ getLogins: () => [100003]
78
+ ```
79
+
80
+ Multiple logins are sent as a comma-separated `x-wuyong-logins` header.
81
+
82
+ If no logins are available, `client.chat()` throws:
83
+
84
+ ```ts
85
+ WuyongError { code: "MISSING_LOGINS" }
86
+ ```
87
+
88
+ ## Error handling
89
+
90
+ ```ts
91
+ try {
92
+ const result = await client.chat({ threadId, message });
93
+ renderAnswer(result.answer);
94
+ } catch (error) {
95
+ if (error instanceof WuyongError) {
96
+ switch (error.code) {
97
+ case "AUTH_REQUIRED":
98
+ loginWithRedirect();
99
+ break;
100
+ case "MISSING_LOGINS":
101
+ showAccountPicker();
102
+ break;
103
+ case "INVALID_REQUEST":
104
+ showValidationError(error.details);
105
+ break;
106
+ case "SERVER_ERROR":
107
+ case "NETWORK_ERROR":
108
+ showRetryMessage();
109
+ break;
110
+ }
111
+ }
112
+ }
113
+ ```
114
+
115
+ ## Response
116
+
117
+ `client.chat()` returns:
118
+
119
+ ```ts
120
+ type ChatResponse = {
121
+ answer: string;
122
+ facts: Record<string, Fact>;
123
+ audit_events: AuditEvent[];
124
+ ui_events: UiEvent[];
125
+ tool_calls: string[];
126
+ };
127
+ ```
128
+
129
+ Use `answer` for the user-visible response. Use `facts`, `tool_calls`, and `audit_events` for traceability/debug views.
@@ -0,0 +1,55 @@
1
+ export type WuyongErrorCode = "AUTH_REQUIRED" | "INVALID_REQUEST" | "SERVER_ERROR" | "MISSING_LOGINS" | "NETWORK_ERROR";
2
+ export interface WuyongClientOptions {
3
+ baseUrl: string;
4
+ getAccessToken: () => Promise<string> | string;
5
+ getLogins: () => Promise<number[]> | number[];
6
+ fetch?: typeof fetch;
7
+ }
8
+ export interface ChatRequest {
9
+ threadId: string;
10
+ message: string;
11
+ }
12
+ export interface Fact {
13
+ key: string;
14
+ value: Record<string, unknown>;
15
+ source_tool: string;
16
+ source_mcp_server: string;
17
+ ttl_seconds: number;
18
+ ts: string;
19
+ [key: string]: unknown;
20
+ }
21
+ export interface AuditEvent {
22
+ agent: string;
23
+ action: string;
24
+ outcome: string;
25
+ [key: string]: unknown;
26
+ }
27
+ export interface UiEvent {
28
+ type?: string;
29
+ [key: string]: unknown;
30
+ }
31
+ export interface ChatResponse {
32
+ answer: string;
33
+ facts: Record<string, Fact>;
34
+ audit_events: AuditEvent[];
35
+ ui_events: UiEvent[];
36
+ tool_calls: string[];
37
+ }
38
+ export declare class WuyongError extends Error {
39
+ readonly code: WuyongErrorCode;
40
+ readonly status?: number;
41
+ readonly details?: string;
42
+ constructor(code: WuyongErrorCode, message: string, options?: {
43
+ status?: number;
44
+ details?: string;
45
+ });
46
+ }
47
+ export declare class WuyongClient {
48
+ private readonly baseUrl;
49
+ private readonly getAccessToken;
50
+ private readonly getLogins;
51
+ private readonly fetchImpl;
52
+ constructor(options: WuyongClientOptions);
53
+ chat(request: ChatRequest): Promise<ChatResponse>;
54
+ private errorFromResponse;
55
+ }
package/dist/index.js ADDED
@@ -0,0 +1,75 @@
1
+ export class WuyongError extends Error {
2
+ code;
3
+ status;
4
+ details;
5
+ constructor(code, message, options = {}) {
6
+ super(message);
7
+ this.name = "WuyongError";
8
+ this.code = code;
9
+ this.status = options.status;
10
+ this.details = options.details;
11
+ }
12
+ }
13
+ export class WuyongClient {
14
+ baseUrl;
15
+ getAccessToken;
16
+ getLogins;
17
+ fetchImpl;
18
+ constructor(options) {
19
+ this.baseUrl = options.baseUrl.replace(/\/+$/, "");
20
+ this.getAccessToken = options.getAccessToken;
21
+ this.getLogins = options.getLogins;
22
+ this.fetchImpl = options.fetch ?? fetch;
23
+ }
24
+ async chat(request) {
25
+ const [token, logins] = await Promise.all([this.getAccessToken(), this.getLogins()]);
26
+ if (!logins.length) {
27
+ throw new WuyongError("MISSING_LOGINS", "At least one trading login is required.");
28
+ }
29
+ let response;
30
+ try {
31
+ response = await this.fetchImpl(`${this.baseUrl}/chat`, {
32
+ method: "POST",
33
+ headers: {
34
+ "Content-Type": "application/json",
35
+ Authorization: `Bearer ${token}`,
36
+ "x-wuyong-logins": logins.join(","),
37
+ },
38
+ body: JSON.stringify({
39
+ thread_id: request.threadId,
40
+ mode: "member",
41
+ capability: "readonly",
42
+ message: request.message,
43
+ }),
44
+ });
45
+ }
46
+ catch (error) {
47
+ throw new WuyongError("NETWORK_ERROR", "Unable to reach Wuyong Orchestrator.", {
48
+ details: error instanceof Error ? error.message : String(error),
49
+ });
50
+ }
51
+ if (!response.ok) {
52
+ throw await this.errorFromResponse(response);
53
+ }
54
+ return (await response.json());
55
+ }
56
+ async errorFromResponse(response) {
57
+ const details = await response.text();
58
+ if (response.status === 401) {
59
+ return new WuyongError("AUTH_REQUIRED", "Authentication is required.", {
60
+ status: response.status,
61
+ details,
62
+ });
63
+ }
64
+ if (response.status === 422) {
65
+ return new WuyongError("INVALID_REQUEST", "The Wuyong request is invalid.", {
66
+ status: response.status,
67
+ details,
68
+ });
69
+ }
70
+ return new WuyongError("SERVER_ERROR", "Wuyong Orchestrator returned an error.", {
71
+ status: response.status,
72
+ details,
73
+ });
74
+ }
75
+ }
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "@lifebyte-systems-sa/wuyong-client",
3
+ "version": "0.1.3",
4
+ "type": "module",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/index.d.ts",
10
+ "import": "./dist/index.js"
11
+ }
12
+ },
13
+ "files": [
14
+ "dist",
15
+ "README.md"
16
+ ],
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "git+https://github.com/lifebyte-systems-sa/ai-routers.git",
20
+ "directory": "packages/wuyong-client"
21
+ },
22
+ "publishConfig": {
23
+ "access": "public",
24
+ "registry": "https://registry.npmjs.org/"
25
+ },
26
+ "scripts": {
27
+ "build": "tsc -p tsconfig.json",
28
+ "prepack": "npm run build",
29
+ "test": "vitest run"
30
+ },
31
+ "devDependencies": {
32
+ "typescript": "^5.9.3",
33
+ "vitest": "^4.0.8"
34
+ }
35
+ }