@layr-labs/benchmaxx-arena-mcp 0.1.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/README.md +155 -0
- package/dist/apiTypes.d.ts +379 -0
- package/dist/apiTypes.js +24 -0
- package/dist/apiTypes.js.map +1 -0
- package/dist/browser.d.ts +33 -0
- package/dist/browser.js +65 -0
- package/dist/browser.js.map +1 -0
- package/dist/client.d.ts +210 -0
- package/dist/client.js +407 -0
- package/dist/client.js.map +1 -0
- package/dist/config.d.ts +25 -0
- package/dist/config.js +47 -0
- package/dist/config.js.map +1 -0
- package/dist/credentialStore.d.ts +103 -0
- package/dist/credentialStore.js +168 -0
- package/dist/credentialStore.js.map +1 -0
- package/dist/device.d.ts +87 -0
- package/dist/device.js +92 -0
- package/dist/device.js.map +1 -0
- package/dist/errors.d.ts +50 -0
- package/dist/errors.js +167 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +49 -0
- package/dist/index.js.map +1 -0
- package/dist/loopback.d.ts +29 -0
- package/dist/loopback.js +120 -0
- package/dist/loopback.js.map +1 -0
- package/dist/pkce.d.ts +24 -0
- package/dist/pkce.js +27 -0
- package/dist/pkce.js.map +1 -0
- package/dist/tools.d.ts +28 -0
- package/dist/tools.js +350 -0
- package/dist/tools.js.map +1 -0
- package/package.json +44 -0
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed HTTP client for the benchmaxx-arena API.
|
|
3
|
+
*
|
|
4
|
+
* The client wraps `fetch` and takes `fetch`, the credential store, the loopback
|
|
5
|
+
* listener, the browser opener, and the idempotency-key generator as injected
|
|
6
|
+
* dependencies, so the login flow, the error mapping, and the paid submit path
|
|
7
|
+
* are unit-testable with no network, no browser, and no randomness. Every
|
|
8
|
+
* endpoint here is unary. It sends and reads camelCase JSON, URL-encodes every path
|
|
9
|
+
* segment, and attaches the bearer key only for the endpoints that need it. On
|
|
10
|
+
* a non-2xx response it throws `ApiError` carrying the server `rpcStatus.message`;
|
|
11
|
+
* on a fetch rejection it throws `NetworkError`. Neither the client nor a thrown
|
|
12
|
+
* error ever includes the bearer token, the PKCE verifier, or a login code.
|
|
13
|
+
*/
|
|
14
|
+
import type { CancelRunResponse, CatalogResponse, CompetitionInsightsResponse, CreateSubmissionResponse, GetAccountingStatusResponse, GetBenchmarkResponse, GetRunLogResponse, GetRunResponse, GetRunTimelineResponse, LeaderboardResponse, ListApiKeysResponse, ListBenchmarksResponse, ListMySubmissionsResponse, ListRunsResponse, SubmissionConfigResponse, SubmissionResponse } from './apiTypes.js';
|
|
15
|
+
import { type StoredCredential } from './credentialStore.js';
|
|
16
|
+
import { type LoopbackListener } from './loopback.js';
|
|
17
|
+
/** The `fetch` shape the client depends on. */
|
|
18
|
+
export type FetchLike = (input: string, init?: {
|
|
19
|
+
method?: string;
|
|
20
|
+
headers?: Record<string, string>;
|
|
21
|
+
body?: string;
|
|
22
|
+
signal?: AbortSignal;
|
|
23
|
+
}) => Promise<FetchResponse>;
|
|
24
|
+
/** The subset of the Response the client reads. */
|
|
25
|
+
export interface FetchResponse {
|
|
26
|
+
ok: boolean;
|
|
27
|
+
status: number;
|
|
28
|
+
text(): Promise<string>;
|
|
29
|
+
}
|
|
30
|
+
/** A minimal credential-store contract, so tests can inject a fake. */
|
|
31
|
+
export interface CredentialStoreLike {
|
|
32
|
+
get(origin: string): Promise<StoredCredential | undefined>;
|
|
33
|
+
set(origin: string, credential: StoredCredential): Promise<void>;
|
|
34
|
+
delete(origin: string): Promise<boolean>;
|
|
35
|
+
}
|
|
36
|
+
/** Operator-facing sink for login instructions. Defaults to stderr. */
|
|
37
|
+
export type OperatorLog = (line: string) => void;
|
|
38
|
+
/** Progress sink for a long-running tool, so an MCP host sees liveness. */
|
|
39
|
+
export type ProgressReport = (progress: {
|
|
40
|
+
message: string;
|
|
41
|
+
}) => void | Promise<void>;
|
|
42
|
+
/** Binds the single-shot loopback listener that receives the code. */
|
|
43
|
+
export type StartListener = () => Promise<LoopbackListener>;
|
|
44
|
+
/** Opens a URL in the user's browser. False means no browser could be opened. */
|
|
45
|
+
export type OpenBrowser = (url: string) => Promise<boolean>;
|
|
46
|
+
/** A completed login: the key is stored. */
|
|
47
|
+
export interface LoginCompleted {
|
|
48
|
+
kind: 'completed';
|
|
49
|
+
username: string;
|
|
50
|
+
keyPrefix: string;
|
|
51
|
+
expiresAt: string;
|
|
52
|
+
}
|
|
53
|
+
/** No browser could be opened. The human must finish through `finishLogin`. */
|
|
54
|
+
export interface LoginManualRequired {
|
|
55
|
+
kind: 'manual';
|
|
56
|
+
authorizeUrl: string;
|
|
57
|
+
}
|
|
58
|
+
export type LoginOutcome = LoginCompleted | LoginManualRequired;
|
|
59
|
+
export interface ClientDeps {
|
|
60
|
+
origin: string;
|
|
61
|
+
fetch: FetchLike;
|
|
62
|
+
store: CredentialStoreLike;
|
|
63
|
+
/** Where the login instructions print. Defaults to stderr. */
|
|
64
|
+
operatorLog?: OperatorLog;
|
|
65
|
+
/** Binds the loopback listener. Defaults to `startLoopbackListener`. */
|
|
66
|
+
startListener?: StartListener;
|
|
67
|
+
/** Opens the authorize page. Defaults to `openInBrowser`. */
|
|
68
|
+
openBrowser?: OpenBrowser;
|
|
69
|
+
/** Generates an idempotency key per paid submission. Defaults to randomUUID. */
|
|
70
|
+
newIdempotencyKey?: () => string;
|
|
71
|
+
}
|
|
72
|
+
export declare class ArenaClient {
|
|
73
|
+
private readonly origin;
|
|
74
|
+
private readonly fetch;
|
|
75
|
+
private readonly store;
|
|
76
|
+
private readonly operatorLog;
|
|
77
|
+
private readonly startListener;
|
|
78
|
+
private readonly openBrowser;
|
|
79
|
+
private readonly newIdempotencyKey;
|
|
80
|
+
/**
|
|
81
|
+
* The verifier for a manual login awaiting `finishLogin`.
|
|
82
|
+
*
|
|
83
|
+
* In memory only, deliberately: it is the secret half of the PKCE pair, so it
|
|
84
|
+
* never touches disk. A restart of this process therefore voids a pending
|
|
85
|
+
* manual login, and the human runs `login` again.
|
|
86
|
+
*/
|
|
87
|
+
private pending;
|
|
88
|
+
constructor(deps: ClientDeps);
|
|
89
|
+
private request;
|
|
90
|
+
private serverMessage;
|
|
91
|
+
private requireCredential;
|
|
92
|
+
/** Whether a credential is stored for this origin. */
|
|
93
|
+
currentCredential(): Promise<StoredCredential | undefined>;
|
|
94
|
+
/** Delete the stored credential. Returns true when one was removed. */
|
|
95
|
+
logout(): Promise<boolean>;
|
|
96
|
+
/**
|
|
97
|
+
* Log in through the browser: bind a loopback listener, open the arena's
|
|
98
|
+
* authorize page, wait for the one-time code it redirects back, and redeem it
|
|
99
|
+
* for an API key with the PKCE verifier this process never sent anywhere else.
|
|
100
|
+
*
|
|
101
|
+
* The authorize URL is NOT reported when the browser opened. It carries the
|
|
102
|
+
* challenge and the state, and an MCP host transcript is routinely logged,
|
|
103
|
+
* shared, or pasted; anyone holding the challenge can mint a code against
|
|
104
|
+
* THEIR arena account bound to it, hand it to this listener, and the verifier
|
|
105
|
+
* still matches — an authorization-code injection PKCE cannot stop once the
|
|
106
|
+
* challenge leaks. The URL is emitted only on the manual path, where the human
|
|
107
|
+
* cannot proceed without it, and the username guard below backs that up
|
|
108
|
+
* independently.
|
|
109
|
+
*
|
|
110
|
+
* Approval is human-paced and routinely outlives an MCP host's default
|
|
111
|
+
* 60-second tool timeout, so progress is reported before the wait: it shows
|
|
112
|
+
* liveness and resets the host's timeout. The abort signal is honored at the
|
|
113
|
+
* wait AND rechecked immediately before the credential write, so a cancelled
|
|
114
|
+
* login cannot leave a key on disk after the caller gave up.
|
|
115
|
+
*/
|
|
116
|
+
login(options?: {
|
|
117
|
+
signal?: AbortSignal;
|
|
118
|
+
reportProgress?: ProgressReport;
|
|
119
|
+
}): Promise<LoginOutcome>;
|
|
120
|
+
/**
|
|
121
|
+
* Finish a login that fell back to the manual path, with the code the browser
|
|
122
|
+
* displayed.
|
|
123
|
+
*
|
|
124
|
+
* The pending verifier lives in memory only, so a restart of this process
|
|
125
|
+
* voids a pending manual login and the human runs `login` again.
|
|
126
|
+
*/
|
|
127
|
+
finishLogin(code: string): Promise<LoginCompleted>;
|
|
128
|
+
/**
|
|
129
|
+
* Exchange a one-time code and the verifier for an API key, then store it.
|
|
130
|
+
*
|
|
131
|
+
* Neither the code, the verifier, nor the token appears in any message or
|
|
132
|
+
* error raised here.
|
|
133
|
+
*/
|
|
134
|
+
private redeem;
|
|
135
|
+
/** List the caller's API keys (bearer). */
|
|
136
|
+
listApiKeys(): Promise<ListApiKeysResponse>;
|
|
137
|
+
getCatalog(): Promise<CatalogResponse>;
|
|
138
|
+
getLeaderboard(params: {
|
|
139
|
+
benchmark?: string;
|
|
140
|
+
variant?: string;
|
|
141
|
+
class?: string;
|
|
142
|
+
orderBy?: string;
|
|
143
|
+
asc?: boolean;
|
|
144
|
+
limit?: number;
|
|
145
|
+
offset?: number;
|
|
146
|
+
username?: string;
|
|
147
|
+
model?: string;
|
|
148
|
+
harness?: string;
|
|
149
|
+
harnessVersion?: string;
|
|
150
|
+
}): Promise<LeaderboardResponse>;
|
|
151
|
+
getInsights(params?: {
|
|
152
|
+
benchmark?: string;
|
|
153
|
+
variant?: string;
|
|
154
|
+
class?: string;
|
|
155
|
+
model?: string;
|
|
156
|
+
}): Promise<CompetitionInsightsResponse>;
|
|
157
|
+
getAccountingStatus(): Promise<GetAccountingStatusResponse>;
|
|
158
|
+
listBenchmarks(): Promise<ListBenchmarksResponse>;
|
|
159
|
+
getBenchmark(id: string): Promise<GetBenchmarkResponse>;
|
|
160
|
+
getSubmission(id: string): Promise<SubmissionResponse>;
|
|
161
|
+
getSubmissionConfig(id: string): Promise<SubmissionConfigResponse>;
|
|
162
|
+
/**
|
|
163
|
+
* Create a prompt_only submission. This is the one tool call that spends
|
|
164
|
+
* money, and MCP hosts retry a tool call whose response they never saw, so it
|
|
165
|
+
* always carries an `idempotencyKey`: without one a retried submit bills a
|
|
166
|
+
* second run. The caller may supply the key to keep retry identity stable
|
|
167
|
+
* across its own reattempts; otherwise a fresh UUID is generated per call.
|
|
168
|
+
*/
|
|
169
|
+
submitPrompt(params: {
|
|
170
|
+
benchmarkVariantId: string;
|
|
171
|
+
model: string;
|
|
172
|
+
systemPrompt: string;
|
|
173
|
+
idempotencyKey?: string;
|
|
174
|
+
}): Promise<CreateSubmissionResponse>;
|
|
175
|
+
listMySubmissions(): Promise<ListMySubmissionsResponse>;
|
|
176
|
+
listRuns(params?: {
|
|
177
|
+
submissionId?: string;
|
|
178
|
+
pageSize?: number;
|
|
179
|
+
pageToken?: string;
|
|
180
|
+
}): Promise<ListRunsResponse>;
|
|
181
|
+
getRun(id: string): Promise<GetRunResponse>;
|
|
182
|
+
/**
|
|
183
|
+
* Read persisted run events after a sequence number.
|
|
184
|
+
*
|
|
185
|
+
* This calls the UNARY `GET /v1/runs/{id}/timeline`. The server-streaming
|
|
186
|
+
* GetRunEvents RPC is still Unimplemented (501) and pinned that way by a test
|
|
187
|
+
* — the in-process grpc-gateway cannot serve a stream — so the timeline is the
|
|
188
|
+
* sanctioned reader for the same persisted events. Being unary, it needs no
|
|
189
|
+
* abort timeout, event cap, or byte cap: the server bounds the page and
|
|
190
|
+
* returns `nextSeq` as the resume cursor.
|
|
191
|
+
*/
|
|
192
|
+
getRunTimeline(id: string, options?: {
|
|
193
|
+
sinceSeq?: string;
|
|
194
|
+
signal?: AbortSignal;
|
|
195
|
+
}): Promise<GetRunTimelineResponse>;
|
|
196
|
+
/** Read run stdout/stderr chunks after a sequence number. */
|
|
197
|
+
getRunLog(id: string, options?: {
|
|
198
|
+
sinceSeq?: string;
|
|
199
|
+
signal?: AbortSignal;
|
|
200
|
+
}): Promise<GetRunLogResponse>;
|
|
201
|
+
/**
|
|
202
|
+
* Request cancellation of a run. Asynchronous: the response reports that the
|
|
203
|
+
* request was recorded, not that the run has stopped. Work already billed
|
|
204
|
+
* stays billed.
|
|
205
|
+
*/
|
|
206
|
+
cancelRun(runId: string, params?: {
|
|
207
|
+
reason?: string;
|
|
208
|
+
requestId?: string;
|
|
209
|
+
}): Promise<CancelRunResponse>;
|
|
210
|
+
}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,407 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed HTTP client for the benchmaxx-arena API.
|
|
3
|
+
*
|
|
4
|
+
* The client wraps `fetch` and takes `fetch`, the credential store, the loopback
|
|
5
|
+
* listener, the browser opener, and the idempotency-key generator as injected
|
|
6
|
+
* dependencies, so the login flow, the error mapping, and the paid submit path
|
|
7
|
+
* are unit-testable with no network, no browser, and no randomness. Every
|
|
8
|
+
* endpoint here is unary. It sends and reads camelCase JSON, URL-encodes every path
|
|
9
|
+
* segment, and attaches the bearer key only for the endpoints that need it. On
|
|
10
|
+
* a non-2xx response it throws `ApiError` carrying the server `rpcStatus.message`;
|
|
11
|
+
* on a fetch rejection it throws `NetworkError`. Neither the client nor a thrown
|
|
12
|
+
* error ever includes the bearer token, the PKCE verifier, or a login code.
|
|
13
|
+
*/
|
|
14
|
+
import { randomUUID } from 'node:crypto';
|
|
15
|
+
import { openInBrowser } from './browser.js';
|
|
16
|
+
import {} from './credentialStore.js';
|
|
17
|
+
import { ApiError, CliRedeemFailed, LoginCancelled, NetworkError } from './errors.js';
|
|
18
|
+
import { startLoopbackListener } from './loopback.js';
|
|
19
|
+
import { createPkcePair, createStateNonce } from './pkce.js';
|
|
20
|
+
/** The 64 lowercase hex characters a mintable authorization code always is. */
|
|
21
|
+
const CODE_PATTERN = /^[0-9a-f]{64}$/;
|
|
22
|
+
function encodePath(segment) {
|
|
23
|
+
return encodeURIComponent(segment);
|
|
24
|
+
}
|
|
25
|
+
function throwIfAborted(signal) {
|
|
26
|
+
if (signal?.aborted) {
|
|
27
|
+
throw new LoginCancelled();
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
export class ArenaClient {
|
|
31
|
+
origin;
|
|
32
|
+
fetch;
|
|
33
|
+
store;
|
|
34
|
+
operatorLog;
|
|
35
|
+
startListener;
|
|
36
|
+
openBrowser;
|
|
37
|
+
newIdempotencyKey;
|
|
38
|
+
/**
|
|
39
|
+
* The verifier for a manual login awaiting `finishLogin`.
|
|
40
|
+
*
|
|
41
|
+
* In memory only, deliberately: it is the secret half of the PKCE pair, so it
|
|
42
|
+
* never touches disk. A restart of this process therefore voids a pending
|
|
43
|
+
* manual login, and the human runs `login` again.
|
|
44
|
+
*/
|
|
45
|
+
pending;
|
|
46
|
+
constructor(deps) {
|
|
47
|
+
this.origin = deps.origin;
|
|
48
|
+
this.fetch = deps.fetch;
|
|
49
|
+
this.store = deps.store;
|
|
50
|
+
this.operatorLog = deps.operatorLog ?? ((line) => process.stderr.write(`${line}\n`));
|
|
51
|
+
this.startListener = deps.startListener ?? startLoopbackListener;
|
|
52
|
+
this.openBrowser = deps.openBrowser ?? ((url) => openInBrowser(url));
|
|
53
|
+
this.newIdempotencyKey = deps.newIdempotencyKey ?? (() => randomUUID());
|
|
54
|
+
}
|
|
55
|
+
// --- Core request helpers -------------------------------------------------
|
|
56
|
+
async request(path, options = {}) {
|
|
57
|
+
const headers = { Accept: 'application/json' };
|
|
58
|
+
if (options.body !== undefined) {
|
|
59
|
+
headers['Content-Type'] = 'application/json';
|
|
60
|
+
}
|
|
61
|
+
if (options.bearer) {
|
|
62
|
+
const credential = await this.requireCredential();
|
|
63
|
+
headers['Authorization'] = `Bearer ${credential.token}`;
|
|
64
|
+
}
|
|
65
|
+
let res;
|
|
66
|
+
try {
|
|
67
|
+
res = await this.fetch(`${this.origin}${path}`, {
|
|
68
|
+
method: options.method ?? 'GET',
|
|
69
|
+
headers,
|
|
70
|
+
body: options.body === undefined ? undefined : JSON.stringify(options.body),
|
|
71
|
+
signal: options.signal,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
// Never include the caught error: it can carry the request, and the
|
|
76
|
+
// request carries the bearer header.
|
|
77
|
+
throw new NetworkError('fetch failed');
|
|
78
|
+
}
|
|
79
|
+
const text = await res.text();
|
|
80
|
+
if (!res.ok) {
|
|
81
|
+
throw new ApiError(res.status, this.serverMessage(text, res.status));
|
|
82
|
+
}
|
|
83
|
+
if (!text) {
|
|
84
|
+
return undefined;
|
|
85
|
+
}
|
|
86
|
+
return JSON.parse(text);
|
|
87
|
+
}
|
|
88
|
+
serverMessage(body, status) {
|
|
89
|
+
if (body) {
|
|
90
|
+
try {
|
|
91
|
+
const parsed = JSON.parse(body);
|
|
92
|
+
if (typeof parsed.message === 'string' && parsed.message) {
|
|
93
|
+
return parsed.message;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
// Fall through to the status-only message.
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return `request failed with status ${status}`;
|
|
101
|
+
}
|
|
102
|
+
async requireCredential() {
|
|
103
|
+
const credential = await this.store.get(this.origin);
|
|
104
|
+
if (!credential) {
|
|
105
|
+
throw new ApiError(401, 'not authenticated');
|
|
106
|
+
}
|
|
107
|
+
return credential;
|
|
108
|
+
}
|
|
109
|
+
// --- Auth -----------------------------------------------------------------
|
|
110
|
+
/** Whether a credential is stored for this origin. */
|
|
111
|
+
async currentCredential() {
|
|
112
|
+
return this.store.get(this.origin);
|
|
113
|
+
}
|
|
114
|
+
/** Delete the stored credential. Returns true when one was removed. */
|
|
115
|
+
async logout() {
|
|
116
|
+
return this.store.delete(this.origin);
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Log in through the browser: bind a loopback listener, open the arena's
|
|
120
|
+
* authorize page, wait for the one-time code it redirects back, and redeem it
|
|
121
|
+
* for an API key with the PKCE verifier this process never sent anywhere else.
|
|
122
|
+
*
|
|
123
|
+
* The authorize URL is NOT reported when the browser opened. It carries the
|
|
124
|
+
* challenge and the state, and an MCP host transcript is routinely logged,
|
|
125
|
+
* shared, or pasted; anyone holding the challenge can mint a code against
|
|
126
|
+
* THEIR arena account bound to it, hand it to this listener, and the verifier
|
|
127
|
+
* still matches — an authorization-code injection PKCE cannot stop once the
|
|
128
|
+
* challenge leaks. The URL is emitted only on the manual path, where the human
|
|
129
|
+
* cannot proceed without it, and the username guard below backs that up
|
|
130
|
+
* independently.
|
|
131
|
+
*
|
|
132
|
+
* Approval is human-paced and routinely outlives an MCP host's default
|
|
133
|
+
* 60-second tool timeout, so progress is reported before the wait: it shows
|
|
134
|
+
* liveness and resets the host's timeout. The abort signal is honored at the
|
|
135
|
+
* wait AND rechecked immediately before the credential write, so a cancelled
|
|
136
|
+
* login cannot leave a key on disk after the caller gave up.
|
|
137
|
+
*/
|
|
138
|
+
async login(options = {}) {
|
|
139
|
+
const { signal, reportProgress } = options;
|
|
140
|
+
throwIfAborted(signal);
|
|
141
|
+
const { verifier, challenge } = createPkcePair();
|
|
142
|
+
const state = createStateNonce();
|
|
143
|
+
const listener = await this.startListener();
|
|
144
|
+
let code;
|
|
145
|
+
try {
|
|
146
|
+
// The origin serves both the SPA and the API, so the authorize page is a
|
|
147
|
+
// path on it and needs no separate configuration.
|
|
148
|
+
const authorizeUrl = new URL('/cli/authorize', this.origin);
|
|
149
|
+
authorizeUrl.searchParams.set('callback', listener.callbackUrl);
|
|
150
|
+
authorizeUrl.searchParams.set('challenge', challenge);
|
|
151
|
+
authorizeUrl.searchParams.set('state', state);
|
|
152
|
+
if (!(await this.openBrowser(authorizeUrl.toString()))) {
|
|
153
|
+
// No browser: the human has to carry the URL and the code by hand, so
|
|
154
|
+
// the verifier stays pending for `finishLogin`. The listener can never
|
|
155
|
+
// receive a callback in this mode, so it closes in the `finally`.
|
|
156
|
+
const manualUrl = new URL(authorizeUrl);
|
|
157
|
+
manualUrl.searchParams.set('manual', '1');
|
|
158
|
+
const manual = manualUrl.toString();
|
|
159
|
+
this.pending = { verifier };
|
|
160
|
+
this.operatorLog('benchmaxx-arena login (no browser could be opened)');
|
|
161
|
+
this.operatorLog(` 1. Open ${manual}`);
|
|
162
|
+
this.operatorLog(' 2. Approve, then pass the code it shows to finish_login.');
|
|
163
|
+
await reportProgress?.({
|
|
164
|
+
message: `No browser could be opened. Open ${manual}, approve, then pass the code it shows to finish_login.`,
|
|
165
|
+
});
|
|
166
|
+
return { kind: 'manual', authorizeUrl: manual };
|
|
167
|
+
}
|
|
168
|
+
// Carries no URL, no challenge, and no state -- see the note above.
|
|
169
|
+
await reportProgress?.({
|
|
170
|
+
message: 'Waiting for you to approve the login in your browser...',
|
|
171
|
+
});
|
|
172
|
+
this.operatorLog('benchmaxx-arena login: waiting for you to approve it in your browser...');
|
|
173
|
+
code = await listener.waitForCode(state, { signal });
|
|
174
|
+
}
|
|
175
|
+
finally {
|
|
176
|
+
await listener.close();
|
|
177
|
+
}
|
|
178
|
+
// The code is unredeemed at this point, so bailing here spends nothing.
|
|
179
|
+
throwIfAborted(signal);
|
|
180
|
+
return this.redeem(code, verifier, signal);
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Finish a login that fell back to the manual path, with the code the browser
|
|
184
|
+
* displayed.
|
|
185
|
+
*
|
|
186
|
+
* The pending verifier lives in memory only, so a restart of this process
|
|
187
|
+
* voids a pending manual login and the human runs `login` again.
|
|
188
|
+
*/
|
|
189
|
+
async finishLogin(code) {
|
|
190
|
+
const pending = this.pending;
|
|
191
|
+
if (!pending) {
|
|
192
|
+
throw new Error('no login is pending — run the login tool first.');
|
|
193
|
+
}
|
|
194
|
+
const trimmed = code.trim();
|
|
195
|
+
// Fail a mistyped paste here rather than spending a round trip on it. The
|
|
196
|
+
// message quotes no part of the code.
|
|
197
|
+
if (!CODE_PATTERN.test(trimmed)) {
|
|
198
|
+
throw new Error('that does not look like a login code — it is 64 hexadecimal characters. Copy it from the authorize page exactly.');
|
|
199
|
+
}
|
|
200
|
+
const outcome = await this.redeem(trimmed, pending.verifier);
|
|
201
|
+
// Cleared only on success, so a rejected paste can be retried against the
|
|
202
|
+
// same pending flow.
|
|
203
|
+
this.pending = undefined;
|
|
204
|
+
return outcome;
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Exchange a one-time code and the verifier for an API key, then store it.
|
|
208
|
+
*
|
|
209
|
+
* Neither the code, the verifier, nor the token appears in any message or
|
|
210
|
+
* error raised here.
|
|
211
|
+
*/
|
|
212
|
+
async redeem(code, verifier, signal) {
|
|
213
|
+
let response;
|
|
214
|
+
try {
|
|
215
|
+
response = await this.request('/v1/auth/cli/redeem', {
|
|
216
|
+
method: 'POST',
|
|
217
|
+
body: { code, verifier },
|
|
218
|
+
signal,
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
catch (error) {
|
|
222
|
+
// The endpoint answers Unauthenticated for an unknown, used, or expired
|
|
223
|
+
// code and for a wrong verifier alike. No stored key is involved, so this
|
|
224
|
+
// must not reach the generic 401 "key revoked" mapping.
|
|
225
|
+
if (error instanceof ApiError && error.status === 401) {
|
|
226
|
+
throw new CliRedeemFailed();
|
|
227
|
+
}
|
|
228
|
+
throw error;
|
|
229
|
+
}
|
|
230
|
+
if (!response.token || !response.username) {
|
|
231
|
+
throw new Error('the arena accepted the login but returned no key — run the login tool again.');
|
|
232
|
+
}
|
|
233
|
+
const username = response.username;
|
|
234
|
+
// The account-confusion guard. PKCE binds the code to the verifier, but the
|
|
235
|
+
// challenge is not secret, so a code minted against SOMEONE ELSE'S account
|
|
236
|
+
// can satisfy this flow's verifier and silently move the user into their
|
|
237
|
+
// account. This check does not depend on the challenge staying secret.
|
|
238
|
+
const existing = await this.store.get(this.origin);
|
|
239
|
+
if (existing && existing.username && existing.username !== username) {
|
|
240
|
+
throw new Error(`that login is for ${username}, but a key for ${existing.username} is already stored for this arena. Run the logout tool first if you meant to switch accounts.`);
|
|
241
|
+
}
|
|
242
|
+
// The redemption succeeded, but the caller may have cancelled while it was
|
|
243
|
+
// in flight. Writing the key now would persist a credential for a login the
|
|
244
|
+
// caller abandoned.
|
|
245
|
+
throwIfAborted(signal);
|
|
246
|
+
await this.store.set(this.origin, {
|
|
247
|
+
token: response.token,
|
|
248
|
+
keyId: response.id ?? '',
|
|
249
|
+
keyPrefix: response.prefix ?? '',
|
|
250
|
+
username,
|
|
251
|
+
});
|
|
252
|
+
// Always report the identity, so an unexpected account is visible rather
|
|
253
|
+
// than silent.
|
|
254
|
+
return {
|
|
255
|
+
kind: 'completed',
|
|
256
|
+
username,
|
|
257
|
+
keyPrefix: response.prefix ?? '',
|
|
258
|
+
expiresAt: response.expiresAt ?? '',
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
/** List the caller's API keys (bearer). */
|
|
262
|
+
async listApiKeys() {
|
|
263
|
+
return this.request('/v1/auth/keys', { bearer: true });
|
|
264
|
+
}
|
|
265
|
+
// --- Public reads ---------------------------------------------------------
|
|
266
|
+
async getCatalog() {
|
|
267
|
+
return this.request('/v1/catalog');
|
|
268
|
+
}
|
|
269
|
+
async getLeaderboard(params) {
|
|
270
|
+
const query = new URLSearchParams();
|
|
271
|
+
if (params.benchmark)
|
|
272
|
+
query.set('benchmark', params.benchmark);
|
|
273
|
+
if (params.variant)
|
|
274
|
+
query.set('variant', params.variant);
|
|
275
|
+
if (params.class)
|
|
276
|
+
query.set('class', params.class);
|
|
277
|
+
if (params.orderBy)
|
|
278
|
+
query.set('orderBy', params.orderBy);
|
|
279
|
+
if (params.asc !== undefined)
|
|
280
|
+
query.set('asc', String(params.asc));
|
|
281
|
+
if (params.limit !== undefined)
|
|
282
|
+
query.set('limit', String(params.limit));
|
|
283
|
+
if (params.offset !== undefined)
|
|
284
|
+
query.set('offset', String(params.offset));
|
|
285
|
+
if (params.username)
|
|
286
|
+
query.set('username', params.username);
|
|
287
|
+
if (params.model)
|
|
288
|
+
query.set('model', params.model);
|
|
289
|
+
if (params.harness)
|
|
290
|
+
query.set('harness', params.harness);
|
|
291
|
+
if (params.harnessVersion)
|
|
292
|
+
query.set('harnessVersion', params.harnessVersion);
|
|
293
|
+
const qs = query.toString();
|
|
294
|
+
return this.request(`/v1/leaderboard${qs ? `?${qs}` : ''}`);
|
|
295
|
+
}
|
|
296
|
+
async getInsights(params = {}) {
|
|
297
|
+
const query = new URLSearchParams();
|
|
298
|
+
if (params.benchmark)
|
|
299
|
+
query.set('benchmark', params.benchmark);
|
|
300
|
+
if (params.variant)
|
|
301
|
+
query.set('variant', params.variant);
|
|
302
|
+
if (params.class)
|
|
303
|
+
query.set('class', params.class);
|
|
304
|
+
if (params.model)
|
|
305
|
+
query.set('model', params.model);
|
|
306
|
+
const qs = query.toString();
|
|
307
|
+
return this.request(`/v1/insights${qs ? `?${qs}` : ''}`);
|
|
308
|
+
}
|
|
309
|
+
async getAccountingStatus() {
|
|
310
|
+
return this.request('/v1/accounting/status');
|
|
311
|
+
}
|
|
312
|
+
async listBenchmarks() {
|
|
313
|
+
return this.request('/v1/benchmarks');
|
|
314
|
+
}
|
|
315
|
+
async getBenchmark(id) {
|
|
316
|
+
return this.request(`/v1/benchmarks/${encodePath(id)}`);
|
|
317
|
+
}
|
|
318
|
+
async getSubmission(id) {
|
|
319
|
+
return this.request(`/v1/submissions/${encodePath(id)}`);
|
|
320
|
+
}
|
|
321
|
+
async getSubmissionConfig(id) {
|
|
322
|
+
return this.request(`/v1/submissions/${encodePath(id)}/config`);
|
|
323
|
+
}
|
|
324
|
+
// --- Bearer reads & writes ------------------------------------------------
|
|
325
|
+
/**
|
|
326
|
+
* Create a prompt_only submission. This is the one tool call that spends
|
|
327
|
+
* money, and MCP hosts retry a tool call whose response they never saw, so it
|
|
328
|
+
* always carries an `idempotencyKey`: without one a retried submit bills a
|
|
329
|
+
* second run. The caller may supply the key to keep retry identity stable
|
|
330
|
+
* across its own reattempts; otherwise a fresh UUID is generated per call.
|
|
331
|
+
*/
|
|
332
|
+
async submitPrompt(params) {
|
|
333
|
+
return this.request('/v1/submissions', {
|
|
334
|
+
method: 'POST',
|
|
335
|
+
bearer: true,
|
|
336
|
+
body: {
|
|
337
|
+
prompt: {
|
|
338
|
+
benchmarkVariantId: params.benchmarkVariantId,
|
|
339
|
+
model: params.model,
|
|
340
|
+
systemPrompt: params.systemPrompt,
|
|
341
|
+
},
|
|
342
|
+
idempotencyKey: params.idempotencyKey ?? this.newIdempotencyKey(),
|
|
343
|
+
},
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
async listMySubmissions() {
|
|
347
|
+
return this.request('/v1/me/submissions', { bearer: true });
|
|
348
|
+
}
|
|
349
|
+
async listRuns(params = {}) {
|
|
350
|
+
const query = new URLSearchParams();
|
|
351
|
+
if (params.submissionId)
|
|
352
|
+
query.set('submissionId', params.submissionId);
|
|
353
|
+
if (params.pageSize !== undefined)
|
|
354
|
+
query.set('pageSize', String(params.pageSize));
|
|
355
|
+
if (params.pageToken)
|
|
356
|
+
query.set('pageToken', params.pageToken);
|
|
357
|
+
const qs = query.toString();
|
|
358
|
+
return this.request(`/v1/runs${qs ? `?${qs}` : ''}`, { bearer: true });
|
|
359
|
+
}
|
|
360
|
+
async getRun(id) {
|
|
361
|
+
return this.request(`/v1/runs/${encodePath(id)}`, { bearer: true });
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* Read persisted run events after a sequence number.
|
|
365
|
+
*
|
|
366
|
+
* This calls the UNARY `GET /v1/runs/{id}/timeline`. The server-streaming
|
|
367
|
+
* GetRunEvents RPC is still Unimplemented (501) and pinned that way by a test
|
|
368
|
+
* — the in-process grpc-gateway cannot serve a stream — so the timeline is the
|
|
369
|
+
* sanctioned reader for the same persisted events. Being unary, it needs no
|
|
370
|
+
* abort timeout, event cap, or byte cap: the server bounds the page and
|
|
371
|
+
* returns `nextSeq` as the resume cursor.
|
|
372
|
+
*/
|
|
373
|
+
async getRunTimeline(id, options = {}) {
|
|
374
|
+
const query = new URLSearchParams();
|
|
375
|
+
if (options.sinceSeq !== undefined)
|
|
376
|
+
query.set('sinceSeq', options.sinceSeq);
|
|
377
|
+
const qs = query.toString();
|
|
378
|
+
return this.request(`/v1/runs/${encodePath(id)}/timeline${qs ? `?${qs}` : ''}`, { bearer: true, signal: options.signal });
|
|
379
|
+
}
|
|
380
|
+
/** Read run stdout/stderr chunks after a sequence number. */
|
|
381
|
+
async getRunLog(id, options = {}) {
|
|
382
|
+
const query = new URLSearchParams();
|
|
383
|
+
if (options.sinceSeq !== undefined)
|
|
384
|
+
query.set('sinceSeq', options.sinceSeq);
|
|
385
|
+
const qs = query.toString();
|
|
386
|
+
return this.request(`/v1/runs/${encodePath(id)}/log${qs ? `?${qs}` : ''}`, {
|
|
387
|
+
bearer: true,
|
|
388
|
+
signal: options.signal,
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
/**
|
|
392
|
+
* Request cancellation of a run. Asynchronous: the response reports that the
|
|
393
|
+
* request was recorded, not that the run has stopped. Work already billed
|
|
394
|
+
* stays billed.
|
|
395
|
+
*/
|
|
396
|
+
async cancelRun(runId, params = {}) {
|
|
397
|
+
return this.request(`/v1/runs/${encodePath(runId)}/cancel`, {
|
|
398
|
+
method: 'POST',
|
|
399
|
+
bearer: true,
|
|
400
|
+
body: {
|
|
401
|
+
reason: params.reason ?? '',
|
|
402
|
+
requestId: params.requestId ?? this.newIdempotencyKey(),
|
|
403
|
+
},
|
|
404
|
+
});
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration for the benchmaxx-arena MCP server.
|
|
3
|
+
*
|
|
4
|
+
* The only knob is the base-URL origin. `BENCHMAXX_ARENA_URL` overrides it;
|
|
5
|
+
* only the origin (scheme, host, port) is used, any path is dropped. The
|
|
6
|
+
* default is production. A bearer key travels on this transport, so the scheme
|
|
7
|
+
* must be `https`, with the single exception of `http://localhost` and
|
|
8
|
+
* `http://127.0.0.1` for local development.
|
|
9
|
+
*/
|
|
10
|
+
export declare const PRODUCTION_ORIGIN = "https://harnessarena.xyz";
|
|
11
|
+
export declare const ARENA_URL_ENV = "BENCHMAXX_ARENA_URL";
|
|
12
|
+
/**
|
|
13
|
+
* Normalize a raw URL string to its origin. Throws on a malformed URL or a
|
|
14
|
+
* scheme that would send a credential in cleartext to a non-loopback host.
|
|
15
|
+
*/
|
|
16
|
+
export declare function normalizeOrigin(raw: string): string;
|
|
17
|
+
export interface Config {
|
|
18
|
+
/** Base-URL origin. All API paths are relative to this. */
|
|
19
|
+
origin: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Resolve the configuration from an environment map. Defaults to production
|
|
23
|
+
* when the override is absent or empty.
|
|
24
|
+
*/
|
|
25
|
+
export declare function loadConfig(env?: NodeJS.ProcessEnv): Config;
|