diff --git a/deps/agent-native b/deps/agent-native index 79e1a8f..fe0c4a9 160000 --- a/deps/agent-native +++ b/deps/agent-native @@ -1 +1 @@ -Subproject commit 79e1a8fa85b8195ae27139934e999d5ceee78fe3 +Subproject commit fe0c4a9f82d8a5e160997f3608f2eb96594fe0fd diff --git a/deps/agent-squad b/deps/agent-squad index 90077b6..f38cf7c 160000 --- a/deps/agent-squad +++ b/deps/agent-squad @@ -1 +1 @@ -Subproject commit 90077b660101ffae843d37a28d528bff612d93d0 +Subproject commit f38cf7c441d19a1bb06ef0dfbe65b2b5d87f5675 diff --git a/internal/app/app.go b/internal/app/app.go index 048f089..56615b9 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -84,7 +84,6 @@ func Run(opt Options) error { if opt.InsecureListen && !config.IsLoopbackListen(opt.Addr) && !resolved.AuthEnabled() { log.Printf("warning: listening on %s without authentication because insecureListen is set", opt.Addr) } - traceFn := telemetry.StartFunc(logger) var st *store.Store var err error if opt.StorageDSN != "" { @@ -124,6 +123,10 @@ func Run(opt Options) error { return fmt.Errorf("code orchestration tool: %w", err) } setSvc := settings.NewService(st) + effBoot := setSvc.Effective(store.OwnerDefault, "") + traceFn := telemetry.StartFunc(logger, + telemetry.WithServiceName(effBoot.GetString("telemetry.serviceName", "agent-system-backend")), + telemetry.WithEndpoint(effBoot.GetString("telemetry.otlpEndpoint", ""))) setSvc.SetSystemOverride(map[string]any{"storage": map[string]any{"dataDir": opt.DataDir}}) // 点路径键展开必须在读 tools.tavily.apiKeys 之前,否则启动仍注册旧池。 norm, err := setSvc.NormalizeStored() diff --git a/internal/app/intent_flags_test.go b/internal/app/intent_flags_test.go index 0d47f5a..de77ba1 100644 --- a/internal/app/intent_flags_test.go +++ b/internal/app/intent_flags_test.go @@ -27,3 +27,18 @@ func TestIntentSlowLaneFlagsDefaultOff(t *testing.T) { } } } + +// 遥测开关默认安全(N3 WP4):otlpEndpoint 默认空(不导出,保持现状), +// serviceName 有非空默认。两处都注册进 Schema。 +func TestTelemetryFlagsDefaults(t *testing.T) { + seen := map[string]core.SettingDesc{} + for _, d := range settings.Schema() { + seen[d.Key] = d + } + if d, ok := seen["telemetry.otlpEndpoint"]; !ok || d.Default != "" { + t.Fatalf("otlpEndpoint 必须注册且默认空:%+v", d) + } + if d, ok := seen["telemetry.serviceName"]; !ok || d.Default != "agent-system-backend" { + t.Fatalf("serviceName 必须注册且默认 agent-system-backend:%+v", d) + } +} diff --git a/internal/runtime/llm.go b/internal/runtime/llm.go index dba3315..a92aad5 100644 --- a/internal/runtime/llm.go +++ b/internal/runtime/llm.go @@ -399,6 +399,14 @@ func outputTokenCap(budget core.RunBudget, eff core.EffectiveSettings, key strin return 0 } +// agentNameOf 是 OTel gen_ai.agent.name 的取值(画像 ID,空回退 agent-system)。 +func agentNameOf(prof core.AgentProfile) string { + if strings.TrimSpace(prof.ID) != "" { + return prof.ID + } + return "agent-system" +} + // openLLMClient 不设 HTTP 客户端超时。单次生成可能很长,停止按钮通过 run 的 context 取消。 func openLLMClient(base, key string) *agentllm.Client { return &agentllm.Client{BaseURL: base, APIKey: key, HTTPClient: &http.Client{}} diff --git a/internal/runtime/llm_direct.go b/internal/runtime/llm_direct.go index aaeca00..4d9f5b8 100644 --- a/internal/runtime/llm_direct.go +++ b/internal/runtime/llm_direct.go @@ -204,6 +204,7 @@ func (l *LLMRunner) runDirect(rc RunCtx, stream agentllm.StreamFunc, model strin Reminders: st.reminders, PermissionAsk: PermissionAskOf(rc), Trace: l.Trace, + AgentName: agentNameOf(rc.Profile()), UnknownTool: func(call agentllm.ToolCall) agenttools.Result { return st.runTool(call.Name, call.Arguments) }, diff --git a/internal/runtime/sub_loop.go b/internal/runtime/sub_loop.go index 7098b82..566b334 100644 --- a/internal/runtime/sub_loop.go +++ b/internal/runtime/sub_loop.go @@ -110,6 +110,7 @@ func (l *SubLLMRunner) Execute(rc RunCtx) error { OnEvent: st.onEvent, PermissionAsk: PermissionAskOf(rc), Trace: l.Trace, + AgentName: agentNameOf(rc.Profile()), }, user) if len(st.parts) == 0 { st.parts = append(st.parts, core.Part{Type: core.PartText, Text: "(子代理未返回内容)"}) diff --git a/internal/settings/settings.go b/internal/settings/settings.go index 0558b3a..fc07d12 100644 --- a/internal/settings/settings.go +++ b/internal/settings/settings.go @@ -96,6 +96,8 @@ func Schema() []core.SettingDesc { {Key: "runtime.composeFinal", Group: "runtime", Label: "终轮整理回复", Type: core.SettingBool, Default: true, Effect: core.EffectNewRun, Description: "用过工具的回合结束后,再用主模型写一段直接回答用户的最终回复"}, {Key: "runtime.intentSemantic", Group: "runtime", Label: "意图语义裁决(慢通道)", Type: core.SettingBool, Default: false, Effect: core.EffectRestart, Description: "规则歧义时用 embedding 语义相似度裁决。需已配置 embedding 端点。默认关闭(行为与 I1 一致)"}, {Key: "runtime.intentGenerator", Group: "runtime", Label: "意图命令生成(慢通道)", Type: core.SettingBool, Default: false, Effect: core.EffectRestart, Description: "规则与语义都未命中时用轻量模型生成意图命令(幻觉 fail-closed 回退)。默认关闭(行为与 I1 一致)"}, + {Key: "telemetry.otlpEndpoint", Group: "telemetry", Label: "OTLP 端点", Type: core.SettingString, Default: "", Effect: core.EffectRestart, Description: "OTel HTTP JSON 上报端点(如 http://localhost:4318)。空 = 不导出(默认);环境变量 OTEL_EXPORTER_OTLP_ENDPOINT 作为后备"}, + {Key: "telemetry.serviceName", Group: "telemetry", Label: "遥测 service.name", Type: core.SettingString, Default: "agent-system-backend", Effect: core.EffectRestart, Description: "OTLP resource 的 service.name"}, {Key: "context.maxHistoryMessages", Group: "context", Label: "历史窗口条数", Type: core.SettingNumber, Default: 40, Effect: core.EffectNewRun}, {Key: "context.maxToolResultChars", Group: "context", Label: "工具结果上限(字符)", Type: core.SettingNumber, Default: 20000, Effect: core.EffectNewRun}, {Key: "context.userInstructions", Group: "context", Label: "个人指令", Type: core.SettingString, Default: "", Effect: core.EffectNewRun, Description: "每次对话附在上下文末尾,不改系统前缀"},