Documentation
¶
Overview ¶
Package upload drives the ingest protocol from the client side, statelessly. The server is authoritative for how many bytes of each file it holds, so the client persists nothing: it announces, reconciles against the server's cursor and content hash, and streams the gap in newline-terminated chunks.
Index ¶
- Variables
- func NewHTTPClient() *http.Client
- type Action
- type Client
- func (c *Client) ProviderUsageWatermark(ctx context.Context, provider, accountID string) (time.Time, error)
- func (c *Client) SendProviderUsage(ctx context.Context, provider, accountID string, events []ProviderUsageEvent) (int, error)
- func (c *Client) SyncFile(ctx context.Context, t Target) (Outcome, error)
- type Outcome
- type ProviderUsageEvent
- type Target
Constants ¶
This section is empty.
Variables ¶
var ErrRetryableStatus = errors.New("upload server returned a retryable status")
ErrRetryableStatus marks a response that should pause a long-running client before it sends more work to an unavailable or overloaded server.
Functions ¶
func NewHTTPClient ¶ added in v0.5.5
NewHTTPClient builds the production HTTP client used by sync and watch. The transport bounds connection setup and response headers, while upload bodies use progress deadlines in Client so a large transfer has no wall-clock cap. Redirects are refused; see errIngestRedirectRefused.
Types ¶
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client talks to one akari server with one bearer token.
func (*Client) ProviderUsageWatermark ¶ added in v0.7.7
func (c *Client) ProviderUsageWatermark(ctx context.Context, provider, accountID string) (time.Time, error)
ProviderUsageWatermark asks where a collection should resume: the newest event instant the server already holds for this vendor account, or the zero time when it holds none.
The client keeps no cursor of its own, exactly as it keeps none for a transcript upload. A fresh checkout, a second machine, and a reinstalled client therefore all resume from the same place, and the only durable record of what has been collected is the server's.
func (*Client) SendProviderUsage ¶ added in v0.7.7
func (c *Client) SendProviderUsage(ctx context.Context, provider, accountID string, events []ProviderUsageEvent) (int, error)
SendProviderUsage uploads collected events and reports how many were new.
Events are sent in fixed-size batches rather than one body, so a first collection of an account with years of history does not build a single enormous request. Each batch is independently idempotent on its event key, so a failure part way through leaves the batches that landed stored and the rest to be re-collected on the next run.
func (*Client) SyncFile ¶
SyncFile announces a file, reconciles against the server's cursor, and uploads any new complete lines. It is safe to call repeatedly: an up-to-date file moves no bytes.
A mid-stream offset conflict (HTTP 409) means the server's cursor moved out from under us, so the prefix verified at announce is stale. Rather than trust the conflict's reported cursor blindly (which could append onto a divergent prefix), SyncFile re-announces and re-verifies the prefix from scratch, up to maxConflictRetries times.
type Outcome ¶
type Outcome struct {
Action Action
UploadedBytes int64
StoredBytes int64
// SessionID is the server's id for the synced session, learned at announce. It
// lets SyncFile address the session after the upload (the finalize refresh), and
// is carried out to the caller for the same reason.
SessionID int64
}
Outcome reports the result of syncing one file.
type ProviderUsageEvent ¶ added in v0.7.7
type ProviderUsageEvent struct {
EventKey string `json:"event_key"`
ConversationID string `json:"conversation_id"`
Model string `json:"model"`
Input int `json:"input_tokens"`
Output int `json:"output_tokens"`
CacheWrite int `json:"cache_write_tokens"`
CacheRead int `json:"cache_read_tokens"`
CostUSD float64 `json:"cost_usd"`
CostKnown bool `json:"cost_known"`
OccurredAt time.Time `json:"occurred_at"`
}
ProviderUsageEvent is one vendor-reported billing event on its way to the server. It mirrors the ingest endpoint's JSON exactly; the collector fills it from whichever vendor package fetched the event.
type Target ¶
type Target struct {
Agent string
Path string
SourceID string
Kind string
ProjectKey string
LocalRoot string
GitBranch string
Cwd string
Machine string
// Finalize forces the session's trailing turn to be treated as settled on this
// sync regardless of how recently the file was written. A Codex session's final
// turn has no closing user line, so it is normally withheld until the file has
// been idle for settleWindow (see syncOnce); on an ephemeral host (CI, a cloud
// sandbox) that idle window never elapses before the host is torn down, so the
// final turn would never upload. Set by `akari sync --finalize`, an assertion by
// the caller that every session being synced is terminal.
Finalize bool
}
Target is everything needed to upload one resolved session file. Kind is the session's classification ("remote", "standalone", or "orphaned"). ProjectKey is set only for a remote session; for standalone and orphaned sessions the server derives the project key from Machine and the local location. LocalRoot, set only for a standalone session in a live worktree, is the repo root shared by every worktree; the server keys on it so a local-only repo's worktrees collapse into one project. When it is empty the server falls back to Cwd.