app

package
v0.710.6 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 11, 2026 License: MIT Imports: 85 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ErrEnrichmentTimeout = errors.New("enrichment loop timed out")

ErrEnrichmentTimeout is wrapped into the error runLoop returns when the loop did not finish within its configured timeout, so EnrichContextForSession can tell a timeout apart from every other failure without string matching.

Functions

func RefreshDynamicModels added in v0.416.3

func RefreshDynamicModels(ctx context.Context)

RefreshDynamicModels fetches and caches models from all configured provider accounts. It is safe to call concurrently and is exported so other startup modes (e.g. LLM Proxy) can trigger the same refresh without a full App instance.

func StartModelRefreshLoop added in v0.416.3

func StartModelRefreshLoop(ctx context.Context)

StartModelRefreshLoop refreshes dynamic models immediately and then every 24 h until ctx is cancelled. Use this in startup modes that do not create a full App instance (e.g. LLM Proxy).

Types

type App

type App struct {
	Sessions    session.Service
	Messages    message.Service
	History     history.Service
	Permissions permission.Service
	UserInput   userinput.Service
	DBQuerier   db.Querier

	CoderAgent agent.Service

	Projects            project.Service
	ProjectManager      *project.Manager
	AgentVCS            agentvcs.Service
	LSPClients          map[string]*lsp.Client
	SkillManager        *skills.SkillManager
	MesnadaOrchestrator *mesnadaOrch.Orchestrator
	CronService         *cronjob.Service
	MesnadaServer       *mesnadaServer.Server
	Remembrances        *rag.RemembrancesService
	ContextEnricher     *rag.ContextEnricher
	LuaManager          *luaengine.FilterManager
	MCPGateway          *mcpgateway.Gateway
	Evaluator           *evaluator.EvaluatorService

	// Extensions owns the compiled-in extensions (pkg/extension). It is always
	// non-nil; a build with no extensions simply holds an empty manager.
	Extensions *extension.Manager

	// MemorySink is the fan-out from remembrance writes to the extensions that
	// observe them. Nil unless [Extensions.Memory] opens the gate and a loaded
	// extension implements extension.MemorySink.
	MemorySink *extensions.MemoryPublisher

	// Identity reports who the host is running for, when a loaded extension
	// implements extension.IdentityProvider. It is always non-nil and is asked
	// per use, never cached, so a sign-in or a sign-out during a run takes
	// effect without a restart. With no provider it always reports false and
	// every consumer behaves exactly as an unextended Pando.
	Identity func(ctx context.Context) (extensions.Identity, bool)

	// UIPolicy reports what the settings surfaces should hide and what they
	// should render read-only, when a loaded extension implements
	// extension.UIPolicyProvider. It is always non-nil and is asked at render
	// time, so a policy that appears or disappears during a run takes effect on
	// the next rebuild. With no provider it returns the zero policy and every
	// surface behaves exactly as an unextended Pando.
	UIPolicy func(ctx context.Context) extensions.UIPolicy

	// IPCBus is set on the primary instance after calling SetupIPC, or by a
	// failover promotion. Secondary instances leave this nil. Guarded by ipcMu.
	IPCBus *ipc.Bus
	// contains filtered or unexported fields
}

func New

func New(ctx context.Context, conn *sql.DB, opts ...AppOptions) (*App, error)

func (*App) ACPDBCompactor added in v0.605.1

func (app *App) ACPDBCompactor() mesnadaACP.DBCompactor

ACPDBCompactor returns an ACP DBCompactor backed by this app's CompactDatabase.

func (*App) ApplyCronJobsFromPeer added in v0.710.6

func (app *App) ApplyCronJobsFromPeer(jobs config.CronJobsConfig) (protocol.CronJobReloadResult, error)

ApplyCronJobsFromPeer is the primary's cronjob.reload handler body: it installs jobs as the in-memory cron configuration (config.SetCronJobsInMemory: no file write, no config.Reload, so in-memory runtime overrides survive) and reschedules the cron service. The file was already written by the sender.

func (*App) Clients added in v0.503.5

func (app *App) Clients() map[string]*lsp.Client

Clients returns a snapshot copy of all running LSP clients.

