@downcity/agent 1.1.113 → 1.1.118
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/bin/agent/local/Agent.d.ts +22 -0
- package/bin/agent/local/Agent.d.ts.map +1 -1
- package/bin/agent/local/Agent.js +31 -0
- package/bin/agent/local/Agent.js.map +1 -1
- package/bin/agent/local/services/AgentAssemblyService.d.ts +4 -0
- package/bin/agent/local/services/AgentAssemblyService.d.ts.map +1 -1
- package/bin/agent/local/services/AgentAssemblyService.js +18 -2
- package/bin/agent/local/services/AgentAssemblyService.js.map +1 -1
- package/bin/agent/local/services/AgentLifecycleService.d.ts +6 -0
- package/bin/agent/local/services/AgentLifecycleService.d.ts.map +1 -1
- package/bin/agent/local/services/AgentLifecycleService.js +4 -0
- package/bin/agent/local/services/AgentLifecycleService.js.map +1 -1
- package/bin/agent/remote/RemoteAgent.d.ts +18 -1
- package/bin/agent/remote/RemoteAgent.d.ts.map +1 -1
- package/bin/agent/remote/RemoteAgent.js +19 -1
- package/bin/agent/remote/RemoteAgent.js.map +1 -1
- package/bin/agent/remote/RemoteTransport.d.ts +11 -0
- package/bin/agent/remote/RemoteTransport.d.ts.map +1 -1
- package/bin/agent/remote/transports/HttpRemoteAgentTransport.d.ts +9 -0
- package/bin/agent/remote/transports/HttpRemoteAgentTransport.d.ts.map +1 -1
- package/bin/agent/remote/transports/HttpRemoteAgentTransport.js +28 -0
- package/bin/agent/remote/transports/HttpRemoteAgentTransport.js.map +1 -1
- package/bin/agent/remote/transports/RpcRemoteAgentTransport.d.ts +8 -0
- package/bin/agent/remote/transports/RpcRemoteAgentTransport.d.ts.map +1 -1
- package/bin/agent/remote/transports/RpcRemoteAgentTransport.js +9 -0
- package/bin/agent/remote/transports/RpcRemoteAgentTransport.js.map +1 -1
- package/bin/executor/Executor.d.ts.map +1 -1
- package/bin/executor/Executor.js +7 -1
- package/bin/executor/Executor.js.map +1 -1
- package/bin/index.d.ts +0 -1
- package/bin/index.d.ts.map +1 -1
- package/bin/index.js +0 -1
- package/bin/index.js.map +1 -1
- package/bin/rpc/Client.d.ts +13 -0
- package/bin/rpc/Client.d.ts.map +1 -1
- package/bin/rpc/Client.js +31 -0
- package/bin/rpc/Client.js.map +1 -1
- package/bin/rpc/server/InternalHandlers.d.ts.map +1 -1
- package/bin/rpc/server/InternalHandlers.js +30 -0
- package/bin/rpc/server/InternalHandlers.js.map +1 -1
- package/bin/rpc/server/ServerTypes.d.ts +5 -0
- package/bin/rpc/server/ServerTypes.d.ts.map +1 -1
- package/bin/types/agent/AgentOptions.d.ts +9 -0
- package/bin/types/agent/AgentOptions.d.ts.map +1 -1
- package/bin/types/config/DowncityConfig.d.ts +2 -2
- package/bin/types/config/DowncityConfig.d.ts.map +1 -1
- package/bin/types/rpc/RpcProtocol.d.ts +25 -0
- package/bin/types/rpc/RpcProtocol.d.ts.map +1 -1
- package/package.json +4 -3
- package/scripts/linux-bubblewrap-sandbox.test.mjs +1 -1
- package/scripts/shell-sandbox-preflight.test.mjs +1 -1
- package/src/agent/local/Agent.ts +38 -0
- package/src/agent/local/services/AgentAssemblyService.ts +23 -2
- package/src/agent/local/services/AgentLifecycleService.ts +11 -0
- package/src/agent/remote/RemoteAgent.ts +26 -1
- package/src/agent/remote/RemoteTransport.ts +10 -0
- package/src/agent/remote/transports/HttpRemoteAgentTransport.ts +45 -0
- package/src/agent/remote/transports/RpcRemoteAgentTransport.ts +16 -0
- package/src/executor/Executor.ts +12 -2
- package/src/index.ts +0 -1
- package/src/rpc/Client.ts +38 -0
- package/src/rpc/server/InternalHandlers.ts +31 -0
- package/src/rpc/server/ServerTypes.ts +5 -0
- package/src/types/agent/AgentOptions.ts +10 -0
- package/src/types/config/DowncityConfig.ts +2 -2
- package/src/types/rpc/RpcProtocol.ts +28 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/bin/executor/tools/shell/ShellToolBridge.d.ts +0 -79
- package/bin/executor/tools/shell/ShellToolBridge.d.ts.map +0 -1
- package/bin/executor/tools/shell/ShellToolBridge.js +0 -320
- package/bin/executor/tools/shell/ShellToolBridge.js.map +0 -1
- package/bin/executor/tools/shell/ShellToolDefinition.d.ts +0 -116
- package/bin/executor/tools/shell/ShellToolDefinition.d.ts.map +0 -1
- package/bin/executor/tools/shell/ShellToolDefinition.js +0 -369
- package/bin/executor/tools/shell/ShellToolDefinition.js.map +0 -1
- package/bin/executor/tools/shell/ShellToolFormatting.d.ts +0 -17
- package/bin/executor/tools/shell/ShellToolFormatting.d.ts.map +0 -1
- package/bin/executor/tools/shell/ShellToolFormatting.js +0 -36
- package/bin/executor/tools/shell/ShellToolFormatting.js.map +0 -1
- package/bin/executor/tools/shell/ShellToolSchemas.d.ts +0 -61
- package/bin/executor/tools/shell/ShellToolSchemas.d.ts.map +0 -1
- package/bin/executor/tools/shell/ShellToolSchemas.js +0 -130
- package/bin/executor/tools/shell/ShellToolSchemas.js.map +0 -1
- package/bin/executor/tools/shell/types/Shell.d.ts +0 -115
- package/bin/executor/tools/shell/types/Shell.d.ts.map +0 -1
- package/bin/executor/tools/shell/types/Shell.js +0 -9
- package/bin/executor/tools/shell/types/Shell.js.map +0 -1
- package/bin/executor/tools/shell/types/ShellPlugin.d.ts +0 -258
- package/bin/executor/tools/shell/types/ShellPlugin.d.ts.map +0 -1
- package/bin/executor/tools/shell/types/ShellPlugin.js +0 -9
- package/bin/executor/tools/shell/types/ShellPlugin.js.map +0 -1
- package/bin/sandbox/LinuxBubblewrapSandbox.d.ts +0 -19
- package/bin/sandbox/LinuxBubblewrapSandbox.d.ts.map +0 -1
- package/bin/sandbox/LinuxBubblewrapSandbox.js +0 -186
- package/bin/sandbox/LinuxBubblewrapSandbox.js.map +0 -1
- package/bin/sandbox/MacOsSeatbeltSandbox.d.ts +0 -16
- package/bin/sandbox/MacOsSeatbeltSandbox.d.ts.map +0 -1
- package/bin/sandbox/MacOsSeatbeltSandbox.js +0 -154
- package/bin/sandbox/MacOsSeatbeltSandbox.js.map +0 -1
- package/bin/sandbox/SandboxConfigResolver.d.ts +0 -37
- package/bin/sandbox/SandboxConfigResolver.d.ts.map +0 -1
- package/bin/sandbox/SandboxConfigResolver.js +0 -130
- package/bin/sandbox/SandboxConfigResolver.js.map +0 -1
- package/bin/sandbox/SandboxPreflight.d.ts +0 -73
- package/bin/sandbox/SandboxPreflight.d.ts.map +0 -1
- package/bin/sandbox/SandboxPreflight.js +0 -122
- package/bin/sandbox/SandboxPreflight.js.map +0 -1
- package/bin/sandbox/SandboxRunner.d.ts +0 -61
- package/bin/sandbox/SandboxRunner.d.ts.map +0 -1
- package/bin/sandbox/SandboxRunner.js +0 -107
- package/bin/sandbox/SandboxRunner.js.map +0 -1
- package/bin/sandbox/UnrestrictedSandbox.d.ts +0 -16
- package/bin/sandbox/UnrestrictedSandbox.d.ts.map +0 -1
- package/bin/sandbox/UnrestrictedSandbox.js +0 -39
- package/bin/sandbox/UnrestrictedSandbox.js.map +0 -1
- package/bin/sandbox/types/Sandbox.d.ts +0 -130
- package/bin/sandbox/types/Sandbox.d.ts.map +0 -1
- package/bin/sandbox/types/Sandbox.js +0 -10
- package/bin/sandbox/types/Sandbox.js.map +0 -1
- package/bin/sandbox/types/SandboxRuntime.d.ts +0 -370
- package/bin/sandbox/types/SandboxRuntime.d.ts.map +0 -1
- package/bin/sandbox/types/SandboxRuntime.js +0 -10
- package/bin/sandbox/types/SandboxRuntime.js.map +0 -1
- package/src/executor/tools/shell/ShellToolBridge.ts +0 -412
- package/src/executor/tools/shell/ShellToolDefinition.ts +0 -524
- package/src/executor/tools/shell/ShellToolFormatting.ts +0 -34
- package/src/executor/tools/shell/ShellToolSchemas.ts +0 -139
- package/src/executor/tools/shell/types/Shell.ts +0 -123
- package/src/executor/tools/shell/types/ShellPlugin.ts +0 -278
- package/src/sandbox/LinuxBubblewrapSandbox.ts +0 -222
- package/src/sandbox/MacOsSeatbeltSandbox.ts +0 -191
- package/src/sandbox/SandboxConfigResolver.ts +0 -152
- package/src/sandbox/SandboxPreflight.ts +0 -205
- package/src/sandbox/SandboxRunner.ts +0 -151
- package/src/sandbox/UnrestrictedSandbox.ts +0 -53
- package/src/sandbox/types/Sandbox.ts +0 -144
- package/src/sandbox/types/SandboxRuntime.ts +0 -440
package/src/agent/local/Agent.ts
CHANGED
|
@@ -24,6 +24,11 @@ import type {
|
|
|
24
24
|
AgentStartResult,
|
|
25
25
|
AgentStopResult,
|
|
26
26
|
} from "@/types/agent/AgentTypes.js";
|
|
27
|
+
import type {
|
|
28
|
+
ShellApprovalDecisionResult,
|
|
29
|
+
ShellApprovalView,
|
|
30
|
+
Shell,
|
|
31
|
+
} from "@downcity/shell";
|
|
27
32
|
import { PluginRegistry } from "@/plugin/core/PluginRegistry.js";
|
|
28
33
|
import { Logger } from "@/utils/logger/Logger.js";
|
|
29
34
|
import { normalizeInstructionInput } from "@/agent/local/AgentInstructions.js";
|
|
@@ -53,6 +58,7 @@ export class Agent {
|
|
|
53
58
|
private readonly SessionClass: AgentOptions["Session"];
|
|
54
59
|
private readonly sessionManager: AgentSessionManager;
|
|
55
60
|
private readonly lifecycleService: AgentLifecycleService;
|
|
61
|
+
private readonly shell?: AgentOptions["shell"];
|
|
56
62
|
|
|
57
63
|
private instruction: string[];
|
|
58
64
|
|
|
@@ -88,6 +94,7 @@ export class Agent {
|
|
|
88
94
|
this.config = assembly.config;
|
|
89
95
|
this.env = assembly.env;
|
|
90
96
|
this.instruction = assembly.instruction;
|
|
97
|
+
this.shell = assembly.shell;
|
|
91
98
|
|
|
92
99
|
this.sessionManager = this.create_session_manager(assembly);
|
|
93
100
|
session_manager_ref = this.sessionManager;
|
|
@@ -96,6 +103,7 @@ export class Agent {
|
|
|
96
103
|
agent_context: this.agentContext,
|
|
97
104
|
session_collection: this.sessionManager.get_session_collection(),
|
|
98
105
|
get_runtime: () => this.runtime,
|
|
106
|
+
get_shell: () => this.shell,
|
|
99
107
|
});
|
|
100
108
|
}
|
|
101
109
|
|
|
@@ -136,6 +144,29 @@ export class Agent {
|
|
|
136
144
|
return await this.lifecycleService.stop();
|
|
137
145
|
}
|
|
138
146
|
|
|
147
|
+
/**
|
|
148
|
+
* 列出当前 shell pending approvals。
|
|
149
|
+
*/
|
|
150
|
+
approvals(): ShellApprovalView[] {
|
|
151
|
+
return this.shell?.approvals() || [];
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* 批准当前 shell pending approval。
|
|
156
|
+
*/
|
|
157
|
+
async approve(input: { approval_id: string }): Promise<ShellApprovalDecisionResult> {
|
|
158
|
+
if (!this.shell) throw new Error("Agent shell is not configured");
|
|
159
|
+
return await this.shell.approve(input);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* 拒绝当前 shell pending approval。
|
|
164
|
+
*/
|
|
165
|
+
async deny(input: { approval_id: string }): Promise<ShellApprovalDecisionResult> {
|
|
166
|
+
if (!this.shell) throw new Error("Agent shell is not configured");
|
|
167
|
+
return await this.shell.deny(input);
|
|
168
|
+
}
|
|
169
|
+
|
|
139
170
|
/**
|
|
140
171
|
* 更新当前 SDK Agent 的静态基础指令。
|
|
141
172
|
*/
|
|
@@ -178,6 +209,13 @@ export class Agent {
|
|
|
178
209
|
return this.sessionManager.get_session_collection();
|
|
179
210
|
}
|
|
180
211
|
|
|
212
|
+
/**
|
|
213
|
+
* 返回当前 agent 挂载的 Shell。
|
|
214
|
+
*/
|
|
215
|
+
getShell(): Shell | undefined {
|
|
216
|
+
return this.shell;
|
|
217
|
+
}
|
|
218
|
+
|
|
181
219
|
private create_session_manager(
|
|
182
220
|
assembly: AgentAssemblyResult,
|
|
183
221
|
): AgentSessionManager {
|
|
@@ -28,13 +28,13 @@ import {
|
|
|
28
28
|
createAgentContext,
|
|
29
29
|
createAgentRuntime,
|
|
30
30
|
} from "@/agent/local/AgentRuntimeFactory.js";
|
|
31
|
-
import { setShellToolRuntime } from "@executor/tools/shell/ShellToolDefinition.js";
|
|
32
31
|
import {
|
|
33
32
|
plugin_tools,
|
|
34
33
|
setPluginToolRuntime,
|
|
35
34
|
} from "@executor/tools/plugin/PluginToolDefinition.js";
|
|
36
35
|
import type { AgentManagedSession } from "@/types/agent/AgentTypes.js";
|
|
37
36
|
import type { SessionPort } from "@/types/runtime/agent/AgentContext.js";
|
|
37
|
+
import type { AgentSessionEvent } from "@/types/sdk/AgentSessionEvent.js";
|
|
38
38
|
|
|
39
39
|
type AgentAssemblyServiceOptions = {
|
|
40
40
|
/**
|
|
@@ -123,6 +123,11 @@ export interface AgentAssemblyResult {
|
|
|
123
123
|
* 当前 agent context。
|
|
124
124
|
*/
|
|
125
125
|
agent_context: AgentContext;
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* 当前 agent 挂载的内建 shell。
|
|
129
|
+
*/
|
|
130
|
+
shell?: AgentOptions["shell"];
|
|
126
131
|
}
|
|
127
132
|
|
|
128
133
|
/**
|
|
@@ -201,7 +206,22 @@ export class AgentAssemblyService {
|
|
|
201
206
|
resolve_session_model: async (session_id) =>
|
|
202
207
|
await this.resolve_session_model(session_id),
|
|
203
208
|
});
|
|
204
|
-
|
|
209
|
+
const shell = this.options.shell;
|
|
210
|
+
if (shell) {
|
|
211
|
+
shell.configure({
|
|
212
|
+
root_path: path,
|
|
213
|
+
env,
|
|
214
|
+
agent_id: id,
|
|
215
|
+
sandbox: config.sandbox,
|
|
216
|
+
logger,
|
|
217
|
+
emit_event: (event) => {
|
|
218
|
+
const session_id = String(event.session_id || "").trim();
|
|
219
|
+
if (!session_id) return;
|
|
220
|
+
agent_context.session.get(session_id).publishEvent(event as unknown as AgentSessionEvent);
|
|
221
|
+
},
|
|
222
|
+
});
|
|
223
|
+
Object.assign(tools, shell.tools);
|
|
224
|
+
}
|
|
205
225
|
setPluginToolRuntime(plugins);
|
|
206
226
|
|
|
207
227
|
return {
|
|
@@ -217,6 +237,7 @@ export class AgentAssemblyService {
|
|
|
217
237
|
plugins,
|
|
218
238
|
runtime,
|
|
219
239
|
agent_context,
|
|
240
|
+
...(shell ? { shell } : {}),
|
|
220
241
|
};
|
|
221
242
|
}
|
|
222
243
|
|
|
@@ -22,6 +22,7 @@ import { startActionScheduleRuntime } from "@/plugin/core/ActionScheduleRuntime.
|
|
|
22
22
|
import { startAllPlugins, stopAllPlugins } from "@/plugin/core/Manager.js";
|
|
23
23
|
import { startRpcServer } from "@/rpc/Server.js";
|
|
24
24
|
import type { AgentRuntime } from "@/types/runtime/agent/AgentRuntime.js";
|
|
25
|
+
import type { Shell } from "@downcity/shell";
|
|
25
26
|
|
|
26
27
|
type AgentLifecycleServiceOptions = {
|
|
27
28
|
/**
|
|
@@ -43,6 +44,11 @@ type AgentLifecycleServiceOptions = {
|
|
|
43
44
|
* 读取当前 agent runtime。
|
|
44
45
|
*/
|
|
45
46
|
get_runtime: () => AgentRuntime;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* 读取当前 agent 挂载的 Shell。
|
|
50
|
+
*/
|
|
51
|
+
get_shell?: () => Shell | undefined;
|
|
46
52
|
};
|
|
47
53
|
|
|
48
54
|
/**
|
|
@@ -53,6 +59,7 @@ export class AgentLifecycleService {
|
|
|
53
59
|
private readonly agent_context: AgentContext;
|
|
54
60
|
private readonly session_collection: AgentSessionCollection;
|
|
55
61
|
private readonly get_runtime: AgentLifecycleServiceOptions["get_runtime"];
|
|
62
|
+
private readonly get_shell: AgentLifecycleServiceOptions["get_shell"];
|
|
56
63
|
|
|
57
64
|
private plugins_started = false;
|
|
58
65
|
private action_schedule_runtime: ActionScheduleRuntimeHandle | null = null;
|
|
@@ -64,6 +71,7 @@ export class AgentLifecycleService {
|
|
|
64
71
|
this.agent_context = options.agent_context;
|
|
65
72
|
this.session_collection = options.session_collection;
|
|
66
73
|
this.get_runtime = options.get_runtime;
|
|
74
|
+
this.get_shell = options.get_shell;
|
|
67
75
|
}
|
|
68
76
|
|
|
69
77
|
/**
|
|
@@ -112,6 +120,8 @@ export class AgentLifecycleService {
|
|
|
112
120
|
await this.stop_rpc();
|
|
113
121
|
}
|
|
114
122
|
|
|
123
|
+
await this.get_shell?.()?.dispose();
|
|
124
|
+
|
|
115
125
|
this.start_promise = null;
|
|
116
126
|
|
|
117
127
|
return {
|
|
@@ -168,6 +178,7 @@ export class AgentLifecycleService {
|
|
|
168
178
|
sessionCollection: this.session_collection,
|
|
169
179
|
getAgentContext: () => this.agent_context,
|
|
170
180
|
getAgentRuntime: () => this.get_runtime(),
|
|
181
|
+
getShell: () => this.get_shell?.(),
|
|
171
182
|
});
|
|
172
183
|
this.rpc_binding = {
|
|
173
184
|
url: `rpc://${host}:${port}`,
|
|
@@ -16,6 +16,10 @@ import type {
|
|
|
16
16
|
RemoteAgentOptions,
|
|
17
17
|
RemoteAgentSession,
|
|
18
18
|
} from "@/types/agent/AgentTypes.js";
|
|
19
|
+
import type {
|
|
20
|
+
ShellApprovalDecisionResult,
|
|
21
|
+
ShellApprovalView,
|
|
22
|
+
} from "@downcity/shell";
|
|
19
23
|
import type { RemoteAgentTransport } from "@/agent/remote/RemoteTransport.js";
|
|
20
24
|
import { RemoteSession } from "@/agent/remote/RemoteSession.js";
|
|
21
25
|
import { create_remote_agent_transport } from "@/agent/remote/TransportFactory.js";
|
|
@@ -70,7 +74,7 @@ export class RemoteAgent {
|
|
|
70
74
|
*
|
|
71
75
|
* 关键点(中文)
|
|
72
76
|
* - 这是 RemoteAgent 顶层能力,不绑定某个 session。
|
|
73
|
-
* -
|
|
77
|
+
* - Shell approval 请使用 `approvals()` / `approve()` / `deny()`。
|
|
74
78
|
*/
|
|
75
79
|
async runPluginAction(
|
|
76
80
|
input: RemoteAgentPluginActionInput,
|
|
@@ -90,6 +94,27 @@ export class RemoteAgent {
|
|
|
90
94
|
});
|
|
91
95
|
}
|
|
92
96
|
|
|
97
|
+
/**
|
|
98
|
+
* 列出远程 Agent 的 shell pending approvals。
|
|
99
|
+
*/
|
|
100
|
+
async approvals(): Promise<ShellApprovalView[]> {
|
|
101
|
+
return await this.transport.approvals();
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* 批准远程 Agent 的 shell approval。
|
|
106
|
+
*/
|
|
107
|
+
async approve(input: { approval_id: string }): Promise<ShellApprovalDecisionResult> {
|
|
108
|
+
return await this.transport.approve(input);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* 拒绝远程 Agent 的 shell approval。
|
|
113
|
+
*/
|
|
114
|
+
async deny(input: { approval_id: string }): Promise<ShellApprovalDecisionResult> {
|
|
115
|
+
return await this.transport.deny(input);
|
|
116
|
+
}
|
|
117
|
+
|
|
93
118
|
/**
|
|
94
119
|
* 关闭远程 transport。
|
|
95
120
|
*
|
|
@@ -20,6 +20,10 @@ import type {
|
|
|
20
20
|
} from "@/types/agent/AgentTypes.js";
|
|
21
21
|
import type { AgentSessionEvent } from "@/types/sdk/AgentSessionEvent.js";
|
|
22
22
|
import type { AgentSessionPromptInput } from "@/types/sdk/AgentSessionPrompt.js";
|
|
23
|
+
import type {
|
|
24
|
+
ShellApprovalDecisionResult,
|
|
25
|
+
ShellApprovalView,
|
|
26
|
+
} from "@downcity/shell";
|
|
23
27
|
|
|
24
28
|
/**
|
|
25
29
|
* Transport 持有的事件订阅句柄。
|
|
@@ -72,6 +76,12 @@ export type RemoteAgentTransport = RemoteSessionTransport & {
|
|
|
72
76
|
run_plugin_action(
|
|
73
77
|
input: RemoteAgentPluginActionInput,
|
|
74
78
|
): Promise<RemoteAgentPluginActionResult>;
|
|
79
|
+
/** 列出 shell approvals。 */
|
|
80
|
+
approvals(): Promise<ShellApprovalView[]>;
|
|
81
|
+
/** 批准 shell approval。 */
|
|
82
|
+
approve(input: { approval_id: string }): Promise<ShellApprovalDecisionResult>;
|
|
83
|
+
/** 拒绝 shell approval。 */
|
|
84
|
+
deny(input: { approval_id: string }): Promise<ShellApprovalDecisionResult>;
|
|
75
85
|
/** 关闭 transport 持有的长期连接。 */
|
|
76
86
|
close?(): Promise<void>;
|
|
77
87
|
};
|
|
@@ -24,6 +24,10 @@ import type {
|
|
|
24
24
|
RemoteAgentTransport,
|
|
25
25
|
TransportSubscription,
|
|
26
26
|
} from "@/agent/remote/RemoteTransport.js";
|
|
27
|
+
import type {
|
|
28
|
+
ShellApprovalDecisionResult,
|
|
29
|
+
ShellApprovalView,
|
|
30
|
+
} from "@downcity/shell";
|
|
27
31
|
|
|
28
32
|
type SdkEventsReadyFrame = {
|
|
29
33
|
/** SDK HTTP events 连接内部 ready 标记。 */
|
|
@@ -264,6 +268,47 @@ export class HttpRemoteAgentTransport implements RemoteAgentTransport {
|
|
|
264
268
|
}
|
|
265
269
|
return payload;
|
|
266
270
|
}
|
|
271
|
+
|
|
272
|
+
async approvals(): Promise<ShellApprovalView[]> {
|
|
273
|
+
const payload = await read_http_json<{
|
|
274
|
+
success?: boolean;
|
|
275
|
+
error?: string;
|
|
276
|
+
approvals?: ShellApprovalView[];
|
|
277
|
+
}>(`${this.base_url}/api/shell/approvals`, {
|
|
278
|
+
headers: this.headers(),
|
|
279
|
+
});
|
|
280
|
+
if (!payload.success || !Array.isArray(payload.approvals)) {
|
|
281
|
+
throw new Error(String(payload.error || "Remote shell approvals failed"));
|
|
282
|
+
}
|
|
283
|
+
return payload.approvals;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
async approve(input: { approval_id: string }): Promise<ShellApprovalDecisionResult> {
|
|
287
|
+
return await this.run_shell_decision("approve", input.approval_id);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
async deny(input: { approval_id: string }): Promise<ShellApprovalDecisionResult> {
|
|
291
|
+
return await this.run_shell_decision("deny", input.approval_id);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
private async run_shell_decision(
|
|
295
|
+
action: "approve" | "deny",
|
|
296
|
+
approval_id: string,
|
|
297
|
+
): Promise<ShellApprovalDecisionResult> {
|
|
298
|
+
const payload = await read_http_json<ShellApprovalDecisionResult & {
|
|
299
|
+
error?: string;
|
|
300
|
+
}>(`${this.base_url}/api/shell/${action}`, {
|
|
301
|
+
method: "POST",
|
|
302
|
+
headers: this.headers({
|
|
303
|
+
"Content-Type": "application/json",
|
|
304
|
+
}),
|
|
305
|
+
body: JSON.stringify({ approval_id }),
|
|
306
|
+
});
|
|
307
|
+
if (typeof payload.success !== "boolean") {
|
|
308
|
+
throw new Error(String(payload.error || `Remote shell ${action} failed`));
|
|
309
|
+
}
|
|
310
|
+
return payload;
|
|
311
|
+
}
|
|
267
312
|
}
|
|
268
313
|
|
|
269
314
|
async function read_http_json<T>(input: string, init?: RequestInit): Promise<T> {
|
|
@@ -25,6 +25,10 @@ import type {
|
|
|
25
25
|
RemoteAgentTransport,
|
|
26
26
|
TransportSubscription,
|
|
27
27
|
} from "@/agent/remote/RemoteTransport.js";
|
|
28
|
+
import type {
|
|
29
|
+
ShellApprovalDecisionResult,
|
|
30
|
+
ShellApprovalView,
|
|
31
|
+
} from "@downcity/shell";
|
|
28
32
|
|
|
29
33
|
/**
|
|
30
34
|
* 本机 RPC transport。
|
|
@@ -113,6 +117,18 @@ export class RpcRemoteAgentTransport implements RemoteAgentTransport {
|
|
|
113
117
|
});
|
|
114
118
|
}
|
|
115
119
|
|
|
120
|
+
async approvals(): Promise<ShellApprovalView[]> {
|
|
121
|
+
return await this.client.list_shell_approvals();
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
async approve(input: { approval_id: string }): Promise<ShellApprovalDecisionResult> {
|
|
125
|
+
return await this.client.approve_shell_approval(input.approval_id);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
async deny(input: { approval_id: string }): Promise<ShellApprovalDecisionResult> {
|
|
129
|
+
return await this.client.deny_shell_approval(input.approval_id);
|
|
130
|
+
}
|
|
131
|
+
|
|
116
132
|
async close(): Promise<void> {
|
|
117
133
|
await this.client.close();
|
|
118
134
|
}
|
package/src/executor/Executor.ts
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import { streamText, type LanguageModel, type Tool } from "ai";
|
|
11
|
+
import { withShellRunScope } from "@downcity/shell";
|
|
11
12
|
import { SessionHistoryWriter } from "@executor/composer/history/SessionHistoryWriter.js";
|
|
12
13
|
import type { SessionHistoryComposer } from "@executor/composer/history/SessionHistoryComposer.js";
|
|
13
14
|
import type { SessionHistoryStore } from "@/executor/store/history/SessionHistoryStore.js";
|
|
@@ -267,7 +268,15 @@ export class Executor implements SessionExecutor {
|
|
|
267
268
|
runContext: run_context,
|
|
268
269
|
},
|
|
269
270
|
async () =>
|
|
270
|
-
await
|
|
271
|
+
await withShellRunScope(
|
|
272
|
+
{
|
|
273
|
+
run_context: {
|
|
274
|
+
session_id: run_context.sessionId,
|
|
275
|
+
...(run_context.turnId ? { turn_id: run_context.turnId } : {}),
|
|
276
|
+
},
|
|
277
|
+
},
|
|
278
|
+
async () =>
|
|
279
|
+
await this.recovery_policy.run_with_retry({
|
|
271
280
|
query,
|
|
272
281
|
model: this.resolveModelOrThrow(),
|
|
273
282
|
run_context,
|
|
@@ -293,7 +302,8 @@ export class Executor implements SessionExecutor {
|
|
|
293
302
|
model,
|
|
294
303
|
next_run_context,
|
|
295
304
|
),
|
|
296
|
-
|
|
305
|
+
}),
|
|
306
|
+
),
|
|
297
307
|
);
|
|
298
308
|
return result;
|
|
299
309
|
} finally {
|
package/src/index.ts
CHANGED
package/src/rpc/Client.ts
CHANGED
|
@@ -37,6 +37,10 @@ import type {
|
|
|
37
37
|
RpcSessionSubscription,
|
|
38
38
|
RpcSystemPromptPayload,
|
|
39
39
|
} from "@/types/rpc/RpcProtocol.js";
|
|
40
|
+
import type {
|
|
41
|
+
ShellApprovalDecisionResult,
|
|
42
|
+
ShellApprovalView,
|
|
43
|
+
} from "@downcity/shell";
|
|
40
44
|
|
|
41
45
|
export type {
|
|
42
46
|
RpcClientEndpoint,
|
|
@@ -358,6 +362,40 @@ export class RpcClient {
|
|
|
358
362
|
});
|
|
359
363
|
}
|
|
360
364
|
|
|
365
|
+
/**
|
|
366
|
+
* 列出 shell approvals。
|
|
367
|
+
*/
|
|
368
|
+
async list_shell_approvals(): Promise<ShellApprovalView[]> {
|
|
369
|
+
const data = await this.request<{ approvals: ShellApprovalView[] }>({
|
|
370
|
+
method: "internal.shell.approvals",
|
|
371
|
+
});
|
|
372
|
+
return Array.isArray(data.approvals) ? data.approvals : [];
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* 批准 shell approval。
|
|
377
|
+
*/
|
|
378
|
+
async approve_shell_approval(approval_id: string): Promise<ShellApprovalDecisionResult> {
|
|
379
|
+
return await this.request<ShellApprovalDecisionResult>({
|
|
380
|
+
method: "internal.shell.approve",
|
|
381
|
+
params: {
|
|
382
|
+
approvalId: approval_id,
|
|
383
|
+
},
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* 拒绝 shell approval。
|
|
389
|
+
*/
|
|
390
|
+
async deny_shell_approval(approval_id: string): Promise<ShellApprovalDecisionResult> {
|
|
391
|
+
return await this.request<ShellApprovalDecisionResult>({
|
|
392
|
+
method: "internal.shell.deny",
|
|
393
|
+
params: {
|
|
394
|
+
approvalId: approval_id,
|
|
395
|
+
},
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
|
|
361
399
|
/**
|
|
362
400
|
* 关闭底层连接。
|
|
363
401
|
*/
|
|
@@ -154,11 +154,42 @@ export async function handleInternalRpcRequest(params: {
|
|
|
154
154
|
});
|
|
155
155
|
return true;
|
|
156
156
|
}
|
|
157
|
+
case "internal.shell.approvals": {
|
|
158
|
+
const shell = requireShell(options);
|
|
159
|
+
write_success(request.id, {
|
|
160
|
+
approvals: shell.approvals(),
|
|
161
|
+
});
|
|
162
|
+
return true;
|
|
163
|
+
}
|
|
164
|
+
case "internal.shell.approve": {
|
|
165
|
+
const shell = requireShell(options);
|
|
166
|
+
const result = await shell.approve({
|
|
167
|
+
approval_id: String(request.params.approvalId || "").trim(),
|
|
168
|
+
});
|
|
169
|
+
write_success(request.id, result);
|
|
170
|
+
return true;
|
|
171
|
+
}
|
|
172
|
+
case "internal.shell.deny": {
|
|
173
|
+
const shell = requireShell(options);
|
|
174
|
+
const result = await shell.deny({
|
|
175
|
+
approval_id: String(request.params.approvalId || "").trim(),
|
|
176
|
+
});
|
|
177
|
+
write_success(request.id, result);
|
|
178
|
+
return true;
|
|
179
|
+
}
|
|
157
180
|
default:
|
|
158
181
|
return false;
|
|
159
182
|
}
|
|
160
183
|
}
|
|
161
184
|
|
|
185
|
+
function requireShell(options: RpcRequestHandlerOptions) {
|
|
186
|
+
const shell = options.getShell?.();
|
|
187
|
+
if (!shell) {
|
|
188
|
+
throw new Error("Agent RPC server was started without Shell");
|
|
189
|
+
}
|
|
190
|
+
return shell;
|
|
191
|
+
}
|
|
192
|
+
|
|
162
193
|
function requireAgentContext(options: RpcRequestHandlerOptions): AgentContext {
|
|
163
194
|
const context = options.getAgentContext?.();
|
|
164
195
|
if (!context) {
|
|
@@ -10,6 +10,7 @@ import type { AgentSessionCollection } from "@/types/agent/AgentTypes.js";
|
|
|
10
10
|
import type { AgentContext } from "@/types/runtime/agent/AgentContext.js";
|
|
11
11
|
import type { AgentRuntime } from "@/types/runtime/agent/AgentRuntime.js";
|
|
12
12
|
import type { RpcEventFrame } from "@/types/rpc/RpcProtocol.js";
|
|
13
|
+
import type { Shell } from "@downcity/shell";
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* RPC Server 启动参数。
|
|
@@ -25,6 +26,8 @@ export interface RpcServerStartOptions {
|
|
|
25
26
|
getAgentContext?: () => AgentContext;
|
|
26
27
|
/** Agent 运行态访问口。 */
|
|
27
28
|
getAgentRuntime?: () => AgentRuntime;
|
|
29
|
+
/** Shell 访问口。 */
|
|
30
|
+
getShell?: () => Shell | undefined;
|
|
28
31
|
}
|
|
29
32
|
|
|
30
33
|
/**
|
|
@@ -37,6 +40,8 @@ export interface RpcRequestHandlerOptions {
|
|
|
37
40
|
getAgentContext?: () => AgentContext;
|
|
38
41
|
/** Agent 运行态访问口。 */
|
|
39
42
|
getAgentRuntime?: () => AgentRuntime;
|
|
43
|
+
/** Shell 访问口。 */
|
|
44
|
+
getShell?: () => Shell | undefined;
|
|
40
45
|
}
|
|
41
46
|
|
|
42
47
|
/**
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import type { Tool } from "ai";
|
|
10
|
+
import type { Shell } from "@downcity/shell";
|
|
10
11
|
import type { BasePlugin } from "@/plugin/core/BasePlugin.js";
|
|
11
12
|
import type { AgentModel } from "@/model/CityModelAdapter.js";
|
|
12
13
|
import type { RpcServerInstance } from "@/rpc/Server.js";
|
|
@@ -51,6 +52,15 @@ export interface AgentOptions {
|
|
|
51
52
|
*/
|
|
52
53
|
tools?: Record<string, Tool>;
|
|
53
54
|
|
|
55
|
+
/**
|
|
56
|
+
* 当前 agent 内建 shell 能力。
|
|
57
|
+
*
|
|
58
|
+
* 关键点(中文)
|
|
59
|
+
* - Shell 不是 plugin,而是 agent 直接挂载的内建工具对象。
|
|
60
|
+
* - 未传入时,Agent 不会自动注入 shell tools。
|
|
61
|
+
*/
|
|
62
|
+
shell?: Shell;
|
|
63
|
+
|
|
54
64
|
/**
|
|
55
65
|
* 调用方显式传入的静态基础指令。
|
|
56
66
|
*
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
import type { LlmConfig } from "@/types/config/LlmConfig.js";
|
|
9
9
|
import type { ExecutionBindingConfig } from "@/types/config/ExecutionBinding.js";
|
|
10
10
|
import type { JsonObject } from "@/types/common/Json.js";
|
|
11
|
-
import type { SandboxProjectConfig } from "
|
|
11
|
+
import type { SandboxProjectConfig } from "@downcity/shell/sandbox/types/Sandbox.js";
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* 单个聊天渠道配置。
|
|
@@ -165,7 +165,7 @@ export interface DowncityConfig {
|
|
|
165
165
|
* shell / CLI 执行 sandbox 配置。
|
|
166
166
|
*
|
|
167
167
|
* 关键点(中文)
|
|
168
|
-
* -
|
|
168
|
+
* - 当前只作用于内建 shell 这条命令执行链。
|
|
169
169
|
* - 这里不表达审批、用户授权与复杂策略系统,只表达最小边界。
|
|
170
170
|
*/
|
|
171
171
|
sandbox?: SandboxProjectConfig;
|
|
@@ -231,6 +231,34 @@ export type RpcRequest =
|
|
|
231
231
|
/** action payload。 */
|
|
232
232
|
payload?: JsonValue;
|
|
233
233
|
};
|
|
234
|
+
}
|
|
235
|
+
| {
|
|
236
|
+
/** 请求 id,用于匹配响应。 */
|
|
237
|
+
id: string;
|
|
238
|
+
/** 列出 shell approvals。 */
|
|
239
|
+
method: "internal.shell.approvals";
|
|
240
|
+
}
|
|
241
|
+
| {
|
|
242
|
+
/** 请求 id,用于匹配响应。 */
|
|
243
|
+
id: string;
|
|
244
|
+
/** 批准 shell approval。 */
|
|
245
|
+
method: "internal.shell.approve";
|
|
246
|
+
/** approval 参数。 */
|
|
247
|
+
params: {
|
|
248
|
+
/** approval id。 */
|
|
249
|
+
approvalId: string;
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
| {
|
|
253
|
+
/** 请求 id,用于匹配响应。 */
|
|
254
|
+
id: string;
|
|
255
|
+
/** 拒绝 shell approval。 */
|
|
256
|
+
method: "internal.shell.deny";
|
|
257
|
+
/** approval 参数。 */
|
|
258
|
+
params: {
|
|
259
|
+
/** approval id。 */
|
|
260
|
+
approvalId: string;
|
|
261
|
+
};
|
|
234
262
|
};
|
|
235
263
|
|
|
236
264
|
/**
|