584 Commits

Author SHA1 Message Date
e9eaaa24db fix(BuiltinCommand): spill session streams to log files 2026-04-20 14:37:40 +08:00
2ec2d8e096 fix(CommandExecutionService): preserve stdout and stderr outputs 2026-04-20 14:32:25 +08:00
eea72c747c fix(DirectoryWatchSupport): isolate handler failures 2026-04-19 17:31:36 +08:00
137b1ee917 fix(CommandExecutionService): avoid persistent reader executor 2026-04-19 17:30:16 +08:00
c5aa558319 fix(McpActionExecutor): handle client call failures gracefully 2026-04-19 17:27:27 +08:00
8c8b0883bb fix(BuiltinCommand): expire finished command sessions by ttl 2026-04-19 17:26:20 +08:00
dd8e20838d fix(BuiltinCommand): apply execution policy to command tools 2026-04-19 17:23:04 +08:00
15d7eb6850 fix(DynamicActionMcp): apply execution policy to tool handler 2026-04-19 17:21:37 +08:00
657023694c fix(OriginExecution): apply execution policy to process launch 2026-04-19 17:19:39 +08:00
9b97fffc5c fix(LocalRunnerClient): unregister policy listener on close 2026-04-19 17:13:40 +08:00
14df95fc59 fix(McpConfigWatcher): clean stale actions on client removal 2026-04-19 17:13:04 +08:00
864bda95e4 refactor(action): register no blocks while no actions recovered 2026-04-19 00:51:22 +08:00
bfa3562335 refactor(exception): optimize exception report behavior 2026-04-19 00:47:31 +08:00
9b24b662da chore: add slf4j log annotation on AgentModule implementations 2026-04-19 00:36:15 +08:00
41c611cb70 refactor(framework): support inject Standalone into Standalone modules 2026-04-19 00:34:45 +08:00
6ca77bdb74 feat(perceive): add SystemStatsMonitor 2026-04-18 23:51:23 +08:00
e5ce6d6722 refactor(memory): rename MemoryUpdater into MemoryRecallProfileExtractor, and create prompt 2026-04-18 23:50:48 +08:00
a7ef9bff49 refactor(memory): enhance topic-based memory runtime on recalling and indexing 2026-04-18 22:28:40 +08:00
92c8e01000 feat(memory): create prompts for submodules of memory selector 2026-04-18 19:19:05 +08:00
e0543a8966 refactor(communication): create prompts for summarizer, and optimize message structure 2026-04-17 23:16:20 +08:00
0c079c127e chore: remove useless annotations on module 2026-04-17 18:09:40 +08:00
96301dc64a refactor(action): use synchronized lock to prevent concurrent problems in executable actions executing 2026-04-17 18:05:04 +08:00
3fd90c0f5b refactor(context): sort context blocks by descending 2026-04-17 16:01:50 +08:00
8928ec9e07 feat(action): create prompts for submodules of ActionExecutor 2026-04-17 15:01:45 +08:00
503afecbe2 refactor(action): redefine ExtractorResult structure to support openai sdk better, and make failed meta-action executing should be recorded as history normally 2026-04-16 23:27:46 +08:00
281984bb05 feat(action): redefine structure of evaluator result to support json schema of openai sdk, and create system prompt for sub-modules of ActionPlanner 2026-04-16 21:38:11 +08:00
062af4b7d2 feat(communication): update prompt 2026-04-16 21:05:39 +08:00
380c674d06 feat(communication): enrich and correct system-prompt in CommunicationProducer, and support NO_REPLY answering 2026-04-16 17:44:36 +08:00
347560d979 refactor(context): rename VisibleDomain into FocusedDomain, and optimize related context usage 2026-04-15 22:16:33 +08:00
999a6a8d7e refactor(dialog): remove legacy data class 2026-04-15 17:24:22 +08:00
f510dc5a42 refactor(context): support wait a debounce delay before executing turn 2026-04-15 16:36:23 +08:00
d8ff0b5ea4 refactor(context): simplify constructor and inputs encoding of running flow context 2026-04-15 15:45:42 +08:00
dc147000ba refactor(runtime): support collect context by source and interrupt same-source running flow by module order 2026-04-15 14:32:52 +08:00
247057e100 fix(test): fix MemoryRuntimeTest 2026-04-14 15:07:32 +08:00
33ffd782c4 refactor(cognition): remove duplicate recent chat block building logic, refresh which in cognition core uniformly 2026-04-14 12:40:56 +08:00
a847f3bff8 refactor(rolling): separate dialog rolling with memory topic binding,
now support register after-rolling consumer independently
2026-04-14 11:14:37 +08:00
28d0a43ef3 refactor(log): support advice invoke or invoke with no result via different methods to avoid unnecessary nullable check 2026-04-14 10:08:31 +08:00
cb4380eb1e feat(trace): support trace context workspace changes 2026-04-13 22:48:31 +08:00
737f9d122a feat(trace): support trace input/output information on Running/Sub AgentModule 2026-04-13 22:27:11 +08:00
e65d3302c6 feat(trace): support create advice for method with no return value 2026-04-13 21:57:10 +08:00
fece67135f feat(trace): support create loggable advice and implement common trace recorder 2026-04-13 21:39:42 +08:00
d30e58ff83 refactor(framework): centralize model exception reporting in ActivateModel and remove duplicated module-level handlers 2026-04-12 22:15:08 +08:00
93304878ad refactor(memory): migrate slice/topic/date lookup to Result flow and unify MemoryLookupException reporting 2026-04-12 20:13:11 +08:00
e37a282141 fix(test): adapt ActionExecutor tests to Result-based extractor/corrector execution flow 2026-04-12 19:19:07 +08:00
04d6ad6d80 refactor(core): normalize memory unit after adding new slice before return 2026-04-12 19:08:35 +08:00
9755672750 refactor(action-core): wrap runner submit flow with Result.runCatching and centralize action error handling 2026-04-12 18:51:33 +08:00
e0f955694d refactor(framework): wrap module execution in Result and report failures via exception handler 2026-04-12 17:33:11 +08:00
c14e6f84e7 refactor(action-core): migrate action modules to Result return flow and unify exception reporting 2026-04-12 17:29:10 +08:00
19f56d11f0 refactor(framework): add Result chain APIs and align runtime exception handling 2026-04-12 16:58:36 +08:00
94d91d9746 feat(agent): support add custom configurable object in Agent launch flow 2026-04-11 21:07:50 +08:00
fac6e24e49 feat(exception): support report necessary exception info into context 2026-04-11 18:52:53 +08:00
2aae1b1f14 refactor(action-core): return Result for meta action lookups and adapt runtime callers 2026-04-11 18:30:24 +08:00
1b48e955bd refactor(core): migrate deprecated exceptions to new hierarchy and align tests 2026-04-11 16:10:34 +08:00
b8cb2afbcf refactor(framework): unify model invocation result and exception handling 2026-04-11 14:50:12 +08:00
3732555f02 refactor(framework): migrate startup chain exceptions to AgentException hierarchy 2026-04-10 22:39:59 +08:00
ec52d64e73 refactor(exception): register exception reporters on Agent launcher 2026-04-10 19:04:11 +08:00
7b963df991 refactor(exception): establish new exception system, and move the legacy into deprecated package 2026-04-10 18:41:13 +08:00
4876d621b2 将 .java 重命名为 .kt 2026-04-10 18:37:49 +08:00
663d66fdea chore: remove legacy exception handler and adjust runtime class location 2026-04-10 14:31:56 +08:00
d29dad4691 refactor(config): adjust declared config location 2026-04-09 17:28:23 +08:00
291371f8da chore: adjust reflect related util's location 2026-04-09 16:58:24 +08:00
3e5d6ebeb4 feat(runtime): support mask assigned modules; and remove legacy module record in agent context 2026-04-09 16:13:04 +08:00
56daaf0b60 refactor(agent): normalize Agent launch flow 2026-04-09 12:26:52 +08:00
d6593c10f9 refactor(agent): support register registry shutdown hooks while agent launching 2026-04-09 12:19:20 +08:00
328befecca refactor(action): add shutdown method to ActionCore to close runner client and thread pool 2026-04-09 12:00:32 +08:00
1e46149d0a refactor(agent): remove legacy ConfigLoader and related factory; refactor agent launch flow 2026-04-09 10:35:13 +08:00
427d224f65 refactor(gateway): manage gateway implementions via related registry and interface 2026-04-08 22:24:07 +08:00
0528890d60 refactor(communication): remove channel assignment in ReplyDispatcher 2026-04-08 20:49:37 +08:00
f233c5ce32 fixup! refactor(runner): manage execution policy via ConfigCenter 2026-04-08 20:48:42 +08:00
91a595d073 chore: remove legacy utils and constant class 2026-04-08 17:36:03 +08:00
6d27e55a1e refactor(runner): manage execution policy via ConfigCenter 2026-04-08 17:21:35 +08:00
2935daeffa refactor(action): support recover schedulable executable actions together, and ActionExecutor will emit a context block to explain recovering result 2026-04-08 16:52:21 +08:00
e04b2c4fe8 refactor(memory): manage state serialization via StateCenter in MemoryRuntime 2026-04-08 14:55:37 +08:00
21a9d2114f chore(core): remove legact PartnerCore 2026-04-07 23:27:31 +08:00
3640cc2108 feat(action): support continuing executable actions after state restored 2026-04-07 23:16:12 +08:00
a114044c23 refactor(action): manage state serialization via StateCenter in ActionCore 2026-04-07 22:01:46 +08:00
874488ea79 test(memory): test with new memory behavior 2026-04-07 17:23:14 +08:00
b80ff8400c refactor(memory): compute memory slice in MemoryCore 2026-04-07 17:13:51 +08:00
6fd12cd19f fix(memory): restore normalizing logic in memory core, and fix errors in MemoryCoreTest 2026-04-07 15:02:55 +08:00
2cbaccedba refactor(cognition): manage state serialization via StateCenter in CognitionCore 2026-04-07 14:44:47 +08:00
006e7c61e5 refactor(context): remove legacy attribute coreResponse in PartnerRunningFlowContext 2026-04-07 14:42:15 +08:00
2458ea4849 refactor(memory): manage state serialization via StateCenter in MemoryUnit, and support optional loading on register in StateCenter 2026-04-07 12:27:36 +08:00
eab8eec46e chore(memory): add refactor todo in MemoryUpdater 2026-04-07 10:23:55 +08:00
a242723727 refactor(memory): manage state serialization via StateCenter in MemoryCore, and normalize slice and unit building 2026-04-07 10:21:17 +08:00
57bc63c57b refactor(perceive): manage state serialization via StateCenter in PerceiveCore 2026-04-07 10:05:35 +08:00
9aa793df8e feat(state): add StateCenter and related interface 2026-04-06 22:16:50 +08:00
8c04566243 chore(framework): reorganize Partner-Framework 2026-04-06 20:16:51 +08:00
b1ba86be57 chore(build): adjust pom.xml in Partner-Framework and fix test errors 2026-04-06 16:12:13 +08:00
f79a0521b2 refactor(vector): refactor VectorClient configuration loading method 2026-04-06 15:52:30 +08:00
332792daa2 refactor(action): make LocalRunnerClient as default runner client 2026-04-05 23:23:02 +08:00
3b236286b9 refactor(action): remove problematic action tendency cache 2026-04-05 22:32:52 +08:00
50db3fa7b2 refactor(config): adjust method init and onReload to support polymorphic config loading 2026-04-04 23:34:00 +08:00
6503ec32b4 chore(git): update gitignore 2026-04-04 17:54:25 +08:00
9771aa1de5 refactor(model): manage model registry by ConfigCenter 2026-04-04 17:53:54 +08:00
660bb01440 chore(config): add config doc to WebSocketConfig 2026-04-04 14:49:06 +08:00
188b5e8b53 refactor(config): support printing more information after init failed by ConfigDoc 2026-04-04 00:33:25 +08:00
db4dc6d040 refactor(gateway): init and load config from config center for WebSocketGateway 2026-04-03 23:07:40 +08:00
ef9d177adc fix(config): correct duplicate config checking 2026-04-03 15:35:27 +08:00
5a41e02602 fixup! refactor(config): rename watching method and remove useless covariant 2026-04-02 22:59:09 +08:00
f387c36b17 refactor(config): prevent registering Configurable after watching started 2026-04-02 22:55:53 +08:00
03532d3d97 refactor(config): run init after watching started 2026-04-02 22:19:37 +08:00
f37bef57ba refactor(config): rename watching method and remove useless covariant 2026-04-02 22:12:08 +08:00
29d6546b07 feat(config): support ConfigCenter file watching and registered json reloads 2026-04-01 23:43:19 +08:00
b9fd9bcaac refactor(mcp): switch desc.json loading to fastjson2 to avoid desc.json loading error 2026-04-01 22:57:17 +08:00
4ae65b885e refactor(watch): support configurable directory watch depth 2026-04-01 22:15:00 +08:00
632e47ec13 feat(config): add config center and runtime path resolution 2026-04-01 20:42:45 +08:00
4f200cadfc refactor(model): move model APIs from chat to agent.model 2026-03-31 21:13:57 +08:00
e4df68ea5d refactor(chat): extract model activation into provider registry
- move ActivateModel and StreamChatMessageConsumer into api.chat
- replace direct OpenAI runtime construction with ModelRuntimeRegistry
- add provider config, runtime override and OpenAI-compatible provider forking
- rename OpenAiChatRuntime to OpenAiCompatibleProvider and update imports
2026-03-31 18:37:41 +08:00
81aa4b7933 feat(chat): support streaming reply in agent turn 2026-03-31 14:44:58 +08:00
b4c44c7d98 fix(perceive): fix legacy errors 2026-03-31 12:14:52 +08:00
1301a0f8b1 refactor(event): enrich necessary attributes in InteractionEvent.Reply 2026-03-31 10:28:27 +08:00
7d82ec7238 refactor(gateway): register WebsocketGateway as response channel while launch 2026-03-31 10:15:31 +08:00
d70054cd9b refactor(interaction): decouple gateway IO from runtime response flow
- replace interaction adapter/input-output DTO flow with InputData and InteractionEvent
  - introduce ResponseChannel and default LogChannel for runtime response dispatch
  - let AgentGateway parse running context directly and submit turns asynchronously
  - update WebSocketGateway to emit serialized interaction events
  - simplify cognition turn initiation to fire-and-forget semantics
  - streamline running flow context source construction and runtime module execution
