merge paths utilities into util

This commit is contained in:
Ollie Agent 2026-08-16 18:37:03 +02:00
parent 0758cef14e
commit 59c4ed23ac
23 changed files with 52 additions and 56 deletions

View File

@ -12,8 +12,8 @@ import (
"ollie/cmd/olliesrv/internal/backend" "ollie/cmd/olliesrv/internal/backend"
lib9p "ollie/lib9p/client" lib9p "ollie/lib9p/client"
olog "ollie/log" olog "ollie/log"
"ollie/paths"
toolsrvclient "ollie/toolsrv/client" toolsrvclient "ollie/toolsrv/client"
"ollie/util"
) )
// Agent holds the state of the current Agent entity (the "agent" // Agent holds the state of the current Agent entity (the "agent"
@ -528,7 +528,7 @@ func (ag *Agent) SetCWD(dir string) {
ag.stateMu.Lock() ag.stateMu.Lock()
ag.cwd = dir ag.cwd = dir
ag.stateMu.Unlock() ag.stateMu.Unlock()
isGitRepo := paths.IsGitRepo(dir) isGitRepo := util.IsGitRepo(dir)
ag.envBlock = EnvironmentBlock(dir, runtime.GOOS, isGitRepo, "") ag.envBlock = EnvironmentBlock(dir, runtime.GOOS, isGitRepo, "")
ag.runtime.Preamble.Set(SectionEnv, ag.envBlock) ag.runtime.Preamble.Set(SectionEnv, ag.envBlock)
if ag.runtime.ToolServer != nil { if ag.runtime.ToolServer != nil {

View File

@ -3,12 +3,12 @@ package agent
import ( import (
"os" "os"
"ollie/paths" "ollie/util"
) )
// AgentsDirs returns all agent directories. Currently just the default. // AgentsDirs returns all agent directories. Currently just the default.
func AgentsDirs() []string { func AgentsDirs() []string {
return []string{paths.CfgDir() + "/agents"} return []string{util.CfgDir() + "/agents"}
} }
// AgentConfigPath resolves the config file path for a named agent. // AgentConfigPath resolves the config file path for a named agent.

View File

@ -9,7 +9,7 @@ import (
"strings" "strings"
"ollie/cmd/olliesrv/internal/backend" "ollie/cmd/olliesrv/internal/backend"
"ollie/paths" "ollie/util"
) )
const ( const (
@ -43,13 +43,13 @@ func RestoreHistoryFromMessages(messages []backend.Message) *History {
} }
for i := range s.messages { for i := range s.messages {
if s.messages[i].Role == "assistant" && s.messages[i].ID == "" { if s.messages[i].Role == "assistant" && s.messages[i].ID == "" {
s.messages[i].ID = paths.NewUUID() s.messages[i].ID = util.NewUUID()
} }
if s.messages[i].Role == "tool" && s.messages[i].ID == "" { if s.messages[i].Role == "tool" && s.messages[i].ID == "" {
if s.messages[i].ToolCallID != "" { if s.messages[i].ToolCallID != "" {
s.messages[i].ID = toolMessageID(s.messages[i]) s.messages[i].ID = toolMessageID(s.messages[i])
} else { } else {
s.messages[i].ID = paths.NewUUID() s.messages[i].ID = util.NewUUID()
} }
} }
} }
@ -198,7 +198,7 @@ func (s *History) update(assistant backend.Message, results []toolResult) {
if r.ToolCallID != "" { if r.ToolCallID != "" {
m.ID = toolMessageID(m) m.ID = toolMessageID(m)
} else { } else {
m.ID = paths.NewUUID() m.ID = util.NewUUID()
} }
s.messages = append(s.messages, m) s.messages = append(s.messages, m)
} }
@ -504,7 +504,7 @@ func (s *History) stripCold(ctx context.Context, b backend.Backend) (backend.Usa
if m.ToolCallID != "" { if m.ToolCallID != "" {
id = toolMessageID(*m) id = toolMessageID(*m)
} else { } else {
id = paths.NewUUID() id = util.NewUUID()
} }
m.ID = id m.ID = id
} }

View File

@ -11,8 +11,8 @@ import (
"time" "time"
"ollie/cmd/olliesrv/internal/backend" "ollie/cmd/olliesrv/internal/backend"
"ollie/paths"
toolsrvclient "ollie/toolsrv/client" toolsrvclient "ollie/toolsrv/client"
"ollie/util"
) )
const maxTransientRetries = 3 const maxTransientRetries = 3
@ -124,7 +124,7 @@ func (ag *Agent) run(ctx context.Context) error {
history := h.history() history := h.history()
responseID := paths.NewUUID() responseID := util.NewUUID()
content, reasoning, toolCalls, stopReason, err := ag.streamResponse(ctx, history, responseID, step) content, reasoning, toolCalls, stopReason, err := ag.streamResponse(ctx, history, responseID, step)
if err != nil { if err != nil {
// On context cancellation mid-stream, persist partial state. // On context cancellation mid-stream, persist partial state.

View File

@ -5,7 +5,7 @@ import (
"os" "os"
"strings" "strings"
"ollie/paths" "ollie/util"
) )
// BackendConfig holds the per-backend configuration from backends.conf. // BackendConfig holds the per-backend configuration from backends.conf.
@ -26,7 +26,7 @@ type configFile struct {
// loadConfig reads ~/.config/ollie/backends.conf. // loadConfig reads ~/.config/ollie/backends.conf.
// Returns zero value if the file doesn't exist or is unreadable. // Returns zero value if the file doesn't exist or is unreadable.
func loadConfig() configFile { func loadConfig() configFile {
return parseConfigFile(paths.CfgDir() + "/backends.conf") return parseConfigFile(util.CfgDir() + "/backends.conf")
} }
// CompactionModel returns the configured compaction model for a backend. // CompactionModel returns the configured compaction model for a backend.

View File

@ -30,7 +30,7 @@ import (
"sync" "sync"
"time" "time"
"ollie/paths" "ollie/util"
) )
// ── Public constructor ──────────────────────────────────────────────────────── // ── Public constructor ────────────────────────────────────────────────────────
@ -336,8 +336,8 @@ func buildKiroRequest(model string, messages []Message, tools []Tool, profileARN
return nil, fmt.Errorf("last message role %q is not supported (expected user, system, or tool)", lastRole) return nil, fmt.Errorf("last message role %q is not supported (expected user, system, or tool)", lastRole)
} }
convID := paths.NewUUID() convID := util.NewUUID()
contID := paths.NewUUID() contID := util.NewUUID()
req := &kiroGenerateRequest{ req := &kiroGenerateRequest{
ProfileARN: profileARN, ProfileARN: profileARN,
@ -446,7 +446,7 @@ func encodeKiroAssistantMessage(m Message) *kiroAssistantResponseMessage {
} }
toolUseID := strings.TrimSpace(tc.ID) toolUseID := strings.TrimSpace(tc.ID)
if toolUseID == "" { if toolUseID == "" {
toolUseID = paths.NewUUID() toolUseID = util.NewUUID()
} }
msg.ToolUses = append(msg.ToolUses, kiroToolUse{ msg.ToolUses = append(msg.ToolUses, kiroToolUse{
ToolUseID: toolUseID, ToolUseID: toolUseID,
@ -1471,5 +1471,5 @@ func newKiroAuthSource(apiKey string) (kiroAuthSource, error) {
} }
func kiroDefaultSQLiteKey() string { func kiroDefaultSQLiteKey() string {
return "sqlite://" + filepath.Join(paths.UserDataHome(), "kiro-cli", "data.sqlite3") return "sqlite://" + filepath.Join(util.UserDataHome(), "kiro-cli", "data.sqlite3")
} }

View File

@ -23,7 +23,7 @@ import (
"net/url" "net/url"
"strings" "strings"
"ollie/paths" "ollie/util"
) )
// ── Wire types ──────────────────────────────────────────────────────────────── // ── Wire types ────────────────────────────────────────────────────────────────
@ -511,7 +511,7 @@ type kiroToolUseAccumulator struct {
} }
func (c *kiroAPIClient) applyHeaders(req *http.Request) error { func (c *kiroAPIClient) applyHeaders(req *http.Request) error {
invocationID := paths.NewUUID() invocationID := util.NewUUID()
req.Header.Set("Content-Type", "application/x-amz-json-1.0") req.Header.Set("Content-Type", "application/x-amz-json-1.0")
req.Header.Set("X-Amz-Target", kiroGenerateTarget) req.Header.Set("X-Amz-Target", kiroGenerateTarget)
req.Header.Set("Authorization", "Bearer "+c.token) req.Header.Set("Authorization", "Bearer "+c.token)
@ -666,7 +666,7 @@ func (c *kiroOIDCClient) RefreshToken(ctx context.Context, req kiroRefreshTokenR
if err != nil { if err != nil {
return nil, fmt.Errorf("build refresh request: %w", err) return nil, fmt.Errorf("build refresh request: %w", err)
} }
invocationID := paths.NewUUID() invocationID := util.NewUUID()
httpReq.Header.Set("Content-Type", "application/json") httpReq.Header.Set("Content-Type", "application/json")
httpReq.Header.Set("Accept", "*/*") httpReq.Header.Set("Accept", "*/*")
httpReq.Header.Set("Accept-Encoding", "gzip") httpReq.Header.Set("Accept-Encoding", "gzip")
@ -748,7 +748,7 @@ func (c *kiroAPIClient) ListModels(ctx context.Context, profileARN string) (*kir
if err != nil { if err != nil {
return nil, err return nil, err
} }
invocationID := paths.NewUUID() invocationID := util.NewUUID()
req.Header.Set("Content-Type", "application/x-amz-json-1.0") req.Header.Set("Content-Type", "application/x-amz-json-1.0")
req.Header.Set("X-Amz-Target", kiroListModelsTarget) req.Header.Set("X-Amz-Target", kiroListModelsTarget)
req.Header.Set("Authorization", "Bearer "+c.token) req.Header.Set("Authorization", "Bearer "+c.token)

View File

@ -17,7 +17,7 @@ import (
"ollie/cmd/olliesrv/internal/backend" "ollie/cmd/olliesrv/internal/backend"
"ollie/cmd/olliesrv/internal/metrics" "ollie/cmd/olliesrv/internal/metrics"
"ollie/cmd/olliesrv/internal/session" "ollie/cmd/olliesrv/internal/session"
"ollie/paths" "ollie/util"
"ollie/virtfs" "ollie/virtfs"
) )
@ -745,7 +745,7 @@ func buildAgentChildren(a *agent.Agent, s *session.Session) []virtfs.FsNodeDecl
if len(args) == 0 { if len(args) == 0 {
return []byte(a.Cwd() + "\n"), nil return []byte(a.Cwd() + "\n"), nil
} }
dir := paths.ExpandHome(strings.Join(args, " ")) dir := util.ExpandHome(strings.Join(args, " "))
if _, err := os.Stat(dir); err != nil { if _, err := os.Stat(dir); err != nil {
return nil, fmt.Errorf("cwd: %w", err) return nil, fmt.Errorf("cwd: %w", err)
} }

View File

@ -12,7 +12,7 @@ import (
"time" "time"
"ollie/cmd/olliesrv/internal/backend" "ollie/cmd/olliesrv/internal/backend"
"ollie/paths" "ollie/util"
) )
// Record is one backend usage event. Records are append-only and independently // Record is one backend usage event. Records are append-only and independently
@ -178,7 +178,7 @@ func (a *Aggregate) add(r Record) {
var appendMu sync.Mutex var appendMu sync.Mutex
// EventsPath returns the append-only metrics event log path. // EventsPath returns the append-only metrics event log path.
func EventsPath() string { return filepath.Join(paths.DataDir(), "metrics", "events.jsonl") } func EventsPath() string { return filepath.Join(util.DataDir(), "metrics", "events.jsonl") }
// RecordUsage appends one usage event to the global metrics log. // RecordUsage appends one usage event to the global metrics log.
func RecordUsage(sessionID, agentID, backendName, model string, u backend.Usage, estimated bool) error { func RecordUsage(sessionID, agentID, backendName, model string, u backend.Usage, estimated bool) error {

View File

@ -20,7 +20,7 @@ import (
"ollie/cmd/olliesrv/internal/agent" "ollie/cmd/olliesrv/internal/agent"
"ollie/cmd/olliesrv/internal/backend" "ollie/cmd/olliesrv/internal/backend"
olog "ollie/log" olog "ollie/log"
"ollie/paths" "ollie/util"
) )
// Package-level session registry with thread-safe access. // Package-level session registry with thread-safe access.
@ -284,7 +284,7 @@ func BuildAgentIndex(sess *Session) []byte {
// CreateEmpty creates an empty session (no agent) and registers it. // CreateEmpty creates an empty session (no agent) and registers it.
func CreateEmpty(name, remote string) (*Session, error) { func CreateEmpty(name, remote string) (*Session, error) {
sessID := paths.NewUUID() sessID := util.NewUUID()
if name == "" { if name == "" {
name = sessID name = sessID
if idx := strings.IndexByte(sessID, '-'); idx > 0 { if idx := strings.IndexByte(sessID, '-'); idx > 0 {

View File

@ -13,9 +13,9 @@ import (
"ollie/cmd/olliesrv/internal/backend" "ollie/cmd/olliesrv/internal/backend"
"ollie/cmd/olliesrv/internal/toolclient" "ollie/cmd/olliesrv/internal/toolclient"
olog "ollie/log" olog "ollie/log"
"ollie/paths"
toolsrvclient "ollie/toolsrv/client" toolsrvclient "ollie/toolsrv/client"
"ollie/toolsrv/protocol" "ollie/toolsrv/protocol"
"ollie/util"
) )
// Session owns all session-level state: identity, agents, tool server lifecycle. // Session owns all session-level state: identity, agents, tool server lifecycle.
@ -57,7 +57,7 @@ type Session struct {
var sweepTmpOnce sync.Once var sweepTmpOnce sync.Once
func ollieTmpDir() string { func ollieTmpDir() string {
return filepath.Join(paths.DataDir(), "tmp") return filepath.Join(util.DataDir(), "tmp")
} }
func sweepStaleTmpDirs() { func sweepStaleTmpDirs() {

View File

@ -7,8 +7,8 @@ import (
"ollie/cmd/olliesrv/internal/agent" "ollie/cmd/olliesrv/internal/agent"
"ollie/cmd/olliesrv/internal/prompts" "ollie/cmd/olliesrv/internal/prompts"
"ollie/cmd/olliesrv/internal/toolclient" "ollie/cmd/olliesrv/internal/toolclient"
"ollie/paths"
toolsrvclient "ollie/toolsrv/client" toolsrvclient "ollie/toolsrv/client"
"ollie/util"
) )
// SessionInfra holds the tool server infrastructure for a session. // SessionInfra holds the tool server infrastructure for a session.
@ -74,7 +74,7 @@ func SetupToolServer(cfg ToolServerConfig) (*SessionInfra, error) {
ToolsConn: newToolServer(), ToolsConn: newToolServer(),
NewToolServer: newToolServer, NewToolServer: newToolServer,
Platform: "linux", Platform: "linux",
IsGitRepo: paths.IsGitRepo(cfg.CWD), IsGitRepo: util.IsGitRepo(cfg.CWD),
}, nil }, nil
} }
var proc *toolclient.Process var proc *toolclient.Process
@ -134,7 +134,7 @@ func SetupToolServer(cfg ToolServerConfig) (*SessionInfra, error) {
return conn return conn
} }
platform = "linux" platform = "linux"
isGitRepo = paths.IsGitRepo(cfg.CWD) isGitRepo = util.IsGitRepo(cfg.CWD)
} }
toolsConn := newToolServer() toolsConn := newToolServer()

View File

@ -17,8 +17,8 @@ import (
"syscall" "syscall"
"time" "time"
"ollie/paths"
toolsrvclient "ollie/toolsrv/client" toolsrvclient "ollie/toolsrv/client"
"ollie/util"
) )
// Process represents a running toolsrv process. // Process represents a running toolsrv process.
@ -148,13 +148,13 @@ type RemoteConfig struct {
// remote host, then starts toolsrv with SSH Unix socket forwarding. // remote host, then starts toolsrv with SSH Unix socket forwarding.
func SpawnRemote(ctx context.Context, cfg RemoteConfig) (*Process, error) { func SpawnRemote(ctx context.Context, cfg RemoteConfig) (*Process, error) {
// Verify local config dir exists // Verify local config dir exists
cfgDir := paths.CfgDir() cfgDir := util.CfgDir()
if _, err := os.Stat(cfgDir); err != nil { if _, err := os.Stat(cfgDir); err != nil {
return nil, fmt.Errorf("local config dir not found at %s", cfgDir) return nil, fmt.Errorf("local config dir not found at %s", cfgDir)
} }
// Generate socket paths // Generate socket paths
sockDir := filepath.Join(paths.RuntimeDir(), "ollie") sockDir := filepath.Join(util.RuntimeDir(), "ollie")
os.MkdirAll(sockDir, 0700) os.MkdirAll(sockDir, 0700)
localSock := filepath.Join(sockDir, fmt.Sprintf("remote-%d-%s.sock", os.Getpid(), randomHex(8))) localSock := filepath.Join(sockDir, fmt.Sprintf("remote-%d-%s.sock", os.Getpid(), randomHex(8)))
remoteSock := fmt.Sprintf("/tmp/ollie-toolsrv-%d-%s.sock", os.Getpid(), randomHex(8)) remoteSock := fmt.Sprintf("/tmp/ollie-toolsrv-%d-%s.sock", os.Getpid(), randomHex(8))

View File

@ -14,7 +14,6 @@ import (
"ollie/cmd/olliesrv/internal/agent" "ollie/cmd/olliesrv/internal/agent"
"ollie/cmd/olliesrv/internal/fs" "ollie/cmd/olliesrv/internal/fs"
olog "ollie/log" olog "ollie/log"
"ollie/paths"
"ollie/util" "ollie/util"
"9fans.net/go/plan9/client" "9fans.net/go/plan9/client"
@ -57,7 +56,7 @@ func runServer(sockPath string) {
sink := olog.NewSink(os.Stdout, os.Stderr, olog.ParseLevel(os.Getenv("OLLIE_LOG"), olog.LevelWarn)) sink := olog.NewSink(os.Stdout, os.Stderr, olog.ParseLevel(os.Getenv("OLLIE_LOG"), olog.LevelWarn))
agentsDirs := agent.AgentsDirs() agentsDirs := agent.AgentsDirs()
sessionsDir := paths.DataDir() + "/sessions" sessionsDir := util.DataDir() + "/sessions"
daemonCtx, daemonCancel := context.WithCancel(context.Background()) daemonCtx, daemonCancel := context.WithCancel(context.Background())
defer daemonCancel() defer daemonCancel()

View File

@ -16,9 +16,9 @@ import (
"ollie/cmd/toolsrv/internal/bypass" "ollie/cmd/toolsrv/internal/bypass"
"ollie/cmd/toolsrv/internal/sandbox" "ollie/cmd/toolsrv/internal/sandbox"
"ollie/paths"
"ollie/toolsrv/metadata" "ollie/toolsrv/metadata"
"ollie/toolsrv/protocol" "ollie/toolsrv/protocol"
"ollie/util"
) )
// Config contains all context needed for tool execution. // Config contains all context needed for tool execution.
@ -114,7 +114,7 @@ func ExecuteTool(ctx context.Context, info protocol.ToolInfo, args json.RawMessa
func executeSandboxed(ctx context.Context, toolPath, stdinData, cwd string, envExtra map[string]string, timeout int, yolo bool, streamOut io.Writer, started chan *os.Process) (string, error) { func executeSandboxed(ctx context.Context, toolPath, stdinData, cwd string, envExtra map[string]string, timeout int, yolo bool, streamOut io.Writer, started chan *os.Process) (string, error) {
var sandboxCfg *sandbox.Config var sandboxCfg *sandbox.Config
if !yolo { if !yolo {
cfgPath := filepath.Join(paths.CfgDir(), "sandbox.yaml") cfgPath := filepath.Join(util.CfgDir(), "sandbox.yaml")
f, err := os.Open(cfgPath) f, err := os.Open(cfgPath)
if err != nil { if err != nil {
return "", fmt.Errorf("sandbox config not found: %w", err) return "", fmt.Errorf("sandbox config not found: %w", err)

View File

@ -8,7 +8,7 @@ import (
"regexp" "regexp"
"strings" "strings"
"ollie/paths" "ollie/util"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
) )
@ -106,7 +106,7 @@ func expandPath(pattern, cwd string, getenv EnvFunc) string {
return match return match
}) })
s = paths.ExpandHome(s) s = util.ExpandHome(s)
return s return s
} }

View File

@ -18,8 +18,8 @@ import (
"ollie/cmd/toolsrv/internal/exec" "ollie/cmd/toolsrv/internal/exec"
"ollie/cmd/toolsrv/internal/registry" "ollie/cmd/toolsrv/internal/registry"
"ollie/paths"
"ollie/toolsrv/protocol" "ollie/toolsrv/protocol"
"ollie/util"
) )
// State implements the filesystem state for toolsrvclient. // State implements the filesystem state for toolsrvclient.
@ -119,7 +119,7 @@ func (st *State) CWD() string {
// SetCWD sets the current working directory. // SetCWD sets the current working directory.
func (st *State) SetCWD(dir string) { func (st *State) SetCWD(dir string) {
st.mu.Lock() st.mu.Lock()
st.cwd = paths.ExpandHome(dir) st.cwd = util.ExpandHome(dir)
st.mu.Unlock() st.mu.Unlock()
} }

View File

@ -29,10 +29,9 @@ import (
"ollie/cmd/toolsrv/internal/registry" "ollie/cmd/toolsrv/internal/registry"
"ollie/cmd/toolsrv/internal/server" "ollie/cmd/toolsrv/internal/server"
lib9p "ollie/lib9p/client" lib9p "ollie/lib9p/client"
"ollie/util"
olog "ollie/log" olog "ollie/log"
"ollie/paths" "ollie/util"
) )
var ( var (
@ -66,7 +65,7 @@ func main() {
} }
// Expand ~ in CWD (shell doesn't expand ~ in arguments). // Expand ~ in CWD (shell doesn't expand ~ in arguments).
*cwd = paths.ExpandHome(*cwd) *cwd = util.ExpandHome(*cwd)
// Set up logger // Set up logger
sink := olog.NewSink(os.Stdout, os.Stderr, olog.LevelInfo) sink := olog.NewSink(os.Stdout, os.Stderr, olog.LevelInfo)

View File

@ -3,7 +3,7 @@ package lsp
import ( import (
"path/filepath" "path/filepath"
"ollie/paths" "ollie/util"
) )
// Adapter describes an LSP server for a specific language. // Adapter describes an LSP server for a specific language.
@ -109,7 +109,7 @@ func LanguageID(path string) string {
// SockPath returns the path to the bridge Unix socket. // SockPath returns the path to the bridge Unix socket.
func SockPath() string { func SockPath() string {
return filepath.Join(paths.RuntimeDir(), "ollie-lsp.sock") return filepath.Join(util.RuntimeDir(), "ollie-lsp.sock")
} }
// PidPath returns the path to the bridge PID file. // PidPath returns the path to the bridge PID file.

View File

@ -7,14 +7,12 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
"ollie/paths"
) )
// EnsureEnv loads $XDG_CONFIG_HOME/ollie/env and sets default values for any // EnsureEnv loads $XDG_CONFIG_HOME/ollie/env and sets default values for any
// OLLIE_* vars not already present in the process environment. // OLLIE_* vars not already present in the process environment.
func EnsureEnv() { func EnsureEnv() {
f, err := os.Open(filepath.Join(paths.CfgDir(), "env")) f, err := os.Open(filepath.Join(CfgDir(), "env"))
if err != nil { if err != nil {
return return
} }
@ -39,7 +37,7 @@ func EnsureEnv() {
v = v[1 : len(v)-1] v = v[1 : len(v)-1]
} }
if k != "" && os.Getenv(k) == "" { if k != "" && os.Getenv(k) == "" {
os.Setenv(k, paths.ExpandHome(os.ExpandEnv(v))) //nolint:errcheck os.Setenv(k, ExpandHome(os.ExpandEnv(v))) //nolint:errcheck
} }
} }
} }

View File

@ -1,4 +1,4 @@
package paths package util
import ( import (
"fmt" "fmt"

View File

@ -1,4 +1,4 @@
package paths package util
import ( import (
"os" "os"

View File

@ -1,4 +1,4 @@
package paths package util
import ( import (
"crypto/rand" "crypto/rand"