@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
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
> @axiom-lattice/gateway@2.1.
|
|
2
|
+
> @axiom-lattice/gateway@2.1.23 build /home/runner/work/agentic/agentic/packages/gateway
|
|
3
3
|
> tsup src/index.ts --format cjs,esm --dts --clean --sourcemap
|
|
4
4
|
|
|
5
5
|
[34mCLI[39m Building entry: src/index.ts
|
|
@@ -9,13 +9,13 @@
|
|
|
9
9
|
[34mCLI[39m Cleaning output folder
|
|
10
10
|
[34mCJS[39m Build start
|
|
11
11
|
[34mESM[39m Build start
|
|
12
|
-
[
|
|
13
|
-
[
|
|
14
|
-
[
|
|
15
|
-
[
|
|
16
|
-
[
|
|
17
|
-
[
|
|
12
|
+
[32mESM[39m [1mdist/index.mjs [22m[32m83.88 KB[39m
|
|
13
|
+
[32mESM[39m [1mdist/index.mjs.map [22m[32m200.51 KB[39m
|
|
14
|
+
[32mESM[39m ⚡️ Build success in 221ms
|
|
15
|
+
[32mCJS[39m [1mdist/index.js [22m[32m86.51 KB[39m
|
|
16
|
+
[32mCJS[39m [1mdist/index.js.map [22m[32m200.54 KB[39m
|
|
17
|
+
[32mCJS[39m ⚡️ Build success in 223ms
|
|
18
18
|
[34mDTS[39m Build start
|
|
19
|
-
[32mDTS[39m ⚡️ Build success in
|
|
19
|
+
[32mDTS[39m ⚡️ Build success in 9197ms
|
|
20
20
|
[32mDTS[39m [1mdist/index.d.ts [22m[32m3.72 KB[39m
|
|
21
21
|
[32mDTS[39m [1mdist/index.d.mts [22m[32m3.72 KB[39m
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# @axiom-lattice/gateway
|
|
2
2
|
|
|
3
|
+
## 2.1.23
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- e0a5f54: enhance file
|
|
8
|
+
- Updated dependencies [e0a5f54]
|
|
9
|
+
- @axiom-lattice/core@2.1.18
|
|
10
|
+
|
|
11
|
+
## 2.1.22
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- 2422cbf: add sandbox and mcp
|
|
16
|
+
- Updated dependencies [2422cbf]
|
|
17
|
+
- @axiom-lattice/protocols@2.1.11
|
|
18
|
+
- @axiom-lattice/core@2.1.17
|
|
19
|
+
- @axiom-lattice/queue-redis@1.0.10
|
|
20
|
+
|
|
3
21
|
## 2.1.21
|
|
4
22
|
|
|
5
23
|
### Patch Changes
|
package/dist/index.js
CHANGED
|
@@ -35,7 +35,9 @@ __export(index_exports, {
|
|
|
35
35
|
module.exports = __toCommonJS(index_exports);
|
|
36
36
|
var import_fastify = __toESM(require("fastify"));
|
|
37
37
|
var import_cors = __toESM(require("@fastify/cors"));
|
|
38
|
+
var import_multipart = __toESM(require("@fastify/multipart"));
|
|
38
39
|
var import_sensible = __toESM(require("@fastify/sensible"));
|
|
40
|
+
var import_websocket = __toESM(require("@fastify/websocket"));
|
|
39
41
|
|
|
40
42
|
// src/services/agent_service.ts
|
|
41
43
|
var import_messages = require("@langchain/core/messages");
|
|
@@ -70,7 +72,11 @@ async function agent_invoke({
|
|
|
70
72
|
if (!runnable_agent) {
|
|
71
73
|
throw new Error(`Agent ${assistant_id} not found`);
|
|
72
74
|
}
|
|
73
|
-
const runConfig =
|
|
75
|
+
const runConfig = {
|
|
76
|
+
...agentLattice?.config?.runConfig || {},
|
|
77
|
+
assistant_id,
|
|
78
|
+
sandboxConfig: agentLattice?.config?.connectedSandbox
|
|
79
|
+
};
|
|
74
80
|
const result = await runnable_agent.invoke(
|
|
75
81
|
command ? new import_langgraph.Command(command) : { ...rest, messages, "x-tenant-id": tenant_id },
|
|
76
82
|
{
|
|
@@ -80,6 +86,7 @@ async function agent_invoke({
|
|
|
80
86
|
"x-tenant-id": tenant_id,
|
|
81
87
|
"x-request-id": run_id,
|
|
82
88
|
"x-thread-id": thread_id,
|
|
89
|
+
"x-assistant-id": assistant_id,
|
|
83
90
|
runConfig
|
|
84
91
|
// Inject runConfig for tools to access
|
|
85
92
|
},
|
|
@@ -112,7 +119,11 @@ async function agent_stream({
|
|
|
112
119
|
messages = [humanMessage];
|
|
113
120
|
}
|
|
114
121
|
const chunkBuffer = getOrCreateChunkBuffer();
|
|
115
|
-
const runConfig =
|
|
122
|
+
const runConfig = {
|
|
123
|
+
...agentLattice?.config?.runConfig || {},
|
|
124
|
+
assistant_id,
|
|
125
|
+
sandboxConfig: agentLattice?.config?.connectedSandbox
|
|
126
|
+
};
|
|
116
127
|
try {
|
|
117
128
|
if (!runnable_agent) {
|
|
118
129
|
throw new Error(`Agent ${assistant_id} not found`);
|
|
@@ -130,6 +141,7 @@ async function agent_stream({
|
|
|
130
141
|
"x-tenant-id": tenant_id,
|
|
131
142
|
"x-request-id": run_id,
|
|
132
143
|
"x-thread-id": thread_id,
|
|
144
|
+
"x-assistant-id": assistant_id,
|
|
133
145
|
runConfig
|
|
134
146
|
// Inject runConfig for tools to access
|
|
135
147
|
},
|
|
@@ -1644,6 +1656,88 @@ async function filterSkillsByLicense(request, reply) {
|
|
|
1644
1656
|
}
|
|
1645
1657
|
}
|
|
1646
1658
|
|
|
1659
|
+
// src/controllers/tools.ts
|
|
1660
|
+
var import_core11 = require("@axiom-lattice/core");
|
|
1661
|
+
function serializeSchema(schema) {
|
|
1662
|
+
if (!schema) {
|
|
1663
|
+
return void 0;
|
|
1664
|
+
}
|
|
1665
|
+
try {
|
|
1666
|
+
if (schema._def) {
|
|
1667
|
+
const def = schema._def;
|
|
1668
|
+
if (def.typeName === "ZodObject") {
|
|
1669
|
+
const shape = def.shape();
|
|
1670
|
+
const properties = {};
|
|
1671
|
+
const required = [];
|
|
1672
|
+
for (const [key, value] of Object.entries(shape)) {
|
|
1673
|
+
const fieldDef = value._def;
|
|
1674
|
+
if (fieldDef) {
|
|
1675
|
+
properties[key] = {
|
|
1676
|
+
type: fieldDef.typeName === "ZodString" ? "string" : fieldDef.typeName === "ZodNumber" ? "number" : fieldDef.typeName === "ZodBoolean" ? "boolean" : fieldDef.typeName === "ZodArray" ? "array" : fieldDef.typeName === "ZodObject" ? "object" : "unknown",
|
|
1677
|
+
description: fieldDef.description
|
|
1678
|
+
};
|
|
1679
|
+
if (!value.isOptional()) {
|
|
1680
|
+
required.push(key);
|
|
1681
|
+
}
|
|
1682
|
+
}
|
|
1683
|
+
}
|
|
1684
|
+
return {
|
|
1685
|
+
type: "object",
|
|
1686
|
+
properties,
|
|
1687
|
+
required: required.length > 0 ? required : void 0
|
|
1688
|
+
};
|
|
1689
|
+
}
|
|
1690
|
+
}
|
|
1691
|
+
return {
|
|
1692
|
+
type: "object",
|
|
1693
|
+
description: schema.description || "Schema definition"
|
|
1694
|
+
};
|
|
1695
|
+
} catch (error) {
|
|
1696
|
+
return {
|
|
1697
|
+
type: "object",
|
|
1698
|
+
description: "Schema definition"
|
|
1699
|
+
};
|
|
1700
|
+
}
|
|
1701
|
+
}
|
|
1702
|
+
async function getToolConfigs(request, reply) {
|
|
1703
|
+
try {
|
|
1704
|
+
const allLattices = import_core11.toolLatticeManager.getAllLattices();
|
|
1705
|
+
const toolConfigs = allLattices.map((lattice) => {
|
|
1706
|
+
const config = { ...lattice.config };
|
|
1707
|
+
const serializedSchema = config.schema ? serializeSchema(config.schema) : void 0;
|
|
1708
|
+
return {
|
|
1709
|
+
id: lattice.key,
|
|
1710
|
+
name: config.name,
|
|
1711
|
+
description: config.description,
|
|
1712
|
+
schema: serializedSchema,
|
|
1713
|
+
returnDirect: config.returnDirect,
|
|
1714
|
+
needUserApprove: config.needUserApprove
|
|
1715
|
+
};
|
|
1716
|
+
});
|
|
1717
|
+
return reply.send({
|
|
1718
|
+
success: true,
|
|
1719
|
+
message: "Successfully retrieved tool configs",
|
|
1720
|
+
data: {
|
|
1721
|
+
records: toolConfigs,
|
|
1722
|
+
total: toolConfigs.length
|
|
1723
|
+
}
|
|
1724
|
+
});
|
|
1725
|
+
} catch (error) {
|
|
1726
|
+
console.error("Failed to get tool configs", {
|
|
1727
|
+
error: error.message,
|
|
1728
|
+
stack: error.stack
|
|
1729
|
+
});
|
|
1730
|
+
return reply.status(500).send({
|
|
1731
|
+
success: false,
|
|
1732
|
+
message: `Failed to retrieve tool configs: ${error.message}`,
|
|
1733
|
+
data: {
|
|
1734
|
+
records: [],
|
|
1735
|
+
total: 0
|
|
1736
|
+
}
|
|
1737
|
+
});
|
|
1738
|
+
}
|
|
1739
|
+
}
|
|
1740
|
+
|
|
1647
1741
|
// src/schemas/index.ts
|
|
1648
1742
|
var getAllMemoryItemsSchema = {
|
|
1649
1743
|
description: "Get all memory items for an assistant thread",
|
|
@@ -1915,6 +2009,332 @@ var getHealthSchema = {
|
|
|
1915
2009
|
}
|
|
1916
2010
|
};
|
|
1917
2011
|
|
|
2012
|
+
// src/controllers/sandbox.ts
|
|
2013
|
+
var import_stream = require("stream");
|
|
2014
|
+
|
|
2015
|
+
// src/services/sandbox_service.ts
|
|
2016
|
+
var import_core12 = require("@axiom-lattice/core");
|
|
2017
|
+
var ERROR_HTML = `<!DOCTYPE html>
|
|
2018
|
+
<html lang="zh-CN">
|
|
2019
|
+
<head>
|
|
2020
|
+
<meta charset="UTF-8">
|
|
2021
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
2022
|
+
<title>Sandbox \u8FDE\u63A5\u9519\u8BEF</title>
|
|
2023
|
+
<style>
|
|
2024
|
+
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
2025
|
+
body {
|
|
2026
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
2027
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
2028
|
+
min-height: 100vh;
|
|
2029
|
+
display: flex;
|
|
2030
|
+
align-items: center;
|
|
2031
|
+
justify-content: center;
|
|
2032
|
+
padding: 20px;
|
|
2033
|
+
}
|
|
2034
|
+
.container {
|
|
2035
|
+
background: white;
|
|
2036
|
+
border-radius: 16px;
|
|
2037
|
+
padding: 40px;
|
|
2038
|
+
max-width: 500px;
|
|
2039
|
+
width: 100%;
|
|
2040
|
+
box-shadow: 0 20px 60px rgba(0,0,0,0.3);
|
|
2041
|
+
}
|
|
2042
|
+
.error-icon {
|
|
2043
|
+
width: 80px;
|
|
2044
|
+
height: 80px;
|
|
2045
|
+
background: #fee2e2;
|
|
2046
|
+
border-radius: 50%;
|
|
2047
|
+
display: flex;
|
|
2048
|
+
align-items: center;
|
|
2049
|
+
justify-content: center;
|
|
2050
|
+
margin: 0 auto 24px;
|
|
2051
|
+
}
|
|
2052
|
+
.error-icon svg {
|
|
2053
|
+
width: 40px;
|
|
2054
|
+
height: 40px;
|
|
2055
|
+
color: #dc2626;
|
|
2056
|
+
}
|
|
2057
|
+
h1 { color: #1f2937; margin-bottom: 16px; text-align: center; }
|
|
2058
|
+
p { color: #6b7280; margin-bottom: 12px; line-height: 1.6; }
|
|
2059
|
+
.info {
|
|
2060
|
+
background: #f3f4f6;
|
|
2061
|
+
border-radius: 8px;
|
|
2062
|
+
padding: 16px;
|
|
2063
|
+
margin: 20px 0;
|
|
2064
|
+
}
|
|
2065
|
+
.info-item {
|
|
2066
|
+
display: flex;
|
|
2067
|
+
justify-content: space-between;
|
|
2068
|
+
padding: 8px 0;
|
|
2069
|
+
border-bottom: 1px solid #e5e7eb;
|
|
2070
|
+
}
|
|
2071
|
+
.info-item:last-child { border-bottom: none; }
|
|
2072
|
+
.label { color: #6b7280; font-size: 14px; }
|
|
2073
|
+
.value { color: #1f2937; font-weight: 500; font-family: monospace; }
|
|
2074
|
+
.retry-btn {
|
|
2075
|
+
width: 100%;
|
|
2076
|
+
padding: 14px;
|
|
2077
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
2078
|
+
color: white;
|
|
2079
|
+
border: none;
|
|
2080
|
+
border-radius: 8px;
|
|
2081
|
+
font-size: 16px;
|
|
2082
|
+
cursor: pointer;
|
|
2083
|
+
transition: transform 0.2s;
|
|
2084
|
+
}
|
|
2085
|
+
.retry-btn:hover { transform: translateY(-2px); }
|
|
2086
|
+
</style>
|
|
2087
|
+
</head>
|
|
2088
|
+
<body>
|
|
2089
|
+
<div class="container">
|
|
2090
|
+
<div class="error-icon">
|
|
2091
|
+
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
2092
|
+
<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"/>
|
|
2093
|
+
</svg>
|
|
2094
|
+
</div>
|
|
2095
|
+
<h1>\u65E0\u6CD5\u8FDE\u63A5\u5230 Sandbox</h1>
|
|
2096
|
+
<p>\u65E0\u6CD5\u8FDE\u63A5\u5230\u6C99\u7BB1\u73AF\u5883\uFF0C\u8BF7\u68C0\u67E5\u914D\u7F6E\u540E\u91CD\u8BD5\u3002</p>
|
|
2097
|
+
<div class="info">
|
|
2098
|
+
<div class="info-item">
|
|
2099
|
+
<span class="label">Assistant ID</span>
|
|
2100
|
+
<span class="value" id="assistantId">-</span>
|
|
2101
|
+
</div>
|
|
2102
|
+
<div class="info-item">
|
|
2103
|
+
<span class="label">Thread ID</span>
|
|
2104
|
+
<span class="value" id="threadId">-</span>
|
|
2105
|
+
</div>
|
|
2106
|
+
<div class="info-item">
|
|
2107
|
+
<span class="label">\u9694\u79BB\u7EA7\u522B</span>
|
|
2108
|
+
<span class="value" id="isolatedLevel">-</span>
|
|
2109
|
+
</div>
|
|
2110
|
+
<div class="info-item">
|
|
2111
|
+
<span class="label">\u9519\u8BEF\u4FE1\u606F</span>
|
|
2112
|
+
<span class="value" id="errorMsg">-</span>
|
|
2113
|
+
</div>
|
|
2114
|
+
</div>
|
|
2115
|
+
<button class="retry-btn" onclick="window.location.reload()">\u91CD\u65B0\u8FDE\u63A5</button>
|
|
2116
|
+
</div>
|
|
2117
|
+
<script>
|
|
2118
|
+
const params = new URLSearchParams(window.location.search);
|
|
2119
|
+
document.getElementById('assistantId').textContent = params.get('assistantId') || '-';
|
|
2120
|
+
document.getElementById('threadId').textContent = params.get('threadId') || '-';
|
|
2121
|
+
document.getElementById('isolatedLevel').textContent = params.get('isolatedLevel') || '-';
|
|
2122
|
+
document.getElementById('errorMsg').textContent = params.get('error') || '\u672A\u77E5\u9519\u8BEF';
|
|
2123
|
+
</script>
|
|
2124
|
+
</body>
|
|
2125
|
+
</html>`;
|
|
2126
|
+
var SandboxService = class {
|
|
2127
|
+
getSandboxConfig(assistantId) {
|
|
2128
|
+
const agentConfig = (0, import_core12.getAgentConfig)(assistantId);
|
|
2129
|
+
if (!agentConfig) {
|
|
2130
|
+
return null;
|
|
2131
|
+
}
|
|
2132
|
+
const agentLattice = (0, import_core12.getAgentLattice)(assistantId);
|
|
2133
|
+
return agentLattice?.config?.connectedSandbox || null;
|
|
2134
|
+
}
|
|
2135
|
+
computeSandboxName(assistantId, threadId, isolatedLevel) {
|
|
2136
|
+
let sandboxName;
|
|
2137
|
+
switch (isolatedLevel) {
|
|
2138
|
+
case "agent":
|
|
2139
|
+
sandboxName = assistantId;
|
|
2140
|
+
break;
|
|
2141
|
+
case "thread":
|
|
2142
|
+
sandboxName = threadId;
|
|
2143
|
+
break;
|
|
2144
|
+
case "global":
|
|
2145
|
+
default:
|
|
2146
|
+
sandboxName = "global";
|
|
2147
|
+
break;
|
|
2148
|
+
}
|
|
2149
|
+
return (0, import_core12.normalizeSandboxName)(sandboxName);
|
|
2150
|
+
}
|
|
2151
|
+
getTargetUrl(sandboxName) {
|
|
2152
|
+
const sandboxManager = (0, import_core12.getSandBoxManager)("default");
|
|
2153
|
+
return `${sandboxManager.getBaseURL()}/sandbox/${sandboxName}`;
|
|
2154
|
+
}
|
|
2155
|
+
async getVncHtml(sandboxName) {
|
|
2156
|
+
const response = await fetch(`${this.getTargetUrl(sandboxName)}/vnc/index.html`);
|
|
2157
|
+
if (!response.ok) {
|
|
2158
|
+
throw new Error(`Failed to fetch VNC HTML: ${response.statusText}`);
|
|
2159
|
+
}
|
|
2160
|
+
return response.text();
|
|
2161
|
+
}
|
|
2162
|
+
rewriteHtml(html, assistantId, threadId) {
|
|
2163
|
+
const prefix = `/api/assistants/${assistantId}/threads/${threadId}/sandbox/vnc`;
|
|
2164
|
+
let rewritten = html;
|
|
2165
|
+
rewritten = rewritten.replace(
|
|
2166
|
+
/(src|href)=["']([^"']*)["']/g,
|
|
2167
|
+
(match, attr, url) => {
|
|
2168
|
+
if (url.startsWith("http://") || url.startsWith("https://") || url.startsWith("//")) {
|
|
2169
|
+
return match;
|
|
2170
|
+
}
|
|
2171
|
+
const rewrittenUrl = url.startsWith("/") ? `${prefix}${url}` : `${prefix}/${url}`;
|
|
2172
|
+
return `${attr}="${rewrittenUrl}"`;
|
|
2173
|
+
}
|
|
2174
|
+
);
|
|
2175
|
+
rewritten = rewritten.replace(
|
|
2176
|
+
/path=sandbox\/[^&"']+/g,
|
|
2177
|
+
(match) => {
|
|
2178
|
+
return `path=${prefix}/websockify`;
|
|
2179
|
+
}
|
|
2180
|
+
);
|
|
2181
|
+
rewritten = rewritten.replace(
|
|
2182
|
+
/new WebSocket\([^)]*\?path=sandbox[^)]*\)/g,
|
|
2183
|
+
(match) => {
|
|
2184
|
+
return match.replace(/path=sandbox[^)]+/, `path=${prefix}/websockify`);
|
|
2185
|
+
}
|
|
2186
|
+
);
|
|
2187
|
+
return rewritten;
|
|
2188
|
+
}
|
|
2189
|
+
generateErrorHtml(assistantId, threadId, isolatedLevel, errorMessage) {
|
|
2190
|
+
const encodedError = encodeURIComponent(errorMessage);
|
|
2191
|
+
return ERROR_HTML.replace("{assistantId}", assistantId).replace("{threadId}", threadId).replace("{isolatedLevel}", isolatedLevel).replace("{errorMessage}", errorMessage);
|
|
2192
|
+
}
|
|
2193
|
+
};
|
|
2194
|
+
var sandboxService = new SandboxService();
|
|
2195
|
+
|
|
2196
|
+
// src/controllers/sandbox.ts
|
|
2197
|
+
var import_core13 = require("@axiom-lattice/core");
|
|
2198
|
+
function getFilenameFromPath(path) {
|
|
2199
|
+
const segments = path.replace(/\/+$/, "").split("/");
|
|
2200
|
+
return segments[segments.length - 1] || "download";
|
|
2201
|
+
}
|
|
2202
|
+
var EXT_TO_MIME = {
|
|
2203
|
+
".txt": "text/plain",
|
|
2204
|
+
".html": "text/html",
|
|
2205
|
+
".css": "text/css",
|
|
2206
|
+
".js": "application/javascript",
|
|
2207
|
+
".json": "application/json",
|
|
2208
|
+
".pdf": "application/pdf",
|
|
2209
|
+
".png": "image/png",
|
|
2210
|
+
".jpg": "image/jpeg",
|
|
2211
|
+
".jpeg": "image/jpeg",
|
|
2212
|
+
".gif": "image/gif",
|
|
2213
|
+
".webp": "image/webp",
|
|
2214
|
+
".svg": "image/svg+xml",
|
|
2215
|
+
".zip": "application/zip",
|
|
2216
|
+
".csv": "text/csv",
|
|
2217
|
+
".xml": "application/xml"
|
|
2218
|
+
};
|
|
2219
|
+
function getContentTypeFromFilename(filename) {
|
|
2220
|
+
const ext = filename.includes(".") ? filename.slice(filename.lastIndexOf(".")).toLowerCase() : "";
|
|
2221
|
+
return EXT_TO_MIME[ext] ?? "application/octet-stream";
|
|
2222
|
+
}
|
|
2223
|
+
function registerSandboxProxyRoutes(app2) {
|
|
2224
|
+
app2.post(
|
|
2225
|
+
"/api/assistants/:assistantId/threads/:threadId/sandbox/uploadfile",
|
|
2226
|
+
async (request, reply) => {
|
|
2227
|
+
console.log("[Sandbox Upload] Route matched:", request.url);
|
|
2228
|
+
const { assistantId, threadId } = request.params;
|
|
2229
|
+
const sandboxConfig = sandboxService.getSandboxConfig(assistantId);
|
|
2230
|
+
if (!sandboxConfig) {
|
|
2231
|
+
return reply.status(500).send({ error: "Assistant sandbox config not found" });
|
|
2232
|
+
}
|
|
2233
|
+
const { isolatedLevel } = sandboxConfig;
|
|
2234
|
+
const sandboxName = sandboxService.computeSandboxName(
|
|
2235
|
+
assistantId,
|
|
2236
|
+
threadId,
|
|
2237
|
+
isolatedLevel
|
|
2238
|
+
);
|
|
2239
|
+
const sandboxManager = (0, import_core13.getSandBoxManager)("default");
|
|
2240
|
+
const sandbox = await sandboxManager.createSandbox(sandboxName);
|
|
2241
|
+
try {
|
|
2242
|
+
const data = await request.file();
|
|
2243
|
+
if (!data) {
|
|
2244
|
+
return reply.status(400).send({ error: "No file in request" });
|
|
2245
|
+
}
|
|
2246
|
+
const buffer = await data.toBuffer();
|
|
2247
|
+
const pathEntry = data.fields?.path;
|
|
2248
|
+
const pathValue = pathEntry && typeof pathEntry === "object" && "value" in pathEntry ? String(pathEntry.value) : typeof pathEntry === "string" ? pathEntry : void 0;
|
|
2249
|
+
const formData = new FormData();
|
|
2250
|
+
formData.append("file", new Blob([buffer]), data.filename ?? "file");
|
|
2251
|
+
const path = `/home/gem/uploads/${pathValue ? pathValue : ""}${data.filename}`;
|
|
2252
|
+
const uploadResult = await sandbox.file.uploadFile({
|
|
2253
|
+
file: buffer,
|
|
2254
|
+
path
|
|
2255
|
+
});
|
|
2256
|
+
if (!uploadResult.ok) {
|
|
2257
|
+
return reply.status(502).send({ error: `Upload error: ${uploadResult.error}` });
|
|
2258
|
+
}
|
|
2259
|
+
const relativePath = uploadResult.body?.data?.file_path.replace(`/home/gem`, "");
|
|
2260
|
+
const result = { id: relativePath, name: data.filename, size: buffer.length };
|
|
2261
|
+
return reply.status(200).send({ message: "File uploaded successfully", ...result });
|
|
2262
|
+
} catch (error) {
|
|
2263
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2264
|
+
return reply.status(502).send({ error: `Upload proxy error: ${message}` });
|
|
2265
|
+
}
|
|
2266
|
+
}
|
|
2267
|
+
);
|
|
2268
|
+
app2.get(
|
|
2269
|
+
"/api/assistants/:assistantId/threads/:threadId/sandbox/downloadfile",
|
|
2270
|
+
async (request, reply) => {
|
|
2271
|
+
const { assistantId, threadId } = request.params;
|
|
2272
|
+
const { path: filePath } = request.query;
|
|
2273
|
+
if (!filePath || typeof filePath !== "string") {
|
|
2274
|
+
return reply.status(400).send({ error: "Query parameter 'path' is required" });
|
|
2275
|
+
}
|
|
2276
|
+
const sandboxConfig = sandboxService.getSandboxConfig(assistantId);
|
|
2277
|
+
if (!sandboxConfig) {
|
|
2278
|
+
return reply.status(404).send({ error: "Assistant sandbox config not found" });
|
|
2279
|
+
}
|
|
2280
|
+
const { isolatedLevel } = sandboxConfig;
|
|
2281
|
+
const sandboxName = sandboxService.computeSandboxName(
|
|
2282
|
+
assistantId,
|
|
2283
|
+
threadId,
|
|
2284
|
+
isolatedLevel
|
|
2285
|
+
);
|
|
2286
|
+
const sandboxManager = (0, import_core13.getSandBoxManager)("default");
|
|
2287
|
+
const sandbox = await sandboxManager.createSandbox(sandboxName);
|
|
2288
|
+
try {
|
|
2289
|
+
const resolvedPath = filePath.startsWith("/home/gem") ? filePath : `/home/gem/${filePath.replace(/^\//, "")}`;
|
|
2290
|
+
const filename = getFilenameFromPath(resolvedPath);
|
|
2291
|
+
const inferredContentType = getContentTypeFromFilename(filename);
|
|
2292
|
+
const downloadResult = await sandbox.file.downloadFile({
|
|
2293
|
+
path: resolvedPath
|
|
2294
|
+
});
|
|
2295
|
+
if (!downloadResult.ok) {
|
|
2296
|
+
return reply.status(502).send({
|
|
2297
|
+
error: `Download error: ${JSON.stringify(downloadResult.error)}`
|
|
2298
|
+
});
|
|
2299
|
+
}
|
|
2300
|
+
const body = downloadResult.body;
|
|
2301
|
+
if (typeof body?.stream === "function") {
|
|
2302
|
+
const webStream = body.stream();
|
|
2303
|
+
const nodeStream = import_stream.Readable.fromWeb(webStream);
|
|
2304
|
+
const contentType2 = body.contentType ?? inferredContentType;
|
|
2305
|
+
const contentDisposition2 = body.contentDisposition ?? `inline; filename="${filename.replace(/"/g, '\\"')}"; filename*=UTF-8''${encodeURIComponent(filename)}`;
|
|
2306
|
+
reply = reply.status(200).type(contentType2).header("Content-Disposition", contentDisposition2).send(nodeStream);
|
|
2307
|
+
return reply;
|
|
2308
|
+
}
|
|
2309
|
+
const bodyUnknown = downloadResult.body;
|
|
2310
|
+
let buf;
|
|
2311
|
+
let contentType = inferredContentType;
|
|
2312
|
+
let contentDisposition = `inline; filename="${filename.replace(/"/g, '\\"')}"; filename*=UTF-8''${encodeURIComponent(filename)}`;
|
|
2313
|
+
if (bodyUnknown instanceof ArrayBuffer) {
|
|
2314
|
+
buf = Buffer.from(bodyUnknown);
|
|
2315
|
+
} else if (bodyUnknown instanceof Buffer) {
|
|
2316
|
+
buf = bodyUnknown;
|
|
2317
|
+
} else if (bodyUnknown && typeof bodyUnknown.arrayBuffer === "function") {
|
|
2318
|
+
const res = bodyUnknown;
|
|
2319
|
+
buf = Buffer.from(await res.arrayBuffer());
|
|
2320
|
+
if (res.headers?.get("content-type")) contentType = res.headers.get("content-type");
|
|
2321
|
+
if (res.headers?.get("content-disposition")) contentDisposition = res.headers.get("content-disposition");
|
|
2322
|
+
} else if (bodyUnknown && typeof bodyUnknown.blob === "function") {
|
|
2323
|
+
const blob = await bodyUnknown.blob();
|
|
2324
|
+
buf = Buffer.from(await blob.arrayBuffer());
|
|
2325
|
+
} else {
|
|
2326
|
+
return reply.status(502).send({ error: "Unexpected download response format" });
|
|
2327
|
+
}
|
|
2328
|
+
reply = reply.status(200).type(contentType).header("Content-Disposition", contentDisposition).send(buf);
|
|
2329
|
+
return reply;
|
|
2330
|
+
} catch (error) {
|
|
2331
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2332
|
+
return reply.status(502).send({ error: `Download proxy error: ${message}` });
|
|
2333
|
+
}
|
|
2334
|
+
}
|
|
2335
|
+
);
|
|
2336
|
+
}
|
|
2337
|
+
|
|
1918
2338
|
// src/routes/index.ts
|
|
1919
2339
|
var registerLatticeRoutes = (app2) => {
|
|
1920
2340
|
app2.post("/api/runs", createRun);
|
|
@@ -1990,6 +2410,7 @@ var registerLatticeRoutes = (app2) => {
|
|
|
1990
2410
|
);
|
|
1991
2411
|
app2.get("/api/models", getModels);
|
|
1992
2412
|
app2.put("/api/models", updateModels);
|
|
2413
|
+
app2.get("/api/tools", getToolConfigs);
|
|
1993
2414
|
app2.get(
|
|
1994
2415
|
"/health",
|
|
1995
2416
|
{ schema: getHealthSchema },
|
|
@@ -2032,6 +2453,7 @@ var registerLatticeRoutes = (app2) => {
|
|
|
2032
2453
|
"/api/skills/filter/license",
|
|
2033
2454
|
filterSkillsByLicense
|
|
2034
2455
|
);
|
|
2456
|
+
registerSandboxProxyRoutes(app2);
|
|
2035
2457
|
};
|
|
2036
2458
|
|
|
2037
2459
|
// src/swagger.ts
|
|
@@ -2097,7 +2519,7 @@ var configureSwagger = async (app2, customSwaggerConfig, customSwaggerUiConfig)
|
|
|
2097
2519
|
};
|
|
2098
2520
|
|
|
2099
2521
|
// src/services/agent_task_consumer.ts
|
|
2100
|
-
var
|
|
2522
|
+
var import_core14 = require("@axiom-lattice/core");
|
|
2101
2523
|
var handleAgentTask = async (taskRequest, retryCount = 0) => {
|
|
2102
2524
|
const {
|
|
2103
2525
|
assistant_id,
|
|
@@ -2161,7 +2583,7 @@ var handleAgentTask = async (taskRequest, retryCount = 0) => {
|
|
|
2161
2583
|
}
|
|
2162
2584
|
if (callback_event) {
|
|
2163
2585
|
const state = await agent_state({ assistant_id, thread_id });
|
|
2164
|
-
|
|
2586
|
+
import_core14.eventBus.publish(callback_event, {
|
|
2165
2587
|
success: true,
|
|
2166
2588
|
state,
|
|
2167
2589
|
config: { assistant_id, thread_id, tenant_id }
|
|
@@ -2175,7 +2597,7 @@ var handleAgentTask = async (taskRequest, retryCount = 0) => {
|
|
|
2175
2597
|
await response.text();
|
|
2176
2598
|
if (callback_event) {
|
|
2177
2599
|
const state = await agent_state({ assistant_id, thread_id });
|
|
2178
|
-
|
|
2600
|
+
import_core14.eventBus.publish(callback_event, {
|
|
2179
2601
|
success: true,
|
|
2180
2602
|
state,
|
|
2181
2603
|
config: { assistant_id, thread_id, tenant_id }
|
|
@@ -2202,7 +2624,7 @@ var handleAgentTask = async (taskRequest, retryCount = 0) => {
|
|
|
2202
2624
|
return handleAgentTask(taskRequest, nextRetryCount);
|
|
2203
2625
|
}
|
|
2204
2626
|
if (callback_event) {
|
|
2205
|
-
|
|
2627
|
+
import_core14.eventBus.publish(callback_event, {
|
|
2206
2628
|
success: false,
|
|
2207
2629
|
error: error instanceof Error ? error.message : String(error),
|
|
2208
2630
|
config: { assistant_id, thread_id, tenant_id }
|
|
@@ -2240,7 +2662,7 @@ var _AgentTaskConsumer = class _AgentTaskConsumer {
|
|
|
2240
2662
|
* 初始化事件监听和队列轮询
|
|
2241
2663
|
*/
|
|
2242
2664
|
initialize() {
|
|
2243
|
-
|
|
2665
|
+
import_core14.eventBus.subscribe(import_core14.AGENT_TASK_EVENT, this.trigger_agent_task.bind(this));
|
|
2244
2666
|
this.startPollingQueue();
|
|
2245
2667
|
console.log("Agent\u4EFB\u52A1\u6D88\u8D39\u8005\u5DF2\u542F\u52A8\u5E76\u76D1\u542C\u4EFB\u52A1\u4E8B\u4EF6\u548C\u961F\u5217");
|
|
2246
2668
|
}
|
|
@@ -2359,7 +2781,7 @@ var _AgentTaskConsumer = class _AgentTaskConsumer {
|
|
|
2359
2781
|
handleAgentTask(taskRequest).catch((error) => {
|
|
2360
2782
|
console.error("\u5904\u7406Agent\u4EFB\u52A1\u65F6\u53D1\u751F\u672A\u6355\u83B7\u7684\u9519\u8BEF:", error);
|
|
2361
2783
|
if (taskRequest.callback_event) {
|
|
2362
|
-
|
|
2784
|
+
import_core14.eventBus.publish(taskRequest.callback_event, {
|
|
2363
2785
|
success: false,
|
|
2364
2786
|
error: error instanceof Error ? error.message : String(error),
|
|
2365
2787
|
config: {
|
|
@@ -2379,7 +2801,7 @@ _AgentTaskConsumer.agent_run_endpoint = "http://localhost:4001/api/runs";
|
|
|
2379
2801
|
var AgentTaskConsumer = _AgentTaskConsumer;
|
|
2380
2802
|
|
|
2381
2803
|
// src/index.ts
|
|
2382
|
-
var
|
|
2804
|
+
var import_core15 = require("@axiom-lattice/core");
|
|
2383
2805
|
var import_protocols2 = require("@axiom-lattice/protocols");
|
|
2384
2806
|
process.on("unhandledRejection", (reason, promise) => {
|
|
2385
2807
|
console.error("\u672A\u5904\u7406\u7684Promise\u62D2\u7EDD:", reason);
|
|
@@ -2394,11 +2816,11 @@ var DEFAULT_LOGGER_CONFIG = {
|
|
|
2394
2816
|
var loggerLattice = initializeLogger(DEFAULT_LOGGER_CONFIG);
|
|
2395
2817
|
var logger = loggerLattice.client;
|
|
2396
2818
|
function initializeLogger(config) {
|
|
2397
|
-
if (
|
|
2398
|
-
|
|
2819
|
+
if (import_core15.loggerLatticeManager.hasLattice("default")) {
|
|
2820
|
+
import_core15.loggerLatticeManager.removeLattice("default");
|
|
2399
2821
|
}
|
|
2400
|
-
(0,
|
|
2401
|
-
return (0,
|
|
2822
|
+
(0, import_core15.registerLoggerLattice)("default", config);
|
|
2823
|
+
return (0, import_core15.getLoggerLattice)("default");
|
|
2402
2824
|
}
|
|
2403
2825
|
var app = (0, import_fastify.default)({
|
|
2404
2826
|
logger: false,
|
|
@@ -2444,12 +2866,20 @@ app.register(import_cors.default, {
|
|
|
2444
2866
|
"Authorization",
|
|
2445
2867
|
"X-Requested-With",
|
|
2446
2868
|
"x-tenant-id",
|
|
2447
|
-
"x-request-id"
|
|
2869
|
+
"x-request-id",
|
|
2870
|
+
"x-assistant-id",
|
|
2871
|
+
"x-thread-id"
|
|
2448
2872
|
],
|
|
2449
2873
|
exposedHeaders: ["Content-Type"],
|
|
2450
2874
|
credentials: true
|
|
2451
2875
|
});
|
|
2452
2876
|
app.register(import_sensible.default);
|
|
2877
|
+
app.register(import_multipart.default, {
|
|
2878
|
+
limits: {
|
|
2879
|
+
fileSize: Number(process.env.BODY_LIMIT) || 50 * 1024 * 1024
|
|
2880
|
+
}
|
|
2881
|
+
});
|
|
2882
|
+
app.register(import_websocket.default);
|
|
2453
2883
|
app.setErrorHandler((error, request, reply) => {
|
|
2454
2884
|
const getHeaderValue = (header) => {
|
|
2455
2885
|
if (Array.isArray(header)) {
|