2026-03-30 22:46:02 +08:00
def48fd0ce refactor(context): remove legacy module context 2026-03-30 18:01:55 +08:00
0b750f8028 refactor(action): support initiate turn after evaluation 2026-03-29 22:58:55 +08:00
6e37ed032b refactor(context): support skip modules by adding specific moduleName into runningFlowContext 2026-03-29 22:26:10 +08:00
b6c86c6640 refactor(action): adjust pending action block content and make full-expanded block as SUPPLY block 2026-03-29 22:07:29 +08:00
71956b4dce refactor(action): adjust tendency evaluation to be performed asynchronously, and pass the tendency in evaluation to communication as a block of SUPPLY type. 2026-03-29 21:55:53 +08:00
c9466f4359 refactor(executor): remove legacy InteractionThreadPoolExecutor , and change related executor calling into virtual executor and CountDownLatch 2026-03-29 20:19:09 +08:00
cb09b86b23 refactor(memory): remove legacy dialogMap in MemoryRuntime and related modules 2026-03-29 18:54:23 +08:00
d4a5c5a0ed fix(memory): trim persisted overlap from chat snapshot in MemoryUpdater 2026-03-29 18:49:44 +08:00
274d007ba1 refactor(memory): add DialogRollingService to control message rolling logic 2026-03-29 18:24:38 +08:00
c7df35beb4 refactor(memory): correct memorySlice-topicPath binding behavior and adjust slice index into [startIndex,endIndex) 2026-03-29 18:11:02 +08:00
1c995923a1 refactor(context): support copy attributes on root tag into snapshot element 2026-03-29 17:28:41 +08:00
247052e318 refactor(memory): update end index of memory slice 2026-03-29 16:15:30 +08:00
eb1723de97 refactor(memory): remove legacy activated memory slice records in memory core 2026-03-29 16:08:29 +08:00
c2fbfe751f refactor(memory): add memory recalling builtin capability meta-action 2026-03-29 16:04:06 +08:00
4a1828ed94 refactor(memory): finished the context block content produced in MemorySelector 2026-03-29 00:17:14 +08:00
db20e0ca78 refactor(memory): refactor memory selector into asynchronous module 2026-03-28 22:41:48 +08:00
09f90d8ad5 refactor(memory): refactor memory extract/evaluating logic and messages building in memory modules 2026-03-28 21:52:02 +08:00
baa6870ccf chore(action): remove unused attribute 2026-03-28 21:50:17 +08:00
fd43466dd5 refactor(runner): remove useless builtin capability meta actions 2026-03-27 15:22:34 +08:00
7628d40645 refactor(communication): rename module directory 2026-03-27 15:19:36 +08:00
d806693e08 refactor(action): simplify ActionCorrectionRecognizer input and build messages with context/task block 2026-03-27 15:01:45 +08:00
dbfd0b1fc3 refactor(action): simplify corrector input and build messages with context/task block 2026-03-27 14:53:00 +08:00
f5b9f8fc58 refactor(action): simplify extractor input and switch params extraction to context/task block messages 2026-03-26 21:43:48 +08:00
7bbb7745f4 refactor(action): remove legacy additionalContext from Action state and snapshots 2026-03-26 21:22:59 +08:00
b65f5f37fb refactor(context): rename encodeToContextMessage to encodeToMessage and update usages 2026-03-26 20:43:58 +08:00
fb9b3860af refactor(common): extract shared XML Block base and reuse it in BlockContent and TaskBlock 2026-03-26 20:43:26 +08:00
c5256cbc90 refactor(module): flatten package paths from module.modules.* to module.* and remove unused ModelConstant 2026-03-26 19:59:03 +08:00
1592c876c7 refactor(action): emit full execution lifecycle/correction blocks and carry correction reason in CorrectorResult 2026-03-26 17:32:40 +08:00
453a1cfe84 refactor(build): move kotlin sourceDirs into compile/test-compile executions 2026-03-26 16:52:29 +08:00
54320dbfde refactor(context): make block activation/rendering exposure-aware and use rendered projections in aggregation 2026-03-26 16:49:56 +08:00
201addbc64 refactor(build): centralize surefire config in parent POM and default to running tests 2026-03-26 16:44:21 +08:00
5219142b5c refactor(action): add ExecutingActionBlockManager to emit execution lifecycle ContextBlocks from action snapshots 2026-03-26 15:38:01 +08:00
750bef0fd8 refactor(action): add snapshot models and snapshot builders for Action/StateAction 2026-03-26 15:18:46 +08:00
a9b925c614 refactor(context): aggregate resolved blocks by source snapshots and centralize elapsed-time activation refresh 2026-03-25 20:13:55 +08:00
264a45c85f refactor(context): adjust fading factor of pending-action block 2026-03-24 22:55:58 +08:00
155d06df45 refactor(context): add urgency attribute/label to BlockContent 2026-03-24 22:52:02 +08:00
7879836b91 refactor(action): remove the explicit PendingAction control flow and assume the confirmation semantics through a short-term, fast-decaying ContextBlock belonging to the ACTION domain. 2026-03-24 22:28:42 +08:00
82db27484c refactor(communication): adjust domains that involved in communication 2026-03-24 14:28:51 +08:00
d11a431614 refactor(action): remove the redundant fields in the prompt construction logic and data classes left in ActionEvaluator 2026-03-24 14:24:31 +08:00
50b07488a6 refactor(action): adjust ActionPlanner and related submodules to adapt to current Agent Context acquisition 2026-03-24 11:49:29 +08:00
313cea0d3b refactor(communication): register recent chat messages as context into ContextWorkspace 2026-03-24 11:28:40 +08:00
4494d58ff9 refactor(context): add ResolvedContext as response of ContextWorkspace#resolve, integrated with Message encoding 2026-03-24 11:04:03 +08:00
d7179364a1 refactor(context): forces the context of the first domain hit to be fully expanded to adapt to the context focus needs within the module 2026-03-24 10:29:15 +08:00
b05ef8683d refactor(executor): remove legacy PhaserRecord and related methods in ActionCapability 2026-03-23 23:27:37 +08:00
556b8a5348 refactor(executor): remove legacy ActionRepairer、DynamicActionGenerator and related data class 2026-03-23 23:19:16 +08:00
027ebf860e refactor(executor): Reconstruct the execution process of ExecutableAction in ActionExecutor, remove ActionRepairer, and adjust the execution timing of ActionCorrector 2026-03-23 23:16:57 +08:00
8cd12f7379 refactor(action): add resume/interrupt methods to ExecutableAction; add related definitions to support acquiring help from user 2026-03-23 17:24:19 +08:00
617daea17c refactor(context): remove legacy ContextBlock 2026-03-22 22:18:32 +08:00
61d5270625 refactor(perceive): refactor into registering context via ContextWorkspace 2026-03-22 22:17:21 +08:00
93b0199c9e refactor(communication): route messages through cognition workspace 2026-03-22 22:01:04 +08:00
977d92881c feat(cognition): add ContextWorkspace to manage context blocks 2026-03-22 21:39:25 +08:00
6aa96c33ac refactor(cognition): remove legacy user exception 2026-03-22 13:50:18 +08:00
e85094670b refactor(cognition): rename Cognation core/capability and package references to Cognition 2026-03-22 12:31:57 +08:00
21ea6a25c8 refactor(chat): remove legacy MetaMessage POJO 2026-03-22 11:02:37 +08:00
ad65cd4c09 feat(runner): add and register DynamicAction related builtin MetaAction provider 2026-03-21 23:53:13 +08:00
ff46d97eed feat(scheduler): add cancel method to ActionScheduler 2026-03-21 22:39:18 +08:00
1a83075031 refactor(runner): inline command action JSON responses and remove command response DTOs 2026-03-21 18:14:47 +08:00
809d38bd07 refactor(action): remove outdated TODO comments in ActionScheduler 2026-03-20 23:16:57 +08:00
f7d46c8ef1 refactor(action): remove legacy interventor module and move intervention entities into core action package 2026-03-20 23:09:58 +08:00
e1ee6589ef feat(runner): add and register builtin intervention action provider with intervention meta actions 2026-03-20 23:04:32 +08:00
17108f3239 fix(runner): correct actions list provided in BuiltinCapabilityActionProvider 2026-03-20 15:02:13 +08:00
59a5e22f35 refactor(runner): extract createActionKey as an abstract method in BuiltinActionProvider 2026-03-20 15:01:22 +08:00
30373cbc02 feat(runner): register builtin capability action definitions in BuiltinActionRegistry 2026-03-19 23:20:06 +08:00
0e164115c0 feat(runner): add builtin capability action provider for memory slices, initiate turn, and interaction status 2026-03-19 23:18:32 +08:00
3cc6e8df99 refactor(perceive): return Instant in showLastInteract 2026-03-19 23:16:02 +08:00
ccb7041093 refactor(perceive): remove legacy user storage in perceive core 2026-03-19 23:14:20 +08:00
e0b20ce414 refactor(runner): adjust command action response shcema in BuiltinCommandActionProvider 2026-03-19 11:31:34 +08:00
1029624dc7 refactor(cogiaiateTurnnation): support assigning reply target in method
initiateTurn
2026-03-19 10:54:36 +08:00
5b9b9c3c09 refactor(runner): add builtin action provider interface 2026-03-19 10:39:06 +08:00
67d7fd34f8 feat(runner): register builtin command action definitions in BuiltinActionRegistry 2026-03-18 23:06:06 +08:00
12368ded53 feat(runner): implement builtin command session actions with start/inspect/read/cancel/overview 2026-03-18 23:00:56 +08:00
7d9ec976e3 feat(runner): implement builtin command execute MetaAction definition 2026-03-18 17:15:47 +08:00
d8b19ebcea refactor(runner): refactor CommandExecutionService into single instance 2026-03-18 16:52:52 +08:00
7f4b82204a refactor(runner): change stdout/stderr reading thread into virtual thread in CommandExecutionService 2026-03-18 16:18:10 +08:00
664bd5a0fb refactor(runner): add typed param helper methods in BuiltinActionRegistry 2026-03-17 22:54:55 +08:00
6474eb8dc6 refactor(runner): allow object-typed params in BuiltinActionRegistry builtin actions 2026-03-17 22:51:00 +08:00
4439e5c04b feat(runner): add BuiltinCommandActionManager and command action data models scaffold 2026-03-17 22:24:23 +08:00
ef2eb909b7 refactor(runner): use string-only params and return type for BuiltinActionRegistry builtin actions 2026-03-17 22:12:22 +08:00
fd20af3e1c test(exec): add test for CommandExecutionService 2026-03-17 14:59:48 +08:00
d30ff322a2 refactor(runner): remove unused static method definition in BuiltinActionRegistry 2026-03-17 14:32:29 +08:00
cb63bbf570 feat(runner): add builtinAction defining method to BuiltinActionRegistry 2026-03-17 14:08:50 +08:00
4da4e5f161 refactor(runner): rename method buildDefinitions in BuiltinActionRegistry 2026-03-17 13:56:25 +08:00
5a717dbdda refactor(runner): load different policy provider according to os, now support bwrap sandbox in linux only 2026-03-17 12:21:31 +08:00
a6682a7719 feat(runner): implement BubbleWrap policy provider and related test 2026-03-17 12:11:54 +08:00
1465d7687b refactor(runner): add policy listener registering function and support registering McpConfigWatcher after starting 2026-03-17 10:35:35 +08:00
d31cac70a6 refactor(runner): apply execution policy wrapping in MCP transport and reload on policy changes 2026-03-16 22:45:49 +08:00
108cf9b071 refactor(runner): rename method buildFileExecutionCommands in CommandExecutionService 2026-03-16 16:52:04 +08:00
c4b8c2a858 refactor(runner): rename exec vararg parameter to commands for clarity 2026-03-15 22:41:46 +08:00
d55b849747 refactor(runner): apply execution policy wrapping before command execution in OriginExecutionService 2026-03-15 22:41:19 +08:00
a9993299a5 refactor(runner): add exec(List<String>) overload in CommandExecutionService 2026-03-15 22:41:11 +08:00
4c47cac3a5 fix(runner): repair MetaAction related logic in McpMetaRegistry and tests 2026-03-14 21:44:27 +08:00
cba9ff4f0b refactor(action): pass launcher through meta action flow instead of inferring command by file extension 2026-03-14 21:27:38 +08:00
603b0835c5 将 .java 重命名为 .kt 2026-03-14 21:27:38 +08:00
fc0d4ef03b refactor(runner): remove legacy abstract for command execution 2026-03-13 15:22:14 +08:00
97bb897407 feat(runner): add execution policy abstract for local running 2026-03-13 14:45:50 +08:00
8463eb9dae refactor(runner): remove unused method listSystemDependencies 2026-03-12 16:07:06 +08:00
9794b39572 refactor(runner): adjust the directory organization of runner 2026-03-12 15:32:28 +08:00
0506149f5f refactor(runner): separate logic of different domain in LocalRunnerClient into different class 2026-03-12 15:04:13 +08:00
9325b84d14 refactor(ActionExecutor): remove unused ActionScheduler in executor 2026-03-12 11:59:26 +08:00
6c8a1b2636 refactor(action): support built-in actions 2026-03-12 10:41:17 +08:00
3c550af33d refactor(perceive): omit user lookup when building evaluator input 2026-03-11 14:41:43 +08:00
229c7a0edb refactor(memory): remove redundant activated slice helpers 2026-03-11 13:37:18 +08:00
a067e058fb refactor(memory): remove module context and recall tracking 2026-03-10 23:09:32 +08:00
cdfae8ab1a refactor(memory): remove postprocess executor and simplify memory updater trigger 2026-03-10 23:07:58 +08:00
c1998f61b6 refactor(perceive): drop legacy perceive updater modules and remove PreProcessExecutor 2026-03-10 22:59:29 +08:00
3f6283d12a refactor(perceive): expose last interaction tracking and refresh memory sessions 2026-03-10 22:57:59 +08:00
3d1c258944 refactor(memory): drop message cleanup before summarizing 2026-03-10 21:15:35 +08:00
36dfd65046 refactor(CommunicationProducer): drop timestamp from user message 2026-03-10 21:13:12 +08:00
ee1a033c1b refactor(memory): centralize memory recording and retrieval logic 2026-03-10 20:42:46 +08:00
027e8bddc0 refactor(memory): move memory id refresh into runtime init 2026-03-10 20:17:34 +08:00
0903b8482b test(CommunicationProducer): remove CommunicationProducerTest 2026-03-10 19:54:37 +08:00
f51401e2f2 refactor(CommunicationProducer): snapshot chat history when assembling conversation 2026-03-10 19:53:20 +08:00
5ad80d8b86 refactor(memory): decouple memory storage and runtime structures 2026-03-10 19:41:05 +08:00
760ba8300b refactor(module): remove legacy prompt scaffolding 2026-03-10 17:15:50 +08:00
0f3d4659ae chore(project): remove legacy module Partner-Test-Demo 2026-03-10 15:04:16 +08:00
331d415925 refactor(CommunicationProducer): update datetime pattern and source in communicating 2026-03-10 15:01:07 +08:00
f5f64971f3 refactor(ContextBlock): return dom nodes directly 2026-03-10 14:48:14 +08:00
1cd6ba11bb refactor(CommunicationProducer): split context and supply message assembly 2026-03-10 14:31:13 +08:00
5db533f823 refactor(chat): use Message.Character enum for roles and remove unused prompt helpers 2026-03-09 22:12:35 +08:00
1b2ccaee9c refactor(chat): replace custom client with OpenAI runtime and remove file-based module prompt loading logic, prompt will be provided by each module 2026-03-09 21:51:07 +08:00
8dc7ed080b chore(build): import OpenAI dependency 2026-03-09 16:20:10 +08:00
3348557352 refactor(Action): backfill ExecutableAction result on success/failure and add immediate-action completion watcher self-talk 2026-03-08 15:42:25 +08:00
4bb83f86a8 refactor(ActionPlanner): switch pending confirmation flow to PendingActionRecord with decision parsing and reminder/expire lifecycle scheduling 2026-03-08 14:40:53 +08:00
b256af0f58 refactor(Action): remove @JvmOverloads from SchedulableExecutableAction constructor 2026-03-08 13:32:08 +08:00
ec429db4da refactor(Core): normalize preprocess user resolution from source/additional info, add Kotlin-safe AgentConfigLoader getters, and update async summary writes by index 2026-03-08 13:31:53 +08:00
145aeed600 refactor(Module): remove unused meta component POJOs from agent factory 2026-03-08 13:31:02 +08:00
5e8ef6d66f refactor(build): add kotlin-maven-plugin setup to Partner-Core and Partner-Framework poms 2026-03-08 13:30:39 +08:00
65690c65f8 refactor(MemoryUpdater): move auto-update to ActionScheduler cron and use Cognation snapshot/drain APIs for thread-safe memory refresh 2026-03-08 13:11:20 +08:00
7df0f208b5 refactor(Module): rename PostRunningAbstractAgentModuleAbstract to PostRunningAgentModule and update updater inheritance 2026-03-08 12:04:29 +08:00
4484d4a06b refactor(Context): remove finished state from flow/module context and drop MemoryUpdater finish guard 2026-03-08 11:47:44 +08:00
25ddc6f181 refactor(ActionExecutor): enforce action timeout with cancellation and move timeout defaults into Action base model 2026-03-07 20:15:41 +08:00
d905c4ace1 refactor(Action): add @JvmOverloads constructors to SchedulableExecutableAction and StateAction 2026-03-07 18:52:36 +08:00
c3c4c88c9a refactor(ActionScheduler): add timeout attribute to Schedulable, and support reschedule Schedulable content when it's fished in ActionScheduler 2026-03-07 17:05:07 +08:00
ae1b7fc033 refactor(ActionScheduler): support receiving single data that implements Schedulable and Action in ActionScheduler 2026-03-07 15:30:25 +08:00
d9e384960f refactor(action): remove ActionExecutorInput 2026-03-07 15:15:08 +08:00
2baa3971a8 refactor(action): support executing any type of Actions with virtual thread in ActionExecutor, ActionScheduler will send actionData to executor directly 2026-03-07 15:05:51 +08:00
4ee7a52f42 refactor(Action): make attribute status available for all implementations of Action, StateAction needs to present its trigger status also 2026-03-07 14:29:11 +08:00
28400545a7 chore(ActionExecutor): remove unused Void return value 2026-03-07 14:20:07 +08:00
1ce2038ab8 fix(Communication): fix Message appending logic and add refactor todo 2026-03-07 14:01:33 +08:00
0b63ec8523 fix(MemoryUpdater): fix message cleaning logic, and add refactor todo in updater 2026-03-07 13:53:34 +08:00
28a1bf8d1f refactor(chat): migrate Message from Java POJO to Kotlin data class 2026-03-06 21:04:58 +08:00
77059f84c4 将 .java 重命名为 .kt 2026-03-06 21:04:58 +08:00
d3eb5e8ee3 refactor(config): migrate ModelConfig from Java POJO to Kotlin data class 2026-03-06 17:01:03 +08:00
01cfc04dc7 将 .java 重命名为 .kt 2026-03-06 17:01:03 +08:00
6919fe656e refactor(module): rename CoreModel into CommunicationProducer 2026-03-06 15:21:36 +08:00
df25f488fa refactor(action): remove ActionDispatcher and related empty directory 2026-03-06 15:06:32 +08:00
036fd9e051 refactor(ActionPlanner): support schedule or execute actions(or
confirmed actions) immediately
2026-03-06 14:58:13 +08:00
383a49b855 refactor(ActionExecutor): refactor into Standalone module 2026-03-06 14:49:01 +08:00
7e88b8b926 chore(action): add refactor todos in ActionScheduler 2026-03-06 14:28:52 +08:00
c6c8a83dad chore(test): remove unused non-null test for ActionScheduler 2026-03-06 14:17:04 +08:00
6635d7aca2 refactor(Action): add attribute enabled status into Action, and update related collectToTrigger logic in ActionScheduler 2026-03-06 14:15:51 +08:00
facc49a799 refactor(ActionScheduler): rename entry method into schedule 2026-03-06 14:04:15 +08:00
3c6076ee0a chore(idea): update misc.xml 2026-03-06 12:49:02 +08:00
40bd2deeba feat(cognation): add initiateTurn to execute input via AgentRuntime.submit 2026-03-05 16:49:17 +08:00
839f19f15b refactor(context): add PartnerRunningFlowContext factories for user/self source and update adapter creation 2026-03-04 20:02:56 +08:00
da1abbdc88 fix(AgentRuntime): repair exception handling logic in method executeTurn 2026-03-04 17:23:14 +08:00
e6a071fc93 refactor(context): migrate running flow context to source/status/info model, and update related modules 2026-03-04 17:21:34 +08:00
56688785ba 将 .java 重命名为 .kt 2026-03-04 17:21:34 +08:00
8a9892f039 chore(core): add TODO to use RunningFlowContext for message timestamp in CoreModel 2026-03-04 13:52:19 +08:00
06f5ae9aac refactor(core): remove global running flow context map and exception context reference 2026-03-04 13:11:42 +08:00
f8d90fbcee refactor(framework): make AgentRuntime.submit blocking and remove runBlocking from AgentInteractionAdapter 2026-03-03 21:23:52 +08:00
b02f29b1b1 refactor(framework): extract interaction execution into AgentRuntime and delegate from AgentInteractionAdapter 2026-03-03 21:14:10 +08:00
f1848fece4 refactor(framework): cache running modules in AgentInteractionAdapter and add refresh method 2026-03-03 20:29:23 +08:00
85cc5cace8 chore(framework): add message queue todo in AgentGateway 2026-03-03 11:48:59 +08:00
d462f02960 refactor(framework): mv interaction in-out flow into AgentInteractionAdapter 2026-03-03 11:48:08 +08:00
5ae8b713d7 refactor(framework): correct InteractionAdapter, support loading latest modules while running 2026-03-03 11:26:36 +08:00
cf25fce09e refactor(framework): remove coordinated capability mechanism and related manager/annotations 2026-03-02 20:34:30 +08:00
868b17b56b refactor(core): use chat message user IDs for single-user check in
`MemorySelector`
2026-03-02 20:34:16 +08:00
fe8031d9ac fix(core): remove CoordinatedManager log tag from memory insert logs 2026-03-02 20:31:22 +08:00
5847b38f2b refactor(framework): remove obsolete lifecycle TODO comment in AgentModule 2026-03-01 21:35:30 +08:00
6920bc6130 refactor(core): remove redundant @NotNull type-use annotation from async resource spec builder 2026-03-01 21:34:56 +08:00
fa9512db3b refactor(framework): migrate AgentInteractionAdapter flow execution to Kotlin coroutines and remove AgentRunningFlow 2026-03-01 21:33:31 +08:00
51d51937ed 将 .java 重命名为 .kt 2026-03-01 21:33:31 +08:00
23026d6dc8 refactor(framework): move RunningFlowContext from flow.entity to flow package 2026-03-01 21:31:04 +08:00
661dd625e3 chore(maven): move coroutines dependencies into Partner-Framework 2026-03-01 20:48:41 +08:00
33fdc61eff refactor(framework): remove module enabled-status loading and persistence from config loaders 2026-02-28 21:19:58 +08:00
0870d7bc0e fix(framework): fail module registration on duplicate moduleName in AgentContext 2026-02-28 21:05:12 +08:00
baf0b05e60 doc(framework): add KDoc for factory responsibilities and agent registration lifecycle 2026-02-28 20:44:40 +08:00
51efb55259 refactor(framework): rename ComponentInitHookExecuteFactory to ComponentInitHookExecutorFactory 2026-02-28 20:38:29 +08:00
d5095359db refactor(framework): validate and collect @Shutdown hooks during agent
registration
2026-02-28 20:38:09 +08:00
1abfc729f8 fix(framework): reject @Init methods with parameters during component validation 2026-02-28 20:25:33 +08:00
528e88f613 refactor(framework): scope shutdown-only Instances and computeInstances helpers inside installShutdownHook 2026-02-27 00:34:07 +08:00
333d087979 refactor(framework): register and execute ordered @Shutdown hooks in AgentContext via JVM shutdown hook 2026-02-27 00:28:14 +08:00
a863b43563 refactor(framework): register capability core instances per capability and store cores in AgentContext 2026-02-26 22:27:43 +08:00
dde01a6253 fix(framework): reject additional components missing @AgentComponent annotation 2026-02-26 22:18:36 +08:00
fa50f4aeb7 refactor(framework): store AgentContext additional components by type and update init/injection target collection 2026-02-26 22:17:41 +08:00
b87ede0e8b refactor(framework): add @Shutdown annotation to AgentContext for ordered shutdown hook execution 2026-02-26 22:08:33 +08:00
010860de8d refactor(framework): migrate AgentRegisterFactory to Kotlin object and preserve agent registration flow 2026-02-23 23:34:54 +08:00
379cabe042 refactor(framework): replace ModuleInitHookExecuteFactory with Kotlin ComponentInitHookExecuteFactory and drive @Init execution from validated component context 2026-02-23 23:14:45 +08:00
1b164cedf1 refactor(framework): migrate capability injection to Kotlin CapabilityInjectorFactory and inject capability instances directly into components 2026-02-23 22:59:47 +08:00
7ee698768c refactor(framework): simplify AgentContext capability storage to a single implementation per capability 2026-02-23 22:59:20 +08:00
2e29e5ca7f refactor(framework): migrate CapabilityRegisterFactory to Kotlin and rebuild capability registration from validated context 2026-02-23 22:32:32 +08:00
e0a62053b5 refactor(framework): migrate AgentRegisterContext to Kotlin and store validated capability scan results in context 2026-02-23 22:12:56 +08:00
f13e45327d refactor(framework): remove legacy CapabilityFactoryContext and ModuleFactoryContext from registration flow 2026-02-23 21:58:25 +08:00
f56ff7d719 refactor(framework): rework AgentContext capability storage to group implementations by capability and include method metadata 2026-02-23 21:53:37 +08:00
fd9b376afa refactor(framework): replace CapabilityCheckFactory with Kotlin CapabilityAnnotationValidatorFactory and update capability validation flow 2026-02-23 21:41:38 +08:00
542de84640 refactor(framework): add ComponentInjectorFactory for module/additional component injection before capability registration 2026-02-23 21:16:04 +08:00
907bb626f2 chore(gitignore): update gitignore 2026-02-22 14:15:17 +08:00
2cdeaa1c30 refactor(framework): make AgentContext capabilities non-null and infer capability type on registration 2026-02-21 22:38:56 +08:00
833fe4deb3 refactor(framework): add component annotation validation before component registration 2026-02-21 19:27:17 +08:00
3c26e77b76 refactor(framework): rename AgentComponentRegisterFactory to ComponentRegisterFactory 2026-02-21 19:19:04 +08:00
2825f7f1de refactor(framework): replace legacy module check/register/proxy flow with unified AgentComponentRegisterFactory 2026-02-21 18:56:40 +08:00
86b7e5c492 refactor(framework): rename agent.factory.module to agent.factory.component and update related imports 2026-02-21 17:57:29 +08:00
b1e4d3c2e4 fixup! refactor(framework): rename AgentConfigManager to AgentConfigLoader and update agent/core wiring 2026-02-21 17:46:16 +08:00
997616e45f refactor(framework): migrate ConfigLoaderFactory to Kotlin and simplify loader metadata registration 2026-02-21 17:42:05 +08:00
6733984843 将 .java 重命名为 .kt 2026-02-21 17:42:05 +08:00
0f2052c507 refactor(framework): migrate AgentBaseFactory from Java to Kotlin and update execute signature 2026-02-21 17:22:38 +08:00
23bfb8bac1 将 .java 重命名为 .kt 2026-02-21 17:22:38 +08:00
15c11ac500 refactor(framework): type AgentContext metadata entries and add JSON-backed metadata registration 2026-02-21 17:10:46 +08:00
deffc91dd1 refactor(framework): remove obsolete Java AgentContext class 2026-02-21 16:55:31 +08:00
b2d44668da refactor(framework): rename AgentConfigManager to AgentConfigLoader and update agent/core wiring 2026-02-21 16:51:59 +08:00
f8399d2280 refactor(framework): add additional component storage and guarded registration in AgentContext 2026-02-21 16:28:20 +08:00
2870e79f79 refactor(framework): remove obsolete agent proxy and register test stubs 2026-02-21 16:19:57 +08:00
3c9ace8e56 refactor(framework): rename CapabilityHolder to AgentComponent across factory and module hooks 2026-02-21 16:19:00 +08:00
e510725e71 refactor(framework): remove legacy running/sub module base classes and module annotations 2026-02-21 16:14:46 +08:00
f963cae4ed refactor(framework): rename Context.kt to AgentContext.kt 2026-02-21 16:06:11 +08:00
45c4e8169a refactor(framework): add mutable metadata map to Context 2026-02-21 15:43:19 +08:00
6bf4d95b05 refactor(framework): encapsulate AgentContext maps and require modelInfo in module contexts 2026-02-20 21:31:20 +08:00
00ef090d2f refactor(framework): generalize AgentContext and ModuleContextData generics with wildcard bounds 2026-02-20 20:55:56 +08:00
e62cddfe44 refactor(framework): add enabled flag to ModuleContextData.Running 2026-02-20 19:00:49 +08:00
115a8d5446 refactor(framework): redesign AgentContext to store typed module contexts and runtime metadata 2026-02-20 18:57:36 +08:00
ef5d5802a7 refactor(framework): make Standalone extend AbstractAgentModule 2026-02-20 17:46:33 +08:00
87c34cc699 refactor(modules): convert ActionScheduler to Standalone and simplify async execute signature 2026-02-20 17:29:26 +08:00
bbace28d7a refactor(project): normalize formatting and reorder class members across modules 2026-02-20 17:22:54 +08:00
c47d2b2285 refactor(modules): refactor modules base class into AbstractAgentModule and remove unused @slf4j annotation 2026-02-20 17:17:49 +08:00
38c618a222 chore(gitignore): update gitignore 2026-02-20 16:30:22 +08:00
e00441faa8 refactor(framework): make AbstractAgentModule sealed with class-based module contracts and streamline ActivateModel model access 2026-02-20 16:12:35 +08:00
c3b0a9dd25 refactor(framework): make ActivateModel companion configManager private 2026-02-20 15:39:52 +08:00
6b7c9db5b1 refactor(framework): add order() to AbstractAgentModule.Running contract 2026-02-20 15:30:55 +08:00
e2ef92ce43 refactor(framework): use moduleName as modelKey for
`AbstractAgentModule` instances in ActivateModel
2026-02-20 15:29:38 +08:00
051b6450e7 refactor(framework): mark AbstractAgentModule as capability holder and consolidate module contracts within abstracts 2026-02-20 15:24:35 +08:00
2a3d33a61e refactor(framework): correct comments for ActivateModel 2026-02-20 15:02:33 +08:00
e57c03e213 refactor(framework): migrate module abstracts/ActivateModel to Kotlin and introduce shared model/context structures 2026-02-20 15:00:14 +08:00
14e6d71ac9 将 .java 重命名为 .kt 2026-02-20 15:00:14 +08:00
dc9f9417bc refactor(framework): remove @BeforeExecute/@AfterExecute hook proxy logic and use direct module instantiation 2026-02-19 22:53:49 +08:00
5051c2f662 refactor(framework): use existing model instance in
init hook `ActivateModel#modelSettings`
2026-02-19 21:46:37 +08:00
c30ec35f85 refactor(framework): rename @AgentModule to @AgentRunningModule 2026-02-19 21:39:59 +08:00
c7f113b59a refactor(framework): rename AgentRunningModule/SubModule to AbstractAgent* and migrate module inheritance usage 2026-02-19 15:04:30 +08:00
8735660830 refactor(framework): remove log hook surrounded with method execute in AgentRunningSubModule 2026-02-19 14:37:21 +08:00
18b2bb8812 refactor(framework): reorganize Module abstracts location 2026-02-19 14:09:51 +08:00
7fccea5b91 chore(agent): add todo for PartnerOutputData 2026-02-19 14:07:39 +08:00
a9bf7ca1c2 refactor(framework): correct exception names in Partner-Framework 2026-02-19 14:01:26 +08:00
1685d148c4 chore(gitignore): update gitignore 2026-02-19 14:00:35 +08:00
73ab40416d refactor(Project): rename Partner-Api/Partner-Main modules to Partner-Framework/Partner-Core and update Maven dependencies 2026-02-19 10:39:21 +08:00
1244d59fa4 chore(ActionScheduler): remove todos 2026-02-18 15:22:02 +08:00
11ea1045f4 refactor(Action): generalize ActionScheduler to Schedulable and add StateAction trigger execution path 2026-02-18 15:20:52 +08:00
a1bc784da5 refactor(Action): rename Scheduled interfaces/classes to Schedulable 2026-02-15 23:09:35 +08:00
747d3e47d6 refactor(Action): add StateAction with scheduled trigger support for state updates/callbacks 2026-02-15 21:27:11 +08:00
5f0165fa3a refactor(Action): split ActionData into Action/ExecutableAction and unify scheduled action types 2026-02-15 21:26:17 +08:00
2b0682b9e0 chore(Action): remove todo in ActionData
Context:
SYNC is like the normal reAct execution, the thread based execution model with necessary notification can cover the demands entirely
2026-02-14 12:02:03 +08:00
16a92de377 chore(Action): add TODO notes for trigger type design and executor write-back flow 2026-02-13 21:27:23 +08:00
cbba183b60 docs(README): formatted 2026-02-10 13:52:14 +08:00
8e642b07d9 docs(README): expand Action system section with architecture and execution flow details 2026-02-10 13:50:31 +08:00
66d8a95c73 docs(README): clean up section formatting and update content 2026-02-10 13:26:31 +08:00
0850f8403d docs(README): rewrite project description and adjust planning items 2026-02-10 13:17:30 +08:00
24c29a6dc6 chore(resource): remove legacy Partner prompt and module config in resources, which will be provided in config dir or other ways 2026-02-10 13:17:05 +08:00
f703cc8157 refactor(vector): make embedding URL and model fields final 2026-02-10 13:05:09 +08:00
d52f48f132 fix(AgentConfigManager): set default INSTANCE to null instead of FileAgentConfigManager, which will be set in ConfigLoaderFactory or AgentApp 2026-02-10 13:03:58 +08:00
f6afe21b43 Merge branch 'feature/ActionModule'
# Conflicts:
#	.gitignore
2026-02-09 21:22:26 +08:00
d381a97731 refactor(ActionScheduler): add debug log for hour-change trigger scan 2026-02-09 21:12:38 +08:00
940beb2587 test(ActionScheduler): add test 2026-02-09 21:05:08 +08:00
69d9f04f11 fix(ActionScheduler): stabilize wheel tick pacing and run trigger scan before hour/day refresh 2026-02-09 21:04:48 +08:00
e2bd9eb0af fix(ActionScheduler): enqueue same-hour actions in wheel and add scheduling debug logs 2026-02-09 21:19:40 +08:00
9ec03c4c95 fix(ActionScheduler): include previous tick in trigger scan and tighten next execution filtering 2026-02-09 21:01:22 +08:00
ecbbbc9954 refactor(ActionScheduler): include tick in wheel stop debug log 2026-02-09 20:56:45 +08:00
a5d26769e8 fix(ActionScheduler): skip trigger callback when tick has no actions 2026-02-09 20:54:35 +08:00
2db1bdf3e9 refactor(ActionScheduler): add debug log for action execution 2026-02-09 20:50:36 +08:00
656d6b65e3 refactor(ActionScheduler): add debug logs for wheel start/stop, wait window, and action loading 2026-02-09 20:41:01 +08:00
7c46f1d1ff fix(ActionScheduler): remove triggered hour actions by uuid to avoid removeAll mismatch 2026-02-09 20:03:24 +08:00
406b4250aa refactor(ActionScheduler): correct actions loading logic in hour/day updating 2026-02-09 20:03:10 +08:00
eab3d00fe8 refactor(ActionScheduler): remove useless delay in TimeWheel#wheel 2026-02-09 20:02:26 +08:00
d47e9fbf95 fix(ActionScheduler): initialize wheel tick baseline before launch to avoid check-to-wheel startup drift 2026-02-09 17:29:32 +08:00
4b77f26e7b refactor(ActionScheduler): capture current hour once and reuse it for
day/hour rollover checks
2026-02-09 16:37:46 +08:00
650f9b27a1 fix(ActionScheduler): use checkThenExecute current hour consistently and trigger wheel tasks outside lock 2026-02-09 15:56:12 +08:00
9f479c5f6f fix(ActionScheduler): unify time check/loading under checkThenExecute and guard wheel loop with launch-hour consistency 2026-02-09 14:57:13 +08:00
227c735667 fix(ActionScheduler): make TimeWheel load scheduled actions dynamically instead of using init snapshot 2026-02-09 00:13:36 +08:00
b05b665960 fix(ActionScheduler): reload day/hour action buckets on time changes via checkTimeAndLoad, and reorganize functions 2026-02-09 00:03:21 +08:00
882ec43f2b fix(ActionScheduler): make scheduling thread-safe with Mutex and cancel scheduler/time wheel scopes on shutdown 2026-02-08 23:07:03 +08:00
7cb565fd1b fix(ActionScheduler): use withTimeoutOrNull when waiting for ACTIVE state, to avoid exception leading to wheel stopped 2026-02-08 21:56:35 +08:00
84b96b6645 test(ActionScheduler): remove unused actionExecutor mock 2026-02-08 21:52:16 +08:00
2169376062 test(ActionScheduler): add unit test for ActionScheduler 2026-02-08 21:51:57 +08:00
9bff74c8c7 fix(ActionScheduler): remove second offset when loading hour actions 2026-02-08 21:51:30 +08:00
76c9c27532 refactor(MetaAction): make result a read-only property 2026-02-08 17:22:47 +08:00
8524ca6f9f refactor(ActionData): use action.result.reset() when clearing action chain state 2026-02-08 17:22:10 +08:00
7dd2104689 refactor(MetaAction): migrate to Kotlin data class, merge MetaActionType/ResultStatus into nested enums, and update runner/action usages 2026-02-08 17:15:58 +08:00
6ba5784a7f 将 .java 重命名为 .kt 2026-02-08 17:15:58 +08:00
cdea8d6322 refactor(ActionData): migrate to Kotlin sealed class and data classes, update planner/scheduler usage 2026-02-08 16:27:44 +08:00
8ca2b9998d 将 .java 重命名为 .kt 2026-02-08 16:27:44 +08:00
d098b28f31 refactor(ActionExecutorInput): migrate to Kotlin data class 2026-02-08 15:12:10 +08:00
98e4d4cf1b 将 .java 重命名为 .kt 2026-02-08 15:12:10 +08:00
70489e57f7 chore(pom): add kotlinx-coroutines-test dependency 2026-02-08 14:34:19 +08:00
a43c87006e refactor(ActionCore): replace existing action with same UUID before putAction 2026-02-08 13:29:18 +08:00
be43b7eec6 refactor(ActionScheduler): implement Kotlin time-wheel scheduling and requeue scheduled actions after execution 2026-02-08 13:24:56 +08:00
3bc2ce839a 将 .java 重命名为 .kt 2026-02-08 13:24:56 +08:00
fe5a366527 refactor(ActionExecutor): remove userId from ActionExecutorInput and use source 2026-02-08 11:29:36 +08:00
9f724cee5d chore(pom): remove test scope from coroutines dependency 2026-02-08 11:22:47 +08:00
ad58b83020 refactor(ActionExecutor): rename actions variable for clarity 2026-02-08 11:22:30 +08:00
c9b64fec2a chore(pom): add cron-utils dependency 2026-02-07 15:36:45 +08:00
0eb4765235 refactor(ActionExecutor): use HistoryAction record and track scheduled history reset 2026-02-07 15:35:34 +08:00
050c39cbc7 refactor(ActionExecutor): correct input actions' type in ActionExecutor 2026-02-06 23:38:13 +08:00
08100aea8a refactor(ActionCore): replace prepared action APIs with generic list/put 2026-02-06 21:38:54 +08:00
2cd0774834 refactor(ActionCapability): rename listAvailableActions to listAvailableMetaActions 2026-02-06 21:05:10 +08:00
12df938d85 refactor(ActionCore): simplify handleInterventions to use ActionData 2026-02-06 20:41:08 +08:00
277c0d437f chore(ActionCore): update comment 2026-02-06 20:36:50 +08:00
6b861f4b77 fix(ActionExecutor): correct logic in ActionExecutor when actionChain is empty, which will skip execution 2026-02-05 20:40:02 +08:00
d33b6617c1 fix(ActionExecutor): support removing phaserRecord correctly when exception occurred in ActionCorrector 2026-02-05 19:40:28 +08:00
a1dcf4a6fa test(ActionExecutor): test with action failure 2026-02-05 17:05:53 +08:00
9c38719514 test(ActionExecutor): test with additionalContext appending 2026-02-05 16:58:22 +08:00
33df0fa017 test(ActionExecutor): test with virtual thread pool support 2026-02-05 16:53:38 +08:00
08bda84471 refactor(ActionCore): Specifies the minimum platform thread pool size
Context:
 The ActionExecutor needs at least 2 platform thread to support async  action execution,
 otherwise the current ActionExecutor logic cannot be executed
