issue

package
v0.2.0-alpha.2 Latest Latest
Warning

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

Go to latest
Published: Aug 26, 2026 License: Apache-2.0 Imports: 12 Imported by: 0

Documentation

Index

Constants

View Source
const CommentBodyLimit = 16 * 1024

CommentBodyLimit bounds a comment body in bytes.

A comment is a statement about an issue, not a place to paste a run's output: long content belongs in an artifact, and a comment points at one. The limit also bounds the size of a thread response, which is otherwise unbounded in the number of comments times their length.

Variables

View Source
var (
	ErrCommentsNotConfigured = apierr.New(apierr.KindNotConfigured, "comments not configured")
	ErrCommentBodyRequired   = apierr.New(apierr.KindInvalid, "comment body required")
	ErrCommentTooLong        = apierr.New(apierr.KindInvalid, "comment too long")
	ErrCommentNotFound       = apierr.New(apierr.KindNotFound, "comment not found")
	ErrCommentNotEditable    = apierr.New(apierr.KindForbidden, "comment not editable")
)
View Source
var (
	ErrIssuesNotConfigured    = apierr.New(apierr.KindNotConfigured, "issues not configured")
	ErrTeamsNotConfigured     = apierr.New(apierr.KindNotConfigured, "teams not configured")
	ErrTitleRequired          = apierr.New(apierr.KindInvalid, "title required")
	ErrInvalidStatus          = apierr.New(apierr.KindInvalid, "invalid status")
	ErrInvalidAssigneeKind    = apierr.New(apierr.KindInvalid, "invalid assignee_kind")
	ErrInvalidAssigneeID      = apierr.New(apierr.KindInvalid, "invalid assignee_id")
	ErrIssueNotFound          = apierr.New(apierr.KindNotFound, "issue not found")
	ErrAgentsNotConfigured    = apierr.New(apierr.KindNotConfigured, "agents not configured")
	ErrAgentNotFound          = apierr.New(apierr.KindInvalid, "agent not found")
	ErrWorkflowsNotConfigured = apierr.New(apierr.KindNotConfigured, "workflows not configured")
	ErrWorkflowNotFound       = apierr.New(apierr.KindInvalid, "workflow not found")
	ErrWorkflowNotPublished   = apierr.New(apierr.KindInvalid, "workflow not published")
	// ErrParentNotFound covers both a parent that does not exist and one that
	// belongs to another team. The two are reported identically on purpose:
	// distinguishing them would confirm that an issue ID exists somewhere the
	// caller cannot see, and issue IDs are what Portal puts in URLs.
	ErrParentNotFound   = apierr.New(apierr.KindInvalid, "parent issue not found")
	ErrHierarchyTooDeep = apierr.New(apierr.KindInvalid, "issue hierarchy too deep")
	ErrIssueHasChildren = apierr.New(apierr.KindInvalid, "issue has sub-issues")
	ErrInvalidParent    = apierr.New(apierr.KindInvalid, "invalid parent_issue_id")
)
View Source
var (
	// ErrNotAssignedToAgent means the Issue names no Agent to start.
	ErrNotAssignedToAgent = apierr.New(apierr.KindInvalid, "issue not assigned to agent")
	// ErrNotAssignedToWorkflow means the Issue names no Workflow to start.
	ErrNotAssignedToWorkflow = apierr.New(apierr.KindInvalid, "issue not assigned to workflow")
	// ErrAssignedAgentGone means the Issue names an Agent the team no longer
	// has. An assignment outlives a deletion, so this is reachable.
	ErrAssignedAgentGone = apierr.New(apierr.KindInvalid, "agent not found")
)

Refusals starting an Issue's assigned work can produce.

Functions

func IsRefusal

func IsRefusal(err error) bool

IsRefusal reports whether err is one of this package's refusals rather than a failure, so a transport can tell the two apart without listing them.

Types

type Admitter

type Admitter interface {
	Admits(ctx context.Context, teamID string) error
}

Admitter reports whether a team may start one more background run.

It is asked before anything is written. The task service checks the same allowance when it creates the task, but by then this orchestration has already created a conversation for the task to hang on -- and a refusal there leaves that conversation behind, in a team's list, with nothing to delete it.

type ConversationOpener

type ConversationOpener interface {
	OpenForIssue(ctx context.Context, teamID, userID string) (conversationID string, err error)
}

ConversationOpener creates the thread an Issue's run reports into.

type Counts

type Counts struct {
	Children     int
	DoneChildren int
	Comments     int
}

Counts are the derived numbers a list of issues carries: how many sub-issues each has, how many are done, how many comments.

type CreateCommentCmd

type CreateCommentCmd struct {
	IssueID         string
	AuthorKind      string
	AuthorID        string
	Body            string
	SourceTaskID    *string
	SourceTaskRunID *string
}

type CreateIssueCmd

type CreateIssueCmd struct {
	UserID        string
	TeamID        string
	Title         string
	Description   string
	ParentIssueID *string
}

type DeleteCommentCmd

type DeleteCommentCmd struct {
	IssueID     string
	CommentID   string
	UserID      string
	CanModerate bool
}

type RunReporter