func (*App) ClientsForFile added in v0.503.5

func (app *App) ClientsForFile(path string) map[string]*lsp.Client

ClientsForFile returns a snapshot of the running LSP clients that handle the given file. The returned map is a copy, safe to iterate without holding the app lock while clients are added or removed concurrently.

func (*App) CompactDatabase added in v0.605.1

func (app *App) CompactDatabase(ctx context.Context, incremental, enableAutoVacuum bool) (protocol.DBCompactResult, error)

CompactDatabase reclaims unused space in the SQLite database (VACUUM). Because only the primary owns DB writes, this is a single funnel used by every UI (/db-compact in TUI/WebUI/ACP) and the IPC db.compact handler:

  • On the primary (or when IPC is not active) it runs db.Compact directly on the read-write connection.
  • On a secondary it forwards the request to the primary over IPC and returns the primary's result, so two writers never contend for the database.

incremental runs only PRAGMA incremental_vacuum; enableAutoVacuum switches the database to auto_vacuum=INCREMENTAL before the full VACUUM.

func (*App) EnsureForFile added in v0.503.5

func (app *App) EnsureForFile(ctx context.Context, path string)

EnsureForFile implements the lazy-activation half of the LSP provider used by the tools. It is a thin wrapper around EnsureLSPForFile.

func (*App) EnsureForFileTrigger added in v0.629.4

func (app *App) EnsureForFileTrigger(ctx context.Context, path string, trigger config.LSPTrigger)

EnsureForFileTrigger implements the trigger-aware half of the LSP provider, letting each tool declare why it wants a language server.

func (*App) EnsureLSPForFile added in v0.503.5

func (app *App) EnsureLSPForFile(ctx context.Context, path string)

EnsureLSPForFile lazily activates the language server(s) for a file Pando is about to modify. It is shorthand for EnsureLSPForFileTrigger with the edit trigger.

func (*App) EnsureLSPForFileTrigger added in v0.629.4

func (app *App) EnsureLSPForFileTrigger(ctx context.Context, path string, trigger config.LSPTrigger)

EnsureLSPForFileTrigger lazily activates the language server(s) that handle the given file's extension, provided the configuration allows the trigger to start a server (see Config.LSPActivateOn).

It is safe to call frequently (e.g. on every edit): servers already running, currently spawning, or known-broken are skipped, and a server whose binary is not on PATH is recorded so it is not retried. When several preset servers handle the same extension only the first installed one is started, while servers the user configured explicitly are always honored.

func (*App) EnsurePrimary added in v0.326.0

func (app *App) EnsurePrimary(ctx context.Context)

EnsurePrimary performs an active liveness probe of the primary and, if the primary is unreachable and auto-failover is enabled, triggers the failover sequence. Must be called before processing each user prompt on a secondary instance. Safe to call on the primary instance (no-op).

func (*App) ForwardCronJobsToPrimary added in v0.710.6

func (app *App) ForwardCronJobsToPrimary(ctx context.Context, jobs config.CronJobsConfig) (bool, error)

ForwardCronJobsToPrimary sends jobs (a cron configuration this process has just persisted with config.UpdateCronJobs) to the IPC primary over the cronjob.reload RPC. It reports whether a forward was attempted: on the primary itself, or without IPC, there is nobody to tell and it returns (false, nil) — the caller's own CronService.Reload already covered it.

Cron jobs live in the config file, not the database, so no changepub event reaches the primary, and only a TUI watches the file. Without this call a non-TUI primary (ACP, mcp-server, serve, ...) would keep scheduling the old jobs until it restarts.

func (*App) IsIPCPrimary added in v0.710.6

func (app *App) IsIPCPrimary() bool

IsIPCPrimary reports whether this instance currently holds the IPC primary role (started as primary, or promoted by failover).

func (*App) LSPActivationSettings added in v0.629.4

func (app *App) LSPActivationSettings() config.LSPActivationSettings

LSPActivationSettings returns the global on-demand knobs, so a surface can render them next to the per-server statuses.

func (*App) LSPCatalog added in v0.629.4

func (app *App) LSPCatalog() []tools.LSPCatalogEntry

