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