2026-02-05 16:49:58 +08:00
76da3c29f8 fix(ActionExecutorTest): repair stub in test 2026-02-05 16:13:21 +08:00
558b589830 refactor(ActionInterventor): redefine DTOs in ActionInterventor to adapt the actual intervention logic 2026-02-05 15:48:58 +08:00
80d7c283c5 refactor(ActionExecutor): update ActionChain execution, support executing and advancing correctly 2026-02-04 00:29:42 +08:00
b0bb40c5f0 test(ActionExecutor): add unit test for ActionExecutor 2026-02-01 19:49:21 +08:00
eec8f71096 fix(action): correct return type of method runnerClient() in ActionCapability 2026-02-01 16:43:12 +08:00
fbd30d1a96 build(maven): import Mockito related dependencies 2026-02-01 14:56:47 +08:00
346f925b66 chore(ActionExecutor): update comment 2026-01-31 23:35:17 +08:00
04e8d9e531 feat(ActionExecutor): support executing interventions in ActionExecutor 2026-01-30 20:58:12 +08:00
63d1552de2 refactor(ActionInterventor): remove InterventionHandler and related data class
Context:
Since last commit, the logic of interventions has been moved into ActionCapability,
the InterventionHandler is not needed.
2026-01-30 20:52:36 +08:00
77eb9b92a4 refactor(ActionCorrector): move intervention logic from InterventionHandler into ActionCapability 2026-01-30 20:10:01 +08:00
a1b4743eeb feat(ActionCorrector): complete corrector's executing logic 2026-01-30 19:19:48 +08:00
0768cddd2d fix(ActivateModel): correct modelSettings 2026-01-30 16:50:45 +08:00
75145cc547 chore(ActionRepairer): correct name of AssemblyHelper 2026-01-30 16:30:10 +08:00
d1ca1cda7d feature(ActionExecutor): complete CorrectorInput 2026-01-28 23:11:45 +08:00
fac6609d6b refactor(ActionExecutor): remove useless method getHistoryActionResults 2026-01-28 23:00:53 +08:00
dce8825e58 refactor(ActionExecutor): update type of history field in ActionData 2026-01-28 21:16:51 +08:00
cd641ac8dd fix(ActionExecutor): correct phaser block logic in method execute 2026-01-28 15:38:13 +08:00
5ffdab9e4a refactor(ActionExecutor): rework staged execution and runner submit
Context:
This refactor drops unnecessary method abstractions and cleans the action execution flow.
Additionally, method 'run' is renamed to 'submit' in RunnerClient, which better reflects that execution results are held in MetaAction.
2026-01-25 19:38:53 +08:00
830503eee4 chore(ActionExecutor): update comments 2026-01-23 19:23:07 +08:00
96e74ec877 test(LocalRunnerClient): add test for method run in RunnerClient 2026-01-17 11:28:21 +08:00
420d51af15 fix(LocalRunnerClient): harden doRun branches and add tests 2026-01-16 23:28:46 +08:00
8ead306b7b fix(RunnerClient): correct RunnerResponse's visibility 2026-01-16 22:17:15 +08:00
c793851107 fix(LocalRunnerClient): support cleaning non-existing MCP Servers' tools while MCP configuration files changed in CommonMcp 2026-01-16 21:48:17 +08:00
fb5cabc747 fix(LocalRunnerClient): support read MetaActionInfo according to desc files when an MCP Client with described tools registered by CommonMcp 2026-01-16 21:28:45 +08:00
c5f6c4e0ae fix(LocalRunnerClient): recover desc watcher after root deletion and expand DescMcp tests 2026-01-14 19:57:24 +08:00
200c0f3f13 fix(LocalRunnerClient): guard against null tool meta and ignore non-protocol MCP 2026-01-14 16:10:33 +08:00
fdf398b86e fix(LocalRunnerClient): close old MCP client while a new client's name is duplicated with the old one 2026-01-13 23:22:54 +08:00
774e2b6cd5 fix(LocalRunnerClient): correct abnormal deleting condition in CommonMcp 2026-01-13 23:13:52 +08:00
837a4c92d1 fix(LocalRunnerClient): treat missing action dir as invalid path during DELETE in DynamicMcp
Context:
Action directories may already be removed when DELETE events are handled.
Return null from loadFiles to signal invalid paths and lock behavior with DynamicAction watch tests.
2026-01-12 21:46:34 +08:00
ddd999d47b fix(LocalRunnerClient): prevent WatchService event loss caused by concurrent consumers
Context:
Shared WatchService with multiple watch threads caused WatchKey events to be consumed by mismatched processors, leading to missed file events.
Use isolated WatchService per WatchContext to restore correct semantics.
2026-01-12 19:46:45 +08:00
9694a022c7 chore(gitignore): update gitignore 2026-01-12 19:35:41 +08:00
31968c7076 chore(gitignore): create AGENTS.md for codex, and add it to .gitignore 2026-01-12 14:25:20 +08:00
abec141e4e fix(LocalRunnerClient): correct path creating logic in RunnerClient and its implementations 2026-01-11 16:47:14 +08:00
cdb6ae9d01 fix(LocalRunnerClient): correct method loadFiles in LocalWatchEventProcessor 2026-01-11 16:30:44 +08:00
dd8d86d3c4 chore(LocalRunnerClient): add logs to LocalRunnerClient 2026-01-11 16:27:14 +08:00
99b42620d0 refactor(LocalRunnerClient): repair paths registering order and support creating directories automatically 2026-01-11 15:01:19 +08:00
70b8335d49 feat(LocalRunnerClient): support atomic persist serialization in LocalRunnerClient 2026-01-11 14:24:34 +08:00
8ca475beeb feat(LocalRunnerClient): support registering CommonMcp 2026-01-08 22:28:12 +08:00
4f36c0dd2d feat(LocalRunnerClient): support deleting MCP configurations in CommonMcp 2026-01-08 22:23:08 +08:00
00993bd763 feat(LocalRunnerClient): support creating MCP configurations in CommonMcp 2026-01-08 22:09:14 +08:00
a0bca668cb refactor(LocalRunnerClient): support update existedMetaActions in method registerMcpClient 2026-01-08 21:48:30 +08:00
c6118c41b0 refactor(LocalRunnerClient): support loading primary fileMcpCache when CommonMcp launched 2026-01-08 21:33:39 +08:00
872d21170a feat(LocalRunnerClient): support modify and overflow events on mcp configurations in CommonMcp
Context:
Due to single file cannot present all mcp configurations, loading all MCPs at once is required.
This is compatible in both modify and overflow events.
2026-01-08 21:16:28 +08:00
44ab6cfac8 feat(LocalRunnerClient): support registering MCP clients in CommonMcp 2026-01-05 23:06:17 +08:00
ec30ac1922 refactor(LocalRunnerClient): remove tool change consumer in registerMcpClient
Context:
ExistedMetaActions' updating logic is covered by implementations of LocalWatchEventProcessor.
2026-01-03 16:34:04 +08:00
74b6d0c653 chore(RunnerClient): fix RunnerClient error usages in implementations 2026-01-03 15:49:54 +08:00
de462866b2 feat(LocalRunnerClient): support registering DescMcpServer watch service 2026-01-02 21:41:47 +08:00
4ea8926363 feat(LocalRunnerClient): support repairing description data while OVERFLOW event happened in DescMcpServer 2026-01-02 21:29:18 +08:00
04c98c7856 fix(LocalRunnerClient): support deleting descCache while *.desc.json is not available in DescMcpServer 2026-01-02 18:18:15 +08:00
0757856187 feat(LocalRunnerClient): support deleting *.desc.json in DescMcpServer 2026-01-02 17:20:12 +08:00
19ec93f248 feat(LocalRunnerClient): create modify *.desc.json in DescMcpServer 2026-01-02 16:45:01 +08:00
5877b9e80d feat(LocalRunnerClient): support modify *.desc.json in DescMcpServer 2026-01-02 16:42:56 +08:00
5db0b5fad1 feat(LocalRunnerClient): support load *.desc.json when DescMcpServer launched 2026-01-02 15:55:29 +08:00
623a86daab chore(LocalRunnerClient): update mcp servers' comments 2026-01-02 15:52:44 +08:00
64f24d3fc3 chore(LocalRunnerClient): adjust mcp servers' comments location 2026-01-02 13:38:43 +08:00
3097efe453 feat(LocalRunnerClient): support register DynamicActionMcp watch service 2026-01-02 13:29:00 +08:00
b58eeffd2f feat(LocalRunnerClient): support overflow event in DynamicActionMcpServer 2026-01-01 23:32:21 +08:00
62cec79005 refactor(LocalRunnerClient): extract duplicated action adding logic 2026-01-01 22:39:32 +08:00
03a5935107 fix(LocalRunnerClient): support deleting event for action directories in DynamicActionMcp 2026-01-01 21:29:30 +08:00
0ecaec0545 fix(LocalRunnerClient): repair loading logic of action subdirectories 2026-01-01 20:28:19 +08:00
74f2c6c950 fix(LocalRunnerClient): support creating and registering new action in
method buildCreate in DynamicActionMcp
2026-01-01 00:32:34 +08:00
f35a467ebc fix(LocalRunnerClient): support registering subdirectories in LocalWatchServiceBuild 2025-12-31 23:15:27 +08:00
64b907707a refactor(LocalRunnerClient): introduce WatchContext and decouple build/processor state 2025-12-31 23:11:15 +08:00
a6e33edc7a refactor(LocalRunnerClient): support remove action temporarily while action is not usable 2025-12-31 16:27:34 +08:00
94ef79c67d feat(LocalRunnerClient): support program deletion for DynamicActionMcp 2025-12-31 13:41:35 +08:00
a222015abb feat(LocalRunnerClient): support program modify and unify action load protocol
Context:
The method buildModify reuses AsyncToolSpecification building logic in buildLoad.
This feature unifies local action directory protocol, and refactors related logic in buildLoad.
New action directory protocol defines the file names of program and description files.
2025-12-30 20:52:32 +08:00
1c562f0e7b refactor(LocalRunnerClient): update action keys building source in
DynamicActionMcp

 Context:
 Building action keys by subdirector's name keeps unique identity for each local action.
2025-12-30 16:43:39 +08:00
89535a6b1c feat(LocalRunnerClient): add initial support for loading local action tools from filesystem
Context:
This feature supports DynamicActionMcpServer.

During initialization, directories containing a program file and a
.meta.json description are scanned and registered as MCP tools.
Tool execution is handled asynchronously via boundedElastic to avoid blocking server threads.
2025-12-29 20:46:26 +08:00
6e90bc8d67 refactor(LocalRunnerClient): co-locate system execution result 2025-12-29 18:53:41 +08:00
0e741802d1 refactor(LocalRunnerClient): consolidate MCP client transport params
Context:
Group HTTP and STDIO transport parameter variants under a sealed internal transport parameter hierarchy.
2025-12-29 18:48:53 +08:00
db3435fccf refactor(LocalRunnerClient): co-locate watch service builder internals
Context:
Group WatchService build interfaces and registry implementation into a
single internal structure for better cohesion.
2025-12-29 18:40:20 +08:00
e3294ec302 refactor(LocalRunnerClient): move system execution methods into SystemExecHelper 2025-12-29 18:26:30 +08:00
bf99e01b51 feat(LocalRunnerClient): introduce LocalWatchServiceHelper and internal implementations
Context:
This change introduces an internal scaffold to organize WatchEventHandler building logic.
2025-12-29 17:45:39 +08:00
1bd23b20c4 refactor(LocalRunnerClient): introduce DescMcpServer
Context:
This refactor supports creating descriptional files for common MCP Tools.
2025-12-29 17:35:03 +08:00
442dd55686 refactor(LocalRunnerClient): rename LocalWatchServiceRegistry 2025-12-29 14:27:00 +08:00
abe5dd5251 chore(idea): update misc.xml 2025-12-26 21:28:10 +08:00
1f737c0e29 refactor(action): reorganize constants in action module 2025-12-26 21:28:02 +08:00
d41074c814 refactor(LocalRunnerClient): replace ActionWatchService with unified watch service builder.
Context:
ActionWatchService was used to support SCRIPT and PLUGIN type actions loading from local FileSystem, this refactor allows register different paths to watch.
2025-12-25 15:41:49 +08:00
621441601a feat(LocalRunnerClient): correct method signature 2025-12-25 10:20:55 +08:00
e00d77f076 feat(LocalRunnerClient): add shutdown logic for dynamicActionMcpServer 2025-12-25 10:12:38 +08:00
d614ac0b15 feat(LocalRunnerClient): support initializing in-process dynamic action MCP Server 2025-12-24 21:36:39 +08:00
592e2604d9 refactor(mcp): move InProcessMcpTransport into Partner-Common module
Context:
Action modules in Partner-Main and SandboxRunner module rely on in-process MCP transport to support dynamically action generating.
2025-12-24 19:34:04 +08:00
dcbd2c6569 build(maven): introduce common module 2025-12-24 19:21:53 +08:00
476acb0641 refactor(LocalRunnerClient): rename McpServerParams into McpClientTrasnportParams 2025-12-22 15:02:07 +08:00
88a14f36b2 refactor(runner): relocate InProcessMcpTransport to experimental and move local MCP client logic into LocalRunnerClient
Context:
Recent changes blurred the responsibility boundary between RunnerClient and LocalRunnerClient.
This refactor moves local MCP client–specific logic into LocalRunnerClient and isolates InProcessMcpTransport and related code under the experimental package.
RunnerClient only defines indispensable methods and attributes.
2025-12-22 14:56:23 +08:00
05d1fff125 refactor(RunnerClient): remove unused MCP type enum class 2025-12-21 23:03:25 +08:00
49a4c9eb01 docs(RunnerClient): add architecture-location comment on RunnerClient 2025-12-21 22:05:46 +08:00
9e76c3e7ad refactor(SandboxRunnerClient): align doRun visibility with superclass 2025-12-19 23:34:17 +08:00
9762739138 refactor(action): replace HashMap with ConcurrentHashMap for thread-safe MetaAction storage 2025-12-19 23:30:27 +08:00
1f5509c17d refactor(RunnerClient): redesign existedMetaActions update strategy
Context:
Resource-change events cannot reliably represent tool changes.
The previous approach attempted to externalize descriptive content into files, but the meta attribute of McpSchema.Tool can provide this information.
2025-12-19 23:22:36 +08:00
ed042cfffa fix(action): correct params type in related DTOs 2025-12-19 22:57:34 +08:00
128592e23c chore(MetaActionInfo): remove unused type attribute 2025-12-19 22:47:06 +08:00
5ba36ed3e8 feat(LocalRunnerClient): support executing MetaActions via MCP type 2025-12-19 22:29:03 +08:00
4dea948f82 refactor(MetaAction): separate key attribute into name and location
Context:
This change adapts MetaAction locating to support different MetaAction types,
including loading from the local filesystem and from MCP tools.
2025-12-19 21:35:39 +08:00
dc4074715e chore(MetaAction): remove unused order attribute 2025-12-19 20:53:01 +08:00
225802c1a8 refactor(MetaActionInfo): remove key attribute and update related logic
Context:
MetaActionInfo was previously located via its own key attribute.
This is now redundant, as ActionCore already uses the key of existedMetaActions
as the single source of truth.
2025-12-19 20:41:07 +08:00
e851e33b2e feat(RunnerClient): support MCP type-based dynamic client/server registration
This allows implementations of RunnerClient to dynamically register different types of MCP service, and also provides a shutdown hook to close client/server properly.
2025-12-18 22:25:32 +08:00
cb28a5b068 feat(RunnerClient): add InProcessMcpTransport to support in-process MCP communication
Context:
This allows RunnerClient implementations to host local MCP servers without spawning another process.
2025-12-18 21:48:35 +08:00
ad58567ada chore(deps): introduce mcp dependencies 2025-12-18 17:52:15 +08:00
0eee12d685 refactor(MetaActionInfo): remove outdated constructor
Context:
Previously, MetaActionInfo comes from the local filesystem changes.
But now MCP Servers already provide a method to get information of MetaActions.
The pre- or post-dependencies are still required, for some MCP Tools cannot just be executed without additional context.
2025-12-18 17:49:52 +08:00
1e6ff1b30c chore(ActionCore): update outdated comment 2025-12-18 17:49:52 +08:00
0413fc281d chore(MetaAction): update outdated comment 2025-12-17 22:18:43 +08:00
8a7681ae31 chore(LocalRunnerClient): remove a redundant comment 2025-12-17 20:02:28 +08:00
1947f25ed6 feat(LocalRunnerClient): support executing origin actions
Context:
Origin actions are generated by DynamicActionGenerator and may optionally be
persistently serialized. This feature adds the basic execution flow for origin
actions within LocalRunnerClient.

