@antseed/cli 0.1.168 → 0.1.170
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 +4 -0
- package/dist/buyer-identities/loader.d.ts +28 -0
- package/dist/buyer-identities/loader.d.ts.map +1 -0
- package/dist/buyer-identities/loader.js +58 -0
- package/dist/buyer-identities/loader.js.map +1 -0
- package/dist/buyer-identities/store.d.ts +41 -0
- package/dist/buyer-identities/store.d.ts.map +1 -0
- package/dist/buyer-identities/store.js +171 -0
- package/dist/buyer-identities/store.js.map +1 -0
- package/dist/buyer-identities/store.test.d.ts +2 -0
- package/dist/buyer-identities/store.test.d.ts.map +1 -0
- package/dist/buyer-identities/store.test.js +122 -0
- package/dist/buyer-identities/store.test.js.map +1 -0
- package/dist/cli/commands/buyer/channel-withdraw.d.ts.map +1 -1
- package/dist/cli/commands/buyer/channel-withdraw.js +9 -4
- package/dist/cli/commands/buyer/channel-withdraw.js.map +1 -1
- package/dist/cli/commands/buyer/channel-withdraw.test.js +69 -0
- package/dist/cli/commands/buyer/channel-withdraw.test.js.map +1 -1
- package/dist/cli/commands/buyer/channels.js +1 -1
- package/dist/cli/commands/buyer/channels.js.map +1 -1
- package/dist/cli/commands/buyer/identity.d.ts +3 -0
- package/dist/cli/commands/buyer/identity.d.ts.map +1 -0
- package/dist/cli/commands/buyer/identity.js +115 -0
- package/dist/cli/commands/buyer/identity.js.map +1 -0
- package/dist/cli/commands/buyer/index.d.ts.map +1 -1
- package/dist/cli/commands/buyer/index.js +2 -0
- package/dist/cli/commands/buyer/index.js.map +1 -1
- package/dist/cli/commands/buyer/start.d.ts.map +1 -1
- package/dist/cli/commands/buyer/start.js +30 -2
- package/dist/cli/commands/buyer/start.js.map +1 -1
- package/dist/cli/commands/gateway/index.d.ts +3 -0
- package/dist/cli/commands/gateway/index.d.ts.map +1 -0
- package/dist/cli/commands/gateway/index.js +43 -0
- package/dist/cli/commands/gateway/index.js.map +1 -0
- package/dist/cli/commands/gateway/key.d.ts +3 -0
- package/dist/cli/commands/gateway/key.d.ts.map +1 -0
- package/dist/cli/commands/gateway/key.js +240 -0
- package/dist/cli/commands/gateway/key.js.map +1 -0
- package/dist/cli/commands/gateway/shared.d.ts +29 -0
- package/dist/cli/commands/gateway/shared.d.ts.map +1 -0
- package/dist/cli/commands/gateway/shared.js +90 -0
- package/dist/cli/commands/gateway/shared.js.map +1 -0
- package/dist/cli/commands/seller/setup.d.ts.map +1 -1
- package/dist/cli/commands/seller/setup.js +4 -0
- package/dist/cli/commands/seller/setup.js.map +1 -1
- package/dist/cli/commands/seller/start.d.ts.map +1 -1
- package/dist/cli/commands/seller/start.js +8 -2
- package/dist/cli/commands/seller/start.js.map +1 -1
- package/dist/cli/commands/seller/start.test.js +20 -0
- package/dist/cli/commands/seller/start.test.js.map +1 -1
- package/dist/cli/commands/tunnel/start.d.ts.map +1 -1
- package/dist/cli/commands/tunnel/start.js +25 -14
- package/dist/cli/commands/tunnel/start.js.map +1 -1
- package/dist/cli/index.js +2 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/gateway/accounting.d.ts +45 -0
- package/dist/gateway/accounting.d.ts.map +1 -0
- package/dist/gateway/accounting.js +94 -0
- package/dist/gateway/accounting.js.map +1 -0
- package/dist/gateway/cdp-auth.d.ts +12 -0
- package/dist/gateway/cdp-auth.d.ts.map +1 -0
- package/dist/gateway/cdp-auth.js +53 -0
- package/dist/gateway/cdp-auth.js.map +1 -0
- package/dist/gateway/cdp-auth.test.d.ts +2 -0
- package/dist/gateway/cdp-auth.test.d.ts.map +1 -0
- package/dist/gateway/cdp-auth.test.js +96 -0
- package/dist/gateway/cdp-auth.test.js.map +1 -0
- package/dist/gateway/gateway.test.d.ts.map +1 -0
- package/dist/gateway/gateway.test.js +709 -0
- package/dist/gateway/gateway.test.js.map +1 -0
- package/dist/gateway/keys.d.ts +13 -0
- package/dist/gateway/keys.d.ts.map +1 -0
- package/dist/gateway/keys.js +24 -0
- package/dist/gateway/keys.js.map +1 -0
- package/dist/gateway/limits.d.ts +25 -0
- package/dist/gateway/limits.d.ts.map +1 -0
- package/dist/gateway/limits.js +45 -0
- package/dist/gateway/limits.js.map +1 -0
- package/dist/gateway/money.d.ts +9 -0
- package/dist/gateway/money.d.ts.map +1 -0
- package/dist/gateway/money.js +37 -0
- package/dist/gateway/money.js.map +1 -0
- package/dist/gateway/runtime.d.ts +38 -0
- package/dist/gateway/runtime.d.ts.map +1 -0
- package/dist/gateway/runtime.js +144 -0
- package/dist/gateway/runtime.js.map +1 -0
- package/dist/gateway/server.d.ts +49 -0
- package/dist/gateway/server.d.ts.map +1 -0
- package/dist/gateway/server.js +460 -0
- package/dist/gateway/server.js.map +1 -0
- package/dist/gateway/spend-feed.d.ts +32 -0
- package/dist/gateway/spend-feed.d.ts.map +1 -0
- package/dist/gateway/spend-feed.js +86 -0
- package/dist/gateway/spend-feed.js.map +1 -0
- package/dist/gateway/store.d.ts +114 -0
- package/dist/gateway/store.d.ts.map +1 -0
- package/dist/gateway/store.js +253 -0
- package/dist/gateway/store.js.map +1 -0
- package/dist/gateway/x402.d.ts +95 -0
- package/dist/gateway/x402.d.ts.map +1 -0
- package/dist/gateway/x402.js +120 -0
- package/dist/gateway/x402.js.map +1 -0
- package/dist/plugins/registry.d.ts.map +1 -1
- package/dist/plugins/registry.js +2 -0
- package/dist/plugins/registry.js.map +1 -1
- package/dist/proxy/buyer-proxy.d.ts +15 -0
- package/dist/proxy/buyer-proxy.d.ts.map +1 -1
- package/dist/proxy/buyer-proxy.js +157 -15
- package/dist/proxy/buyer-proxy.js.map +1 -1
- package/dist/proxy/buyer-proxy.test.js +157 -1
- package/dist/proxy/buyer-proxy.test.js.map +1 -1
- package/dist/proxy/native-video-proxy.d.ts +34 -0
- package/dist/proxy/native-video-proxy.d.ts.map +1 -0
- package/dist/proxy/native-video-proxy.js +41 -0
- package/dist/proxy/native-video-proxy.js.map +1 -0
- package/dist/proxy/native-video-proxy.test.d.ts +2 -0
- package/dist/proxy/native-video-proxy.test.d.ts.map +1 -0
- package/dist/proxy/native-video-proxy.test.js +23 -0
- package/dist/proxy/native-video-proxy.test.js.map +1 -0
- package/dist/proxy/network-models.d.ts +3 -2
- package/dist/proxy/network-models.d.ts.map +1 -1
- package/dist/proxy/network-models.js +3 -0
- package/dist/proxy/network-models.js.map +1 -1
- package/dist/proxy/network-models.test.js +13 -0
- package/dist/proxy/network-models.test.js.map +1 -1
- package/dist/proxy/request-utils.d.ts +3 -0
- package/dist/proxy/request-utils.d.ts.map +1 -1
- package/dist/proxy/request-utils.js +6 -1
- package/dist/proxy/request-utils.js.map +1 -1
- package/dist/proxy/resource-routes.d.ts +20 -0
- package/dist/proxy/resource-routes.d.ts.map +1 -0
- package/dist/proxy/resource-routes.js +48 -0
- package/dist/proxy/resource-routes.js.map +1 -0
- package/dist/proxy/resource-routes.test.d.ts +2 -0
- package/dist/proxy/resource-routes.test.d.ts.map +1 -0
- package/dist/proxy/resource-routes.test.js +21 -0
- package/dist/proxy/resource-routes.test.js.map +1 -0
- package/dist/proxy/routing.d.ts.map +1 -1
- package/dist/proxy/routing.js +5 -2
- package/dist/proxy/routing.js.map +1 -1
- package/dist/proxy/service-api-adapter.d.ts +1 -1
- package/dist/proxy/service-api-adapter.d.ts.map +1 -1
- package/dist/proxy/service-api-adapter.js +1 -1
- package/dist/proxy/service-api-adapter.js.map +1 -1
- package/dist/proxy/spend-attribution.d.ts +63 -0
- package/dist/proxy/spend-attribution.d.ts.map +1 -0
- package/dist/proxy/spend-attribution.js +97 -0
- package/dist/proxy/spend-attribution.js.map +1 -0
- package/dist/proxy/video-download.d.ts +7 -0
- package/dist/proxy/video-download.d.ts.map +1 -0
- package/dist/proxy/video-download.js +66 -0
- package/dist/proxy/video-download.js.map +1 -0
- package/dist/proxy/video-download.test.d.ts +2 -0
- package/dist/proxy/video-download.test.d.ts.map +1 -0
- package/dist/proxy/video-download.test.js +108 -0
- package/dist/proxy/video-download.test.js.map +1 -0
- package/package.json +9 -7
- package/dist/tunnel/gateway.d.ts +0 -16
- package/dist/tunnel/gateway.d.ts.map +0 -1
- package/dist/tunnel/gateway.js +0 -146
- package/dist/tunnel/gateway.js.map +0 -1
- package/dist/tunnel/gateway.test.d.ts.map +0 -1
- package/dist/tunnel/gateway.test.js +0 -89
- package/dist/tunnel/gateway.test.js.map +0 -1
- /package/dist/{tunnel → gateway}/gateway.test.d.ts +0 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type AntseedNode, type PeerInfo, type ModelRoutingPreferences, type SerializedHttpResponse, type SweepReceiptPayload } from '@antseed/node';
|
|
2
|
+
import { BuyerIdentityLoader } from '../buyer-identities/loader.js';
|
|
2
3
|
import type { DepositWatcher } from './deposit-watcher.js';
|
|
3
4
|
import { type VerifierPolicy, type SellerReach } from '../plugins/verifier.js';
|
|
4
5
|
export { selectCandidatePeersForRouting, type CandidatePeerRouteSelection } from './routing.js';
|
|
@@ -41,6 +42,8 @@ export interface BuyerProxyConfig {
|
|
|
41
42
|
now?: () => number;
|
|
42
43
|
/** Verifier-SDK policy: which verifier the buyer commits to + whether it is required. */
|
|
43
44
|
verifier?: VerifierPolicy;
|
|
45
|
+
/** Loads stored buyer identities on demand; defaults to one reading `dataDir`. */
|
|
46
|
+
buyerIdentities?: BuyerIdentityLoader;
|
|
44
47
|
}
|
|
45
48
|
/**
|
|
46
49
|
* Detect a "model not served" rejection: the seller's own pre-payment 400
|
|
@@ -111,12 +114,14 @@ export declare class BuyerProxy {
|
|
|
111
114
|
*/
|
|
112
115
|
private _lastModelActivityAt;
|
|
113
116
|
private readonly _verifier?;
|
|
117
|
+
private readonly _buyerIdentities;
|
|
114
118
|
private readonly _teeVerification;
|
|
115
119
|
private readonly _teeControl;
|
|
116
120
|
private _stateWatchDebounce;
|
|
117
121
|
private _configWatchDebounce;
|
|
118
122
|
private _routingPreferences;
|
|
119
123
|
private _stateWriteChain;
|
|
124
|
+
private readonly _resourceRoutes;
|
|
120
125
|
private _cachedPeers;
|
|
121
126
|
private _cacheLastUpdatedAtMs;
|
|
122
127
|
private _cacheMutationEpoch;
|
|
@@ -157,9 +162,18 @@ export declare class BuyerProxy {
|
|
|
157
162
|
* deltas (buyer- and seller-initiated auth both advance the cumulative).
|
|
158
163
|
*/
|
|
159
164
|
private readonly _requestConversations;
|
|
165
|
+
/** Signed spend for requests a local gateway tagged, polled over the control plane. */
|
|
166
|
+
private readonly _spendAttribution;
|
|
160
167
|
constructor(config: BuyerProxyConfig);
|
|
161
168
|
/** Roll a signed spend delta into the conversation that triggered it. */
|
|
162
169
|
private _attributeSpend;
|
|
170
|
+
/**
|
|
171
|
+
* Identity named by a request: null for the default, the name when it is
|
|
172
|
+
* (or can be) loaded, undefined when no stored identity has that name.
|
|
173
|
+
*/
|
|
174
|
+
private _resolveBuyerIdentity;
|
|
175
|
+
/** `?identity=` on control-plane reads; undefined when it names no stored identity. */
|
|
176
|
+
private _controlPlaneIdentity;
|
|
163
177
|
/**
|
|
164
178
|
* Remember which chat a request belongs to for the life of the request plus
|
|
165
179
|
* a grace window — the seller-initiated auth path can land just after the
|
|
@@ -184,6 +198,7 @@ export declare class BuyerProxy {
|
|
|
184
198
|
private _markModelActivity;
|
|
185
199
|
/** Serialised read-modify-write to buyer.state.json. Returns the queued write promise. */
|
|
186
200
|
private _mergeStateFile;
|
|
201
|
+
private _persistResourceRoutes;
|
|
187
202
|
private _writeStateFile;
|
|
188
203
|
private _startIncrementalDiscoverySweep;
|
|
189
204
|
private _startBackgroundRefresh;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"buyer-proxy.d.ts","sourceRoot":"","sources":["../../src/proxy/buyer-proxy.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"buyer-proxy.d.ts","sourceRoot":"","sources":["../../src/proxy/buyer-proxy.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,17 +1,23 @@
|
|
|
1
|
+
import { nativeVideoRoute } from '@antseed/api-adapter';
|
|
2
|
+
import { ResourceRoutes } from './resource-routes.js';
|
|
3
|
+
import { prepareVideoRequest, recordVideoAcceptance } from './native-video-proxy.js';
|
|
4
|
+
import { downloadVideo } from './video-download.js';
|
|
1
5
|
import { createServer } from 'node:http';
|
|
2
6
|
import { randomUUID } from 'node:crypto';
|
|
3
7
|
import { watchFile, unwatchFile } from 'node:fs';
|
|
4
8
|
import { readFile, writeFile, rename, mkdir, readdir, stat, unlink } from 'node:fs/promises';
|
|
5
9
|
import { join } from 'node:path';
|
|
6
|
-
import { ANTSEED_BUYER_FAULT_ERROR_CODE, ANTSEED_FAULT_ATTRIBUTION_HEADER, ANTSEED_ATTEST_PATH, adaptPeerFaultErrorResponse, computeTrustScore, decodeSweepRequest, faultAttributionOf, faultCodeOf, isModelRouteEligible, modelRouteTotalPrice, normalizedModelReputationScore, peerSupportsCooperativeClose, rankModelRoutes, sanitizePeerDisplayName, } from '@antseed/node';
|
|
10
|
+
import { ANTSEED_BUYER_FAULT_ERROR_CODE, ANTSEED_FAULT_ATTRIBUTION_HEADER, ANTSEED_ATTEST_PATH, adaptPeerFaultErrorResponse, computeTrustScore, decodeSweepRequest, faultAttributionOf, faultCodeOf, isModelRouteEligible, modelRouteTotalPrice, normalizedModelReputationScore, peerSupportsCooperativeClose, DEFAULT_BUYER_IDENTITY, rankModelRoutes, sanitizePeerDisplayName, } from '@antseed/node';
|
|
7
11
|
import { canonicalModelKey } from '@antseed/node/model-identity';
|
|
8
12
|
import { createStreamingAdapter, detectRequestServiceApiProtocol, transformRequest, transformResponse, } from './service-api-adapter.js';
|
|
9
|
-
import { DEBUG, log, extractRequestedService, summarizeRequestShape, summarizeErrorResponse, requestWantsStreaming, parsePeerPinnedService, rewritePeerPinnedServiceInBody, substituteRoutedModelAlias, overrideRoutedModelInBody, ROUTED_MODEL_ALIAS, SYSTEM_PROXY_SOURCE_HEADER, SYSTEM_ROUTED_MODEL_HEADER, normalizePeerId, } from './request-utils.js';
|
|
13
|
+
import { DEBUG, log, extractRequestedService, summarizeRequestShape, summarizeErrorResponse, requestWantsStreaming, parsePeerPinnedService, rewritePeerPinnedServiceInBody, substituteRoutedModelAlias, overrideRoutedModelInBody, ROUTED_MODEL_ALIAS, SYSTEM_PROXY_SOURCE_HEADER, SYSTEM_ROUTED_MODEL_HEADER, BUYER_IDENTITY_HEADER, normalizePeerId, } from './request-utils.js';
|
|
14
|
+
import { BuyerIdentityLoader } from '../buyer-identities/loader.js';
|
|
10
15
|
import { buildNetworkModels, effectiveModelReputationScore, parseModelTypeFilter, } from './network-models.js';
|
|
11
16
|
import { findMissingRequiredParameters, findUnannouncedRequestParameters, findAdvertisedServiceOffer, findAdvertisedServiceProtocols, getExplicitProviderOverride, getExplicitPeerIdOverride, parseRequiredParametersHeader, REQUIRED_PARAMETERS_HEADER, resolvePeerRoutePlan, selectCandidatePeersForRouting, } from './routing.js';
|
|
12
17
|
import { computeResponseTelemetry, attachAntseedTelemetryHeaders, attachStreamingAntseedHeaders, } from './telemetry.js';
|
|
13
18
|
import { DEFAULT_BUYER_PEER_REFRESH_INTERVAL_MS } from '../config/defaults.js';
|
|
14
19
|
import { extractConversationIdentity, extractFirstUserSnippet, isCompletionRequestPath, isTitleGenerationRequest, parseRequestBodyObject, } from './conversation-identity.js';
|
|
20
|
+
import { SPEND_ATTRIBUTION_HEADER, SpendAttributionFeed, parseSpendAttributionTag } from './spend-attribution.js';
|
|
15
21
|
import { ConversationStore } from './conversation-store.js';
|
|
16
22
|
import { recordPeerFailureEntry, clearPeerHealthEntry, isCoolingDown, parsePersistedPeerHealth, prunePeerHealth, serializePeerHealth, reasonEscalates, } from './peer-health.js';
|
|
17
23
|
import { PeerAttributionTracker, HEARTBEAT_MS } from './peer-attribution.js';
|
|
@@ -277,6 +283,14 @@ export function sanitizePeerBuyerFaultMarker(response) {
|
|
|
277
283
|
? { ...response, body: Buffer.from(JSON.stringify(parsed)) }
|
|
278
284
|
: response;
|
|
279
285
|
}
|
|
286
|
+
function buyerFaultStatusCode(faultCode) {
|
|
287
|
+
switch (faultCode) {
|
|
288
|
+
case 'invalid-request': return 400;
|
|
289
|
+
case 'buyer-budget-too-low': return 422;
|
|
290
|
+
case 'buyer-reserve-topup-timeout': return 504;
|
|
291
|
+
default: return 503;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
280
294
|
/**
|
|
281
295
|
* Inject the buyer-known peerId into a 402 payment_required JSON body.
|
|
282
296
|
* The seller doesn't include its own peerId (and shouldn't — self-reported
|
|
@@ -595,6 +609,10 @@ export async function mergeJsonStateFile(stateDir, stateFile, patch) {
|
|
|
595
609
|
throw err;
|
|
596
610
|
}
|
|
597
611
|
}
|
|
612
|
+
function sendUnknownBuyerIdentity(res) {
|
|
613
|
+
res.writeHead(404, { 'content-type': 'application/json' });
|
|
614
|
+
res.end(JSON.stringify({ ok: false, error: 'Unknown buyer identity' }));
|
|
615
|
+
}
|
|
598
616
|
export class BuyerProxy {
|
|
599
617
|
_server;
|
|
600
618
|
_node;
|
|
@@ -623,12 +641,14 @@ export class BuyerProxy {
|
|
|
623
641
|
*/
|
|
624
642
|
_lastModelActivityAt = 0;
|
|
625
643
|
_verifier;
|
|
644
|
+
_buyerIdentities;
|
|
626
645
|
_teeVerification;
|
|
627
646
|
_teeControl;
|
|
628
647
|
_stateWatchDebounce = null;
|
|
629
648
|
_configWatchDebounce = null;
|
|
630
649
|
_routingPreferences;
|
|
631
650
|
_stateWriteChain = Promise.resolve();
|
|
651
|
+
_resourceRoutes = new ResourceRoutes();
|
|
632
652
|
_cachedPeers = [];
|
|
633
653
|
_cacheLastUpdatedAtMs = 0;
|
|
634
654
|
_cacheMutationEpoch = 0;
|
|
@@ -669,9 +689,12 @@ export class BuyerProxy {
|
|
|
669
689
|
* deltas (buyer- and seller-initiated auth both advance the cumulative).
|
|
670
690
|
*/
|
|
671
691
|
_requestConversations = new Map();
|
|
692
|
+
/** Signed spend for requests a local gateway tagged, polled over the control plane. */
|
|
693
|
+
_spendAttribution = new SpendAttributionFeed();
|
|
672
694
|
constructor(config) {
|
|
673
695
|
this._node = config.node;
|
|
674
696
|
this._verifier = config.verifier;
|
|
697
|
+
this._buyerIdentities = config.buyerIdentities ?? new BuyerIdentityLoader(config.node, config.dataDir);
|
|
675
698
|
this._teeVerification = new TeeVerification(config.verifier);
|
|
676
699
|
this._teeControl = new TeeControl(this._teeVerification.sessionId);
|
|
677
700
|
this._port = config.port;
|
|
@@ -714,6 +737,7 @@ export class BuyerProxy {
|
|
|
714
737
|
if (typeof spendEventNode.on === 'function') {
|
|
715
738
|
spendEventNode.on('payment:spend', (event) => {
|
|
716
739
|
this._attributeSpend(event);
|
|
740
|
+
this._spendAttribution.record(event);
|
|
717
741
|
});
|
|
718
742
|
}
|
|
719
743
|
const eventNode = this._node;
|
|
@@ -741,6 +765,25 @@ export class BuyerProxy {
|
|
|
741
765
|
}, !entry.counted);
|
|
742
766
|
entry.counted = true;
|
|
743
767
|
}
|
|
768
|
+
/**
|
|
769
|
+
* Identity named by a request: null for the default, the name when it is
|
|
770
|
+
* (or can be) loaded, undefined when no stored identity has that name.
|
|
771
|
+
*/
|
|
772
|
+
async _resolveBuyerIdentity(header) {
|
|
773
|
+
const name = header?.trim().toLowerCase() ?? '';
|
|
774
|
+
if (!name || name === DEFAULT_BUYER_IDENTITY)
|
|
775
|
+
return null;
|
|
776
|
+
const loaded = await this._buyerIdentities.ensure(name).catch((err) => {
|
|
777
|
+
log(`Buyer identity "${name}" failed to load: ${err instanceof Error ? err.message : String(err)}`);
|
|
778
|
+
return false;
|
|
779
|
+
});
|
|
780
|
+
return loaded ? name : undefined;
|
|
781
|
+
}
|
|
782
|
+
/** `?identity=` on control-plane reads; undefined when it names no stored identity. */
|
|
783
|
+
async _controlPlaneIdentity(path) {
|
|
784
|
+
const param = new URL(path, 'http://localhost').searchParams.get('identity');
|
|
785
|
+
return this._resolveBuyerIdentity(param ?? undefined);
|
|
786
|
+
}
|
|
744
787
|
/**
|
|
745
788
|
* Remember which chat a request belongs to for the life of the request plus
|
|
746
789
|
* a grace window — the seller-initiated auth path can land just after the
|
|
@@ -778,6 +821,11 @@ export class BuyerProxy {
|
|
|
778
821
|
// startup route from the warm cache without blocking on DHT discovery.
|
|
779
822
|
// The background refresh still runs to pick up fresh peers and IP changes.
|
|
780
823
|
await this._hydratePeersFromStateFile();
|
|
824
|
+
try {
|
|
825
|
+
const state = JSON.parse(await readFile(this._stateFile, 'utf8'));
|
|
826
|
+
this._resourceRoutes.hydrate(state.resourceRoutes);
|
|
827
|
+
}
|
|
828
|
+
catch { }
|
|
781
829
|
// Adopt persisted session overrides (peer pin, default routed model) so
|
|
782
830
|
// they survive daemon restart. A --peer CLI flag beats the persisted pin
|
|
783
831
|
// at startup; runtime `connection set` writes still take over via the
|
|
@@ -868,7 +916,10 @@ export class BuyerProxy {
|
|
|
868
916
|
await this._writeStateFile('stopped');
|
|
869
917
|
await this._conversations.flush();
|
|
870
918
|
return new Promise((resolve) => {
|
|
871
|
-
this._server.close(() =>
|
|
919
|
+
this._server.close(() => {
|
|
920
|
+
this._spendAttribution.close();
|
|
921
|
+
resolve();
|
|
922
|
+
});
|
|
872
923
|
});
|
|
873
924
|
}
|
|
874
925
|
_watchStateFile() {
|
|
@@ -969,6 +1020,11 @@ export class BuyerProxy {
|
|
|
969
1020
|
}).catch(() => { });
|
|
970
1021
|
return this._stateWriteChain;
|
|
971
1022
|
}
|
|
1023
|
+
async _persistResourceRoutes() {
|
|
1024
|
+
const write = this._stateWriteChain.then(() => mergeJsonStateFile(this._stateDir, this._stateFile, { resourceRoutes: this._resourceRoutes.snapshot() }));
|
|
1025
|
+
this._stateWriteChain = write.catch(() => { });
|
|
1026
|
+
return write;
|
|
1027
|
+
}
|
|
972
1028
|
async _writeStateFile(state) {
|
|
973
1029
|
// When stopping, preserve whatever session overrides are already
|
|
974
1030
|
// in the file — the debounce may have been cancelled before
|
|
@@ -1682,11 +1738,20 @@ export class BuyerProxy {
|
|
|
1682
1738
|
}
|
|
1683
1739
|
return;
|
|
1684
1740
|
}
|
|
1741
|
+
if (path.startsWith('/_antseed/buyer-identities') && method === 'GET') {
|
|
1742
|
+
await this._buyerIdentities.loadAll();
|
|
1743
|
+
res.writeHead(200, { 'content-type': 'application/json' });
|
|
1744
|
+
res.end(JSON.stringify({ ok: true, identities: this._node.buyerIdentities() }));
|
|
1745
|
+
return;
|
|
1746
|
+
}
|
|
1685
1747
|
if (path.startsWith('/_antseed/channels') && method === 'GET') {
|
|
1686
1748
|
const all = /[?&]all=1/.test(path);
|
|
1749
|
+
const identity = await this._controlPlaneIdentity(path);
|
|
1750
|
+
if (identity === undefined)
|
|
1751
|
+
return sendUnknownBuyerIdentity(res);
|
|
1687
1752
|
const channels = all
|
|
1688
|
-
? this._node.getAllBuyerChannels()
|
|
1689
|
-
: this._node.getActiveBuyerChannels();
|
|
1753
|
+
? this._node.getAllBuyerChannels(identity ?? undefined)
|
|
1754
|
+
: this._node.getActiveBuyerChannels(identity ?? undefined);
|
|
1690
1755
|
const peers = await this._getPeers();
|
|
1691
1756
|
const peersById = new Map(peers.map((peer) => [peer.peerId, peer]));
|
|
1692
1757
|
const channelsWithCapabilities = channels.map((channel) => {
|
|
@@ -1701,16 +1766,30 @@ export class BuyerProxy {
|
|
|
1701
1766
|
res.end(JSON.stringify({ ok: true, channels: channelsWithCapabilities }));
|
|
1702
1767
|
return;
|
|
1703
1768
|
}
|
|
1769
|
+
// Unauthenticated like every /_antseed route: it relies on the buyer
|
|
1770
|
+
// listening on 127.0.0.1 only, since it exposes per-seller spend and tags.
|
|
1771
|
+
if (path.startsWith('/_antseed/attributed-spend') && method === 'GET') {
|
|
1772
|
+
const after = Number(new URL(path, 'http://localhost').searchParams.get('after') ?? '0');
|
|
1773
|
+
res.writeHead(200, { 'content-type': 'application/json' });
|
|
1774
|
+
res.end(JSON.stringify({ ok: true, ...this._spendAttribution.page(Number.isFinite(after) ? after : 0) }));
|
|
1775
|
+
return;
|
|
1776
|
+
}
|
|
1704
1777
|
if (path.startsWith('/_antseed/buyer-usage') && method === 'GET') {
|
|
1705
|
-
const
|
|
1778
|
+
const identity = await this._controlPlaneIdentity(path);
|
|
1779
|
+
if (identity === undefined)
|
|
1780
|
+
return sendUnknownBuyerIdentity(res);
|
|
1781
|
+
const totals = this._node.getBuyerUsageTotals(identity ?? undefined);
|
|
1706
1782
|
res.writeHead(200, { 'content-type': 'application/json' });
|
|
1707
1783
|
res.end(JSON.stringify({ ok: true, totals, lastActivityAt: this._lastModelActivityAt || null }));
|
|
1708
1784
|
return;
|
|
1709
1785
|
}
|
|
1710
|
-
const meteringMatch = path.match(/^\/_antseed\/metering\/(
|
|
1786
|
+
const meteringMatch = path.match(/^\/_antseed\/metering\/([^?]+)/);
|
|
1711
1787
|
if (meteringMatch && method === 'GET') {
|
|
1712
1788
|
const sellerPeerId = decodeURIComponent(meteringMatch[1]);
|
|
1713
|
-
const
|
|
1789
|
+
const identity = await this._controlPlaneIdentity(path);
|
|
1790
|
+
if (identity === undefined)
|
|
1791
|
+
return sendUnknownBuyerIdentity(res);
|
|
1792
|
+
const stats = this._node.getMeteringStatsByPeer(sellerPeerId, identity ?? undefined);
|
|
1714
1793
|
res.writeHead(200, { 'content-type': 'application/json' });
|
|
1715
1794
|
res.end(JSON.stringify(stats));
|
|
1716
1795
|
return;
|
|
@@ -1764,11 +1843,14 @@ export class BuyerProxy {
|
|
|
1764
1843
|
}
|
|
1765
1844
|
let peerId;
|
|
1766
1845
|
let includeAuth = true;
|
|
1846
|
+
let identityParam;
|
|
1767
1847
|
try {
|
|
1768
1848
|
const body = JSON.parse(Buffer.concat(chunks).toString());
|
|
1769
1849
|
peerId = String(body.peerId ?? '');
|
|
1770
1850
|
if (body.includeAuth === false)
|
|
1771
1851
|
includeAuth = false;
|
|
1852
|
+
if (typeof body.identity === 'string')
|
|
1853
|
+
identityParam = body.identity;
|
|
1772
1854
|
}
|
|
1773
1855
|
catch {
|
|
1774
1856
|
res.writeHead(400, { 'content-type': 'application/json' });
|
|
@@ -1781,7 +1863,10 @@ export class BuyerProxy {
|
|
|
1781
1863
|
return;
|
|
1782
1864
|
}
|
|
1783
1865
|
try {
|
|
1784
|
-
const
|
|
1866
|
+
const identity = await this._resolveBuyerIdentity(identityParam);
|
|
1867
|
+
if (identity === undefined)
|
|
1868
|
+
throw new Error('Unknown buyer identity');
|
|
1869
|
+
const result = await this._node.requestChannelClose(peerId, { includeAuth, ...(identity ? { buyerIdentity: identity } : {}) });
|
|
1785
1870
|
log(`Cooperative close of ${result.channelId.slice(0, 18)}... with ${peerId.slice(0, 12)}...: ` +
|
|
1786
1871
|
`${result.status}${result.code ? ` (${result.code})` : ''}`);
|
|
1787
1872
|
res.writeHead(200, { 'content-type': 'application/json' });
|
|
@@ -1911,7 +1996,7 @@ export class BuyerProxy {
|
|
|
1911
1996
|
res.writeHead(400, responseHeaders);
|
|
1912
1997
|
res.end(JSON.stringify({
|
|
1913
1998
|
error: {
|
|
1914
|
-
message: `Unknown model type "${url.searchParams.get('type') ?? ''}" — expected "text", "images", or "
|
|
1999
|
+
message: `Unknown model type "${url.searchParams.get('type') ?? ''}" — expected "text", "images", "decisions", or "videos".`,
|
|
1915
2000
|
type: 'invalid_request_error',
|
|
1916
2001
|
param: 'type',
|
|
1917
2002
|
},
|
|
@@ -1933,7 +2018,9 @@ export class BuyerProxy {
|
|
|
1933
2018
|
}
|
|
1934
2019
|
// Only proxy known API paths — reject everything else with 404
|
|
1935
2020
|
const normalizedPath = path.split('?')[0]?.trim().toLowerCase() ?? '/';
|
|
1936
|
-
const
|
|
2021
|
+
const nativeVideo = nativeVideoRoute({ method, path });
|
|
2022
|
+
const isKnownApiPath = nativeVideo !== null ||
|
|
2023
|
+
normalizedPath.startsWith('/v1/messages') ||
|
|
1937
2024
|
normalizedPath.startsWith('/v1/chat/completions') ||
|
|
1938
2025
|
normalizedPath.startsWith('/v1/responses') ||
|
|
1939
2026
|
normalizedPath.startsWith('/v1/images/generations') ||
|
|
@@ -1986,6 +2073,29 @@ export class BuyerProxy {
|
|
|
1986
2073
|
// it never reaches a seller.
|
|
1987
2074
|
const systemRoutedModel = headers[SYSTEM_ROUTED_MODEL_HEADER] === '1';
|
|
1988
2075
|
delete headers[SYSTEM_ROUTED_MODEL_HEADER];
|
|
2076
|
+
// Internal marker from the API-key gateway: report this request's signed
|
|
2077
|
+
// spend under the gateway's tag. Stripped so it never reaches a seller.
|
|
2078
|
+
const spendAttributionTag = parseSpendAttributionTag(headers[SPEND_ATTRIBUTION_HEADER]);
|
|
2079
|
+
delete headers[SPEND_ATTRIBUTION_HEADER];
|
|
2080
|
+
// The paying identity rides on the internal headers through routing, like
|
|
2081
|
+
// a peer pin, and is stripped when the request is built for the seller.
|
|
2082
|
+
const buyerIdentity = await this._resolveBuyerIdentity(headers[BUYER_IDENTITY_HEADER]);
|
|
2083
|
+
if (buyerIdentity === undefined) {
|
|
2084
|
+
res.writeHead(400, { 'content-type': 'application/json' });
|
|
2085
|
+
res.end(JSON.stringify({
|
|
2086
|
+
error: {
|
|
2087
|
+
type: 'invalid_request_error',
|
|
2088
|
+
code: 'unknown_buyer_identity',
|
|
2089
|
+
message: `${BUYER_IDENTITY_HEADER} names no stored buyer identity. Create one with \`antseed buyer identity create <name>\`.`,
|
|
2090
|
+
param: BUYER_IDENTITY_HEADER,
|
|
2091
|
+
},
|
|
2092
|
+
}));
|
|
2093
|
+
return;
|
|
2094
|
+
}
|
|
2095
|
+
if (buyerIdentity)
|
|
2096
|
+
headers[BUYER_IDENTITY_HEADER] = buyerIdentity;
|
|
2097
|
+
else
|
|
2098
|
+
delete headers[BUYER_IDENTITY_HEADER];
|
|
1989
2099
|
let serializedReq = {
|
|
1990
2100
|
requestId: randomUUID(),
|
|
1991
2101
|
method,
|
|
@@ -1993,6 +2103,8 @@ export class BuyerProxy {
|
|
|
1993
2103
|
headers,
|
|
1994
2104
|
body: new Uint8Array(body),
|
|
1995
2105
|
};
|
|
2106
|
+
if (spendAttributionTag)
|
|
2107
|
+
this._spendAttribution.track(serializedReq.requestId, spendAttributionTag);
|
|
1996
2108
|
const requiredParameters = parseRequiredParametersHeader(serializedReq.headers[REQUIRED_PARAMETERS_HEADER]);
|
|
1997
2109
|
if (requiredParameters === null) {
|
|
1998
2110
|
res.writeHead(400, { 'content-type': 'application/json' });
|
|
@@ -2006,6 +2118,16 @@ export class BuyerProxy {
|
|
|
2006
2118
|
}));
|
|
2007
2119
|
return;
|
|
2008
2120
|
}
|
|
2121
|
+
if (nativeVideo) {
|
|
2122
|
+
// Re-classify with the body: some APIs (Venice) carry the job ID in it.
|
|
2123
|
+
const prepared = prepareVideoRequest(nativeVideoRoute(serializedReq) ?? nativeVideo, serializedReq.headers, this._resourceRoutes);
|
|
2124
|
+
if ('error' in prepared) {
|
|
2125
|
+
res.writeHead(prepared.error.statusCode, { 'content-type': 'application/json' });
|
|
2126
|
+
res.end(JSON.stringify(prepared.error.body));
|
|
2127
|
+
return;
|
|
2128
|
+
}
|
|
2129
|
+
serializedReq = { ...serializedReq, headers: prepared.headers };
|
|
2130
|
+
}
|
|
2009
2131
|
// Snapshot the session overrides before any await so a concurrent
|
|
2010
2132
|
// _reloadSessionOverrides() cannot change routing mid-request.
|
|
2011
2133
|
const effectivePinnedPeer = this._pinnedPeer;
|
|
@@ -2325,6 +2447,13 @@ export class BuyerProxy {
|
|
|
2325
2447
|
}
|
|
2326
2448
|
return;
|
|
2327
2449
|
}
|
|
2450
|
+
// Never retry a video on another seller: a create may already have
|
|
2451
|
+
// started (and been charged), and follow-ups only exist on one seller.
|
|
2452
|
+
if (nativeVideo) {
|
|
2453
|
+
res.writeHead(result.statusCode, result.responseHeaders);
|
|
2454
|
+
res.end(result.responseBody);
|
|
2455
|
+
return;
|
|
2456
|
+
}
|
|
2328
2457
|
lastRetry = result;
|
|
2329
2458
|
if (result.responseHeaders[ANTSEED_FAULT_ATTRIBUTION_HEADER]?.toLowerCase() === 'buyer') {
|
|
2330
2459
|
res.writeHead(result.statusCode, result.responseHeaders);
|
|
@@ -2593,7 +2722,7 @@ export class BuyerProxy {
|
|
|
2593
2722
|
+ `did not announce for this service: ${unannounced.join(', ')} — the upstream may ignore or reject them`);
|
|
2594
2723
|
}
|
|
2595
2724
|
}
|
|
2596
|
-
const { 'x-antseed-pin-peer': _pinPeer, 'x-antseed-prefer-peer': _preferPeer, [REQUIRED_PARAMETERS_HEADER]: _requiredParameters, 'x-vpr-session-id': _vprSession,
|
|
2725
|
+
const { 'x-antseed-pin-peer': _pinPeer, 'x-antseed-prefer-peer': _preferPeer, [BUYER_IDENTITY_HEADER]: buyerIdentity, [REQUIRED_PARAMETERS_HEADER]: _requiredParameters, 'x-vpr-session-id': _vprSession,
|
|
2597
2726
|
// Legacy desktop builds (pre AntStation → VPR rename) still send this.
|
|
2598
2727
|
'x-antstation-session-id': _antstationSession, ...headersForPeer } = serializedReq.headers;
|
|
2599
2728
|
let requestForPeer = {
|
|
@@ -2661,7 +2790,13 @@ export class BuyerProxy {
|
|
|
2661
2790
|
log(`Routing to peer ${selectedPeer.peerId.slice(0, 12)}...`);
|
|
2662
2791
|
this._markModelActivity();
|
|
2663
2792
|
// Forward through P2P
|
|
2664
|
-
const
|
|
2793
|
+
const videoRoute = nativeVideoRoute(requestForPeer);
|
|
2794
|
+
// Video responses are JSON job objects or a streamed MP4, never SSE.
|
|
2795
|
+
const wantsStreaming = clientWantsStreaming && !videoRoute;
|
|
2796
|
+
if (videoRoute?.action === 'retrieve') {
|
|
2797
|
+
await downloadVideo(requestForPeer, res, (request, callbacks, signal) => this._node.sendRequestStream(selectedPeer, request, callbacks, { signal, pinned: true }), requestSignal);
|
|
2798
|
+
return { done: true };
|
|
2799
|
+
}
|
|
2665
2800
|
const peerResponseProtocol = selectedRoutePlan.selection?.targetProtocol ?? requestProtocol;
|
|
2666
2801
|
const adaptPeerResponse = (response) => adaptPeerFaultErrorResponse(response, peerResponseProtocol, { pinned });
|
|
2667
2802
|
const startTime = Date.now();
|
|
@@ -2701,7 +2836,7 @@ export class BuyerProxy {
|
|
|
2701
2836
|
}
|
|
2702
2837
|
}
|
|
2703
2838
|
},
|
|
2704
|
-
}, { signal: requestSignal, pinned });
|
|
2839
|
+
}, { signal: requestSignal, pinned, ...(buyerIdentity ? { buyerIdentity } : {}) });
|
|
2705
2840
|
let responseForClient = adaptBuyerFaultErrorResponse(response, requestProtocol);
|
|
2706
2841
|
responseForClient = adaptPeerResponse(responseForClient);
|
|
2707
2842
|
if (!streamed
|
|
@@ -2768,10 +2903,17 @@ export class BuyerProxy {
|
|
|
2768
2903
|
const upstreamResponse = await this._node.sendRequest(selectedPeer, requestForPeer, {
|
|
2769
2904
|
signal: requestSignal,
|
|
2770
2905
|
pinned,
|
|
2906
|
+
...(buyerIdentity ? { buyerIdentity } : {}),
|
|
2771
2907
|
});
|
|
2772
2908
|
if (upstreamResponse.statusCode >= 400 && !adaptResponse) {
|
|
2773
2909
|
log(`Upstream raw error detail: ${summarizeErrorResponse(upstreamResponse)}`);
|
|
2774
2910
|
}
|
|
2911
|
+
// Only the seller that accepted a video job knows its ID. Remember and
|
|
2912
|
+
// persist job ID -> seller so later retrieve requests (even
|
|
2913
|
+
// after a proxy restart) are pinned back to that seller.
|
|
2914
|
+
if (videoRoute && recordVideoAcceptance(videoRoute, upstreamResponse, { peerId: selectedPeer.peerId, provider: selectedRoutePlan.provider, service: requestedService }, this._resourceRoutes)) {
|
|
2915
|
+
await this._persistResourceRoutes().catch(error => console.error('[proxy] Accepted video route was not persisted:', error));
|
|
2916
|
+
}
|
|
2775
2917
|
let response = adaptBuyerFaultErrorResponse(upstreamResponse, requestProtocol);
|
|
2776
2918
|
response = adaptPeerResponse(response);
|
|
2777
2919
|
if (adaptResponse
|
|
@@ -2879,7 +3021,7 @@ export class BuyerProxy {
|
|
|
2879
3021
|
if (fault === 'buyer') {
|
|
2880
3022
|
const buyerResponse = adaptBuyerFaultErrorResponse({
|
|
2881
3023
|
requestId: requestForPeer.requestId,
|
|
2882
|
-
statusCode:
|
|
3024
|
+
statusCode: buyerFaultStatusCode(faultCode),
|
|
2883
3025
|
headers: {
|
|
2884
3026
|
'content-type': 'application/json',
|
|
2885
3027
|
[ANTSEED_FAULT_ATTRIBUTION_HEADER]: 'buyer',
|