agents-relay 2.0.188 → 2.0.189
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/adapters.js +42 -59
- package/dist/browser-worker-pool.js +167 -0
- package/dist/browser-worker-routing.js +10 -0
- package/dist/browser-worker-runtime.js +233 -0
- package/dist/chatgpt-platform-fallback.js +4 -4
- package/dist/cli-support.js +1 -1
- package/dist/cli-worker-task.js +2 -2
- package/dist/cli.js +5 -4
- package/dist/dashboard-html.js +2 -1
- package/dist/execution-recovery.js +2 -2
- package/dist/force-restate-validation.js +1 -1
- package/dist/managed-worker-input.js +1 -1
- package/dist/model-routing.js +2 -0
- package/dist/planner.js +3 -3
- package/dist/reconciler-review.js +7 -6
- package/dist/reconciler-runtime.js +13 -10
- package/dist/reconciler.js +28 -6
- package/dist/relayd.js +2 -1
- package/dist/store-task-definition.js +1 -1
- package/dist/task-inactivity-watchdog.js +1 -1
- package/dist/usage.js +2 -2
- package/dist/worker-rejection.js +3 -0
- package/dist/worker-routing.js +1 -1
- package/dist/workflow/definitions-v2.js +1 -0
- package/dist/z-adapter.js +83 -0
- package/dist/z-oauth.js +86 -0
- package/package.json +1 -1
- package/workflow/task-lifecycle.mmd +6 -1
package/dist/z-oauth.js
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { createHash, randomBytes } from 'node:crypto';
|
|
2
|
+
import { readFile } from 'node:fs/promises';
|
|
3
|
+
import { homedir } from 'node:os';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
/** A one-hour Neo OAuth credential for one Z worker. The operator secret stays on the Relay host. */
|
|
6
|
+
export async function issueZWorkerCredential(options = {}) {
|
|
7
|
+
const origin = (options.origin ?? process.env.AGENTS_RELAY_Z_NEO_ORIGIN ?? 'https://neoy.qili2.com').replace(/\/$/, '');
|
|
8
|
+
if (!/^https:\/\/[A-Za-z0-9.-]+(?::\d{1,5})?$/.test(origin))
|
|
9
|
+
throw new Error('Z OAuth origin must be HTTPS');
|
|
10
|
+
const operatorToken = options.operatorToken ?? process.env.AGENTS_RELAY_Z_NEO_OPERATOR_TOKEN ??
|
|
11
|
+
(await readFile(process.env.AGENTS_RELAY_Z_NEO_OPERATOR_TOKEN_FILE ?? join(homedir(), 'Library', 'Application Support', 'NeoY', 'core-token'), 'utf8').catch(() => '')).trim();
|
|
12
|
+
if (!operatorToken)
|
|
13
|
+
throw new Error('Set AGENTS_RELAY_Z_NEO_OPERATOR_TOKEN_FILE to a private Neo operator token file');
|
|
14
|
+
const fetcher = options.fetcher ?? fetch;
|
|
15
|
+
const redirectUri = 'http://127.0.0.1:8765/neo/oauth/callback';
|
|
16
|
+
const verifier = randomBytes(32).toString('base64url');
|
|
17
|
+
const challenge = createHash('sha256').update(verifier).digest('base64url');
|
|
18
|
+
const state = randomBytes(18).toString('hex');
|
|
19
|
+
const request = async (path, init) => fetcher(origin + path, { ...init, signal: AbortSignal.timeout(15_000), redirect: 'manual' });
|
|
20
|
+
const registration = await request('/register', {
|
|
21
|
+
method: 'POST', headers: { 'Content-Type': 'application/json' },
|
|
22
|
+
body: JSON.stringify({
|
|
23
|
+
client_name: 'Agents Relay Z worker',
|
|
24
|
+
redirect_uris: [redirectUri],
|
|
25
|
+
grant_types: ['authorization_code', 'refresh_token'],
|
|
26
|
+
response_types: ['code'],
|
|
27
|
+
token_endpoint_auth_method: 'none',
|
|
28
|
+
}),
|
|
29
|
+
});
|
|
30
|
+
if (registration.status !== 201)
|
|
31
|
+
throw new Error('Neo Z OAuth registration rejected: HTTP ' + registration.status);
|
|
32
|
+
const client = await registration.json();
|
|
33
|
+
if (!client.client_id)
|
|
34
|
+
throw new Error('Neo Z OAuth registration returned no client_id');
|
|
35
|
+
const qs = new URLSearchParams({
|
|
36
|
+
response_type: 'code', client_id: client.client_id, redirect_uri: redirectUri,
|
|
37
|
+
code_challenge: challenge, code_challenge_method: 'S256', scope: 'mcp',
|
|
38
|
+
resource: origin + '/mcp', state,
|
|
39
|
+
});
|
|
40
|
+
const page = await request('/authorize?' + qs, { method: 'GET' });
|
|
41
|
+
if (page.status !== 200)
|
|
42
|
+
throw new Error('Neo OAuth authorization page rejected: HTTP ' + page.status);
|
|
43
|
+
const html = await page.text();
|
|
44
|
+
const rid = html.match(/name="rid"\s+value="([A-Za-z0-9_-]+)"/)?.[1];
|
|
45
|
+
if (!rid)
|
|
46
|
+
throw new Error('Neo OAuth authorization page lacked request ID');
|
|
47
|
+
const approval = await request('/authorize', {
|
|
48
|
+
method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
49
|
+
body: new URLSearchParams({ rid, token: operatorToken }),
|
|
50
|
+
});
|
|
51
|
+
if (approval.status !== 302)
|
|
52
|
+
throw new Error('Neo OAuth consent rejected: HTTP ' + approval.status);
|
|
53
|
+
const location = approval.headers.get('location');
|
|
54
|
+
if (!location)
|
|
55
|
+
throw new Error('Neo OAuth approval lacked callback');
|
|
56
|
+
const callback = new URL(location);
|
|
57
|
+
if (callback.origin !== new URL(redirectUri).origin || callback.pathname !== '/neo/oauth/callback'
|
|
58
|
+
|| callback.searchParams.get('state') !== state || callback.searchParams.get('iss') !== origin) {
|
|
59
|
+
throw new Error('Neo OAuth callback state, redirect, or issuer mismatch');
|
|
60
|
+
}
|
|
61
|
+
const code = callback.searchParams.get('code');
|
|
62
|
+
if (!code)
|
|
63
|
+
throw new Error('Neo OAuth callback lacked authorization code');
|
|
64
|
+
const response = await request('/token', {
|
|
65
|
+
method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
66
|
+
body: new URLSearchParams({
|
|
67
|
+
grant_type: 'authorization_code', client_id: client.client_id,
|
|
68
|
+
redirect_uri: redirectUri, code, code_verifier: verifier,
|
|
69
|
+
}),
|
|
70
|
+
});
|
|
71
|
+
if (response.status !== 200)
|
|
72
|
+
throw new Error('Neo OAuth token exchange rejected: HTTP ' + response.status);
|
|
73
|
+
const token = await response.json();
|
|
74
|
+
if (!token.access_token || token.expires_in !== 3600)
|
|
75
|
+
throw new Error('Neo OAuth returned an invalid worker access token');
|
|
76
|
+
// Z workers receive only access tokens, never refresh tokens or the operator credential.
|
|
77
|
+
if (token.refresh_token) {
|
|
78
|
+
const revoke = await request('/revoke', {
|
|
79
|
+
method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
80
|
+
body: new URLSearchParams({ token: token.refresh_token }),
|
|
81
|
+
});
|
|
82
|
+
if (revoke.status !== 200)
|
|
83
|
+
throw new Error('Neo OAuth failed to revoke unused refresh credential');
|
|
84
|
+
}
|
|
85
|
+
return token.access_token;
|
|
86
|
+
}
|
package/package.json
CHANGED
|
@@ -35,6 +35,8 @@ recoveryReopenClearLease["action: mutation.clearLease"]
|
|
|
35
35
|
recoveryReopenClearExecution["action: mutation.clearExecution"]
|
|
36
36
|
|
|
37
37
|
plannerRetryAvailable["guard: retryAvailable"]
|
|
38
|
+
platformFallbackSafe["guard: platformFallbackSafe"]
|
|
39
|
+
preparePlatformFallback["action: mutation.preparePlatformFallback"]
|
|
38
40
|
plannerUnavailableMark["action: mutation.markPlannerUnavailable"]
|
|
39
41
|
orphanFailMark["action: mutation.markUnknownOutcome"]
|
|
40
42
|
orphanFailClearLease["action: mutation.clearLease"]
|
|
@@ -127,7 +129,10 @@ queued -->|on: effect.launchTask.failed| failed
|
|
|
127
129
|
queued -->|on: watchdog.failed| failed
|
|
128
130
|
queued -->|on: worker.delivery_failed| failed
|
|
129
131
|
queued -->|on: worker.start_ack_failed| failed
|
|
130
|
-
queued -->|on: worker.platform_failure|
|
|
132
|
+
queued -->|on: worker.platform_failure| platformFallbackSafe
|
|
133
|
+
platformFallbackSafe -->|true| preparePlatformFallback
|
|
134
|
+
preparePlatformFallback --> queued
|
|
135
|
+
platformFallbackSafe -->|false| platformFallbackQuarantine
|
|
131
136
|
platformFallbackQuarantine["action: mutation.quarantinePlatformFailure"]
|
|
132
137
|
platformFallbackQuarantine --> failed
|
|
133
138
|
queued -->|on: planner.unavailable| plannerUnavailableMark
|