Notes:
The current mapping between action files and their extensions is hardcoded. This should later be replaced with a configurable registry or loaded dynamically
during application startup.
2025-12-16 21:59:53 +08:00
488246525f chore(gitignore): exclude runtime data directory from version control 2025-12-16 21:39:11 +08:00
534dcd5ade fix(LocalRunnerClient): correctly capture stdout and stderr to avoid missing output in method exec 2025-12-16 21:30:51 +08:00
ad58c0cc7c refactor(LocalRunnerClient): allow injecting action watch path
Context:
The hardcoded action watch path made LocalRunnerClient difficult to test and
tightened it to a specific runtime layout. Injecting the watch path improves
testability and allows the runner to work in different runtime environments.
2025-12-16 21:02:29 +08:00
d546148d69 chore(test): organize experimental tests and test resources 2025-12-16 19:58:08 +08:00
bf2d5ac707 refactor(RunnerClient): restructure serialization and temp execution paths
Context:
Following the consolidation of action types into ORIGIN and MCP,
the serialization logic needs to be separated into dedicated methods.
These methods are invoked by DynamicActionGenerator.
2025-12-16 10:47:23 +08:00
628234f6e2 refactor(MetaActionType): redefine meta action types into MCP and ORIGIN
Context:
Previously, SCRIPT and PLUGIN were treated as separate action types,
but their semantics are already covered by MCP.
However, a generic execution path for locally generated actions is still
required, which is represented by ORIGIN.
2025-12-16 10:37:04 +08:00
4b852e0049 推进 ActionExecutor 下的‘行动生成与执行’部分
- 新增 RunnerClient 抽象类,并划分 SandboxRunnerClient、LocalRunnerClient两个子类(内容待完善)。前者负责对接 SandboxRunner 模块,后者直接使用本地作为执行环境(但不推荐)。
- 将 ActionWatchService 划为 LocalRunnerClient 的内部类,负责采用本地执行环境时,监听行动程序变化
- 完善 ActionRepairer 处的修复逻辑
- 调整 MetaAction 中路径获取逻辑

这提交方式真该调整一下了,这阶段推进容易攒太多,但又不好停手。或许阶段目标可以保留,但推进点应该可以细化🤔
2025-12-15 21:54:24 +08:00
6e3deced77 推进 ActionExecutor 下的 DynamicActionGenerator 子模块
- 完善了 DynamicActionGenerator 的大致逻辑,序列化逻辑待实现
- 补充了 PhaserRecord 中的阻塞逻辑,使用普通的线程sleep操作
- 调整了 MetaAction 中参数形式,由列表替换为 Map,便于执行时填写参数
- 完善了 DynamicActionGenerator 相关的数据类
2025-12-07 20:10:53 +08:00
6a351413a1 推进行动执行模块: 调整了 ActionExecutor 以支持行动链动态修复和参数提取; 完善了 ActionRepairer、ParamsExtractor 的主要逻辑; 完善了部分数据类的内容
- 在 ActionData 中新增 additionalContext 用于存储各个执行阶段临时修复生成的上下文,同样以执行阶段为键
- 调整 ActionExecutor 的输入参数,可传入用户标识,用于执行器调用 ActionRepairer 的修复过程
- 完善了 ActionExecutor 中行动单元的执行与修复逻辑,将支持正常状态推进执行、触发自对话时阻塞当前行动单元、所有修复方式失败时将整个行动数据标为 FAILED
- 完善了 ActionExecutor 中各个DTO的构建方法
- 完善了 ParamsExtractor 中的参数提取逻辑
- 在 PhaserRecord 中新增 interrupt 和 complete 方法,将用于后续行动单元的阻塞(ActionExecutor中)与恢复(InterventionHandler中)
- 完善了 ActionRepairer 中的修复逻辑,但自对话通道的暴露方式、DynamicActionGenerator 的具体逻辑待完善
2025-12-05 21:58:21 +08:00
ad973d4230 对 ActionExecutor 下子模块的功能分布、某些实体类进行了调整; 完善了 ActionExecutor 中的大致执行逻辑
- 梳理执行链路时发现 ActionRepairer 的能力明显超出可实现边界,故将其能力进行限定
- 新增 ActionCorrector 负责单组行动执行完毕后,根据意图和执行状况进行行动链修正
- 将 PhaserRecord 拆分为独立实体,未来将封装一部分流程控制逻辑
2025-12-02 22:35:53 +08:00
1d315a9b62 ActionExecutor 的执行流程规划完毕,具体逻辑待填充
- 调整了部分代码分布,移除了某些非必需的转发方法
- 新增几个 TODO 内容,后续工作已明确

这套调度方式看起来真的有些‘探索性质’了。实际上看起来有些像把 ReAct 的逻辑显式地进行了工程实现,不管是修复、依据状态选择行动单元生成还是阶段间针对行动单元的参数提取,在 ReAct Agent 中都是由一个智能体完成的。

但在这里,它要做的事情太多了,再加上 Partner 行动链的干预逻辑、幻觉参数又不可接受所以需要自对话或者用户干预,这些东西交给一个 ReAct 模块恐怕并不合适也不放心。所以这种显式模块划分应该更符合 Partner 行动模块的需求。

这点硬要说的话,应该还是在于‘ReAct 行为’并非 Partner 的全部吧。

不过谁知道呢,也许以后也会变,但这套至少现在看来是更能实现理想行为的
2025-12-01 19:25:21 +08:00
4e32129b31 优化行动链结构及相关组件、针对 ActionPlanner 相关组件做出调整
- 将existedMetaActions的实现由LinkedHashMap替换为HashMap,免去不必要的性能消耗
- 在 ActionCapability 中新增 listAvailableActions 方法用于获取当前存在的可用行动
- 将 ActionData 及相关类中的 LinkedHashMap 替换为普通Map,阶段并发将通过遍历key集合进行,而非针对原始行动链进行遍历
- 在 ActionPlanner 中完善行动链依赖修正逻辑,防止行动单元执行时的输入缺失
- 在 ActionEvaluator 中调整了 Prompt 构建方式
- 调整处理行动链相关代码,移除多余参数,简化方法签名
- 修正 EvaluatorResult 中行动链数据结构为Map,LLM将直接返回初始行动链,后续将加载行动数据并修复行动单元间的依赖关系
- 优化 InterventionHandler、ActionExecutor 等模块中对行动链Map的使用
2025-12-01 17:20:54 +08:00
3f59719e16 调整 MetaAction 的执行方式,将交给 ActionCapability、SandBoxRunnerClient 执行 2025-11-30 22:16:57 +08:00
c548cceec6 新增 SandboxRunner 项目子模块,该模块将在指定容器运行持久服务,与外部主进程通信,将用于后续执行JARSCRIPT两类行动类型 2025-11-30 18:41:42 +08:00
b3098310b4 完善了 ActionConfirmer 的遗漏逻辑 2025-11-30 15:16:57 +08:00
f48d559a7b 调整了 ActionInterventor 中数据构建方法的组织方式 2025-11-30 14:38:50 +08:00
14a57f0be6 推进行动干预模块,前置部分逻辑已基本完成
- 在`ActionData`中添加必要注释、新增`executingStage`字段表示当前执行阶段、移除了`WAITING`的状态类型
- 调整并修正了`ActionExecutor`中的`Phaser`阻塞逻辑
- 完善了`ActionInterventor`中`识别 -> 评估 -> 异步执行`的干预逻辑,并将干预结果以 Prompt 形式回写至流程上下文,作为主模块的已知内容
- 调整了干预模块内部的各个数据类的字段结构,适配干预流程
- 完善了`InterventionEvaluator`、`InterventionHandler`、`InterventionRecognizer`等必需的干预子模块
2025-11-29 20:56:29 +08:00
dff7b69b51 更新 README 2025-11-12 19:53:48 +08:00
d77ffd1db6 Merge remote-tracking branch 'origin/doc/architechture' into doc/architechture 2025-11-11 16:51:18 +08:00
264cdb09e5 推进行动干预模块; 接下来将进一步完善 InterventionHandler 的具体内容
- 调整相关目录为 interventor
-  调整了某些 ActionInterventor 的子模块用到的数据类结构
- 完善了 InterventionEvaluator 的具体逻辑
- 为 InterventionType 添加了注释,并新增了 CANCEL 干预类型
2025-11-11 16:11:09 +08:00
fea7f9c81f PerceiveSelector、PeiceiveUpdater 流程图制作完毕 2025-11-11 08:47:21 +08:00
a1520f117b 推进行动干预模块
- 完善了 ActionInterventor 中的具体逻辑以及不同情况下的prompt填充内容;
- 调整了 PreRunningModule 中的 getPromptDataMap 方法;
- 在 ActionCapability 中新增了检查 actionKey 是否存在的逻辑
2025-11-10 23:02:48 +08:00
ae5caf8475 更新 memory.md 2025-11-10 18:59:05 +08:00
980d9384d1 MemoryUpdater 流程图制作完毕 2025-11-08 17:33:05 +08:00
9ba0d1363a 创建了 action、memory、perceive 三类模块的流程文档; 完成了记忆模块中 MemorySelector 的流程图 2025-11-07 15:14:29 +08:00
f6d5cad5cd 更新 README 2025-11-07 13:51:30 +08:00
c3ca4145b8 推进行动干预模块
- 完善了大致的执行流程
- 明确并创建了评估与处理所需的数据类及干预类型
- 不同情况的Prompt处理结果、评估和处理的具体流程需要进一步完善
2025-11-06 22:07:27 +08:00
5419722c40 更新文档内容 2025-11-06 11:17:25 +08:00
31ebee3ded 制作了整体流程图 2025-11-06 11:14:37 +08:00
746fda1a5e 干预意图提取模块初步完成,Prompt 待制定; 在 ChatClient 中添加了默认的超时设定,超时时间后续可能需要调整。
另: 发现很多细节错误,比如“各个后置模块允许执行的条件”、“主模块出现异常时需要如何处理”、“模块Prompt的构建方式、采用格式不统一”等,需要后续进行修复或调整
2025-10-31 21:26:45 +08:00
ec4fbb7f19 行动干预足以抽离为新的前置模块,但仍属于‘行动’语义,大致框架已确立。后续实现时并发控制、各种干预的协调与触发时机需要注意。 2025-10-31 21:26:45 +08:00
f9c3cacfea 推进 ActionExecutor 相关的动态插拔式行动调度机制
- 移除先前构想的 SpecializedPartnerInputData 及相关类,无论是自反思、向用户求助还是用户主动干预,都应当通过语义识别来作用于对应行动事件,使用固定行动id的机制不足以支撑这种机制
- 在 ActionCore 中新增执行中行动的 phaser 管理逻辑
- 新增几个异常类,适用于行动数据加载的异常情况
- 新增 ActionIdentifier 负责行动干预意图的识别
-
2025-10-31 21:25:12 +08:00
e35e18f3b7 推进 ActionExecutor、确定动态插拔式行动调度的实现思路
- 在 ActionCore 中添加关闭hook,用于正确设置异常中断时执行中任务的状态
- 修正 actionPool 相关注释及用法
- 将 ActionData 中行动链字段调整为 LinkedHashMap 用于更好地支持分组并发及动态调度
- 重构 ActionExecutor 行动链执行逻辑,采用 Phaser 支持动态调度
- 扩展 InputData、Context 字段并调整 GateWay 格式化逻辑以适应特殊输入
2025-10-31 21:25:12 +08:00
83832d2060 推进 ActionExecutor、针对action core做出了一些调整
- 将 ActionWatchService 抽取为独立的类,使用构造参数传递所需内容
- ActionCore 中除了pendingAction外,将只维护一个行动池,通过用户键和STATUS区分类型
- 开始推进 ActionExecutor,但其中的同组并发、动态行动链、行动间参数对齐、参数重构等内容需要仔细考虑
2025-10-31 21:25:12 +08:00
4757425a15 推进 ActionDispatcher 模块、完善行动程序规范与加载逻辑
- 明确行动程序的存储形式与加载规则,分为执行程序和描述文件,前者负责逻辑,后者提供必要的描述性信息;
- 将 ActionInfo 重命名为 ActionData,更新相关接口和实现,增强代码一致性和可读性;
- 添加异常处理类以支持行动程序、描述信息的初始化和加载失败的场景;
- 实现行动程序目录的监控功能,支持行动程序的动态加载与管理;
- 明确了 ActionDispatcher 两个子模块的输入输出规范
2025-10-31 21:25:12 +08:00
21b3a0e846 开始推进 ActionDispatcher 模块
- ActionDispatcher 划分为 ActionScheduler 和 ActionExecutor 两个子模块,分别负责处理计划任务和即时任务
- 正式确定 Action 将以 ActionChain 的形式进行执行,也采用同组并发策略,按照 order 字段在 chain 中进行排序
- 调整了 ActionInfo 等类以适应当前的元行动类
- 对于行动能力的支持,或可考虑这几种方式: Agent自生成python脚本(必须经过验证,确认可执行且无风险)、MCP调用(需适配为Partner所支持的形式)、普通插件(在指定目录动态加载)
2025-10-31 21:25:12 +08:00
6bfa941c35 更新 README 2025-10-31 21:24:46 +08:00
456a7e04e8 更新 README 2025-10-24 17:29:55 +08:00
5864760f35 Action 模块语义缓存机制实现完毕,支持三种情况的语义缓存相关行为: 命中缓存且评估通过、命中缓存但评估未通过、未命中缓存但评估通过。将在评估过后步入主模块之前,进行异步更新操作(借助@AfterExecute注解,通过虚拟线程进入异步流程,在真正调用处使用平台线程加速计算) 2025-10-19 22:05:27 +08:00
aee6d879e9 推进 Action 模块语义缓存机制
- 完善缓存命中部分;
- 调整 ActionExtractor 以适配缓存逻辑
- 缓存更新大致框架待填充具体更新逻辑;
2025-10-18 21:56:50 +08:00
d1ea8dde79 推进 ActionExtractor 语义缓存机制: 移除了 VectorUtil,实现了 ollama、onnx runtime 两种向量客户端,通过 Agent 启动类暴露的后置启动任务加载并进行测试。 2025-10-17 11:20:11 +08:00
7094a8a68b 推进 ActionExtractor 语义缓存机制: 两种嵌入模型的连接方式测试完毕,在高性能主机上,可以通过ollama调用mxbai-embed-large这类模型,但放到4核8G香橙派3B就会出现推理时长过长,哪怕换成ONNX RUNTIME JAVA 也难以避免,但如果更换成 nomic-embed-text + ONNX RUNTIME JAVA ,仍能够拿到70左右ms的推理时长,远低于提取模型以及向量模型API的调用时长。预期可提供两种语义缓存所用的嵌入模型接入方式: 通过 http 调用 本地ollama接口; 指定 ONNX 格式的嵌入模型直接调用。 2025-10-16 23:04:41 +08:00
e78048f66d 推进 ActionExtractor: 新增语义向量计算工具;开始推进语义缓存相关;调整配置类格式 2025-10-16 15:39:38 +08:00
2f09c0cd71 推进 ActionExtractor: 完善大致逻辑,开始语义-行为缓存相关部分 2025-10-16 15:39:31 +08:00
8c43d6594f 推进 ActionPlanner: 新增行动确认机制,将与原‘提取-评估’流程并发执行; 将繁杂的装配逻辑封装在内部类ActionAssemblyHelper
# Conflicts:
#	Partner-Main/src/main/java/work/slhaf/partner/core/cache/CacheCapability.java
#	Partner-Main/src/main/java/work/slhaf/partner/core/memory/MemoryCore.java
#	Partner-Main/src/main/java/work/slhaf/partner/module/modules/memory/selector/MemorySelector.java
2025-10-16 15:39:16 +08:00
2d052442b1 推进 ActionPlanner: 添加行动短路机制,如果未提取到行动,则跳过评估子模块 2025-10-16 15:34:30 +08:00
84f7befb75 推进 ActionPlanner: 完成了 ActionPlanner 模块中的执行逻辑,同步调整了数据类中的字段。下一步将进行 ActionPlanner 子模块的开发。 2025-10-16 15:34:30 +08:00
85818556f8 将记忆模块的缓存逻辑迁移至 MemoryCore; 移除了 CacheCore,并将 CoordinatedManager 中原记忆模块与缓存模块中的逻辑迁移至现记忆模块中,确保语义正确 2025-10-16 15:22:19 +08:00
cb1a25e9d5 移除 ActiveData ,其逻辑回归至 CacheCore,下一步将对 CacheCore 及 CoordinateManager 中的 cognation 相关内容进行拆分 2025-10-16 11:40:55 +08:00
a10a149edb 开始推进行动模块(ActionModule); 针对框架与本体分别进行了一系列架构优化。
框架:
- 调整模块注册以及AgentRunningFlow的相关逻辑,以支持同组模块并发执行,将以@AgentModule注解中的order属性区分组间顺序先后及是否同组
- 针对@CoordinateManager注解新增了Core的自动注入处理,以便更好的协调不同Core的逻辑

本体: - 开始推进行动模块。将采取类似记忆模块的分层思路,分为ActionPlanner与ActionDispatcher两个主要模块,再各自细分子模块划分
- 将CognationCore从核心统筹的身份下降至与其他核心平级,同时将其中的序列化逻辑抽取至统一的PartnerCore父类,所有核心都将继承该类以获得序列化能力,不同core的内容将序列化至各自的memory文件
- 将SessionManager移除,相关逻辑迁移至CognationCore,统一序列化逻辑的同时又保证语义正确
- 将CognationCore中的某些缓存性质逻辑移动至CacheCore,确保语义正确
- 调整了目录结构以适应优化过的架构
2025-10-12 16:23:11 +08:00
41bf19f43e 将 .java 重命名为 .kt 2025-10-12 16:23:11 +08:00
941943f696 Partner 主体与框架适配完成! 完整逻辑已达到适配框架之前的完成度。发现并修复了不少问题,以及更新了README
框架:
- 由于`Gateway`的启动属于`Agent`启动流程的子线程,而主线程可能由于逻辑执行结束时机早于`Gateway`创建完成时机而报错,故引入`CountDownLatch`进行阻塞
- 在`AgentRunningModule`与`AgentRunningSubModule`中添加日志hook,记录模块执行的起始与截止时机
- 修复了`AgentUtil`中收集继承链时遗忘起始类的错误
- 在`CapabilityCheckFactory`中针对`CoordinateManager`无参构造方法的实现检验
- 在`CapabilityRegisterFactory`中添加了收集模块之外的CapabilityHolder的逻辑,与`@InjectCapability`的校验与注入逻辑保持一致
- 修复了‘生成模块启用配置时,多余局部变量导致无法执行流正确读取启用情况’的错误
- 在GlobalExceptionHandler中添加了对于未知异常的处理逻辑,确保不会导致程序异常终止
- 发现`ModuleProxyFactory`中使用`record`类型会导致`ByteBuddy`无法正确创建代理类,已修复,替换成普通类

本体:
- `ActiveData`由于`CognationCore`的引用,也需要实现序列化,已修复
- 修复了`MemorySelectExtractor`中由于匹配到的主题列表为空导致的空指针异常
- 将后置模块的trigger判定抽取到新的父类中,统一判断
- 修复了`WebSocketServer`如果存在过ws连接,关闭后短时间再次启动内仍提示端口占用的情况,设置允许端口重用
- 在`WebSocketGateway`新增了断开ws客户端连接的逻辑
2025-09-30 15:46:05 +08:00
a7d54349e4 进行 框架-主题 的适配测试,发现了一些问题并进行了修复
框架:
- 去除了 ActivateModel 中 modelKey() 方法的默认实现,对于特殊的 AgentModule 继承者(CoreModule)而言,直接获取注解信息不可行,如果保持,则需要另加判断逻辑。这是没有必要的
- 发现 Agent 启动流程中,由于 Gateway 的启动可能依赖配置文件的加载,故将 AgentConfigManager 与 AgentGateway 的指定替换为类型指定,在合适的时机通过反射进行实例化
- 在 AgentUtil 中新增了链式判断指定类的注解链上是否存在指定注解的方法,目前用于 CapabilityHolder 的持有实例判定
- 发现 CapabilityFactoryContext 中 cores、capabilities 未赋值导致空指针异常,已修复
- 将 AgentConfigManager 中的检验逻辑进行抽离,放到了 ConfigLoaderFactory 中,避免职责混淆
- 发现 CoreModule 的注解使用错误,`@Retention(RetentionPolicy.RUNTIME)`元注解可以使得注解在代码运行时能够被反射扫描
- 在 ModuleCheckFactory 中添加了对于 Module 与 SubModule 的注解、继承使用是否匹配的检验
- 发现对于一个类来说,无法直接通过一层反射获取到‘注解的注解’,故在 ModuleRegisterFactory 中针对 CoreModule 的注册做了特殊处理

主体:
- 发现一些类缺少必要注解,已修复
- 发现存在有些必要的类未公开化无参构造函数,已修复,并在框架部分增加校验逻辑

其他:
- 由于项目的启动流程与完整的配置文件密不可分,所以开始尝试编写启动说明,目前只写了开头
2025-09-21 23:29:45 +08:00
3c2ac32708 完成了本体与框架的适配工作,并修复了某些问题。需要进一步进行测试
- 修复了 CognationCapability 相关的注解使用错误
- 将前置模块中的 setAppendedPrompt 与 setActiveModule 方法抽取到 execute 模板方法中
- 完善了已有模块的适配工作, 并去除了不必要的单例配置
2025-09-18 16:03:59 +08:00
7f9d007f07 适配框架时发现工厂注册链上存在一些执行顺序上的错误,于是尝试修复问题,为Agent启动链添加了完整的注释,并做出了必要的修复与调整 2025-09-13 23:37:35 +08:00
c1018d6b54 进行 Partner 框架层的部分调整
- 新增 AgentSubModule 注解,用于标识子模块
- 新增 MetaSubModule 类,用于存储子模块元信息
- 支持子模块初始化和注入逻辑,不再使用单例模式为执行模块提供子模块服务
- 重构模块初始化流程,支持模块和子模块的初始化
- 优化模块注册流程,分别处理模块和子模块
2025-09-11 13:07:48 +08:00
47684c78e0 进行 Partner 本体对于框架的适配,以及框架层的部分调整
框架:

- 调整 ActivateModel 中模型初始化设置的 initHook 权重为-1(最优先)
- 为 AgentGateway 中 receive 操作提供模板方法,子类需实现发送逻辑并提供适配器
- 取消了 AgentInteractionAdapter 的单例配置
- 调整 RunningFlow 的异常处理,并在RunningFlowContext中提供错误码进行判断
- 调整模块基类
-

本体:
- 新增配置加载异常,继承自Agent启动异常
- 修改 GlobalExceptionData 获取逻辑
- 移除 MessageSender 等交互接口,适配框架的交互逻辑
- 异常处理已适配
- 配置加载逻辑已适配
- Gateway 已适配
- CoreModel 已适配
2025-09-09 20:42:28 +08:00
430 changed files with 25973 additions and 8186 deletions

16
.gitignore vendored
View File

@@ -8,6 +8,8 @@ target/
.idea/jarRepositories.xml .idea/jarRepositories.xml
.idea/compiler.xml .idea/compiler.xml
.idea/libraries/ .idea/libraries/
.idea/db-forest-config.xml
.idea/markdown.xml
*.iws *.iws
*.iml *.iml
*.ipr *.ipr
@@ -36,8 +38,8 @@ build/
### Mac OS ### ### Mac OS ###
.DS_Store .DS_Store
/data/ /backup/data/
/config/ /backup/config/
/Partner-Core/src/main/java/src/test/java/memory/test.json /Partner-Core/src/main/java/src/test/java/memory/test.json
/Partner-Core/src/main/java/src/test/java/memory/result/input1.json /Partner-Core/src/main/java/src/test/java/memory/result/input1.json
/Partner-Core/src/main/java/src/test/java/memory/result/input2.json /Partner-Core/src/main/java/src/test/java/memory/result/input2.json
@@ -51,3 +53,13 @@ build/
/backup/ /backup/
/Partner-Main/src/test/java/text/test.json /Partner-Main/src/test/java/text/test.json
/CLAUDE.md /CLAUDE.md
/config/
/data/
/generated-classes/
/.idea/copilot.data.migration.ask2agent.xml
/Partner-Main/data/
/AGENTS.md
/.serena/
/Partner-Core/data/
/.ai/mcp/mcp.json
/.codex

