@virtue-ai/gateway-connect 0.3.4 → 0.3.6
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 +8 -2
- package/dist/index.js +10 -6
- package/dist/trajectory-plugin.js +12 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -23,7 +23,11 @@ openclaw models auth paste-token --provider openai
|
|
|
23
23
|
### Step 3: Connect to VirtueAI MCP Gateway
|
|
24
24
|
|
|
25
25
|
```bash
|
|
26
|
+
# Standalone gateway
|
|
26
27
|
npx @virtue-ai/gateway-connect --gateway-url https://virtueai-agent-gtw-xxxx.ngrok.io
|
|
28
|
+
|
|
29
|
+
# Platform-hosted gateway
|
|
30
|
+
npx @virtue-ai/gateway-connect --gateway-url https://your-domain.ngrok.app/api/gateways/gtw_xxxx
|
|
27
31
|
```
|
|
28
32
|
|
|
29
33
|
This will:
|
|
@@ -39,7 +43,7 @@ This will:
|
|
|
39
43
|
One-shot mode:
|
|
40
44
|
|
|
41
45
|
```bash
|
|
42
|
-
openclaw agent --local --message "What tools do you have?"
|
|
46
|
+
openclaw agent --local --agent main --message "What tools do you have?"
|
|
43
47
|
```
|
|
44
48
|
|
|
45
49
|
Interactive TUI mode:
|
|
@@ -91,7 +95,9 @@ This approach works with any embedded model provider (not just Claude CLI), beca
|
|
|
91
95
|
npx @virtue-ai/gateway-connect [options]
|
|
92
96
|
|
|
93
97
|
Options:
|
|
94
|
-
--gateway-url <url> Gateway URL (
|
|
98
|
+
--gateway-url <url> Gateway URL (standalone or platform-hosted)
|
|
99
|
+
--api-url <url> Prompt-guard API URL (default: https://agentgateway1.virtueai.io)
|
|
100
|
+
--gateway-id <id> Gateway ID for trajectory recording
|
|
95
101
|
--model <model> Model to use (e.g. openai/gpt-4o, anthropic/claude-sonnet-4-5)
|
|
96
102
|
--guard-uuid <uuid> Guard UUID for trajectory recording (or set VIRTUEAI_GUARD_UUID)
|
|
97
103
|
--help Show help message
|
package/dist/index.js
CHANGED
|
@@ -27,7 +27,7 @@ import { generateTrajectoryPlugin, enableTrajectoryPlugin } from './trajectory-p
|
|
|
27
27
|
const CALLBACK_PORT = 19876;
|
|
28
28
|
const CALLBACK_PATH = '/callback';
|
|
29
29
|
const REDIRECT_URI = `http://localhost:${CALLBACK_PORT}${CALLBACK_PATH}`;
|
|
30
|
-
const
|
|
30
|
+
const DEFAULT_SCOPES = 'claudeai copilot mcp:read mcp:execute mcp:access';
|
|
31
31
|
const OPENCLAW_DIR = path.join(os.homedir(), '.openclaw');
|
|
32
32
|
const MCP_CONFIG_PATH = path.join(OPENCLAW_DIR, 'mcp-gateway.json');
|
|
33
33
|
const OPENCLAW_CONFIG_PATH = path.join(OPENCLAW_DIR, 'openclaw.json');
|
|
@@ -102,7 +102,7 @@ function openBrowser(url) {
|
|
|
102
102
|
// ---------------------------------------------------------------------------
|
|
103
103
|
async function authenticate(gatewayUrl) {
|
|
104
104
|
console.log(' Discovering OAuth endpoints...');
|
|
105
|
-
const { data: metadata } = await fetchJson(`${gatewayUrl}/.well-known/oauth-authorization-server`, { method: 'GET' });
|
|
105
|
+
const { data: metadata } = await fetchJson(`${gatewayUrl}/.well-known/oauth-authorization-server`, { method: 'GET', headers: { Accept: 'application/json' } });
|
|
106
106
|
if (!metadata.authorization_endpoint || !metadata.token_endpoint) {
|
|
107
107
|
console.error('Error: Could not discover OAuth endpoints from gateway.');
|
|
108
108
|
console.error('Response:', JSON.stringify(metadata, null, 2));
|
|
@@ -111,8 +111,12 @@ async function authenticate(gatewayUrl) {
|
|
|
111
111
|
const authEndpoint = metadata.authorization_endpoint;
|
|
112
112
|
const tokenEndpoint = metadata.token_endpoint;
|
|
113
113
|
const registerEndpoint = metadata.registration_endpoint;
|
|
114
|
+
const scopes = metadata.scopes_supported
|
|
115
|
+
? metadata.scopes_supported.join(' ')
|
|
116
|
+
: DEFAULT_SCOPES;
|
|
114
117
|
console.log(` Auth endpoint: ${authEndpoint}`);
|
|
115
118
|
console.log(` Token endpoint: ${tokenEndpoint}`);
|
|
119
|
+
console.log(` Scopes: ${scopes}`);
|
|
116
120
|
console.log(' Registering OAuth client...');
|
|
117
121
|
const { status: regStatus, data: clientInfo } = await fetchJson(registerEndpoint, {
|
|
118
122
|
method: 'POST',
|
|
@@ -121,7 +125,7 @@ async function authenticate(gatewayUrl) {
|
|
|
121
125
|
client_name: 'openclaw-gateway-connect',
|
|
122
126
|
grant_types: ['authorization_code', 'refresh_token'],
|
|
123
127
|
redirect_uris: [REDIRECT_URI],
|
|
124
|
-
scope:
|
|
128
|
+
scope: scopes,
|
|
125
129
|
token_endpoint_auth_method: 'none',
|
|
126
130
|
}),
|
|
127
131
|
});
|
|
@@ -139,7 +143,7 @@ async function authenticate(gatewayUrl) {
|
|
|
139
143
|
authUrl.searchParams.set('client_id', clientId);
|
|
140
144
|
authUrl.searchParams.set('redirect_uri', REDIRECT_URI);
|
|
141
145
|
authUrl.searchParams.set('response_type', 'code');
|
|
142
|
-
authUrl.searchParams.set('scope',
|
|
146
|
+
authUrl.searchParams.set('scope', scopes);
|
|
143
147
|
authUrl.searchParams.set('state', state);
|
|
144
148
|
authUrl.searchParams.set('code_challenge', codeChallenge);
|
|
145
149
|
authUrl.searchParams.set('code_challenge_method', 'S256');
|
|
@@ -347,7 +351,7 @@ function writeGatewayConfig(gatewayUrl, accessToken, guardUuid, apiUrl, gatewayI
|
|
|
347
351
|
const config = {
|
|
348
352
|
trajectory: {
|
|
349
353
|
gatewayUrl,
|
|
350
|
-
apiUrl: apiUrl ||
|
|
354
|
+
apiUrl: apiUrl || '',
|
|
351
355
|
gatewayId: gatewayId || DEFAULT_GATEWAY_ID,
|
|
352
356
|
guardUuid: guardUuid || process.env.VIRTUEAI_GUARD_UUID || '',
|
|
353
357
|
},
|
|
@@ -501,7 +505,7 @@ Supported models:
|
|
|
501
505
|
${TOOLS_PLUGIN_DIR}
|
|
502
506
|
|
|
503
507
|
Start using it:
|
|
504
|
-
openclaw agent --local --message "What tools do you have?"
|
|
508
|
+
openclaw agent --local --agent main --message "What tools do you have?"
|
|
505
509
|
|
|
506
510
|
To use a different model:
|
|
507
511
|
npx @virtue-ai/gateway-connect --gateway-url ${gatewayUrl} --model openai/gpt-4o
|
|
@@ -50,7 +50,7 @@ function loadConfig() {
|
|
|
50
50
|
const cfg = JSON.parse(raw);
|
|
51
51
|
|
|
52
52
|
const gatewayUrl = cfg._auth?.gatewayUrl ?? cfg.trajectory?.gatewayUrl ?? "";
|
|
53
|
-
const apiUrl = cfg.trajectory?.apiUrl ??
|
|
53
|
+
const apiUrl = cfg.trajectory?.apiUrl ?? "";
|
|
54
54
|
const gatewayId = cfg.trajectory?.gatewayId ?? "";
|
|
55
55
|
const token = cfg._auth?.accessToken ?? "";
|
|
56
56
|
|
|
@@ -59,8 +59,13 @@ function loadConfig() {
|
|
|
59
59
|
process.env.VIRTUEAI_GUARD_UUID ||
|
|
60
60
|
DEFAULT_GUARD_UUID;
|
|
61
61
|
|
|
62
|
-
|
|
63
|
-
|
|
62
|
+
// If explicit apiUrl is set, use old path; otherwise derive from gatewayUrl
|
|
63
|
+
const trajectoryEndpoint = apiUrl
|
|
64
|
+
? apiUrl + "/api/prompt-guard/topic_guard"
|
|
65
|
+
: gatewayUrl + "/prompt-guard/topic_guard";
|
|
66
|
+
|
|
67
|
+
if (!gatewayUrl || !token) return null;
|
|
68
|
+
return { gatewayUrl, gatewayId, token, guardUuid, trajectoryEndpoint };
|
|
64
69
|
} catch {
|
|
65
70
|
return null;
|
|
66
71
|
}
|
|
@@ -100,7 +105,7 @@ const plugin = {
|
|
|
100
105
|
|
|
101
106
|
let gatewaySessionId = null;
|
|
102
107
|
let endpointDisabled = false;
|
|
103
|
-
const endpoint = config.
|
|
108
|
+
const endpoint = config.trajectoryEndpoint;
|
|
104
109
|
const localSessionId = "local_" + Date.now().toString(36);
|
|
105
110
|
|
|
106
111
|
try { mkdirSync(TRAJECTORY_LOG_DIR, { recursive: true }); } catch {}
|
|
@@ -113,7 +118,7 @@ const plugin = {
|
|
|
113
118
|
} catch {}
|
|
114
119
|
}
|
|
115
120
|
|
|
116
|
-
api.logger.info("[virtueai-trajectory] Plugin registered,
|
|
121
|
+
api.logger.info("[virtueai-trajectory] Plugin registered, endpoint: " + endpoint);
|
|
117
122
|
|
|
118
123
|
async function sendStep(role, content) {
|
|
119
124
|
if (endpointDisabled) return;
|
|
@@ -138,9 +143,9 @@ const plugin = {
|
|
|
138
143
|
body: JSON.stringify(body),
|
|
139
144
|
});
|
|
140
145
|
|
|
141
|
-
if (res.status === 404) {
|
|
146
|
+
if (res.status === 404 || res.status === 401 || res.status === 403) {
|
|
142
147
|
endpointDisabled = true;
|
|
143
|
-
api.logger.warn("[virtueai-trajectory]
|
|
148
|
+
api.logger.warn("[virtueai-trajectory] HTTP " + res.status + " — trajectory recording disabled");
|
|
144
149
|
return;
|
|
145
150
|
}
|
|
146
151
|
if (!res.ok) {
|