aws-runtime-bridge 1.9.2 → 1.9.5
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/dist/config.d.ts +5 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +25 -0
- package/dist/index.js +19 -3
- package/dist/middleware/auth.d.ts +8 -0
- package/dist/middleware/auth.d.ts.map +1 -1
- package/dist/middleware/auth.js +44 -0
- package/dist/routes/dashboard.d.ts +8 -0
- package/dist/routes/dashboard.d.ts.map +1 -0
- package/dist/routes/dashboard.js +1347 -0
- package/dist/routes/instance.d.ts +1 -0
- package/dist/routes/instance.d.ts.map +1 -1
- package/dist/routes/instance.js +53 -4
- package/dist/routes/instance.test.js +4 -0
- package/dist/routes/processes.js +1 -1
- package/dist/routes/runtime-binding.d.ts.map +1 -1
- package/dist/routes/runtime-binding.js +37 -0
- package/dist/routes/sessions.js +7 -7
- package/dist/routes/terminal.d.ts.map +1 -1
- package/dist/routes/terminal.js +137 -33
- package/dist/services/agent-process-manager.d.ts +12 -0
- package/dist/services/agent-process-manager.d.ts.map +1 -1
- package/dist/services/agent-process-manager.js +47 -13
- package/dist/services/orphan-monitor.js +2 -2
- package/dist/services/panel-auth.d.ts +26 -0
- package/dist/services/panel-auth.d.ts.map +1 -0
- package/dist/services/panel-auth.js +105 -0
- package/dist/services/process-detector.d.ts +16 -9
- package/dist/services/process-detector.d.ts.map +1 -1
- package/dist/services/process-detector.js +136 -66
- package/dist/services/session-output.d.ts.map +1 -1
- package/dist/services/session-output.js +106 -6
- package/package.json +1 -1
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* 管理终端会话的输出缓冲和刷新机制
|
|
5
5
|
*/
|
|
6
6
|
import axios from "axios";
|
|
7
|
+
import { requestRuntimeAccessTokenRefreshForServer } from "../services/auto-register.js";
|
|
7
8
|
import { resolveSchedulerBaseUrlFrom } from "../config.js";
|
|
8
9
|
import { logger } from "../utils/logger.js";
|
|
9
10
|
import { getRuntimeAccessToken } from "./runtime-binding.js";
|
|
@@ -22,6 +23,42 @@ function resolveRuntimeCallbackBaseUrl(options) {
|
|
|
22
23
|
}
|
|
23
24
|
/** 输出刷新防抖时间:合并启动期高频小块输出,降低 HTTP/WebSocket 压力。 */
|
|
24
25
|
const OUTPUT_FLUSH_DEBOUNCE_MS = 100;
|
|
26
|
+
function getAxiosStatusCode(error) {
|
|
27
|
+
if (typeof error !== "object" || error === null)
|
|
28
|
+
return undefined;
|
|
29
|
+
const response = error.response;
|
|
30
|
+
if (typeof response !== "object" || response === null)
|
|
31
|
+
return undefined;
|
|
32
|
+
const status = response.status;
|
|
33
|
+
return typeof status === "number" ? status : undefined;
|
|
34
|
+
}
|
|
35
|
+
/** 防止并发回调同时触发多次 token 刷新。 */
|
|
36
|
+
let tokenRefreshPromise = null;
|
|
37
|
+
async function tryRefreshRuntimeToken(serverBaseUrl) {
|
|
38
|
+
if (tokenRefreshPromise)
|
|
39
|
+
return tokenRefreshPromise;
|
|
40
|
+
tokenRefreshPromise = (async () => {
|
|
41
|
+
try {
|
|
42
|
+
const result = await requestRuntimeAccessTokenRefreshForServer(serverBaseUrl);
|
|
43
|
+
if (result.success && result.runtimeAccessToken) {
|
|
44
|
+
logger.info("[session-output] Runtime token refreshed after 401");
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
logger.warn("[session-output] Runtime token refresh failed", { error: result.error });
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
logger.warn("[session-output] Runtime token refresh threw", { error });
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
})();
|
|
55
|
+
try {
|
|
56
|
+
return await tokenRefreshPromise;
|
|
57
|
+
}
|
|
58
|
+
finally {
|
|
59
|
+
tokenRefreshPromise = null;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
25
62
|
/** 单个会话待发送输出上限,避免调度器不可达时内存无限增长。 */
|
|
26
63
|
const MAX_PENDING_OUTPUT_CHARS = 64 * 1024;
|
|
27
64
|
/** 单次回调最大发送量,避免一次 POST 携带过大的终端噪声。 */
|
|
@@ -66,6 +103,23 @@ export async function sendStatus(agentId, sessionId, status, actionInfo, usage,
|
|
|
66
103
|
return await axios.post(`${callbackBaseUrl}/api/runtime/callback/status`, payload, { headers });
|
|
67
104
|
}
|
|
68
105
|
catch (error) {
|
|
106
|
+
if (getAxiosStatusCode(error) === 401) {
|
|
107
|
+
const refreshed = await tryRefreshRuntimeToken(callbackBaseUrl);
|
|
108
|
+
if (refreshed) {
|
|
109
|
+
const retryHeaders = runtimeAuthHeaders(authOptions, callbackBaseUrl);
|
|
110
|
+
if (retryHeaders) {
|
|
111
|
+
try {
|
|
112
|
+
return await axios.post(`${callbackBaseUrl}/api/runtime/callback/status`, payload, { headers: retryHeaders });
|
|
113
|
+
}
|
|
114
|
+
catch (retryError) {
|
|
115
|
+
logger.warn("Runtime status callback retry failed after token refresh", {
|
|
116
|
+
agentId, sessionId, status, error: retryError,
|
|
117
|
+
});
|
|
118
|
+
return undefined;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
69
123
|
logger.warn("Runtime status callback failed", {
|
|
70
124
|
agentId,
|
|
71
125
|
sessionId,
|
|
@@ -85,8 +139,8 @@ export async function sendStatus(agentId, sessionId, status, actionInfo, usage,
|
|
|
85
139
|
* @param seq - 序列号
|
|
86
140
|
*/
|
|
87
141
|
export async function sendOutput(agentId, output, sessionId, seq, metadata, authOptions) {
|
|
142
|
+
const callbackBaseUrl = resolveRuntimeCallbackBaseUrl(authOptions);
|
|
88
143
|
try {
|
|
89
|
-
const callbackBaseUrl = resolveRuntimeCallbackBaseUrl(authOptions);
|
|
90
144
|
const headers = runtimeAuthHeaders(authOptions, callbackBaseUrl);
|
|
91
145
|
if (!headers) {
|
|
92
146
|
logger.warn("Skip runtime output callback because runtime token is missing", {
|
|
@@ -99,6 +153,21 @@ export async function sendOutput(agentId, output, sessionId, seq, metadata, auth
|
|
|
99
153
|
await axios.post(`${callbackBaseUrl}/api/runtime/callback/output`, { agentId, output, sessionId, seq, ...metadata }, { headers });
|
|
100
154
|
}
|
|
101
155
|
catch (error) {
|
|
156
|
+
if (getAxiosStatusCode(error) === 401) {
|
|
157
|
+
const refreshed = await tryRefreshRuntimeToken(callbackBaseUrl);
|
|
158
|
+
if (refreshed) {
|
|
159
|
+
const retryHeaders = runtimeAuthHeaders(authOptions, callbackBaseUrl);
|
|
160
|
+
if (retryHeaders) {
|
|
161
|
+
try {
|
|
162
|
+
await axios.post(`${callbackBaseUrl}/api/runtime/callback/output`, { agentId, output, sessionId, seq, ...metadata }, { headers: retryHeaders });
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
catch {
|
|
166
|
+
// retry also failed
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
102
171
|
logger.warn("Runtime output callback failed", {
|
|
103
172
|
agentId,
|
|
104
173
|
sessionId,
|
|
@@ -114,15 +183,31 @@ export async function sendOutput(agentId, output, sessionId, seq, metadata, auth
|
|
|
114
183
|
* @param questions - 结构化问题列表
|
|
115
184
|
*/
|
|
116
185
|
export async function sendQuestionRequest(agentId, sessionId, questions, authOptions) {
|
|
186
|
+
const callbackBaseUrl = resolveRuntimeCallbackBaseUrl(authOptions);
|
|
187
|
+
const payload = { agentId, sessionId, questions };
|
|
117
188
|
try {
|
|
118
|
-
const callbackBaseUrl = resolveRuntimeCallbackBaseUrl(authOptions);
|
|
119
189
|
const headers = runtimeAuthHeaders(authOptions, callbackBaseUrl);
|
|
120
190
|
if (!headers) {
|
|
121
191
|
return;
|
|
122
192
|
}
|
|
123
|
-
await axios.post(`${callbackBaseUrl}/api/runtime/callback/question`,
|
|
193
|
+
await axios.post(`${callbackBaseUrl}/api/runtime/callback/question`, payload, { headers });
|
|
124
194
|
}
|
|
125
|
-
catch {
|
|
195
|
+
catch (error) {
|
|
196
|
+
if (getAxiosStatusCode(error) === 401) {
|
|
197
|
+
const refreshed = await tryRefreshRuntimeToken(callbackBaseUrl);
|
|
198
|
+
if (refreshed) {
|
|
199
|
+
const retryHeaders = runtimeAuthHeaders(authOptions, callbackBaseUrl);
|
|
200
|
+
if (retryHeaders) {
|
|
201
|
+
try {
|
|
202
|
+
await axios.post(`${callbackBaseUrl}/api/runtime/callback/question`, payload, { headers: retryHeaders });
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
catch {
|
|
206
|
+
// retry also failed
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
126
211
|
// ignore transient callback failures
|
|
127
212
|
}
|
|
128
213
|
}
|
|
@@ -130,15 +215,30 @@ export async function sendQuestionRequest(agentId, sessionId, questions, authOpt
|
|
|
130
215
|
* 发送工作区文件变更事件到调度器,由调度器通过 WebSocket 通知前端刷新预览。
|
|
131
216
|
*/
|
|
132
217
|
export async function sendFileChanged(payload) {
|
|
218
|
+
const callbackBaseUrl = resolveRuntimeCallbackBaseUrl();
|
|
133
219
|
try {
|
|
134
|
-
const callbackBaseUrl = resolveRuntimeCallbackBaseUrl();
|
|
135
220
|
const headers = runtimeAuthHeaders(undefined, callbackBaseUrl);
|
|
136
221
|
if (!headers) {
|
|
137
222
|
return;
|
|
138
223
|
}
|
|
139
224
|
await axios.post(`${callbackBaseUrl}/api/runtime/callback/file-changed`, payload, { headers });
|
|
140
225
|
}
|
|
141
|
-
catch {
|
|
226
|
+
catch (error) {
|
|
227
|
+
if (getAxiosStatusCode(error) === 401) {
|
|
228
|
+
const refreshed = await tryRefreshRuntimeToken(callbackBaseUrl);
|
|
229
|
+
if (refreshed) {
|
|
230
|
+
const retryHeaders = runtimeAuthHeaders(undefined, callbackBaseUrl);
|
|
231
|
+
if (retryHeaders) {
|
|
232
|
+
try {
|
|
233
|
+
await axios.post(`${callbackBaseUrl}/api/runtime/callback/file-changed`, payload, { headers: retryHeaders });
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
catch {
|
|
237
|
+
// retry also failed
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
142
242
|
// ignore transient callback failures
|
|
143
243
|
}
|
|
144
244
|
}
|