@axiom-lattice/gateway 2.1.21 → 2.1.22

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.
@@ -59,7 +59,11 @@ export async function agent_invoke({
59
59
  }
60
60
 
61
61
  // Get runConfig from agent config and merge into configurable
62
- const runConfig = agentLattice?.config?.runConfig || {};
62
+ const runConfig = {
63
+ ...agentLattice?.config?.runConfig || {},
64
+ assistant_id,
65
+ sandboxConfig: agentLattice?.config?.connectedSandbox,
66
+ }
63
67
 
64
68
  const result = await runnable_agent.invoke(
65
69
  command
@@ -116,7 +120,11 @@ export async function agent_stream({
116
120
  const chunkBuffer = getOrCreateChunkBuffer();
117
121
 
118
122
  // Get runConfig from agent config and merge into configurable
119
- const runConfig = agentLattice?.config?.runConfig || {};
123
+ const runConfig = {
124
+ ...agentLattice?.config?.runConfig || {},
125
+ assistant_id,
126
+ sandboxConfig: agentLattice?.config?.connectedSandbox,
127
+ }
120
128
 
121
129
  try {
122
130
  if (!runnable_agent) {
@@ -126,10 +134,10 @@ export async function agent_stream({
126
134
  command
127
135
  ? new Command(command)
128
136
  : {
129
- ...rest,
130
- messages,
131
- "x-tenant-id": tenant_id,
132
- },
137
+ ...rest,
138
+ messages,
139
+ "x-tenant-id": tenant_id,
140
+ },
133
141
 
134
142
  {
135
143
  configurable: {
@@ -0,0 +1,222 @@
1
+ import { getAgentConfig, getAgentLattice, normalizeSandboxName } from "@axiom-lattice/core";
2
+ import { ConnectedSandboxConfig } from "@axiom-lattice/protocols";
3
+
4
+ const SANDBOX_BASE_URL = process.env.SANDBOX_BASE_URL || "http://localhost:8080";
5
+
6
+ const ERROR_HTML = `<!DOCTYPE html>
7
+ <html lang="zh-CN">
8
+ <head>
9
+ <meta charset="UTF-8">
10
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
11
+ <title>Sandbox 连接错误</title>
12
+ <style>
13
+ * { box-sizing: border-box; margin: 0; padding: 0; }
14
+ body {
15
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
16
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
17
+ min-height: 100vh;
18
+ display: flex;
19
+ align-items: center;
20
+ justify-content: center;
21
+ padding: 20px;
22
+ }
23
+ .container {
24
+ background: white;
25
+ border-radius: 16px;
26
+ padding: 40px;
27
+ max-width: 500px;
28
+ width: 100%;
29
+ box-shadow: 0 20px 60px rgba(0,0,0,0.3);
30
+ }
31
+ .error-icon {
32
+ width: 80px;
33
+ height: 80px;
34
+ background: #fee2e2;
35
+ border-radius: 50%;
36
+ display: flex;
37
+ align-items: center;
38
+ justify-content: center;
39
+ margin: 0 auto 24px;
40
+ }
41
+ .error-icon svg {
42
+ width: 40px;
43
+ height: 40px;
44
+ color: #dc2626;
45
+ }
46
+ h1 { color: #1f2937; margin-bottom: 16px; text-align: center; }
47
+ p { color: #6b7280; margin-bottom: 12px; line-height: 1.6; }
48
+ .info {
49
+ background: #f3f4f6;
50
+ border-radius: 8px;
51
+ padding: 16px;
52
+ margin: 20px 0;
53
+ }
54
+ .info-item {
55
+ display: flex;
56
+ justify-content: space-between;
57
+ padding: 8px 0;
58
+ border-bottom: 1px solid #e5e7eb;
59
+ }
60
+ .info-item:last-child { border-bottom: none; }
61
+ .label { color: #6b7280; font-size: 14px; }
62
+ .value { color: #1f2937; font-weight: 500; font-family: monospace; }
63
+ .retry-btn {
64
+ width: 100%;
65
+ padding: 14px;
66
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
67
+ color: white;
68
+ border: none;
69
+ border-radius: 8px;
70
+ font-size: 16px;
71
+ cursor: pointer;
72
+ transition: transform 0.2s;
73
+ }
74
+ .retry-btn:hover { transform: translateY(-2px); }
75
+ </style>
76
+ </head>
77
+ <body>
78
+ <div class="container">
79
+ <div class="error-icon">
80
+ <svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
81
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"/>
82
+ </svg>
83
+ </div>
84
+ <h1>无法连接到 Sandbox</h1>
85
+ <p>无法连接到沙箱环境,请检查配置后重试。</p>
86
+ <div class="info">
87
+ <div class="info-item">
88
+ <span class="label">Assistant ID</span>
89
+ <span class="value" id="assistantId">-</span>
90
+ </div>
91
+ <div class="info-item">
92
+ <span class="label">Thread ID</span>
93
+ <span class="value" id="threadId">-</span>
94
+ </div>
95
+ <div class="info-item">
96
+ <span class="label">隔离级别</span>
97
+ <span class="value" id="isolatedLevel">-</span>
98
+ </div>
99
+ <div class="info-item">
100
+ <span class="label">错误信息</span>
101
+ <span class="value" id="errorMsg">-</span>
102
+ </div>
103
+ </div>
104
+ <button class="retry-btn" onclick="window.location.reload()">重新连接</button>
105
+ </div>
106
+ <script>
107
+ const params = new URLSearchParams(window.location.search);
108
+ document.getElementById('assistantId').textContent = params.get('assistantId') || '-';
109
+ document.getElementById('threadId').textContent = params.get('threadId') || '-';
110
+ document.getElementById('isolatedLevel').textContent = params.get('isolatedLevel') || '-';
111
+ document.getElementById('errorMsg').textContent = params.get('error') || '未知错误';
112
+ </script>
113
+ </body>
114
+ </html>`;
115
+
116
+ export class SandboxService {
117
+ private baseUrl: string;
118
+
119
+ constructor(baseUrl?: string) {
120
+ this.baseUrl = baseUrl || SANDBOX_BASE_URL;
121
+ }
122
+
123
+ getSandboxConfig(assistantId: string): ConnectedSandboxConfig | null {
124
+ const agentConfig = getAgentConfig(assistantId);
125
+ if (!agentConfig) {
126
+ return null;
127
+ }
128
+
129
+ const agentLattice = getAgentLattice(assistantId);
130
+ return agentLattice?.config?.connectedSandbox || null;
131
+ }
132
+
133
+ computeSandboxName(
134
+ assistantId: string,
135
+ threadId: string,
136
+ isolatedLevel: string
137
+ ): string {
138
+ let sandboxName: string;
139
+
140
+ switch (isolatedLevel) {
141
+ case "agent":
142
+ sandboxName = assistantId;
143
+ break;
144
+ case "thread":
145
+ sandboxName = threadId;
146
+ break;
147
+ case "global":
148
+ default:
149
+ sandboxName = "global";
150
+ break;
151
+ }
152
+
153
+ return normalizeSandboxName(sandboxName);
154
+ }
155
+
156
+ getTargetUrl(sandboxName: string): string {
157
+ return `${this.baseUrl}/sandbox/${sandboxName}`;
158
+ }
159
+
160
+ async getVncHtml(sandboxName: string): Promise<string> {
161
+ const response = await fetch(`${this.getTargetUrl(sandboxName)}/vnc/index.html`);
162
+
163
+ if (!response.ok) {
164
+ throw new Error(`Failed to fetch VNC HTML: ${response.statusText}`);
165
+ }
166
+
167
+ return response.text();
168
+ }
169
+
170
+ rewriteHtml(
171
+ html: string,
172
+ assistantId: string,
173
+ threadId: string
174
+ ): string {
175
+ const prefix = `/api/assistants/${assistantId}/threads/${threadId}/sandbox/vnc`;
176
+
177
+ let rewritten = html;
178
+
179
+ rewritten = rewritten.replace(
180
+ /(src|href)=["']([^"']*)["']/g,
181
+ (match, attr, url) => {
182
+ if (url.startsWith("http://") || url.startsWith("https://") || url.startsWith("//")) {
183
+ return match;
184
+ }
185
+ const rewrittenUrl = url.startsWith("/") ? `${prefix}${url}` : `${prefix}/${url}`;
186
+ return `${attr}="${rewrittenUrl}"`;
187
+ }
188
+ );
189
+
190
+ rewritten = rewritten.replace(
191
+ /path=sandbox\/[^&"']+/g,
192
+ (match) => {
193
+ return `path=${prefix}/websockify`;
194
+ }
195
+ );
196
+
197
+ rewritten = rewritten.replace(
198
+ /new WebSocket\([^)]*\?path=sandbox[^)]*\)/g,
199
+ (match) => {
200
+ return match.replace(/path=sandbox[^)]+/, `path=${prefix}/websockify`);
201
+ }
202
+ );
203
+
204
+ return rewritten;
205
+ }
206
+
207
+ generateErrorHtml(
208
+ assistantId: string,
209
+ threadId: string,
210
+ isolatedLevel: string,
211
+ errorMessage: string
212
+ ): string {
213
+ const encodedError = encodeURIComponent(errorMessage);
214
+ return ERROR_HTML
215
+ .replace("{assistantId}", assistantId)
216
+ .replace("{threadId}", threadId)
217
+ .replace("{isolatedLevel}", isolatedLevel)
218
+ .replace("{errorMessage}", errorMessage);
219
+ }
220
+ }
221
+
222
+ export const sandboxService = new SandboxService();