mirror of
https://github.com/slhaf/Partner.git
synced 2026-05-12 08:43:02 +08:00
refactor(framework): migrate startup chain exceptions to AgentException hierarchy
This commit is contained in:
@@ -3,7 +3,8 @@ package work.slhaf.partner.framework.agent.config
|
||||
import com.alibaba.fastjson2.JSON
|
||||
import com.alibaba.fastjson2.JSONObject
|
||||
import org.slf4j.LoggerFactory
|
||||
import work.slhaf.partner.framework.agent.exception.deprecated.AgentLaunchFailedException
|
||||
import work.slhaf.partner.framework.agent.exception.AgentStartupException
|
||||
import work.slhaf.partner.framework.agent.exception.checkAgentStartup
|
||||
import work.slhaf.partner.framework.agent.support.DirectoryWatchSupport
|
||||
import java.io.IOException
|
||||
import java.lang.reflect.Field
|
||||
@@ -19,6 +20,7 @@ import kotlin.reflect.full.memberProperties
|
||||
import kotlin.reflect.jvm.javaField
|
||||
|
||||
object ConfigCenter : AutoCloseable {
|
||||
private const val COMPONENT_NAME = "config-center"
|
||||
|
||||
private val log = LoggerFactory.getLogger(ConfigCenter::class.java)
|
||||
val paths = resolvePaths()
|
||||
@@ -31,9 +33,8 @@ object ConfigCenter : AutoCloseable {
|
||||
|
||||
@Synchronized
|
||||
fun register(configurable: Configurable) {
|
||||
|
||||
check(!started) {
|
||||
"ConfigCenter does not allow registration after watching started"
|
||||
checkAgentStartup(!started) {
|
||||
AgentStartupException("ConfigCenter does not allow registration after watching started", COMPONENT_NAME)
|
||||
}
|
||||
|
||||
val declared = configurable.declare()
|
||||
@@ -42,15 +43,18 @@ object ConfigCenter : AutoCloseable {
|
||||
declared.forEach { (path, registration) ->
|
||||
val normalizedPath = normalizeRelativePath(path)
|
||||
|
||||
check(normalized.putIfAbsent(normalizedPath, registration) == null) {
|
||||
"Duplicated config path declared in the same configurable: $normalizedPath"
|
||||
checkAgentStartup(normalized.putIfAbsent(normalizedPath, registration) == null) {
|
||||
AgentStartupException(
|
||||
"Duplicated config path declared in the same configurable: $normalizedPath",
|
||||
COMPONENT_NAME
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
normalized.forEach { (path, registration) ->
|
||||
check(registrations.putIfAbsent(path, registration) == null) {
|
||||
"Config path already registered: $path"
|
||||
checkAgentStartup(registrations.putIfAbsent(path, registration) == null) {
|
||||
AgentStartupException("Config path already registered: $path", COMPONENT_NAME)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,7 +97,10 @@ object ConfigCenter : AutoCloseable {
|
||||
(registration as ConfigRegistration<Config>).init(defaultConfig, null)
|
||||
}
|
||||
val configDoc = resolveConfigDoc(registration.type())
|
||||
throw AgentLaunchFailedException("Failed to init config, related path: $path, config definition: $configDoc")
|
||||
throw AgentStartupException(
|
||||
"Failed to init config, related path: $path, config definition: $configDoc",
|
||||
COMPONENT_NAME
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -232,8 +239,8 @@ object ConfigCenter : AutoCloseable {
|
||||
}
|
||||
|
||||
private fun normalizeRelativePath(path: Path): Path {
|
||||
require(!path.isAbsolute) {
|
||||
"Config path must be relative: $path"
|
||||
checkAgentStartup(!path.isAbsolute) {
|
||||
AgentStartupException("Config path must be relative: $path", COMPONENT_NAME)
|
||||
}
|
||||
return path.normalize()
|
||||
}
|
||||
|
||||
@@ -34,6 +34,16 @@ open class GatewayException @JvmOverloads constructor(
|
||||
}
|
||||
}
|
||||
|
||||
open class GatewayRegistryException @JvmOverloads constructor(
|
||||
message: String,
|
||||
val gatewayName: String,
|
||||
cause: Throwable? = null
|
||||
) : InteractionException(message, cause) {
|
||||
override fun toReport(): ExceptionReport = super.toReport().also {
|
||||
it.extra["gatewayName"] = gatewayName
|
||||
}
|
||||
}
|
||||
|
||||
open class ModelInvokeException(
|
||||
message: String,
|
||||
val providerName: String,
|
||||
@@ -51,3 +61,17 @@ open class ModelInvokeException(
|
||||
it.extra["override"] = override
|
||||
}
|
||||
}
|
||||
|
||||
open class ModelRegistryException(
|
||||
message: String,
|
||||
val providerName: String,
|
||||
val modelKey: String,
|
||||
val override: Map<String, String> = emptyMap(),
|
||||
cause: Throwable? = null
|
||||
) : AgentRuntimeException(message, cause) {
|
||||
override fun toReport(): ExceptionReport = super.toReport().also {
|
||||
it.extra["providerName"] = providerName
|
||||
it.extra["modelKey"] = modelKey
|
||||
it.extra["override"] = override
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,3 +23,31 @@ open class FactoryExecutionException @JvmOverloads constructor(
|
||||
return report
|
||||
}
|
||||
}
|
||||
|
||||
open class GatewayStartupException @JvmOverloads constructor(
|
||||
message: String,
|
||||
val gatewayName: String,
|
||||
cause: Throwable? = null
|
||||
) : AgentStartupException(message, "agent-gateway-registry", cause) {
|
||||
override fun toReport(): ExceptionReport {
|
||||
val report = super.toReport()
|
||||
report.extra["gatewayName"] = gatewayName
|
||||
return report
|
||||
}
|
||||
}
|
||||
|
||||
open class ModelRegistryStartupException @JvmOverloads constructor(
|
||||
message: String,
|
||||
val providerName: String,
|
||||
val modelKey: String,
|
||||
val override: Map<String, String> = emptyMap(),
|
||||
cause: Throwable? = null
|
||||
) : AgentStartupException(message, "model-runtime-registry", cause) {
|
||||
override fun toReport(): ExceptionReport {
|
||||
val report = super.toReport()
|
||||
report.extra["providerName"] = providerName
|
||||
report.extra["modelKey"] = modelKey
|
||||
report.extra["override"] = override
|
||||
return report
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package work.slhaf.partner.framework.agent.factory
|
||||
|
||||
import org.reflections.util.ClasspathHelper
|
||||
import work.slhaf.partner.framework.agent.exception.FactoryExecutionException
|
||||
import work.slhaf.partner.framework.agent.factory.capability.CapabilityAnnotationValidatorFactory
|
||||
import work.slhaf.partner.framework.agent.factory.capability.CapabilityInjectorFactory
|
||||
import work.slhaf.partner.framework.agent.factory.capability.CapabilityRegisterFactory
|
||||
@@ -10,7 +11,6 @@ import work.slhaf.partner.framework.agent.factory.component.ComponentInjectorFac
|
||||
import work.slhaf.partner.framework.agent.factory.component.ComponentRegisterFactory
|
||||
import work.slhaf.partner.framework.agent.factory.context.AgentRegisterContext
|
||||
import work.slhaf.partner.framework.agent.factory.context.ShutdownHookCollectorFactory
|
||||
import work.slhaf.partner.framework.agent.factory.exception.ExternalModuleLoadFailedException
|
||||
import java.io.File
|
||||
import java.net.URL
|
||||
|
||||
@@ -72,7 +72,11 @@ object AgentRegisterFactory {
|
||||
.filter { it.name.endsWith(".jar") }
|
||||
.forEach { urls.add(it.toURI().toURL()) }
|
||||
} catch (e: Exception) {
|
||||
throw ExternalModuleLoadFailedException("外部模块URL获取失败: $externalPackagePath", e)
|
||||
throw FactoryExecutionException(
|
||||
"Failed to load external module URLs from: $externalPackagePath",
|
||||
"agent-register-factory",
|
||||
e
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,14 +2,12 @@ package work.slhaf.partner.framework.agent.factory.capability
|
||||
|
||||
import cn.hutool.core.util.ClassUtil
|
||||
import org.reflections.Reflections
|
||||
import work.slhaf.partner.framework.agent.exception.FactoryExecutionException
|
||||
import work.slhaf.partner.framework.agent.factory.AgentBaseFactory
|
||||
import work.slhaf.partner.framework.agent.factory.capability.annotation.Capability
|
||||
import work.slhaf.partner.framework.agent.factory.capability.annotation.CapabilityCore
|
||||
import work.slhaf.partner.framework.agent.factory.capability.annotation.CapabilityMethod
|
||||
import work.slhaf.partner.framework.agent.factory.capability.annotation.InjectCapability
|
||||
import work.slhaf.partner.framework.agent.factory.capability.exception.DuplicateCapabilityException
|
||||
import work.slhaf.partner.framework.agent.factory.capability.exception.UnMatchedCapabilityException
|
||||
import work.slhaf.partner.framework.agent.factory.capability.exception.UnMatchedCapabilityMethodException
|
||||
import work.slhaf.partner.framework.agent.factory.component.annotation.AgentComponent
|
||||
import work.slhaf.partner.framework.agent.factory.context.AgentRegisterContext
|
||||
import work.slhaf.partner.framework.agent.factory.util.ReflectUtil.isAssignableFromAnnotation
|
||||
@@ -25,6 +23,8 @@ import work.slhaf.partner.framework.agent.factory.util.ReflectUtil.methodSignatu
|
||||
* - `@InjectCapability` 字段仅允许位于 `@AgentComponent` 相关类中。
|
||||
*/
|
||||
class CapabilityAnnotationValidatorFactory : AgentBaseFactory() {
|
||||
private val factoryName = "capability-annotation-validator-factory"
|
||||
|
||||
override fun execute(context: AgentRegisterContext) {
|
||||
val reflections = context.reflections
|
||||
val cores = loadCores(reflections)
|
||||
@@ -61,7 +61,7 @@ class CapabilityAnnotationValidatorFactory : AgentBaseFactory() {
|
||||
val value = capability.getAnnotation(Capability::class.java).value
|
||||
val existed = capabilityByValue.putIfAbsent(value, capability)
|
||||
if (existed != null) {
|
||||
throw DuplicateCapabilityException("Capability 注册异常: 重复的Capability接口: $value")
|
||||
throw FactoryExecutionException("Duplicate capability value detected: $value", factoryName)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -73,9 +73,9 @@ class CapabilityAnnotationValidatorFactory : AgentBaseFactory() {
|
||||
methods.forEach { method ->
|
||||
val declaringClass = method.declaringClass
|
||||
if (!declaringClass.isAnnotationPresent(CapabilityCore::class.java)) {
|
||||
throw UnMatchedCapabilityException(
|
||||
"@CapabilityMethod 仅能用于 @CapabilityCore 所标注类中: " +
|
||||
"${declaringClass.name}#${method.name}"
|
||||
throw FactoryExecutionException(
|
||||
"@CapabilityMethod can only be declared in @CapabilityCore classes: ${declaringClass.name}#${method.name}",
|
||||
factoryName
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -109,13 +109,19 @@ class CapabilityAnnotationValidatorFactory : AgentBaseFactory() {
|
||||
val signature = methodSignature(method)
|
||||
val implementors = signatureMap[signature].orEmpty()
|
||||
if (implementors.isEmpty()) {
|
||||
throw UnMatchedCapabilityMethodException(
|
||||
"Capability方法缺少实现: $capabilityValue.$signature"
|
||||
throw FactoryExecutionException(
|
||||
"Missing capability method implementation: $capabilityValue.$signature",
|
||||
factoryName
|
||||
)
|
||||
}
|
||||
if (implementors.size > 1) {
|
||||
throw UnMatchedCapabilityMethodException(
|
||||
"Capability方法存在多个实现: $capabilityValue.$signature -> ${implementors.joinToString(", ")}"
|
||||
throw FactoryExecutionException(
|
||||
"Multiple capability method implementations found: $capabilityValue.$signature -> ${
|
||||
implementors.joinToString(
|
||||
", "
|
||||
)
|
||||
}",
|
||||
factoryName
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -129,8 +135,9 @@ class CapabilityAnnotationValidatorFactory : AgentBaseFactory() {
|
||||
reflections.getFieldsAnnotatedWith(InjectCapability::class.java).forEach { field ->
|
||||
val declaringClass = field.declaringClass
|
||||
if (!isAssignableFromAnnotation(declaringClass, AgentComponent::class.java)) {
|
||||
throw UnMatchedCapabilityException(
|
||||
"InjectCapability 注解只能用于 AgentComponent 注解所在类,检查该类是否使用了@CapabilityHolder注解或者受其标注的注解或父类: $declaringClass"
|
||||
throw FactoryExecutionException(
|
||||
"@InjectCapability can only be declared on AgentComponent classes: $declaringClass",
|
||||
factoryName
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package work.slhaf.partner.framework.agent.factory.capability
|
||||
|
||||
import work.slhaf.partner.framework.agent.exception.FactoryExecutionException
|
||||
import work.slhaf.partner.framework.agent.factory.AgentBaseFactory
|
||||
import work.slhaf.partner.framework.agent.factory.capability.annotation.Capability
|
||||
import work.slhaf.partner.framework.agent.factory.capability.annotation.InjectCapability
|
||||
import work.slhaf.partner.framework.agent.factory.capability.exception.CapabilityProxySetFailedException
|
||||
import work.slhaf.partner.framework.agent.factory.context.AgentContext
|
||||
import work.slhaf.partner.framework.agent.factory.context.AgentRegisterContext
|
||||
import java.lang.reflect.Field
|
||||
@@ -16,6 +16,8 @@ import java.lang.reflect.Modifier
|
||||
* 注入值来源于 `AgentContext.capabilities`。
|
||||
*/
|
||||
class CapabilityInjectorFactory : AgentBaseFactory() {
|
||||
private val factoryName = "capability-injector-factory"
|
||||
|
||||
override fun execute(context: AgentRegisterContext) {
|
||||
val agentContext = context.agentContext
|
||||
val targets = buildTargets(agentContext)
|
||||
@@ -38,11 +40,12 @@ class CapabilityInjectorFactory : AgentBaseFactory() {
|
||||
field.isAccessible = true
|
||||
val value = resolveCapabilityInstance(field, capabilityMap, target::class.java)
|
||||
field.set(target, value)
|
||||
} catch (e: CapabilityProxySetFailedException) {
|
||||
} catch (e: FactoryExecutionException) {
|
||||
throw e
|
||||
} catch (e: Exception) {
|
||||
throw CapabilityProxySetFailedException(
|
||||
"Capability 注入失败: ${target::class.java.name}#${field.name}",
|
||||
throw FactoryExecutionException(
|
||||
"Failed to inject capability dependency: ${target::class.java.name}#${field.name}",
|
||||
factoryName,
|
||||
e
|
||||
)
|
||||
}
|
||||
@@ -55,17 +58,20 @@ class CapabilityInjectorFactory : AgentBaseFactory() {
|
||||
targetClass: Class<*>
|
||||
): Any {
|
||||
val capability = field.type.getAnnotation(Capability::class.java)
|
||||
?: throw CapabilityProxySetFailedException(
|
||||
"InjectCapability 字段类型未标注 @Capability: ${targetClass.name}#${field.name} -> ${field.type.name}"
|
||||
?: throw FactoryExecutionException(
|
||||
"InjectCapability target type is not annotated with @Capability: ${targetClass.name}#${field.name} -> ${field.type.name}",
|
||||
factoryName
|
||||
)
|
||||
|
||||
val capabilityValue = capability.value
|
||||
val implementation = capabilityMap[capabilityValue] ?: throw CapabilityProxySetFailedException(
|
||||
"未找到可注入 Capability 实例: ${targetClass.name}#${field.name} -> $capabilityValue"
|
||||
val implementation = capabilityMap[capabilityValue] ?: throw FactoryExecutionException(
|
||||
"Injectable capability implementation not found: ${targetClass.name}#${field.name} -> $capabilityValue",
|
||||
factoryName
|
||||
)
|
||||
if (!field.type.isAssignableFrom(implementation.instance.javaClass)) {
|
||||
throw CapabilityProxySetFailedException(
|
||||
"Capability 实例类型不匹配: ${targetClass.name}#${field.name} -> $capabilityValue"
|
||||
throw FactoryExecutionException(
|
||||
"Capability implementation type mismatch: ${targetClass.name}#${field.name} -> $capabilityValue",
|
||||
factoryName
|
||||
)
|
||||
}
|
||||
return implementation.instance
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
package work.slhaf.partner.framework.agent.factory.capability
|
||||
|
||||
import work.slhaf.partner.framework.agent.exception.FactoryExecutionException
|
||||
import work.slhaf.partner.framework.agent.factory.AgentBaseFactory
|
||||
import work.slhaf.partner.framework.agent.factory.capability.annotation.Capability
|
||||
import work.slhaf.partner.framework.agent.factory.capability.annotation.CapabilityCore
|
||||
import work.slhaf.partner.framework.agent.factory.capability.annotation.CapabilityMethod
|
||||
import work.slhaf.partner.framework.agent.factory.capability.exception.CapabilityCoreInstancesCreateFailedException
|
||||
import work.slhaf.partner.framework.agent.factory.capability.exception.CapabilityFactoryExecuteFailedException
|
||||
import work.slhaf.partner.framework.agent.factory.capability.exception.DuplicateMethodException
|
||||
import work.slhaf.partner.framework.agent.factory.context.AgentRegisterContext
|
||||
import work.slhaf.partner.framework.agent.factory.util.ReflectUtil.methodSignature
|
||||
import java.lang.reflect.Method
|
||||
@@ -23,6 +21,8 @@ import java.util.function.Function
|
||||
* - 将 capability 代理、cores 与方法映射注册到 `AgentContext`。
|
||||
*/
|
||||
class CapabilityRegisterFactory : AgentBaseFactory() {
|
||||
private val factoryName = "capability-register-factory"
|
||||
|
||||
override fun execute(context: AgentRegisterContext) {
|
||||
val capabilityFactoryContext = context.capabilityFactoryContext
|
||||
val agentContext = context.agentContext
|
||||
@@ -30,7 +30,10 @@ class CapabilityRegisterFactory : AgentBaseFactory() {
|
||||
val cores = capabilityFactoryContext.cores.toSet()
|
||||
val capabilities = capabilityFactoryContext.capabilities.toSet()
|
||||
if (cores.isEmpty() || capabilities.isEmpty()) {
|
||||
throw CapabilityFactoryExecuteFailedException("CapabilityFactoryContext 中缺少已校验的 capability/core 信息")
|
||||
throw FactoryExecutionException(
|
||||
"Validated capability/core scan result is missing from CapabilityFactoryContext",
|
||||
factoryName
|
||||
)
|
||||
}
|
||||
|
||||
val coreInstances = LinkedHashMap<Class<*>, Any>()
|
||||
@@ -59,7 +62,7 @@ class CapabilityRegisterFactory : AgentBaseFactory() {
|
||||
coreInstances[core] = constructor.newInstance()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
throw CapabilityCoreInstancesCreateFailedException("core实例创建失败", e)
|
||||
throw FactoryExecutionException("Failed to instantiate capability cores", factoryName, e)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,14 +75,17 @@ class CapabilityRegisterFactory : AgentBaseFactory() {
|
||||
cores.forEach { core ->
|
||||
val capabilityValue = core.getAnnotation(CapabilityCore::class.java).value
|
||||
val coreInstance = coreInstances[core]
|
||||
?: throw CapabilityFactoryExecuteFailedException("未找到CapabilityCore实例: ${core.name}")
|
||||
?: throw FactoryExecutionException("Capability core instance not found: ${core.name}", factoryName)
|
||||
|
||||
core.methods
|
||||
.filter { it.isAnnotationPresent(CapabilityMethod::class.java) }
|
||||
.forEach { method ->
|
||||
val key = "$capabilityValue.${methodSignature(method)}"
|
||||
if (map.containsKey(key) || methodsRouterTable.containsKey(key)) {
|
||||
throw DuplicateMethodException("重复注册能力方法: ${core.name}#${method.name}")
|
||||
throw FactoryExecutionException(
|
||||
"Duplicate capability method binding: ${core.name}#${method.name}",
|
||||
factoryName
|
||||
)
|
||||
}
|
||||
map[key] = MethodBinding(core, coreInstance, method)
|
||||
methodsRouterTable[key] = Function { args ->
|
||||
@@ -106,7 +112,7 @@ class CapabilityRegisterFactory : AgentBaseFactory() {
|
||||
else -> {
|
||||
val key = "$capabilityValue.${methodSignature(method)}"
|
||||
val fn = methodsRouterTable[key]
|
||||
?: throw CapabilityFactoryExecuteFailedException("未找到能力方法路由: $key")
|
||||
?: throw FactoryExecutionException("Capability method route not found: $key", factoryName)
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val actualArgs = (args ?: emptyArray<Any?>()) as Array<Any?>
|
||||
@@ -128,7 +134,7 @@ class CapabilityRegisterFactory : AgentBaseFactory() {
|
||||
}
|
||||
val key = "$capabilityValue.${methodSignature(method)}"
|
||||
val binding = methodBindingMap[key]
|
||||
?: throw CapabilityFactoryExecuteFailedException("Capability方法缺少实现: $key")
|
||||
?: throw FactoryExecutionException("Missing capability method implementation for: $key", factoryName)
|
||||
methods[key] = binding.method
|
||||
}
|
||||
return methods
|
||||
@@ -149,8 +155,9 @@ class CapabilityRegisterFactory : AgentBaseFactory() {
|
||||
return try {
|
||||
method.invoke(instance, *args)
|
||||
} catch (e: Exception) {
|
||||
throw CapabilityFactoryExecuteFailedException(
|
||||
"能力方法调用失败: ${instance::class.java.name}#${method.name}",
|
||||
throw FactoryExecutionException(
|
||||
"Failed to invoke capability method: ${instance::class.java.name}#${method.name}",
|
||||
factoryName,
|
||||
e
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
package work.slhaf.partner.framework.agent.factory.capability.exception;
|
||||
|
||||
import work.slhaf.partner.framework.agent.exception.deprecated.AgentLaunchFailedException;
|
||||
|
||||
public class CapabilityCheckFailedException extends AgentLaunchFailedException {
|
||||
public CapabilityCheckFailedException(String message) {
|
||||
super("Capability注册失败: " + message);
|
||||
}
|
||||
|
||||
public CapabilityCheckFailedException(String message, Throwable cause) {
|
||||
super("Capability注册失败: " + message, cause);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package work.slhaf.partner.framework.agent.factory.capability.exception;
|
||||
|
||||
public class CapabilityCoreInstancesCreateFailedException extends CapabilityFactoryExecuteFailedException {
|
||||
public CapabilityCoreInstancesCreateFailedException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public CapabilityCoreInstancesCreateFailedException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package work.slhaf.partner.framework.agent.factory.capability.exception;
|
||||
|
||||
import work.slhaf.partner.framework.agent.exception.deprecated.AgentLaunchFailedException;
|
||||
|
||||
public class CapabilityFactoryExecuteFailedException extends AgentLaunchFailedException {
|
||||
public CapabilityFactoryExecuteFailedException(String message) {
|
||||
super("CapabilityRegisterFactory 执行失败: " + message);
|
||||
}
|
||||
|
||||
public CapabilityFactoryExecuteFailedException(String message, Throwable cause) {
|
||||
super("CapabilityRegisterFactory 执行失败: " + message, cause);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package work.slhaf.partner.framework.agent.factory.capability.exception;
|
||||
|
||||
public class CapabilityProxySetFailedException extends CapabilityFactoryExecuteFailedException {
|
||||
public CapabilityProxySetFailedException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public CapabilityProxySetFailedException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package work.slhaf.partner.framework.agent.factory.capability.exception;
|
||||
|
||||
public class DuplicateCapabilityException extends CapabilityCheckFailedException {
|
||||
public DuplicateCapabilityException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public DuplicateCapabilityException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package work.slhaf.partner.framework.agent.factory.capability.exception;
|
||||
|
||||
public class DuplicateMethodException extends CapabilityCheckFailedException {
|
||||
public DuplicateMethodException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public DuplicateMethodException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package work.slhaf.partner.framework.agent.factory.capability.exception;
|
||||
|
||||
public class EmptyCapabilityHolderException extends CapabilityCheckFailedException {
|
||||
public EmptyCapabilityHolderException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public EmptyCapabilityHolderException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package work.slhaf.partner.framework.agent.factory.capability.exception;
|
||||
|
||||
public class UnMatchedCapabilityException extends CapabilityCheckFailedException {
|
||||
public UnMatchedCapabilityException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public UnMatchedCapabilityException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package work.slhaf.partner.framework.agent.factory.capability.exception;
|
||||
|
||||
public class UnMatchedCapabilityMethodException extends CapabilityCheckFailedException {
|
||||
public UnMatchedCapabilityMethodException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public UnMatchedCapabilityMethodException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package work.slhaf.partner.framework.agent.factory.capability.exception;
|
||||
|
||||
public class UnMatchedCoordinatedMethodException extends CapabilityCheckFailedException {
|
||||
public UnMatchedCoordinatedMethodException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public UnMatchedCoordinatedMethodException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
package work.slhaf.partner.framework.agent.factory.component
|
||||
|
||||
import work.slhaf.partner.framework.agent.exception.FactoryExecutionException
|
||||
import work.slhaf.partner.framework.agent.factory.AgentBaseFactory
|
||||
import work.slhaf.partner.framework.agent.factory.component.abstracts.AbstractAgentModule
|
||||
import work.slhaf.partner.framework.agent.factory.component.annotation.AgentComponent
|
||||
import work.slhaf.partner.framework.agent.factory.component.annotation.Init
|
||||
import work.slhaf.partner.framework.agent.factory.component.annotation.InjectModule
|
||||
import work.slhaf.partner.framework.agent.factory.component.exception.ModuleCheckException
|
||||
import work.slhaf.partner.framework.agent.factory.context.AgentRegisterContext
|
||||
import work.slhaf.partner.framework.agent.factory.util.ReflectUtil
|
||||
|
||||
@@ -18,6 +18,8 @@ import work.slhaf.partner.framework.agent.factory.util.ReflectUtil
|
||||
* - 通过校验的 `@Init` 方法按声明类存入 `ComponentFactoryContext`。
|
||||
*/
|
||||
class ComponentAnnotationValidatorFactory : AgentBaseFactory() {
|
||||
private val factoryName = "component-annotation-validator-factory"
|
||||
|
||||
override fun execute(context: AgentRegisterContext) {
|
||||
val reflections = context.reflections
|
||||
val componentFactoryContext = context.componentFactoryContext
|
||||
@@ -27,15 +29,15 @@ class ComponentAnnotationValidatorFactory : AgentBaseFactory() {
|
||||
.forEach { method ->
|
||||
val declaringClass = method.declaringClass
|
||||
if (!ReflectUtil.isAssignableFromAnnotation(declaringClass, AgentComponent::class.java)) {
|
||||
throw ModuleCheckException(
|
||||
"@Init 只能用于 AgentComponent 中: " +
|
||||
"${declaringClass.name}#${method.name}"
|
||||
throw FactoryExecutionException(
|
||||
"@Init can only be declared on AgentComponent classes: ${declaringClass.name}#${method.name}",
|
||||
factoryName
|
||||
)
|
||||
}
|
||||
if (method.parameterCount > 0) {
|
||||
throw ModuleCheckException(
|
||||
"@Init 标注的方法不能包含形参: " +
|
||||
"${declaringClass.name}#${method.name}"
|
||||
throw FactoryExecutionException(
|
||||
"@Init methods must not declare parameters: ${declaringClass.name}#${method.name}",
|
||||
factoryName
|
||||
)
|
||||
}
|
||||
val methods = componentFactoryContext
|
||||
@@ -48,15 +50,15 @@ class ComponentAnnotationValidatorFactory : AgentBaseFactory() {
|
||||
.forEach { field ->
|
||||
val declaringClass = field.declaringClass
|
||||
if (!ReflectUtil.isAssignableFromAnnotation(declaringClass, AgentComponent::class.java)) {
|
||||
throw ModuleCheckException(
|
||||
"@InjectModule 只能用于 AgentComponent 中: " +
|
||||
"${declaringClass.name}#${field.name}"
|
||||
throw FactoryExecutionException(
|
||||
"@InjectModule can only be declared on AgentComponent classes: ${declaringClass.name}#${field.name}",
|
||||
factoryName
|
||||
)
|
||||
}
|
||||
if (AbstractAgentModule.Running::class.java.isAssignableFrom(field.type)) {
|
||||
throw ModuleCheckException(
|
||||
"@InjectModule 不可注入 AbstractAgentModule.Running 子类: " +
|
||||
"${declaringClass.name}#${field.name} -> ${field.type.name}"
|
||||
throw FactoryExecutionException(
|
||||
"@InjectModule cannot target AbstractAgentModule.Running subclasses: ${declaringClass.name}#${field.name} -> ${field.type.name}",
|
||||
factoryName
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package work.slhaf.partner.framework.agent.factory.component
|
||||
|
||||
import work.slhaf.partner.framework.agent.exception.FactoryExecutionException
|
||||
import work.slhaf.partner.framework.agent.factory.AgentBaseFactory
|
||||
import work.slhaf.partner.framework.agent.factory.component.annotation.Init
|
||||
import work.slhaf.partner.framework.agent.factory.component.exception.ModuleInitHookExecuteFailedException
|
||||
import work.slhaf.partner.framework.agent.factory.context.AgentContext
|
||||
import work.slhaf.partner.framework.agent.factory.context.AgentRegisterContext
|
||||
import work.slhaf.partner.framework.agent.factory.util.ReflectUtil.methodSignature
|
||||
@@ -15,6 +15,8 @@ import java.lang.reflect.Method
|
||||
* 执行目标包括 modules 与 additionalComponents,按 `order` 升序执行。
|
||||
*/
|
||||
class ComponentInitHookExecutorFactory : AgentBaseFactory() {
|
||||
private val factoryName = "component-init-hook-executor-factory"
|
||||
|
||||
override fun execute(context: AgentRegisterContext) {
|
||||
val initMethodsByDeclaringType = context.componentFactoryContext.initMethodsByDeclaringType
|
||||
val targets = buildTargets(context.agentContext)
|
||||
@@ -48,21 +50,19 @@ class ComponentInitHookExecutorFactory : AgentBaseFactory() {
|
||||
initMethods.forEach { method ->
|
||||
try {
|
||||
if (method.parameterCount > 0) {
|
||||
throw ModuleInitHookExecuteFailedException(
|
||||
"Init方法不支持参数: ${target::class.java.name}#${methodSignature(method)}"
|
||||
throw FactoryExecutionException(
|
||||
"Init method must not declare parameters: ${target::class.java.name}#${methodSignature(method)}",
|
||||
factoryName
|
||||
)
|
||||
}
|
||||
method.isAccessible = true
|
||||
method.invoke(target)
|
||||
} catch (e: ModuleInitHookExecuteFailedException) {
|
||||
} catch (e: FactoryExecutionException) {
|
||||
throw e
|
||||
} catch (e: Exception) {
|
||||
throw ModuleInitHookExecuteFailedException(
|
||||
"模块的init hook方法执行失败! 模块: ${target::class.java.simpleName} 方法签名: ${
|
||||
methodSignature(
|
||||
method
|
||||
)
|
||||
}",
|
||||
throw FactoryExecutionException(
|
||||
"Failed to execute init hook: ${target::class.java.name}#${methodSignature(method)}",
|
||||
factoryName,
|
||||
e
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package work.slhaf.partner.framework.agent.factory.component
|
||||
|
||||
import work.slhaf.partner.framework.agent.exception.FactoryExecutionException
|
||||
import work.slhaf.partner.framework.agent.factory.AgentBaseFactory
|
||||
import work.slhaf.partner.framework.agent.factory.component.annotation.InjectModule
|
||||
import work.slhaf.partner.framework.agent.factory.component.exception.ModuleInstanceGenerateFailedException
|
||||
import work.slhaf.partner.framework.agent.factory.context.AgentRegisterContext
|
||||
import work.slhaf.partner.framework.agent.factory.context.ModuleContextData
|
||||
import java.lang.reflect.Field
|
||||
@@ -19,6 +19,8 @@ import java.lang.reflect.Modifier
|
||||
* 当注入目标无匹配实例或存在多个匹配实例时抛出异常。
|
||||
*/
|
||||
class ComponentInjectorFactory : AgentBaseFactory() {
|
||||
private val factoryName = "component-injector-factory"
|
||||
|
||||
override fun execute(context: AgentRegisterContext) {
|
||||
val agentContext = context.agentContext
|
||||
val moduleContextList = agentContext.modules.values.toList()
|
||||
@@ -62,8 +64,9 @@ class ComponentInjectorFactory : AgentBaseFactory() {
|
||||
field.isAccessible = true
|
||||
field.set(target, value)
|
||||
} catch (e: IllegalAccessException) {
|
||||
throw ModuleInstanceGenerateFailedException(
|
||||
"模块注入失败: ${target::class.java.name}#${field.name}",
|
||||
throw FactoryExecutionException(
|
||||
"Failed to inject module dependency: ${target::class.java.name}#${field.name}",
|
||||
factoryName,
|
||||
e
|
||||
)
|
||||
}
|
||||
@@ -73,13 +76,15 @@ class ComponentInjectorFactory : AgentBaseFactory() {
|
||||
private fun resolveInjectValue(field: Field, providers: List<Any>, targetClass: Class<*>): Any {
|
||||
val matched = providers.filter { field.type.isAssignableFrom(it::class.java) }
|
||||
if (matched.isEmpty()) {
|
||||
throw ModuleInstanceGenerateFailedException(
|
||||
"模块注入失败, 未找到可注入实例: ${targetClass.name}#${field.name} -> ${field.type.name}"
|
||||
throw FactoryExecutionException(
|
||||
"No injectable module instance found for: ${targetClass.name}#${field.name} -> ${field.type.name}",
|
||||
factoryName
|
||||
)
|
||||
}
|
||||
if (matched.size > 1) {
|
||||
throw ModuleInstanceGenerateFailedException(
|
||||
"模块注入失败, 存在多个可注入实例: ${targetClass.name}#${field.name} -> ${field.type.name}"
|
||||
throw FactoryExecutionException(
|
||||
"Multiple injectable module instances found for: ${targetClass.name}#${field.name} -> ${field.type.name}",
|
||||
factoryName
|
||||
)
|
||||
}
|
||||
return matched.first()
|
||||
|
||||
@@ -3,10 +3,10 @@ package work.slhaf.partner.framework.agent.factory.component
|
||||
import com.alibaba.fastjson2.JSONArray
|
||||
import com.alibaba.fastjson2.JSONObject
|
||||
import org.slf4j.LoggerFactory
|
||||
import work.slhaf.partner.framework.agent.exception.FactoryExecutionException
|
||||
import work.slhaf.partner.framework.agent.factory.AgentBaseFactory
|
||||
import work.slhaf.partner.framework.agent.factory.component.abstracts.AbstractAgentModule
|
||||
import work.slhaf.partner.framework.agent.factory.component.annotation.AgentComponent
|
||||
import work.slhaf.partner.framework.agent.factory.component.exception.ModuleFactoryInitFailedException
|
||||
import work.slhaf.partner.framework.agent.factory.context.AgentContext
|
||||
import work.slhaf.partner.framework.agent.factory.context.AgentRegisterContext
|
||||
import work.slhaf.partner.framework.agent.factory.context.ModuleContextData
|
||||
@@ -25,6 +25,7 @@ import java.time.ZonedDateTime
|
||||
class ComponentRegisterFactory : AgentBaseFactory() {
|
||||
companion object {
|
||||
private val log = LoggerFactory.getLogger(ComponentRegisterFactory::class.java)
|
||||
private const val FACTORY_NAME = "component-register-factory"
|
||||
}
|
||||
|
||||
override fun execute(context: AgentRegisterContext) {
|
||||
@@ -40,7 +41,11 @@ class ComponentRegisterFactory : AgentBaseFactory() {
|
||||
constructor.isAccessible = true
|
||||
constructor.newInstance()
|
||||
} catch (e: Exception) {
|
||||
throw ModuleFactoryInitFailedException("AgentComponent 实例化失败: ${componentClass.name}", e)
|
||||
throw FactoryExecutionException(
|
||||
"Failed to instantiate AgentComponent: ${componentClass.name}",
|
||||
FACTORY_NAME,
|
||||
e
|
||||
)
|
||||
}
|
||||
|
||||
if (componentInstance is AbstractAgentModule) {
|
||||
@@ -62,8 +67,9 @@ class ComponentRegisterFactory : AgentBaseFactory() {
|
||||
module: AbstractAgentModule
|
||||
) {
|
||||
if (agentContext.modules.containsKey(module.moduleName)) {
|
||||
throw ModuleFactoryInitFailedException(
|
||||
"模块注册失败, 存在重复 moduleName: ${module.moduleName} (class=${componentClass.name})"
|
||||
throw FactoryExecutionException(
|
||||
"Duplicate module name detected: ${module.moduleName} (class=${componentClass.name})",
|
||||
FACTORY_NAME
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
package work.slhaf.partner.framework.agent.factory.component.exception;
|
||||
|
||||
public class ModuleCheckException extends ModuleFactoryInitFailedException {
|
||||
public ModuleCheckException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public ModuleCheckException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package work.slhaf.partner.framework.agent.factory.component.exception;
|
||||
|
||||
public class ModuleFactoryInitFailedException extends RuntimeException {
|
||||
public ModuleFactoryInitFailedException(String message) {
|
||||
super("ModuleFactory 执行失败: " + message);
|
||||
}
|
||||
|
||||
public ModuleFactoryInitFailedException(String message, Throwable cause) {
|
||||
super("ModuleFactory 执行失败: " + message, cause);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package work.slhaf.partner.framework.agent.factory.component.exception;
|
||||
|
||||
public class ModuleInitHookExecuteFailedException extends ModuleFactoryInitFailedException {
|
||||
public ModuleInitHookExecuteFailedException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public ModuleInitHookExecuteFailedException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package work.slhaf.partner.framework.agent.factory.component.exception;
|
||||
|
||||
public class ModuleInstanceGenerateFailedException extends ModuleFactoryInitFailedException {
|
||||
public ModuleInstanceGenerateFailedException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public ModuleInstanceGenerateFailedException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package work.slhaf.partner.framework.agent.factory.component.exception;
|
||||
|
||||
public class ModuleProxyGenerateFailedException extends ModuleFactoryInitFailedException {
|
||||
public ModuleProxyGenerateFailedException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public ModuleProxyGenerateFailedException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package work.slhaf.partner.framework.agent.factory.component.exception;
|
||||
|
||||
import work.slhaf.partner.framework.agent.exception.deprecated.AgentRuntimeException;
|
||||
|
||||
public class ProxiedModuleRunningException extends AgentRuntimeException {
|
||||
public ProxiedModuleRunningException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public ProxiedModuleRunningException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package work.slhaf.partner.framework.agent.factory.config.exception;
|
||||
|
||||
public class ConfigDirNotExistException extends ConfigFactoryInitFailedException {
|
||||
public ConfigDirNotExistException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public ConfigDirNotExistException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package work.slhaf.partner.framework.agent.factory.config.exception;
|
||||
|
||||
import work.slhaf.partner.framework.agent.exception.deprecated.AgentLaunchFailedException;
|
||||
|
||||
public class ConfigFactoryInitFailedException extends AgentLaunchFailedException {
|
||||
public ConfigFactoryInitFailedException(String message, Throwable cause) {
|
||||
super("AgentConfigLoader 执行失败: " + message, cause);
|
||||
}
|
||||
|
||||
public ConfigFactoryInitFailedException(String message) {
|
||||
super("AgentConfigLoader 执行失败: " + message);
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package work.slhaf.partner.framework.agent.factory.config.exception;
|
||||
|
||||
import work.slhaf.partner.framework.agent.exception.deprecated.AgentRuntimeException;
|
||||
|
||||
public class ConfigFactoryRuntimeException extends AgentRuntimeException {
|
||||
public ConfigFactoryRuntimeException(String message, Throwable cause) {
|
||||
super("ConfigFactory 运行出错: " + message, cause);
|
||||
}
|
||||
|
||||
public ConfigFactoryRuntimeException(String message) {
|
||||
super("ConfigFactory 运行出错: " + message);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package work.slhaf.partner.framework.agent.factory.config.exception;
|
||||
|
||||
public class ConfigGenerateFailedException extends ConfigFactoryInitFailedException {
|
||||
public ConfigGenerateFailedException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public ConfigGenerateFailedException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package work.slhaf.partner.framework.agent.factory.config.exception;
|
||||
|
||||
public class ConfigNotExistException extends ConfigFactoryInitFailedException {
|
||||
public ConfigNotExistException(String message, Throwable e) {
|
||||
super(message, e);
|
||||
}
|
||||
|
||||
public ConfigNotExistException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package work.slhaf.partner.framework.agent.factory.config.exception;
|
||||
|
||||
public class ConfigUpdateFailedException extends ConfigFactoryRuntimeException {
|
||||
public ConfigUpdateFailedException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public ConfigUpdateFailedException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package work.slhaf.partner.framework.agent.factory.config.exception;
|
||||
|
||||
public class PromptDirNotExistException extends ConfigFactoryInitFailedException {
|
||||
public PromptDirNotExistException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public PromptDirNotExistException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package work.slhaf.partner.framework.agent.factory.config.exception;
|
||||
|
||||
public class PromptNotExistException extends ConfigFactoryInitFailedException {
|
||||
public PromptNotExistException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public PromptNotExistException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@ package work.slhaf.partner.framework.agent.factory.context
|
||||
import com.alibaba.fastjson2.JSONArray
|
||||
import com.alibaba.fastjson2.JSONObject
|
||||
import org.slf4j.LoggerFactory
|
||||
import work.slhaf.partner.framework.agent.exception.deprecated.AgentRunningFailedException
|
||||
import work.slhaf.partner.framework.agent.exception.AgentRuntimeException
|
||||
import work.slhaf.partner.framework.agent.factory.capability.annotation.CapabilityCore
|
||||
import work.slhaf.partner.framework.agent.factory.component.abstracts.AbstractAgentModule
|
||||
import work.slhaf.partner.framework.agent.factory.component.annotation.AgentComponent
|
||||
@@ -150,7 +150,7 @@ object AgentContext {
|
||||
ShutdownHookDesc.Type.CAPABILITY -> instances.capability[clazz]
|
||||
}
|
||||
if (instance == null) {
|
||||
throw AgentRunningFailedException("Instance of type $type not found")
|
||||
throw AgentRuntimeException("Instance of type $type not found")
|
||||
}
|
||||
return instance
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package work.slhaf.partner.framework.agent.factory.context
|
||||
|
||||
import work.slhaf.partner.framework.agent.exception.FactoryExecutionException
|
||||
import work.slhaf.partner.framework.agent.factory.AgentBaseFactory
|
||||
import work.slhaf.partner.framework.agent.factory.capability.annotation.CapabilityCore
|
||||
import work.slhaf.partner.framework.agent.factory.component.annotation.AgentComponent
|
||||
import work.slhaf.partner.framework.agent.factory.component.exception.ModuleCheckException
|
||||
import work.slhaf.partner.framework.agent.factory.util.ReflectUtil
|
||||
|
||||
/**
|
||||
@@ -16,6 +16,8 @@ import work.slhaf.partner.framework.agent.factory.util.ReflectUtil
|
||||
* 收集通过后,统一调用 `AgentContext.addShutdownHook` 注册。
|
||||
*/
|
||||
class ShutdownHookCollectorFactory : AgentBaseFactory() {
|
||||
private val factoryName = "shutdown-hook-collector-factory"
|
||||
|
||||
override fun execute(context: AgentRegisterContext) {
|
||||
val reflections = context.reflections
|
||||
val agentContext = context.agentContext
|
||||
@@ -29,23 +31,24 @@ class ShutdownHookCollectorFactory : AgentBaseFactory() {
|
||||
ReflectUtil.isAssignableFromAnnotation(declaringClass, CapabilityCore::class.java)
|
||||
|
||||
if (!isAgentComponentRelated && !isCapabilityCoreRelated) {
|
||||
throw ModuleCheckException(
|
||||
"@Shutdown 仅能用于 AgentComponent/CapabilityCore 相关类: " +
|
||||
"${declaringClass.name}#${method.name}"
|
||||
throw FactoryExecutionException(
|
||||
"@Shutdown can only be declared on AgentComponent/CapabilityCore classes: ${declaringClass.name}#${method.name}",
|
||||
factoryName
|
||||
)
|
||||
}
|
||||
if (method.parameterCount > 0) {
|
||||
throw ModuleCheckException(
|
||||
"@Shutdown 标注的方法不能包含形参: " +
|
||||
"${declaringClass.name}#${method.name}"
|
||||
throw FactoryExecutionException(
|
||||
"@Shutdown methods must not declare parameters: ${declaringClass.name}#${method.name}",
|
||||
factoryName
|
||||
)
|
||||
}
|
||||
|
||||
val order = method.getAnnotation(Shutdown::class.java).order
|
||||
val added = agentContext.addShutdownHook(method, order)
|
||||
if (!added) {
|
||||
throw ModuleCheckException(
|
||||
"ShutdownHook 收集失败: ${declaringClass.name}#${method.name}"
|
||||
throw FactoryExecutionException(
|
||||
"Failed to collect shutdown hook: ${declaringClass.name}#${method.name}",
|
||||
factoryName
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
package work.slhaf.partner.framework.agent.factory.exception;
|
||||
|
||||
public class AgentRegisterFactoryFailedException extends RuntimeException {
|
||||
public AgentRegisterFactoryFailedException(String message, Throwable cause) {
|
||||
super("AgentRegisterFactory 执行失败: " + message, cause);
|
||||
}
|
||||
|
||||
public AgentRegisterFactoryFailedException(String message) {
|
||||
super("AgentRegisterFactory 执行失败: " + message);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package work.slhaf.partner.framework.agent.factory.exception;
|
||||
|
||||
public class ExternalModuleLoadFailedException extends AgentRegisterFactoryFailedException {
|
||||
public ExternalModuleLoadFailedException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public ExternalModuleLoadFailedException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -7,11 +7,13 @@ import work.slhaf.partner.framework.agent.config.Config
|
||||
import work.slhaf.partner.framework.agent.config.ConfigDoc
|
||||
import work.slhaf.partner.framework.agent.config.ConfigRegistration
|
||||
import work.slhaf.partner.framework.agent.config.Configurable
|
||||
import work.slhaf.partner.framework.agent.exception.*
|
||||
import java.nio.file.Path
|
||||
import java.util.concurrent.locks.ReentrantLock
|
||||
import kotlin.concurrent.withLock
|
||||
|
||||
object AgentGatewayRegistry : Configurable, ConfigRegistration<AgentGatewayRegistryConfig>, AutoCloseable {
|
||||
private const val COMPONENT_NAME = "agent-gateway-registry"
|
||||
|
||||
private val log = LoggerFactory.getLogger(AgentGatewayRegistry::class.java)
|
||||
private val registryLock = ReentrantLock()
|
||||
@@ -26,8 +28,11 @@ object AgentGatewayRegistry : Configurable, ConfigRegistration<AgentGatewayRegis
|
||||
|
||||
fun register(registration: AgentGatewayRegistration) = registryLock.withLock {
|
||||
val previous = registrations.putIfAbsent(registration.channelName, registration)
|
||||
check(previous == null || previous === registration) {
|
||||
"AgentGateway channel already registered: ${registration.channelName}"
|
||||
checkAgentStartup(previous == null || previous === registration) {
|
||||
AgentStartupException(
|
||||
"AgentGateway channel already registered: ${registration.channelName}",
|
||||
COMPONENT_NAME
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +45,13 @@ object AgentGatewayRegistry : Configurable, ConfigRegistration<AgentGatewayRegis
|
||||
}
|
||||
|
||||
override fun init(config: AgentGatewayRegistryConfig, json: JSONObject?) = registryLock.withLock {
|
||||
try {
|
||||
applyConfig(config)
|
||||
} catch (e: GatewayRegistryException) {
|
||||
throw GatewayStartupException(e.message ?: "Failed to apply gateway registry config", e.gatewayName, e)
|
||||
} catch (e: GatewayException) {
|
||||
throw GatewayStartupException(e.message ?: "Failed to apply gateway config", e.gatewayName, e)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onReload(config: AgentGatewayRegistryConfig, json: JSONObject?) = registryLock.withLock {
|
||||
@@ -48,7 +59,10 @@ object AgentGatewayRegistry : Configurable, ConfigRegistration<AgentGatewayRegis
|
||||
val defaultSnapshot = AgentRuntime.defaultResponseChannel()
|
||||
try {
|
||||
applyConfig(config)
|
||||
} catch (e: Exception) {
|
||||
} catch (e: GatewayRegistryException) {
|
||||
log.error("Error while reloading gateway config", e)
|
||||
restoreSnapshot(runtimeSnapshot, defaultSnapshot)
|
||||
} catch (e: GatewayException) {
|
||||
log.error("Error while reloading gateway config", e)
|
||||
restoreSnapshot(runtimeSnapshot, defaultSnapshot)
|
||||
}
|
||||
@@ -69,20 +83,34 @@ object AgentGatewayRegistry : Configurable, ConfigRegistration<AgentGatewayRegis
|
||||
}
|
||||
|
||||
private fun validateConfig(config: AgentGatewayRegistryConfig) {
|
||||
require(config.defaultChannel.isNotBlank()) { "default_channel must not be blank" }
|
||||
require(config.channels.isNotEmpty()) { "channels must not be empty" }
|
||||
if (config.defaultChannel.isBlank()) {
|
||||
throw GatewayRegistryException("default_channel must not be blank", COMPONENT_NAME)
|
||||
}
|
||||
if (config.channels.isEmpty()) {
|
||||
throw GatewayRegistryException("channels must not be empty", COMPONENT_NAME)
|
||||
}
|
||||
|
||||
val channelNames = mutableSetOf<String>()
|
||||
config.channels.forEach { channel ->
|
||||
require(channel.channelName.isNotBlank()) { "channel_name must not be blank" }
|
||||
require(channelNames.add(channel.channelName)) { "Duplicated channel_name: ${channel.channelName}" }
|
||||
require(registrations.containsKey(channel.channelName)) {
|
||||
"AgentGateway channel is not registered: ${channel.channelName}"
|
||||
if (channel.channelName.isBlank()) {
|
||||
throw GatewayRegistryException("channel_name must not be blank", COMPONENT_NAME)
|
||||
}
|
||||
if (!channelNames.add(channel.channelName)) {
|
||||
throw GatewayRegistryException("Duplicate channel_name: ${channel.channelName}", channel.channelName)
|
||||
}
|
||||
if (!registrations.containsKey(channel.channelName)) {
|
||||
throw GatewayRegistryException(
|
||||
"AgentGateway channel is not registered: ${channel.channelName}",
|
||||
channel.channelName
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
require(channelNames.contains(config.defaultChannel)) {
|
||||
"default_channel must exist in channels: ${config.defaultChannel}"
|
||||
if (!channelNames.contains(config.defaultChannel)) {
|
||||
throw GatewayRegistryException(
|
||||
"default_channel must exist in channels: ${config.defaultChannel}",
|
||||
config.defaultChannel
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,7 +121,10 @@ object AgentGatewayRegistry : Configurable, ConfigRegistration<AgentGatewayRegis
|
||||
|
||||
configuredChannels.forEach { channelConfig ->
|
||||
val registration = registrations[channelConfig.channelName]
|
||||
?: error("AgentGateway channel is not registered: ${channelConfig.channelName}")
|
||||
?: throw GatewayRegistryException(
|
||||
"AgentGateway channel is not registered: ${channelConfig.channelName}",
|
||||
channelConfig.channelName
|
||||
)
|
||||
val existing = runningChannels[channelConfig.channelName]
|
||||
if (existing != null && existing.registration === registration &&
|
||||
registration.supportsHotReloadReuse(existing.params, channelConfig.params)
|
||||
@@ -129,7 +160,11 @@ object AgentGatewayRegistry : Configurable, ConfigRegistration<AgentGatewayRegis
|
||||
shutdownError
|
||||
)
|
||||
}
|
||||
throw e
|
||||
throw GatewayException(
|
||||
"Failed to launch gateway channel: ${channelConfig.channelName}",
|
||||
channelConfig.channelName,
|
||||
e
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,8 @@ import work.slhaf.partner.framework.agent.config.Config
|
||||
import work.slhaf.partner.framework.agent.config.ConfigDoc
|
||||
import work.slhaf.partner.framework.agent.config.ConfigRegistration
|
||||
import work.slhaf.partner.framework.agent.config.Configurable
|
||||
import work.slhaf.partner.framework.agent.exception.ModelRegistryException
|
||||
import work.slhaf.partner.framework.agent.exception.ModelRegistryStartupException
|
||||
import work.slhaf.partner.framework.agent.model.ProviderConfig.ProviderType.OPENAI_COMPATIBLE
|
||||
import work.slhaf.partner.framework.agent.model.provider.ModelProvider
|
||||
import work.slhaf.partner.framework.agent.model.provider.ProviderOverride
|
||||
@@ -18,6 +20,7 @@ import kotlin.concurrent.withLock
|
||||
object ModelRuntimeRegistry : Configurable, ConfigRegistration<ModelRuntimeRegistryConfig> {
|
||||
|
||||
private const val DEFAULT_PROVIDER = "default"
|
||||
private const val COMPONENT_NAME = "model-runtime-registry"
|
||||
|
||||
/**
|
||||
* 基础的 provider 提供商,可 fork 出新的 runtime provider,必须提供一个 default provider
|
||||
@@ -49,14 +52,29 @@ object ModelRuntimeRegistry : Configurable, ConfigRegistration<ModelRuntimeRegis
|
||||
|
||||
private fun forkProvider(config: RuntimeProviderConfig) {
|
||||
val provider = baseProvider[config.providerName]
|
||||
?: throw IllegalArgumentException("Provider ${config.providerName} not found")
|
||||
?: throw runtimeModelException(
|
||||
"Provider ${config.providerName} not found",
|
||||
config.providerName,
|
||||
config.modelKey,
|
||||
config.override
|
||||
)
|
||||
val override = config.override
|
||||
|
||||
try {
|
||||
runtimeProvider[config.modelKey] = if (override != null) {
|
||||
provider.fork(override)
|
||||
} else {
|
||||
provider
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
throw runtimeModelException(
|
||||
"Failed to build runtime provider for model key ${config.modelKey}",
|
||||
config.providerName,
|
||||
config.modelKey,
|
||||
override,
|
||||
e
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun declare(): Map<Path, ConfigRegistration<out Config>> {
|
||||
@@ -66,8 +84,17 @@ object ModelRuntimeRegistry : Configurable, ConfigRegistration<ModelRuntimeRegis
|
||||
override fun type(): Class<ModelRuntimeRegistryConfig> = ModelRuntimeRegistryConfig::class.java
|
||||
|
||||
override fun init(config: ModelRuntimeRegistryConfig, json: JSONObject?) = providerLock.withLock {
|
||||
config.providerConfigSet.forEach { registerProvider(it) }
|
||||
config.runtimeConfigSet.forEach { forkProvider(it) }
|
||||
try {
|
||||
applyConfig(config)
|
||||
} catch (e: ModelRegistryException) {
|
||||
throw ModelRegistryStartupException(
|
||||
e.message ?: "Failed to apply model runtime config",
|
||||
e.providerName,
|
||||
e.modelKey,
|
||||
e.override,
|
||||
e
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onReload(config: ModelRuntimeRegistryConfig, json: JSONObject?) = providerLock.withLock {
|
||||
@@ -76,19 +103,33 @@ object ModelRuntimeRegistry : Configurable, ConfigRegistration<ModelRuntimeRegis
|
||||
val runtimeProviderSnapshot = runtimeProvider.toMap()
|
||||
try {
|
||||
val providerSetJson = root.getJSONArray("providerConfigSet")
|
||||
?: throw IllegalStateException("providerConfigSet is missing or not an array")
|
||||
?: throw runtimeModelException("providerConfigSet is missing or not an array")
|
||||
baseProvider.clear()
|
||||
for (i in providerSetJson.indices) {
|
||||
val providerJson = providerSetJson.getJSONObject(i)
|
||||
?: throw IllegalStateException("providerConfigSet[$i] is not an object")
|
||||
?: throw runtimeModelException("providerConfigSet[$i] is not an object")
|
||||
val typeText = providerJson.getString("type")
|
||||
?: throw IllegalStateException("providerConfigSet[$i].type is missing")
|
||||
val providerType = ProviderConfig.ProviderType.valueOf(typeText.uppercase(getDefault()))
|
||||
?: throw runtimeModelException(
|
||||
"providerConfigSet[$i].type is missing",
|
||||
providerJson.getString("name") ?: COMPONENT_NAME
|
||||
)
|
||||
val providerType = try {
|
||||
ProviderConfig.ProviderType.valueOf(typeText.uppercase(getDefault()))
|
||||
} catch (e: IllegalArgumentException) {
|
||||
throw runtimeModelException(
|
||||
"Unsupported provider type: $typeText",
|
||||
providerJson.getString("name") ?: COMPONENT_NAME,
|
||||
cause = e
|
||||
)
|
||||
}
|
||||
val concreteProviderConfig = when (providerType) {
|
||||
OPENAI_COMPATIBLE -> providerJson.toJavaObject(OpenAiCompatibleProviderConfig::class.java)
|
||||
}
|
||||
registerProvider(concreteProviderConfig)
|
||||
}
|
||||
if (!baseProvider.containsKey(DEFAULT_PROVIDER)) {
|
||||
throw runtimeModelException("Provider default not found", DEFAULT_PROVIDER)
|
||||
}
|
||||
runtimeProvider.clear()
|
||||
config.runtimeConfigSet.forEach { forkProvider(it) }
|
||||
} catch (e: Exception) {
|
||||
@@ -114,6 +155,42 @@ object ModelRuntimeRegistry : Configurable, ConfigRegistration<ModelRuntimeRegis
|
||||
), setOf()
|
||||
)
|
||||
}
|
||||
|
||||
private fun applyConfig(config: ModelRuntimeRegistryConfig) {
|
||||
baseProvider.clear()
|
||||
runtimeProvider.clear()
|
||||
config.providerConfigSet.forEach { registerProvider(it) }
|
||||
if (!baseProvider.containsKey(DEFAULT_PROVIDER)) {
|
||||
throw runtimeModelException("Provider default not found", DEFAULT_PROVIDER)
|
||||
}
|
||||
config.runtimeConfigSet.forEach { forkProvider(it) }
|
||||
}
|
||||
|
||||
private fun runtimeModelException(
|
||||
message: String,
|
||||
providerName: String = COMPONENT_NAME,
|
||||
modelKey: String = COMPONENT_NAME,
|
||||
override: ProviderOverride? = null,
|
||||
cause: Throwable? = null
|
||||
): ModelRegistryException {
|
||||
return ModelRegistryException(
|
||||
message,
|
||||
providerName,
|
||||
modelKey,
|
||||
override?.toReportOverride() ?: emptyMap(),
|
||||
cause
|
||||
)
|
||||
}
|
||||
|
||||
private fun ProviderOverride.toReportOverride(): Map<String, String> {
|
||||
val result = linkedMapOf<String, String>()
|
||||
result["model"] = model
|
||||
temperature?.let { result["temperature"] = it.toString() }
|
||||
topP?.let { result["topP"] = it.toString() }
|
||||
maxTokens?.let { result["maxTokens"] = it.toString() }
|
||||
extras?.forEach { (key, value) -> result["extra.$key"] = value?.toString() ?: "null" }
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
data class ModelRuntimeRegistryConfig(
|
||||
|
||||
Reference in New Issue
Block a user