package ai import ( "encoding/json" "regexp" "strings" ) // SeerBridge supplies persisted notes and streams LLM payloads to The Seer UI. type SeerBridge interface { NotesForPrompt(agentID string) string AppendNote(agentID, content, promptHash string) error EmitEvent(agentID, direction string, payload interface{}) } // SeerNoteInstruction is appended to the system prompt when Seer memory is active. var SeerNoteInstruction string // SeerToolCatalog documents fleet tool endpoints the model may invoke via tool-call JSON. var SeerToolCatalog string func init() { SeerNoteInstruction = strings.TrimSpace(` Seer memory: after your JSON commands block, append exactly one line: SEER_NOTE: . The server persists SEER_NOTE lines and replays them on the next turn — this is your only cross-turn memory.`) SeerToolCatalog = strings.TrimSpace(` Available Seer tool endpoints (POST /api/v1/seer/tools/{name}): - spread_route: BGP-style minimum-clearance spread routing — body {"session_id","target_subnets":[],"join_lane"} - graft_strain: clone winning spread strain onto sibling subnet — body {"source_agent_id","target_subnet","strain"} - fork_onion: split LOTL tier chain for A/B recovery — body {"agent_id","tier_order":[],"skip_tiers":[]} Stub handlers return {"ok":true,"stub":true} until live orchestration ships.`) } var seerNoteLineRe = regexp.MustCompile(`(?m)^SEER_NOTE:\s*(.+)$`) // AugmentUserPromptWithNotes prepends replayed Seer notes before the fresh snapshot. func AugmentUserPromptWithNotes(basePrompt, notesBlock string) string { notesBlock = strings.TrimSpace(notesBlock) if notesBlock == "" { return basePrompt } var b strings.Builder b.WriteString("Seer notes (server memory — replayed from prior turns):\n") b.WriteString(notesBlock) b.WriteString("\n\n--- current snapshot ---\n") b.WriteString(basePrompt) return b.String() } // FormatSeerNotesBlock renders DB notes for prompt injection. func FormatSeerNotesBlock(notes []string) string { if len(notes) == 0 { return "" } var b strings.Builder for i, n := range notes { n = strings.TrimSpace(n) if n == "" { continue } if i > 0 { b.WriteByte('\n') } b.WriteString("- ") b.WriteString(n) } return b.String() } // ExtractSeerNote pulls the SEER_NOTE line from an LLM response. func ExtractSeerNote(response string) (note string, ok bool) { m := seerNoteLineRe.FindStringSubmatch(response) if len(m) < 2 { return "", false } note = strings.TrimSpace(m[1]) if note == "" { return "", false } if len(note) > 2000 { note = note[:2000] } return note, true } // BuildChatCompletionPayload mirrors the exact OpenAI-compatible body sent to the LLM. func BuildChatCompletionPayload(model, systemPrompt, userPrompt string) map[string]interface{} { if strings.TrimSpace(model) == "" { model = "llama3.2" } return map[string]interface{}{ "model": model, "messages": []map[string]string{ {"role": "system", "content": systemPrompt}, {"role": "user", "content": userPrompt}, }, "stream": false, } } // SeerStreamEvent is one request/response frame for The Seer terminal. type SeerStreamEvent struct { ID int64 `json:"id"` AgentID string `json:"agent_id"` Direction string `json:"direction"` Payload json.RawMessage `json:"payload"` Ts string `json:"ts"` }