mirror of
https://github.com/BaaRai/ARTEX.git
synced 2026-11-13 11:40:53 +08:00
Comments, doc comments, UI labels, log and error messages, LLM prompt strings, markdown docs, test data and assertions. Identifiers, enum keys, routes, placeholders and code structure are unchanged. Notes: - docs/漏洞流量证据.md renamed to docs/vulnerability-traffic-evidence.md - tests that exercised CJK specific handling (GBK zip names, Chinese full text search) now use ASCII equivalents; go build passes and the test suite matches the pre translation baseline (remaining failures need a PostgreSQL DSN and fail identically on the original) - frontend mention syntax now uses English kinds (finding, asset, ...) matching the backend, chat mentions tests pass
124 lines
3.4 KiB
Go
124 lines
3.4 KiB
Go
package server
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
|
|
"github.com/Autumn-27/artex/db"
|
|
)
|
|
|
|
type taskLLMResolution struct {
|
|
ProfileID *int64 `json:"profile_id,omitempty"`
|
|
Name string `json:"name"`
|
|
Format string `json:"format"`
|
|
Model string `json:"model"`
|
|
Source string `json:"source"`
|
|
Available bool `json:"available"`
|
|
Reason string `json:"reason,omitempty"`
|
|
}
|
|
|
|
func (s *Server) resolutionFromProfile(p *db.LLMProfile, source string) taskLLMResolution {
|
|
if p == nil {
|
|
return taskLLMResolution{Source: source, Reason: "LLM profile does not exist"}
|
|
}
|
|
id := p.ID
|
|
result := taskLLMResolution{
|
|
ProfileID: &id,
|
|
Name: p.Name,
|
|
Format: p.Format,
|
|
Model: p.Model,
|
|
Source: source,
|
|
}
|
|
if p.APIKey == "" {
|
|
result.Reason = "LLM profile has no API Key set"
|
|
return result
|
|
}
|
|
if _, _, ok := s.providerForProfile(p.ID); !ok {
|
|
result.Reason = "LLM profile format or parameters are invalid"
|
|
return result
|
|
}
|
|
result.Available = true
|
|
return result
|
|
}
|
|
|
|
// resolveTaskRoleLLM mirrors taskLLMRuntime.current without creating a provider:
|
|
// role Agent binding -> explicit task chain -> active/global environment config.
|
|
// Database failures are returned rather than represented as an unavailable model.
|
|
func (s *Server) resolveTaskRoleLLM(t *Task, agentKey string) (taskLLMResolution, error) {
|
|
if s == nil || s.m == nil || s.m.pg == nil {
|
|
return taskLLMResolution{}, fmt.Errorf("database unavailable")
|
|
}
|
|
a, err := s.m.pg.GetAgentByKey(agentKey)
|
|
if err != nil {
|
|
return taskLLMResolution{}, fmt.Errorf("load agent %q: %w", agentKey, err)
|
|
}
|
|
if a != nil && a.LLMProfileID != nil {
|
|
p, err := s.m.pg.ProfileByID(*a.LLMProfileID)
|
|
if err != nil {
|
|
return taskLLMResolution{}, fmt.Errorf("load agent LLM profile: %w", err)
|
|
}
|
|
if p != nil {
|
|
resolved := s.resolutionFromProfile(p, "agent_binding")
|
|
if resolved.Available {
|
|
return resolved, nil
|
|
}
|
|
}
|
|
}
|
|
state := t.llmStateSnapshot()
|
|
if len(state.ProfileIDs) > 0 {
|
|
if state.ActiveID == nil {
|
|
return taskLLMResolution{Source: "task_chain", Reason: "task LLM profile chain quota exhausted"}, nil
|
|
}
|
|
p, err := s.m.pg.ProfileByID(*state.ActiveID)
|
|
if err != nil {
|
|
return taskLLMResolution{}, fmt.Errorf("load task LLM profile: %w", err)
|
|
}
|
|
return s.resolutionFromProfile(p, "task_chain"), nil
|
|
}
|
|
p, err := s.m.pg.ActiveProfile()
|
|
if err != nil {
|
|
return taskLLMResolution{}, fmt.Errorf("load global LLM profile: %w", err)
|
|
}
|
|
if p != nil {
|
|
resolved := s.resolutionFromProfile(p, "global_profile")
|
|
if resolved.Available {
|
|
return resolved, nil
|
|
}
|
|
}
|
|
s.cfgMu.Lock()
|
|
on, name, cfg := s.llmOn, s.llmProf, s.llmCfg
|
|
s.cfgMu.Unlock()
|
|
if on {
|
|
if name == "" {
|
|
name = "global configuration"
|
|
}
|
|
return taskLLMResolution{
|
|
Name: name, Format: cfg.Provider(), Model: cfg.Model,
|
|
Source: "environment", Available: true,
|
|
}, nil
|
|
}
|
|
return taskLLMResolution{Source: "global", Reason: "no available LLM profile"}, nil
|
|
}
|
|
|
|
func (s *Server) taskLLMResolutionHandler(w http.ResponseWriter, r *http.Request) {
|
|
t, ok := s.m.Task(r.PathValue("id"))
|
|
if !ok {
|
|
writeErr(w, 404, "task not found")
|
|
return
|
|
}
|
|
roles := map[string]taskLLMResolution{}
|
|
for responseKey, agentKey := range map[string]string{
|
|
"mainagent": "mainagent",
|
|
"planner": "planner",
|
|
"worker": "worker",
|
|
} {
|
|
resolved, err := s.resolveTaskRoleLLM(t, agentKey)
|
|
if err != nil {
|
|
writeErr(w, http.StatusInternalServerError, err.Error())
|
|
return
|
|
}
|
|
roles[responseKey] = resolved
|
|
}
|
|
writeJSON(w, http.StatusOK, roles)
|
|
}
|