LSPCatalog implements tools.SetupLSPCatalog: it is the same report as LSPServerStatuses, in the shape the pando_setup tool consumes.

func (*App) LSPServerStatusByName added in v0.629.4

func (app *App) LSPServerStatusByName(name string) (LSPServerStatus, bool)

LSPServerStatusByName returns the status of a single server.

func (*App) LSPServerStatuses added in v0.629.4

func (app *App) LSPServerStatuses() []LSPServerStatus

LSPServerStatuses describes every server in the registry: the presets plus anything the user configured. It is the single source of truth behind the TUI settings page, the REST config API and the pando_setup tool, so all three agree on what "installed" means.

Resolution is read-only: it never installs anything and never starts a server; a server that is only installable is reported as such.

func (*App) PromoteToPrimary added in v0.326.0

func (app *App) PromoteToPrimary(ctx context.Context, lockFile *os.File) error

PromoteToPrimary is the failover.PromoteFunc implementation. It is called by the Watcher when this secondary wins the lock race. lockFile is the open flock file that must be kept open for the duration of this instance's primary role; the App now owns it and releases it in the Shutdown handover.

Promotion is IN PLACE: nothing that services captured at construction is closed or swapped. The session/message services, history, project, the MCP gateway, the design provider and the remembrances stores all keep the same *sql.DB (app.rwConn, the runtime's secondary pool) and the same DBProxy (app.DBQuerier), and simply start behaving like the primary's:

  1. db.PromoteToPrimaryPool upgrades the pool: primary busy_timeout and pragmas on every connection, 8 connections, goose migrations.
  2. A new Bus (with ipc.ping) gets the primary-side handlers through ipcBusSetupFunc (coordinator, changepub, db.write, bridge) and the remembrances dispatcher, then binds the primary's ports.
  3. DBProxy.Promote turns the proxy into a passthrough, so session/message writes and every remembrances store (which check IsRemote) write directly from now on.
  4. The App records the bus, coordinator and lock for the ordered handover, the watcher switches to publishing heartbeats on the new bus, the instance registry entry is re-announced with IsPrimary=true, and instance.promoted is published.

On an error before step 3 the pool is reverted to the secondary settings and the error is returned; the watcher then releases the lock and keeps monitoring as a secondary.

func (*App) RefreshAgentTools added in v0.643.1

func (a *App) RefreshAgentTools()

RefreshAgentTools rebuilds the coder agent's tool set from the current configuration and installs it on the running agent. It is called after the MCP server configuration changes so newly configured tools become usable without restarting Pando. It is a no-op when the agent does not support a runtime swap or the builder is not wired yet.

func (*App) RelinkKB added in v0.710.6

func (app *App) RelinkKB(ctx context.Context, force bool) (kb.BackfillStats, error)

RelinkKB rebuilds the knowledge-base wiki-link graph on this process's own writer: BackfillLinks (documents with no links yet) or, with force, RelinkAll.

It is the primary's kb.relink handler body. It uses the KB store's own write path — short, batched IMMEDIATE transactions on the primary pool, exactly what the primary's kb-link-backfill service does — rather than the write coordinator: the coordinator is a single goroutine, and a bulk relink queued on it would hold up every write forwarded by secondaries until it finished, while per-batch transactions already serialize with the coordinator's own writes through SQLite's write lock and the primary's busy timeout.

On a secondary it refuses: its store would silently skip the pass (a remote proxy means "the primary owns the writer").

func (*App) RunNonInteractive

func (a *App) RunNonInteractive(ctx context.Context, prompt string, outputFormat string, quiet bool, yoloMode bool) error

RunNonInteractive handles the execution flow when a prompt is provided via CLI flag.

func (*App) RunNonInteractiveGoal added in v0.324.0

func (a *App) RunNonInteractiveGoal(ctx context.Context, objective string, outputFormat string, quiet bool, yoloMode bool) (NonInteractiveGoalResult, error)

func (*App) SetIPCPrimaryHandover added in v0.710.6

func (app *App) SetIPCPrimaryHandover(coord PrimaryWriteCoordinator, releaseLock func())

SetIPCPrimaryHandover registers, on an instance that started as the IPC primary, the resources Shutdown must hand over first and in order: drain coord, then call releaseLock (idempotent, e.g. BootstrapResult.ReleaseLock), then shut down the bus set by SetupIPC. Without it the lock is only released by the runtime cleanup at the very end of process shutdown. A promoted primary registers the equivalent resources itself in PromoteToPrimary.

func (*App) SetIPCSecondaryContext added in v0.326.0

func (app *App) SetIPCSecondaryContext(
	client *ipc.Client,
	secondaryConn *sql.DB,
	workdir, instanceID string,
	pubPort, rpcPort int,
	watcher *failover.Watcher,
	busSetupFunc IPCBusSetupFunc,
)

SetIPCSecondaryContext stores the secondary IPC state and registers the active-probe function on the watcher so it can perform per-prompt and per-minute liveness checks.

secondaryConn is the secondary's RW pool (the runtime's SQLDB). It must be the same pool the App was built on: promotion upgrades it in place.

