520 Commits

Author SHA1 Message Date
68589a21fc chore(release): add partnerctl release workflow 2026-05-11 15:18:15 +08:00
e8228d0cc1 fix(ci): make partnerctl native test workflow dispatchable 2026-05-11 11:33:00 +08:00
cc99e565f0 chore(ci): add partnerctl native build test workflow 2026-05-11 11:29:33 +08:00
github-actions[bot]
718271417d chore(registry): update latest core release to release-core/0.5.0 2026-05-11 03:15:42 +00:00
04ee38726b chore(release): use release-core tag workflow 2026-05-11 11:09:10 +08:00
github-actions[bot]
4a00e65868 chore(registry): update latest core release to rel-v0.5.0 2026-05-11 03:00:38 +00:00
6c3c08b5d5 chore: unify workflows name style 2026-05-11 10:24:29 +08:00
ef5a332f17 chore(release): add partner core release workflow 2026-05-11 10:05:43 +08:00
github-actions[bot]
9acabca40e chore(registry): update latest buildable to buildable/0.5.0 2026-05-10 15:28:36 +00:00
b654090a6e feat(git): add latest buildable update workflow 2026-05-10 23:18:07 +08:00
github-actions[bot]
c9a7343b30 chore: update registry index 2026-05-10 14:27:29 +00:00
6250b480e0 chore: add onebot adapter registry manifest 2026-05-10 22:27:13 +08:00
github-actions[bot]
63e8cc314a chore: update registry index 2026-05-10 14:22:35 +00:00
451f83e14d fix(module-registry): resolve manifest paths from registry in index update script 2026-05-10 22:22:12 +08:00
2b7e6718d9 fix(git): stage registry/index.json in update workflow 2026-05-10 22:10:41 +08:00
ed806c668a feat(git): add module index updating workflow 2026-05-10 22:08:47 +08:00
da381c3adf refactor(partnerctl-module): add version attribute to manifest 2026-05-10 21:40:20 +08:00
1cbff98b36 chore(git): remove legacy gitea sync workflow 2026-05-10 21:36:12 +08:00
95a30f147c chore: add initial module registry structure 2026-05-10 21:32:06 +08:00
0ea8dfc7d9 fix(core): correct logback log level fallback syntax (#1) 2026-05-09 14:51:28 +08:00
8cb876b532 feat(partnerctl): add --log-level option for run command and wire runtime log level to Partner-Core 2026-05-09 14:12:32 +08:00
d72b34acfd fix(partnerctl): align Partner-Core jar path to resources/partner-core.jar across init/control 2026-05-09 13:38:51 +08:00
79dcda082f refactor(partnerctl-chat): optimize color of chat prompt 2026-05-09 10:14:36 +08:00
fbd1d17fc4 refactor(partnerctl): extract TerminalText styling utility and reuse it in prompt/chat rendering 2026-05-08 23:44:08 +08:00
a8e3a84db8 feat(partnerctl): implement interactive WebSocket chat client with live event rendering 2026-05-08 23:16:49 +08:00
e6e0eef161 refactor(interaction-api): extract interaction data models into new Partner-Interaction-Api module and update imports/dependencies 2026-05-08 20:32:11 +08:00
4c042769f2 refactor(partnerctl): disable Config and Module command temporally in root command 2026-05-06 15:18:20 +08:00
7bee14452e feat(partnerctl): add shared help option mixin across commands 2026-05-06 15:06:20 +08:00
442397c1f5 feat(partnerctl): i18n-ize command and option descriptions via message bundles 2026-05-06 14:55:16 +08:00
0b329aa370 docs(readme): update build/run commands for Partner-Core module and jar naming 2026-05-06 13:55:14 +08:00
ffc96bbb64 refactor(partnerctl): split control commands into dedicated classes and extract shared runtime utilities 2026-05-06 13:26:46 +08:00
8398c14794 feat(partnerctl): add background run mode and log command with pid/log file management 2026-05-05 23:57:32 +08:00
bd4d5164d3 feat(partnerctl): add run and shutdown commands with process lifecycle handling 2026-05-05 23:39:17 +08:00
9073f88117 feat(partnerctl-init): add i18n message bundles for init flow and source build output 2026-05-05 22:37:41 +08:00
0710f60ed6 fix(partnerctl-init): use numeric default for heartbeat interval prompt 2026-05-05 17:33:44 +08:00
1bf02f543e feat(partnerctl-init): add safe Partner Home selection with overwrite/cancel flow 2026-05-05 17:21:02 +08:00
19f87c93e3 feat(partnerctl): add ANSI-styled interactive prompt output and labels 2026-05-05 16:36:59 +08:00
828ddff2c2 chore(log): remove legacy log output 2026-05-05 01:29:12 +08:00
57b23e0dcb feat(partnerctl-init): add finalize step 2026-05-05 00:41:25 +08:00
11f7200e23 feat(partnerctl-init): add interactive model provider configuration 2026-05-04 23:52:13 +08:00
ee8f568006 refactor(partnerctl): move GatewayConfig into commands.data model file 2026-05-04 20:35:36 +08:00
393dcff6df feat(partnerctl-init): add interactive gateway configuration and gateway.json generation 2026-05-04 17:48:58 +08:00
0fdc0038a5 docs(partnerctl-support): add KDoc for source build spec and external module manifest models 2026-05-04 17:47:20 +08:00
97bf0618f4 feat(partnerctl): add details output helper for key-value prompt sections 2026-05-04 17:08:20 +08:00
4200df6525 feat(partnerctl-support): add external module manifest models and gateway/module loaders 2026-05-04 15:20:34 +08:00
686dc76b55 chore(partnerctl-pom): add kotlinx serialization 2026-05-03 23:30:26 +08:00
adab925e7d refactor(partnerctl-init): extract source build/install flow into reusable support helper 2026-05-03 21:50:25 +08:00
6c74de2126 feat(partnerctl-init): add source build install choice 2026-05-03 21:06:46 +08:00
7fcdb1c671 refactor(partnerctl-exception): add command interrupted exception, and unify exception handling 2026-05-03 20:08:18 +08:00
78877f14d5 feat(partnerctl-init): support initialize Partner Home 2026-05-03 19:35:43 +08:00
729700ceb7 feat(partnerctl): add path prompt with completion and validation 2026-05-03 19:27:07 +08:00
6f48c36f67 feat(partnerctl): add interactive single select 2026-05-03 18:45:03 +08:00
551a2a16d9 feat(partnerctl): add command execution helpers with captured and inherited IO 2026-05-03 18:34:01 +08:00
40af7a4de6 feat(partnerctl): add Prompt UI helper with ask/confirm/select and multi-select support 2026-05-03 17:38:56 +08:00
cbdb33fefe chore(partnerctl): add GraalVM native-image setup and arm64 build tooling 2026-05-03 15:46:26 +08:00
d2c3416f48 feat(partnerctl): add main command with init/run/module and chat demo subcommands 2026-05-03 15:44:53 +08:00
c3dc8180f1 feat(partnerctl): initialize PartnerCtl maven module with CLI dependencies 2026-05-02 23:35:39 +08:00
1564c7d5e1 refactor(gateway): provide websocket as default agent gateway 2026-05-02 22:46:14 +08:00
9e33f16aae fix(onebot): flush buffered replies on terminal events 2026-05-02 21:55:28 +08:00
c84d88eab7 refactor(communication): simplify reply consumer buffering 2026-05-02 21:55:11 +08:00
692c601f17 refactor(model): expose stream chat lifecycle callbacks 2026-05-02 21:54:48 +08:00
2a8b2aff7b test(onebot): add test class for OneBot adapter 2026-05-02 16:32:49 +08:00
afb896e6db refactor(context): support assign response channel while running flow context creating 2026-05-02 16:32:25 +08:00
2b575df3f9 fix(agent): add url class loader to support load external modules 2026-05-02 00:36:34 +08:00
db18c818ac chore(pom): add kotlin-maven-plugin setup 2026-05-02 00:16:19 +08:00
973875b2e7 feat(onebot): add OneBot v11 reverse websocket adapter 2026-05-02 00:02:22 +08:00
018b524be3 refactor(gateway): remove unused abstract methods 2026-05-01 22:09:16 +08:00
843549dadf chore(gateway): update log output in websocket gateway 2026-05-01 21:43:40 +08:00
32f0c5c6a8 feat(pom): add Partner-Onebot-Adapter module and Maven config 2026-05-01 21:11:40 +08:00
dd31f6a20d chore(idea): update project dictionary and encodings 2026-05-01 21:11:13 +08:00
178c5138f7 refactor(gateway): remove duplicate response channel register 2026-05-01 21:10:13 +08:00
f9cdf164f3 feat(pom): create Partner-External-Modules 2026-04-30 22:55:20 +08:00
0c2843a889 chore(gitignore): update gitignore 2026-04-30 22:50:43 +08:00
572bedcd18 refactor(pom): align Maven coordinates to work.slhaf.partner and lowercase artifactIds 2026-04-30 22:45:08 +08:00
32ee6b5ed6 docs(architecture): update startup/register-chain flow for AgentBootstrap and registerContext 2026-04-30 22:24:19 +08:00
428f133ac3 refactor(agent): introduce AgentBootstrap for startup wiring and simplify app launch 2026-04-30 22:12:04 +08:00
7aab236221 docs(readme): update readme 2026-04-30 16:15:55 +08:00
0d456596a8 docs(readme): update readme 2026-04-30 16:12:10 +08:00
cbd926bd41 docs(memory): add document for memory 2026-04-30 16:08:18 +08:00
4a00e5f320 docs(action): add document for action 2026-04-29 22:27:27 +08:00
690f258dc9 docs(context): add document for context workspace 2026-04-29 11:03:03 +08:00
d7b271bf71 docs(model): add model provider runtime/config docs and link from README 2026-04-28 23:00:23 +08:00
ff80d6bbc4 docs(config): add config center lifecycle docs and split config reference into dedicated doc 2026-04-28 22:13:12 +08:00
3e73d574df docs(readme): update readme 2026-04-28 21:12:08 +08:00
9ea475432f docs(architecture): add startup/register/runtime/shutdown flow docs and architecture overview 2026-04-28 21:09:33 +08:00
e66ed9e9c0 refactor(trace): move sink registration to TraceSink default methods and restrict registry APIs 2026-04-28 14:58:09 +08:00
73f6ff2745 refactor(trace): decouple recorder from file persistence
Turn TraceRecorder into a lightweight trace event entry point and move
file persistence responsibilities into the default FileTraceSink. Trace
events are now published through TraceSinkRegistry, allowing additional
runtime observers to subscribe without parsing trace files.

Add TraceSink and TraceSinkRegistry, keep FileTraceSink registered as the
default sink, and preserve the existing active/historical/archived trace
file rotation behavior inside the file sink.

Also change TraceEvent to carry a logical key instead of a caller-provided
path, so trace storage locations are resolved internally under the traceroot. Update existing trace producers to emit logical keys such ascontext-workspace, exception, and advice targets.
2026-04-27 23:53:20 +08:00
3eac52f4e2 refactor(action): switch builtin actions to provider-driven self-registration 2026-04-27 20:53:45 +08:00
cf61c171a5 fix(action): stabilize staged action execution metadata
Use a stage-local Phaser in ActionExecutor so each action-chain stage
waits on its own execution phase. This avoids reusing a terminated
Phaser after the first stage completes, which could cause later stages
to advance without actually waiting for their MetaActions and trigger
FINAL_CHECK prematurely.

Add stage-level descriptions to evaluated action chains and pass them
through execution/correction contexts. Stage descriptions are now aligned
with normalized action-chain order, exposed to ParamsExtractor, persisted
in action state, and included in CorrectorInput so repeated MetaActions
can be parameterized and corrected according to their concrete stage
objective.

Also fix APPEND intervention semantics to append after the requested
stage instead of overwriting or dropping stages, and include stage
descriptions in correction prompts to distinguish stage intent from
generic MetaAction capability descriptions.
2026-04-27 18:41:32 +08:00
822ea82593 feat(action): add stage descriptions to action chains 2026-04-27 17:54:38 +08:00
f957d7caa4 fix(action): continue execution after final correction 2026-04-27 17:01:50 +08:00
9be499eb64 refactor(action): optimize prompt of ActionExtractor 2026-04-27 17:01:38 +08:00
184c396752 fix(action): stabilize scheduler wheel lifecycle 2026-04-27 16:25:42 +08:00
04ceccc46f fix(action): clarify pending action intention context 2026-04-27 15:51:42 +08:00
b0185c65c8 chore(action): remove unused variable 2026-04-27 15:34:48 +08:00
d43476864c docs: update README 2026-04-27 15:07:55 +08:00
e022f134ac docs: update README and add documentation skeleton 2026-04-27 15:03:03 +08:00
9144cd90ce refactor(project): remove Partner-Common module and move InProcessMcpTransport into Partner-Core 2026-04-26 19:45:38 +08:00
c23bda430f refactor(project): remove Partner-SandboxRunner module and clean related files 2026-04-26 18:20:07 +08:00
aa98c29744 refactor(communication): optimize prompt to avoid unexpected output in communication producer 2026-04-26 16:38:13 +08:00
eade39328a refactor(memory-selector): refactor memory recalling into async worker 2026-04-25 23:22:43 +08:00
94adf9a368 fix(openai-provider): add cached structured-output downgrade to prompt-only JSON fallback 2026-04-25 22:12:07 +08:00
dd5ab3aaf3 fix(openai-provider): generate and inject response-type JSON shape instruction for structured chat 2026-04-25 20:23:28 +08:00
075a8ece3e refactor(action-planner): optimize prompts and initiate-turn input 2026-04-25 19:31:51 +08:00
4bc2e4adbf refactor(action-executor): add FINAL_CHECK fallback correction at chain end and pass check mode/result in corrector input 2026-04-25 16:56:47 +08:00
9240ed44c4 refactor(action-evaluator): optimize prompt 2026-04-25 14:41:56 +08:00
878fe4dc10 refactor(action-planner): simplify tendencies state hint naming and always follow up on refused candidates 2026-04-25 13:17:23 +08:00
03bae6424e fix(openai-provider): ensure structured chat adds JSON instruction when missing 2026-04-25 00:11:57 +08:00
a14e123ff6 fix(communication): rolling out all chat messages on auto triggered and raise dialog rolling trigger length limit 2026-04-24 23:20:56 +08:00
d4277aed33 chore(config-center): downgrade skipped reload deletion log from info to
debug
2026-04-24 23:08:58 +08:00
e37dc7bc9b refactor(action-executor): emit action-finished state hint and trigger cognition turn on executable completion 2026-04-24 22:28:25 +08:00
51706eb55e refactor(action-planner): replace pending confirm blocks with StateHintContent and streamline tendency turns 2026-04-24 22:04:02 +08:00
eb3e5f3f34 refactor(context): add StateHintContent to fit information exchange between different modules with communication producer 2026-04-23 22:01:10 +08:00
164078bf42 refactor(action-evaluator): optimize prompt 2026-04-22 15:41:53 +08:00
13d04f85e2 fix(action): correct behavior of resume intervention 2026-04-21 21:38:04 +08:00
3a5d0f1cb4 refactor(action): optimize builtin actions descriptions and param explanations 2026-04-21 21:31:23 +08:00
aa05d3817b fix(action-evaluator): fix content of available-meta-actions block 2026-04-21 17:23:08 +08:00
45f7d1c51e refactor(action): optimize resolved context domains 2026-04-21 17:21:59 +08:00
3d56966381 fix(action): fix unexpected scheduled action losing 2026-04-21 17:12:44 +08:00
de340029c6 refactor(action): optimize prompts 2026-04-21 16:56:24 +08:00
96101de227 refactor(trace): trace full snapshot of context workspace on changes 2026-04-21 16:48:21 +08:00
2927cb2b6f fix(config): fix config reloading errors that caused by using wrong relative paths to load config file 2026-04-21 15:07:35 +08:00
4af8feb178 fix(memory): enhance null-safe in memory-related modules 2026-04-21 09:18:49 +08:00
43c2c648ac refactor(framework): support inject Standalone module into Sub module 2026-04-21 09:05:51 +08:00
a64c8f6c97 feat(exception): trace exception log in LogExceptionReporter 2026-04-21 08:49:05 +08:00
406b7ba831 refactor(action): update watcher self-turn message for immediate action 2026-04-21 08:48:25 +08:00
9c902e68d0 fix(dto): add NoArgsConstructor to support formatted chat 2026-04-20 23:10:39 +08:00
4e894384bf refactor(block): optimize state action triggered block fading factor 2026-04-20 23:08:23 +08:00
a5cee79a8f fix(state): enable first-time state file save and block overwrites until explicit load 2026-04-20 22:40:39 +08:00
d1da99c44d fix(action): correct action chain fixing error 2026-04-20 22:26:31 +08:00
d90c514159 fix(communication): fix errors while import external xml node into input xml 2026-04-20 16:40:36 +08:00
ac715602a6 refactor(gateway): print warn log while receiving invalid input 2026-04-20 15:36:23 +08:00
e1a5a07e2a Merge branch 'codex-review-localrunnerclient-v2' 2026-04-20 14:48:51 +08:00
9108d1db46 feat(gateway): support assign hostname on websocket gateway 2026-04-20 14:38:58 +08:00
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
95a3f782e6 Merge branch 'codex-review-localrunnerclient-v2' 2026-04-20 14:06:03 +08:00
6ec3bfcc9b fix(model): correct deserialization behavior of model provider config 2026-04-19 18:52:57 +08:00
b4d6be849b fix(agent): run system exit after agent launch failed 2026-04-19 18:52:10 +08:00
a9e41eb4c7 fix(config): repair unexpected exiting in method initAll 2026-04-19 18:51:23 +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
7ce7461f79 refactor(exception): correct exception report print message 2026-04-19 17:26:42 +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
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
fea7f9c81f PerceiveSelector、PeiceiveUpdater 流程图制作完毕 2025-11-11 08:47:21 +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
5419722c40 更新文档内容 2025-11-06 11:17:25 +08:00
31ebee3ded 制作了整体流程图 2025-11-06 11:14:37 +08:00
550 changed files with 32044 additions and 14774 deletions

137
.github/workflows/release-core.yml vendored Normal file
View File

@@ -0,0 +1,137 @@
name: Release Partner Core
on:
workflow_dispatch:
inputs:
tag:
description: "Core release tag, for example release-core/0.5.0"
required: true
type: string
push:
tags:
- "release-core/*"
permissions:
contents: write
jobs:
release-core:
runs-on: ubuntu-latest
steps:
- name: Resolve release metadata
id: release
shell: bash
run: |
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
TAG="${{ inputs.tag }}"
else
TAG="${GITHUB_REF_NAME}"
fi
VERSION="${TAG#release-core/}"
VERSION="${VERSION#v}"
ENCODED_TAG="${TAG//\//%2F}"
ASSET_NAME="partner-core-${VERSION}.jar"
ASSET_URL="https://github.com/slhaf/Partner/releases/download/${ENCODED_TAG}/${ASSET_NAME}"
echo "tag=${TAG}" >> "$GITHUB_OUTPUT"
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
echo "asset_name=${ASSET_NAME}" >> "$GITHUB_OUTPUT"
echo "asset_url=${ASSET_URL}" >> "$GITHUB_OUTPUT"
echo "Core release tag: ${TAG}"
echo "Core release version: ${VERSION}"
echo "Core release asset: ${ASSET_NAME}"
- name: Checkout release source
uses: actions/checkout@v4
with:
ref: ${{ steps.release.outputs.tag }}
- name: Set up Java 21
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: "21"
- name: Build Partner Core
run: |
mvn -B -DskipTests=true -pl Partner-Core -am package
- name: Prepare release artifact
shell: bash
run: |
mkdir -p dist
SOURCE_JAR="Partner-Core/target/partner-core-${{ steps.release.outputs.version }}.jar"
if [ ! -f "$SOURCE_JAR" ]; then
echo "Expected artifact not found: $SOURCE_JAR"
echo "Available Partner-Core target files:"
find Partner-Core/target -maxdepth 1 -type f -name "*.jar" -print
exit 1
fi
cp "$SOURCE_JAR" "dist/${{ steps.release.outputs.asset_name }}"
ls -lh dist
- name: Create GitHub Release
shell: bash
run: |
if gh release view "${{ steps.release.outputs.tag }}" >/dev/null 2>&1; then
echo "Release ${{ steps.release.outputs.tag }} already exists."
exit 1
fi
gh release create "${{ steps.release.outputs.tag }}" \
"dist/${{ steps.release.outputs.asset_name }}" \
--title "Partner Core ${{ steps.release.outputs.version }}" \
--notes "Partner Core ${{ steps.release.outputs.version }}"
env:
GH_TOKEN: ${{ github.token }}
- name: Checkout master for registry update
uses: actions/checkout@v4
with:
ref: master
path: registry-worktree
- name: Update latestRelease
working-directory: registry-worktree
run: |
python3 - <<'PY'
import json
from pathlib import Path
version = "${{ steps.release.outputs.version }}"
url = "${{ steps.release.outputs.asset_url }}"
index_path = Path("registry/index.json")
index = json.loads(index_path.read_text(encoding="utf-8"))
index["partner"]["latestRelease"] = {
"url": url,
"version": version
}
index_path.write_text(
json.dumps(index, ensure_ascii=False, indent=2) + "\n",
encoding="utf-8"
)
PY
- name: Commit registry update
working-directory: registry-worktree
run: |
if git diff --quiet registry/index.json; then
echo "No latestRelease changes."
exit 0
fi
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add registry/index.json
git commit -m "chore(registry): update latest core release to ${{ steps.release.outputs.tag }}"
git push origin HEAD:master

156
.github/workflows/release-ctl.yml vendored Normal file
View File

@@ -0,0 +1,156 @@
name: Release PartnerCtl
on:
workflow_dispatch:
inputs:
tag:
description: "Ctl release tag, for example release-ctl/0.5.0"
required: true
type: string
push:
tags:
- "release-ctl/*"
permissions:
contents: write
jobs:
build:
name: Build ${{ matrix.platform }}
strategy:
fail-fast: false
matrix:
include:
- platform: linux-x64
runner: ubuntu-latest
binaryPath: PartnerCtl/target/partnerctl
assetSuffix: linux-x64
- platform: linux-arm64
runner: ubuntu-24.04-arm
binaryPath: PartnerCtl/target/partnerctl
assetSuffix: linux-arm64
- platform: windows-x64
runner: windows-latest
binaryPath: PartnerCtl/target/partnerctl.exe
assetSuffix: windows-x64.exe
runs-on: ${{ matrix.runner }}
steps:
- name: Resolve release metadata
id: release
shell: bash
run: |
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
TAG="${{ inputs.tag }}"
else
TAG="${GITHUB_REF_NAME}"
fi
VERSION="${TAG#release-ctl/}"
VERSION="${VERSION#v}"
ASSET_NAME="partnerctl-${VERSION}-${{ matrix.assetSuffix }}"
echo "tag=${TAG}" >> "$GITHUB_OUTPUT"
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
echo "asset_name=${ASSET_NAME}" >> "$GITHUB_OUTPUT"
echo "Ctl release tag: ${TAG}"
echo "Ctl release version: ${VERSION}"
echo "Ctl release asset: ${ASSET_NAME}"
- name: Checkout release source
uses: actions/checkout@v4
with:
ref: ${{ steps.release.outputs.tag }}
- name: Set up GraalVM 21
uses: graalvm/setup-graalvm@v1
with:
distribution: graalvm-community
java-version: "21"
github-token: ${{ github.token }}
- name: Build partnerctl native image
run: mvn -B -DskipTests=true -pl PartnerCtl -am package native:compile
- name: Prepare release artifact
shell: bash
run: |
mkdir -p dist
BINARY_PATH="${{ matrix.binaryPath }}"
ASSET_PATH="dist/${{ steps.release.outputs.asset_name }}"
if [ ! -f "$BINARY_PATH" ]; then
echo "Expected native binary not found: $BINARY_PATH"
echo "Available PartnerCtl target files:"
find PartnerCtl/target -maxdepth 2 -type f -print
exit 1
fi
cp "$BINARY_PATH" "$ASSET_PATH"
if [[ "${{ matrix.platform }}" == linux-* ]]; then
chmod +x "$ASSET_PATH"
fi
ls -lh dist
- name: Upload release artifact
uses: actions/upload-artifact@v4
with:
name: ${{ steps.release.outputs.asset_name }}
path: dist/${{ steps.release.outputs.asset_name }}
if-no-files-found: error
retention-days: 1
release:
name: Create GitHub Release
needs: build
runs-on: ubuntu-latest
steps:
- name: Resolve release metadata
id: release
shell: bash
run: |
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
TAG="${{ inputs.tag }}"
else
TAG="${GITHUB_REF_NAME}"
fi
VERSION="${TAG#release-ctl/}"
VERSION="${VERSION#v}"
echo "tag=${TAG}" >> "$GITHUB_OUTPUT"
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
echo "Ctl release tag: ${TAG}"
echo "Ctl release version: ${VERSION}"
- name: Download release artifacts
uses: actions/download-artifact@v4
with:
path: dist
merge-multiple: true
- name: Show release artifacts
run: |
ls -lh dist
- name: Create GitHub Release
shell: bash
run: |
if gh release view "${{ steps.release.outputs.tag }}" >/dev/null 2>&1; then
echo "Release ${{ steps.release.outputs.tag }} already exists."
exit 1
fi
gh release create "${{ steps.release.outputs.tag }}" \
dist/* \
--title "PartnerCtl ${{ steps.release.outputs.version }}" \
--notes "PartnerCtl ${{ steps.release.outputs.version }}"
env:
GH_TOKEN: ${{ github.token }}

View File

@@ -1,36 +0,0 @@
name: Sync from Gitea
# 1. 给 GITHUB_TOKEN 开写权限
permissions:
contents: write
on:
schedule:
- cron: '*/30 * * * *'
workflow_dispatch:
jobs:
sync:
runs-on: ubuntu-latest
steps:
- name: 配置 Git 用户
run: |
git config --global user.name "Gitea Sync Bot"
git config --global user.email "slhafzjw@slhaf.work"
- name: 关闭全局 SSL 校验
run: git config --global http.sslVerify false
- name: Clone from Gitea (mirror)
run: |
git clone --mirror \
https://${{ secrets.GITEA_USER }}:${{ secrets.GITEA_TOKEN }}@${{ secrets.GITEA_URL }} \
gitea-mirror
- name: Push to GitHub
run: |
cd gitea-mirror
# 明确推到名为 "github" 的 remote
git remote add github \
https://${{ github.repository_owner }}:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git
git push --mirror github

View File

@@ -0,0 +1,137 @@
name: Test PartnerCtl Native Build
on:
workflow_dispatch:
inputs:
platform:
description: "Target platform to test"
required: true
default: "windows-x64"
type: choice
options:
- windows-x64
- linux-x64
- linux-arm64
permissions:
contents: read
jobs:
test-linux-x64:
name: Test linux-x64
if: ${{ inputs.platform == 'linux-x64' }}
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up GraalVM 21
uses: graalvm/setup-graalvm@v1
with:
distribution: graalvm-community
java-version: "21"
github-token: ${{ github.token }}
- name: Build partnerctl native image
run: mvn -B -DskipTests=true -pl PartnerCtl -am package native:compile
- name: Check Linux output
shell: bash
run: |
if [ ! -f "PartnerCtl/target/partnerctl" ]; then
echo "Expected native binary not found: PartnerCtl/target/partnerctl"
echo "Available PartnerCtl target files:"
find PartnerCtl/target -maxdepth 2 -type f -print
exit 1
fi
chmod +x PartnerCtl/target/partnerctl
./PartnerCtl/target/partnerctl --help
- name: Upload test artifact
uses: actions/upload-artifact@v4
with:
name: partnerctl-linux-x64-test
path: PartnerCtl/target/partnerctl
if-no-files-found: error
retention-days: 1
test-linux-arm64:
name: Test linux-arm64
if: ${{ inputs.platform == 'linux-arm64' }}
runs-on: ubuntu-24.04-arm
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up GraalVM 21
uses: graalvm/setup-graalvm@v1
with:
distribution: graalvm-community
java-version: "21"
github-token: ${{ github.token }}
- name: Build partnerctl native image
run: mvn -B -DskipTests=true -pl PartnerCtl -am package native:compile
- name: Check Linux output
shell: bash
run: |
if [ ! -f "PartnerCtl/target/partnerctl" ]; then
echo "Expected native binary not found: PartnerCtl/target/partnerctl"
echo "Available PartnerCtl target files:"
find PartnerCtl/target -maxdepth 2 -type f -print
exit 1
fi
chmod +x PartnerCtl/target/partnerctl
./PartnerCtl/target/partnerctl --help
- name: Upload test artifact
uses: actions/upload-artifact@v4
with:
name: partnerctl-linux-arm64-test
path: PartnerCtl/target/partnerctl
if-no-files-found: error
retention-days: 1
test-windows-x64:
name: Test windows-x64
if: ${{ inputs.platform == 'windows-x64' }}
runs-on: windows-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up GraalVM 21
uses: graalvm/setup-graalvm@v1
with:
distribution: graalvm-community
java-version: "21"
github-token: ${{ github.token }}
- name: Build partnerctl native image
run: mvn -B -DskipTests=true -pl PartnerCtl -am package native:compile
- name: Check Windows output
shell: pwsh
run: |
if (!(Test-Path "PartnerCtl/target/partnerctl.exe")) {
Write-Host "Expected native binary not found: PartnerCtl/target/partnerctl.exe"
Write-Host "Available PartnerCtl target files:"
Get-ChildItem -Recurse PartnerCtl/target | Select-Object FullName
throw "partnerctl.exe not found"
}
.\PartnerCtl\target\partnerctl.exe --help
- name: Upload test artifact
uses: actions/upload-artifact@v4
with:
name: partnerctl-windows-x64-test
path: PartnerCtl/target/partnerctl.exe
if-no-files-found: error
retention-days: 1

View File

@@ -0,0 +1,70 @@
name: Update Latest Buildable
on:
workflow_dispatch:
inputs:
ref:
description: "Buildable ref, for example buildable/v0.5.0"
required: true
type: string
push:
tags:
- "buildable/*"
permissions:
contents: write
jobs:
update-latest-buildable:
runs-on: ubuntu-latest
steps:
- name: Resolve buildable ref
id: buildable
run: |
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
echo "ref=${{ inputs.ref }}" >> "$GITHUB_OUTPUT"
else
echo "ref=${GITHUB_REF_NAME}" >> "$GITHUB_OUTPUT"
fi
- name: Checkout master
uses: actions/checkout@v4
with:
ref: master
- name: Update latestBuildable
run: |
python3 - <<'PY'
import json
from pathlib import Path
ref = "${{ steps.buildable.outputs.ref }}"
index_path = Path("registry/index.json")
index = json.loads(index_path.read_text(encoding="utf-8"))
index["partner"]["latestBuildable"] = {
"url": "https://github.com/slhaf/Partner.git",
"ref": ref
}
index_path.write_text(
json.dumps(index, ensure_ascii=False, indent=2) + "\n",
encoding="utf-8"
)
PY
- name: Commit registry update
run: |
if git diff --quiet registry/index.json; then
echo "No latestBuildable changes."
exit 0
fi
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add registry/index.json
git commit -m "chore(registry): update latest buildable to ${{ steps.buildable.outputs.ref }}"
git push

View File

@@ -0,0 +1,38 @@
name: Update Module Index
on:
push:
branches:
- master
paths:
- "registry/modules/*.json"
- "registry/index.json"
- "scripts/update_module_index.py"
- "update-module-index.yml"
permissions:
contents: write
jobs:
update-registry-index:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Update module index
run: python3 scripts/update_module_index.py
- name: Commit updated index
run: |
if git diff --quiet registry/index.json; then
echo "No module index changes"
exit 0
fi
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add registry/index.json
git commit -m "chore: update registry index"
git push

11
.gitignore vendored
View File

@@ -4,10 +4,7 @@ target/
!**/src/test/**/target/
### IntelliJ IDEA ###
.idea/modules.xml
.idea/jarRepositories.xml
.idea/compiler.xml
.idea/libraries/
.idea/
*.iws
*.iml
*.ipr
@@ -58,3 +55,9 @@ build/
/Partner-Main/data/
/AGENTS.md
/.serena/
/Partner-Core/data/
/.ai/mcp/mcp.json
/.codex
# Maven / build outputs
dependency-reduced-pom.xml

View File

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

25
.idea/encodings.xml generated
View File

@@ -1,17 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding">
<file url="file://$PROJECT_DIR$/Partner-Api/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/java" 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-Main/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-Main/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/resources" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/Partner-Core/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-Core/src/main/java/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-External-Modules/Partner-Onebot-Adapter/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/Partner-External-Modules/Partner-Onebot-Adapter/src/main/resources" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/Partner-External-Modules/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/Partner-External-Modules/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-Interaction-Api/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/Partner-Interaction-Api/src/main/resources" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/PartnerCtl/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/PartnerCtl/src/main/resources" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
</component>

45
.idea/misc.xml generated
View File

@@ -1,25 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="EntryPointsManager">
<list size="15">
<list size="21">
<item index="0" class="java.lang.String" itemvalue="lombok.Data" />
<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.Capability" />
<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.agent.factory.capability.annotation.CapabilityMethod" />
<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.module.annotation.AfterExecute" />
<item index="8" class="java.lang.String" itemvalue="work.slhaf.partner.api.agent.factory.module.annotation.AgentModule" />
<item index="9" class="java.lang.String" itemvalue="work.slhaf.partner.api.agent.factory.module.annotation.AgentSubModule" />
<item index="10" class="java.lang.String" itemvalue="work.slhaf.partner.api.agent.factory.module.annotation.BeforeExecute" />
<item index="11" class="java.lang.String" itemvalue="work.slhaf.partner.api.agent.factory.module.annotation.Init" />
<item index="12" class="java.lang.String" itemvalue="work.slhaf.partner.api.capability.annotation.CapabilityMethod" />
<item index="13" class="java.lang.String" itemvalue="work.slhaf.partner.api.capability.annotation.CoordinateManager" />
<item index="14" class="java.lang.String" itemvalue="work.slhaf.partner.api.register.capability.annotation.Capability" />
<item index="2" class="java.lang.String" itemvalue="picocli.CommandLine.Command" />
<item index="3" class="java.lang.String" itemvalue="picocli.CommandLine.Mixin" />
<item index="4" class="java.lang.String" itemvalue="work.slhaf.partner.api.agent.factory.capability.annotation.Capability" />
<item index="5" class="java.lang.String" itemvalue="work.slhaf.partner.api.agent.factory.capability.annotation.CapabilityCore" />
<item index="6" class="java.lang.String" itemvalue="work.slhaf.partner.api.agent.factory.capability.annotation.CapabilityMethod" />
<item index="7" class="java.lang.String" itemvalue="work.slhaf.partner.api.agent.factory.capability.annotation.CoordinateManager" />
<item index="8" class="java.lang.String" itemvalue="work.slhaf.partner.api.agent.factory.capability.annotation.Coordinated" />
<item index="9" class="java.lang.String" itemvalue="work.slhaf.partner.api.agent.factory.component.annotation.Init" />
<item index="10" class="java.lang.String" itemvalue="work.slhaf.partner.api.agent.factory.module.annotation.AfterExecute" />
<item index="11" class="java.lang.String" itemvalue="work.slhaf.partner.api.agent.factory.module.annotation.AgentRunningModule" />
<item index="12" class="java.lang.String" itemvalue="work.slhaf.partner.api.agent.factory.module.annotation.AgentSubModule" />
<item index="13" class="java.lang.String" itemvalue="work.slhaf.partner.api.agent.factory.module.annotation.BeforeExecute" />
<item index="14" class="java.lang.String" itemvalue="work.slhaf.partner.api.agent.factory.module.annotation.Init" />
<item index="15" class="java.lang.String" itemvalue="work.slhaf.partner.api.capability.annotation.CapabilityMethod" />
<item index="16" class="java.lang.String" itemvalue="work.slhaf.partner.api.capability.annotation.CoordinateManager" />
<item index="17" class="java.lang.String" itemvalue="work.slhaf.partner.api.register.capability.annotation.Capability" />
<item index="18" class="java.lang.String" itemvalue="work.slhaf.partner.framework.agent.factory.capability.annotation.CapabilityCore" />
<item index="19" class="java.lang.String" itemvalue="work.slhaf.partner.framework.agent.factory.capability.annotation.CapabilityMethod" />
<item index="20" class="java.lang.String" itemvalue="work.slhaf.partner.framework.agent.factory.component.annotation.AgentComponent" />
</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 name="ExternalStorageConfigurationManager" enabled="true" />
@@ -30,6 +40,13 @@
<option value="$PROJECT_DIR$/PartnerExecutor/pom.xml" />
</list>
</option>
<option name="ignoredFiles">
<set>
<option value="$PROJECT_DIR$/Partner-Common/pom.xml" />
<option value="$PROJECT_DIR$/Partner-SandboxRunner/pom.xml" />
<option value="$PROJECT_DIR$/Partner-Test-Demo/pom.xml" />
</set>
</option>
</component>
<component name="PWA">
<option name="enabled" value="true" />

View File

@@ -1,29 +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/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-Api</artifactId>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
<exclusions>
<exclusion>
<artifactId>hamcrest-core</artifactId>
<groupId>org.hamcrest</groupId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<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>

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,156 +0,0 @@
package work.slhaf.partner.api.agent;
import lombok.extern.slf4j.Slf4j;
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.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* <h2>Agent 启动入口</h2>
* 详细启动流程请参阅{@link AgentRegisterFactory}
*/
@Slf4j
public final class Agent {
public static AgentConfigManagerStep newAgent(Class<?> clazz) {
if (clazz == null) {
throw new AgentLaunchFailedException("Agent class 和 interaction flow context 不能为 null");
}
return new AgentApp(clazz);
}
public interface AgentConfigManagerStep {
AgentGatewayStep setAgentConfigManager(Class<? extends AgentConfigManager> agentConfigManager);
}
public interface AgentGatewayStep {
AgentStep setGateway(Class<? extends AgentGateway> gateway);
}
public interface AgentStep {
AgentStep addBeforeLaunchRunners(Runnable... runners);
AgentStep addAfterLaunchRunners(Runnable... runners);
AgentStep setAgentExceptionCallback(Class<? extends AgentExceptionCallback> agentExceptionCallback);
AgentStep addScanPackage(String packageName);
AgentStep addScanDir(String externalPackagePath);
void launch();
}
public static class AgentApp implements AgentStep, AgentGatewayStep, AgentConfigManagerStep {
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 Class<? extends AgentConfigManager> agentConfigManagerClass;
private Class<? extends AgentGateway> gatewayClass;
private Class<? extends AgentExceptionCallback> agentExceptionCallbackClass;
private final CountDownLatch latch = new CountDownLatch(1);
private AgentApp(Class<?> clazz) {
this.applicationClass = clazz;
}
@Override
public AgentStep setGateway(Class<? extends AgentGateway> gateway) {
this.gatewayClass = 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 AgentGatewayStep setAgentConfigManager(Class<? extends AgentConfigManager> agentConfigManager) {
this.agentConfigManagerClass = agentConfigManager;
return this;
}
@Override
public AgentStep setAgentExceptionCallback(Class<? extends AgentExceptionCallback> agentExceptionCallback) {
agentExceptionCallbackClass = 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() {
beforeLaunch();
AgentRegisterFactory.launch(applicationClass.getPackageName());
afterLaunch();
}
private void afterLaunch() {
try {
this.gateway = gatewayClass.getDeclaredConstructor().newInstance();
executorService.execute(() -> {
gateway.launch();
latch.countDown();
log.info("Gateway 启动完毕: {}", gatewayClass.getSimpleName());
});
latch.await();
launchRunners(afterLaunchRunners);
log.info("后置任务启动完毕");
} catch (Exception e) {
throw new AgentLaunchFailedException("Agent 后置任务启动失败", e);
}
}
private void beforeLaunch() {
try {
AgentConfigManager.setINSTANCE(agentConfigManagerClass.getDeclaredConstructor().newInstance());
log.info("配置管理器设置完毕: {}",agentConfigManagerClass.getSimpleName());
GlobalExceptionHandler.setExceptionCallback(agentExceptionCallbackClass.getDeclaredConstructor().newInstance());
log.info("异常处理回调设置完毕: {}",agentExceptionCallbackClass.getSimpleName());
launchRunners(beforeLaunchRunners);
log.info("前置任务启动完毕");
} catch (Exception e) {
throw new AgentLaunchFailedException("Agent 前置任务启动失败", e);
}
}
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,104 +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.config.AgentConfigManager;
import work.slhaf.partner.api.agent.runtime.data.AgentContext;
import work.slhaf.partner.api.agent.runtime.interaction.flow.AgentRunningFlow;
import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
/**
* <h2>Agent 注册工厂</h2>
*
* <p>
* 具体流程依次按照 {@link AgentRegisterFactory#launch(String)} 方法顺序执行,最终将执行模块列表对应实例交给 {@link AgentConfigManager} ,传递给 {@link AgentRunningFlow} 针对交互做出调用
* <p/>
*/
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. 注册并检查Module
new ModuleCheckFactory().execute(registerContext);
new ModuleRegisterFactory().execute(registerContext);
//2. 为module通过动态代理添加PostHook逻辑并进行实例化
new ModuleProxyFactory().execute(registerContext);
//3. 加载检查Capability层内容后进行能力层的内容注册
new CapabilityCheckFactory().execute(registerContext);
new CapabilityRegisterFactory().execute(registerContext);
//. 先一步注入Capability,避免因前hook逻辑存在针对能力的引用而报错
new CapabilityInjectFactory().execute(registerContext);
//. 执行模块PreHook逻辑
new ModuleInitHookExecuteFactory().execute(registerContext);
List<MetaModule> moduleList = registerContext.getModuleFactoryContext().getAgentModuleList();
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,271 +0,0 @@
package work.slhaf.partner.api.agent.factory.capability;
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.capability.annotation.*;
import work.slhaf.partner.api.agent.factory.capability.exception.*;
import work.slhaf.partner.api.agent.factory.context.AgentRegisterContext;
import work.slhaf.partner.api.agent.factory.context.CapabilityFactoryContext;
import work.slhaf.partner.api.agent.factory.module.annotation.AgentModule;
import work.slhaf.partner.api.agent.factory.module.annotation.AgentSubModule;
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.isAssignableFromAnnotation;
import static work.slhaf.partner.api.agent.util.AgentUtil.methodSignature;
/**
* <h2>Agent启动流程 4</h2>
*
* <p>负责通过反射收集 {@link Capability} 和 {@link CapabilityCore} 注解所在类,并判断是否存在被错误忽略的方法</p>
*
* <ol>
* <li>
* <p>{@link CapabilityCheckFactory#loadCoresAndCapabilities()}</p>
* 通过反射收集 {@link Capability} 和 {@link CapabilityCore} 注解所在类为对应集合
* </li>
* <li>
* <p>{@link CapabilityCheckFactory#checkCountAndCapabilities()}</p>
* 检测 {@link Capability} 与 {@link CapabilityCore} 的数量、对应的能力是否相等。每一个core都将对应一个capability并通过value属性进行匹配
* </li>
* <li>
* <p>{@link CapabilityCheckFactory#checkCapabilityMethods()}</p>
* 检测在 {@link Capability} 与 {@link CapabilityCore} 中是否存在对方尚未实现/注册的方法
* </li>
* <li>
* <p>{@link CapabilityCheckFactory#checkCoordinatedMethods()}</p>
* 检查是否包含协调方法({@link ToCoordinated}),如果存在,则进一步检查在 {@link CoordinateManager} 所注类中是否有提供对应的实现
* </li>
* <li>
* <p>{@link CapabilityCheckFactory#checkInjectCapability()}</p>
* 检查 {@link InjectCapability} 注解是否只用在 {@link CapabilityHolder} 所标识类的字段上。{@link AgentModule} 与 {@link AgentSubModule} 已经被 {@link CapabilityHolder} 标注
* </li>
* </ol>
*
* <p>下一步流程请参阅{@link CapabilityRegisterFactory}</p>
*/
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() {
loadCoresAndCapabilities();
checkCountAndCapabilities();
checkCapabilityMethods();
checkCoordinatedMethods();
checkCoordinatedManager();
checkInjectCapability();
}
private void checkCoordinatedManager() {
reflections.getTypesAnnotatedWith(CoordinateManager.class)
.stream()
.filter(ClassUtil::isNormalClass)
.forEach(managerClass -> {
try {
if (!managerClass.getDeclaredConstructor().canAccess(null)) {
throw new CapabilityCheckFailedException("CoordinateManager 所注类的无参构造方法未公开!");
}
} catch (NoSuchMethodException e) {
throw new CapabilityCheckFailedException("CoordinateManager 所注类缺少无参构造方法!");
}
});
}
private void loadCoresAndCapabilities() {
cores.addAll(reflections.getTypesAnnotatedWith(CapabilityCore.class));
capabilities.addAll(reflections.getTypesAnnotatedWith(Capability.class));
}
/**
* 检查<code>@InjectCapability</code>注解是否只用在<code>@CapabilityHolder</code>所标识类的字段上
*/
private void checkInjectCapability() {
reflections.getFieldsAnnotatedWith(InjectCapability.class).forEach(field -> {
Class<?> declaringClass = field.getDeclaringClass();
if (!isAssignableFromAnnotation(declaringClass, CapabilityHolder.class)) {
throw new UnMatchedCapabilityException("InjectCapability 注解只能用于 CapabilityHolder 注解所在类,检查该类是否使用了@CapabilityHolder注解或者受其标注的注解或父类: " + declaringClass);
}
});
}
/**
* 检查是否包含协调方法,如果存在,则进一步检查是否存在<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,88 +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 work.slhaf.partner.api.agent.factory.module.ModuleInitHookExecuteFactory;
import work.slhaf.partner.api.agent.factory.module.annotation.AgentModule;
import work.slhaf.partner.api.agent.factory.module.annotation.AgentSubModule;
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;
/**
* <h2>Agent启动流程 6</h2>
*
* <p>负责执行 {@link Capability} 的注入逻辑。</p>
*
* <p>实现方式:</p>
* <ol>
* <li>通过动态代理,为 {@link AgentModule} 与 {@link AgentSubModule} 中待注入的
* <b>能力接口</b> 类型(即 {@link Capability} 标注的接口类)生成代理对象。
* </li>
* <li>在代理对象内部,根据调用方法的签名确定路由,将调用转发至对应的具体函数。
* </li>
* <li>通过此机制,实现了 {@link Capability} 单一语义层面上普通方法与协调方法的统一入口。
* </li>
* </ol>
*
* <p>下一步流程请参阅 {@link ModuleInitHookExecuteFactory}</p>
*/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,211 +0,0 @@
package work.slhaf.partner.api.agent.factory.capability;
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.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 work.slhaf.partner.api.agent.factory.module.annotation.AgentModule;
import work.slhaf.partner.api.agent.factory.module.annotation.AgentSubModule;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
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 java.util.stream.Collectors;
import static work.slhaf.partner.api.agent.util.AgentUtil.methodSignature;
/**
* <h2>Agent启动流程 5</h2>
*
* <p>
* 负责收集注解 {@link Capability} 和 {@link CapabilityCore} 标识的类并生成函数路由表、创建core、capability实例以及放入instanceMap供后续进行注入操作
* </p>
*
* <ol>
* <li>
* <p>{@link CapabilityRegisterFactory#setCoreInstances()}</p>
* 通过反射调用无参构造函数创建core实例并将实例放入instanceMap供后续使用
* </li>
* <li>
* <p>{@link CapabilityRegisterFactory#generateRouterTable()}</p>
* 生成函数路由表:
* <ul>
* <li>
* <p>{@link CapabilityRegisterFactory#generateMethodsRouterTable()}</p>
* 生成普通方法对应的函数路由表
* </li>
* <li>
* <p>{@link CapabilityRegisterFactory#generateCoordinatedMethodsRouterTable()}</p>
* 生成协调方法对应的函数路由表
* </li>
* </ul>
* </li>
* <li>
* 函数路由表生成完毕、core实例创建完毕之后将交由下一工厂完成能力(Capability)注入操作,注入到 {@link AgentModule} 与 {@link AgentSubModule} 对应的实例中
* </li>
* </ol>
*
* <p>下一步流程请参阅{@link CapabilityInjectFactory}</p>
*/
public 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> coreInstances;
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();
coreInstances = factoryContext.getCapabilityCoreInstances();
cores = factoryContext.getCores();
capabilities = factoryContext.getCapabilities();
capabilityHolderInstances = factoryContext.getCapabilityHolderInstances();
}
@Override
protected void run() {
setCapabilityHolderInstances();
setCoreInstances();
generateRouterTable();
}
private void setCapabilityHolderInstances() {
Set<Class<?>> collect = reflections.getTypesAnnotatedWith(CapabilityHolder.class).stream()
.filter(ClassUtil::isNormalClass)
.filter(clazz -> !capabilityHolderInstances.containsKey(clazz))
.collect(Collectors.toSet());
for (Class<?> clazz : collect) {
try {
Constructor<?> constructor = clazz.getDeclaredConstructor();
if (constructor.canAccess(null)) {
throw new CapabilityFactoryExecuteFailedException("缺少无参构造方法的类: " + clazz);
}
Object o = constructor.newInstance();
capabilityHolderInstances.put(clazz, o);
} catch (Exception e) {
throw new CapabilityFactoryExecuteFailedException("创建代理对象失败: " + clazz, e);
}
}
}
/**
* 生成函数路由表
*/
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();
setCores(instance, c);
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 setCores(Object cmInstance, Class<?> cmClazz) throws IllegalAccessException {
for (Field field : cmClazz.getFields()) {
if (field.getType().isAnnotationPresent(CapabilityCore.class)) {
field.setAccessible(true);
field.set(cmInstance, coreInstances.get(field.getType()));
}
}
}
/**
* 扫描`@Capability`与`@CapabilityMethod`注解的类与方法
* 将`capabilityValue.methodSignature`作为key,函数对象为通过反射拿到的core实例对应的方法
*/
private void generateMethodsRouterTable() {
cores.forEach(core -> Arrays.stream(core.getMethods())
.filter(method -> method.isAnnotationPresent(CapabilityMethod.class))
.forEach(method -> {
Function<Object[], Object> function = args -> {
try {
return method.invoke(coreInstances.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 setCoreInstances() {
try {
for (Class<?> core : cores) {
Constructor<?> constructor = core.getDeclaredConstructor();
constructor.setAccessible(true);
coreInstances.put(core, constructor.newInstance());
}
} catch (InvocationTargetException | NoSuchMethodException | InstantiationException |
IllegalAccessException e) {
throw new CoreInstancesCreateFailedExceptionCapability("core实例创建失败");
}
}
}

View File

@@ -1,14 +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;
/**
* Core的协调类该注解的实现类中如果存在任何{@link CapabilityCore}实例的引用,都将被自动注入
*/
@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,77 +0,0 @@
package work.slhaf.partner.api.agent.factory.config;
import lombok.extern.slf4j.Slf4j;
import work.slhaf.partner.api.agent.factory.AgentBaseFactory;
import work.slhaf.partner.api.agent.factory.config.exception.ConfigNotExistException;
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.context.AgentRegisterContext;
import work.slhaf.partner.api.agent.factory.context.ConfigFactoryContext;
import work.slhaf.partner.api.agent.factory.module.ModuleCheckFactory;
import work.slhaf.partner.api.agent.runtime.config.AgentConfigManager;
import work.slhaf.partner.api.agent.runtime.config.FileAgentConfigManager;
import work.slhaf.partner.api.chat.pojo.Message;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* <h2>Agent启动流程 0</h2>
* <p>
* 通过指定的 {@link AgentConfigManager} 或者默认的 {@link FileAgentConfigManager} 加载配置文件
* <p/>
*
* <p>下一步流程请参阅{@link ModuleCheckFactory}</p>
*/
@Slf4j
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 FileAgentConfigManager());
}
agentConfigManager = AgentConfigManager.INSTANCE;
}
@Override
protected void run() {
agentConfigManager.load();
modelConfigMap.putAll(agentConfigManager.getModelConfigMap());
modelPromptMap.putAll(agentConfigManager.getModelPromptMap());
check();
}
/**
* 对模型Config与Prompt分别进行检验,除了都必须包含default外还需要确保数量、key一致毕竟是模型配置与提示词
*/
private void check() {
log.info("执行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("存在未被提示词包含的模型配置,该配置将无法生效!");
}
//检查提示词数量与`ActivateModel`的实现数量是否一致
log.info("检测完毕.");
}
}

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,18 +0,0 @@
package work.slhaf.partner.api.agent.factory.context;
import lombok.Data;
import java.util.HashMap;
import java.util.HashSet;
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 = new HashSet<>();
private Set<Class<?>> capabilities = new HashSet<>();
}

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,14 +0,0 @@
package work.slhaf.partner.api.agent.factory.context;
import lombok.Data;
import work.slhaf.partner.api.agent.factory.module.pojo.MetaModule;
import work.slhaf.partner.api.agent.factory.module.pojo.MetaSubModule;
import java.util.ArrayList;
import java.util.List;
@Data
public class ModuleFactoryContext {
private List<MetaModule> agentModuleList = new ArrayList<>();
private List<MetaSubModule> agentSubModuleList = 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,227 +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.AgentSubModule;
import work.slhaf.partner.api.agent.factory.module.annotation.BeforeExecute;
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;
import static work.slhaf.partner.api.agent.util.AgentUtil.getMethodAnnotationTypeSet;
/**
* <h2>Agent启动流程 1</h2>
*
* <p>
* 检查模块部分抽象类与注解、接口的使用方式
* </p>
*
* <ol>
* <li>
* <p>{@link ModuleCheckFactory#annotationAbstractCheck(Set, Class)}</p>
* 所有添加了 {@link AgentModule} 注解的类都将作为Agent的执行模块为规范模块入口都必须实现抽象类: {@link AgentRunningModule}; {@link AgentSubModule} 注解所在类则必须实现 {@link AgentRunningSubModule}
* </li>
* <li>
* <p>{@link ModuleCheckFactory#moduleConstructorsCheck(Set)}</p>
* 所有 {@link AgentModule} 与 {@link AgentSubModule} 注解所在类都必须具备空参构造方法,初始化逻辑可放在 @Init 注解所处方法中,将在 Capability 与 subModules 注入后才会执行
* </li>
* <li>
* <p>{@link ModuleCheckFactory#activateModelImplCheck()}</p>
* 检查实现了 {@link ActivateModel} 的模块数量、名称与prompt是否一致
* </li>
* </ol>
*
* <p>下一步流程请参阅{@link ModuleRegisterFactory}</p>
*/
public class ModuleCheckFactory extends AgentBaseFactory {
private Reflections reflections;
@Override
protected void setVariables(AgentRegisterContext context) {
reflections = context.getReflections();
}
@Override
protected void run() {
AnnotatedModules annotatedModules = getAnnotatedModules();
ExtendedModules extendedModules = getExtendedModules();
checkIfClassCorresponds(annotatedModules, extendedModules);
//检查注解AgentModule或AgentSubModule所在类是否继承了对应的抽象类
annotationAbstractCheck(annotatedModules.moduleTypes(), AgentRunningModule.class);
annotationAbstractCheck(annotatedModules.subModuleTypes(), AgentRunningSubModule.class);
//检查AgentModule是否具备无参构造方法
moduleConstructorsCheck(annotatedModules.moduleTypes());
moduleConstructorsCheck(annotatedModules.subModuleTypes());
//检查实现了ActivateModel的模块数量、名称与prompt是否一致
activateModelImplCheck();
//检查hook注解所在位置是否正确
hookLocationCheck();
}
private ExtendedModules getExtendedModules() {
Set<Class<?>> moduleTypes = reflections.getSubTypesOf(AgentRunningModule.class)
.stream()
.filter(ClassUtil::isNormalClass)
.collect(Collectors.toSet());
Set<Class<?>> subModuleTypes = reflections.getSubTypesOf(AgentRunningSubModule.class)
.stream()
.filter(ClassUtil::isNormalClass)
.collect(Collectors.toSet());
return new ExtendedModules(moduleTypes, subModuleTypes);
}
private AnnotatedModules getAnnotatedModules() {
Set<Class<?>> moduleTypes = reflections.getTypesAnnotatedWith(AgentModule.class)
.stream()
.filter(ClassUtil::isNormalClass)
.collect(Collectors.toSet());
Set<Class<?>> subModuleTypes = reflections.getTypesAnnotatedWith(AgentSubModule.class)
.stream()
.filter(ClassUtil::isNormalClass)
.collect(Collectors.toSet());
return new AnnotatedModules(moduleTypes, subModuleTypes);
}
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();
}
private void initHookLocationCheck() {
Set<Class<?>> types = getMethodAnnotationTypeSet(AgentModule.class, reflections);
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 annotationAbstractCheck(Set<Class<?>> types, Class<?> clazz) {
for (Class<?> type : types) {
if (type.isAnnotation()) {
continue;
}
if (clazz.isAssignableFrom(type) && ClassUtil.isNormalClass(type)) {
continue;
}
throw new ModuleCheckException("存在未继承AgentInteractionModule.class的AgentModule实现: " + type.getSimpleName());
}
}
private void checkIfClassCorresponds(AnnotatedModules annotatedModules, ExtendedModules extendedModules) {
// 检查是否有被@AgentModule注解但没有继承AgentRunningModule的类
checkSets(annotatedModules.moduleTypes(), extendedModules.moduleTypes(),
"存在被@AgentModule注解但未继承AgentRunningModule的类");
// 检查是否有继承AgentRunningModule但没有被@AgentModule注解的类
checkSets(extendedModules.moduleTypes(), annotatedModules.moduleTypes(),
"存在继承AgentRunningModule但未被@AgentModule注解的类");
// 检查是否有被@AgentSubModule注解但没有继承AgentRunningSubModule的类
checkSets(annotatedModules.subModuleTypes(), extendedModules.subModuleTypes(),
"存在被@AgentSubModule注解但未继承AgentRunningSubModule的类");
// 检查是否有继承AgentRunningSubModule但没有被@AgentSubModule注解的类
checkSets(extendedModules.subModuleTypes(), annotatedModules.subModuleTypes(),
"存在继承AgentRunningSubModule但未被@AgentSubModule注解的类");
}
/**
* 检查源集合中是否有不在目标集合中的元素
* @param source 源集合
* @param target 目标集合
* @param errorMessage 错误信息前缀
*/
private void checkSets(Set<Class<?>> source, Set<Class<?>> target, String errorMessage) {
// 只有在需要时才创建HashSet以节省内存
if (!target.containsAll(source)) {
// 使用流式处理找出差异部分,避免创建完整的中间集合
String classNames = source.stream()
.filter(clazz -> !target.contains(clazz))
.map(Class::getSimpleName)
.limit(10) // 限制显示数量,避免信息泄露
.collect(Collectors.joining(", ", "[", "]"));
throw new ModuleCheckException(errorMessage + ": " + classNames);
}
}
private record AnnotatedModules(Set<Class<?>> moduleTypes, Set<Class<?>> subModuleTypes) {
}
private record ExtendedModules(Set<Class<?>> moduleTypes, Set<Class<?>> subModuleTypes) {
}
}

View File

@@ -1,97 +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.AgentRegisterFactory;
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.BaseMetaModule;
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.factory.module.pojo.MetaSubModule;
import work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts.AgentRunningModule;
import work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts.AgentRunningSubModule;
import work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts.Module;
import work.slhaf.partner.api.agent.util.AgentUtil;
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;
/**
* <h2>Agent启动流程 7</h2>
*
* <p>负责执行初始化hook逻辑即 {@link Init} 注解所在方法</p>
*
* <ol>
* <li>
* <p>{@link ModuleInitHookExecuteFactory#collectInitHookMethods(Class, Class)}</p>
* 分别遍历前置模块拿到的模块列表({@link ModuleInitHookExecuteFactory#moduleList}, {@link ModuleInitHookExecuteFactory#subModuleList}),通过 {@link AgentUtil#collectExtendedClasses(Class, Class)} 收集到当前模块类的继承链上的所有类后,收集其所有带有 {@link Init} 注解的方法
* </li>
* <li>
* <p>{@link ModuleInitHookExecuteFactory#proceedInitMethods(BaseMetaModule, List)}</p>
* 收集好初始化方法后,将通过反射执行该方法,所用实例即为前置模块中收集到的执行模块与子模块的 {@link MetaModule} 与 {@link MetaSubModule} 内容
* </li>
* </ol>
*
* <p>Agent启动流程到此进行完毕。整个工厂执行链中均为针对 {@link AgentRegisterContext} 进行的操作,在 {@link AgentRegisterFactory} 中,将进行最终处理以及将必要内容进行传递。</p>
*/
public class ModuleInitHookExecuteFactory extends AgentBaseFactory {
private List<MetaModule> moduleList;
private List<MetaSubModule> subModuleList;
@Override
protected void setVariables(AgentRegisterContext context) {
ModuleFactoryContext factoryContext = context.getModuleFactoryContext();
moduleList = factoryContext.getAgentModuleList();
subModuleList = factoryContext.getAgentSubModuleList();
}
@Override
protected void run() {
//遍历模块列表,并向上查找@Init注解
for (MetaSubModule metaSubModule : subModuleList) {
List<MetaMethod> initHookMethods = collectInitHookMethods(metaSubModule.getClazz(),AgentRunningModule.class);
proceedInitMethods(metaSubModule, initHookMethods);
}
for (MetaModule metaModule : moduleList) {
List<MetaMethod> initHookMethods = collectInitHookMethods(metaModule.getClazz(), AgentRunningSubModule.class);
proceedInitMethods(metaModule, initHookMethods);
}
}
private void proceedInitMethods(BaseMetaModule metaModule, List<MetaMethod> initHookMethods) {
for (MetaMethod metaMethod : initHookMethods) {
try {
metaMethod.getMethod().invoke(metaModule.getInstance());
} catch (IllegalAccessException | InvocationTargetException e) {
throw new ModuleInitHookExecuteFailedException("模块的init hook方法执行失败! 模块: " + metaModule.getClazz().getSimpleName() + " 方法签名: " + methodSignature(metaMethod.getMethod()), e);
}
}
}
private List<MetaMethod> collectInitHookMethods(Class<?> clazz, Class<? extends Module> target) {
Set<Class<?>> classes = collectExtendedClasses(clazz, target);
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,259 +0,0 @@
package work.slhaf.partner.api.agent.factory.module;
import lombok.Getter;
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.capability.CapabilityCheckFactory;
import work.slhaf.partner.api.agent.factory.context.AgentRegisterContext;
import work.slhaf.partner.api.agent.factory.context.CapabilityFactoryContext;
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.annotation.InjectModule;
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.exception.ProxiedModuleRunningException;
import work.slhaf.partner.api.agent.factory.module.pojo.BaseMetaModule;
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.factory.module.pojo.MetaSubModule;
import work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts.AgentRunningModule;
import work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts.AgentRunningSubModule;
import work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts.Module;
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;
/**
* <h2>Agent启动流程 3</h2>
*
* <p>
* 扫描前置模块各个hook注解生成代理对象放入对应的list中并按照类型为键放入 {@link ModuleProxyFactory#capabilityHolderInstances} 中供后续完成能力(capability)注入
* <p/>
*
* <ol>
*
* <li>
* <p>{@link ModuleProxyFactory#createProxiedInstances()}</p>
* 根据moduleList中的类型信息向上查找继承链获取所有hook方法收集为{@link MethodsListRecord}然后通过ByteBuddy根据收集到的preHook与postHook生成代理对象放入对应的 {@link MetaModule} 对象以及 instanceMap 中
* </li>
* <li>
* <p>{@link ModuleProxyFactory#injectSubModule()}</p>
* 通过反射将子模块实例注入到执行模块中带有注解 {@link InjectModule} 的字段
* </li>
* </ol>
*
* <p>下一步流程请参阅{@link CapabilityCheckFactory}</p>
*/
public class ModuleProxyFactory extends AgentBaseFactory {
private List<MetaModule> moduleList;
private List<MetaSubModule> subModuleList;
private HashMap<Class<?>, Object> capabilityHolderInstances;
private final HashMap<Class<?>, Object> subModuleInstances = new HashMap<>();
private final HashMap<Class<?>, Object> moduleInstances = new HashMap<>();
@Override
protected void setVariables(AgentRegisterContext context) {
ModuleFactoryContext factoryContext = context.getModuleFactoryContext();
CapabilityFactoryContext capabilityFactoryContext = context.getCapabilityFactoryContext();
moduleList = factoryContext.getAgentModuleList();
subModuleList = factoryContext.getAgentSubModuleList();
capabilityHolderInstances = capabilityFactoryContext.getCapabilityHolderInstances();
}
@Override
protected void run() {
createProxiedInstances();
injectSubModule();
}
private void injectSubModule() {
for (MetaModule module : moduleList) {
//因为实际上ByteBuddy生成的是module.getClazz()的子类所以应当使用getDeclaredFields()获取字段
Arrays.stream(module.getClazz().getDeclaredFields())
.filter(field -> field.isAnnotationPresent(InjectModule.class))
.forEach(field -> {
try {
field.setAccessible(true);
field.set(
moduleInstances.get(module.getClazz()),
subModuleInstances.get(field.getType())
);
} catch (IllegalAccessException e) {
throw new ModuleInstanceGenerateFailedException("模块实例注入失败", e);
}
});
}
}
private void createProxiedInstances() {
generateModuleProxy(moduleList, AgentRunningModule.class);
generateModuleProxy(subModuleList, AgentRunningSubModule.class);
updateInstanceMap(moduleInstances, moduleList);
updateInstanceMap(subModuleInstances, subModuleList);
updateCapabilityHolderInstances();
}
private void updateCapabilityHolderInstances() {
capabilityHolderInstances.putAll(moduleInstances);
capabilityHolderInstances.putAll(subModuleInstances);
}
private void updateInstanceMap(HashMap<Class<?>, Object> instanceMap, List<? extends BaseMetaModule> list) {
for (BaseMetaModule baseMetaModule : list) {
instanceMap.put(baseMetaModule.getClazz(), baseMetaModule.getInstance());
}
}
private void generateModuleProxy(List<? extends BaseMetaModule> list, Class<? extends Module> overrideSource) {
for (BaseMetaModule module : list) {
Class<?> clazz = module.getClazz();
try {
MethodsListRecord record = collectHookMethods(clazz);
//生成实例
generateProxiedInstances(record, module, overrideSource);
} catch (Exception e) {
throw new ModuleProxyGenerateFailedException("创建代理对象失败: " + clazz.getSimpleName(), e);
}
}
}
private void generateProxiedInstances(MethodsListRecord record, BaseMetaModule module, Class<? extends Module> overrideSource) {
try {
Class<? extends Module> clazz = module.getClazz();
Class<? extends Module> proxyClass = new ByteBuddy()
.subclass(clazz)
.method(ElementMatchers.isOverriddenFrom(overrideSource))
.intercept(MethodDelegation.to(new ModuleProxyInterceptor(record.post, record.pre)))
.make()
.load(ModuleProxyFactory.class.getClassLoader())
.getLoaded();
// new ByteBuddy()
// .subclass(clazz)
// .method(ElementMatchers.isOverriddenFrom(overrideSource))
// .intercept(MethodDelegation.to(new ModuleProxyInterceptor(record.post, record.pre)))
//
// .make()
// .saveIn(new File("./generated-classes"));
module.setInstance(proxyClass.getConstructor().newInstance());
} catch (Exception e) {
throw new ModuleProxyGenerateFailedException("模块Hook代理生成失败! 代理失败的模块名: " + module.getClazz().getSimpleName(), e);
}
}
private MethodsListRecord collectHookMethods(Class<?> clazz) {
List<MetaMethod> post = new ArrayList<>();
List<MetaMethod> pre = new ArrayList<>();
//获取该类本身的hook逻辑
collectHookMethods(post, pre, clazz);
//获取它所继承、实现的抽象类或接口, 以Module为终点收集继承链上所有父类和接口
Set<Class<?>> classes = collectExtendedClasses(clazz, Module.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.getDeclaredMethods();
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);
}
}
}
@Getter
@SuppressWarnings("ClassCanBeRecord")
public static class ModuleProxyInterceptor {
private final List<MetaMethod> postHookMethods;
private final List<MetaMethod> preHookMethods;
public ModuleProxyInterceptor(List<MetaMethod> postHookMethods, List<MetaMethod> preHookMethods) {
this.postHookMethods = postHookMethods;
this.preHookMethods = preHookMethods;
}
@RuntimeType
public Object intercept(@Origin Method method, @AllArguments Object[] allArguments, @SuperCall Callable<?> zuper, @This Object proxy) throws Exception {
executeHookMethods(preHookMethods, proxy);
Object res = zuper.call();
executeHookMethods(postHookMethods, proxy);
return res;
}
private void executeHookMethods(List<MetaMethod> hookMethods, Object proxy) {
for (MetaMethod metaMethod : hookMethods) {
Method m = metaMethod.getMethod();
try {
m.setAccessible(true);
m.invoke(proxy);
} catch (Exception e) {
throw new ProxiedModuleRunningException("hook方法执行异常: " + m.getDeclaringClass() + "#" + m.getName(), e);
}
}
}
}
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,104 +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.annotation.AgentSubModule;
import work.slhaf.partner.api.agent.factory.module.annotation.CoreModule;
import work.slhaf.partner.api.agent.factory.module.pojo.MetaModule;
import work.slhaf.partner.api.agent.factory.module.pojo.MetaSubModule;
import work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts.AgentRunningModule;
import work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts.AgentRunningSubModule;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
/**
* <h2>Agent启动流程 2</h2>
*
* <p>
* 负责收集 {@link AgentModule} 与 {@link AgentSubModule} 注解所在类的信息,供后续工厂完成动态代理、模块与能力注入
* <p/>
*
* <ol>
* <li>
* <p>{@link ModuleRegisterFactory#setModuleList()}</p>
* 扫描 {@link AgentModule} 注解,获取执行模块信息: 类型、模块名称({@link AgentModule#name()}),执行顺序。并按照注解的 {@link AgentModule#order()} 字段进行排序
* </li>
* <li>
* <p>{@link ModuleRegisterFactory#setSubModuleList()}</p>
* 扫描 {@link AgentSubModule} 注册,获取子模块类型信息
* </li>
* <li>
* 两种模块都将存入各自的list中供后续模块完成注册与注入
* </li>
* </ol>
*
* <p>下一步流程请参阅{@link ModuleProxyFactory}</p>
*/
public class ModuleRegisterFactory extends AgentBaseFactory {
private Reflections reflections;
private List<MetaModule> moduleList;
private List<MetaSubModule> subModuleList;
@Override
protected void setVariables(AgentRegisterContext context) {
ModuleFactoryContext factoryContext = context.getModuleFactoryContext();
reflections = context.getReflections();
moduleList = factoryContext.getAgentModuleList();
subModuleList = factoryContext.getAgentSubModuleList();
}
@Override
protected void run() {
setModuleList();
setSubModuleList();
}
private void setSubModuleList() {
Set<Class<?>> subModules = reflections.getTypesAnnotatedWith(AgentSubModule.class);
for (Class<?> subModule : subModules) {
if (!ClassUtil.isNormalClass(subModule)) {
continue;
}
Class<? extends AgentRunningSubModule> clazz = subModule.asSubclass(AgentRunningSubModule.class);
MetaSubModule metaSubModule = new MetaSubModule();
metaSubModule.setClazz(clazz);
subModuleList.add(metaSubModule);
}
}
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);
MetaModule metaModule = getMetaModule(clazz);
moduleList.add(metaModule);
}
moduleList.sort(Comparator.comparing(MetaModule::getOrder));
}
private static MetaModule getMetaModule(Class<? extends AgentRunningModule> clazz) {
MetaModule metaModule = new MetaModule();
AgentModule agentModule;
if (clazz.isAnnotationPresent(CoreModule.class)){
agentModule = CoreModule.class.getAnnotation(AgentModule.class);
}else{
agentModule = clazz.getAnnotation(AgentModule.class);
}
metaModule.setName(agentModule.name());
metaModule.setOrder(agentModule.order());
metaModule.setClazz(clazz);
return metaModule;
}
}

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

View File

@@ -1,14 +0,0 @@
package work.slhaf.partner.api.agent.factory.module.annotation;
import work.slhaf.partner.api.agent.factory.capability.annotation.CapabilityHolder;
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)
@CapabilityHolder
public @interface AgentSubModule {
}

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,9 +0,0 @@
package work.slhaf.partner.api.agent.factory.module.annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
@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,13 +0,0 @@
package work.slhaf.partner.api.agent.factory.module.exception;
import work.slhaf.partner.api.agent.runtime.exception.AgentRuntimeException;
public class ProxiedModuleRunningException extends AgentRuntimeException {
public ProxiedModuleRunningException(String message) {
super(message);
}
public ProxiedModuleRunningException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@@ -1,10 +0,0 @@
package work.slhaf.partner.api.agent.factory.module.pojo;
import lombok.Data;
import work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts.Module;
@Data
public abstract class BaseMetaModule <C extends Module> {
private Class<? extends C> clazz;
private C instance;
}

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 lombok.EqualsAndHashCode;
import work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts.AgentRunningModule;
@EqualsAndHashCode(callSuper = true)
@Data
public class MetaModule extends BaseMetaModule<AgentRunningModule>{
private String name;
private int order;
private boolean enabled = true;
}

View File

@@ -1,10 +0,0 @@
package work.slhaf.partner.api.agent.factory.module.pojo;
import lombok.Data;
import lombok.EqualsAndHashCode;
import work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts.AgentRunningSubModule;
@EqualsAndHashCode(callSuper = true)
@Data
public class MetaSubModule extends BaseMetaModule<AgentRunningSubModule>{
}

View File

@@ -1,103 +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.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.*;
@Slf4j
@Data
public abstract class AgentConfigManager {
@Setter
public static AgentConfigManager INSTANCE = new FileAgentConfigManager();
private static final String DEFAULT_KEY = "default";
protected HashMap<String, ModelConfig> modelConfigMap;
protected HashMap<String, List<Message>> modelPromptMap;
protected HashMap<String, Boolean> moduleEnabledStatus;
protected Map<Integer, List<MetaModule>> moduleOrderedMap = new LinkedHashMap<>();
protected Map<String, MetaModule> moduleMap = new HashMap<>();
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(List<MetaModule> moduleList);
public void moduleEnabledStatusFilterAndRecord(List<MetaModule> moduleList) {
updateModuleMap(moduleList);
updateModuleEnabledStatus(moduleList);
}
private void updateModuleMap(List<MetaModule> moduleList) {
//在ModuleRegisterFactory已进行过排序操作
for (MetaModule module : moduleList) {
int k = module.getOrder();
moduleOrderedMap.computeIfAbsent(k, order -> new ArrayList<>()).add(module);
moduleMap.put(module.getName(), module);
}
}
private void updateModuleEnabledStatus(List<MetaModule> moduleList) {
this.moduleEnabledStatus = loadModuleEnabledStatusMap(moduleList);
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();
}
}
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();
moduleMap.get(key).setEnabled(status);
}
}

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 FileAgentConfigManager extends AgentConfigManager {
protected static final String CONFIG_DIR = "./config/";
protected static final String MODEL_CONFIG_DIR = "./config/model/";
protected static final String PROMPT_CONFIG_DIR = "./config/prompt/";
protected 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(List<MetaModule> moduleList) {
File file = new File(MODULE_ENABLED_STATUS_CONFIG_FILE);
try {
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 AgentRunningFailedException extends AgentRuntimeException{
public AgentRunningFailedException(String message) {
super(message);
}
public AgentRunningFailedException(String message, Throwable cause) {
super(message, cause);
}
}

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,39 +0,0 @@
package work.slhaf.partner.api.agent.runtime.exception;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class GlobalExceptionHandler {
public static GlobalExceptionHandler INSTANCE = new GlobalExceptionHandler();
private AgentExceptionCallback exceptionCallback = new LogAgentExceptionCallback();
public boolean handle(Throwable e) {
boolean exit;
Throwable cause = e.getCause();
switch (cause) {
case AgentRunningFailedException arfe -> {
exit = true;
exceptionCallback.onRuntimeException((AgentRuntimeException) cause);
}
case AgentRuntimeException are -> {
exit = false;
exceptionCallback.onRuntimeException((AgentRuntimeException) cause);
}
case AgentLaunchFailedException alfe -> {
exit = true;
exceptionCallback.onFailedException((AgentLaunchFailedException) cause);
}
default -> {
exit = true;
log.error("意外异常: ", cause);
}
}
return exit;
}
public static void setExceptionCallback(AgentExceptionCallback callback) {
INSTANCE.exceptionCallback = callback;
}
}

View File

@@ -1,17 +0,0 @@
package work.slhaf.partner.api.agent.runtime.exception;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class LogAgentExceptionCallback 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.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 <I extends AgentInputData, O extends AgentOutputData, C extends RunningFlowContext>{
void launch();
default void receive(I inputData){
C finalInputData = adapter().parseInputData(inputData);
C outputContext = adapter().call(finalInputData);
O outputData = adapter().parseOutputData(outputContext);
send(outputData);
}
void send(O outputData);
/**
* 通过adapter提供的receive、send方法进行与客户端的交互行为
*
* @return adapter实例
*/
AgentInteractionAdapter<I, O, C> adapter();
}

View File

@@ -1,26 +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;
import java.util.Map;
public abstract class AgentInteractionAdapter<I extends AgentInputData, O extends AgentOutputData, C extends RunningFlowContext> {
protected AgentRunningFlow<C> agentRunningFlow = new AgentRunningFlow<>();
protected Map<Integer, List<MetaModule>> moduleOrderedMap = AgentConfigManager.INSTANCE.getModuleOrderedMap();
public C call(C finalInputData){
return agentRunningFlow.launch(moduleOrderedMap, finalInputData);
}
protected abstract O parseOutputData(C outputContext);
protected abstract C parseInputData(I inputData);
}

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{
protected 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,49 +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.AgentRuntimeException;
import work.slhaf.partner.api.agent.runtime.exception.GlobalExceptionHandler;
import work.slhaf.partner.api.agent.runtime.interaction.flow.entity.RunningFlowContext;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
/**
* Agent执行流程
*/
public class AgentRunningFlow<C extends RunningFlowContext> {
public C launch(Map<Integer, List<MetaModule>> modules, C interactionContext) {
try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
//流程执行启动
for (Map.Entry<Integer, List<MetaModule>> entry : modules.entrySet()) {
List<Future<?>> futures = new ArrayList<>();
List<MetaModule> moduleList = entry.getValue();
for (MetaModule module : moduleList) {
Future<?> future = executor.submit(() -> {
module.getInstance().execute(interactionContext);
});
futures.add(future);
}
for (Future<?> future : futures) {
try {
future.get();
} catch (Exception e) {
boolean exit = GlobalExceptionHandler.INSTANCE.handle(e);
if (exit) throw new AgentRuntimeException("Agent执行出错!", e);
interactionContext.getErrMsg().add(e.getLocalizedMessage());
}
}
}
interactionContext.setOk(1);
} catch (Exception e) {
interactionContext.setOk(0);
interactionContext.getErrMsg().add(e.getLocalizedMessage());
}
return interactionContext;
}
}

View File

@@ -1,97 +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(order = -1)
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()));
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,36 +0,0 @@
package work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts;
import lombok.extern.slf4j.Slf4j;
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.CoreModule;
import work.slhaf.partner.api.agent.runtime.interaction.flow.entity.RunningFlowContext;
/**
* 流程执行模块基类
*/
@Slf4j
public abstract class AgentRunningModule<C extends RunningFlowContext> extends Module {
public abstract void execute(C context);
@BeforeExecute
private void beforeLog() {
log.debug("[{}] 模块执行开始...", getModuleName());
}
@AfterExecute
private void afterLog() {
log.debug("[{}] 模块执行结束...", getModuleName());
}
private String getModuleName(){
if (this.getClass().isAnnotationPresent(AgentModule.class)) {
return this.getClass().getAnnotation(AgentModule.class).name();
} else if (this.getClass().isAnnotationPresent(CoreModule.class)) {
return CoreModule.class.getAnnotation(AgentModule.class).name();
}else {
return "Unknown Module";
}
}
}

View File

@@ -1,35 +0,0 @@
package work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts;
import lombok.extern.slf4j.Slf4j;
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.CoreModule;
@Slf4j
public abstract class AgentRunningSubModule<I, O> extends Module {
public abstract O execute(I data);
@BeforeExecute
private void beforeLog() {
log.debug("[{}] 模块执行开始...", getModuleName());
}
@AfterExecute
private void afterLog() {
log.debug("[{}] 模块执行结束...", getModuleName());
}
private String getModuleName(){
if (this.getClass().isAnnotationPresent(AgentModule.class)) {
return this.getClass().getAnnotation(AgentModule.class).name();
} else if (this.getClass().isAnnotationPresent(CoreModule.class)) {
return CoreModule.class.getAnnotation(AgentModule.class).name();
}else {
return "Unknown Module";
}
}
}

View File

@@ -1,16 +0,0 @@
package work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts;
import lombok.Getter;
import lombok.Setter;
import work.slhaf.partner.api.agent.runtime.interaction.flow.entity.Model;
/**
* 模块基类
*/
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,18 +0,0 @@
package work.slhaf.partner.api.agent.runtime.interaction.flow.entity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import work.slhaf.partner.api.common.entity.PersistableObject;
import java.util.ArrayList;
import java.util.List;
/**
* 流程上下文
*/
@EqualsAndHashCode(callSuper = true)
@Data
public abstract class RunningFlowContext extends PersistableObject {
protected int ok;
protected List<String> errMsg = new ArrayList<>();
}

View File

@@ -1,84 +0,0 @@
package work.slhaf.partner.api.chat;
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONUtil;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
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;
@Slf4j
@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.setConnectionTimeout(2000);
request.setReadTimeout(15000);
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();
}
ChatResponse finalResponse;
try {
HttpResponse response = request.body(JSONUtil.toJsonStr(body)).execute();
PrimaryChatResponse primaryChatResponse = JSONUtil.toBean(response.body(), PrimaryChatResponse.class);
finalResponse = ChatResponse.builder()
.status(ChatConstant.ResponseStatus.SUCCESS)
.message(primaryChatResponse.getChoices().get(0).getMessage().getContent())
.usageBean(primaryChatResponse.getUsage())
.build();
response.close();
} catch (IORuntimeException e) {
log.error("请求超时", e);
finalResponse = ChatResponse.builder()
.message("连接超时")
.status(ChatConstant.ResponseStatus.FAILED)
.usageBean(null)
.build();
}
return finalResponse;
}
}

View File

@@ -1,14 +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 enum ResponseStatus {
SUCCESS, FAILED
}
}

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,17 +0,0 @@
package work.slhaf.partner.api.chat.pojo;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import work.slhaf.partner.api.chat.constant.ChatConstant;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class ChatResponse {
private ChatConstant.ResponseStatus status;
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,25 +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.io.IOException;
import java.lang.reflect.InvocationTargetException;
public class ModuleProxyTest {
@Test
public void test() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, IOException, ClassNotFoundException {
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);
}
}

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