refactor(framework): migrate startup chain exceptions to AgentException hierarchy

This commit is contained in:
2026-04-10 22:39:59 +08:00
parent ec52d64e73
commit 3732555f02
41 changed files with 328 additions and 413 deletions

View File

@@ -3,7 +3,8 @@ package work.slhaf.partner.framework.agent.config
import com.alibaba.fastjson2.JSON import com.alibaba.fastjson2.JSON
import com.alibaba.fastjson2.JSONObject import com.alibaba.fastjson2.JSONObject
import org.slf4j.LoggerFactory 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 work.slhaf.partner.framework.agent.support.DirectoryWatchSupport
import java.io.IOException import java.io.IOException
import java.lang.reflect.Field import java.lang.reflect.Field
@@ -19,6 +20,7 @@ import kotlin.reflect.full.memberProperties
import kotlin.reflect.jvm.javaField import kotlin.reflect.jvm.javaField
object ConfigCenter : AutoCloseable { object ConfigCenter : AutoCloseable {
private const val COMPONENT_NAME = "config-center"
private val log = LoggerFactory.getLogger(ConfigCenter::class.java) private val log = LoggerFactory.getLogger(ConfigCenter::class.java)
val paths = resolvePaths() val paths = resolvePaths()
@@ -31,9 +33,8 @@ object ConfigCenter : AutoCloseable {
@Synchronized @Synchronized
fun register(configurable: Configurable) { fun register(configurable: Configurable) {
checkAgentStartup(!started) {
check(!started) { AgentStartupException("ConfigCenter does not allow registration after watching started", COMPONENT_NAME)
"ConfigCenter does not allow registration after watching started"
} }
val declared = configurable.declare() val declared = configurable.declare()
@@ -42,15 +43,18 @@ object ConfigCenter : AutoCloseable {
declared.forEach { (path, registration) -> declared.forEach { (path, registration) ->
val normalizedPath = normalizeRelativePath(path) val normalizedPath = normalizeRelativePath(path)
check(normalized.putIfAbsent(normalizedPath, registration) == null) { checkAgentStartup(normalized.putIfAbsent(normalizedPath, registration) == null) {
"Duplicated config path declared in the same configurable: $normalizedPath" AgentStartupException(
"Duplicated config path declared in the same configurable: $normalizedPath",
COMPONENT_NAME
)
} }
} }
normalized.forEach { (path, registration) -> normalized.forEach { (path, registration) ->
check(registrations.putIfAbsent(path, registration) == null) { checkAgentStartup(registrations.putIfAbsent(path, registration) == null) {
"Config path already registered: $path" AgentStartupException("Config path already registered: $path", COMPONENT_NAME)
} }
} }
@@ -93,7 +97,10 @@ object ConfigCenter : AutoCloseable {
(registration as ConfigRegistration<Config>).init(defaultConfig, null) (registration as ConfigRegistration<Config>).init(defaultConfig, null)
} }
val configDoc = resolveConfigDoc(registration.type()) 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 { private fun normalizeRelativePath(path: Path): Path {
require(!path.isAbsolute) { checkAgentStartup(!path.isAbsolute) {
"Config path must be relative: $path" AgentStartupException("Config path must be relative: $path", COMPONENT_NAME)
} }
return path.normalize() return path.normalize()
} }

View File

@@ -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( open class ModelInvokeException(
message: String, message: String,
val providerName: String, val providerName: String,
@@ -51,3 +61,17 @@ open class ModelInvokeException(
it.extra["override"] = override 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
}
}

View File

@@ -23,3 +23,31 @@ open class FactoryExecutionException @JvmOverloads constructor(
return report 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
}
}

View File

@@ -1,6 +1,7 @@
package work.slhaf.partner.framework.agent.factory package work.slhaf.partner.framework.agent.factory
import org.reflections.util.ClasspathHelper 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.CapabilityAnnotationValidatorFactory
import work.slhaf.partner.framework.agent.factory.capability.CapabilityInjectorFactory import work.slhaf.partner.framework.agent.factory.capability.CapabilityInjectorFactory
import work.slhaf.partner.framework.agent.factory.capability.CapabilityRegisterFactory 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.component.ComponentRegisterFactory
import work.slhaf.partner.framework.agent.factory.context.AgentRegisterContext 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.context.ShutdownHookCollectorFactory
import work.slhaf.partner.framework.agent.factory.exception.ExternalModuleLoadFailedException
import java.io.File import java.io.File
import java.net.URL import java.net.URL
@@ -72,7 +72,11 @@ object AgentRegisterFactory {
.filter { it.name.endsWith(".jar") } .filter { it.name.endsWith(".jar") }
.forEach { urls.add(it.toURI().toURL()) } .forEach { urls.add(it.toURI().toURL()) }
} catch (e: Exception) { } catch (e: Exception) {
throw ExternalModuleLoadFailedException("外部模块URL获取失败: $externalPackagePath", e) throw FactoryExecutionException(
"Failed to load external module URLs from: $externalPackagePath",
"agent-register-factory",
e
)
} }
} }

View File

@@ -2,14 +2,12 @@ package work.slhaf.partner.framework.agent.factory.capability
import cn.hutool.core.util.ClassUtil import cn.hutool.core.util.ClassUtil
import org.reflections.Reflections 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.AgentBaseFactory
import work.slhaf.partner.framework.agent.factory.capability.annotation.Capability 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.CapabilityCore
import work.slhaf.partner.framework.agent.factory.capability.annotation.CapabilityMethod 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.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.component.annotation.AgentComponent
import work.slhaf.partner.framework.agent.factory.context.AgentRegisterContext import work.slhaf.partner.framework.agent.factory.context.AgentRegisterContext
import work.slhaf.partner.framework.agent.factory.util.ReflectUtil.isAssignableFromAnnotation 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` 相关类中。 * - `@InjectCapability` 字段仅允许位于 `@AgentComponent` 相关类中。
*/ */
class CapabilityAnnotationValidatorFactory : AgentBaseFactory() { class CapabilityAnnotationValidatorFactory : AgentBaseFactory() {
private val factoryName = "capability-annotation-validator-factory"
override fun execute(context: AgentRegisterContext) { override fun execute(context: AgentRegisterContext) {
val reflections = context.reflections val reflections = context.reflections
val cores = loadCores(reflections) val cores = loadCores(reflections)
@@ -61,7 +61,7 @@ class CapabilityAnnotationValidatorFactory : AgentBaseFactory() {
val value = capability.getAnnotation(Capability::class.java).value val value = capability.getAnnotation(Capability::class.java).value
val existed = capabilityByValue.putIfAbsent(value, capability) val existed = capabilityByValue.putIfAbsent(value, capability)
if (existed != null) { 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 -> methods.forEach { method ->
val declaringClass = method.declaringClass val declaringClass = method.declaringClass
if (!declaringClass.isAnnotationPresent(CapabilityCore::class.java)) { if (!declaringClass.isAnnotationPresent(CapabilityCore::class.java)) {
throw UnMatchedCapabilityException( throw FactoryExecutionException(
"@CapabilityMethod 仅能用于 @CapabilityCore 所标注类中: " + "@CapabilityMethod can only be declared in @CapabilityCore classes: ${declaringClass.name}#${method.name}",
"${declaringClass.name}#${method.name}" factoryName
) )
} }
} }
@@ -109,13 +109,19 @@ class CapabilityAnnotationValidatorFactory : AgentBaseFactory() {
val signature = methodSignature(method) val signature = methodSignature(method)
val implementors = signatureMap[signature].orEmpty() val implementors = signatureMap[signature].orEmpty()
if (implementors.isEmpty()) { if (implementors.isEmpty()) {
throw UnMatchedCapabilityMethodException( throw FactoryExecutionException(
"Capability方法缺少实现: $capabilityValue.$signature" "Missing capability method implementation: $capabilityValue.$signature",
factoryName
) )
} }
if (implementors.size > 1) { if (implementors.size > 1) {
throw UnMatchedCapabilityMethodException( throw FactoryExecutionException(
"Capability方法存在多个实现: $capabilityValue.$signature -> ${implementors.joinToString(", ")}" "Multiple capability method implementations found: $capabilityValue.$signature -> ${
implementors.joinToString(
", "
)
}",
factoryName
) )
} }
} }
@@ -129,8 +135,9 @@ class CapabilityAnnotationValidatorFactory : AgentBaseFactory() {
reflections.getFieldsAnnotatedWith(InjectCapability::class.java).forEach { field -> reflections.getFieldsAnnotatedWith(InjectCapability::class.java).forEach { field ->
val declaringClass = field.declaringClass val declaringClass = field.declaringClass
if (!isAssignableFromAnnotation(declaringClass, AgentComponent::class.java)) { if (!isAssignableFromAnnotation(declaringClass, AgentComponent::class.java)) {
throw UnMatchedCapabilityException( throw FactoryExecutionException(
"InjectCapability 注解只能用于 AgentComponent 注解所在类,检查该类是否使用了@CapabilityHolder注解或者受其标注的注解或父类: $declaringClass" "@InjectCapability can only be declared on AgentComponent classes: $declaringClass",
factoryName
) )
} }
} }

View File

@@ -1,9 +1,9 @@
package work.slhaf.partner.framework.agent.factory.capability 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.AgentBaseFactory
import work.slhaf.partner.framework.agent.factory.capability.annotation.Capability 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.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.AgentContext
import work.slhaf.partner.framework.agent.factory.context.AgentRegisterContext import work.slhaf.partner.framework.agent.factory.context.AgentRegisterContext
import java.lang.reflect.Field import java.lang.reflect.Field
@@ -16,6 +16,8 @@ import java.lang.reflect.Modifier
* 注入值来源于 `AgentContext.capabilities`。 * 注入值来源于 `AgentContext.capabilities`。
*/ */
class CapabilityInjectorFactory : AgentBaseFactory() { class CapabilityInjectorFactory : AgentBaseFactory() {
private val factoryName = "capability-injector-factory"
override fun execute(context: AgentRegisterContext) { override fun execute(context: AgentRegisterContext) {
val agentContext = context.agentContext val agentContext = context.agentContext
val targets = buildTargets(agentContext) val targets = buildTargets(agentContext)
@@ -38,11 +40,12 @@ class CapabilityInjectorFactory : AgentBaseFactory() {
field.isAccessible = true field.isAccessible = true
val value = resolveCapabilityInstance(field, capabilityMap, target::class.java) val value = resolveCapabilityInstance(field, capabilityMap, target::class.java)
field.set(target, value) field.set(target, value)
} catch (e: CapabilityProxySetFailedException) { } catch (e: FactoryExecutionException) {
throw e throw e
} catch (e: Exception) { } catch (e: Exception) {
throw CapabilityProxySetFailedException( throw FactoryExecutionException(
"Capability 注入失败: ${target::class.java.name}#${field.name}", "Failed to inject capability dependency: ${target::class.java.name}#${field.name}",
factoryName,
e e
) )
} }
@@ -55,17 +58,20 @@ class CapabilityInjectorFactory : AgentBaseFactory() {
targetClass: Class<*> targetClass: Class<*>
): Any { ): Any {
val capability = field.type.getAnnotation(Capability::class.java) val capability = field.type.getAnnotation(Capability::class.java)
?: throw CapabilityProxySetFailedException( ?: throw FactoryExecutionException(
"InjectCapability 字段类型未标注 @Capability: ${targetClass.name}#${field.name} -> ${field.type.name}" "InjectCapability target type is not annotated with @Capability: ${targetClass.name}#${field.name} -> ${field.type.name}",
factoryName
) )
val capabilityValue = capability.value val capabilityValue = capability.value
val implementation = capabilityMap[capabilityValue] ?: throw CapabilityProxySetFailedException( val implementation = capabilityMap[capabilityValue] ?: throw FactoryExecutionException(
"未找到可注入 Capability 实例: ${targetClass.name}#${field.name} -> $capabilityValue" "Injectable capability implementation not found: ${targetClass.name}#${field.name} -> $capabilityValue",
factoryName
) )
if (!field.type.isAssignableFrom(implementation.instance.javaClass)) { if (!field.type.isAssignableFrom(implementation.instance.javaClass)) {
throw CapabilityProxySetFailedException( throw FactoryExecutionException(
"Capability 实例类型不匹配: ${targetClass.name}#${field.name} -> $capabilityValue" "Capability implementation type mismatch: ${targetClass.name}#${field.name} -> $capabilityValue",
factoryName
) )
} }
return implementation.instance return implementation.instance

View File

@@ -1,12 +1,10 @@
package work.slhaf.partner.framework.agent.factory.capability 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.AgentBaseFactory
import work.slhaf.partner.framework.agent.factory.capability.annotation.Capability 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.CapabilityCore
import work.slhaf.partner.framework.agent.factory.capability.annotation.CapabilityMethod 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.context.AgentRegisterContext
import work.slhaf.partner.framework.agent.factory.util.ReflectUtil.methodSignature import work.slhaf.partner.framework.agent.factory.util.ReflectUtil.methodSignature
import java.lang.reflect.Method import java.lang.reflect.Method
@@ -23,6 +21,8 @@ import java.util.function.Function
* - 将 capability 代理、cores 与方法映射注册到 `AgentContext`。 * - 将 capability 代理、cores 与方法映射注册到 `AgentContext`。
*/ */
class CapabilityRegisterFactory : AgentBaseFactory() { class CapabilityRegisterFactory : AgentBaseFactory() {
private val factoryName = "capability-register-factory"
override fun execute(context: AgentRegisterContext) { override fun execute(context: AgentRegisterContext) {
val capabilityFactoryContext = context.capabilityFactoryContext val capabilityFactoryContext = context.capabilityFactoryContext
val agentContext = context.agentContext val agentContext = context.agentContext
@@ -30,7 +30,10 @@ class CapabilityRegisterFactory : AgentBaseFactory() {
val cores = capabilityFactoryContext.cores.toSet() val cores = capabilityFactoryContext.cores.toSet()
val capabilities = capabilityFactoryContext.capabilities.toSet() val capabilities = capabilityFactoryContext.capabilities.toSet()
if (cores.isEmpty() || capabilities.isEmpty()) { 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>() val coreInstances = LinkedHashMap<Class<*>, Any>()
@@ -59,7 +62,7 @@ class CapabilityRegisterFactory : AgentBaseFactory() {
coreInstances[core] = constructor.newInstance() coreInstances[core] = constructor.newInstance()
} }
} catch (e: Exception) { } 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 -> cores.forEach { core ->
val capabilityValue = core.getAnnotation(CapabilityCore::class.java).value val capabilityValue = core.getAnnotation(CapabilityCore::class.java).value
val coreInstance = coreInstances[core] val coreInstance = coreInstances[core]
?: throw CapabilityFactoryExecuteFailedException("未找到CapabilityCore实例: ${core.name}") ?: throw FactoryExecutionException("Capability core instance not found: ${core.name}", factoryName)
core.methods core.methods
.filter { it.isAnnotationPresent(CapabilityMethod::class.java) } .filter { it.isAnnotationPresent(CapabilityMethod::class.java) }
.forEach { method -> .forEach { method ->
val key = "$capabilityValue.${methodSignature(method)}" val key = "$capabilityValue.${methodSignature(method)}"
if (map.containsKey(key) || methodsRouterTable.containsKey(key)) { 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) map[key] = MethodBinding(core, coreInstance, method)
methodsRouterTable[key] = Function { args -> methodsRouterTable[key] = Function { args ->
@@ -106,7 +112,7 @@ class CapabilityRegisterFactory : AgentBaseFactory() {
else -> { else -> {
val key = "$capabilityValue.${methodSignature(method)}" val key = "$capabilityValue.${methodSignature(method)}"
val fn = methodsRouterTable[key] val fn = methodsRouterTable[key]
?: throw CapabilityFactoryExecuteFailedException("未找到能力方法路由: $key") ?: throw FactoryExecutionException("Capability method route not found: $key", factoryName)
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
val actualArgs = (args ?: emptyArray<Any?>()) as Array<Any?> val actualArgs = (args ?: emptyArray<Any?>()) as Array<Any?>
@@ -128,7 +134,7 @@ class CapabilityRegisterFactory : AgentBaseFactory() {
} }
val key = "$capabilityValue.${methodSignature(method)}" val key = "$capabilityValue.${methodSignature(method)}"
val binding = methodBindingMap[key] val binding = methodBindingMap[key]
?: throw CapabilityFactoryExecuteFailedException("Capability方法缺少实现: $key") ?: throw FactoryExecutionException("Missing capability method implementation for: $key", factoryName)
methods[key] = binding.method methods[key] = binding.method
} }
return methods return methods
@@ -149,8 +155,9 @@ class CapabilityRegisterFactory : AgentBaseFactory() {
return try { return try {
method.invoke(instance, *args) method.invoke(instance, *args)
} catch (e: Exception) { } catch (e: Exception) {
throw CapabilityFactoryExecuteFailedException( throw FactoryExecutionException(
"能力方法调用失败: ${instance::class.java.name}#${method.name}", "Failed to invoke capability method: ${instance::class.java.name}#${method.name}",
factoryName,
e e
) )
} }

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -1,11 +1,11 @@
package work.slhaf.partner.framework.agent.factory.component 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.AgentBaseFactory
import work.slhaf.partner.framework.agent.factory.component.abstracts.AbstractAgentModule 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.AgentComponent
import work.slhaf.partner.framework.agent.factory.component.annotation.Init 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.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.context.AgentRegisterContext
import work.slhaf.partner.framework.agent.factory.util.ReflectUtil import work.slhaf.partner.framework.agent.factory.util.ReflectUtil
@@ -18,6 +18,8 @@ import work.slhaf.partner.framework.agent.factory.util.ReflectUtil
* - 通过校验的 `@Init` 方法按声明类存入 `ComponentFactoryContext`。 * - 通过校验的 `@Init` 方法按声明类存入 `ComponentFactoryContext`。
*/ */
class ComponentAnnotationValidatorFactory : AgentBaseFactory() { class ComponentAnnotationValidatorFactory : AgentBaseFactory() {
private val factoryName = "component-annotation-validator-factory"
override fun execute(context: AgentRegisterContext) { override fun execute(context: AgentRegisterContext) {
val reflections = context.reflections val reflections = context.reflections
val componentFactoryContext = context.componentFactoryContext val componentFactoryContext = context.componentFactoryContext
@@ -27,15 +29,15 @@ class ComponentAnnotationValidatorFactory : AgentBaseFactory() {
.forEach { method -> .forEach { method ->
val declaringClass = method.declaringClass val declaringClass = method.declaringClass
if (!ReflectUtil.isAssignableFromAnnotation(declaringClass, AgentComponent::class.java)) { if (!ReflectUtil.isAssignableFromAnnotation(declaringClass, AgentComponent::class.java)) {
throw ModuleCheckException( throw FactoryExecutionException(
"@Init 只能用于 AgentComponent 中: " + "@Init can only be declared on AgentComponent classes: ${declaringClass.name}#${method.name}",
"${declaringClass.name}#${method.name}" factoryName
) )
} }
if (method.parameterCount > 0) { if (method.parameterCount > 0) {
throw ModuleCheckException( throw FactoryExecutionException(
"@Init 标注的方法不能包含形参: " + "@Init methods must not declare parameters: ${declaringClass.name}#${method.name}",
"${declaringClass.name}#${method.name}" factoryName
) )
} }
val methods = componentFactoryContext val methods = componentFactoryContext
@@ -48,15 +50,15 @@ class ComponentAnnotationValidatorFactory : AgentBaseFactory() {
.forEach { field -> .forEach { field ->
val declaringClass = field.declaringClass val declaringClass = field.declaringClass
if (!ReflectUtil.isAssignableFromAnnotation(declaringClass, AgentComponent::class.java)) { if (!ReflectUtil.isAssignableFromAnnotation(declaringClass, AgentComponent::class.java)) {
throw ModuleCheckException( throw FactoryExecutionException(
"@InjectModule 只能用于 AgentComponent 中: " + "@InjectModule can only be declared on AgentComponent classes: ${declaringClass.name}#${field.name}",
"${declaringClass.name}#${field.name}" factoryName
) )
} }
if (AbstractAgentModule.Running::class.java.isAssignableFrom(field.type)) { if (AbstractAgentModule.Running::class.java.isAssignableFrom(field.type)) {
throw ModuleCheckException( throw FactoryExecutionException(
"@InjectModule 不可注入 AbstractAgentModule.Running 子类: " + "@InjectModule cannot target AbstractAgentModule.Running subclasses: ${declaringClass.name}#${field.name} -> ${field.type.name}",
"${declaringClass.name}#${field.name} -> ${field.type.name}" factoryName
) )
} }
} }

View File

@@ -1,8 +1,8 @@
package work.slhaf.partner.framework.agent.factory.component 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.AgentBaseFactory
import work.slhaf.partner.framework.agent.factory.component.annotation.Init 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.AgentContext
import work.slhaf.partner.framework.agent.factory.context.AgentRegisterContext import work.slhaf.partner.framework.agent.factory.context.AgentRegisterContext
import work.slhaf.partner.framework.agent.factory.util.ReflectUtil.methodSignature import work.slhaf.partner.framework.agent.factory.util.ReflectUtil.methodSignature
@@ -15,6 +15,8 @@ import java.lang.reflect.Method
* 执行目标包括 modules 与 additionalComponents按 `order` 升序执行。 * 执行目标包括 modules 与 additionalComponents按 `order` 升序执行。
*/ */
class ComponentInitHookExecutorFactory : AgentBaseFactory() { class ComponentInitHookExecutorFactory : AgentBaseFactory() {
private val factoryName = "component-init-hook-executor-factory"
override fun execute(context: AgentRegisterContext) { override fun execute(context: AgentRegisterContext) {
val initMethodsByDeclaringType = context.componentFactoryContext.initMethodsByDeclaringType val initMethodsByDeclaringType = context.componentFactoryContext.initMethodsByDeclaringType
val targets = buildTargets(context.agentContext) val targets = buildTargets(context.agentContext)
@@ -48,21 +50,19 @@ class ComponentInitHookExecutorFactory : AgentBaseFactory() {
initMethods.forEach { method -> initMethods.forEach { method ->
try { try {
if (method.parameterCount > 0) { if (method.parameterCount > 0) {
throw ModuleInitHookExecuteFailedException( throw FactoryExecutionException(
"Init方法不支持参数: ${target::class.java.name}#${methodSignature(method)}" "Init method must not declare parameters: ${target::class.java.name}#${methodSignature(method)}",
factoryName
) )
} }
method.isAccessible = true method.isAccessible = true
method.invoke(target) method.invoke(target)
} catch (e: ModuleInitHookExecuteFailedException) { } catch (e: FactoryExecutionException) {
throw e throw e
} catch (e: Exception) { } catch (e: Exception) {
throw ModuleInitHookExecuteFailedException( throw FactoryExecutionException(
"模块的init hook方法执行失败! 模块: ${target::class.java.simpleName} 方法签名: ${ "Failed to execute init hook: ${target::class.java.name}#${methodSignature(method)}",
methodSignature( factoryName,
method
)
}",
e e
) )
} }

View File

@@ -1,8 +1,8 @@
package work.slhaf.partner.framework.agent.factory.component 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.AgentBaseFactory
import work.slhaf.partner.framework.agent.factory.component.annotation.InjectModule 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.AgentRegisterContext
import work.slhaf.partner.framework.agent.factory.context.ModuleContextData import work.slhaf.partner.framework.agent.factory.context.ModuleContextData
import java.lang.reflect.Field import java.lang.reflect.Field
@@ -19,6 +19,8 @@ import java.lang.reflect.Modifier
* 当注入目标无匹配实例或存在多个匹配实例时抛出异常。 * 当注入目标无匹配实例或存在多个匹配实例时抛出异常。
*/ */
class ComponentInjectorFactory : AgentBaseFactory() { class ComponentInjectorFactory : AgentBaseFactory() {
private val factoryName = "component-injector-factory"
override fun execute(context: AgentRegisterContext) { override fun execute(context: AgentRegisterContext) {
val agentContext = context.agentContext val agentContext = context.agentContext
val moduleContextList = agentContext.modules.values.toList() val moduleContextList = agentContext.modules.values.toList()
@@ -62,8 +64,9 @@ class ComponentInjectorFactory : AgentBaseFactory() {
field.isAccessible = true field.isAccessible = true
field.set(target, value) field.set(target, value)
} catch (e: IllegalAccessException) { } catch (e: IllegalAccessException) {
throw ModuleInstanceGenerateFailedException( throw FactoryExecutionException(
"模块注入失败: ${target::class.java.name}#${field.name}", "Failed to inject module dependency: ${target::class.java.name}#${field.name}",
factoryName,
e e
) )
} }
@@ -73,13 +76,15 @@ class ComponentInjectorFactory : AgentBaseFactory() {
private fun resolveInjectValue(field: Field, providers: List<Any>, targetClass: Class<*>): Any { private fun resolveInjectValue(field: Field, providers: List<Any>, targetClass: Class<*>): Any {
val matched = providers.filter { field.type.isAssignableFrom(it::class.java) } val matched = providers.filter { field.type.isAssignableFrom(it::class.java) }
if (matched.isEmpty()) { if (matched.isEmpty()) {
throw ModuleInstanceGenerateFailedException( throw FactoryExecutionException(
"模块注入失败, 未找到可注入实例: ${targetClass.name}#${field.name} -> ${field.type.name}" "No injectable module instance found for: ${targetClass.name}#${field.name} -> ${field.type.name}",
factoryName
) )
} }
if (matched.size > 1) { if (matched.size > 1) {
throw ModuleInstanceGenerateFailedException( throw FactoryExecutionException(
"模块注入失败, 存在多个可注入实例: ${targetClass.name}#${field.name} -> ${field.type.name}" "Multiple injectable module instances found for: ${targetClass.name}#${field.name} -> ${field.type.name}",
factoryName
) )
} }
return matched.first() return matched.first()

View File

@@ -3,10 +3,10 @@ package work.slhaf.partner.framework.agent.factory.component
import com.alibaba.fastjson2.JSONArray import com.alibaba.fastjson2.JSONArray
import com.alibaba.fastjson2.JSONObject import com.alibaba.fastjson2.JSONObject
import org.slf4j.LoggerFactory 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.AgentBaseFactory
import work.slhaf.partner.framework.agent.factory.component.abstracts.AbstractAgentModule 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.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.AgentContext
import work.slhaf.partner.framework.agent.factory.context.AgentRegisterContext import work.slhaf.partner.framework.agent.factory.context.AgentRegisterContext
import work.slhaf.partner.framework.agent.factory.context.ModuleContextData import work.slhaf.partner.framework.agent.factory.context.ModuleContextData
@@ -25,6 +25,7 @@ import java.time.ZonedDateTime
class ComponentRegisterFactory : AgentBaseFactory() { class ComponentRegisterFactory : AgentBaseFactory() {
companion object { companion object {
private val log = LoggerFactory.getLogger(ComponentRegisterFactory::class.java) private val log = LoggerFactory.getLogger(ComponentRegisterFactory::class.java)
private const val FACTORY_NAME = "component-register-factory"
} }
override fun execute(context: AgentRegisterContext) { override fun execute(context: AgentRegisterContext) {
@@ -40,7 +41,11 @@ class ComponentRegisterFactory : AgentBaseFactory() {
constructor.isAccessible = true constructor.isAccessible = true
constructor.newInstance() constructor.newInstance()
} catch (e: Exception) { } catch (e: Exception) {
throw ModuleFactoryInitFailedException("AgentComponent 实例化失败: ${componentClass.name}", e) throw FactoryExecutionException(
"Failed to instantiate AgentComponent: ${componentClass.name}",
FACTORY_NAME,
e
)
} }
if (componentInstance is AbstractAgentModule) { if (componentInstance is AbstractAgentModule) {
@@ -62,8 +67,9 @@ class ComponentRegisterFactory : AgentBaseFactory() {
module: AbstractAgentModule module: AbstractAgentModule
) { ) {
if (agentContext.modules.containsKey(module.moduleName)) { if (agentContext.modules.containsKey(module.moduleName)) {
throw ModuleFactoryInitFailedException( throw FactoryExecutionException(
"模块注册失败, 存在重复 moduleName: ${module.moduleName} (class=${componentClass.name})" "Duplicate module name detected: ${module.moduleName} (class=${componentClass.name})",
FACTORY_NAME
) )
} }

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -3,7 +3,7 @@ package work.slhaf.partner.framework.agent.factory.context
import com.alibaba.fastjson2.JSONArray import com.alibaba.fastjson2.JSONArray
import com.alibaba.fastjson2.JSONObject import com.alibaba.fastjson2.JSONObject
import org.slf4j.LoggerFactory 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.capability.annotation.CapabilityCore
import work.slhaf.partner.framework.agent.factory.component.abstracts.AbstractAgentModule 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.AgentComponent
@@ -150,7 +150,7 @@ object AgentContext {
ShutdownHookDesc.Type.CAPABILITY -> instances.capability[clazz] ShutdownHookDesc.Type.CAPABILITY -> instances.capability[clazz]
} }
if (instance == null) { if (instance == null) {
throw AgentRunningFailedException("Instance of type $type not found") throw AgentRuntimeException("Instance of type $type not found")
} }
return instance return instance
} }

View File

@@ -1,9 +1,9 @@
package work.slhaf.partner.framework.agent.factory.context 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.AgentBaseFactory
import work.slhaf.partner.framework.agent.factory.capability.annotation.CapabilityCore 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.annotation.AgentComponent
import work.slhaf.partner.framework.agent.factory.component.exception.ModuleCheckException
import work.slhaf.partner.framework.agent.factory.util.ReflectUtil import work.slhaf.partner.framework.agent.factory.util.ReflectUtil
/** /**
@@ -16,6 +16,8 @@ import work.slhaf.partner.framework.agent.factory.util.ReflectUtil
* 收集通过后,统一调用 `AgentContext.addShutdownHook` 注册。 * 收集通过后,统一调用 `AgentContext.addShutdownHook` 注册。
*/ */
class ShutdownHookCollectorFactory : AgentBaseFactory() { class ShutdownHookCollectorFactory : AgentBaseFactory() {
private val factoryName = "shutdown-hook-collector-factory"
override fun execute(context: AgentRegisterContext) { override fun execute(context: AgentRegisterContext) {
val reflections = context.reflections val reflections = context.reflections
val agentContext = context.agentContext val agentContext = context.agentContext
@@ -29,23 +31,24 @@ class ShutdownHookCollectorFactory : AgentBaseFactory() {
ReflectUtil.isAssignableFromAnnotation(declaringClass, CapabilityCore::class.java) ReflectUtil.isAssignableFromAnnotation(declaringClass, CapabilityCore::class.java)
if (!isAgentComponentRelated && !isCapabilityCoreRelated) { if (!isAgentComponentRelated && !isCapabilityCoreRelated) {
throw ModuleCheckException( throw FactoryExecutionException(
"@Shutdown 仅能用于 AgentComponent/CapabilityCore 相关类: " + "@Shutdown can only be declared on AgentComponent/CapabilityCore classes: ${declaringClass.name}#${method.name}",
"${declaringClass.name}#${method.name}" factoryName
) )
} }
if (method.parameterCount > 0) { if (method.parameterCount > 0) {
throw ModuleCheckException( throw FactoryExecutionException(
"@Shutdown 标注的方法不能包含形参: " + "@Shutdown methods must not declare parameters: ${declaringClass.name}#${method.name}",
"${declaringClass.name}#${method.name}" factoryName
) )
} }
val order = method.getAnnotation(Shutdown::class.java).order val order = method.getAnnotation(Shutdown::class.java).order
val added = agentContext.addShutdownHook(method, order) val added = agentContext.addShutdownHook(method, order)
if (!added) { if (!added) {
throw ModuleCheckException( throw FactoryExecutionException(
"ShutdownHook 收集失败: ${declaringClass.name}#${method.name}" "Failed to collect shutdown hook: ${declaringClass.name}#${method.name}",
factoryName
) )
} }
} }

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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.ConfigDoc
import work.slhaf.partner.framework.agent.config.ConfigRegistration import work.slhaf.partner.framework.agent.config.ConfigRegistration
import work.slhaf.partner.framework.agent.config.Configurable import work.slhaf.partner.framework.agent.config.Configurable
import work.slhaf.partner.framework.agent.exception.*
import java.nio.file.Path import java.nio.file.Path
import java.util.concurrent.locks.ReentrantLock import java.util.concurrent.locks.ReentrantLock
import kotlin.concurrent.withLock import kotlin.concurrent.withLock
object AgentGatewayRegistry : Configurable, ConfigRegistration<AgentGatewayRegistryConfig>, AutoCloseable { object AgentGatewayRegistry : Configurable, ConfigRegistration<AgentGatewayRegistryConfig>, AutoCloseable {
private const val COMPONENT_NAME = "agent-gateway-registry"
private val log = LoggerFactory.getLogger(AgentGatewayRegistry::class.java) private val log = LoggerFactory.getLogger(AgentGatewayRegistry::class.java)
private val registryLock = ReentrantLock() private val registryLock = ReentrantLock()
@@ -26,8 +28,11 @@ object AgentGatewayRegistry : Configurable, ConfigRegistration<AgentGatewayRegis
fun register(registration: AgentGatewayRegistration) = registryLock.withLock { fun register(registration: AgentGatewayRegistration) = registryLock.withLock {
val previous = registrations.putIfAbsent(registration.channelName, registration) val previous = registrations.putIfAbsent(registration.channelName, registration)
check(previous == null || previous === registration) { checkAgentStartup(previous == null || previous === registration) {
"AgentGateway channel already registered: ${registration.channelName}" 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 { override fun init(config: AgentGatewayRegistryConfig, json: JSONObject?) = registryLock.withLock {
applyConfig(config) 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 { override fun onReload(config: AgentGatewayRegistryConfig, json: JSONObject?) = registryLock.withLock {
@@ -48,7 +59,10 @@ object AgentGatewayRegistry : Configurable, ConfigRegistration<AgentGatewayRegis
val defaultSnapshot = AgentRuntime.defaultResponseChannel() val defaultSnapshot = AgentRuntime.defaultResponseChannel()
try { try {
applyConfig(config) 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) log.error("Error while reloading gateway config", e)
restoreSnapshot(runtimeSnapshot, defaultSnapshot) restoreSnapshot(runtimeSnapshot, defaultSnapshot)
} }
@@ -69,20 +83,34 @@ object AgentGatewayRegistry : Configurable, ConfigRegistration<AgentGatewayRegis
} }
private fun validateConfig(config: AgentGatewayRegistryConfig) { private fun validateConfig(config: AgentGatewayRegistryConfig) {
require(config.defaultChannel.isNotBlank()) { "default_channel must not be blank" } if (config.defaultChannel.isBlank()) {
require(config.channels.isNotEmpty()) { "channels must not be empty" } 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>() val channelNames = mutableSetOf<String>()
config.channels.forEach { channel -> config.channels.forEach { channel ->
require(channel.channelName.isNotBlank()) { "channel_name must not be blank" } if (channel.channelName.isBlank()) {
require(channelNames.add(channel.channelName)) { "Duplicated channel_name: ${channel.channelName}" } throw GatewayRegistryException("channel_name must not be blank", COMPONENT_NAME)
require(registrations.containsKey(channel.channelName)) { }
"AgentGateway channel is not registered: ${channel.channelName}" 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)) { if (!channelNames.contains(config.defaultChannel)) {
"default_channel must exist in channels: ${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 -> configuredChannels.forEach { channelConfig ->
val registration = registrations[channelConfig.channelName] 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] val existing = runningChannels[channelConfig.channelName]
if (existing != null && existing.registration === registration && if (existing != null && existing.registration === registration &&
registration.supportsHotReloadReuse(existing.params, channelConfig.params) registration.supportsHotReloadReuse(existing.params, channelConfig.params)
@@ -129,7 +160,11 @@ object AgentGatewayRegistry : Configurable, ConfigRegistration<AgentGatewayRegis
shutdownError shutdownError
) )
} }
throw e throw GatewayException(
"Failed to launch gateway channel: ${channelConfig.channelName}",
channelConfig.channelName,
e
)
} }
} }

View File

@@ -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.ConfigDoc
import work.slhaf.partner.framework.agent.config.ConfigRegistration import work.slhaf.partner.framework.agent.config.ConfigRegistration
import work.slhaf.partner.framework.agent.config.Configurable 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.ProviderConfig.ProviderType.OPENAI_COMPATIBLE
import work.slhaf.partner.framework.agent.model.provider.ModelProvider import work.slhaf.partner.framework.agent.model.provider.ModelProvider
import work.slhaf.partner.framework.agent.model.provider.ProviderOverride import work.slhaf.partner.framework.agent.model.provider.ProviderOverride
@@ -18,6 +20,7 @@ import kotlin.concurrent.withLock
object ModelRuntimeRegistry : Configurable, ConfigRegistration<ModelRuntimeRegistryConfig> { object ModelRuntimeRegistry : Configurable, ConfigRegistration<ModelRuntimeRegistryConfig> {
private const val DEFAULT_PROVIDER = "default" private const val DEFAULT_PROVIDER = "default"
private const val COMPONENT_NAME = "model-runtime-registry"
/** /**
* 基础的 provider 提供商,可 fork 出新的 runtime provider必须提供一个 default provider * 基础的 provider 提供商,可 fork 出新的 runtime provider必须提供一个 default provider
@@ -49,13 +52,28 @@ object ModelRuntimeRegistry : Configurable, ConfigRegistration<ModelRuntimeRegis
private fun forkProvider(config: RuntimeProviderConfig) { private fun forkProvider(config: RuntimeProviderConfig) {
val provider = baseProvider[config.providerName] 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 val override = config.override
runtimeProvider[config.modelKey] = if (override != null) { try {
provider.fork(override) runtimeProvider[config.modelKey] = if (override != null) {
} else { provider.fork(override)
provider } else {
provider
}
} catch (e: Exception) {
throw runtimeModelException(
"Failed to build runtime provider for model key ${config.modelKey}",
config.providerName,
config.modelKey,
override,
e
)
} }
} }
@@ -66,8 +84,17 @@ object ModelRuntimeRegistry : Configurable, ConfigRegistration<ModelRuntimeRegis
override fun type(): Class<ModelRuntimeRegistryConfig> = ModelRuntimeRegistryConfig::class.java override fun type(): Class<ModelRuntimeRegistryConfig> = ModelRuntimeRegistryConfig::class.java
override fun init(config: ModelRuntimeRegistryConfig, json: JSONObject?) = providerLock.withLock { override fun init(config: ModelRuntimeRegistryConfig, json: JSONObject?) = providerLock.withLock {
config.providerConfigSet.forEach { registerProvider(it) } try {
config.runtimeConfigSet.forEach { forkProvider(it) } 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 { override fun onReload(config: ModelRuntimeRegistryConfig, json: JSONObject?) = providerLock.withLock {
@@ -76,19 +103,33 @@ object ModelRuntimeRegistry : Configurable, ConfigRegistration<ModelRuntimeRegis
val runtimeProviderSnapshot = runtimeProvider.toMap() val runtimeProviderSnapshot = runtimeProvider.toMap()
try { try {
val providerSetJson = root.getJSONArray("providerConfigSet") 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() baseProvider.clear()
for (i in providerSetJson.indices) { for (i in providerSetJson.indices) {
val providerJson = providerSetJson.getJSONObject(i) 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") val typeText = providerJson.getString("type")
?: throw IllegalStateException("providerConfigSet[$i].type is missing") ?: throw runtimeModelException(
val providerType = ProviderConfig.ProviderType.valueOf(typeText.uppercase(getDefault())) "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) { val concreteProviderConfig = when (providerType) {
OPENAI_COMPATIBLE -> providerJson.toJavaObject(OpenAiCompatibleProviderConfig::class.java) OPENAI_COMPATIBLE -> providerJson.toJavaObject(OpenAiCompatibleProviderConfig::class.java)
} }
registerProvider(concreteProviderConfig) registerProvider(concreteProviderConfig)
} }
if (!baseProvider.containsKey(DEFAULT_PROVIDER)) {
throw runtimeModelException("Provider default not found", DEFAULT_PROVIDER)
}
runtimeProvider.clear() runtimeProvider.clear()
config.runtimeConfigSet.forEach { forkProvider(it) } config.runtimeConfigSet.forEach { forkProvider(it) }
} catch (e: Exception) { } catch (e: Exception) {
@@ -114,6 +155,42 @@ object ModelRuntimeRegistry : Configurable, ConfigRegistration<ModelRuntimeRegis
), setOf() ), 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( data class ModelRuntimeRegistryConfig(