A model request names the subagent that makes it, and the usage record
of the call holds that name in the agent field. A call of the agent
itself has no such field. The name goes only to the usage file, never to
the endpoint, so the usage records show the cost of each subagent in the
shared usage file of the agent.
Issue:
b1ac698
}
record.Turn = request.Turn
}
record.Turn = request.Turn
+ record.Agent = request.Agent
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()
// ModelRequest is one model call. Input holds the input items in order, such as
// modelUserMessage values or output items of an earlier response. Node names
// the node that a compaction builds, or is nil. Turn names the request of a
// ModelRequest is one model call. Input holds the input items in order, such as
// modelUserMessage values or output items of an earlier response. Node names
// the node that a compaction builds, or is nil. Turn names the request of a
-// turn: first or next. Node and Turn go only to the usage file, never to the
-// endpoint.
+// turn: first or next. Agent names the subagent that makes the call, or is
+// empty for a call of the agent itself. Node, Turn, and Agent go only to the
+// usage file, never to the endpoint.
type ModelRequest struct {
Model string
Effort string
type ModelRequest struct {
Model string
Effort string
Input []any
Node *NodeKey
Turn string
Input []any
Node *NodeKey
Turn string
}
// ModelResponse is the result of a model call. Output holds the output items as
}
// ModelResponse is the result of a model call. Output holds the output items as
// ModelUsageRecord 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
// ModelUsageRecord 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. Turn names the request of a turn. Quota holds the
-// x-codex-* headers of the response, without the turn state.
+// text of the reply. Turn names the request of a turn. Agent names the subagent
+// of the call. Quota holds the x-codex-* headers of the response, without the
+// turn state.
type ModelUsageRecord struct {
Date string `json:"date"`
Seconds float64 `json:"seconds"`
Model string `json:"model"`
Node *[2]int `json:"node,omitempty"`
Turn string `json:"turn,omitempty"`
type ModelUsageRecord struct {
Date string `json:"date"`
Seconds float64 `json:"seconds"`
Model string `json:"model"`
Node *[2]int `json:"node,omitempty"`
Turn string `json:"turn,omitempty"`
+ Agent string `json:"agent,omitempty"`
Status int `json:"status"`
InputTokens int `json:"input_tokens"`
CachedTokens int `json:"cached_tokens"`
Status int `json:"status"`
InputTokens int `json:"input_tokens"`
CachedTokens int `json:"cached_tokens"`
client := newTestModelClient(t, server)
request := modelTestRequest()
request.Node = &NodeKey{2, 5}
client := newTestModelClient(t, server)
request := modelTestRequest()
request.Node = &NodeKey{2, 5}
+ request.Agent = "GreenOtter"
_, err := client.Create(t.Context(), request)
require.NoError(t, err)
require.NotContains(t, server.Call(0).body, "node")
require.NotContains(t, string(server.Call(0).raw), "[2,5]")
_, err := client.Create(t.Context(), request)
require.NoError(t, err)
require.NotContains(t, server.Call(0).body, "node")
require.NotContains(t, string(server.Call(0).raw), "[2,5]")
+ require.NotContains(t, string(server.Call(0).raw), "GreenOtter")
_, err = client.Create(t.Context(), modelTestRequest())
require.ErrorContains(t, err, "HTTP 429")
_, err = client.Create(t.Context(), modelTestRequest())
require.ErrorContains(t, err, "HTTP 429")
require.Equal(t, 7, records[0].OutputTokens)
require.Equal(t, quota, records[0].Quota)
require.Equal(t, &[2]int{2, 5}, records[0].Node)
require.Equal(t, 7, records[0].OutputTokens)
require.Equal(t, quota, records[0].Quota)
require.Equal(t, &[2]int{2, 5}, records[0].Node)
+ require.Equal(t, "GreenOtter", records[0].Agent)
require.Equal(t, len("ok"), records[0].TextBytes)
require.Greater(t, records[0].Seconds, 0.0)
require.Empty(t, records[0].Error)
require.NotEmpty(t, records[0].Date)
require.Nil(t, records[1].Node)
require.Equal(t, len("ok"), records[0].TextBytes)
require.Greater(t, records[0].Seconds, 0.0)
require.Empty(t, records[0].Error)
require.NotEmpty(t, records[0].Date)
require.Nil(t, records[1].Node)
+ require.Empty(t, records[1].Agent)
require.Zero(t, records[1].TextBytes)
require.Equal(t, http.StatusTooManyRequests, records[1].Status)
require.Zero(t, records[1].TextBytes)
require.Equal(t, http.StatusTooManyRequests, records[1].Status)