Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions cmd/root/new.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,11 @@ func (f *newFlags) runNewCommand(cmd *cobra.Command, args []string) error {

sess := session.New(opts...)

return runTUI(ctx, "", rt, sess, firstMessage)
return runTUI(ctx, rt, sess, firstMessage)
}

func runTUI(ctx context.Context, agentFilename string, rt runtime.Runtime, sess *session.Session, firstMessage *string) error {
a := app.New(ctx, agentFilename, rt, sess, firstMessage)
func runTUI(ctx context.Context, rt runtime.Runtime, sess *session.Session, firstMessage *string) error {
a := app.New(ctx, rt, sess, firstMessage)
m := tui.New(ctx, a)

progOpts := []tea.ProgramOption{
Expand Down
12 changes: 6 additions & 6 deletions cmd/root/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,10 +114,10 @@ func (f *runExecFlags) runOrExec(ctx context.Context, out *cli.Printer, args []s
}

if !tui {
return f.handleExecMode(ctx, out, agentFileName, rt, sess, args)
return f.handleExecMode(ctx, out, rt, sess, args)
}

return handleRunMode(ctx, agentFileName, rt, sess, args)
return handleRunMode(ctx, rt, sess, args)
}

func (f *runExecFlags) loadAgentFrom(ctx context.Context, source teamloader.AgentSource) (*team.Team, error) {
Expand Down Expand Up @@ -187,7 +187,7 @@ func (f *runExecFlags) createLocalRuntimeAndSession(t *team.Team) (runtime.Runti
return localRt, sess, nil
}

func (f *runExecFlags) handleExecMode(ctx context.Context, out *cli.Printer, agentFilename string, rt runtime.Runtime, sess *session.Session, args []string) error {
func (f *runExecFlags) handleExecMode(ctx context.Context, out *cli.Printer, rt runtime.Runtime, sess *session.Session, args []string) error {
execArgs := []string{"exec"}
if len(args) == 2 {
execArgs = append(execArgs, args[1])
Expand All @@ -198,7 +198,7 @@ func (f *runExecFlags) handleExecMode(ctx context.Context, out *cli.Printer, age
err := cli.Run(ctx, out, cli.Config{
AppName: AppName,
AttachmentPath: f.attachmentPath,
}, agentFilename, rt, sess, execArgs)
}, rt, sess, execArgs)
if cliErr, ok := err.(cli.RuntimeError); ok {
return RuntimeError{Err: cliErr.Err}
}
Expand All @@ -222,11 +222,11 @@ func readInitialMessage(args []string) (*string, error) {
return &args[1], nil
}

func handleRunMode(ctx context.Context, agentFilename string, rt runtime.Runtime, sess *session.Session, args []string) error {
func handleRunMode(ctx context.Context, rt runtime.Runtime, sess *session.Session, args []string) error {
firstMessage, err := readInitialMessage(args)
if err != nil {
return err
}

return runTUI(ctx, agentFilename, rt, sess, firstMessage)
return runTUI(ctx, rt, sess, firstMessage)
}
2 changes: 1 addition & 1 deletion pkg/acp/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ func (a *Agent) Prompt(ctx context.Context, params acp.PromptRequest) (acp.Promp
}

if userContent != "" {
acpSess.sess.AddMessage(session.UserMessage(a.agentFilename, userContent))
acpSess.sess.AddMessage(session.UserMessage(userContent))
}

// Run the agent and stream updates
Expand Down
3 changes: 1 addition & 2 deletions pkg/api/pagination_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@ func createTestMessages(count int) []session.Message {
role = chat.MessageRoleAssistant
}
messages[i] = session.Message{
AgentFilename: "test.yaml",
AgentName: "test",
AgentName: "test",
Message: chat.Message{
Role: role,
Content: "Message " + strconv.Itoa(i),
Expand Down
15 changes: 7 additions & 8 deletions pkg/api/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,14 +115,13 @@ type DeleteAgentResponse struct {

// SessionsResponse represents a session in the sessions list
type SessionsResponse struct {
ID string `json:"id"`
Title string `json:"title"`
CreatedAt string `json:"created_at"`
NumMessages int `json:"num_messages"`
InputTokens int `json:"input_tokens"`
OutputTokens int `json:"output_tokens"`
GetMostRecentAgentFilename string `json:"most_recent_agent_filename"`
WorkingDir string `json:"working_dir,omitempty"`
ID string `json:"id"`
Title string `json:"title"`
CreatedAt string `json:"created_at"`
NumMessages int `json:"num_messages"`
InputTokens int `json:"input_tokens"`
OutputTokens int `json:"output_tokens"`
WorkingDir string `json:"working_dir,omitempty"`
}

// SessionResponse represents a detailed session
Expand Down
6 changes: 2 additions & 4 deletions pkg/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import (
)

type App struct {
agentFilename string
runtime runtime.Runtime
session *session.Session
firstMessage *string
Expand All @@ -25,9 +24,8 @@ type App struct {
cancel context.CancelFunc
}

func New(ctx context.Context, agentFilename string, rt runtime.Runtime, sess *session.Session, firstMessage *string) *App {
func New(ctx context.Context, rt runtime.Runtime, sess *session.Session, firstMessage *string) *App {
app := &App{
agentFilename: agentFilename,
runtime: rt,
session: sess,
firstMessage: firstMessage,
Expand Down Expand Up @@ -129,7 +127,7 @@ func (a *App) EmitStartupInfo(ctx context.Context, events chan runtime.Event) {
func (a *App) Run(ctx context.Context, cancel context.CancelFunc, message string) {
a.cancel = cancel
go func() {
a.session.AddMessage(session.UserMessage(a.agentFilename, message))
a.session.AddMessage(session.UserMessage(message))
for event := range a.runtime.RunStream(ctx, a.session) {
if ctx.Err() != nil {
return
Expand Down
12 changes: 6 additions & 6 deletions pkg/cli/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ type Config struct {
}

// Run executes an agent in non-TUI mode, handling user input and runtime events
func Run(ctx context.Context, out *Printer, cfg Config, agentFilename string, rt runtime.Runtime, sess *session.Session, args []string) error {
func Run(ctx context.Context, out *Printer, cfg Config, rt runtime.Runtime, sess *session.Session, args []string) error {
// Create a cancellable context for this agentic loop and wire Ctrl+C to cancel it
ctx, cancel := context.WithCancel(ctx)
defer cancel()
Expand Down Expand Up @@ -79,7 +79,7 @@ func Run(ctx context.Context, out *Printer, cfg Config, agentFilename string, rt
finalAttachPath = cfg.AttachmentPath
}

sess.AddMessage(createUserMessageWithAttachment(agentFilename, messageText, finalAttachPath))
sess.AddMessage(createUserMessageWithAttachment(messageText, finalAttachPath))

firstLoop := true
lastAgent := rt.CurrentAgentName()
Expand Down Expand Up @@ -390,16 +390,16 @@ func parseAttachCommand(userInput string) (messageText, attachPath string) {
}

// createUserMessageWithAttachment creates a user message with optional image attachment
func createUserMessageWithAttachment(agentFilename, userContent, attachmentPath string) *session.Message {
func createUserMessageWithAttachment(userContent, attachmentPath string) *session.Message {
if attachmentPath == "" {
return session.UserMessage(agentFilename, userContent)
return session.UserMessage(userContent)
}

// Convert file to data URL
dataURL, err := fileToDataURL(attachmentPath)
if err != nil {
slog.Warn("Failed to attach file", "path", attachmentPath, "error", err)
return session.UserMessage(agentFilename, userContent)
return session.UserMessage(userContent)
}

// Ensure we have some text content when attaching a file
Expand All @@ -423,7 +423,7 @@ func createUserMessageWithAttachment(agentFilename, userContent, attachmentPath
},
}

return session.UserMessage(agentFilename, "", multiContent...)
return session.UserMessage("", multiContent...)
}

// fileToDataURL converts a file to a data URL
Expand Down
4 changes: 2 additions & 2 deletions pkg/runtime/runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -1335,7 +1335,7 @@ func (r *LocalRuntime) handleTaskTransfer(ctx context.Context, sess *session.Ses

s := session.New(
session.WithSystemMessage(memberAgentTask),
session.WithImplicitUserMessage("", "Follow the default instructions"),
session.WithImplicitUserMessage("Follow the default instructions"),
session.WithMaxIterations(child.MaxIterations()),
session.WithTitle("Transferred task"),
session.WithToolsApproved(sess.ToolsApproved),
Expand Down Expand Up @@ -1489,7 +1489,7 @@ func (r *LocalRuntime) Summarize(ctx context.Context, sess *session.Session, eve
)

summarySession := session.New(session.WithSystemMessage(systemPrompt))
summarySession.AddMessage(session.UserMessage("", userPrompt))
summarySession.AddMessage(session.UserMessage(userPrompt))
summarySession.Title = "Generating summary..."

summaryRuntime, err := New(newTeam, WithSessionCompaction(false))
Expand Down
98 changes: 9 additions & 89 deletions pkg/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,20 +40,13 @@ type Server struct {
ociTeamKey string
agentsDir string
agentsPath string // For local files: specific file path to reload (instead of scanning agentsDir)
rootFS *os.Root
}

type Opt func(*Server) error

func WithAgentsDir(dir string) Opt {
return func(s *Server) error {
rootFs, err := os.OpenRoot(dir)
if err != nil {
return fmt.Errorf("failed to open root filesystem at %s: %w", dir, err)
}

s.agentsDir = dir
s.rootFS = rootFs
return nil
}
}
Expand Down Expand Up @@ -106,17 +99,11 @@ func New(sessionStore session.Store, runConfig *config.RuntimeConfig, teams map[

// List all available agents
group.GET("/agents", s.getAgents)
// Get an agent by id
group.GET("/agents/:id", s.getAgentConfig)
// Get an agent's raw YAML configuration by id
group.GET("/agents/:id/yaml", s.getAgentConfigYAML)

// SESSIONS

// List all sessions
group.GET("/sessions", s.getSessions)
// Get sessions by agent filename
group.GET("/sessions/agent/:id", s.getSessionsByAgent)
// Get a session by id
group.GET("/sessions/:id", s.getSession)
// Resume a session by id
Expand Down Expand Up @@ -154,7 +141,7 @@ func (s *Server) Serve(ctx context.Context, ln net.Listener) error {
// hasAgentsDir returns true if the server has a local agents directory.
// Returns false for OCI reference-based servers, which load from memory.
func (s *Server) hasAgentsDir() bool {
return s.agentsDir != "" && s.rootFS != nil
return s.agentsDir != ""
}

// getTeam retrieves a team by key with read lock
Expand Down Expand Up @@ -191,38 +178,6 @@ func (s *Server) getOCIRef(key string) (string, bool) {

// API handlers

func (s *Server) getAgentConfig(c echo.Context) error {
agentID := c.Param("id")
p := addYamlExt(agentID)

data, err := s.rootFS.ReadFile(p)
if err != nil {
return fmt.Errorf("reading config file %s: %w", p, err)
}

cfg, err := config.Load(c.Request().Context(), teamloader.NewBytesSource(data))
if err != nil {
slog.Error("Failed to load config", "error", err)
return echo.NewHTTPError(http.StatusNotFound, "agent not found")
}

return c.JSON(http.StatusOK, cfg)
}

func (s *Server) getAgentConfigYAML(c echo.Context) error {
agentID := c.Param("id")
p := addYamlExt(agentID)

// Read the YAML file
yamlContent, err := s.rootFS.ReadFile(p)
if err != nil {
slog.Error("Failed to read agent YAML file", "path", p, "error", err)
return echo.NewHTTPError(http.StatusInternalServerError, "failed to read agent file")
}

return c.String(http.StatusOK, string(yamlContent))
}

func (s *Server) getAgents(c echo.Context) error {
// Refresh agents from disk to get the latest configurations
// Only refresh for local files/dirs (hasAgentsDir == true)
Expand Down Expand Up @@ -346,41 +301,13 @@ func (s *Server) getSessions(c echo.Context) error {
responses := make([]api.SessionsResponse, len(sessions))
for i, sess := range sessions {
responses[i] = api.SessionsResponse{
ID: sess.ID,
Title: sess.Title,
CreatedAt: sess.CreatedAt.Format(time.RFC3339),
NumMessages: len(sess.GetAllMessages()),
InputTokens: sess.InputTokens,
OutputTokens: sess.OutputTokens,
GetMostRecentAgentFilename: sess.GetMostRecentAgentFilename(),
WorkingDir: sess.WorkingDir,
}
}
return c.JSON(http.StatusOK, responses)
}

func (s *Server) getSessionsByAgent(c echo.Context) error {
agentFilename := c.Param("id")
if agentFilename == "" {
return echo.NewHTTPError(http.StatusBadRequest, "id parameter is required")
}

sessions, err := s.sessionStore.GetSessionsByAgent(c.Request().Context(), agentFilename)
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, fmt.Sprintf("failed to get sessions for agent: %v", err))
}

responses := make([]api.SessionsResponse, len(sessions))
for i, sess := range sessions {
responses[i] = api.SessionsResponse{
ID: sess.ID,
Title: sess.Title,
CreatedAt: sess.CreatedAt.Format(time.RFC3339),
NumMessages: len(sess.GetAllMessages()),
InputTokens: sess.InputTokens,
OutputTokens: sess.OutputTokens,
GetMostRecentAgentFilename: sess.GetMostRecentAgentFilename(),
WorkingDir: sess.WorkingDir,
ID: sess.ID,
Title: sess.Title,
CreatedAt: sess.CreatedAt.Format(time.RFC3339),
NumMessages: len(sess.GetAllMessages()),
InputTokens: sess.InputTokens,
OutputTokens: sess.OutputTokens,
WorkingDir: sess.WorkingDir,
}
}
return c.JSON(http.StatusOK, responses)
Expand Down Expand Up @@ -540,7 +467,7 @@ func (s *Server) runAgent(c echo.Context) error {
}

for _, msg := range messages {
sess.AddMessage(session.UserMessage(agentFilename, msg.Content, msg.MultiContent...))
sess.AddMessage(session.UserMessage(msg.Content, msg.MultiContent...))
}

if err := s.sessionStore.UpdateSession(c.Request().Context(), sess); err != nil {
Expand Down Expand Up @@ -655,13 +582,6 @@ func (s *Server) loadTeamForSession(ctx context.Context, agentFilename string, s
return t, nil
}

func addYamlExt(filename string) string {
if strings.HasSuffix(filename, ".yaml") || strings.HasSuffix(filename, ".yml") {
return filename
}
return filename + ".yaml"
}

func (s *Server) elicitation(c echo.Context) error {
sessionID := c.Param("id")
var req api.ResumeElicitationRequest
Expand Down
Loading
Loading