Documentation
¶
Index ¶
- Constants
- Variables
- func IsRefusal(err error) bool
- type Admitter
- type ConversationOpener
- type Counts
- type CreateCommentCmd
- type CreateIssueCmd
- type DeleteCommentCmd
- type RunReporter
- type Service
- func (s *Service) AssignedWorkflowID(ctx context.Context, teamID, issueID string) (*coreissue.Issue, string, error)
- func (s *Service) CountsFor(ctx context.Context, issueIDs []string) map[string]Counts
- func (s *Service) CreateComment(ctx context.Context, cmd CreateCommentCmd) (*coreissue.Comment, error)
- func (s *Service) CreateIssue(ctx context.Context, cmd CreateIssueCmd) (*coreissue.Issue, error)
- func (s *Service) DeleteComment(ctx context.Context, cmd DeleteCommentCmd) error
- func (s *Service) GetIssue(ctx context.Context, teamID, issueID string) (*coreissue.Issue, error)
- func (s *Service) ListComments(ctx context.Context, issueID string, limit, offset int) ([]coreissue.Comment, int, error)
- func (s *Service) ListIssues(ctx context.Context, teamID string, filter coreissue.ListFilter, ...) ([]coreissue.Issue, int, error)
- func (s *Service) PlanAssignedAgentRun(ctx context.Context, cmd StartAssignedAgentCmd, admitter Admitter, ...) (*StartAssignedAgentPlan, error)
- func (s *Service) UpdateComment(ctx context.Context, cmd UpdateCommentCmd) (*coreissue.Comment, error)
- func (s *Service) UpdateIssue(ctx context.Context, cmd UpdateIssueCmd) (*coreissue.Issue, error)
- type StartAssignedAgentCmd
- type StartAssignedAgentPlan
- type UpdateCommentCmd
- type UpdateIssueCmd
Constants ¶
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 ¶
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") )
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") )
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 ¶
Types ¶
type Admitter ¶
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 ¶
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 CreateIssueCmd ¶
type DeleteCommentCmd ¶
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 ¶
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 (*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 ¶
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 (*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 ¶
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 ¶
StartAssignedAgentPlan is a validated, admitted start: what to run, on what input, in which conversation.