busSetupFunc is called during promotion with the new Bus and that pool. It must wire the writecoordinator, changepub publisher, and bridge handlers.

func (*App) SetupIPC added in v0.294.1

func (app *App) SetupIPC(bus *ipc.Bus)

Shutdown performs a clean shutdown of the application SetupIPC configures the primary IPC bus for this instance. Call this after New() on the primary instance to enable ZMQ event broadcasting and to register the db.write handler so secondary instances can proxy writes. bus must already be started (bus.Start called) before calling SetupIPC.

func (*App) Shutdown

func (app *App) Shutdown()

func (*App) UnavailableReason added in v0.629.4

func (app *App) UnavailableReason(path string) string

UnavailableReason explains why no ready language server could be obtained for a file, in terms the user can act on: a missing binary with its install command, an install still running, or activation being switched off. It returns an empty string when a ready server exists.

func (*App) WaitForFile added in v0.603.0

func (app *App) WaitForFile(ctx context.Context, path string) map[string]*lsp.Client

WaitForFile waits for a lazily spawned LSP client to become *ready* for the requested file, so a tool call never queries a server that is still starting up. It returns early when startup settles (ready or unavailable).

The wait is bounded by LSPStartupTimeout, extended once to LSPInstallTimeout when the matching server is still being downloaded — a first-run install is an order of magnitude slower than a cold start.

type AppOptions added in v0.100.0

type AppOptions struct {
	// SkipLSP disables LSP client initialisation. Set this to true in headless
	// modes (e.g. ACP stdio) where the editor manages its own language servers.
	SkipLSP bool
	// SkipMesnadaServer avoids starting the embedded Mesnada HTTP server while
	// still allowing the orchestrator and related tools to be initialized.
	SkipMesnadaServer bool
	// StartupMode identifies the mode in which Pando is starting so background
	// remembrances behaviors can be aligned consistently across entrypoints.
	StartupMode string
	// DBQuerier overrides the db.Querier used for sessions, messages, and projects.
	// When non-nil this querier is used instead of db.New(conn).
	// Primary instances leave this nil; secondary instances pass a dbproxy.DBProxy.
	DBQuerier db.Querier
	// IPCRole is the IPC role this process took at bootstrap
	// (ipcruntime.RolePrimary or RoleSecondary). It gates the primary-only
	// background services (see startPrimaryServices): a secondary defers them
	// until it is promoted. When empty, New infers the role: secondary when
	// DBQuerier is a remote *dbproxy.DBProxy, primary otherwise, so callers
	// without IPC (tests, one-shot CLIs) keep running every service.
	IPCRole ipcruntime.Role
	// OneShot marks a short-lived process (`pando cronjob run`) that must never
	// start the primary-only background services (code index + watcher, KB
	// sync/watch/backfill, memory GC, cron scheduler...), not at startup even
	// when it holds the IPC primary role, and not on a promotion either: it
	// exits within seconds, so starting them would only duplicate work the
	// long-running primary does and race its own shutdown.
	OneShot bool
}

AppOptions configures optional behaviour for New().

type IPCBusSetupFunc added in v0.710.6