type RunReporter struct {
	Tasks    coretask.Store
	Comments coreissue.CommentStore
}

RunReporter posts an agent comment on the issue a finished task run belongs to.

It is driven by the terminal-run callback, which fires after the worker has already been answered. Every failure path here returns without an error reaching that response: a comment that could not be written must not turn a completed run into a failed one.

func (*RunReporter) ReportRunTerminal

func (r *RunReporter) ReportRunTerminal(ctx context.Context, info coretask.RunTerminalInfo) error

ReportRunTerminal writes one comment for a run that reached a terminal status, and nothing at all when there is no issue, no store, or nothing to say.

One comment per terminal run is the whole budget. A run that streamed for twenty minutes still produces one line in the thread.

type Service

type Service struct {
	Issues    coreissue.Store
	Comments  coreissue.CommentStore
	Agents    agentdef.Store
	Teams     coreteam.Store
	Workflows coreworkflow.Store
}

func (*Service) AssignedWorkflowID

func (s *Service) AssignedWorkflowID(ctx context.Context, teamID, issueID string) (*coreissue.Issue, string, error)

AssignedWorkflowID validates that the Issue names a Workflow to start and reports which, so the caller does not repeat the assignment rules the workflow service would otherwise check a second time.

func (*Service) CountsFor

func (s *Service) CountsFor(ctx context.Context, issueIDs []string) map[string]Counts

CountsFor loads the derived counts for a page of issues with one grouped query each, rather than a count per row.

A failure degrades to zero for that count instead of failing the page: a missing progress badge is a worse-looking list, an error is no list at all. Both stores are optional, and a deployment without one simply reports zero.

func (*Service) CreateComment

func (s *Service) CreateComment(ctx context.Context, cmd CreateCommentCmd) (*coreissue.Comment, error)

CreateComment appends a comment to an issue. The caller is responsible for having authorized the issue's team.

func (*Service) CreateIssue

func (s *Service) CreateIssue(ctx context.Context, cmd CreateIssueCmd) (*coreissue.Issue, error)

func (*Service) DeleteComment

func (s *Service) DeleteComment(ctx context.Context, cmd DeleteCommentCmd) error

DeleteComment removes a comment. The author may delete their own; a moderator may delete any comment on the issue, including one an agent wrote.

func (*Service) GetIssue

func (s *Service) GetIssue(ctx context.Context, teamID, issueID string) (*coreissue.Issue, error)

GetIssue resolves an issue the team owns.

An issue belonging to another team reads as not found rather than forbidden, so the answer does not confirm that an id exists elsewhere.

func (*Service) ListComments

func (s *Service) ListComments(ctx context.Context, issueID string, limit, offset int) ([]coreissue.Comment, int, error)

ListComments returns an issue's thread, oldest first.

func (*Service) ListIssues

func (s *Service) ListIssues(ctx context.Context, teamID string, filter coreissue.ListFilter, limit, offset int) ([]coreissue.Issue, int, error)

func (*Service) PlanAssignedAgentRun

func (s *Service) PlanAssignedAgentRun(
	ctx context.Context,
	cmd StartAssignedAgentCmd,
	admitter Admitter,
	opener ConversationOpener,
) (*StartAssignedAgentPlan, error)

PlanAssignedAgentRun validates the Issue and its assignment, asks whether the team may start a run, and only then opens the conversation.

The order is the point. Validating after the write leaves a bad request with a conversation attached to it; opening the conversation before asking about the allowance leaves one behind on every refusal, which a team at its run limit hits on every attempt.

func (*Service) UpdateComment

func (s *Service) UpdateComment(ctx context.Context, cmd UpdateCommentCmd) (*coreissue.Comment, error)

UpdateComment replaces a comment's body.

Only the person who wrote a comment may edit it. Moderation permits deletion, not rewriting: an edit puts words in another person's mouth, and an agent or system comment is the record of what a run reported — a record anyone can rewrite is not one.

func (*Service) UpdateIssue

func (s *Service) UpdateIssue(ctx context.Context, cmd UpdateIssueCmd) (*coreissue.Issue, error)

type StartAssignedAgentCmd

type StartAssignedAgentCmd struct {
	TeamID  string
	IssueID string
	UserID  string
	// Input overrides what the Agent is asked. Empty means the Issue itself.
	Input string
}

StartAssignedAgentCmd starts the Agent an Issue is assigned to.

type StartAssignedAgentPlan

type StartAssignedAgentPlan struct {
	Issue          coreissue.Issue
	AgentID        string
	ConversationID string
}

StartAssignedAgentPlan is a validated, admitted start: what to run, on what input, in which conversation.

type UpdateCommentCmd

type UpdateCommentCmd struct {
	IssueID   string
	CommentID string
	UserID    string
	Body      string
	// CanModerate is true when the caller may edit or delete a comment they did
	// not write. Only deletion honors it; see UpdateComment.
	CanModerate bool
}

type UpdateIssueCmd

type UpdateIssueCmd struct {
	UserID        string
	TeamID        string
	IssueID       string
	Title         *string
	Description   *string
	Status        *string
	AssigneeKind  *string
	AssigneeID    *string
	ParentIssueID *string
}

Jump to

Keyboard shortcuts

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