]> git.giacomolli.uk - onechat/blobdiff - model.go
Separate returns from longer statement blocks
[onechat] / model.go
index f15be221e2d494e977595d3437d274029eb85552..7c856431124af275fa96c90582b0cdb1bb74be85 100644 (file)
--- a/model.go
+++ b/model.go
@@ -138,9 +138,11 @@ func (k ModelAPIKey) Authorize(ctx context.Context, header http.Header) error {
 // 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.
 // 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.
-// 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.
+// A call of a subagent sends the key of the agent with "-" and the name of the
+// subagent, so that the calls of a subagent do not share a cache entry with the
+// calls of the agent that run at the same time. 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
@@ -166,6 +168,16 @@ func (c *ModelClient) LimitReached() bool {
        return c.limit > 0 && c.calls.Load() >= c.limit
 }
 
        return c.limit > 0 && c.calls.Load() >= c.limit
 }
 
+// CallLimit returns the configured call limit, or zero for no limit.
+func (c *ModelClient) CallLimit() int64 {
+       return c.limit
+}
+
+// UsagePath returns the file that records the calls of this client.
+func (c *ModelClient) UsagePath() string {
+       return c.usage.path
+}
+
 // Create sends the call and reads its event stream to the end. Over the call
 // limit it sends nothing and returns errModelCallLimit.
 func (c *ModelClient) Create(ctx context.Context, request ModelRequest) (ModelResponse, error) {
 // Create sends the call and reads its event stream to the end. Over the call
 // limit it sends nothing and returns errModelCallLimit.
 func (c *ModelClient) Create(ctx context.Context, request ModelRequest) (ModelResponse, error) {
@@ -173,6 +185,11 @@ func (c *ModelClient) Create(ctx context.Context, request ModelRequest) (ModelRe
                return ModelResponse{}, errModelCallLimit
        }
 
                return ModelResponse{}, errModelCallLimit
        }
 
+       cacheKey := c.cacheKey
+       if request.Agent != "" {
+               cacheKey += "-" + request.Agent
+       }
+
        body, err := json.Marshal(ModelRequestBody{
                Model:        request.Model,
                Instructions: request.Instructions,
        body, err := json.Marshal(ModelRequestBody{
                Model:        request.Model,
                Instructions: request.Instructions,
@@ -184,7 +201,7 @@ func (c *ModelClient) Create(ctx context.Context, request ModelRequest) (ModelRe
                Store:          false,
                Stream:         true,
                Include:        []string{"reasoning.encrypted_content"},
                Store:          false,
                Stream:         true,
                Include:        []string{"reasoning.encrypted_content"},
-               PromptCacheKey: c.cacheKey,
+               PromptCacheKey: cacheKey,
        })
        if err != nil {
                return ModelResponse{}, fmt.Errorf("encode request: %w", err)
        })
        if err != nil {
                return ModelResponse{}, fmt.Errorf("encode request: %w", err)
@@ -204,7 +221,7 @@ func (c *ModelClient) Create(ctx context.Context, request ModelRequest) (ModelRe
 
        _, chatgpt := c.auth.(*ChatGPTAuth)
        if chatgpt {
 
        _, chatgpt := c.auth.(*ChatGPTAuth)
        if chatgpt {
-               httpRequest.Header.Set("session_id", c.cacheKey)
+               httpRequest.Header.Set("session_id", cacheKey)
        }
 
        start := time.Now()
        }
 
        start := time.Now()
@@ -304,8 +321,9 @@ type ModelOutputItem struct {
 // 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. Agent names the subagent that makes the call, or is
 // 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. 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.
+// empty for a call of the agent itself. Node, Turn, and Agent go to the usage
+// file, never to the endpoint as fields. Agent also gives the call the cache
+// key of its subagent.
 type ModelRequest struct {
        Model        string
        Effort       string
 type ModelRequest struct {
        Model        string
        Effort       string