type IPCBusSetupFunc func(ctx context.Context, bus *ipc.Bus, rwConn *sql.DB) (PrimaryWriteCoordinator, error)

IPCBusSetupFunc wires the primary-side IPC handlers on bus during a failover promotion — the same wiring a primary entrypoint does after Bootstrap (writecoordinator on rwConn, changepub publisher, db.write handlers, bridge handlers, bridge heartbeats). It must not start the bus. It returns the write coordinator it created so the App can drain and stop it on shutdown. ctx is cancelled when the promoted primary hands over.

type LSPAvailability added in v0.629.4

type LSPAvailability int

LSPAvailability describes whether a language server can be started.

const (
	// LSPAvailable means the binary was resolved and the server can start now.
	LSPAvailable LSPAvailability = iota
	// LSPInstallable means Pando can provision the binary itself before
	// starting the server.
	LSPInstallable
	// LSPManual means the binary is missing and only the user can install it.
	LSPManual
)

type LSPResolution added in v0.629.4

type LSPResolution struct {
	// Command and Args are the process to spawn. They are only meaningful when
	// Availability is LSPAvailable.
	Command string
	Args    []string
	// Availability says whether the server can start, could start after an
	// install, or needs the user to act.
	Availability LSPAvailability
	// Reason explains, in a sentence a user can act on, why the server is not
	// available. Empty when Availability is LSPAvailable.
	Reason string
}

LSPResolution is the outcome of resolving a server's executable.

type LSPServerStatus added in v0.629.4

type LSPServerStatus struct {
	Name        string `json:"name"`
	Description string `json:"description,omitempty"`
	// Command is the configured command, as it should be written back to the
	// configuration; ResolvedCommand is the executable Pando would actually
	// spawn (an absolute path, possibly inside Pando's own staging directory).
	Command         string   `json:"command"`
	ResolvedCommand string   `json:"resolvedCommand,omitempty"`
	Args            []string `json:"args,omitempty"`
	Languages       []string `json:"languages,omitempty"`
	Filenames       []string `json:"filenames,omitempty"`

	// Configured reports that the user declared this server under [LSP.<name>]
	// instead of only inheriting the built-in preset.
	Configured bool `json:"configured"`
	// OptIn reports a preset that stays inactive until it is declared.
	OptIn     bool `json:"optIn"`
	Disabled  bool `json:"disabled"`
	Autostart bool `json:"autostart"`

	// Availability is "installed", "installable" or "manual".
	Availability string `json:"availability"`
	// AvailabilityLabel is the short human-readable form, e.g.
	// "installable (bun)".
	AvailabilityLabel string `json:"availabilityLabel"`
	// Reason explains a non-installed server; Hint is the command the user can
	// run themselves and URL its documentation.
	Reason string `json:"reason,omitempty"`
	Hint   string `json:"hint,omitempty"`
	URL    string `json:"url,omitempty"`

	// RunState is "stopped", "starting", "ready" or "error".
	RunState   string `json:"runState"`
	Installing bool   `json:"installing"`
}

LSPServerStatus is what a settings page, the API or the setup tool needs to describe one language server: how it is configured, whether its binary can be obtained, and what it is doing right now.

type NonInteractiveGoalResult added in v0.324.0

type NonInteractiveGoalResult struct {
	SessionID          string `json:"session_id"`
	Objective          string `json:"objective"`
	Status             string `json:"status"`
	Iteration          int64  `json:"iteration"`
	MaxIterations      int64  `json:"max_iterations"`
	MaxDurationSeconds int64  `json:"max_duration_seconds"`
	Response           string `json:"response"`
	Progress           string `json:"progress,omitempty"`
	NextStep           string `json:"next_step,omitempty"`
	BlockedReason      string `json:"blocked_reason,omitempty"`
}

NonInteractiveGoalResult is the serialized outcome of a CLI goal-mode run.

type PrimaryWriteCoordinator added in v0.710.6

type PrimaryWriteCoordinator interface {
	Drain(ctx context.Context) error
	Shutdown()
}

PrimaryWriteCoordinator is the part of writecoordinator.Coordinator the primary handover needs: stop accepting forwarded writes and apply the queued ones (Drain), then stop (Shutdown).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL