@syfthub/sdk 0.2.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +494 -178
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +495 -146
- package/dist/index.d.ts +495 -146
- package/dist/index.js +494 -179
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -677,6 +677,116 @@ var APITokensResource = class {
|
|
|
677
677
|
}
|
|
678
678
|
};
|
|
679
679
|
|
|
680
|
+
// src/resources/aggregators.ts
|
|
681
|
+
var AggregatorsResource = class {
|
|
682
|
+
constructor(http) {
|
|
683
|
+
this.http = http;
|
|
684
|
+
}
|
|
685
|
+
/**
|
|
686
|
+
* List all aggregator configurations for the current user.
|
|
687
|
+
*
|
|
688
|
+
* @returns Array of UserAggregator objects
|
|
689
|
+
* @throws {AuthenticationError} If not authenticated
|
|
690
|
+
*
|
|
691
|
+
* @example
|
|
692
|
+
* const aggregators = await client.users.aggregators.list();
|
|
693
|
+
* for (const agg of aggregators) {
|
|
694
|
+
* if (agg.isDefault) {
|
|
695
|
+
* console.log(`Default: ${agg.name}`);
|
|
696
|
+
* }
|
|
697
|
+
* }
|
|
698
|
+
*/
|
|
699
|
+
async list() {
|
|
700
|
+
return this.http.get("/api/v1/users/me/aggregators");
|
|
701
|
+
}
|
|
702
|
+
/**
|
|
703
|
+
* Get a specific aggregator configuration by ID.
|
|
704
|
+
*
|
|
705
|
+
* @param aggregatorId - The aggregator ID
|
|
706
|
+
* @returns The UserAggregator object
|
|
707
|
+
* @throws {AuthenticationError} If not authenticated
|
|
708
|
+
* @throws {NotFoundError} If aggregator not found
|
|
709
|
+
*
|
|
710
|
+
* @example
|
|
711
|
+
* const agg = await client.users.aggregators.get(1);
|
|
712
|
+
* console.log(`${agg.name}: ${agg.url}`);
|
|
713
|
+
*/
|
|
714
|
+
async get(aggregatorId) {
|
|
715
|
+
return this.http.get(`/api/v1/users/me/aggregators/${aggregatorId}`);
|
|
716
|
+
}
|
|
717
|
+
/**
|
|
718
|
+
* Create a new aggregator configuration.
|
|
719
|
+
*
|
|
720
|
+
* The first aggregator created is automatically set as the default.
|
|
721
|
+
*
|
|
722
|
+
* @param input - Aggregator creation input
|
|
723
|
+
* @returns The created UserAggregator object
|
|
724
|
+
* @throws {AuthenticationError} If not authenticated
|
|
725
|
+
* @throws {ValidationError} If input is invalid
|
|
726
|
+
*
|
|
727
|
+
* @example
|
|
728
|
+
* const agg = await client.users.aggregators.create({
|
|
729
|
+
* name: 'My Custom Aggregator',
|
|
730
|
+
* url: 'https://my-aggregator.example.com'
|
|
731
|
+
* });
|
|
732
|
+
* console.log(`Created: ${agg.id}`);
|
|
733
|
+
*/
|
|
734
|
+
async create(input) {
|
|
735
|
+
return this.http.post("/api/v1/users/me/aggregators", input);
|
|
736
|
+
}
|
|
737
|
+
/**
|
|
738
|
+
* Update an aggregator configuration.
|
|
739
|
+
*
|
|
740
|
+
* Only provided fields will be updated.
|
|
741
|
+
*
|
|
742
|
+
* @param aggregatorId - The aggregator ID to update
|
|
743
|
+
* @param input - Fields to update
|
|
744
|
+
* @returns The updated UserAggregator object
|
|
745
|
+
* @throws {AuthenticationError} If not authenticated
|
|
746
|
+
* @throws {NotFoundError} If aggregator not found
|
|
747
|
+
* @throws {ValidationError} If input is invalid
|
|
748
|
+
*
|
|
749
|
+
* @example
|
|
750
|
+
* const agg = await client.users.aggregators.update(1, {
|
|
751
|
+
* name: 'Updated Name'
|
|
752
|
+
* });
|
|
753
|
+
*/
|
|
754
|
+
async update(aggregatorId, input) {
|
|
755
|
+
return this.http.put(`/api/v1/users/me/aggregators/${aggregatorId}`, input);
|
|
756
|
+
}
|
|
757
|
+
/**
|
|
758
|
+
* Delete an aggregator configuration.
|
|
759
|
+
*
|
|
760
|
+
* @param aggregatorId - The aggregator ID to delete
|
|
761
|
+
* @throws {AuthenticationError} If not authenticated
|
|
762
|
+
* @throws {NotFoundError} If aggregator not found
|
|
763
|
+
*
|
|
764
|
+
* @example
|
|
765
|
+
* await client.users.aggregators.delete(1);
|
|
766
|
+
*/
|
|
767
|
+
async delete(aggregatorId) {
|
|
768
|
+
await this.http.delete(`/api/v1/users/me/aggregators/${aggregatorId}`);
|
|
769
|
+
}
|
|
770
|
+
/**
|
|
771
|
+
* Set an aggregator as the default.
|
|
772
|
+
*
|
|
773
|
+
* Only one aggregator can be the default at a time. Setting a new default
|
|
774
|
+
* automatically unsets the previous one.
|
|
775
|
+
*
|
|
776
|
+
* @param aggregatorId - The aggregator ID to set as default
|
|
777
|
+
* @returns The updated UserAggregator object with isDefault=true
|
|
778
|
+
* @throws {AuthenticationError} If not authenticated
|
|
779
|
+
* @throws {NotFoundError} If aggregator not found
|
|
780
|
+
*
|
|
781
|
+
* @example
|
|
782
|
+
* const agg = await client.users.aggregators.setDefault(2);
|
|
783
|
+
* console.log(`${agg.name} is now the default`);
|
|
784
|
+
*/
|
|
785
|
+
async setDefault(aggregatorId) {
|
|
786
|
+
return this.http.patch(`/api/v1/users/me/aggregators/${aggregatorId}/default`);
|
|
787
|
+
}
|
|
788
|
+
};
|
|
789
|
+
|
|
680
790
|
// src/resources/auth.ts
|
|
681
791
|
init_errors();
|
|
682
792
|
var AuthResource = class {
|
|
@@ -1064,116 +1174,6 @@ var AuthResource = class {
|
|
|
1064
1174
|
}
|
|
1065
1175
|
};
|
|
1066
1176
|
|
|
1067
|
-
// src/resources/aggregators.ts
|
|
1068
|
-
var AggregatorsResource = class {
|
|
1069
|
-
constructor(http) {
|
|
1070
|
-
this.http = http;
|
|
1071
|
-
}
|
|
1072
|
-
/**
|
|
1073
|
-
* List all aggregator configurations for the current user.
|
|
1074
|
-
*
|
|
1075
|
-
* @returns Array of UserAggregator objects
|
|
1076
|
-
* @throws {AuthenticationError} If not authenticated
|
|
1077
|
-
*
|
|
1078
|
-
* @example
|
|
1079
|
-
* const aggregators = await client.users.aggregators.list();
|
|
1080
|
-
* for (const agg of aggregators) {
|
|
1081
|
-
* if (agg.isDefault) {
|
|
1082
|
-
* console.log(`Default: ${agg.name}`);
|
|
1083
|
-
* }
|
|
1084
|
-
* }
|
|
1085
|
-
*/
|
|
1086
|
-
async list() {
|
|
1087
|
-
return this.http.get("/api/v1/users/me/aggregators");
|
|
1088
|
-
}
|
|
1089
|
-
/**
|
|
1090
|
-
* Get a specific aggregator configuration by ID.
|
|
1091
|
-
*
|
|
1092
|
-
* @param aggregatorId - The aggregator ID
|
|
1093
|
-
* @returns The UserAggregator object
|
|
1094
|
-
* @throws {AuthenticationError} If not authenticated
|
|
1095
|
-
* @throws {NotFoundError} If aggregator not found
|
|
1096
|
-
*
|
|
1097
|
-
* @example
|
|
1098
|
-
* const agg = await client.users.aggregators.get(1);
|
|
1099
|
-
* console.log(`${agg.name}: ${agg.url}`);
|
|
1100
|
-
*/
|
|
1101
|
-
async get(aggregatorId) {
|
|
1102
|
-
return this.http.get(`/api/v1/users/me/aggregators/${aggregatorId}`);
|
|
1103
|
-
}
|
|
1104
|
-
/**
|
|
1105
|
-
* Create a new aggregator configuration.
|
|
1106
|
-
*
|
|
1107
|
-
* The first aggregator created is automatically set as the default.
|
|
1108
|
-
*
|
|
1109
|
-
* @param input - Aggregator creation input
|
|
1110
|
-
* @returns The created UserAggregator object
|
|
1111
|
-
* @throws {AuthenticationError} If not authenticated
|
|
1112
|
-
* @throws {ValidationError} If input is invalid
|
|
1113
|
-
*
|
|
1114
|
-
* @example
|
|
1115
|
-
* const agg = await client.users.aggregators.create({
|
|
1116
|
-
* name: 'My Custom Aggregator',
|
|
1117
|
-
* url: 'https://my-aggregator.example.com'
|
|
1118
|
-
* });
|
|
1119
|
-
* console.log(`Created: ${agg.id}`);
|
|
1120
|
-
*/
|
|
1121
|
-
async create(input) {
|
|
1122
|
-
return this.http.post("/api/v1/users/me/aggregators", input);
|
|
1123
|
-
}
|
|
1124
|
-
/**
|
|
1125
|
-
* Update an aggregator configuration.
|
|
1126
|
-
*
|
|
1127
|
-
* Only provided fields will be updated.
|
|
1128
|
-
*
|
|
1129
|
-
* @param aggregatorId - The aggregator ID to update
|
|
1130
|
-
* @param input - Fields to update
|
|
1131
|
-
* @returns The updated UserAggregator object
|
|
1132
|
-
* @throws {AuthenticationError} If not authenticated
|
|
1133
|
-
* @throws {NotFoundError} If aggregator not found
|
|
1134
|
-
* @throws {ValidationError} If input is invalid
|
|
1135
|
-
*
|
|
1136
|
-
* @example
|
|
1137
|
-
* const agg = await client.users.aggregators.update(1, {
|
|
1138
|
-
* name: 'Updated Name'
|
|
1139
|
-
* });
|
|
1140
|
-
*/
|
|
1141
|
-
async update(aggregatorId, input) {
|
|
1142
|
-
return this.http.put(`/api/v1/users/me/aggregators/${aggregatorId}`, input);
|
|
1143
|
-
}
|
|
1144
|
-
/**
|
|
1145
|
-
* Delete an aggregator configuration.
|
|
1146
|
-
*
|
|
1147
|
-
* @param aggregatorId - The aggregator ID to delete
|
|
1148
|
-
* @throws {AuthenticationError} If not authenticated
|
|
1149
|
-
* @throws {NotFoundError} If aggregator not found
|
|
1150
|
-
*
|
|
1151
|
-
* @example
|
|
1152
|
-
* await client.users.aggregators.delete(1);
|
|
1153
|
-
*/
|
|
1154
|
-
async delete(aggregatorId) {
|
|
1155
|
-
await this.http.delete(`/api/v1/users/me/aggregators/${aggregatorId}`);
|
|
1156
|
-
}
|
|
1157
|
-
/**
|
|
1158
|
-
* Set an aggregator as the default.
|
|
1159
|
-
*
|
|
1160
|
-
* Only one aggregator can be the default at a time. Setting a new default
|
|
1161
|
-
* automatically unsets the previous one.
|
|
1162
|
-
*
|
|
1163
|
-
* @param aggregatorId - The aggregator ID to set as default
|
|
1164
|
-
* @returns The updated UserAggregator object with isDefault=true
|
|
1165
|
-
* @throws {AuthenticationError} If not authenticated
|
|
1166
|
-
* @throws {NotFoundError} If aggregator not found
|
|
1167
|
-
*
|
|
1168
|
-
* @example
|
|
1169
|
-
* const agg = await client.users.aggregators.setDefault(2);
|
|
1170
|
-
* console.log(`${agg.name} is now the default`);
|
|
1171
|
-
*/
|
|
1172
|
-
async setDefault(aggregatorId) {
|
|
1173
|
-
return this.http.patch(`/api/v1/users/me/aggregators/${aggregatorId}/default`);
|
|
1174
|
-
}
|
|
1175
|
-
};
|
|
1176
|
-
|
|
1177
1177
|
// src/resources/users.ts
|
|
1178
1178
|
var UsersResource = class {
|
|
1179
1179
|
constructor(http) {
|
|
@@ -2187,10 +2187,11 @@ function getEndpointPublicPath(endpoint) {
|
|
|
2187
2187
|
|
|
2188
2188
|
// src/resources/chat.ts
|
|
2189
2189
|
var AggregatorError = class extends SyftHubError {
|
|
2190
|
-
constructor(message, status, detail) {
|
|
2190
|
+
constructor(message, status, detail, billing) {
|
|
2191
2191
|
super(message);
|
|
2192
2192
|
this.status = status;
|
|
2193
2193
|
this.detail = detail;
|
|
2194
|
+
this.billing = billing;
|
|
2194
2195
|
this.name = "AggregatorError";
|
|
2195
2196
|
}
|
|
2196
2197
|
};
|
|
@@ -2396,7 +2397,7 @@ var ChatResource = class _ChatResource {
|
|
|
2396
2397
|
* Resolves endpoints, fetches tokens, and builds the aggregator request body.
|
|
2397
2398
|
* Returns the request body and the resolved aggregator URL.
|
|
2398
2399
|
*/
|
|
2399
|
-
async prepareRequest(options, stream) {
|
|
2400
|
+
async prepareRequest(options, stream, retrievalOnly = false) {
|
|
2400
2401
|
const modelRef = await this.resolveEndpointRef(options.model, "model");
|
|
2401
2402
|
const expandedDataSources = await this.expandCollectivePaths(options.dataSources ?? []);
|
|
2402
2403
|
const dsRefs = [];
|
|
@@ -2431,7 +2432,8 @@ var ChatResource = class _ChatResource {
|
|
|
2431
2432
|
stream,
|
|
2432
2433
|
messages: options.messages,
|
|
2433
2434
|
peerToken,
|
|
2434
|
-
peerChannel
|
|
2435
|
+
peerChannel,
|
|
2436
|
+
retrievalOnly
|
|
2435
2437
|
}
|
|
2436
2438
|
);
|
|
2437
2439
|
const effectiveAggregatorUrl = (options.aggregatorUrl ?? this.aggregatorUrl).replace(
|
|
@@ -2445,12 +2447,14 @@ var ChatResource = class _ChatResource {
|
|
|
2445
2447
|
*/
|
|
2446
2448
|
async handleAggregatorErrorResponse(response) {
|
|
2447
2449
|
let message = `HTTP ${response.status}`;
|
|
2450
|
+
let billing;
|
|
2448
2451
|
try {
|
|
2449
2452
|
const data = await response.json();
|
|
2450
|
-
message = String(data["message"] ?? data["error"] ?? message);
|
|
2453
|
+
message = String(data["message"] ?? data["error"] ?? data["detail"] ?? message);
|
|
2454
|
+
billing = this.parseBilling(data);
|
|
2451
2455
|
} catch {
|
|
2452
2456
|
}
|
|
2453
|
-
throw new AggregatorError(`Aggregator error: ${message}`, response.status);
|
|
2457
|
+
throw new AggregatorError(`Aggregator error: ${message}`, response.status, void 0, billing);
|
|
2454
2458
|
}
|
|
2455
2459
|
/**
|
|
2456
2460
|
* Build the request body for the aggregator.
|
|
@@ -2494,6 +2498,9 @@ var ChatResource = class _ChatResource {
|
|
|
2494
2498
|
if (options.peerChannel) {
|
|
2495
2499
|
body["peer_channel"] = options.peerChannel;
|
|
2496
2500
|
}
|
|
2501
|
+
if (options.retrievalOnly) {
|
|
2502
|
+
body["retrieval_only"] = true;
|
|
2503
|
+
}
|
|
2497
2504
|
return body;
|
|
2498
2505
|
}
|
|
2499
2506
|
/**
|
|
@@ -2527,6 +2534,60 @@ var ChatResource = class _ChatResource {
|
|
|
2527
2534
|
totalTokens: Number(data["total_tokens"] ?? 0)
|
|
2528
2535
|
};
|
|
2529
2536
|
}
|
|
2537
|
+
/**
|
|
2538
|
+
* Parse a single billing/policy-metadata entry from a raw (snake_case) dict.
|
|
2539
|
+
*
|
|
2540
|
+
* Shared by {@link parseBilling} (aggregated, carries `source`) and the
|
|
2541
|
+
* direct-path `policy_metadata` parsing in {@link SyftAIResource}.
|
|
2542
|
+
*/
|
|
2543
|
+
static parseBillingEntry(raw) {
|
|
2544
|
+
const recipientRaw = raw["recipient"];
|
|
2545
|
+
const recipient = recipientRaw && typeof recipientRaw === "object" ? {
|
|
2546
|
+
username: recipientRaw["username"],
|
|
2547
|
+
email: recipientRaw["email"],
|
|
2548
|
+
walletAddress: recipientRaw["wallet_address"]
|
|
2549
|
+
} : void 0;
|
|
2550
|
+
const transactionRaw = raw["transaction"];
|
|
2551
|
+
const transaction = transactionRaw && typeof transactionRaw === "object" ? {
|
|
2552
|
+
rail: String(transactionRaw["rail"] ?? ""),
|
|
2553
|
+
id: String(transactionRaw["id"] ?? ""),
|
|
2554
|
+
reference: transactionRaw["reference"]
|
|
2555
|
+
} : void 0;
|
|
2556
|
+
return {
|
|
2557
|
+
source: raw["source"],
|
|
2558
|
+
policyType: String(raw["policy_type"] ?? ""),
|
|
2559
|
+
kind: String(raw["kind"] ?? ""),
|
|
2560
|
+
status: String(raw["status"] ?? ""),
|
|
2561
|
+
amount: raw["amount"] == null ? void 0 : Number(raw["amount"]),
|
|
2562
|
+
currency: raw["currency"],
|
|
2563
|
+
recipient,
|
|
2564
|
+
transaction,
|
|
2565
|
+
reasonCode: raw["reason_code"],
|
|
2566
|
+
reason: raw["reason"],
|
|
2567
|
+
details: raw["details"] ?? {}
|
|
2568
|
+
};
|
|
2569
|
+
}
|
|
2570
|
+
/**
|
|
2571
|
+
* Parse the aggregated `billing` block from a raw aggregator response.
|
|
2572
|
+
*
|
|
2573
|
+
* Returns undefined when no `billing` object is present (e.g. an error body
|
|
2574
|
+
* with no policy metadata). The wire keys are snake_case.
|
|
2575
|
+
*/
|
|
2576
|
+
parseBilling(data) {
|
|
2577
|
+
const b = data["billing"];
|
|
2578
|
+
if (!b || typeof b !== "object") {
|
|
2579
|
+
return void 0;
|
|
2580
|
+
}
|
|
2581
|
+
const billing = b;
|
|
2582
|
+
const entriesRaw = Array.isArray(billing["entries"]) ? billing["entries"] : [];
|
|
2583
|
+
return {
|
|
2584
|
+
totalCost: billing["total_cost"] == null ? null : Number(billing["total_cost"]),
|
|
2585
|
+
currency: billing["currency"] ?? null,
|
|
2586
|
+
entries: entriesRaw.map(
|
|
2587
|
+
(e) => _ChatResource.parseBillingEntry(e)
|
|
2588
|
+
)
|
|
2589
|
+
};
|
|
2590
|
+
}
|
|
2530
2591
|
/**
|
|
2531
2592
|
* Parse document sources from raw data.
|
|
2532
2593
|
* The new format is a dict mapping document title to {slug, content}.
|
|
@@ -2594,15 +2655,82 @@ var ChatResource = class _ChatResource {
|
|
|
2594
2655
|
const usageData = data["usage"];
|
|
2595
2656
|
const usage = usageData ? this.parseUsage(usageData) : void 0;
|
|
2596
2657
|
const profitShare = data["profit_share"];
|
|
2658
|
+
const billing = this.parseBilling(data);
|
|
2597
2659
|
return {
|
|
2598
2660
|
response: String(data["response"] ?? ""),
|
|
2599
2661
|
sources,
|
|
2600
2662
|
retrievalInfo,
|
|
2601
2663
|
metadata,
|
|
2602
2664
|
usage,
|
|
2603
|
-
profitShare
|
|
2665
|
+
profitShare,
|
|
2666
|
+
billing
|
|
2604
2667
|
};
|
|
2605
2668
|
}
|
|
2669
|
+
/**
|
|
2670
|
+
* Placeholder model for retrieval-only requests. The aggregator requires a
|
|
2671
|
+
* `model` field on every request, but short-circuits before dereferencing it
|
|
2672
|
+
* when `retrieval_only` is set, so an empty ref is never contacted.
|
|
2673
|
+
*/
|
|
2674
|
+
static RETRIEVAL_ONLY_MODEL = {
|
|
2675
|
+
url: "",
|
|
2676
|
+
slug: "",
|
|
2677
|
+
name: "retrieval-only"
|
|
2678
|
+
};
|
|
2679
|
+
/**
|
|
2680
|
+
* Retrieve documents from data sources without model generation.
|
|
2681
|
+
*
|
|
2682
|
+
* Drives the aggregator's retrieval-only path: data sources are queried in
|
|
2683
|
+
* parallel (with satellite-token auth and MPP payment handled server-side,
|
|
2684
|
+
* exactly like {@link complete}), but no model is invoked.
|
|
2685
|
+
*
|
|
2686
|
+
* Prefer the symmetric `client.search.query(...)` facade; this is the
|
|
2687
|
+
* underlying primitive.
|
|
2688
|
+
*
|
|
2689
|
+
* @param options - Search options
|
|
2690
|
+
* @returns SearchResponse with retrieved documents and per-source metadata
|
|
2691
|
+
* @throws {EndpointResolutionError} If a data source cannot be resolved
|
|
2692
|
+
* @throws {AggregatorError} If the aggregator service fails
|
|
2693
|
+
*/
|
|
2694
|
+
async retrieve(options) {
|
|
2695
|
+
const chatOptions = {
|
|
2696
|
+
prompt: options.prompt,
|
|
2697
|
+
model: _ChatResource.RETRIEVAL_ONLY_MODEL,
|
|
2698
|
+
dataSources: options.dataSources,
|
|
2699
|
+
topK: options.topK,
|
|
2700
|
+
similarityThreshold: options.similarityThreshold,
|
|
2701
|
+
aggregatorUrl: options.aggregatorUrl,
|
|
2702
|
+
guestMode: options.guestMode
|
|
2703
|
+
};
|
|
2704
|
+
const { requestBody, effectiveAggregatorUrl } = await this.prepareRequest(
|
|
2705
|
+
chatOptions,
|
|
2706
|
+
false,
|
|
2707
|
+
true
|
|
2708
|
+
);
|
|
2709
|
+
const response = await fetch(`${effectiveAggregatorUrl}/chat`, {
|
|
2710
|
+
method: "POST",
|
|
2711
|
+
headers: { "Content-Type": "application/json" },
|
|
2712
|
+
body: JSON.stringify(requestBody),
|
|
2713
|
+
signal: options.signal
|
|
2714
|
+
});
|
|
2715
|
+
if (!response.ok) {
|
|
2716
|
+
return this.handleAggregatorErrorResponse(response);
|
|
2717
|
+
}
|
|
2718
|
+
const data = await response.json();
|
|
2719
|
+
const sources = this.parseDocumentSources(
|
|
2720
|
+
data["sources"]
|
|
2721
|
+
);
|
|
2722
|
+
const documents = Object.entries(sources).map(([title, source]) => ({
|
|
2723
|
+
title,
|
|
2724
|
+
slug: source.slug,
|
|
2725
|
+
content: source.content
|
|
2726
|
+
}));
|
|
2727
|
+
const retrievalInfo = this.parseRetrievalInfo(
|
|
2728
|
+
data["retrieval_info"]
|
|
2729
|
+
);
|
|
2730
|
+
const metadata = this.parseMetadata(data["metadata"] ?? {});
|
|
2731
|
+
const billing = this.parseBilling(data);
|
|
2732
|
+
return { documents, retrievalInfo, metadata, billing };
|
|
2733
|
+
}
|
|
2606
2734
|
/**
|
|
2607
2735
|
* Send a chat request and stream response events.
|
|
2608
2736
|
*
|
|
@@ -2701,13 +2829,24 @@ var ChatResource = class _ChatResource {
|
|
|
2701
2829
|
const usageData = data["usage"];
|
|
2702
2830
|
const usage = usageData ? this.parseUsage(usageData) : void 0;
|
|
2703
2831
|
const profitShare = data["profit_share"];
|
|
2832
|
+
const billing = this.parseBilling(data);
|
|
2704
2833
|
const response = data["response"];
|
|
2705
|
-
return {
|
|
2834
|
+
return {
|
|
2835
|
+
type: "done",
|
|
2836
|
+
sources,
|
|
2837
|
+
retrievalInfo,
|
|
2838
|
+
metadata,
|
|
2839
|
+
usage,
|
|
2840
|
+
profitShare,
|
|
2841
|
+
billing,
|
|
2842
|
+
response
|
|
2843
|
+
};
|
|
2706
2844
|
}
|
|
2707
2845
|
case "error":
|
|
2708
2846
|
return {
|
|
2709
2847
|
type: "error",
|
|
2710
|
-
message: String(data["message"] ?? "Unknown error")
|
|
2848
|
+
message: String(data["message"] ?? "Unknown error"),
|
|
2849
|
+
billing: this.parseBilling(data)
|
|
2711
2850
|
};
|
|
2712
2851
|
default:
|
|
2713
2852
|
console.warn(`[SyftHub] Unknown SSE event type received from aggregator: ${eventType}`);
|
|
@@ -2748,6 +2887,34 @@ var ChatResource = class _ChatResource {
|
|
|
2748
2887
|
}
|
|
2749
2888
|
};
|
|
2750
2889
|
|
|
2890
|
+
// src/resources/search.ts
|
|
2891
|
+
var SearchResource = class {
|
|
2892
|
+
/**
|
|
2893
|
+
* @param chat - The chat resource that owns aggregator communication and
|
|
2894
|
+
* request preparation (satellite tokens, MPP, collective expansion). Search
|
|
2895
|
+
* reuses it rather than duplicating that logic.
|
|
2896
|
+
*/
|
|
2897
|
+
constructor(chat) {
|
|
2898
|
+
this.chat = chat;
|
|
2899
|
+
}
|
|
2900
|
+
/**
|
|
2901
|
+
* Retrieve documents from data sources without model generation.
|
|
2902
|
+
*
|
|
2903
|
+
* @param options - Search options (prompt, data sources, top-k, etc.)
|
|
2904
|
+
* @returns SearchResponse with retrieved documents and per-source metadata
|
|
2905
|
+
*
|
|
2906
|
+
* @example
|
|
2907
|
+
* const result = await client.search.query({
|
|
2908
|
+
* prompt: 'Hello, world!',
|
|
2909
|
+
* dataSources: ['epfl-news/epfl-news'],
|
|
2910
|
+
* });
|
|
2911
|
+
* console.log(result.documents.length, 'documents');
|
|
2912
|
+
*/
|
|
2913
|
+
async query(options) {
|
|
2914
|
+
return this.chat.retrieve(options);
|
|
2915
|
+
}
|
|
2916
|
+
};
|
|
2917
|
+
|
|
2751
2918
|
// src/resources/syftai.ts
|
|
2752
2919
|
init_errors();
|
|
2753
2920
|
var RetrievalError = class extends SyftHubError {
|
|
@@ -2767,28 +2934,149 @@ var GenerationError = class extends SyftHubError {
|
|
|
2767
2934
|
}
|
|
2768
2935
|
};
|
|
2769
2936
|
var SyftAIResource = class {
|
|
2770
|
-
|
|
2937
|
+
/**
|
|
2938
|
+
* @param http - Hub HTTP client, used to mint satellite tokens and settle
|
|
2939
|
+
* MPP payments. Endpoint queries themselves use direct `fetch`, since the
|
|
2940
|
+
* SyftAI-Space URL is arbitrary and not the Hub base URL.
|
|
2941
|
+
*/
|
|
2942
|
+
constructor(http) {
|
|
2943
|
+
this.http = http;
|
|
2944
|
+
}
|
|
2945
|
+
/**
|
|
2946
|
+
* Mint a satellite token for `audience` (the endpoint owner's username).
|
|
2947
|
+
*
|
|
2948
|
+
* Mirrors the aggregator's token coordination layer: try an authenticated
|
|
2949
|
+
* token first, then fall back to a guest token. Returns `undefined` if both
|
|
2950
|
+
* fail, so the caller can still attempt an unauthenticated request.
|
|
2951
|
+
*/
|
|
2952
|
+
async mintSatelliteToken(audience) {
|
|
2953
|
+
if (this.http.hasTokens()) {
|
|
2954
|
+
try {
|
|
2955
|
+
const res = await this.http.get("/api/v1/token", {
|
|
2956
|
+
aud: audience
|
|
2957
|
+
});
|
|
2958
|
+
if (res.targetToken) return res.targetToken;
|
|
2959
|
+
} catch {
|
|
2960
|
+
}
|
|
2961
|
+
}
|
|
2962
|
+
try {
|
|
2963
|
+
const res = await this.http.get(
|
|
2964
|
+
"/api/v1/token/guest",
|
|
2965
|
+
{ aud: audience },
|
|
2966
|
+
{ includeAuth: false }
|
|
2967
|
+
);
|
|
2968
|
+
return res.targetToken;
|
|
2969
|
+
} catch {
|
|
2970
|
+
return void 0;
|
|
2971
|
+
}
|
|
2972
|
+
}
|
|
2973
|
+
/**
|
|
2974
|
+
* Pay an MPP `402` challenge via the Hub wallet, returning an X-Payment credential.
|
|
2975
|
+
*
|
|
2976
|
+
* Mirrors the aggregator's `handleMppPayment`: the `WWW-Authenticate`
|
|
2977
|
+
* challenge is forwarded verbatim to the Hub's `/api/v1/wallet/pay`, which
|
|
2978
|
+
* parses it and returns an `x_payment` string to attach to a retry.
|
|
2979
|
+
*/
|
|
2980
|
+
async payMpp(wwwAuthenticate, slug) {
|
|
2981
|
+
if (!wwwAuthenticate) return void 0;
|
|
2982
|
+
const res = await this.http.post("/api/v1/wallet/pay", {
|
|
2983
|
+
wwwAuthenticate,
|
|
2984
|
+
endpointSlug: slug
|
|
2985
|
+
});
|
|
2986
|
+
return res.xPayment;
|
|
2987
|
+
}
|
|
2771
2988
|
/**
|
|
2772
2989
|
* Build headers for SyftAI-Space request.
|
|
2773
2990
|
*/
|
|
2774
|
-
buildHeaders(tenantName) {
|
|
2991
|
+
buildHeaders(tenantName, authorizationToken) {
|
|
2775
2992
|
const headers = {
|
|
2776
2993
|
"Content-Type": "application/json"
|
|
2777
2994
|
};
|
|
2778
2995
|
if (tenantName) {
|
|
2779
2996
|
headers["X-Tenant-Name"] = tenantName;
|
|
2780
2997
|
}
|
|
2998
|
+
if (authorizationToken) {
|
|
2999
|
+
headers["Authorization"] = `Bearer ${authorizationToken}`;
|
|
3000
|
+
}
|
|
2781
3001
|
return headers;
|
|
2782
3002
|
}
|
|
3003
|
+
/**
|
|
3004
|
+
* Parse documents from a SyftAI-Space query response.
|
|
3005
|
+
*
|
|
3006
|
+
* Mirrors the aggregator's `DataSourceClient._parse_syftai_response`: the
|
|
3007
|
+
* canonical shape nests documents under `references.documents` and names the
|
|
3008
|
+
* score `similarity_score`. A legacy top-level `documents` list (with
|
|
3009
|
+
* `score`) is still honoured for backward compatibility.
|
|
3010
|
+
*/
|
|
3011
|
+
parseDocuments(data) {
|
|
3012
|
+
const references = data["references"];
|
|
3013
|
+
let rawDocs;
|
|
3014
|
+
let scoreKey = "score";
|
|
3015
|
+
if (references && typeof references === "object") {
|
|
3016
|
+
rawDocs = references["documents"];
|
|
3017
|
+
scoreKey = "similarity_score";
|
|
3018
|
+
} else {
|
|
3019
|
+
rawDocs = data["documents"];
|
|
3020
|
+
}
|
|
3021
|
+
const documents = [];
|
|
3022
|
+
if (Array.isArray(rawDocs)) {
|
|
3023
|
+
for (const doc of rawDocs) {
|
|
3024
|
+
documents.push({
|
|
3025
|
+
content: String(doc["content"] ?? ""),
|
|
3026
|
+
score: Number(doc[scoreKey] ?? doc["score"] ?? 0),
|
|
3027
|
+
metadata: doc["metadata"] ?? {}
|
|
3028
|
+
});
|
|
3029
|
+
}
|
|
3030
|
+
}
|
|
3031
|
+
return documents;
|
|
3032
|
+
}
|
|
3033
|
+
/**
|
|
3034
|
+
* Parse the raw `policy_metadata` block from a syft-space response.
|
|
3035
|
+
*
|
|
3036
|
+
* The direct path (Boundary A) carries a top-level `policy_metadata` object
|
|
3037
|
+
* shaped `{ outcome, entries: [...] }`. Entries reuse the {@link BillingEntry}
|
|
3038
|
+
* shape (with `source` absent), so this delegates entry parsing to
|
|
3039
|
+
* {@link ChatResource.parseBillingEntry}. The wire keys are snake_case.
|
|
3040
|
+
*/
|
|
3041
|
+
parsePolicyMetadata(data) {
|
|
3042
|
+
const pm = data["policy_metadata"];
|
|
3043
|
+
if (!pm || typeof pm !== "object") {
|
|
3044
|
+
return void 0;
|
|
3045
|
+
}
|
|
3046
|
+
const meta = pm;
|
|
3047
|
+
const entriesRaw = Array.isArray(meta["entries"]) ? meta["entries"] : [];
|
|
3048
|
+
return {
|
|
3049
|
+
outcome: String(meta["outcome"] ?? ""),
|
|
3050
|
+
entries: entriesRaw.map(
|
|
3051
|
+
(e) => ChatResource.parseBillingEntry(e)
|
|
3052
|
+
)
|
|
3053
|
+
};
|
|
3054
|
+
}
|
|
2783
3055
|
/**
|
|
2784
3056
|
* Query a data source endpoint directly.
|
|
2785
3057
|
*
|
|
3058
|
+
* Authentication mirrors the aggregator: SyftAI-Space endpoints expect a
|
|
3059
|
+
* satellite bearer token whose audience is the endpoint owner's username. If
|
|
3060
|
+
* `authorizationToken` is not supplied, one is minted automatically when an
|
|
3061
|
+
* owner is known (`ownerUsername` option or `endpoint.ownerUsername`).
|
|
3062
|
+
*
|
|
2786
3063
|
* @param options - Query options
|
|
2787
|
-
* @returns
|
|
3064
|
+
* @returns DataSourceQueryResult — the retrieved documents plus the raw
|
|
3065
|
+
* `policyMetadata` block from the syft-space response (price, recipient,
|
|
3066
|
+
* transaction, status).
|
|
2788
3067
|
* @throws {RetrievalError} If the query fails
|
|
2789
3068
|
*/
|
|
2790
3069
|
async queryDataSource(options) {
|
|
2791
|
-
const {
|
|
3070
|
+
const {
|
|
3071
|
+
endpoint,
|
|
3072
|
+
query,
|
|
3073
|
+
userEmail,
|
|
3074
|
+
topK = 5,
|
|
3075
|
+
similarityThreshold = 0.5,
|
|
3076
|
+
authorizationToken,
|
|
3077
|
+
ownerUsername,
|
|
3078
|
+
pay = false
|
|
3079
|
+
} = options;
|
|
2792
3080
|
const url = `${endpoint.url.replace(/\/$/, "")}/api/v1/endpoints/${endpoint.slug}/query`;
|
|
2793
3081
|
const requestBody = {
|
|
2794
3082
|
user_email: userEmail,
|
|
@@ -2797,19 +3085,44 @@ var SyftAIResource = class {
|
|
|
2797
3085
|
limit: topK,
|
|
2798
3086
|
similarity_threshold: similarityThreshold
|
|
2799
3087
|
};
|
|
2800
|
-
let
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
3088
|
+
let token = authorizationToken;
|
|
3089
|
+
if (!token) {
|
|
3090
|
+
const audience = ownerUsername ?? endpoint.ownerUsername;
|
|
3091
|
+
if (audience) {
|
|
3092
|
+
token = await this.mintSatelliteToken(audience);
|
|
3093
|
+
}
|
|
3094
|
+
}
|
|
3095
|
+
const headers = this.buildHeaders(endpoint.tenantName, token);
|
|
3096
|
+
const postQuery = async (extraHeaders) => {
|
|
3097
|
+
try {
|
|
3098
|
+
return await fetch(url, {
|
|
3099
|
+
method: "POST",
|
|
3100
|
+
headers: { ...headers, ...extraHeaders },
|
|
3101
|
+
body: JSON.stringify(requestBody)
|
|
3102
|
+
});
|
|
3103
|
+
} catch (error) {
|
|
3104
|
+
throw new RetrievalError(
|
|
3105
|
+
`Failed to connect to data source '${endpoint.slug}': ${error instanceof Error ? error.message : String(error)}`,
|
|
3106
|
+
endpoint.slug,
|
|
3107
|
+
error
|
|
3108
|
+
);
|
|
3109
|
+
}
|
|
3110
|
+
};
|
|
3111
|
+
let response = await postQuery();
|
|
3112
|
+
if (response.status === 402 && pay) {
|
|
3113
|
+
let xPayment;
|
|
3114
|
+
try {
|
|
3115
|
+
xPayment = await this.payMpp(response.headers.get("www-authenticate") ?? "", endpoint.slug);
|
|
3116
|
+
} catch (error) {
|
|
3117
|
+
throw new RetrievalError(
|
|
3118
|
+
`Payment failed for data source '${endpoint.slug}': ${error instanceof Error ? error.message : String(error)}`,
|
|
3119
|
+
endpoint.slug,
|
|
3120
|
+
error
|
|
3121
|
+
);
|
|
3122
|
+
}
|
|
3123
|
+
if (xPayment) {
|
|
3124
|
+
response = await postQuery({ "X-Payment": xPayment });
|
|
3125
|
+
}
|
|
2813
3126
|
}
|
|
2814
3127
|
if (!response.ok) {
|
|
2815
3128
|
let message = `HTTP ${response.status}`;
|
|
@@ -2821,18 +3134,10 @@ var SyftAIResource = class {
|
|
|
2821
3134
|
throw new RetrievalError(`Data source query failed: ${message}`, endpoint.slug);
|
|
2822
3135
|
}
|
|
2823
3136
|
const data = await response.json();
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
documents.push({
|
|
2829
|
-
content: String(doc["content"] ?? ""),
|
|
2830
|
-
score: Number(doc["score"] ?? 0),
|
|
2831
|
-
metadata: doc["metadata"] ?? {}
|
|
2832
|
-
});
|
|
2833
|
-
}
|
|
2834
|
-
}
|
|
2835
|
-
return documents;
|
|
3137
|
+
return {
|
|
3138
|
+
documents: this.parseDocuments(data),
|
|
3139
|
+
policyMetadata: this.parsePolicyMetadata(data)
|
|
3140
|
+
};
|
|
2836
3141
|
}
|
|
2837
3142
|
/**
|
|
2838
3143
|
* Query a model endpoint directly.
|
|
@@ -2969,8 +3274,10 @@ var SyftHubClient = class {
|
|
|
2969
3274
|
_myEndpoints;
|
|
2970
3275
|
_hub;
|
|
2971
3276
|
_accounting;
|
|
3277
|
+
_aggregators;
|
|
2972
3278
|
_agent;
|
|
2973
3279
|
_chat;
|
|
3280
|
+
_search;
|
|
2974
3281
|
_syftai;
|
|
2975
3282
|
_apiTokens;
|
|
2976
3283
|
/**
|
|
@@ -3089,43 +3396,23 @@ var SyftHubClient = class {
|
|
|
3089
3396
|
* const balance = await client.accounting.getBalance();
|
|
3090
3397
|
*/
|
|
3091
3398
|
get accounting() {
|
|
3092
|
-
if (this._accounting) {
|
|
3093
|
-
return this._accounting;
|
|
3094
|
-
}
|
|
3095
|
-
throw new AuthenticationError(
|
|
3096
|
-
"Accounting not initialized. Call `await client.initAccounting()` after login."
|
|
3097
|
-
);
|
|
3098
|
-
}
|
|
3099
|
-
/**
|
|
3100
|
-
* Initialize the accounting (wallet) resource.
|
|
3101
|
-
*
|
|
3102
|
-
* The wallet API uses the same SyftHub authentication as other resources.
|
|
3103
|
-
* This method simply verifies authentication and creates the resource.
|
|
3104
|
-
*
|
|
3105
|
-
* @returns The initialized AccountingResource
|
|
3106
|
-
* @throws {AuthenticationError} If not authenticated
|
|
3107
|
-
*
|
|
3108
|
-
* @example
|
|
3109
|
-
* // Login first, then initialize accounting
|
|
3110
|
-
* await client.auth.login('alice', 'password');
|
|
3111
|
-
* await client.initAccounting();
|
|
3112
|
-
*
|
|
3113
|
-
* // Now accounting is available
|
|
3114
|
-
* const wallet = await client.accounting.getWallet();
|
|
3115
|
-
* const balance = await client.accounting.getBalance();
|
|
3116
|
-
*/
|
|
3117
|
-
async initAccounting() {
|
|
3118
|
-
if (this._accounting) {
|
|
3119
|
-
return this._accounting;
|
|
3120
|
-
}
|
|
3121
3399
|
if (!this.isAuthenticated) {
|
|
3122
3400
|
throw new AuthenticationError(
|
|
3123
3401
|
"Must be logged in to use accounting. Call client.auth.login() first."
|
|
3124
3402
|
);
|
|
3125
3403
|
}
|
|
3126
|
-
|
|
3404
|
+
if (!this._accounting) {
|
|
3405
|
+
this._accounting = new AccountingResource(this.http);
|
|
3406
|
+
}
|
|
3127
3407
|
return this._accounting;
|
|
3128
3408
|
}
|
|
3409
|
+
/**
|
|
3410
|
+
* @deprecated Accounting is now initialized automatically on first access.
|
|
3411
|
+
* This method is kept for backward compatibility and is a no-op.
|
|
3412
|
+
*/
|
|
3413
|
+
async initAccounting() {
|
|
3414
|
+
return this.accounting;
|
|
3415
|
+
}
|
|
3129
3416
|
/**
|
|
3130
3417
|
* Chat resource for RAG-augmented conversations via the Aggregator.
|
|
3131
3418
|
*
|
|
@@ -3158,6 +3445,28 @@ var SyftHubClient = class {
|
|
|
3158
3445
|
}
|
|
3159
3446
|
return this._chat;
|
|
3160
3447
|
}
|
|
3448
|
+
/**
|
|
3449
|
+
* Retrieval-only search via the Aggregator (no model generation).
|
|
3450
|
+
*
|
|
3451
|
+
* Symmetric counterpart to {@link chat}: queries data sources for relevant
|
|
3452
|
+
* documents without invoking a model. Satellite-token auth and MPP payment
|
|
3453
|
+
* are handled by the aggregator exactly as for chat.
|
|
3454
|
+
*
|
|
3455
|
+
* @example
|
|
3456
|
+
* const result = await client.search.query({
|
|
3457
|
+
* prompt: 'Hello, world!',
|
|
3458
|
+
* dataSources: ['epfl-news/epfl-news'],
|
|
3459
|
+
* });
|
|
3460
|
+
* for (const doc of result.documents) {
|
|
3461
|
+
* console.log(doc.title, doc.content.slice(0, 80));
|
|
3462
|
+
* }
|
|
3463
|
+
*/
|
|
3464
|
+
get search() {
|
|
3465
|
+
if (!this._search) {
|
|
3466
|
+
this._search = new SearchResource(this.chat);
|
|
3467
|
+
}
|
|
3468
|
+
return this._search;
|
|
3469
|
+
}
|
|
3161
3470
|
/**
|
|
3162
3471
|
* SyftAI-Space resource for direct endpoint queries (low-level API).
|
|
3163
3472
|
*
|
|
@@ -3184,7 +3493,7 @@ var SyftHubClient = class {
|
|
|
3184
3493
|
*/
|
|
3185
3494
|
get syftai() {
|
|
3186
3495
|
if (!this._syftai) {
|
|
3187
|
-
this._syftai = new SyftAIResource();
|
|
3496
|
+
this._syftai = new SyftAIResource(this.http);
|
|
3188
3497
|
}
|
|
3189
3498
|
return this._syftai;
|
|
3190
3499
|
}
|
|
@@ -3208,6 +3517,12 @@ var SyftHubClient = class {
|
|
|
3208
3517
|
* // Revoke a token
|
|
3209
3518
|
* await client.apiTokens.revoke(tokenId);
|
|
3210
3519
|
*/
|
|
3520
|
+
get aggregators() {
|
|
3521
|
+
if (!this._aggregators) {
|
|
3522
|
+
this._aggregators = new AggregatorsResource(this.http);
|
|
3523
|
+
}
|
|
3524
|
+
return this._aggregators;
|
|
3525
|
+
}
|
|
3211
3526
|
get apiTokens() {
|
|
3212
3527
|
if (!this._apiTokens) {
|
|
3213
3528
|
this._apiTokens = new APITokensResource(this.http);
|
|
@@ -3290,6 +3605,6 @@ var SyftHubClient = class {
|
|
|
3290
3605
|
// src/index.ts
|
|
3291
3606
|
init_errors();
|
|
3292
3607
|
|
|
3293
|
-
export { APIError, APITokensResource, AccountingAccountExistsError, AccountingResource, AccountingServiceUnavailableError, AgentResource, AgentSessionClient, AgentSessionError, AggregatorError, AggregatorsResource, AuthenticationError, AuthorizationError, ChatResource, ConfigurationError, EndpointResolutionError, EndpointType, GenerationError, InvalidAccountingPasswordError, NetworkError, NotFoundError, PageIterator, RetrievalError, SyftAIResource, SyftHubClient, SyftHubError, UserAlreadyExistsError, UserRole, ValidationError, Visibility, createAccountingResource, getEndpointPublicPath };
|
|
3608
|
+
export { APIError, APITokensResource, AccountingAccountExistsError, AccountingResource, AccountingServiceUnavailableError, AgentResource, AgentSessionClient, AgentSessionError, AggregatorError, AggregatorsResource, AuthenticationError, AuthorizationError, ChatResource, ConfigurationError, EndpointResolutionError, EndpointType, GenerationError, InvalidAccountingPasswordError, NetworkError, NotFoundError, PageIterator, RetrievalError, SearchResource, SyftAIResource, SyftHubClient, SyftHubError, UserAlreadyExistsError, UserRole, ValidationError, Visibility, createAccountingResource, getEndpointPublicPath };
|
|
3294
3609
|
//# sourceMappingURL=index.js.map
|
|
3295
3610
|
//# sourceMappingURL=index.js.map
|