6
.idea/copilot.data.migration.agent.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AgentMigrationStateService">
<option name="migrationStatus" value="COMPLETED" />
</component>
</project>

6
.idea/copilot.data.migration.ask.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AskMigrationStateService">
<option name="migrationStatus" value="COMPLETED" />
</component>
</project>

6
.idea/copilot.data.migration.edit.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="EditMigrationStateService">
<option name="migrationStatus" value="COMPLETED" />
</component>
</project>

View File

@@ -1,6 +1,7 @@
<component name="ProjectDictionaryState"> <component name="ProjectDictionaryState">
<dictionary name="project"> <dictionary name="project">
<words> <words>
<w>openai</w>
<w>zuper</w> <w>zuper</w>
</words> </words>
</dictionary> </dictionary>

15
.idea/encodings.xml generated
View File

@@ -1,12 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="Encoding"> <component name="Encoding">
<file url="file://$PROJECT_DIR$/Partner-Api/src/main/java" charset="UTF-8" /> <file url="file://$PROJECT_DIR$/Partner-Common/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/Partner-Api/src/main/resources" charset="UTF-8" /> <file url="file://$PROJECT_DIR$/Partner-Common/src/main/resources" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/Partner-Main/src/main/java" charset="UTF-8" /> <file url="file://$PROJECT_DIR$/Partner-Core/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/Partner-Main/src/main/java/src/main/java" charset="UTF-8" /> <file url="file://$PROJECT_DIR$/Partner-Core/src/main/java/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/Partner-Main/src/main/java/src/main/resources" charset="UTF-8" /> <file url="file://$PROJECT_DIR$/Partner-Core/src/main/java/src/main/resources" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/Partner-Main/src/main/resources" charset="UTF-8" /> <file url="file://$PROJECT_DIR$/Partner-Core/src/main/resources" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/Partner-Framework/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/Partner-Framework/src/main/resources" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/Partner-SandboxRunner/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/Partner-Test-Demo/src/main/java" charset="UTF-8" /> <file url="file://$PROJECT_DIR$/Partner-Test-Demo/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/Partner-Test-Demo/src/main/resources" charset="UTF-8" /> <file url="file://$PROJECT_DIR$/Partner-Test-Demo/src/main/resources" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" /> <file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />

6
.idea/kotlinc.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="KotlinJpsPluginSettings">
<option name="version" value="2.2.0" />
</component>
</project>

40
.idea/misc.xml generated
View File

@@ -1,22 +1,48 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="EntryPointsManager"> <component name="EntryPointsManager">
<list size="6"> <list size="19">
<item index="0" class="java.lang.String" itemvalue="work.slhaf.partner.api.agent.factory.capability.annotation.Capability" /> <item index="0" class="java.lang.String" itemvalue="lombok.Data" />
<item index="1" class="java.lang.String" itemvalue="work.slhaf.partner.api.agent.factory.capability.annotation.CapabilityCore" /> <item index="1" class="java.lang.String" itemvalue="net.bytebuddy.implementation.bind.annotation.RuntimeType" />
<item index="2" class="java.lang.String" itemvalue="work.slhaf.partner.api.agent.factory.capability.annotation.CapabilityMethod" /> <item index="2" class="java.lang.String" itemvalue="work.slhaf.partner.api.agent.factory.capability.annotation.Capability" />
<item index="3" class="java.lang.String" itemvalue="work.slhaf.partner.api.capability.annotation.CapabilityMethod" /> <item index="3" class="java.lang.String" itemvalue="work.slhaf.partner.api.agent.factory.capability.annotation.CapabilityCore" />
<item index="4" class="java.lang.String" itemvalue="work.slhaf.partner.api.capability.annotation.CoordinateManager" /> <item index="4" class="java.lang.String" itemvalue="work.slhaf.partner.api.agent.factory.capability.annotation.CapabilityMethod" />
<item index="5" class="java.lang.String" itemvalue="work.slhaf.partner.api.register.capability.annotation.Capability" /> <item index="5" class="java.lang.String" itemvalue="work.slhaf.partner.api.agent.factory.capability.annotation.CoordinateManager" />
<item index="6" class="java.lang.String" itemvalue="work.slhaf.partner.api.agent.factory.capability.annotation.Coordinated" />
<item index="7" class="java.lang.String" itemvalue="work.slhaf.partner.api.agent.factory.component.annotation.Init" />
<item index="8" class="java.lang.String" itemvalue="work.slhaf.partner.api.agent.factory.module.annotation.AfterExecute" />
<item index="9" class="java.lang.String" itemvalue="work.slhaf.partner.api.agent.factory.module.annotation.AgentRunningModule" />
<item index="10" class="java.lang.String" itemvalue="work.slhaf.partner.api.agent.factory.module.annotation.AgentSubModule" />
<item index="11" class="java.lang.String" itemvalue="work.slhaf.partner.api.agent.factory.module.annotation.BeforeExecute" />
<item index="12" class="java.lang.String" itemvalue="work.slhaf.partner.api.agent.factory.module.annotation.Init" />
<item index="13" class="java.lang.String" itemvalue="work.slhaf.partner.api.capability.annotation.CapabilityMethod" />
<item index="14" class="java.lang.String" itemvalue="work.slhaf.partner.api.capability.annotation.CoordinateManager" />
<item index="15" class="java.lang.String" itemvalue="work.slhaf.partner.api.register.capability.annotation.Capability" />
<item index="16" class="java.lang.String" itemvalue="work.slhaf.partner.framework.agent.factory.capability.annotation.CapabilityCore" />
<item index="17" class="java.lang.String" itemvalue="work.slhaf.partner.framework.agent.factory.capability.annotation.CapabilityMethod" />
<item index="18" class="java.lang.String" itemvalue="work.slhaf.partner.framework.agent.factory.component.annotation.AgentComponent" />
</list> </list>
<writeAnnotations>
<writeAnnotation name="work.slhaf.partner.api.agent.factory.capability.annotation.InjectCapability" />
<writeAnnotation name="work.slhaf.partner.api.agent.factory.component.annotation.InjectModule" />
<writeAnnotation name="work.slhaf.partner.api.agent.factory.module.annotation.InjectModule" />
<writeAnnotation name="work.slhaf.partner.framework.agent.factory.capability.annotation.InjectCapability" />
<writeAnnotation name="work.slhaf.partner.framework.agent.factory.component.annotation.InjectModule" />
</writeAnnotations>
</component> </component>
<component name="ExternalStorageConfigurationManager" enabled="true" /> <component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="MavenProjectsManager"> <component name="MavenProjectsManager">
<option name="originalFiles"> <option name="originalFiles">
<list> <list>
<option value="$PROJECT_DIR$/pom.xml" /> <option value="$PROJECT_DIR$/pom.xml" />
<option value="$PROJECT_DIR$/PartnerExecutor/pom.xml" />
</list> </list>
</option> </option>
<option name="ignoredFiles">
<set>
<option value="$PROJECT_DIR$/Partner-Test-Demo/pom.xml" />
</set>
</option>
</component> </component>
<component name="PWA"> <component name="PWA">
<option name="enabled" value="true" /> <option name="enabled" value="true" />

View File

@@ -1,33 +0,0 @@
autoDetectedPackages:
- factory
- module
- work.slhaf
enableAutoDetect: true
entryDisplayConfig:
excludedPathPatterns: []
skipJsCss: true
funcDisplayConfig:
skipConstructors: false
skipFieldAccess: true
skipFieldChange: true
skipGetters: false
skipNonProjectPackages: false
skipPrivateMethods: false
skipSetters: false
ignoreSameClassCall: null
ignoreSamePackageCall: null
includedPackagePrefixes: null
includedParentClasses: null
maxColSize: 32
maxNumFirst: 12
maxNumFirstImportant: 1024
maxNumHash: 3
maxNumHashImportant: 256
maxObjectDepth: 4
maxStrSize: 4096
name: xcodemap-filter
openMainWindow: true
recordMode: manual
sourceDisplayConfig:
color: blue
startOnDebug: false

View File

@@ -1,74 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>work.slhaf</groupId>
<artifactId>Partner</artifactId>
<version>0.5.0</version>
</parent>
<artifactId>Partner-Api</artifactId>
<dependencies>
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>
<version>1.17.6</version>
</dependency>
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>0.10.2</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.36</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.13.2</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.17</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.5.17</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.18.0</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.36</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>2.0.56</version>
</dependency>
</dependencies>
<properties>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>

View File

@@ -1,114 +0,0 @@
package work.slhaf.partner.api.agent;
import work.slhaf.partner.api.agent.factory.AgentRegisterFactory;
import work.slhaf.partner.api.agent.runtime.config.AgentConfigManager;
import work.slhaf.partner.api.agent.runtime.exception.AgentExceptionCallback;
import work.slhaf.partner.api.agent.runtime.exception.AgentLaunchFailedException;
import work.slhaf.partner.api.agent.runtime.exception.GlobalExceptionHandler;
import work.slhaf.partner.api.agent.runtime.interaction.AgentGateway;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public final class Agent {
public static AgentGatewayStep newAgent(Class<?> clazz) {
if (clazz == null) {
throw new AgentLaunchFailedException("Agent class 和 interaction flow context 不能为 null");
}
return new AgentApp(clazz);
}
public interface AgentGatewayStep {
AgentStep setGateway(AgentGateway gateway);
}
public interface AgentStep {
AgentStep addBeforeLaunchRunners(Runnable... runners);
AgentStep addAfterLaunchRunners(Runnable... runners);
AgentStep setAgentConfigManager(AgentConfigManager agentConfigManager);
AgentStep setAgentExceptionCallback(AgentExceptionCallback agentExceptionCallback);
AgentStep addScanPackage(String packageName);
AgentStep addScanDir(String externalPackagePath);
void launch();
}
public static class AgentApp implements AgentStep, AgentGatewayStep {
private final ExecutorService executorService = Executors.newVirtualThreadPerTaskExecutor();
private final List<Runnable> beforeLaunchRunners = new ArrayList<>();
private final List<Runnable> afterLaunchRunners = new ArrayList<>();
private AgentGateway gateway;
private final Class<?> applicationClass;
private AgentApp(Class<?> clazz) {
this.applicationClass = clazz;
}
@Override
public AgentStep setGateway(AgentGateway gateway) {
this.gateway = gateway;
return this;
}
@Override
public AgentStep addBeforeLaunchRunners(Runnable... runners) {
this.beforeLaunchRunners.addAll(List.of(runners));
return this;
}
@Override
public AgentStep addAfterLaunchRunners(Runnable... runners) {
this.afterLaunchRunners.addAll(List.of(runners));
return this;
}
@Override
public AgentStep setAgentConfigManager(AgentConfigManager agentConfigManager) {
AgentConfigManager.setINSTANCE(agentConfigManager);
return this;
}
@Override
public AgentStep setAgentExceptionCallback(AgentExceptionCallback agentExceptionCallback) {
GlobalExceptionHandler.setExceptionCallback(agentExceptionCallback);
return this;
}
@Override
public AgentStep addScanPackage(String packageName) {
AgentRegisterFactory.addScanPackage(packageName);
return this;
}
@Override
public AgentStep addScanDir(String externalPackagePath) {
AgentRegisterFactory.addScanDir(externalPackagePath);
return this;
}
@Override
public void launch() {
launchRunners(beforeLaunchRunners);
AgentRegisterFactory.launch(applicationClass.getPackageName());
executorService.execute(() -> gateway.launch());
launchRunners(afterLaunchRunners);
}
private void launchRunners(List<Runnable> runners) {
for (Runnable runner : runners) {
executorService.execute(runner);
}
}
}
}

View File

@@ -1,21 +0,0 @@
package work.slhaf.partner.api.agent.factory;
import work.slhaf.partner.api.agent.factory.capability.exception.CapabilityFactoryExecuteFailedException;
import work.slhaf.partner.api.agent.factory.context.AgentRegisterContext;
import java.lang.reflect.InvocationTargetException;
public abstract class AgentBaseFactory {
public void execute(AgentRegisterContext context) {
try {
setVariables(context);
run();
} catch (Exception e) {
throw new CapabilityFactoryExecuteFailedException(e.getMessage(), e);
}
}
protected abstract void setVariables(AgentRegisterContext context);
protected abstract void run() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException;
}

View File

@@ -1,96 +0,0 @@
package work.slhaf.partner.api.agent.factory;
import cn.hutool.core.bean.BeanUtil;
import org.reflections.util.ClasspathHelper;
import work.slhaf.partner.api.agent.factory.capability.CapabilityCheckFactory;
import work.slhaf.partner.api.agent.factory.capability.CapabilityInjectFactory;
import work.slhaf.partner.api.agent.factory.capability.CapabilityRegisterFactory;
import work.slhaf.partner.api.agent.factory.config.ConfigLoaderFactory;
import work.slhaf.partner.api.agent.factory.context.AgentRegisterContext;
import work.slhaf.partner.api.agent.factory.exception.ExternalModuleLoadFailedException;
import work.slhaf.partner.api.agent.factory.exception.ExternalModulePathNotExistException;
import work.slhaf.partner.api.agent.factory.module.ModuleCheckFactory;
import work.slhaf.partner.api.agent.factory.module.ModuleInitHookExecuteFactory;
import work.slhaf.partner.api.agent.factory.module.ModuleProxyFactory;
import work.slhaf.partner.api.agent.factory.module.ModuleRegisterFactory;
import work.slhaf.partner.api.agent.factory.module.pojo.MetaModule;
import work.slhaf.partner.api.agent.runtime.data.AgentContext;
import work.slhaf.partner.api.agent.runtime.config.AgentConfigManager;
import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
public class AgentRegisterFactory {
private static final List<URL> urls = new ArrayList<>();
private AgentRegisterFactory() {
}
public static void launch(String packageName) {
urls.addAll(packageNameToURL(packageName));
AgentRegisterContext registerContext = new AgentRegisterContext(urls);
//流程
//0. 加载配置
new ConfigLoaderFactory().execute(registerContext);
//1. 注册并检查Capability
new CapabilityRegisterFactory().execute(registerContext);
new CapabilityCheckFactory().execute(registerContext);
//2. 注册并检查Module
new ModuleCheckFactory().execute(registerContext);
new ModuleRegisterFactory().execute(registerContext);
//3. 为module通过动态代理添加PostHook逻辑并进行实例化
new ModuleProxyFactory().execute(registerContext);
//. 先一步注入Capability,避免因前hook逻辑存在针对能力的引用而报错
new CapabilityInjectFactory().execute(registerContext);
//. 执行模块PreHook逻辑
new ModuleInitHookExecuteFactory().execute(registerContext);
List<MetaModule> moduleList = registerContext.getModuleFactoryContext().getModuleList();
AgentConfigManager.INSTANCE.moduleEnabledStatusFilterAndRecord(moduleList);
BeanUtil.copyProperties(registerContext, AgentContext.INSTANCE);
}
/**
* 添加可扫描包
*
* @param packageName 指定的包名
*/
public static void addScanPackage(String packageName) {
urls.addAll(packageNameToURL(packageName));
}
/**
* 添加外部模块目录
*
* @param externalPackagePath 指定的外部模块目录路径
*/
public static void addScanDir(String externalPackagePath) {
File file = new File(externalPackagePath);
if (!file.exists() || !file.isDirectory()) {
throw new ExternalModulePathNotExistException("不存在的外部模块目录: " + externalPackagePath);
}
try {
File[] files = file.listFiles();
if (files == null || files.length == 0) {
throw new ExternalModulePathNotExistException("外部模块目录为空: " + externalPackagePath);
}
for (File f : files) {
if (f.getName().endsWith(".jar")) {
urls.add(f.toURI().toURL());
}
}
} catch (Exception e) {
throw new ExternalModuleLoadFailedException("外部模块URL获取失败: " + externalPackagePath, e);
}
}
private static List<URL> packageNameToURL(String packageName) {
return ClasspathHelper.forPackage(packageName).stream().toList();
}
}

View File

@@ -1,220 +0,0 @@
package work.slhaf.partner.api.agent.factory.capability;
import org.reflections.Reflections;
import work.slhaf.partner.api.agent.factory.AgentBaseFactory;
import work.slhaf.partner.api.agent.factory.capability.annotation.*;
import work.slhaf.partner.api.agent.factory.capability.exception.DuplicateCapabilityException;
import work.slhaf.partner.api.agent.factory.capability.exception.UnMatchedCapabilityException;
import work.slhaf.partner.api.agent.factory.capability.exception.UnMatchedCapabilityMethodException;
import work.slhaf.partner.api.agent.factory.capability.exception.UnMatchedCoordinatedMethodException;
import work.slhaf.partner.api.agent.factory.context.AgentRegisterContext;
import work.slhaf.partner.api.agent.factory.context.CapabilityFactoryContext;
import work.slhaf.partner.api.agent.util.AgentUtil;
import java.lang.reflect.Method;
import java.util.*;
import java.util.stream.Collectors;
import static work.slhaf.partner.api.agent.util.AgentUtil.methodSignature;
/**
* 执行<code>Capability</code>相关检查
*/
public class CapabilityCheckFactory extends AgentBaseFactory {
private Reflections reflections;
private Set<Class<?>> cores;
private Set<Class<?>> capabilities;
@Override
protected void setVariables(AgentRegisterContext context) {
CapabilityFactoryContext factoryContext = context.getCapabilityFactoryContext();
reflections = context.getReflections();
cores = factoryContext.getCores();
capabilities = factoryContext.getCapabilities();
}
@Override
protected void run() {
checkCountAndCapabilities();
checkCapabilityMethods();
checkCoordinatedMethods();
checkInjectCapability();
}
/**
* 检查<code>@InjectCapability</code>注解是否只用在<code>@CapabilityHolder</code>所标识类的字段上
*/
private void checkInjectCapability() {
reflections.getFieldsAnnotatedWith(InjectCapability.class).forEach(field -> {
if (!field.getDeclaringClass().isAssignableFrom(CapabilityHolder.class)) {
throw new UnMatchedCapabilityException("InjectCapability 注解只能用于 CapabilityHolder 注解所在类");
}
});
}
/**
* 检查是否包含协调方法,如果存在,则进一步检查是否存在<code>@CoordinateManager</code>提供对应的实现
*/
private void checkCoordinatedMethods() {
//检查各个capability中是否含有ToCoordinated注解
//如果含有则需要查找AbstractCognationManager的子类,看这里是否有对应的Coordinated注解所在方法
Set<String> methodsToCoordinated = capabilities.stream()
.flatMap(capability -> Arrays.stream(capability.getDeclaredMethods()))
.filter(method -> method.isAnnotationPresent(ToCoordinated.class))
.map(method -> {
String capabilityValue = method.getDeclaringClass().getAnnotation(Capability.class).value();
return capabilityValue + "." + methodSignature(method);
})
.collect(Collectors.toSet());
if (!methodsToCoordinated.isEmpty()) {
Set<Class<?>> subTypesOfAbsCM = reflections.getTypesAnnotatedWith(CoordinateManager.class);
Set<String> methodsCoordinated = getMethodsCoordinated(subTypesOfAbsCM);
if (!methodsCoordinated.equals(methodsToCoordinated)) {
// 找出缺少的协调方法
Set<String> missingMethods = new HashSet<>(methodsToCoordinated);
missingMethods.removeAll(methodsCoordinated);
// 找出多余的协调方法
Set<String> extraMethods = new HashSet<>(methodsCoordinated);
extraMethods.removeAll(methodsToCoordinated);
// 抛出异常或记录错误
if (!missingMethods.isEmpty()) {
throw new UnMatchedCoordinatedMethodException("缺少协调方法: " + String.join(", ", missingMethods));
}
if (!extraMethods.isEmpty()) {
throw new UnMatchedCoordinatedMethodException("发现多余的协调方法: " + String.join(", ", extraMethods));
}
}
}
}
private Set<String> getMethodsCoordinated(Set<Class<?>> classes) {
Set<String> methodsCoordinated = new HashSet<>();
for (Class<?> cm : classes) {
Method[] methods = cm.getMethods();
for (Method method : methods) {
if (method.isAnnotationPresent(Coordinated.class)) {
methodsCoordinated.add(method.getAnnotation(Coordinated.class).capability() + "." + methodSignature(method));
}
}
}
return methodsCoordinated;
}
/**
* 查看在<code>Capability</code>在对应的<core>CapabilityCore</core>中存在尚未实现的方法
*/
private void checkCapabilityMethods() {
HashMap<String, List<Method>> capabilitiesMethods = getCapabilityMethods(capabilities);
StringBuilder sb = new StringBuilder();
for (Class<?> core : cores) {
List<Method> methodsWithAnnotation = Arrays.stream(core.getMethods())
.filter(method -> method.isAnnotationPresent(CapabilityMethod.class))
.toList();
List<Method> capabilityMethods = capabilitiesMethods.get(core.getAnnotation(CapabilityCore.class).value());
LackRecord lackRecord = checkMethodsMatched(methodsWithAnnotation, capabilityMethods);
if (lackRecord.hasNotEmptyRecord()) {
sb.append(lackRecord.toLackErrorMsg(core.getAnnotation(CapabilityCore.class).value()));
}
}
if (!sb.isEmpty()) {
throw new UnMatchedCapabilityMethodException(sb.toString());
}
}
private LackRecord checkMethodsMatched(List<Method> methodsWithAnnotation, List<Method> capabilityMethods) {
Set<String> collectedMethodsWithAnnotation = methodsWithAnnotation.stream()
.filter(method -> !method.isAnnotationPresent(ToCoordinated.class))
.map(AgentUtil::methodSignature)
.collect(Collectors.toSet());
Set<String> collectedCapabilityMethods = capabilityMethods.stream()
.filter(method -> !method.isAnnotationPresent(ToCoordinated.class))
.map(AgentUtil::methodSignature)
.collect(Collectors.toSet());
return checkMethodsMatched(collectedMethodsWithAnnotation, collectedCapabilityMethods);
}
private LackRecord checkMethodsMatched(Set<String> collectedMethodsWithAnnotation, Set<String> collectedCapabilityMethods) {
List<String> coreLack = new ArrayList<>();
List<String> capLack = new ArrayList<>();
// 找出 core 中多余的方法
for (String coreSig : collectedMethodsWithAnnotation) {
if (!collectedCapabilityMethods.contains(coreSig)) {
capLack.add(coreSig);
}
}
// 找出 capability 中多余的方法
for (String capSig : collectedCapabilityMethods) {
if (!collectedMethodsWithAnnotation.contains(capSig)) {
coreLack.add(capSig);
}
}
return new LackRecord(coreLack, capLack);
}
private HashMap<String, List<Method>> getCapabilityMethods(Set<Class<?>> capabilities) {
HashMap<String, List<Method>> capabilityMethods = new HashMap<>();
capabilities.forEach(capability -> {
capabilityMethods.put(capability.getAnnotation(Capability.class).value(), Arrays.stream(capability.getMethods()).toList());
});
return capabilityMethods;
}
/**
* 检查<code>Capability</code>和<code>CapabilityCore</code>的数量和标识是否匹配
*/
private void checkCountAndCapabilities() {
if (cores.size() != capabilities.size()) {
throw new UnMatchedCapabilityException("Capability 注册异常: 已存在的CapabilityCore与Capability数量不匹配!");
}
if (!checkValuesMatched(cores, capabilities)) {
throw new UnMatchedCapabilityException("Capability 注册异常: 已存在的CapabilityCore与Capability不匹配!");
}
}
private boolean checkValuesMatched(Set<Class<?>> cores, Set<Class<?>> capabilities) {
Set<String> coresValues = new HashSet<>();
Set<String> capabilitiesValues = new HashSet<>();
for (Class<?> core : cores) {
CapabilityCore annotation = core.getAnnotation(CapabilityCore.class);
if (annotation != null) {
if (coresValues.contains(annotation.value())) {
throw new DuplicateCapabilityException(String.format("Capability 注册异常: 重复的Capability核心: %s", annotation.value()));
}
coresValues.add(annotation.value());
}
}
for (Class<?> capability : capabilities) {
Capability annotation = capability.getAnnotation(Capability.class);
if (annotation != null) {
if (capabilitiesValues.contains(annotation.value())) {
throw new DuplicateCapabilityException(String.format("Capability 注册异常: 重复的Capability接口: %s", annotation.value()));
}
capabilitiesValues.add(annotation.value());
}
}
return coresValues.equals(capabilitiesValues);
}
record LackRecord(List<String> coreLack, List<String> capLack) {
public boolean hasNotEmptyRecord() {
return !coreLack.isEmpty() || !capLack.isEmpty();
}
public String toLackErrorMsg(String capabilityName) {
StringBuilder sb = new StringBuilder("\n").append(capabilityName).append("\n");
if (!coreLack.isEmpty()) {
sb.append("缺少Core方法:").append("\n").append(coreLack).append("\n");
}
if (!capLack.isEmpty()) {
sb.append("缺少Capability方法:").append("\n").append(capLack).append("\n");
}
return sb.toString();
}
}
}

