proposal

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: 17 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Draft added in v0.3.0

type Draft struct {
	WorkspaceID string `` /* 127-byte string literal not displayed */
	Title       string `` /* 128-byte string literal not displayed */
	Description string `` /* 162-byte string literal not displayed */
	// CustomFieldValues is keyed by the workspace's field ids. A required field the
	// agent could not determine is left out on purpose — the review UI blocks
	// submit until the human fills it, which is better than a fabricated value.
	CustomFieldValues map[string]any `` /* 162-byte string literal not displayed */
	IsTest            bool           `` /* 135-byte string literal not displayed */
}

Draft is the terminal output of a case-draft turn: the case the agent proposes. The schema handed to the model is derived from these struct tags via gollem.ToSchema; Validate enforces what a plain JSON schema cannot.

It is a proposal, not a case: the host renders it into a preview a human reviews, edits and submits.

func (Draft) Validate added in v0.3.0

func (d Draft) Validate() error

Validate enforces the draft's shape invariants so a workspace-less or title-less proposal is rejected inside planexec's regeneration loop rather than reaching the human as a broken preview. It satisfies planexec.Validatable.

The field VALUES are not checked here: that needs the workspace's schema, which this method cannot see. The host's finalizer does it.

type Durable added in v0.3.0

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

Durable runs the case-draft agent on the agentkit runtime.

It coexists with the in-process planner loop: a deployment that has not wired this keeps taking UseCase.RunTurn's synchronous path.

func NewDurable added in v0.3.0

func NewDurable(repo interfaces.Repository, registry *model.WorkspaceRegistry,
	host Host, locator agentkernel.Locator, models agentkernel.ModelPolicy,
) (*Durable, error)

NewDurable builds the durable case-draft 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 case-draft agent and wires this host as its completion handler. Call it before building the Kernel, and Bind after.

func (*Durable) StartTurn added in v0.3.0

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

StartTurn spawns one case-draft turn and returns as soon as the run is recorded. The draft, or the question, is delivered by the completion handler.

type Host added in v0.3.0

type Host interface {
	// Propose renders the draft into the preview UI the human reviews and submits.
	Propose(ctx context.Context, target Target, payload MaterializePayload) error
	// Ask posts the planner's question and records it on the session; the turn has
	// ended, and the user's answer starts the next one.
	Ask(ctx context.Context, target Target, question QuestionPayload) error
	// ReportFallback tells the user the turn reached no conclusion.
	ReportFallback(ctx context.Context, target Target, reason string) error
}

Host is the Slack-facing surface a finished case-draft turn needs. Each method is called at most once per turn, from the completion handler.

type MaterializePayload

type MaterializePayload struct {
	WorkspaceID       string
	Title             string
	Description       string
	CustomFieldValues map[string]any
	// IsTest marks the proposed case as a test case. Defaults to false.
	IsTest bool
}

MaterializePayload is the pure-domain shape passed to Host.Propose.

type QuestionItem

type QuestionItem struct {
	// ID uniquely identifies the question within the payload; the host
	// uses it to correlate answers back when the user submits.
	ID string
	// Text is the prompt shown to the user.
	Text string
	// Type discriminates the answer control (select / multi_select /
	// free_text).
	Type QuestionItemType
	// Options is the allowed answer set for select / multi_select
	// (always ≥2 entries). Ignored for free_text.
	Options []string
}

QuestionItem is one question within QuestionPayload.Items.

type QuestionItemType

type QuestionItemType string

QuestionItemType is the host-rendering hint for a question item.

const (
	// QuestionItemSelect is a single-choice picker.
	QuestionItemSelect QuestionItemType = "select"
	// QuestionItemMultiSelect is a multi-choice picker.
	QuestionItemMultiSelect QuestionItemType = "multi_select"
	// QuestionItemFreeText is a multiline plain-text input. Reserved
	// for the last-resort case where neither investigation nor a
	// closed-list classification can capture what we need from the
	// user.
	QuestionItemFreeText QuestionItemType = "free_text"
)

type QuestionPayload

