mirror of
https://github.com/slhaf/Partner.git
synced 2026-05-12 08:43:02 +08:00
feat(runner): add execution policy abstract for local running
This commit is contained in:
@@ -7,14 +7,14 @@ import io.modelcontextprotocol.client.transport.customizer.McpSyncHttpClientRequ
|
||||
import io.modelcontextprotocol.common.McpTransportContext;
|
||||
import io.modelcontextprotocol.json.McpJsonMapper;
|
||||
import io.modelcontextprotocol.spec.McpClientTransport;
|
||||
import work.slhaf.partner.core.action.runner.policy.RunnerExecutionPolicy;
|
||||
import work.slhaf.partner.core.action.runner.policy.ExecutionPolicyRegistry;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.http.HttpRequest;
|
||||
|
||||
public class McpTransportFactory {
|
||||
|
||||
public McpClientTransport create(McpTransportConfig config, RunnerExecutionPolicy policy) {
|
||||
public McpClientTransport create(McpTransportConfig config, ExecutionPolicyRegistry policy) {
|
||||
return switch (config) {
|
||||
case McpTransportConfig.Stdio stdio -> {
|
||||
ServerParameters serverParameters = ServerParameters.builder(stdio.command())
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package work.slhaf.partner.core.action.runner.policy
|
||||
|
||||
object DirectPolicyProvider : PolicyProvider(
|
||||
policyName = "direct"
|
||||
) {
|
||||
|
||||
override fun prepare(
|
||||
policy: ExecutionPolicy,
|
||||
commands: List<String>
|
||||
): WrappedLaunchSpec {
|
||||
val (command, args) = splitCommands(commands)
|
||||
return WrappedLaunchSpec(
|
||||
command = command,
|
||||
args = args,
|
||||
workingDirectory = policy.workingDirectory,
|
||||
environment = resolveEnvironment(policy)
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
package work.slhaf.partner.core.action.runner.policy
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import java.util.concurrent.CopyOnWriteArraySet
|
||||
|
||||
object ExecutionPolicyRegistry {
|
||||
|
||||
private const val DEFAULT_PROVIDER = "direct"
|
||||
|
||||
private val policyProviders = ConcurrentHashMap<String, PolicyProvider>().apply {
|
||||
put(DEFAULT_PROVIDER, DirectPolicyProvider)
|
||||
}
|
||||
|
||||
private val listeners = CopyOnWriteArraySet<RunnerExecutionPolicyListener>()
|
||||
|
||||
@Volatile
|
||||
private var currentPolicy = ExecutionPolicy(
|
||||
provider = "direct",
|
||||
mode = ExecutionPolicy.Mode.DIRECT,
|
||||
net = ExecutionPolicy.Network.ENABLE,
|
||||
inheritEnv = true,
|
||||
env = emptyMap(),
|
||||
workingDirectory = null,
|
||||
readOnlyPaths = emptySet(),
|
||||
writablePaths = emptySet(),
|
||||
)
|
||||
|
||||
fun prepare(commands: List<String>): WrappedLaunchSpec {
|
||||
val policy = currentPolicy
|
||||
val provider = policyProviders[policy.provider]
|
||||
?: policyProviders[DEFAULT_PROVIDER]
|
||||
?: error("Default provider '${DEFAULT_PROVIDER}' is not registered")
|
||||
return provider.prepare(policy, commands)
|
||||
}
|
||||
|
||||
fun updatePolicy(policy: ExecutionPolicy) {
|
||||
currentPolicy = policy
|
||||
listeners.forEach { it.onPolicyChanged(policy) }
|
||||
}
|
||||
|
||||
fun addListener(listener: RunnerExecutionPolicyListener) {
|
||||
listeners += listener
|
||||
}
|
||||
|
||||
fun removeListener(listener: RunnerExecutionPolicyListener) {
|
||||
listeners -= listener
|
||||
}
|
||||
|
||||
fun registerPolicyProvider(policyProvider: PolicyProvider) {
|
||||
val name = policyProvider.policyName
|
||||
if (policyProviders.containsKey(name)) {
|
||||
return
|
||||
}
|
||||
policyProviders[name] = policyProvider
|
||||
}
|
||||
}
|
||||
|
||||
data class ExecutionPolicy(
|
||||
val mode: Mode,
|
||||
val provider: String,
|
||||
val net: Network,
|
||||
val inheritEnv: Boolean,
|
||||
val env: Map<String, String>,
|
||||
val workingDirectory: String?,
|
||||
val readOnlyPaths: Set<String>,
|
||||
val writablePaths: Set<String>,
|
||||
) {
|
||||
|
||||
enum class Mode {
|
||||
DIRECT,
|
||||
SANDBOX
|
||||
}
|
||||
|
||||
enum class Network {
|
||||
DISABLE,
|
||||
ENABLE
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
data class WrappedLaunchSpec(
|
||||
val command: String,
|
||||
val args: List<String>,
|
||||
val workingDirectory: String? = null,
|
||||
val environment: Map<String, String> = emptyMap()
|
||||
)
|
||||
|
||||
abstract class PolicyProvider(
|
||||
val policyName: String
|
||||
) {
|
||||
|
||||
abstract fun prepare(
|
||||
policy: ExecutionPolicy,
|
||||
commands: List<String>
|
||||
): WrappedLaunchSpec
|
||||
|
||||
protected fun resolveEnvironment(policy: ExecutionPolicy): Map<String, String> {
|
||||
val result = LinkedHashMap<String, String>()
|
||||
if (policy.inheritEnv) {
|
||||
result.putAll(System.getenv())
|
||||
}
|
||||
result.putAll(policy.env)
|
||||
return result
|
||||
}
|
||||
|
||||
protected fun splitCommands(commands: List<String>): Pair<String, List<String>> {
|
||||
require(commands.isNotEmpty()) { "commands must not be empty" }
|
||||
return commands.first() to commands.drop(1)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
interface RunnerExecutionPolicyListener {
|
||||
fun onPolicyChanged(policy: ExecutionPolicy)
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
package work.slhaf.partner.core.action.runner.policy;
|
||||
|
||||
public interface RunnerExecutionPolicy {
|
||||
}
|
||||
Reference in New Issue
Block a user