View File

@@ -1,71 +0,0 @@
package work.slhaf.partner.api.agent.factory.capability;
import org.reflections.Reflections;
import work.slhaf.partner.api.agent.factory.AgentBaseFactory;
import work.slhaf.partner.api.agent.factory.capability.annotation.Capability;
import work.slhaf.partner.api.agent.factory.capability.annotation.InjectCapability;
import work.slhaf.partner.api.agent.factory.capability.annotation.ToCoordinated;
import work.slhaf.partner.api.agent.factory.capability.exception.ProxySetFailedExceptionCapability;
import work.slhaf.partner.api.agent.factory.context.AgentRegisterContext;
import work.slhaf.partner.api.agent.factory.context.CapabilityFactoryContext;
import java.lang.reflect.Field;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Set;
import java.util.function.Function;
import static work.slhaf.partner.api.agent.util.AgentUtil.methodSignature;
/**
* 负责执行<code>Capability</code>的注入逻辑
*/
public class CapabilityInjectFactory extends AgentBaseFactory {
private Reflections reflections;
private HashMap<String, Function<Object[], Object>> coordinatedMethodsRouterTable;
private HashMap<String, Function<Object[], Object>> methodsRouterTable;
private HashMap<Class<?>, Object> capabilityHolderInstances;
@Override
protected void setVariables(AgentRegisterContext context) {
CapabilityFactoryContext factoryContext = context.getCapabilityFactoryContext();
reflections = context.getReflections();
coordinatedMethodsRouterTable = factoryContext.getCoordinatedMethodsRouterTable();
methodsRouterTable = factoryContext.getMethodsRouterTable();
capabilityHolderInstances = factoryContext.getCapabilityHolderInstances();
}
@Override
protected void run() {
//获取现有的`@InjectCapability`注解所在字段,并获取对应的类,通过动态代理注入对象
Set<Field> fields = reflections.getFieldsAnnotatedWith(InjectCapability.class);
//在动态代理内部,通过函数路由表调用对应的方法
createProxy(fields);
}
private void createProxy(Set<Field> fields) {
try {
for (Field field : fields) {
field.setAccessible(true);
Class<?> fieldType = field.getType();
Object instance = Proxy.newProxyInstance(
fieldType.getClassLoader(),
new Class[]{fieldType},
(proxy, method, objects) -> {
if (method.isAnnotationPresent(ToCoordinated.class)) {
String key = method.getDeclaringClass().getAnnotation(Capability.class).value() + "." + methodSignature(method);
return coordinatedMethodsRouterTable.get(key).apply(objects);
}
String key = fieldType.getAnnotation(Capability.class).value() + "." + methodSignature(method);
return methodsRouterTable.get(key).apply(objects);
}
);
field.set(capabilityHolderInstances.get(field.getDeclaringClass()), instance);
}
} catch (Exception e) {
throw new ProxySetFailedExceptionCapability("代理设置失败", e);
}
}
}

View File

@@ -1,169 +0,0 @@
package work.slhaf.partner.api.agent.factory.capability;
import org.reflections.Reflections;
import work.slhaf.partner.api.agent.factory.AgentBaseFactory;
import work.slhaf.partner.api.agent.factory.capability.annotation.*;
import work.slhaf.partner.api.agent.factory.capability.exception.CapabilityFactoryExecuteFailedException;
import work.slhaf.partner.api.agent.factory.capability.exception.CoreInstancesCreateFailedExceptionCapability;
import work.slhaf.partner.api.agent.factory.capability.exception.DuplicateMethodException;
import work.slhaf.partner.api.agent.factory.context.AgentRegisterContext;
import work.slhaf.partner.api.agent.factory.context.CapabilityFactoryContext;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Set;
import java.util.function.Function;
import static cn.hutool.core.util.ClassUtil.isNormalClass;
import static work.slhaf.partner.api.agent.util.AgentUtil.methodSignature;
/**
* 负责获取<code>@Capability</code>和<code>@CapabilityCore</code>标识的类,并生成函数路由表、设置<code>Core</code>实例用于后续注入
*/
public final class CapabilityRegisterFactory extends AgentBaseFactory {
private Reflections reflections;
private HashMap<String, Function<Object[], Object>> methodsRouterTable;
private HashMap<String, Function<Object[], Object>> coordinatedMethodsRouterTable;
private HashMap<Class<?>, Object> capabilityCoreInstances;
private HashMap<Class<?>, Object> capabilityHolderInstances;
private Set<Class<?>> cores;
private Set<Class<?>> capabilities;
@Override
protected void setVariables(AgentRegisterContext context) {
CapabilityFactoryContext factoryContext = context.getCapabilityFactoryContext();
reflections = context.getReflections();
methodsRouterTable = factoryContext.getMethodsRouterTable();
coordinatedMethodsRouterTable = factoryContext.getCoordinatedMethodsRouterTable();
capabilityCoreInstances = factoryContext.getCapabilityCoreInstances();
cores = factoryContext.getCores();
capabilities = factoryContext.getCapabilities();
capabilityHolderInstances = factoryContext.getCapabilityHolderInstances();
}
@Override
protected void run() throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
setCapabilityCoreInstances();
setAnnotatedClasses();
generateRouterTable();
}
/**
* 设置<code>CapabilityCore</code>、<code>Capability</code>注解标识类
*/
private void setAnnotatedClasses() throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
cores.addAll(reflections.getTypesAnnotatedWith(CapabilityCore.class));
capabilities.addAll(reflections.getTypesAnnotatedWith(Capability.class));
setCapabilityHolderInstances();
}
private void setCapabilityHolderInstances() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
for (Class<?> clazz : reflections.getTypesAnnotatedWith(CapabilityHolder.class)) {
if (!isNormalClass(clazz)){
continue;
}
Object o = clazz.getDeclaredConstructor().newInstance();
capabilityHolderInstances.put(clazz, o);
}
}
/**
* 生成函数路由表
*/
private void generateRouterTable() {
generateMethodsRouterTable();
generateCoordinatedMethodsRouterTable();
}
/**
* 生成协调函数对应的函数路由表
*/
private void generateCoordinatedMethodsRouterTable() {
Set<Method> methodsAnnotatedWith = reflections.getMethodsAnnotatedWith(Coordinated.class);
if (methodsAnnotatedWith.isEmpty()) {
return;
}
try {
//获取所有CM实例
HashMap<String, Object> coordinateManagerInstances = getCoordinateManagerInstances();
methodsAnnotatedWith.forEach(method -> {
String key = method.getAnnotation(Coordinated.class).capability() + "." + methodSignature(method);
Function<Object[], Object> function = args -> {
try {
return method.invoke(coordinateManagerInstances.get(key), args);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
};
coordinatedMethodsRouterTable.put(key, function);
});
} catch (Exception e) {
throw new CapabilityFactoryExecuteFailedException("创建协调方法路由表出错", e);
}
}
/**
* 获取<code>CoordinateManager</code>子类实例
*/
private HashMap<String, Object> getCoordinateManagerInstances() throws InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException {
HashMap<String, Object> map = new HashMap<>();
for (Class<?> c : reflections.getTypesAnnotatedWith(CoordinateManager.class)) {
Constructor<?> constructor = c.getDeclaredConstructor();
Object instance = constructor.newInstance();
Arrays.stream(c.getMethods())
.filter(method -> method.isAnnotationPresent(Coordinated.class))
.forEach(method -> {
String key = method.getAnnotation(Coordinated.class).capability() + "." + methodSignature(method);
map.put(key, instance);
});
}
return map;
}
/**
* 生成普通方法对应的函数路由表
*/
private void generateMethodsRouterTable() {
//扫描`@Capability`与`@CapabilityMethod`注解的类与方法
//将`capabilityValue.methodSignature`作为key,函数对象为通过反射拿到的core实例对应的方法
cores.forEach(core -> Arrays.stream(core.getMethods())
.filter(method -> method.isAnnotationPresent(CapabilityMethod.class))
.forEach(method -> {
Function<Object[], Object> function = args -> {
try {
return method.invoke(capabilityCoreInstances.get(core), args);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
};
String key = core.getAnnotation(CapabilityCore.class).value() + "." + methodSignature(method);
if (methodsRouterTable.containsKey(key)) {
throw new DuplicateMethodException("重复注册能力方法: " + core.getPackage().getName() + "." + core.getSimpleName() + "#" + method.getName());
}
methodsRouterTable.put(key, function);
}));
}
/**
* 反射获取<code>CapabilityCore</code>实例
*/
private void setCapabilityCoreInstances() {
try {
for (Class<?> core : cores) {
Constructor<?> constructor = core.getDeclaredConstructor();
constructor.setAccessible(true);
capabilityCoreInstances.put(core, constructor.newInstance());
}
} catch (InvocationTargetException | NoSuchMethodException | InstantiationException |
IllegalAccessException e) {
throw new CoreInstancesCreateFailedExceptionCapability("core实例创建失败");
}
}
}

View File

@@ -1,11 +0,0 @@
package work.slhaf.partner.api.agent.factory.capability.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface CoordinateManager {
}

View File

@@ -1,15 +0,0 @@
package work.slhaf.partner.api.agent.factory.capability.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 用于标注协调方法,`value`值需与对应的`@ToCoordinated`保持一致
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Coordinated {
String capability();
}

View File

@@ -1,15 +0,0 @@
package work.slhaf.partner.api.agent.factory.capability.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 当`@Capability`所注接口中如果存在方法需要协调多个Core服务的调用可以通过该注解进行排除
* value值为方法对应标识需与协调实现处的方法标识保持一致
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ToCoordinated {
}

View File

@@ -1,13 +0,0 @@
package work.slhaf.partner.api.agent.factory.capability.exception;
import work.slhaf.partner.api.agent.runtime.exception.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,13 +0,0 @@
package work.slhaf.partner.api.agent.factory.capability.exception;
import work.slhaf.partner.api.agent.runtime.exception.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.api.agent.factory.capability.exception;
public class CoreInstancesCreateFailedExceptionCapability extends CapabilityFactoryExecuteFailedException {
public CoreInstancesCreateFailedExceptionCapability(String message) {
super(message);
}
public CoreInstancesCreateFailedExceptionCapability(String message, Throwable cause) {
super(message, cause);
}
}

View File

@@ -1,11 +0,0 @@
package work.slhaf.partner.api.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.api.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.api.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.api.agent.factory.capability.exception;
public class ProxySetFailedExceptionCapability extends CapabilityFactoryExecuteFailedException {
public ProxySetFailedExceptionCapability(String message) {
super(message);
}
public ProxySetFailedExceptionCapability(String message, Throwable cause) {
super(message, cause);
}
}

View File

@@ -1,11 +0,0 @@
package work.slhaf.partner.api.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.api.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.api.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,41 +0,0 @@
package work.slhaf.partner.api.agent.factory.config;
import work.slhaf.partner.api.agent.factory.AgentBaseFactory;
import work.slhaf.partner.api.agent.factory.config.pojo.ModelConfig;
import work.slhaf.partner.api.agent.factory.context.AgentRegisterContext;
import work.slhaf.partner.api.agent.factory.context.ConfigFactoryContext;
import work.slhaf.partner.api.agent.runtime.config.AgentConfigManager;
import work.slhaf.partner.api.agent.runtime.config.DefaultAgentConfigManager;
import work.slhaf.partner.api.chat.pojo.Message;
import java.util.HashMap;
import java.util.List;
public class ConfigLoaderFactory extends AgentBaseFactory {
private AgentConfigManager agentConfigManager;
private HashMap<String, ModelConfig> modelConfigMap;
private HashMap<String, List<Message>> modelPromptMap;
@Override
protected void setVariables(AgentRegisterContext context) {
ConfigFactoryContext factoryContext = context.getConfigFactoryContext();
modelConfigMap = factoryContext.getModelConfigMap();
modelPromptMap = factoryContext.getModelPromptMap();
if (AgentConfigManager.INSTANCE == null){
AgentConfigManager.setINSTANCE(new DefaultAgentConfigManager());
}
agentConfigManager = AgentConfigManager.INSTANCE;
}
@Override
protected void run() {
agentConfigManager.load();
agentConfigManager.check();
modelConfigMap.putAll(agentConfigManager.getModelConfigMap());
modelPromptMap.putAll(agentConfigManager.getModelPromptMap());
}
}

View File

@@ -1,11 +0,0 @@
package work.slhaf.partner.api.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.api.agent.factory.config.exception;
import work.slhaf.partner.api.agent.runtime.exception.AgentLaunchFailedException;
public class ConfigFactoryInitFailedException extends AgentLaunchFailedException {
public ConfigFactoryInitFailedException(String message, Throwable cause) {
super("AgentConfigManager 执行失败: " + message, cause);
}
public ConfigFactoryInitFailedException(String message) {
super("AgentConfigManager 执行失败: " + message);
}
}

View File

@@ -1,13 +0,0 @@
package work.slhaf.partner.api.agent.factory.config.exception;
import work.slhaf.partner.api.agent.runtime.exception.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.api.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.api.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.api.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.api.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.api.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

@@ -1,10 +0,0 @@
package work.slhaf.partner.api.agent.factory.config.pojo;
import lombok.Data;
@Data
public class ModelConfig {
private String baseUrl;
private String apikey;
private String model;
}

View File

@@ -1,9 +0,0 @@
package work.slhaf.partner.api.agent.factory.config.pojo;
import lombok.Data;
@Data
public class PrimaryModelConfig {
private String key;
private ModelConfig modelConfig;
}

View File

@@ -1,12 +0,0 @@
package work.slhaf.partner.api.agent.factory.config.pojo;
import lombok.Data;
import work.slhaf.partner.api.chat.pojo.Message;
import java.util.List;
@Data
public class PrimaryModelPrompt {
private String key;
private List<Message> messages;
}

View File

@@ -1,28 +0,0 @@
package work.slhaf.partner.api.agent.factory.context;
import lombok.Data;
import org.reflections.Reflections;
import org.reflections.scanners.Scanners;
import org.reflections.util.ConfigurationBuilder;
import java.net.URL;
import java.util.List;
@Data
public class AgentRegisterContext {
private Reflections reflections;
private CapabilityFactoryContext capabilityFactoryContext = new CapabilityFactoryContext();
private ConfigFactoryContext configFactoryContext = new ConfigFactoryContext();
private ModuleFactoryContext moduleFactoryContext = new ModuleFactoryContext();
public AgentRegisterContext(List<URL> urls) {
reflections = new Reflections(new ConfigurationBuilder().setScanners(
Scanners.FieldsAnnotated,
Scanners.SubTypes,
Scanners.MethodsAnnotated,
Scanners.TypesAnnotated
)
.setUrls(urls)
);
}
}

View File

@@ -1,17 +0,0 @@
package work.slhaf.partner.api.agent.factory.context;
import lombok.Data;
import java.util.HashMap;
import java.util.Set;
import java.util.function.Function;
@Data
public class CapabilityFactoryContext {
private final HashMap<String, Function<Object[], Object>> methodsRouterTable = new HashMap<>();
private final HashMap<String, Function<Object[], Object>> coordinatedMethodsRouterTable = new HashMap<>();
private final HashMap<Class<?>, Object> capabilityCoreInstances = new HashMap<>();
private final HashMap<Class<?>, Object> capabilityHolderInstances = new HashMap<>();
private Set<Class<?>> cores;
private Set<Class<?>> capabilities;
}

View File

@@ -1,14 +0,0 @@
package work.slhaf.partner.api.agent.factory.context;
import lombok.Data;
import work.slhaf.partner.api.agent.factory.config.pojo.ModelConfig;
import work.slhaf.partner.api.chat.pojo.Message;
import java.util.HashMap;
import java.util.List;
@Data
public class ConfigFactoryContext {
private HashMap<String, List<Message>> modelPromptMap = new HashMap<>();
private HashMap<String, ModelConfig> modelConfigMap = new HashMap<>();
}

View File

@@ -1,12 +0,0 @@
package work.slhaf.partner.api.agent.factory.context;
import lombok.Data;
import work.slhaf.partner.api.agent.factory.module.pojo.MetaModule;
import java.util.ArrayList;
import java.util.List;
@Data
public class ModuleFactoryContext {
private List<MetaModule> moduleList = new ArrayList<>();
}

View File

@@ -1,11 +0,0 @@
package work.slhaf.partner.api.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.api.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

@@ -1,11 +0,0 @@
package work.slhaf.partner.api.agent.factory.exception;
public class ExternalModulePathNotExistException extends AgentRegisterFactoryFailedException {
public ExternalModulePathNotExistException(String message) {
super(message);
}
public ExternalModulePathNotExistException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@@ -1,143 +0,0 @@
package work.slhaf.partner.api.agent.factory.module;
import cn.hutool.core.util.ClassUtil;
import org.reflections.Reflections;
import work.slhaf.partner.api.agent.factory.AgentBaseFactory;
import work.slhaf.partner.api.agent.factory.context.AgentRegisterContext;
import work.slhaf.partner.api.agent.factory.module.annotation.AfterExecute;
import work.slhaf.partner.api.agent.factory.module.annotation.AgentModule;
import work.slhaf.partner.api.agent.factory.module.annotation.BeforeExecute;
import work.slhaf.partner.api.agent.factory.module.annotation.Init;
import work.slhaf.partner.api.agent.factory.module.exception.ModuleCheckException;
import work.slhaf.partner.api.agent.runtime.config.AgentConfigManager;
import work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts.ActivateModel;
import work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts.AgentRunningModule;
import work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts.AgentRunningSubModule;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;
public class ModuleCheckFactory extends AgentBaseFactory {
private Reflections reflections;
@Override
protected void setVariables(AgentRegisterContext context) {
reflections = context.getReflections();
}
@Override
protected void run() {
Set<Class<?>> types = reflections.getTypesAnnotatedWith(AgentModule.class);
//检查注解AgentModule所在类是否继承了AgentInteractionModule
agentModuleAnnotationCheck(types);
//检查AgentModule是否具备无参构造方法
moduleConstructorsCheck(types);
//检查hook注解所在方法是否位于AgentInteractionModule子类/AgentInteractionSubModule子类/ActivateModel子类
hookLocationCheck();
//检查实现了ActivateModel的模块数量、名称与prompt是否一致
activateModelImplCheck();
}
private void moduleConstructorsCheck(Set<Class<?>> types) {
for (Class<?> type : types) {
try {
type.getConstructor();
} catch (NoSuchMethodException e) {
throw new ModuleCheckException("缺少无参构造方法的模块: " + type.getSimpleName(), e);
}
}
}
private void activateModelImplCheck() {
try {
Set<Class<? extends ActivateModel>> types = reflections.getSubTypesOf(ActivateModel.class);
Set<String> modelKeySet = new HashSet<>();
for (Class<? extends ActivateModel> type : types) {
ActivateModel instance = type.getConstructor().newInstance();
modelKeySet.add(instance.modelKey());
}
Set<String> promptKeySet = AgentConfigManager.INSTANCE.getModelPromptMap().keySet();
if (!promptKeySet.containsAll(modelKeySet)) {
modelKeySet.removeAll(promptKeySet);
throw new ModuleCheckException("存在未配置Prompt的ActivateModel实现! 缺少Prompt的ModelKey列表: " + modelKeySet);
}
} catch (Exception e) {
throw new ModuleCheckException("ActivateModel 检测出错", e);
}
}
private void hookLocationCheck() {
//检查@AfterExecute注解
postHookLocationCheck();
//检查@BeforeExecute注解
preHookLocationCheck();
//检查@Init注解
initHookLocationCheck();
//检查@AgentModule注解是否只位于普通类上
agentModuleLocationCheck();
}
private void agentModuleLocationCheck() {
Set<Class<?>> types = reflections.getTypesAnnotatedWith(AgentModule.class);
for (Class<?> type : types) {
if (!ClassUtil.isNormalClass(type)) {
throw new ModuleCheckException("AgentModule 注解仅能位于普通类上! 异常类信息: " + type.getSimpleName());
}
}
}
private void initHookLocationCheck() {
Set<Method> methods = reflections.getMethodsAnnotatedWith(Init.class);
Set<Class<?>> types = methods.stream()
.map(Method::getDeclaringClass)
.collect(Collectors.toSet());
checkLocation(types);
}
private void preHookLocationCheck() {
Set<Method> methods = reflections.getMethodsAnnotatedWith(BeforeExecute.class);
Set<Class<?>> types = methods.stream()
.map(Method::getDeclaringClass)
.collect(Collectors.toSet());
checkLocation(types);
}
private void postHookLocationCheck() {
Set<Method> methods = reflections.getMethodsAnnotatedWith(AfterExecute.class);
Set<Class<?>> types = methods.stream()
.map(Method::getDeclaringClass)
.collect(Collectors.toSet());
checkLocation(types);
}
private void checkLocation(Set<Class<?>> types) {
for (Class<?> type : types) {
if (AgentRunningModule.class.isAssignableFrom(type)) {
continue;
}
if (AgentRunningSubModule.class.isAssignableFrom(type)) {
continue;
}
if (ActivateModel.class.isAssignableFrom(type)) {
continue;
}
throw new ModuleCheckException("在不支持的类中使用了hook注解: " + type.getSimpleName());
}
}
private void agentModuleAnnotationCheck(Set<Class<?>> types) {
for (Class<?> type : types) {
if (type.isAnnotation()) {
continue;
}
if (AgentRunningModule.class.isAssignableFrom(type) && ClassUtil.isNormalClass(type)) {
continue;
}
throw new ModuleCheckException("存在未继承AgentInteractionModule.class的AgentModule实现: " + type.getSimpleName());
}
}
}

View File

@@ -1,69 +0,0 @@
package work.slhaf.partner.api.agent.factory.module;
import work.slhaf.partner.api.agent.factory.AgentBaseFactory;
import work.slhaf.partner.api.agent.factory.context.AgentRegisterContext;
import work.slhaf.partner.api.agent.factory.context.ModuleFactoryContext;
import work.slhaf.partner.api.agent.factory.module.annotation.Init;
import work.slhaf.partner.api.agent.factory.module.exception.ModuleInitHookExecuteFailedException;
import work.slhaf.partner.api.agent.factory.module.pojo.MetaMethod;
import work.slhaf.partner.api.agent.factory.module.pojo.MetaModule;
import work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts.AgentRunningModule;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import static work.slhaf.partner.api.agent.util.AgentUtil.collectExtendedClasses;
import static work.slhaf.partner.api.agent.util.AgentUtil.methodSignature;
/**
* 负责执行前hook逻辑
*/
public class ModuleInitHookExecuteFactory extends AgentBaseFactory {
private List<MetaModule> moduleList;
@Override
protected void setVariables(AgentRegisterContext context) {
ModuleFactoryContext factoryContext = context.getModuleFactoryContext();
moduleList = factoryContext.getModuleList();
}
@Override
protected void run() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
//遍历模块列表,并向上查找@Init注解
for (MetaModule metaModule : moduleList) {
List<MetaMethod> initHookMethods = collectInitHookMethods(metaModule.getClazz());
proceedInitMethods(metaModule, initHookMethods);
}
}
private void proceedInitMethods(MetaModule metaModule, List<MetaMethod> initHookMethods) {
for (MetaMethod metaMethod : initHookMethods) {
try {
metaMethod.getMethod().invoke(metaModule.getInstance());
} catch (IllegalAccessException | InvocationTargetException e) {
throw new ModuleInitHookExecuteFailedException("模块的init hook方法执行失败! 模块: " + metaModule.getName() + " 方法签名: " + methodSignature(metaMethod.getMethod()), e);
}
}
}
private List<MetaMethod> collectInitHookMethods(Class<?> clazz) {
Set<Class<?>> classes = collectExtendedClasses(clazz, AgentRunningModule.class);
return classes.stream()
.map(Class::getDeclaredMethods)
.flatMap(Arrays::stream)
.filter(method -> method.isAnnotationPresent(Init.class))
.map(method -> {
MetaMethod metaMethod = new MetaMethod();
metaMethod.setMethod(method);
metaMethod.setOrder(method.getAnnotation(Init.class).order());
return metaMethod;
})
.sorted(Comparator.comparing(MetaMethod::getOrder))
.collect(Collectors.toList());
}
}

View File

@@ -1,169 +0,0 @@
package work.slhaf.partner.api.agent.factory.module;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.implementation.bind.annotation.*;
import net.bytebuddy.matcher.ElementMatchers;
import work.slhaf.partner.api.agent.factory.AgentBaseFactory;
import work.slhaf.partner.api.agent.factory.context.AgentRegisterContext;
import work.slhaf.partner.api.agent.factory.context.ModuleFactoryContext;
import work.slhaf.partner.api.agent.factory.module.annotation.AfterExecute;
import work.slhaf.partner.api.agent.factory.module.annotation.BeforeExecute;
import work.slhaf.partner.api.agent.factory.module.exception.ModuleInstanceGenerateFailedException;
import work.slhaf.partner.api.agent.factory.module.exception.ModuleProxyGenerateFailedException;
import work.slhaf.partner.api.agent.factory.module.pojo.MetaMethod;
import work.slhaf.partner.api.agent.factory.module.pojo.MetaModule;
import work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts.AgentRunningModule;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.stream.Collectors;
import static work.slhaf.partner.api.agent.util.AgentUtil.collectExtendedClasses;
/**
* 通过扫描注解<code>@BeforeExecute</code>获取到各个模块的后hook逻辑并通过动态代理添加到执行逻辑之后
*/
public class ModuleProxyFactory extends AgentBaseFactory {
private List<MetaModule> moduleList;
@Override
protected void setVariables(AgentRegisterContext context) {
ModuleFactoryContext factoryContext = context.getModuleFactoryContext();
moduleList = factoryContext.getModuleList();
}
@Override
protected void run() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
generateInstances();
setHookProxy();
}
private void setHookProxy() {
for (MetaModule module : moduleList) {
Class<?> clazz = module.getClazz();
try {
MethodsListRecord record = collectHookMethods(clazz);
//生成实例
generateProxiedInstances(record, module);
} catch (Exception e) {
throw new ModuleProxyGenerateFailedException("创建代理对象失败: " + clazz.getSimpleName(), e);
}
}
}
private void generateProxiedInstances(MethodsListRecord record, MetaModule metaModule) {
try {
Class<? extends AgentRunningModule> clazz = metaModule.getClazz();
Class<? extends AgentRunningModule> proxyClass = new ByteBuddy()
.subclass(clazz)
.method(ElementMatchers.isOverriddenFrom(AgentRunningModule.class))
.intercept(MethodDelegation.to(new ModuleProxyInterceptor(record.post, record.pre)))
.make()
.load(ModuleProxyFactory.class.getClassLoader())
.getLoaded();
metaModule.setInstance(proxyClass.getConstructor().newInstance());
} catch (Exception e) {
throw new ModuleProxyGenerateFailedException("模块Hook代理生成失败! 代理失败的模块名: " + metaModule.getClazz().getSimpleName(), e);
}
}
private MethodsListRecord collectHookMethods(Class<?> clazz) {
List<MetaMethod> post = new ArrayList<>();
List<MetaMethod> pre = new ArrayList<>();
//获取该类本身的hook逻辑
collectHookMethods(post, pre, clazz);
//获取它所继承、实现的抽象类或接口, 以AgentInteractionModule、ActiveModel为终点
Set<Class<?>> classes = collectExtendedClasses(clazz, AgentRunningModule.class);
//获取这些类中的hook逻辑
collectHookMethods(post, pre, classes);
return new MethodsListRecord(post, pre);
}
private void collectHookMethods(List<MetaMethod> post, List<MetaMethod> pre, Set<Class<?>> classes) {
for (Class<?> type : classes) {
collectPreHookMethods(pre, type);
collectPostHookMethods(post, type);
}
}
private void collectPostHookMethods(List<MetaMethod> post, Class<?> type) {
Set<MetaMethod> collectedPostHookMethod = Arrays.stream(type.getDeclaredMethods())
.filter(method -> method.isAnnotationPresent(AfterExecute.class))
.map(method -> {
MetaMethod metaMethod = new MetaMethod();
metaMethod.setMethod(method);
metaMethod.setOrder(method.getAnnotation(AfterExecute.class).order());
return metaMethod;
})
.collect(Collectors.toSet());
post.addAll(collectedPostHookMethod);
}
private void collectPreHookMethods(List<MetaMethod> pre, Class<?> type) {
Set<MetaMethod> collectedPreHookMethods = Arrays.stream(type.getDeclaredMethods())
.filter(method -> method.isAnnotationPresent(BeforeExecute.class))
.map(method -> {
MetaMethod metaMethod = new MetaMethod();
metaMethod.setMethod(method);
metaMethod.setOrder(method.getAnnotation(BeforeExecute.class).order());
return metaMethod;
})
.collect(Collectors.toSet());
pre.addAll(collectedPreHookMethods);
}
private void collectHookMethods(List<MetaMethod> post, List<MetaMethod> pre, Class<?> clazz) {
Method[] methods = clazz.getMethods();
for (Method method : methods) {
if (method.isAnnotationPresent(BeforeExecute.class)) {
MetaMethod metaMethod = new MetaMethod();
metaMethod.setOrder(method.getAnnotation(BeforeExecute.class).order());
pre.add(metaMethod);
metaMethod.setMethod(method);
} else if (method.isAnnotationPresent(AfterExecute.class)) {
MetaMethod metaMethod = new MetaMethod();
metaMethod.setOrder(method.getAnnotation(AfterExecute.class).order());
post.add(metaMethod);
metaMethod.setMethod(method);
}
}
}
private void generateInstances() {
for (MetaModule metaModule : moduleList) {
try {
Class<? extends AgentRunningModule> clazz = metaModule.getClazz();
AgentRunningModule instance = clazz.getConstructor().newInstance();
metaModule.setInstance(instance);
} catch (Exception e) {
throw new ModuleInstanceGenerateFailedException("模块实例构造失败:" + e.getMessage());
}
}
}
private record ModuleProxyInterceptor(List<MetaMethod> postHookMethods, List<MetaMethod> preHookMethods) {
@RuntimeType
public Object intercept(@Origin Method method, @AllArguments Object[] allArguments, @SuperCall Callable<?> zuper, @This Object proxy) throws Exception {
for (MetaMethod metaMethod : preHookMethods) {
metaMethod.getMethod().invoke(proxy);
}
Object res = zuper.call();
for (MetaMethod metaMethod : postHookMethods) {
metaMethod.getMethod().invoke(proxy);
}
return res;
}
}
record MethodsListRecord(List<MetaMethod> post, List<MetaMethod> pre) {
public MethodsListRecord {
post.sort(Comparator.comparingInt(MetaMethod::getOrder));
pre.sort(Comparator.comparingInt(MetaMethod::getOrder));
}
}
}

