mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
Fixes: coder/internal#1441 - Move `contextConfigAPI` init from `handleManifest` to `init()`, matching all other API fields - Change `agentcontextconfig.NewAPI` to accept `func() string` closure (lazy directory evaluation) - `Config()` and HTTP handler now compute on demand via `a.manifest.Load().Directory` - Widen `TestAgent_Reconnect` to loop 5 reconnections with a non-empty manifest directory - Add `TestContextConfigAPI_InitOnce` internal test verifying lazy eval across manifest changes - Add `TestNewAPI_LazyDirectory` unit test for the lazy contract > 🤖 Written by a Coder Agent. Reviewed by a human.
85 lines
2.9 KiB
Go
85 lines
2.9 KiB
Go
package agentcontextconfig
|
|
|
|
import (
|
|
"cmp"
|
|
"net/http"
|
|
"os"
|
|
"strings"
|
|
|
|
"github.com/go-chi/chi/v5"
|
|
|
|
"github.com/coder/coder/v2/coderd/httpapi"
|
|
"github.com/coder/coder/v2/codersdk/workspacesdk"
|
|
)
|
|
|
|
// Env var names for context configuration. Prefixed with EXP_
|
|
// to indicate these are experimental and may change.
|
|
const (
|
|
EnvInstructionsDirs = "CODER_AGENT_EXP_INSTRUCTIONS_DIRS"
|
|
EnvInstructionsFile = "CODER_AGENT_EXP_INSTRUCTIONS_FILE"
|
|
EnvSkillsDirs = "CODER_AGENT_EXP_SKILLS_DIRS"
|
|
EnvSkillMetaFile = "CODER_AGENT_EXP_SKILL_META_FILE"
|
|
EnvMCPConfigFiles = "CODER_AGENT_EXP_MCP_CONFIG_FILES"
|
|
)
|
|
|
|
// Defaults are defined in codersdk/workspacesdk so both
|
|
// the agent and server can reference them without a
|
|
// cross-layer import.
|
|
|
|
// API exposes the resolved context configuration through the
|
|
// agent's HTTP API.
|
|
type API struct {
|
|
workingDir func() string
|
|
}
|
|
|
|
// NewAPI accepts a closure that returns the working directory.
|
|
// The directory is evaluated lazily on each call to Config(),
|
|
// so the caller can update it after construction.
|
|
func NewAPI(workingDir func() string) *API {
|
|
if workingDir == nil {
|
|
workingDir = func() string { return "" }
|
|
}
|
|
return &API{workingDir: workingDir}
|
|
}
|
|
|
|
// Config reads env vars and resolves paths. Exported for use
|
|
// by the MCP manager and tests.
|
|
func Config(workingDir string) workspacesdk.ContextConfigResponse {
|
|
// TrimSpace all env vars before cmp.Or so that a
|
|
// whitespace-only value falls through to the default
|
|
// consistently. ResolvePaths also trims each comma-
|
|
// separated entry, but without pre-trimming here a
|
|
// bare " " would bypass cmp.Or and produce nil.
|
|
instructionsDir := cmp.Or(strings.TrimSpace(os.Getenv(EnvInstructionsDirs)), workspacesdk.DefaultInstructionsDir)
|
|
instructionsFile := cmp.Or(strings.TrimSpace(os.Getenv(EnvInstructionsFile)), workspacesdk.DefaultInstructionsFile)
|
|
skillsDir := cmp.Or(strings.TrimSpace(os.Getenv(EnvSkillsDirs)), workspacesdk.DefaultSkillsDir)
|
|
skillMetaFile := cmp.Or(strings.TrimSpace(os.Getenv(EnvSkillMetaFile)), workspacesdk.DefaultSkillMetaFile)
|
|
mcpConfigFile := cmp.Or(strings.TrimSpace(os.Getenv(EnvMCPConfigFiles)), workspacesdk.DefaultMCPConfigFile)
|
|
|
|
return workspacesdk.ContextConfigResponse{
|
|
InstructionsDirs: ResolvePaths(instructionsDir, workingDir),
|
|
InstructionsFile: instructionsFile,
|
|
SkillsDirs: ResolvePaths(skillsDir, workingDir),
|
|
SkillMetaFile: skillMetaFile,
|
|
MCPConfigFiles: ResolvePaths(mcpConfigFile, workingDir),
|
|
}
|
|
}
|
|
|
|
// Config returns the resolved config for use by other agent
|
|
// components (e.g. MCP manager).
|
|
func (api *API) Config() workspacesdk.ContextConfigResponse {
|
|
return Config(api.workingDir())
|
|
}
|
|
|
|
// Routes returns the HTTP handler for the context config
|
|
// endpoint.
|
|
func (api *API) Routes() http.Handler {
|
|
r := chi.NewRouter()
|
|
r.Get("/", api.handleGet)
|
|
return r
|
|
}
|
|
|
|
func (api *API) handleGet(rw http.ResponseWriter, r *http.Request) {
|
|
httpapi.Write(r.Context(), rw, http.StatusOK, api.Config())
|
|
}
|