]> git.giacomolli.uk - onechat/blobdiff - responses.go
Format issue bodies and comments with mdformat
[onechat] / responses.go
index cdc1558195e159cd111f0e4968f8e9f5d9aea941..fddec7378650a7ca9c25e6ac1c960f5f53313f19 100644 (file)
@@ -48,8 +48,10 @@ type apiKey string
 // Client sends model calls to a Responses endpoint for one agent. The ChatGPT
 // backend and the OpenAI API take the same request body and differ only in the
 // URL and the credentials. Every call sends the fixed cache key of the agent,
 // Client sends model calls to a Responses endpoint for one agent. The ChatGPT
 // backend and the OpenAI API take the same request body and differ only in the
 // URL and the credentials. Every call sends the fixed cache key of the agent,
-// so the turns and the compactions of the agent share one prompt cache. Every
-// call is recorded in the usage file.
+// so the turns and the compactions of the agent share one prompt cache. The
+// ChatGPT backend caches only with the key in the session_id header, so a call
+// to it sends the key there and in the body. Every call is recorded in the
+// usage file.
 //
 // The request never holds max_output_tokens or metadata, because the ChatGPT
 // backend refuses them. It sets store to false, so the client sends the whole
 //
 // The request never holds max_output_tokens or metadata, because the ChatGPT
 // backend refuses them. It sets store to false, so the client sends the whole
@@ -64,13 +66,16 @@ type Client struct {
 }
 
 // Request is one model call. Input holds the input items in order, such as
 }
 
 // Request is one model call. Input holds the input items in order, such as
-// userMessage values or output items of an earlier response.
+// userMessage values or output items of an earlier response. Node names the
+// node that a compaction builds, or is nil. It goes only to the usage file,
+// never to the endpoint.
 type Request struct {
        Model        string
        Effort       string
        Instructions string
        Tools        []Tool
        Input        []any
 type Request struct {
        Model        string
        Effort       string
        Instructions string
        Tools        []Tool
        Input        []any
+       Node         *nodeKey
 }
 
 // Tool is the definition of a function tool.
 }
 
 // Tool is the definition of a function tool.
@@ -217,19 +222,31 @@ func (c *Client) Create(ctx context.Context, request Request) (Response, error)
                return Response{}, fmt.Errorf("authorize model call: %w", err)
        }
 
                return Response{}, fmt.Errorf("authorize model call: %w", err)
        }
 
+       _, chatgpt := c.auth.(*chatgptAuth)
+       if chatgpt {
+               httpRequest.Header.Set("session_id", c.cacheKey)
+       }
+
+       start := time.Now()
        record := usageRecord{
        record := usageRecord{
-               Date:  time.Now().Format(time.RFC3339Nano),
+               Date:  start.Format(time.RFC3339Nano),
                Model: request.Model,
        }
 
                Model: request.Model,
        }
 
+       if request.Node != nil {
+               record.Node = &[2]int{request.Node.level, request.Node.index}
+       }
+
        response, err := c.send(httpRequest, &record)
        if err != nil {
                record.Error = err.Error()
        }
 
        response, err := c.send(httpRequest, &record)
        if err != nil {
                record.Error = err.Error()
        }
 
+       record.Seconds = time.Since(start).Seconds()
        record.InputTokens = response.Usage.Input
        record.CachedTokens = response.Usage.Cached
        record.OutputTokens = response.Usage.Output
        record.InputTokens = response.Usage.Input
        record.CachedTokens = response.Usage.Cached
        record.OutputTokens = response.Usage.Output
+       record.TextBytes = len(response.Text)
 
        return response, errors.Join(err, c.usage.Write(record))
 }
 
        return response, errors.Join(err, c.usage.Write(record))
 }
@@ -265,16 +282,21 @@ type usageLog struct {
        path  string
 }
 
        path  string
 }
 
-// usageRecord is one line of usage.jsonl. Status is the HTTP status, or 0 when
-// no response came. Quota holds the x-codex-* headers of the response, without
-// the turn state.
+// usageRecord is one line of usage.jsonl. Date is the start of the call, and
+// Seconds its length. Node is the node [l, i] of a compaction. Status is the
+// HTTP status, or 0 when no response came. TextBytes is the size of the text of
+// the reply. Quota holds the x-codex-* headers of the response, without the
+// turn state.
 type usageRecord struct {
        Date         string            `json:"date"`
 type usageRecord struct {
        Date         string            `json:"date"`
+       Seconds      float64           `json:"seconds"`
        Model        string            `json:"model"`
        Model        string            `json:"model"`
+       Node         *[2]int           `json:"node,omitempty"`
        Status       int               `json:"status"`
        InputTokens  int               `json:"input_tokens"`
        CachedTokens int               `json:"cached_tokens"`
        OutputTokens int               `json:"output_tokens"`
        Status       int               `json:"status"`
        InputTokens  int               `json:"input_tokens"`
        CachedTokens int               `json:"cached_tokens"`
        OutputTokens int               `json:"output_tokens"`
+       TextBytes    int               `json:"text_bytes"`
        Quota        map[string]string `json:"quota,omitempty"`
        Error        string            `json:"error,omitempty"`
 }
        Quota        map[string]string `json:"quota,omitempty"`
        Error        string            `json:"error,omitempty"`
 }