View File

@@ -1,53 +0,0 @@
package work.slhaf.partner.api.agent.factory.module;
import cn.hutool.core.util.ClassUtil;
import org.reflections.Reflections;
import work.slhaf.partner.api.agent.factory.AgentBaseFactory;
import work.slhaf.partner.api.agent.factory.context.AgentRegisterContext;
import work.slhaf.partner.api.agent.factory.context.ModuleFactoryContext;
import work.slhaf.partner.api.agent.factory.module.annotation.AgentModule;
import work.slhaf.partner.api.agent.factory.module.pojo.MetaModule;
import work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts.AgentRunningModule;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
/**
* 负责扫描<code>@Module</code>注解获取模块实例
*/
public class ModuleRegisterFactory extends AgentBaseFactory {
private Reflections reflections;
private List<MetaModule> moduleList;
@Override
protected void setVariables(AgentRegisterContext context) {
ModuleFactoryContext factoryContext = context.getModuleFactoryContext();
reflections = context.getReflections();
moduleList = factoryContext.getModuleList();
}
@Override
protected void run() {
setModuleList();
}
private void setModuleList() {
//反射扫描获取@AgentModule所在类, 该部分为Agent流程执行模块
Set<Class<?>> modules = reflections.getTypesAnnotatedWith(AgentModule.class);
for (Class<?> module : modules) {
if (!ClassUtil.isNormalClass(module)) {
continue;
}
Class<? extends AgentRunningModule> clazz = module.asSubclass(AgentRunningModule.class);
AgentModule agentModule = clazz.getAnnotation(AgentModule.class);
MetaModule metaModule = new MetaModule();
metaModule.setName(agentModule.name());
metaModule.setOrder(agentModule.order());
metaModule.setClazz(clazz);
moduleList.add(metaModule);
}
moduleList.sort(Comparator.comparing(MetaModule::getOrder));
}
}

View File

@@ -1,20 +0,0 @@
package work.slhaf.partner.api.agent.factory.module.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 仅适用于以下类中的方法:
* 1. <code>@AgentModule</code>注解所在类
* 2. <code>ActivateModel</code>子类
* 3. <code>AgentRunningModule</code>或者<code>AgentRunningSubModule</code>子类
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AfterExecute {
int order() default 0;
}

View File

@@ -1,23 +0,0 @@
package work.slhaf.partner.api.agent.factory.module.annotation;
import java.lang.annotation.*;
/**
* 用于注解执行模块
*/
@Inherited
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface AgentModule {
/**
* 模块名称
*/
String name();
/**
* 模块执行顺序,数字越小执行越靠前
*/
int order();
}

View File

@@ -1,18 +0,0 @@
package work.slhaf.partner.api.agent.factory.module.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 仅适用于以下类中的方法:
* 1. <code>@AgentModule</code>注解所在类
* 2. <code>ActivateModel</code>子类
* 3. <code>AgentRunningModule</code>或者<code>AgentRunningSubModule</code>子类
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface BeforeExecute {
int order() default 0;
}

View File

@@ -1,5 +0,0 @@
package work.slhaf.partner.api.agent.factory.module.annotation;
@AgentModule(name = "core",order = 5)
public @interface CoreModule {
}

View File