type QuestionPayload struct {
	// Reason explains the information gap (single rationale shared across
	// all items).
	Reason string
	// Items is the ordered list of questions to ask in this turn. Always
	// non-empty (validation guarantees ≥1).
	Items []QuestionItem
}

QuestionPayload is the pure-domain shape passed to Host.Ask.

type Result

type Result struct {
	Status Status
}

Result is the outcome of StartTurn.

type Status

type Status int

Status discriminates what StartTurn did.

const (
	// StatusStarted means the turn was spawned; its draft or question is delivered
	// by the run's own completion handler, so the caller has nothing to post.
	StatusStarted Status = iota
	// StatusBusy means another turn holds this thread.
	StatusBusy
	// StatusIdempotent means the trigger duplicates a turn already started; drop
	// it silently.
	StatusIdempotent
)

type Target added in v0.3.0

type Target struct {
	SessionID string
	ChannelID string
	ThreadTS  string
	// ActorUserID is the person whose request this draft answers.
	ActorUserID string
	// ProcessingTS and PreviewTS name the message the result replaces, and are
	// mutually exclusive: the "working on it" placeholder a fresh mention posted,
	// or the existing preview a workspace switch updates in place.
	ProcessingTS string
	PreviewTS    string
	// ProposalID is the draft THIS run writes into, carried on the run rather than
	// read back from the Session. The Session's ProposalID is mutable — a later
	// mention repoints it while this run is still going — so reading it here would
	// let one turn's result land in another turn's draft.
	ProposalID model.CaseProposalID
	// ProcessID is the run that produced this outcome. A host that records a
	// question needs it so the turn started by the answer can inherit this run's
	// conversation.
	ProcessID string
}

Target locates a finished case-draft run's thread and session.

It is rebuilt from the Process metadata rather than captured at spawn, because the completion handler runs after the turn — possibly on another instance.

type Trigger

type Trigger int

Trigger discriminates how the host started a turn for a given Session. The prompt may use it (e.g. WSSwitch should redraft from the conversation rather than investigating again).

const (
	// TriggerAppMention — the user @-mentioned the bot.
	TriggerAppMention Trigger = iota
	// TriggerThreadReply — the user replied in the thread without a mention,
	// while the prior turn ended on a question.
	TriggerThreadReply
	// TriggerWSSwitch — the user switched the active workspace via the
	// preview UI, requiring a redraft on the existing proposal.
	TriggerWSSwitch
)

type TurnRequest

type TurnRequest struct {
	// Session is the per-thread Session row. Its ID is the turn's subject, so it
	// must already be persisted before a turn can be spawned.
	Session *model.Session

	// UserInput is the agent's first user message. For app_mention this is the
	// mention text; for thread_reply the reply text; for ws_switch a synthetic
	// system-event sentence.
	UserInput string

	// Trigger discriminates the entry point — it drives prompt hints.
	Trigger Trigger

	// TriggerTS is the Slack TS the turn is deduplicated on. It is empty for the
	// synthetic ws_switch trigger, which has no Slack event behind it.
	TriggerTS string

	// ActorUserID is the Slack user who initiated the turn. It is the run's access
	// actor: without it the usecase layer reads the run as a system context and
	// bypasses private-case access control.
	ActorUserID string

	// ExistingProposal is the prior draft persisted by the host (when this turn
	// resumes an existing draft, e.g. ws-switch or thread reply). The agent does
	// not consume it directly — the host uses it to keep preview state coherent
	// across turns.
	ExistingProposal *model.CaseProposal

	// ProcessingTS and PreviewTS name the Slack message this turn's result
	// replaces, and are mutually exclusive: the "working on it" placeholder a fresh
	// mention posted, or the existing preview a workspace switch updates in place.
	//
	// They are carried on the run because the call that posted them returns before
	// the result exists.
	ProcessingTS string
	PreviewTS    string

	// InheritFrom continues a finished run's conversation in this one. It is how an
	// answered question resumes: the answering turn is a NEW run — its own budget,
	// its own record — but it must see the request, the investigation and the
	// question that produced it. Empty starts a fresh conversation.
	InheritFrom string
}

TurnRequest is the input for one case-draft turn.

Jump to

Keyboard shortcuts

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