Documentation
¶
Overview ¶
Package result posts an agent.Result back to the Rensei platform at the end of a session.
Per F.1.1 §6, the wire contract is:
POST /api/sessions/<id>/completion — the canonical "session done" endpoint. The platform side resolves the Linear comment text from the runner-supplied summary and posts it via the platform's getLinearClient resolver. Worker auth: runtime_jwt | registration token | legacy WORKER_API_KEY.
POST /api/sessions/<id>/status — the FSM status transition ("completed" | "failed" | "stopped") with the cost snapshot, provider session id, and worktree path. Drives Linear status transitions, fleet quota release, governor phase tracking, file reservation release, and the lifecycle hook chain (audit + session-status + LLM-billing + event publisher) on the platform side.
Both calls are wrapped by the legacy `apiRequestWithError` retry pattern: 3 attempts with exponential backoff (1s, 2s, 4s) on transient failures. 4xx responses are treated as permanent — retrying a 401 / 403 / 404 / 422 just papers over a programmer error.
Boundaries ¶
- Posts to the platform only. Does NOT post directly to Linear; the platform's completion + status handlers own the Linear-side reflection (REN-1399 tenant scoping requires it).
- Knows nothing about how the Result was produced. The runner hands it a fully-populated agent.Result; this package only translates that to the wire shape.
Retry semantics ¶
Transient errors (network failures, 5xx responses, context-deadline timeouts) trigger the 3-attempt exponential backoff. Permanent errors (4xx) return immediately wrapped in a PermanentError. The caller (runner) typically logs and moves on either way — a failed completion is operationally bad but not worth crashing the daemon over.
Source: F.1.1 §6, F.0.1 §5 ("Result"), legacy ../agentfactory/packages/cli/src/lib/worker-runner.ts::reportStatus + ../agentfactory/packages/core/src/orchestrator/orchestrator.ts (completion fetch).
Index ¶
Constants ¶
const DefaultBaseDelay = time.Second
DefaultBaseDelay is the base delay for exponential backoff between attempts. Backoff is `BaseDelay * 2^(n-1)` — same shape as the legacy 1s / 2s / 4s sequence.
const DefaultMaxAttempts = 3
DefaultMaxAttempts is the legacy 3-attempt pattern from `apiRequestWithError` in worker-runner.ts. Exposed for tests that want to assert "did we retry" semantics.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type CredentialProvider ¶
type CredentialProvider func(context.Context) (RuntimeCredentials, error)
CredentialProvider returns the freshest worker runtime credentials available to the caller. Implementations should be cheap and concurrency-safe.
type Options ¶
type Options struct {
// PlatformURL is the base URL of the platform. Required.
PlatformURL string
// AuthToken is the worker bearer token. Required for all
// non-localhost platform deployments.
AuthToken string
// WorkerID identifies the calling worker; required because the
// platform's status endpoint validates it against the session's
// owner before accepting transitions.
WorkerID string
// CredentialProvider returns the latest worker id + auth token. Empty
// fields fall back to WorkerID/AuthToken.
CredentialProvider CredentialProvider
// HTTPClient overrides the default 30s-timeout client. Optional.
HTTPClient *http.Client
// MaxAttempts overrides DefaultMaxAttempts. Values < 1 fall back to
// DefaultMaxAttempts.
MaxAttempts int
// BaseDelay overrides DefaultBaseDelay. Values < 0 fall back to
// DefaultBaseDelay; a zero value disables sleep between retries
// (handy in tests).
BaseDelay time.Duration
// Now overrides time.Now for deterministic tests. Optional.
Now func() time.Time
}
Options configure a Poster.
type PermanentError ¶
type PermanentError struct {
// StatusCode is the HTTP status the platform returned.
StatusCode int
// Body is up to the first 4 KiB of the response body, trimmed.
Body string
}
PermanentError is returned by Poster.Post when the platform rejected the request with a 4xx status code. Permanent errors are not retried — a 401 / 403 / 404 / 422 indicates a programmer error (wrong session id, expired auth token, invalid wire shape) that retrying will not fix.
func (*PermanentError) Error ¶
func (e *PermanentError) Error() string
Error implements the error interface.
type Poster ¶
type Poster struct {
// contains filtered or unexported fields
}
Poster posts an agent.Result back to the Rensei platform. The zero value is not usable — use NewPoster.
Posters are safe for concurrent use; all fields are read-only after construction.
func NewPoster ¶
NewPoster constructs a Poster from opts. Returns an error when the required PlatformURL is missing or unparseable. Optional fields fall through to their defaults.
func (*Poster) CreateIssueComment ¶
CreateIssueComment posts a comment to the issue identified by issueID. Used by the post-session unknown-WORK_RESULT diagnostic path (sdlc.go::diagnosticCommentBody) and any other runner-side best-effort comments.
Errors mirror UpdateIssueStatus.
func (*Poster) Post ¶
Post sends the runner's terminal agent.Result to the platform.
Order matters: completion first, then status. The completion endpoint posts the human-readable Linear comment; the status endpoint transitions the FSM and triggers the cleanup chain (release claim, archive inbox, release issue lock, promote next pending work). Both are wrapped by the retry helper; a permanent (4xx) failure on completion does NOT block the status post — the runner still wants to release the session lock so the next worker can pick up.
Errors:
- returns nil when both calls succeed.
- returns a wrapped PermanentError when a 4xx response is seen on either call.
- returns a wrapped TransientError when retries are exhausted on a transient failure (5xx, network, timeout). Caller should log and treat as a soft failure.
- returns ctx.Err() when the context is cancelled.
When both calls return errors, errors.Join combines them so downstream logs see the full picture.
func (*Poster) UpdateIssueStatus ¶
UpdateIssueStatus transitions the issue identified by issueID to the named workflow status (e.g. "Finished", "Rejected"). The platform's issue-tracker proxy resolves the named status to the team's stateId via getTeamStatuses + matches the name to a workflow state.
Errors:
- returns nil when the proxy responds 200 with success=true
- returns a wrapped PermanentError on a 4xx response or success=false with retryable=false
- returns a wrapped TransientError when retries are exhausted on a transient failure (5xx, network timeout)
- returns ctx.Err() when the context is cancelled
type RuntimeCredentials ¶
RuntimeCredentials are the bearer-token credentials needed for platform result-post requests. Empty fields fall back to the Poster defaults.
type TransientError ¶
type TransientError struct {
// Attempts is the number of attempts made before giving up.
Attempts int
// Last is the last error observed.
Last error
}
TransientError is returned by Poster.Post when retries were exhausted on a transient failure (5xx, connection refused, DNS, context-deadline timeout that exceeded the per-attempt window).
func (*TransientError) Error ¶
func (e *TransientError) Error() string
Error implements the error interface.
func (*TransientError) Unwrap ¶
func (e *TransientError) Unwrap() error
Unwrap returns the last underlying error so errors.Is / errors.As callers can match the inner cause.