@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.
- package/.turbo/turbo-build.log +8 -8
- package/CHANGELOG.md +10 -0
- package/dist/index.js +357 -13
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +346 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +8 -4
- package/src/controllers/sandbox.ts +150 -0
- package/src/controllers/tools.ts +410 -0
- package/src/index.ts +4 -0
- package/src/routes/index.ts +8 -0
- package/src/schemas/index.ts +42 -0
- package/src/services/agent_service.ts +14 -6
- package/src/services/sandbox_service.ts +222 -0
package/dist/index.mjs
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import fastify from "fastify";
|
|
3
3
|
import cors from "@fastify/cors";
|
|
4
4
|
import sensible from "@fastify/sensible";
|
|
5
|
+
import websocket from "@fastify/websocket";
|
|
5
6
|
|
|
6
7
|
// src/services/agent_service.ts
|
|
7
8
|
import {
|
|
@@ -46,7 +47,11 @@ async function agent_invoke({
|
|
|
46
47
|
if (!runnable_agent) {
|
|
47
48
|
throw new Error(`Agent ${assistant_id} not found`);
|
|
48
49
|
}
|
|
49
|
-
const runConfig =
|
|
50
|
+
const runConfig = {
|
|
51
|
+
...agentLattice?.config?.runConfig || {},
|
|
52
|
+
assistant_id,
|
|
53
|
+
sandboxConfig: agentLattice?.config?.connectedSandbox
|
|
54
|
+
};
|
|
50
55
|
const result = await runnable_agent.invoke(
|
|
51
56
|
command ? new Command(command) : { ...rest, messages, "x-tenant-id": tenant_id },
|
|
52
57
|
{
|
|
@@ -88,7 +93,11 @@ async function agent_stream({
|
|
|
88
93
|
messages = [humanMessage];
|
|
89
94
|
}
|
|
90
95
|
const chunkBuffer = getOrCreateChunkBuffer();
|
|
91
|
-
const runConfig =
|
|
96
|
+
const runConfig = {
|
|
97
|
+
...agentLattice?.config?.runConfig || {},
|
|
98
|
+
assistant_id,
|
|
99
|
+
sandboxConfig: agentLattice?.config?.connectedSandbox
|
|
100
|
+
};
|
|
92
101
|
try {
|
|
93
102
|
if (!runnable_agent) {
|
|
94
103
|
throw new Error(`Agent ${assistant_id} not found`);
|
|
@@ -1624,6 +1633,88 @@ async function filterSkillsByLicense(request, reply) {
|
|
|
1624
1633
|
}
|
|
1625
1634
|
}
|
|
1626
1635
|
|
|
1636
|
+
// src/controllers/tools.ts
|
|
1637
|
+
import { getStoreLattice as getStoreLattice4, toolLatticeManager } from "@axiom-lattice/core";
|
|
1638
|
+
function serializeSchema(schema) {
|
|
1639
|
+
if (!schema) {
|
|
1640
|
+
return void 0;
|
|
1641
|
+
}
|
|
1642
|
+
try {
|
|
1643
|
+
if (schema._def) {
|
|
1644
|
+
const def = schema._def;
|
|
1645
|
+
if (def.typeName === "ZodObject") {
|
|
1646
|
+
const shape = def.shape();
|
|
1647
|
+
const properties = {};
|
|
1648
|
+
const required = [];
|
|
1649
|
+
for (const [key, value] of Object.entries(shape)) {
|
|
1650
|
+
const fieldDef = value._def;
|
|
1651
|
+
if (fieldDef) {
|
|
1652
|
+
properties[key] = {
|
|
1653
|
+
type: fieldDef.typeName === "ZodString" ? "string" : fieldDef.typeName === "ZodNumber" ? "number" : fieldDef.typeName === "ZodBoolean" ? "boolean" : fieldDef.typeName === "ZodArray" ? "array" : fieldDef.typeName === "ZodObject" ? "object" : "unknown",
|
|
1654
|
+
description: fieldDef.description
|
|
1655
|
+
};
|
|
1656
|
+
if (!value.isOptional()) {
|
|
1657
|
+
required.push(key);
|
|
1658
|
+
}
|
|
1659
|
+
}
|
|
1660
|
+
}
|
|
1661
|
+
return {
|
|
1662
|
+
type: "object",
|
|
1663
|
+
properties,
|
|
1664
|
+
required: required.length > 0 ? required : void 0
|
|
1665
|
+
};
|
|
1666
|
+
}
|
|
1667
|
+
}
|
|
1668
|
+
return {
|
|
1669
|
+
type: "object",
|
|
1670
|
+
description: schema.description || "Schema definition"
|
|
1671
|
+
};
|
|
1672
|
+
} catch (error) {
|
|
1673
|
+
return {
|
|
1674
|
+
type: "object",
|
|
1675
|
+
description: "Schema definition"
|
|
1676
|
+
};
|
|
1677
|
+
}
|
|
1678
|
+
}
|
|
1679
|
+
async function getToolConfigs(request, reply) {
|
|
1680
|
+
try {
|
|
1681
|
+
const allLattices = toolLatticeManager.getAllLattices();
|
|
1682
|
+
const toolConfigs = allLattices.map((lattice) => {
|
|
1683
|
+
const config = { ...lattice.config };
|
|
1684
|
+
const serializedSchema = config.schema ? serializeSchema(config.schema) : void 0;
|
|
1685
|
+
return {
|
|
1686
|
+
id: lattice.key,
|
|
1687
|
+
name: config.name,
|
|
1688
|
+
description: config.description,
|
|
1689
|
+
schema: serializedSchema,
|
|
1690
|
+
returnDirect: config.returnDirect,
|
|
1691
|
+
needUserApprove: config.needUserApprove
|
|
1692
|
+
};
|
|
1693
|
+
});
|
|
1694
|
+
return reply.send({
|
|
1695
|
+
success: true,
|
|
1696
|
+
message: "Successfully retrieved tool configs",
|
|
1697
|
+
data: {
|
|
1698
|
+
records: toolConfigs,
|
|
1699
|
+
total: toolConfigs.length
|
|
1700
|
+
}
|
|
1701
|
+
});
|
|
1702
|
+
} catch (error) {
|
|
1703
|
+
console.error("Failed to get tool configs", {
|
|
1704
|
+
error: error.message,
|
|
1705
|
+
stack: error.stack
|
|
1706
|
+
});
|
|
1707
|
+
return reply.status(500).send({
|
|
1708
|
+
success: false,
|
|
1709
|
+
message: `Failed to retrieve tool configs: ${error.message}`,
|
|
1710
|
+
data: {
|
|
1711
|
+
records: [],
|
|
1712
|
+
total: 0
|
|
1713
|
+
}
|
|
1714
|
+
});
|
|
1715
|
+
}
|
|
1716
|
+
}
|
|
1717
|
+
|
|
1627
1718
|
// src/schemas/index.ts
|
|
1628
1719
|
var getAllMemoryItemsSchema = {
|
|
1629
1720
|
description: "Get all memory items for an assistant thread",
|
|
@@ -1895,6 +1986,256 @@ var getHealthSchema = {
|
|
|
1895
1986
|
}
|
|
1896
1987
|
};
|
|
1897
1988
|
|
|
1989
|
+
// src/services/sandbox_service.ts
|
|
1990
|
+
import { getAgentConfig, getAgentLattice as getAgentLattice2, normalizeSandboxName } from "@axiom-lattice/core";
|
|
1991
|
+
var SANDBOX_BASE_URL = process.env.SANDBOX_BASE_URL || "http://localhost:8080";
|
|
1992
|
+
var ERROR_HTML = `<!DOCTYPE html>
|
|
1993
|
+
<html lang="zh-CN">
|
|
1994
|
+
<head>
|
|
1995
|
+
<meta charset="UTF-8">
|
|
1996
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
1997
|
+
<title>Sandbox \u8FDE\u63A5\u9519\u8BEF</title>
|
|
1998
|
+
<style>
|
|
1999
|
+
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
2000
|
+
body {
|
|
2001
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
2002
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
2003
|
+
min-height: 100vh;
|
|
2004
|
+
display: flex;
|
|
2005
|
+
align-items: center;
|
|
2006
|
+
justify-content: center;
|
|
2007
|
+
padding: 20px;
|
|
2008
|
+
}
|
|
2009
|
+
.container {
|
|
2010
|
+
background: white;
|
|
2011
|
+
border-radius: 16px;
|
|
2012
|
+
padding: 40px;
|
|
2013
|
+
max-width: 500px;
|
|
2014
|
+
width: 100%;
|
|
2015
|
+
box-shadow: 0 20px 60px rgba(0,0,0,0.3);
|
|
2016
|
+
}
|
|
2017
|
+
.error-icon {
|
|
2018
|
+
width: 80px;
|
|
2019
|
+
height: 80px;
|
|
2020
|
+
background: #fee2e2;
|
|
2021
|
+
border-radius: 50%;
|
|
2022
|
+
display: flex;
|
|
2023
|
+
align-items: center;
|
|
2024
|
+
justify-content: center;
|
|
2025
|
+
margin: 0 auto 24px;
|
|
2026
|
+
}
|
|
2027
|
+
.error-icon svg {
|
|
2028
|
+
width: 40px;
|
|
2029
|
+
height: 40px;
|
|
2030
|
+
color: #dc2626;
|
|
2031
|
+
}
|
|
2032
|
+
h1 { color: #1f2937; margin-bottom: 16px; text-align: center; }
|
|
2033
|
+
p { color: #6b7280; margin-bottom: 12px; line-height: 1.6; }
|
|
2034
|
+
.info {
|
|
2035
|
+
background: #f3f4f6;
|
|
2036
|
+
border-radius: 8px;
|
|
2037
|
+
padding: 16px;
|
|
2038
|
+
margin: 20px 0;
|
|
2039
|
+
}
|
|
2040
|
+
.info-item {
|
|
2041
|
+
display: flex;
|
|
2042
|
+
justify-content: space-between;
|
|
2043
|
+
padding: 8px 0;
|
|
2044
|
+
border-bottom: 1px solid #e5e7eb;
|
|
2045
|
+
}
|
|
2046
|
+
.info-item:last-child { border-bottom: none; }
|
|
2047
|
+
.label { color: #6b7280; font-size: 14px; }
|
|
2048
|
+
.value { color: #1f2937; font-weight: 500; font-family: monospace; }
|
|
2049
|
+
.retry-btn {
|
|
2050
|
+
width: 100%;
|
|
2051
|
+
padding: 14px;
|
|
2052
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
2053
|
+
color: white;
|
|
2054
|
+
border: none;
|
|
2055
|
+
border-radius: 8px;
|
|
2056
|
+
font-size: 16px;
|
|
2057
|
+
cursor: pointer;
|
|
2058
|
+
transition: transform 0.2s;
|
|
2059
|
+
}
|
|
2060
|
+
.retry-btn:hover { transform: translateY(-2px); }
|
|
2061
|
+
</style>
|
|
2062
|
+
</head>
|
|
2063
|
+
<body>
|
|
2064
|
+
<div class="container">
|
|
2065
|
+
<div class="error-icon">
|
|
2066
|
+
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
2067
|
+
<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"/>
|
|
2068
|
+
</svg>
|
|
2069
|
+
</div>
|
|
2070
|
+
<h1>\u65E0\u6CD5\u8FDE\u63A5\u5230 Sandbox</h1>
|
|
2071
|
+
<p>\u65E0\u6CD5\u8FDE\u63A5\u5230\u6C99\u7BB1\u73AF\u5883\uFF0C\u8BF7\u68C0\u67E5\u914D\u7F6E\u540E\u91CD\u8BD5\u3002</p>
|
|
2072
|
+
<div class="info">
|
|
2073
|
+
<div class="info-item">
|
|
2074
|
+
<span class="label">Assistant ID</span>
|
|
2075
|
+
<span class="value" id="assistantId">-</span>
|
|
2076
|
+
</div>
|
|
2077
|
+
<div class="info-item">
|
|
2078
|
+
<span class="label">Thread ID</span>
|
|
2079
|
+
<span class="value" id="threadId">-</span>
|
|
2080
|
+
</div>
|
|
2081
|
+
<div class="info-item">
|
|
2082
|
+
<span class="label">\u9694\u79BB\u7EA7\u522B</span>
|
|
2083
|
+
<span class="value" id="isolatedLevel">-</span>
|
|
2084
|
+
</div>
|
|
2085
|
+
<div class="info-item">
|
|
2086
|
+
<span class="label">\u9519\u8BEF\u4FE1\u606F</span>
|
|
2087
|
+
<span class="value" id="errorMsg">-</span>
|
|
2088
|
+
</div>
|
|
2089
|
+
</div>
|
|
2090
|
+
<button class="retry-btn" onclick="window.location.reload()">\u91CD\u65B0\u8FDE\u63A5</button>
|
|
2091
|
+
</div>
|
|
2092
|
+
<script>
|
|
2093
|
+
const params = new URLSearchParams(window.location.search);
|
|
2094
|
+
document.getElementById('assistantId').textContent = params.get('assistantId') || '-';
|
|
2095
|
+
document.getElementById('threadId').textContent = params.get('threadId') || '-';
|
|
2096
|
+
document.getElementById('isolatedLevel').textContent = params.get('isolatedLevel') || '-';
|
|
2097
|
+
document.getElementById('errorMsg').textContent = params.get('error') || '\u672A\u77E5\u9519\u8BEF';
|
|
2098
|
+
</script>
|
|
2099
|
+
</body>
|
|
2100
|
+
</html>`;
|
|
2101
|
+
var SandboxService = class {
|
|
2102
|
+
constructor(baseUrl) {
|
|
2103
|
+
this.baseUrl = baseUrl || SANDBOX_BASE_URL;
|
|
2104
|
+
}
|
|
2105
|
+
getSandboxConfig(assistantId) {
|
|
2106
|
+
const agentConfig = getAgentConfig(assistantId);
|
|
2107
|
+
if (!agentConfig) {
|
|
2108
|
+
return null;
|
|
2109
|
+
}
|
|
2110
|
+
const agentLattice = getAgentLattice2(assistantId);
|
|
2111
|
+
return agentLattice?.config?.connectedSandbox || null;
|
|
2112
|
+
}
|
|
2113
|
+
computeSandboxName(assistantId, threadId, isolatedLevel) {
|
|
2114
|
+
let sandboxName;
|
|
2115
|
+
switch (isolatedLevel) {
|
|
2116
|
+
case "agent":
|
|
2117
|
+
sandboxName = assistantId;
|
|
2118
|
+
break;
|
|
2119
|
+
case "thread":
|
|
2120
|
+
sandboxName = threadId;
|
|
2121
|
+
break;
|
|
2122
|
+
case "global":
|
|
2123
|
+
default:
|
|
2124
|
+
sandboxName = "global";
|
|
2125
|
+
break;
|
|
2126
|
+
}
|
|
2127
|
+
return normalizeSandboxName(sandboxName);
|
|
2128
|
+
}
|
|
2129
|
+
getTargetUrl(sandboxName) {
|
|
2130
|
+
return `${this.baseUrl}/sandbox/${sandboxName}`;
|
|
2131
|
+
}
|
|
2132
|
+
async getVncHtml(sandboxName) {
|
|
2133
|
+
const response = await fetch(`${this.getTargetUrl(sandboxName)}/vnc/index.html`);
|
|
2134
|
+
if (!response.ok) {
|
|
2135
|
+
throw new Error(`Failed to fetch VNC HTML: ${response.statusText}`);
|
|
2136
|
+
}
|
|
2137
|
+
return response.text();
|
|
2138
|
+
}
|
|
2139
|
+
rewriteHtml(html, assistantId, threadId) {
|
|
2140
|
+
const prefix = `/api/assistants/${assistantId}/threads/${threadId}/sandbox/vnc`;
|
|
2141
|
+
let rewritten = html;
|
|
2142
|
+
rewritten = rewritten.replace(
|
|
2143
|
+
/(src|href)=["']([^"']*)["']/g,
|
|
2144
|
+
(match, attr, url) => {
|
|
2145
|
+
if (url.startsWith("http://") || url.startsWith("https://") || url.startsWith("//")) {
|
|
2146
|
+
return match;
|
|
2147
|
+
}
|
|
2148
|
+
const rewrittenUrl = url.startsWith("/") ? `${prefix}${url}` : `${prefix}/${url}`;
|
|
2149
|
+
return `${attr}="${rewrittenUrl}"`;
|
|
2150
|
+
}
|
|
2151
|
+
);
|
|
2152
|
+
rewritten = rewritten.replace(
|
|
2153
|
+
/path=sandbox\/[^&"']+/g,
|
|
2154
|
+
(match) => {
|
|
2155
|
+
return `path=${prefix}/websockify`;
|
|
2156
|
+
}
|
|
2157
|
+
);
|
|
2158
|
+
rewritten = rewritten.replace(
|
|
2159
|
+
/new WebSocket\([^)]*\?path=sandbox[^)]*\)/g,
|
|
2160
|
+
(match) => {
|
|
2161
|
+
return match.replace(/path=sandbox[^)]+/, `path=${prefix}/websockify`);
|
|
2162
|
+
}
|
|
2163
|
+
);
|
|
2164
|
+
return rewritten;
|
|
2165
|
+
}
|
|
2166
|
+
generateErrorHtml(assistantId, threadId, isolatedLevel, errorMessage) {
|
|
2167
|
+
const encodedError = encodeURIComponent(errorMessage);
|
|
2168
|
+
return ERROR_HTML.replace("{assistantId}", assistantId).replace("{threadId}", threadId).replace("{isolatedLevel}", isolatedLevel).replace("{errorMessage}", errorMessage);
|
|
2169
|
+
}
|
|
2170
|
+
};
|
|
2171
|
+
var sandboxService = new SandboxService();
|
|
2172
|
+
|
|
2173
|
+
// src/controllers/sandbox.ts
|
|
2174
|
+
var SANDBOX_BASE_URL2 = process.env.SANDBOX_BASE_URL || "http://localhost:8080";
|
|
2175
|
+
async function registerSandboxProxyRoutes(app2) {
|
|
2176
|
+
app2.get(
|
|
2177
|
+
"/api/assistants/:assistantId/threads/:threadId/sandbox",
|
|
2178
|
+
async (request, reply) => {
|
|
2179
|
+
const { assistantId, threadId } = request.params;
|
|
2180
|
+
const sandboxConfig = sandboxService.getSandboxConfig(assistantId);
|
|
2181
|
+
if (!sandboxConfig) {
|
|
2182
|
+
const errorHtml = sandboxService.generateErrorHtml(
|
|
2183
|
+
assistantId,
|
|
2184
|
+
threadId,
|
|
2185
|
+
"unknown",
|
|
2186
|
+
`Assistant ${assistantId} not found`
|
|
2187
|
+
);
|
|
2188
|
+
return reply.status(404).type("text/html").send(errorHtml);
|
|
2189
|
+
}
|
|
2190
|
+
const { isolatedLevel } = sandboxConfig;
|
|
2191
|
+
const sandboxName = sandboxService.computeSandboxName(
|
|
2192
|
+
assistantId,
|
|
2193
|
+
threadId,
|
|
2194
|
+
isolatedLevel
|
|
2195
|
+
);
|
|
2196
|
+
try {
|
|
2197
|
+
const html = await sandboxService.getVncHtml(sandboxName);
|
|
2198
|
+
const rewrittenHtml = sandboxService.rewriteHtml(html, assistantId, threadId);
|
|
2199
|
+
return reply.type("text/html").send(rewrittenHtml);
|
|
2200
|
+
} catch (error) {
|
|
2201
|
+
const errorHtml = sandboxService.generateErrorHtml(
|
|
2202
|
+
assistantId,
|
|
2203
|
+
threadId,
|
|
2204
|
+
isolatedLevel,
|
|
2205
|
+
error.message || "Failed to connect to sandbox"
|
|
2206
|
+
);
|
|
2207
|
+
return reply.status(502).type("text/html").send(errorHtml);
|
|
2208
|
+
}
|
|
2209
|
+
}
|
|
2210
|
+
);
|
|
2211
|
+
app2.get(
|
|
2212
|
+
"/api/assistants/:assistantId/threads/:threadId/sandbox/vnc/*",
|
|
2213
|
+
async (request, reply) => {
|
|
2214
|
+
const { assistantId, threadId, "*": restPath } = request.params;
|
|
2215
|
+
const sandboxConfig = sandboxService.getSandboxConfig(assistantId);
|
|
2216
|
+
if (!sandboxConfig) {
|
|
2217
|
+
return reply.status(404).send("Assistant not found");
|
|
2218
|
+
}
|
|
2219
|
+
const { isolatedLevel } = sandboxConfig;
|
|
2220
|
+
const sandboxName = sandboxService.computeSandboxName(
|
|
2221
|
+
assistantId,
|
|
2222
|
+
threadId,
|
|
2223
|
+
isolatedLevel
|
|
2224
|
+
);
|
|
2225
|
+
const targetPath = restPath ? `/vnc/${restPath}` : "/vnc/";
|
|
2226
|
+
const targetUrl = `${sandboxService.getTargetUrl(sandboxName)}${targetPath}`;
|
|
2227
|
+
try {
|
|
2228
|
+
const response = await fetch(targetUrl);
|
|
2229
|
+
const contentType = response.headers.get("content-type") || "application/octet-stream";
|
|
2230
|
+
const body = await response.arrayBuffer();
|
|
2231
|
+
reply.status(response.status).type(contentType).send(Buffer.from(body));
|
|
2232
|
+
} catch (error) {
|
|
2233
|
+
reply.status(502).send(`Proxy error: ${error.message}`);
|
|
2234
|
+
}
|
|
2235
|
+
}
|
|
2236
|
+
);
|
|
2237
|
+
}
|
|
2238
|
+
|
|
1898
2239
|
// src/routes/index.ts
|
|
1899
2240
|
var registerLatticeRoutes = (app2) => {
|
|
1900
2241
|
app2.post("/api/runs", createRun);
|
|
@@ -1970,6 +2311,7 @@ var registerLatticeRoutes = (app2) => {
|
|
|
1970
2311
|
);
|
|
1971
2312
|
app2.get("/api/models", getModels);
|
|
1972
2313
|
app2.put("/api/models", updateModels);
|
|
2314
|
+
app2.get("/api/tools", getToolConfigs);
|
|
1973
2315
|
app2.get(
|
|
1974
2316
|
"/health",
|
|
1975
2317
|
{ schema: getHealthSchema },
|
|
@@ -2012,6 +2354,7 @@ var registerLatticeRoutes = (app2) => {
|
|
|
2012
2354
|
"/api/skills/filter/license",
|
|
2013
2355
|
filterSkillsByLicense
|
|
2014
2356
|
);
|
|
2357
|
+
registerSandboxProxyRoutes(app2);
|
|
2015
2358
|
};
|
|
2016
2359
|
|
|
2017
2360
|
// src/swagger.ts
|
|
@@ -2436,6 +2779,7 @@ app.register(cors, {
|
|
|
2436
2779
|
credentials: true
|
|
2437
2780
|
});
|
|
2438
2781
|
app.register(sensible);
|
|
2782
|
+
app.register(websocket);
|
|
2439
2783
|
app.setErrorHandler((error, request, reply) => {
|
|
2440
2784
|
const getHeaderValue = (header) => {
|
|
2441
2785
|
if (Array.isArray(header)) {
|