Skip to content

Commit bf57bf1

Browse files
authored
Merge pull request #48 from BetaGoRobot/feature-agentic
commit agentic result
2 parents bf06266 + 65015af commit bf57bf1

File tree

190 files changed

+455504
-840
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

190 files changed

+455504
-840
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,5 @@ __debug_bin*
99
.cache
1010
.env
1111
*.test
12-
script/neteaseapi/api_repo/*
12+
script/neteaseapi/api_repo/*
13+
**__pycache__**

Agents.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,17 @@ BetaGo-Redefine/
203203
| dynamic_configs | 动态配置 |
204204
| cron_cmd_tasks | 定时任务 |
205205

206+
## Agent 数据库变更约束
207+
208+
凡是涉及新建表、改表、索引或约束变更,先遵循 `script/AGENT_DB_CHANGE_SOP.md`
209+
210+
硬约束:
211+
212+
- 先生成 SQL,并保存到 `script/sql/`
213+
- 先等待用户执行 SQL
214+
- 再等待用户执行 `go run ./cmd/generate`
215+
- 用户确认前,不继续写依赖新 schema 的业务代码
216+
206217
## 本地开发
207218

208219
### 前置要求

cmd/larkrobot/bootstrap.go

Lines changed: 58 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ import (
66
"fmt"
77

88
appconfig "github.com/BetaGoRobot/BetaGo-Redefine/internal/application/config"
9+
"github.com/BetaGoRobot/BetaGo-Redefine/internal/application/lark/agentruntime"
10+
"github.com/BetaGoRobot/BetaGo-Redefine/internal/application/lark/agentruntime/runtimecutover"
11+
"github.com/BetaGoRobot/BetaGo-Redefine/internal/application/lark/agentruntime/runtimewire"
912
appcardaction "github.com/BetaGoRobot/BetaGo-Redefine/internal/application/lark/cardaction"
1013
larkchunking "github.com/BetaGoRobot/BetaGo-Redefine/internal/application/lark/chunking"
1114
"github.com/BetaGoRobot/BetaGo-Redefine/internal/application/lark/handlers"
@@ -14,7 +17,7 @@ import (
1417
"github.com/BetaGoRobot/BetaGo-Redefine/internal/application/lark/reaction"
1518
scheduleapp "github.com/BetaGoRobot/BetaGo-Redefine/internal/application/lark/schedule"
1619
todoapp "github.com/BetaGoRobot/BetaGo-Redefine/internal/application/lark/todo"
17-
"github.com/BetaGoRobot/BetaGo-Redefine/internal/infrastructure/aktool"
20+
"github.com/BetaGoRobot/BetaGo-Redefine/internal/infrastructure/akshareapi"
1821
"github.com/BetaGoRobot/BetaGo-Redefine/internal/infrastructure/ark_dal"
1922
infraConfig "github.com/BetaGoRobot/BetaGo-Redefine/internal/infrastructure/config"
2023
"github.com/BetaGoRobot/BetaGo-Redefine/internal/infrastructure/db"
@@ -31,6 +34,7 @@ import (
3134
"github.com/BetaGoRobot/BetaGo-Redefine/pkg/logs"
3235
"github.com/BetaGoRobot/BetaGo-Redefine/pkg/xhttp"
3336
"github.com/larksuite/oapi-sdk-go/v3/event/dispatcher"
37+
larkim "github.com/larksuite/oapi-sdk-go/v3/service/im/v1"
3438
)
3539

3640
type appComponents struct {
@@ -45,7 +49,23 @@ type appComponents struct {
4549

4650
// scheduler 仍保留为包级句柄,是因为当前调度器本身还没有实现
4751
// runtime.Module。真正的生命周期仍由装配阶段注册的模块接管。
48-
var scheduler *scheduleapp.Scheduler
52+
var (
53+
scheduler *scheduleapp.Scheduler
54+
resumeWorker workerHandle
55+
buildAgentRuntimeResumeWorker = func(ctx context.Context) workerHandle {
56+
return runtimewire.BuildResumeWorker(ctx)
57+
}
58+
)
59+
60+
func startAgentRuntimeResumeWorker(ctx context.Context) error {
61+
worker := buildAgentRuntimeResumeWorker(ctx)
62+
if worker == nil || !worker.Available() {
63+
return fmt.Errorf("%w: agent runtime resume worker unavailable", appruntime.ErrDisabled)
64+
}
65+
resumeWorker = worker
66+
resumeWorker.Start()
67+
return nil
68+
}
4969

5070
// buildApp 是当前单体进程的装配根。这里集中完成:
5171
// 1. 构造受控执行器和 handler 入口;
@@ -79,6 +99,13 @@ func newAppComponents(cfg *infraConfig.BaseConfig) *appComponents {
7999
chunkExecutor := appruntime.NewExecutor(executorConfigs["chunk"])
80100
scheduleExecutor := appruntime.NewExecutor(executorConfigs["schedule"])
81101

102+
agentruntime.SetRuntimeAgenticCutoverBuilder(runtimecutover.BuildDefaultHandler)
103+
// agentruntime.SetRuntimeStandardCutoverBuilder(runtimecutover.BuildDefaultStandardHandler)
104+
agentruntime.SetDefaultChatToolProvider(handlers.BuildLarkTools)
105+
agentruntime.SetChatGenerationPlanExecutor(agentruntime.NewDefaultChatGenerationPlanExecutor())
106+
runtimewire.SetDefaultCapabilityProvider(func() []agentruntime.Capability {
107+
return agentruntime.BuildToolCapabilities(handlers.BuildLarkTools(), nil, (*larkim.P2MessageReceiveV1)(nil))
108+
})
82109
messageProcessor := messages.NewMessageProcessor(appconfig.GetManager())
83110
reactionProcessor := reaction.NewReactionProcessor()
84111
handlerSet := larkiface.NewHandlerSet(larkiface.HandlerSetOptions{
@@ -173,10 +200,10 @@ func addInfrastructureModules(app *appruntime.App, cfg *infraConfig.BaseConfig)
173200
}, func(context.Context) error {
174201
return gotify.ErrUnavailable()
175202
}))
176-
app.AddModule(newOptionalModule("aktool", func() {
177-
aktool.Init()
203+
app.AddModule(newOptionalModule("akshareapi", func() {
204+
akshareapi.Init()
178205
}, func(context.Context) error {
179-
if ok, reason := aktool.Status(); !ok {
206+
if ok, reason := akshareapi.Status(); !ok {
180207
return errors.New(reason)
181208
}
182209
return nil
@@ -276,13 +303,39 @@ func addApplicationModules(app *appruntime.App, cfg *infraConfig.BaseConfig, com
276303
},
277304
Stats: components.scheduleExecutor.Stats,
278305
}))
306+
app.AddModule(appruntime.NewFuncModule(appruntime.FuncModuleOptions{
307+
Name: "agent_runtime_resume_worker",
308+
Critical: false,
309+
Start: func(ctx context.Context) error {
310+
return startAgentRuntimeResumeWorker(ctx)
311+
},
312+
Stop: func(context.Context) error {
313+
if resumeWorker != nil {
314+
resumeWorker.Stop()
315+
}
316+
return nil
317+
},
318+
Stats: func() map[string]any {
319+
if resumeWorker == nil {
320+
return nil
321+
}
322+
return resumeWorker.Stats()
323+
},
324+
}))
279325
app.AddModule(appruntime.NewLarkWSModule(
280326
cfg.LarkConfig.AppID,
281327
cfg.LarkConfig.AppSecret,
282328
components.eventDispatcher,
283329
))
284330
}
285331

332+
type workerHandle interface {
333+
Start()
334+
Stop()
335+
Stats() map[string]any
336+
Available() bool
337+
}
338+
286339
// newEventDispatcher 负责把运行时管理的 HandlerSet 绑定到当前订阅的
287340
// Lark 事件类型上。
288341
func newEventDispatcher(handlerSet *larkiface.HandlerSet) *dispatcher.EventDispatcher {

cmd/larkrobot/bootstrap_test.go

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"errors"
6+
"testing"
7+
8+
infraConfig "github.com/BetaGoRobot/BetaGo-Redefine/internal/infrastructure/config"
9+
appruntime "github.com/BetaGoRobot/BetaGo-Redefine/internal/runtime"
10+
)
11+
12+
type fakeWorkerHandle struct {
13+
available bool
14+
started bool
15+
stopped bool
16+
}
17+
18+
func (f *fakeWorkerHandle) Start() {
19+
f.started = true
20+
}
21+
22+
func (f *fakeWorkerHandle) Stop() {
23+
f.stopped = true
24+
}
25+
26+
func (f *fakeWorkerHandle) Stats() map[string]any {
27+
return nil
28+
}
29+
30+
func (f *fakeWorkerHandle) Available() bool {
31+
return f != nil && f.available
32+
}
33+
34+
func TestStartAgentRuntimeResumeWorkerStartsAvailableWorkerWithoutGlobalConfigGate(t *testing.T) {
35+
originalBuilder := buildAgentRuntimeResumeWorker
36+
originalResumeWorker := resumeWorker
37+
defer func() {
38+
buildAgentRuntimeResumeWorker = originalBuilder
39+
resumeWorker = originalResumeWorker
40+
}()
41+
42+
fake := &fakeWorkerHandle{available: true}
43+
buildAgentRuntimeResumeWorker = func(context.Context) workerHandle {
44+
return fake
45+
}
46+
resumeWorker = nil
47+
48+
if err := startAgentRuntimeResumeWorker(context.Background()); err != nil {
49+
t.Fatalf("startAgentRuntimeResumeWorker() error = %v", err)
50+
}
51+
if !fake.started {
52+
t.Fatal("expected resume worker to be started")
53+
}
54+
if resumeWorker != fake {
55+
t.Fatal("expected started worker to be stored globally")
56+
}
57+
}
58+
59+
func TestStartAgentRuntimeResumeWorkerReturnsDisabledWhenUnavailable(t *testing.T) {
60+
originalBuilder := buildAgentRuntimeResumeWorker
61+
originalResumeWorker := resumeWorker
62+
defer func() {
63+
buildAgentRuntimeResumeWorker = originalBuilder
64+
resumeWorker = originalResumeWorker
65+
}()
66+
67+
buildAgentRuntimeResumeWorker = func(context.Context) workerHandle {
68+
return &fakeWorkerHandle{available: false}
69+
}
70+
resumeWorker = nil
71+
72+
err := startAgentRuntimeResumeWorker(context.Background())
73+
if !errors.Is(err, appruntime.ErrDisabled) {
74+
t.Fatalf("startAgentRuntimeResumeWorker() error = %v, want %v", err, appruntime.ErrDisabled)
75+
}
76+
}
77+
78+
func TestAddInfrastructureModulesRegistersAKShareAPIModule(t *testing.T) {
79+
app := appruntime.NewApp()
80+
81+
addInfrastructureModules(app, &infraConfig.BaseConfig{})
82+
83+
snapshot := app.Registry().Snapshot()
84+
if hasComponent(snapshot.Components, "aktool") {
85+
t.Fatalf("unexpected aktool module in registry: %+v", snapshot.Components)
86+
}
87+
if !hasComponent(snapshot.Components, "akshareapi") {
88+
t.Fatalf("expected akshareapi module in registry: %+v", snapshot.Components)
89+
}
90+
}
91+
92+
func hasComponent(items []appruntime.ComponentStatus, name string) bool {
93+
for _, item := range items {
94+
if item.Name == name {
95+
return true
96+
}
97+
}
98+
return false
99+
}

docs/akshare/README.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# AkShare Generated Docs
2+
3+
- `generated/akshare_api_catalog.md`: human-readable Markdown catalog.
4+
- `generated/akshare_api_catalog.json`: structured extraction of the official docs.
5+
- `generated/akshare_openapi.json`: OpenAPI 3.1 skeleton using AKTools' `/api/public/{接口名}` convention.
6+
7+
## Notes
8+
9+
- Sources: `https://akshare.akfamily.xyz/` and `https://aktools.akfamily.xyz/aktools/`.
10+
- Live server: `http://192.168.31.74:1828`.
11+
- Live service reachable: `True`; Swagger docs reachable: `True`; OpenAPI reachable: `True`.
12+
- Live validation for uncertain endpoints: attempted `0`, succeeded `0`, failed `0`.
13+
- The live service currently reports AKShare 1.18.27 while the official docs expose AKShare 1.18.40 content, so newer interfaces may be documentation-only until the service catches up.
14+
- Re-run with `python3 script/akshare_docgen.py` to refresh the source catalog and OpenAPI skeleton.
15+
- Re-run with `python3 script/akshare_focus_codegen.py` to refresh the SDK/focus catalogs and Go client catalog.

0 commit comments

Comments
 (0)