wsagent

package
v0.3.0 Latest Latest
Warning

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

Go to latest
Published: Sep 7, 2026 License: Apache-2.0 Imports: 15 Imported by: 0

Documentation

Overview

Package wsagent hosts the workspace-channel agent: the plan-and-execute agent that runs when the bot is mentioned in a channel-mode workspace's configured workspace channel ([slack] workspace_channel). Unlike casebound / threadcase (pinned to one Case), this host is workspace-scoped and operates across every Case the mentioning user can access, via the cross-case casemulti tool set.

A turn is a durable process: StartTurn spawns it and returns, and the answer is posted from the completion handler through the Host port. Slack SDK imports are forbidden here; the usecase layer owns the Slack service and i18n.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Durable added in v0.3.0

type Durable struct {
	// contains filtered or unexported fields
}

Durable is the workspace agent running on the agentkit runtime.

It coexists with the in-process planexec runner: a deployment that has not wired this yet keeps taking RunTurn's synchronous path, which is what lets the two runtimes overlap while the hosts move over one at a time. It keeps no JobRunLog: those records are case-scoped and this agent is workspace-scoped (CaseID is 0), so there is no case whose run history it would appear in. Its trace is the per-claim Cloud Storage archive the claim middleware opens.

func NewDurable added in v0.3.0

func NewDurable(host Host, locator agentkernel.Locator,
	models agentkernel.ModelPolicy,
) (*Durable, error)

NewDurable builds the durable workspace-agent host. locator is used only to tell a re-delivered Slack event from a busy thread; a nil locator makes every delivery look fresh, which the idempotency key still covers.

func (*Durable) Bind added in v0.3.0

func (d *Durable) Bind(k *agentkit.Kernel, probe *agentkernel.ToolSetProbe)

Bind hands over the Kernel the registered agent runs on, and the probe that tells this host which toolset ids actually resolve to a tool for a given run.

func (*Durable) Register added in v0.3.0

func (d *Durable) Register(
	reg *agentkit.Registry, taskAgent agentkit.Agent[react.Input],
	progress planexec.Progress, limiter agentkit.Limiter, store agentkit.HistoryStore,
) error

Register registers the workspace agent and wires this host as its completion handler. Call it before building the Kernel, and Bind after.

taskAgent is the agent each planned task runs as; progress may be nil.

func (*Durable) StartTurn added in v0.3.0

func (d *Durable) StartTurn(ctx context.Context, req TurnRequest) (*Result, error)

StartTurn spawns one workspace-agent turn and returns as soon as the run is recorded. The planner rounds, the sub-agents and the reply all happen afterwards on the agent worker.

type Host added in v0.3.0

type Host interface {
	// Reply posts the agent's answer to the thread.
	Reply(ctx context.Context, channelID, threadTS, text string) error
	// ReportFailure tells the user the turn could not finish. reason is the
	// technical cause; the host decides how much of it to show.
	ReportFailure(ctx context.Context, channelID, threadTS, reason string) error
}

Host is the Slack-facing surface a finished turn needs.

It exists because a durable turn no longer ends where it started: the run outlives StartTurn, so its reply is posted from the completion handler, on whichever instance committed the terminal transition.

type Result

type Result struct {
	Status Status
	// BusyOwner describes the run holding the thread, set only on StatusBusy.
	BusyOwner string
}

Result is what StartTurn returns to the usecase layer.

type Status

type Status int

Status is the outcome of starting a workspace-agent turn.

const (
	// StatusStarted: the turn was spawned; its answer is posted by the run's own
	// completion handler, so the caller has nothing to post.
	StatusStarted Status = iota
	// StatusBusy: another turn holds this thread (Result.BusyOwner names it).
	StatusBusy
	// StatusIdempotent: a duplicate Slack delivery for a turn already started;
	// drop it silently.
	StatusIdempotent
)

type TurnRequest

type TurnRequest struct {
	// Session is the (channel, thread) session; CaseID is 0 (workspace-scoped,
	// not bound to any single case). It must already exist: its ID is the turn's
	// subject, so the row has to be claimed before a turn can be spawned.
	Session *model.Session
	// Workspace is the channel-mode workspace whose workspace channel was
	// mentioned.
	Workspace *model.WorkspaceEntry
	// ActorID is the mentioning Slack user id — the access actor. It is recorded
	// on the run so every casemulti read/write enforces this user's private-case
	// membership.
	ActorID string
	// MentionText is the user's message (with the bot mention stripped by the
	// caller). It is the planner's first user message.
	MentionText string
	// TriggerTS is the Slack ts of the triggering event. It is the idempotency
	// key, which is what makes a re-delivered Slack event resolve to the run it
	// already started instead of starting a second one.
	TriggerTS string
}

TurnRequest carries everything one workspace-agent turn needs. The host resolves nothing itself: the usecase layer supplies the already-loaded session / workspace and the mentioning user's identity.

Jump to

Keyboard shortcuts

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