@@ -1,11 +0,0 @@
package work.slhaf.partner.api.agent.factory.module.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.api.agent.factory.module.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.api.agent.factory.module.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.api.agent.factory.module.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.api.agent.factory.module.exception;
public class ModuleProxyGenerateFailedException extends ModuleFactoryInitFailedException {
public ModuleProxyGenerateFailedException(String message) {
super(message);
}
public ModuleProxyGenerateFailedException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@@ -1,11 +0,0 @@
package work.slhaf.partner.api.agent.factory.module.pojo;
import lombok.Data;
import java.lang.reflect.Method;
@Data
public class MetaMethod {
private int order;
private Method method;
}

View File

@@ -1,13 +0,0 @@
package work.slhaf.partner.api.agent.factory.module.pojo;
import lombok.Data;
import work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts.AgentRunningModule;
@Data
public class MetaModule {
private String name;
private int order;
private Class<? extends AgentRunningModule> clazz;
private AgentRunningModule instance;
private boolean enabled = true;
}

View File

@@ -1,119 +0,0 @@
package work.slhaf.partner.api.agent.runtime.config;
import lombok.Data;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import work.slhaf.partner.api.agent.factory.config.exception.ConfigNotExistException;
import work.slhaf.partner.api.agent.factory.config.exception.ConfigUpdateFailedException;
import work.slhaf.partner.api.agent.factory.config.exception.PromptNotExistException;
import work.slhaf.partner.api.agent.factory.config.pojo.ModelConfig;
import work.slhaf.partner.api.agent.factory.module.pojo.MetaModule;
import work.slhaf.partner.api.chat.pojo.Message;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@Slf4j
@Data
public abstract class AgentConfigManager {
@Setter
public static AgentConfigManager INSTANCE;
private static final String DEFAULT_KEY = "default";
protected HashMap<String, ModelConfig> modelConfigMap;
protected HashMap<String, List<Message>> modelPromptMap;
protected HashMap<String, Boolean> moduleEnabledStatus;
protected List<MetaModule> moduleList;
public void load() {
modelConfigMap = loadModelConfig();
modelPromptMap = loadModelPrompt();
}
protected abstract HashMap<String, List<Message>> loadModelPrompt();
protected abstract HashMap<String, ModelConfig> loadModelConfig();
public abstract void dumpModelConfig(String key);
protected abstract void dumpModuleEnabledStatus();
protected abstract HashMap<String, Boolean> loadModuleEnabledStatusMap();
public void moduleEnabledStatusFilterAndRecord(List<MetaModule> moduleList) {
this.moduleList = moduleList;
this.moduleEnabledStatus = loadModuleEnabledStatusMap();
boolean unmatch = false;
for (MetaModule metaModule : moduleList) {
String moduleName = metaModule.getName();
if (moduleEnabledStatus.containsKey(moduleName)) {
metaModule.setEnabled(moduleEnabledStatus.get(moduleName));
} else {
log.warn("缺少Module {} 启用配置! 将触发更新操作!", moduleName);
unmatch = true;
}
}
if (unmatch) {
dumpModuleEnabledStatus();
}
}
/**
* 对模型Config与Prompt分别进行检验,除了都必须包含default外还需要确保数量、key一致毕竟是模型配置与提示词
*/
public void check() {
log.info("[AgentConfigManager]: 执行config与prompt检测...");
if (!modelConfigMap.containsKey("default")) {
throw new ConfigNotExistException("缺少默认配置! 需确保存在一个模型配置的key为`default`");
}
if (!modelPromptMap.containsKey("basic")) {
throw new PromptNotExistException("缺少基础Prompt! 需要确保存在key为basic的Prompt文件它将与其他Prompt共同作用于模块节点。");
}
Set<String> configKeySet = new HashSet<>(modelConfigMap.keySet());
configKeySet.remove("default");
Set<String> promptKeySet = new HashSet<>(modelPromptMap.keySet());
promptKeySet.remove("basic");
if (!promptKeySet.containsAll(configKeySet)) {
log.warn("存在未被提示词包含的模型配置,该配置将无法生效!");
}
log.info("[AgentConfigManager]: 检测完毕.");
}
public List<Message> loadModelPrompt(String modelKey) {
if (!modelPromptMap.containsKey(modelKey)) {
throw new PromptNotExistException("不存在的modelPrompt: " + modelKey);
}
return modelPromptMap.get(modelKey);
}
public ModelConfig loadModelConfig(String modelKey) {
if (!modelConfigMap.containsKey(modelKey)) {
return modelConfigMap.get(DEFAULT_KEY);
}
return modelConfigMap.get(modelKey);
}
public void updateModelConfig(String modelKey, ModelConfig config) {
modelConfigMap.put(modelKey, config);
dumpModelConfig(modelKey);
}
public void updateModuleEnabledStatus(String key, boolean status) {
if (!moduleEnabledStatus.containsKey(key)) {
throw new ConfigUpdateFailedException("模块状态更新失败! 不存在的ModuleKey: " + key);
}
moduleEnabledStatus.put(key, status);
dumpModuleEnabledStatus();
for (MetaModule metaModule : moduleList) {
if (metaModule.getName().equals(key)) {
metaModule.setEnabled(status);
break;
}
}
}
}

View File

@@ -1,122 +0,0 @@
package work.slhaf.partner.api.agent.runtime.config;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import work.slhaf.partner.api.agent.factory.config.exception.*;
import work.slhaf.partner.api.agent.factory.config.pojo.ModelConfig;
import work.slhaf.partner.api.agent.factory.config.pojo.PrimaryModelConfig;
import work.slhaf.partner.api.agent.factory.config.pojo.PrimaryModelPrompt;
import work.slhaf.partner.api.agent.factory.module.pojo.MetaModule;
import work.slhaf.partner.api.chat.pojo.Message;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
/**
* 默认配置工厂
* 将从当前运行目录的config文件夹下创建并读取配置
*/
@Slf4j
public class DefaultAgentConfigManager extends AgentConfigManager {
private static final String CONFIG_DIR = "./config/";
private static final String MODEL_CONFIG_DIR = "./config/model/";
private static final String PROMPT_CONFIG_DIR = "./config/prompt/";
private static final String MODULE_ENABLED_STATUS_CONFIG_FILE = CONFIG_DIR + "module_enabled_status.json";
@Override
protected HashMap<String, List<Message>> loadModelPrompt() {
File file = new File(PROMPT_CONFIG_DIR);
if (!file.exists() && !file.isDirectory()) {
throw new PromptDirNotExistException("未找到提示词目录: " + PROMPT_CONFIG_DIR + " 请手动创建!");
}
File[] files = file.listFiles();
if (files == null || files.length == 0) {
throw new PromptNotExistException("在目录 " + PROMPT_CONFIG_DIR + " 中未找到提示词配置!");
}
HashMap<String, List<Message>> promptMap = new HashMap<>();
for (File f : files) {
if (f.isDirectory()) {
continue;
}
PrimaryModelPrompt primaryModelPrompt = JSONUtil.readJSONObject(f, StandardCharsets.UTF_8).toBean(PrimaryModelPrompt.class);
promptMap.put(primaryModelPrompt.getKey(), primaryModelPrompt.getMessages());
}
return promptMap;
}
@Override
protected HashMap<String, ModelConfig> loadModelConfig() {
File file = new File(MODEL_CONFIG_DIR);
if (!file.exists() || !file.isDirectory()) {
throw new ConfigDirNotExistException("未找到配置目录: " + MODEL_CONFIG_DIR + " 请手动创建!");
}
File[] files = file.listFiles();
if (files == null || files.length == 0) {
throw new ConfigNotExistException("在目录" + MODEL_CONFIG_DIR + "中未找到配置文件!");
}
//遍历文件获取所有配置文件并返回
HashMap<String, ModelConfig> configMap = new HashMap<>();
for (File f : files) {
if (f.isDirectory()) {
continue;
}
PrimaryModelConfig primaryModelConfig = JSONUtil.readJSONObject(f, StandardCharsets.UTF_8).toBean(PrimaryModelConfig.class);
configMap.put(primaryModelConfig.getKey(), primaryModelConfig.getModelConfig());
}
return configMap;
}
@Override
protected HashMap<String, Boolean> loadModuleEnabledStatusMap() {
File file = new File(MODULE_ENABLED_STATUS_CONFIG_FILE);
try {
HashMap<String, Boolean> moduleEnabledStatus = new HashMap<>();
if (!file.exists()) {
file.createNewFile();
for (MetaModule module : moduleList) {
moduleEnabledStatus.put(module.getName(), module.isEnabled());
}
dumpModuleEnabledStatus();
} else {
JSONObject obj = JSONUtil.readJSONObject(file, StandardCharsets.UTF_8);
for (String s : obj.keySet()) {
moduleEnabledStatus.put(s, obj.getBool(s));
}
log.info("ModuleEnabledStatusConfig 配置文件已成功读取!");
}
return moduleEnabledStatus;
} catch (Exception e) {
throw new ConfigGenerateFailedException("ModuleEnabledStatusConfig 配置文件创建失败!", e);
}
}
@Override
public void dumpModelConfig(String key) {
try {
File file = new File(MODEL_CONFIG_DIR + key + ".json");
if (!file.exists()) {
file.createNewFile();
}
FileUtils.writeStringToFile(file, JSONUtil.toJsonPrettyStr(modelConfigMap.get(key)), StandardCharsets.UTF_8, false);
} catch (Exception e) {
throw new ConfigUpdateFailedException("ModelConfig 配置文件更新失败!");
}
}
@Override
protected void dumpModuleEnabledStatus() {
try {
File file = new File(MODULE_ENABLED_STATUS_CONFIG_FILE);
FileUtils.writeStringToFile(file, JSONUtil.toJsonPrettyStr(moduleEnabledStatus), StandardCharsets.UTF_8, false);
} catch (IOException e) {
throw new ConfigGenerateFailedException("ModuleEnabledStatus 配置文件更新失败!");
}
}
}

View File

@@ -1,23 +0,0 @@
package work.slhaf.partner.api.agent.runtime.data;
import lombok.Data;
import work.slhaf.partner.api.agent.factory.module.pojo.MetaModule;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
@Data
public class AgentContext {
public static AgentContext INSTANCE = new AgentContext();
private HashMap<String, Function<Object[], Object>> methodsRouterTable;
private HashMap<String, Function<Object[], Object>> coordinatedMethodsRouterTable;
private HashMap<Class<?>, Object> capabilityCoreInstances;
private HashMap<Class<?>, Object> capabilityHolderInstances;
private Set<Class<?>> cores;
private Set<Class<?>> capabilities;
private List<MetaModule> moduleList;
}

View File

@@ -1,6 +0,0 @@
package work.slhaf.partner.api.agent.runtime.exception;
public interface AgentExceptionCallback {
void onRuntimeException(AgentRuntimeException e);
void onFailedException(AgentLaunchFailedException e);
}

View File

@@ -1,11 +0,0 @@
package work.slhaf.partner.api.agent.runtime.exception;
public class AgentLaunchFailedException extends RuntimeException {
public AgentLaunchFailedException(String message, Throwable cause) {
super("Agent 启动失败 " + message, cause);
}
public AgentLaunchFailedException(String message) {
super("Agent 启动失败 " + message);
}
}

View File

@@ -1,11 +0,0 @@
package work.slhaf.partner.api.agent.runtime.exception;
public class AgentRuntimeException extends RuntimeException {
public AgentRuntimeException(String message) {
super("Agent 执行出错 " + message);
}
public AgentRuntimeException(String message, Throwable cause) {
super("Agent 执行出错 " + message, cause);
}
}

View File

@@ -1,17 +0,0 @@
package work.slhaf.partner.api.agent.runtime.exception;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class DefaultAgentExceptionCallback implements AgentExceptionCallback {
@Override
public void onRuntimeException(AgentRuntimeException e) {
log.error("Agent 运行异常: ", e);
}
@Override
public void onFailedException(AgentLaunchFailedException e) {
throw e;
}
}

View File

@@ -1,26 +0,0 @@
package work.slhaf.partner.api.agent.runtime.exception;
public class GlobalExceptionHandler {
public static GlobalExceptionHandler INSTANCE = new GlobalExceptionHandler();
private AgentExceptionCallback exceptionCallback = new DefaultAgentExceptionCallback();
public void handle(Throwable e) {
switch (e.getClass().getSimpleName()) {
case "AgentRuntimeException":
exceptionCallback.onRuntimeException((AgentRuntimeException) e);
break;
case "AgentLaunchFailedException":
exceptionCallback.onFailedException((AgentLaunchFailedException) e);
break;
default:
throw new RuntimeException("未经处理的异常!", e);
}
}
public static void setExceptionCallback(AgentExceptionCallback callback) {
INSTANCE.exceptionCallback = callback;
}
}

View File

@@ -1,12 +0,0 @@
package work.slhaf.partner.api.agent.runtime.interaction;
import work.slhaf.partner.api.agent.runtime.interaction.data.AgentInputData;
import work.slhaf.partner.api.agent.runtime.interaction.data.AgentOutputData;
import work.slhaf.partner.api.agent.runtime.interaction.flow.entity.RunningFlowContext;
public interface AgentGateway {
void launch();
<I extends AgentInputData, O extends AgentOutputData, C extends RunningFlowContext> AgentInteractionAdapter<I, O, C> adapter();
}

View File

@@ -1,41 +0,0 @@
package work.slhaf.partner.api.agent.runtime.interaction;
import work.slhaf.partner.api.agent.factory.module.pojo.MetaModule;
import work.slhaf.partner.api.agent.runtime.config.AgentConfigManager;
import work.slhaf.partner.api.agent.runtime.interaction.data.AgentInputData;
import work.slhaf.partner.api.agent.runtime.interaction.data.AgentOutputData;
import work.slhaf.partner.api.agent.runtime.interaction.flow.AgentRunningFlow;
import work.slhaf.partner.api.agent.runtime.interaction.flow.entity.RunningFlowContext;
import java.util.List;
public abstract class AgentInteractionAdapter<I extends AgentInputData, O extends AgentOutputData, C extends RunningFlowContext> {
private static AgentInteractionAdapter<?,?,?> INSTANCE;
protected AgentRunningFlow<C> agentRunningFlow = new AgentRunningFlow<>();
protected List<MetaModule> moduleList = AgentConfigManager.INSTANCE.getModuleList();
public void receive(I inputData) {
C finalInputData = parseInputData(inputData);
C outputContext = agentRunningFlow.launch(moduleList, finalInputData);
O outputData = parseOutputData(outputContext);
send(outputData);
}
protected abstract O parseOutputData(C outputContext);
protected abstract C parseInputData(I inputData);
public abstract void send(O outputData);
public static <I extends AgentInputData, O extends AgentOutputData, C extends RunningFlowContext> AgentInteractionAdapter<I, O, C> getInstance() {
@SuppressWarnings("unchecked")
AgentInteractionAdapter<I, O, C> instance = (AgentInteractionAdapter<I, O, C>) INSTANCE;
return instance;
}
public static <I extends AgentInputData, O extends AgentOutputData, C extends RunningFlowContext> void setInstance(AgentInteractionAdapter<I, O, C> instance) {
INSTANCE = instance;
}
}

View File

@@ -1,9 +0,0 @@
package work.slhaf.partner.api.agent.runtime.interaction.data;
import lombok.Data;
import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
@Data
public abstract class AgentInputData extends InteractionData{
}

View File

@@ -1,16 +0,0 @@
package work.slhaf.partner.api.agent.runtime.interaction.data;
import lombok.Data;
import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
@Data
public abstract class AgentOutputData extends InteractionData{
private int code;
public static class StatusCode {
public static final int SUCCESS = 1;
public static final int FAILED = 0;
}
}

View File

@@ -1,12 +0,0 @@
package work.slhaf.partner.api.agent.runtime.interaction.data;
import lombok.Data;
import java.time.LocalDateTime;
@Data
public abstract class InteractionData {
protected String userInfo;
protected String content;
protected LocalDateTime dateTime;
}

View File

@@ -1,25 +0,0 @@
package work.slhaf.partner.api.agent.runtime.interaction.flow;
import work.slhaf.partner.api.agent.factory.module.pojo.MetaModule;
import work.slhaf.partner.api.agent.runtime.exception.GlobalExceptionHandler;
import work.slhaf.partner.api.agent.runtime.interaction.flow.entity.RunningFlowContext;
import java.util.List;
/**
* Agent执行流程
*/
public class AgentRunningFlow<C extends RunningFlowContext> {
public C launch(List<MetaModule> moduleList, C interactionContext){
try {
//流程执行启动
for (MetaModule metaModule : moduleList) {
metaModule.getInstance().execute(interactionContext);
}
}catch (Exception e){
GlobalExceptionHandler.INSTANCE.handle(e);
}
return interactionContext;
}
}

View File

@@ -1,94 +0,0 @@
package work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts;
import cn.hutool.core.bean.BeanUtil;
import work.slhaf.partner.api.agent.factory.config.pojo.ModelConfig;
import work.slhaf.partner.api.agent.factory.module.annotation.Init;
import work.slhaf.partner.api.agent.runtime.config.AgentConfigManager;
import work.slhaf.partner.api.agent.runtime.interaction.flow.entity.Model;
import work.slhaf.partner.api.chat.ChatClient;
import work.slhaf.partner.api.chat.constant.ChatConstant;
import work.slhaf.partner.api.chat.pojo.ChatResponse;
import work.slhaf.partner.api.chat.pojo.Message;
import java.util.ArrayList;
import java.util.List;
public interface ActivateModel {
AgentConfigManager AGENT_CONFIG_MANAGER = AgentConfigManager.INSTANCE;
@Init
default void modelSettings() {
Model model = new Model();
ModelConfig modelConfig = AgentConfigManager.INSTANCE.loadModelConfig(modelKey());
model.setBaseMessages(withBasicPrompt() ? loadSpecificPromptAndBasicPrompt(modelKey()) : loadSpecificPrompt(modelKey()));
model.setChatClient(new ChatClient(modelConfig.getBaseUrl(), modelConfig.getApikey(), modelConfig.getModel()));
((Module) this).setModel(model);
}
default void updateModelSettings(ChatClient newChatClient) {
BeanUtil.copyProperties(newChatClient, chatClient());
}
private List<Message> loadSpecificPrompt(String modelKey) {
return AGENT_CONFIG_MANAGER.loadModelPrompt(modelKey);
}
private List<Message> loadSpecificPromptAndBasicPrompt(String modelKey) {
List<Message> messages = new ArrayList<>();
messages.addAll(AGENT_CONFIG_MANAGER.loadModelPrompt("basic"));
messages.addAll(AGENT_CONFIG_MANAGER.loadModelPrompt(modelKey));
return messages;
}
default ChatResponse chat() {
Model model = getModel();
List<Message> temp = new ArrayList<>();
temp.addAll(model.getBaseMessages());
temp.addAll(model.getChatMessages());
return model.getChatClient().runChat(temp);
}
default ChatResponse singleChat(String input) {
Model model = getModel();
List<Message> temp = new ArrayList<>(model.getBaseMessages());
temp.add(new Message(ChatConstant.Character.USER, input));
return model.getChatClient().runChat(temp);
}
default void updateChatClientSettings() {
Model model = getModel();
model.getChatClient().setTemperature(0.4);
model.getChatClient().setTop_p(0.8);
}
default List<Message> chatMessages() {
return getModel().getChatMessages();
}
default List<Message> baseMessages() {
return getModel().getBaseMessages();
}
default ChatClient chatClient() {
return getModel().getChatClient();
}
/**
* 仅适用Module子类否则需要重写
*
* @return 持有的model实例
*/
default Model getModel() {
return ((Module) this).getModel();
}
default void setModel(Model model) {
((Module) this).setModel(model);
}
String modelKey();
boolean withBasicPrompt();
}

View File

@@ -1,10 +0,0 @@
package work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts;
import work.slhaf.partner.api.agent.runtime.interaction.flow.entity.RunningFlowContext;
/**
* 流程执行模块基类
*/
public abstract class AgentRunningModule extends Module {
public abstract void execute(RunningFlowContext context);
}

View File

@@ -1,13 +0,0 @@
package work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts;
/**
* 流程子模块基类
* @param <I> 输入类型
* @param <O> 输出类型
*/
public abstract class AgentRunningSubModule<I, O> extends Module {
public abstract O execute(I data);
}

View File

@@ -1,18 +0,0 @@
package work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts;
import lombok.Getter;
import lombok.Setter;
import work.slhaf.partner.api.agent.factory.capability.annotation.CapabilityHolder;
import work.slhaf.partner.api.agent.runtime.interaction.flow.entity.Model;
/**
* 模块基类
*/
@CapabilityHolder
public abstract class Module {
@Getter
@Setter
protected Model model = new Model();
}

View File

@@ -1,16 +0,0 @@
package work.slhaf.partner.api.agent.runtime.interaction.flow.entity;
import lombok.Data;
import work.slhaf.partner.api.chat.ChatClient;
import work.slhaf.partner.api.chat.pojo.Message;
import java.util.List;
@Data
public class Model {
protected ChatClient chatClient;
protected List<Message> chatMessages;
protected List<Message> baseMessages;
}

View File

@@ -1,11 +0,0 @@
package work.slhaf.partner.api.agent.runtime.interaction.flow.entity;
import lombok.Data;
/**
* 流程上下文
*/
@Data
public abstract class RunningFlowContext {
}

View File

@@ -1,70 +0,0 @@
package work.slhaf.partner.api.chat;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONUtil;
import lombok.Data;
import lombok.NoArgsConstructor;
import work.slhaf.partner.api.chat.constant.ChatConstant;
import work.slhaf.partner.api.chat.pojo.ChatBody;
import work.slhaf.partner.api.chat.pojo.ChatResponse;
import work.slhaf.partner.api.chat.pojo.Message;
import work.slhaf.partner.api.chat.pojo.PrimaryChatResponse;
import java.util.List;
@Data
@NoArgsConstructor
public class ChatClient {
private String clientId;
private String url;
private String apikey;
private String model;
private double top_p;
private double temperature;
private int max_tokens;
public ChatClient(String url, String apikey, String model) {
this.url = url;
this.apikey = apikey;
this.model = model;
}
public ChatResponse runChat(List<Message> messages) {
HttpRequest request = HttpRequest.post(url);
request.header("Content-Type", "application/json");
request.header("Authorization", "Bearer " + apikey);
ChatBody body;
if (top_p > 0) {
body = ChatBody.builder()
.model(model)
.messages(messages)
.top_p(top_p)
.temperature(temperature)
.max_tokens(max_tokens)
.build();
} else {
body = ChatBody.builder()
.model(model)
.messages(messages)
.build();
}
HttpResponse response = request.body(JSONUtil.toJsonStr(body)).execute();
ChatResponse finalResponse;
PrimaryChatResponse primaryChatResponse = JSONUtil.toBean(response.body(), PrimaryChatResponse.class);
finalResponse = ChatResponse.builder()
.type(ChatConstant.Response.SUCCESS)
.message(primaryChatResponse.getChoices().get(0).getMessage().getContent())
.usageBean(primaryChatResponse.getUsage())
.build();
response.close();
return finalResponse;
}
}

View File

@@ -1,15 +0,0 @@
package work.slhaf.partner.api.chat.constant;
public class ChatConstant {
public static class Character {
public static final String USER = "user";
public static final String SYSTEM = "system";
public static final String ASSISTANT = "assistant";
}
public static class Response {
public static final String SUCCESS = "success";
public static final String ERROR = "error";
}
}

View File

@@ -1,25 +0,0 @@
package work.slhaf.partner.api.chat.pojo;
import lombok.*;
import java.util.List;
@Builder
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ChatBody {
@NonNull
private String model;
@NonNull
private List<Message> messages;
@Builder.Default
private double temperature = 1;
@Builder.Default
private double top_p = 1;
private boolean stream;
@Builder.Default
private int max_tokens = 1024;
private int presence_penalty;
private int frequency_penalty;
}

View File

@@ -1,16 +0,0 @@
package work.slhaf.partner.api.chat.pojo;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class ChatResponse {
private String type;
private String message;
private PrimaryChatResponse.UsageBean usageBean;
}

View File

@@ -1,22 +0,0 @@
package work.slhaf.partner.api.chat.pojo;
import lombok.*;
import work.slhaf.partner.api.common.entity.PersistableObject;
import java.io.Serial;
@EqualsAndHashCode(callSuper = true)
@Builder
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Message extends PersistableObject {
@Serial
private static final long serialVersionUID = 1L;
@NonNull
private String role;
@NonNull
private String content;
}

View File

@@ -1,20 +0,0 @@
package work.slhaf.partner.api.chat.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import work.slhaf.partner.api.common.entity.PersistableObject;
import java.io.Serial;
@EqualsAndHashCode(callSuper = true)
@Data
@AllArgsConstructor
public class MetaMessage extends PersistableObject {
@Serial
private static final long serialVersionUID = 1L;
private Message userMessage;
private Message assistantMessage;
}

View File

@@ -1,111 +0,0 @@
package work.slhaf.partner.api.chat.pojo;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
@Getter
@Setter
public class PrimaryChatResponse {
/**
* id
*/
private String id;
/**
* object
*/
private String object;
/**
* created
*/
private int created;
/**
* model
*/
private String model;
/**
* choices
*/
private List<ChoicesBean> choices;
/**
* usage
*/
private UsageBean usage;
/**
* system_fingerprint
*/
private String system_fingerprint;
@Setter
@Getter
public static class UsageBean {
/**
* prompt_tokens
*/
private int prompt_tokens;
/**
* completion_tokens
*/
private int completion_tokens;
/**
* total_tokens
*/
private int total_tokens;
/**
* prompt_cache_hit_tokens
*/
private int prompt_cache_hit_tokens;
/**
* prompt_cache_miss_tokens
*/
private int prompt_cache_miss_tokens;
@Override
public String toString() {
return "UsageBean{" +
"prompt_tokens=" + prompt_tokens +
", completion_tokens=" + completion_tokens +
", total_tokens=" + total_tokens +
", prompt_cache_hit_tokens=" + prompt_cache_hit_tokens +
", prompt_cache_miss_tokens=" + prompt_cache_miss_tokens +
'}';
}
}
@Setter
@Getter
public static class ChoicesBean {
/**
* index
*/
private int index;
/**
* message
*/
private MessageBean message;
/**
* logprobs
*/
private Object logprobs;
/**
* finish_reason
*/
private String finish_reason;
@Setter
@Getter
public static class MessageBean {
/**
* role
*/
private String role;
/**
* content
*/
private String content;
}
}
}

View File

@@ -1,6 +0,0 @@
package work.slhaf.partner.api.common.entity;
import java.io.Serializable;
public abstract class PersistableObject implements Serializable {
}

View File

@@ -1,7 +0,0 @@
package factory;
public class AgentRegisterTest {
public static void main(String[] args) {
}
}

View File

@@ -1,24 +0,0 @@
package module;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.matcher.ElementMatchers;
import org.junit.jupiter.api.Test;
import work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts.AgentRunningModule;
import java.lang.reflect.InvocationTargetException;
public class ModuleProxyTest {
@Test
public void test() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
Class<? extends AgentRunningModule> clazz = new ByteBuddy().subclass(MyAgentRunningModule.class)
.method(ElementMatchers.isOverriddenFrom(AgentRunningModule.class))
.intercept(MethodDelegation.to(
new MyModuleProxyInterceptor()
))
.make()
.load(ModuleProxyTest.class.getClassLoader())
.getLoaded();
clazz.getConstructor().newInstance().execute(null);
}
}

View File

@@ -1,11 +0,0 @@
package module;
import work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts.AgentRunningModule;
import work.slhaf.partner.api.agent.runtime.interaction.flow.entity.RunningFlowContext;
public class MyAgentRunningModule extends AgentRunningModule {
@Override
public void execute(RunningFlowContext context) {
System.out.println("MyAgentRunningModule");
}
}

View File

@@ -1,18 +0,0 @@
package module;
import net.bytebuddy.implementation.bind.annotation.*;
import java.lang.reflect.Method;
import java.util.concurrent.Callable;
public class MyModuleProxyInterceptor {
public MyModuleProxyInterceptor() {}
@RuntimeType
public Object intercept(@Origin Method method, @AllArguments Object[] allArguments, @SuperCall Callable<?> zuper, @This Object proxy) throws Exception {
System.out.println("22222");
Object res = zuper.call();
System.out.println("11111");
return res;
}
}

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" <project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
@@ -9,16 +9,16 @@
<version>0.5.0</version> <version>0.5.0</version>
</parent> </parent>
<artifactId>Partner-Test-Demo</artifactId> <artifactId>Partner-Common</artifactId>
<dependencies> <dependencies>
<!-- https://mvnrepository.com/artifact/io.modelcontextprotocol.sdk/mcp -->
<dependency> <dependency>
<groupId>work.slhaf</groupId> <groupId>io.modelcontextprotocol.sdk</groupId>
<artifactId>Partner-Api</artifactId> <artifactId>mcp</artifactId>
<version>0.5.0</version> <version>0.17.0</version>
</dependency> </dependency>
</dependencies> </dependencies>
<properties> <properties>
<maven.compiler.source>21</maven.compiler.source> <maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target> <maven.compiler.target>21</maven.compiler.target>

View File

@@ -0,0 +1,155 @@
package work.slhaf.partner.common.mcp;
import io.modelcontextprotocol.common.McpTransportContext;
import io.modelcontextprotocol.json.McpJsonMapper;
import io.modelcontextprotocol.json.TypeRef;
import io.modelcontextprotocol.server.McpStatelessServerHandler;
import io.modelcontextprotocol.spec.McpClientTransport;
import io.modelcontextprotocol.spec.McpSchema;
import io.modelcontextprotocol.spec.McpStatelessServerTransport;
import reactor.core.publisher.Mono;
import reactor.core.publisher.Sinks;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;
import java.util.function.Function;
public final class InProcessMcpTransport implements McpClientTransport, McpStatelessServerTransport {
// 每个 transport 只处理一条 inbound 流
private final Sinks.Many<McpSchema.JSONRPCMessage> inbound =
Sinks.many().unicast().onBackpressureBuffer();
private final AtomicBoolean clientConnected = new AtomicBoolean(false);
private final AtomicBoolean serverConnected = new AtomicBoolean(false);
/**
* 对端
*/
private volatile InProcessMcpTransport peer;
private volatile McpStatelessServerHandler serverHandler;
public static Pair pair() {
InProcessMcpTransport client = new InProcessMcpTransport();
InProcessMcpTransport server = new InProcessMcpTransport();
client.peer = server;
server.peer = client;
return new Pair(client, server);
}
/* ======================================================
* Internal receive: peer.sendMessage -> this.receive
* ====================================================== */
private void receive(McpSchema.JSONRPCMessage message) {
if (inbound.tryEmitNext(message).isFailure()) {
throw new RuntimeException("Failed to receive message: " + message);
}
}
/* ======================================================
* Client → Server sendMessage
* ====================================================== */
@Override
public Mono<Void> sendMessage(McpSchema.JSONRPCMessage message) {
InProcessMcpTransport p = this.peer;
if (p == null) {
return Mono.error(new IllegalStateException("Transport is not linked"));
}
return Mono.fromRunnable(() -> p.receive(message));
}
/* ======================================================
* Client connect(handler) 处理 server → client 消息
* ====================================================== */
@Override
public Mono<Void> connect(Function<Mono<McpSchema.JSONRPCMessage>, Mono<McpSchema.JSONRPCMessage>> handler) {
if (!clientConnected.compareAndSet(false, true)) {
return Mono.error(new IllegalStateException("Client already connected"));
}
return inbound.asFlux()
.concatMap(msg ->
handler.apply(Mono.just(msg))
// handler may emit response message → send back to server
.flatMap(resp -> resp != null ? sendMessage(resp) : Mono.empty())
)
.doFinally(sig -> clientConnected.set(false))
.then();
}
@Override
public void setExceptionHandler(Consumer<Throwable> handler) {
McpClientTransport.super.setExceptionHandler(handler);
}
/* ======================================================
* Server: bind stateless handler = process client → server inbound
* ====================================================== */
@Override
public void setMcpHandler(McpStatelessServerHandler handler) {
this.serverHandler = handler;
if (!serverConnected.compareAndSet(false, true)) {
throw new IllegalStateException("Server already connected");
}
// 订阅 client → server 消息
inbound.asFlux()
.concatMap(this::handleServerMessage)
.doFinally(sig -> serverConnected.set(false))
.subscribe();
}
/**
* Server 端处理 JSONRPCMessage
*/
private Mono<Void> handleServerMessage(McpSchema.JSONRPCMessage msg) {
// 创建 transport context简单实现即可
McpTransportContext ctx = key -> null;
if (msg instanceof McpSchema.JSONRPCRequest req) {
return serverHandler.handleRequest(ctx, req)
.flatMap(this::sendMessage);
}
if (msg instanceof McpSchema.JSONRPCNotification noti) {
return serverHandler.handleNotification(ctx, noti);
}
return Mono.empty();
}
@Override
public void close() {
McpClientTransport.super.close();
}
/* ======================================================
* other boilerplate
* ====================================================== */
@Override
public Mono<Void> closeGracefully() {
inbound.tryEmitComplete();
clientConnected.set(false);
serverConnected.set(false);
return Mono.empty();
}
@Override
public <T> T unmarshalFrom(Object data, TypeRef<T> typeRef) {
return McpJsonMapper.getDefault().convertValue(data, typeRef);
}
@Override
public List<String> protocolVersions() {
return McpClientTransport.super.protocolVersions();
}
public record Pair(InProcessMcpTransport clientSide, InProcessMcpTransport serverSide) {
}
}

View File

@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<artifactId>Partner</artifactId>
<groupId>work.slhaf</groupId>
<version>0.5.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>Partner-Main</artifactId>
<build>
<plugins>
<plugin>
<artifactId>maven-shade-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer>
<mainClass>work.slhaf.partner.Main</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skipTests>true</skipTests>
</configuration>
</plugin>
</plugins>
</build>
<properties>
<maven.compiler.target>21</maven.compiler.target>
<maven.compiler.source>21</maven.compiler.source>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>

140
Partner-Core/pom.xml Normal file
View File

@@ -0,0 +1,140 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>work.slhaf</groupId>
<artifactId>Partner</artifactId>
<version>0.5.0</version>
</parent>
<artifactId>Partner-Core</artifactId>
<dependencies>
<dependency>
<groupId>org.java-websocket</groupId>
<artifactId>Java-WebSocket</artifactId>
<version>1.6.0</version>
</dependency>
<dependency>
<groupId>work.slhaf</groupId>
<artifactId>Partner-Framework</artifactId>
<version>0.5.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.nd4j/nd4j-api -->
<dependency>
<groupId>org.nd4j</groupId>
<artifactId>nd4j-api</artifactId>
<version>1.0.0-M2.1</version>
</dependency>
<dependency>
<groupId>com.microsoft.onnxruntime</groupId>
<artifactId>onnxruntime</artifactId>
<version>1.23.1</version>
</dependency>
<dependency>
<groupId>ai.djl.huggingface</groupId>
<artifactId>tokenizers</artifactId>
<version>0.34.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.modelcontextprotocol.sdk/mcp -->
<dependency>
<groupId>io.modelcontextprotocol.sdk</groupId>
<artifactId>mcp</artifactId>
<version>0.17.0</version>
</dependency>
<dependency>
<groupId>work.slhaf</groupId>
<artifactId>Partner-Common</artifactId>
<version>0.5.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>5.20.0</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>5.20.0</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<version>5.2.0</version>
</dependency>
<dependency>
<groupId>com.cronutils</groupId>
<artifactId>cron-utils</artifactId>
<version>9.2.1</version>
</dependency>
</dependencies>
<properties>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>work.slhaf.partner.Main</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<version>${kotlin.version}</version>
<executions>
<execution>
<id>compile</id>
<phase>process-sources</phase>
<goals>
<goal>compile</goal>
</goals>
<configuration>
<sourceDirs>
<sourceDir>${project.basedir}/src/main/java</sourceDir>
</sourceDirs>
</configuration>
</execution>
<execution>
<id>test-compile</id>
<phase>test-compile</phase>
<goals>
<goal>test-compile</goal>
</goals>
<configuration>
<sourceDirs>
<sourceDir>${project.basedir}/src/test/java</sourceDir>
</sourceDirs>
</configuration>
</execution>
</executions>
<configuration>
<jvmTarget>${maven.compiler.target}</jvmTarget>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,14 @@
package work.slhaf.partner;
import work.slhaf.partner.common.vector.VectorClientRegistry;
import work.slhaf.partner.framework.agent.Agent;
import work.slhaf.partner.runtime.gateway.WebSocketGatewayRegistration;
public class Main {
public static void main(String[] args) {
Agent.newAgent(Main.class)
.addGatewayRegistration(WebSocketGatewayRegistration.INSTANCE)
.addConfigurable(new VectorClientRegistry())
.launch();
}
}

Some files were not shown because too many files have changed in this diff Show More