X-Git-Url: https://git.giacomolli.uk/onechat/blobdiff_plain/522d7fd117285e4e4ce3ea5ec9b5a1722521b681..bd7da3557dc7a17020931f5a49ed5007fa81a645:/build_run.go?ds=sidebyside diff --git a/build_run.go b/build_run.go index da75679..44d636d 100644 --- a/build_run.go +++ b/build_run.go @@ -19,12 +19,12 @@ import ( // buildLineBytes is the most bytes of one line in a build input or usage log. const buildLineBytes = 1 << 20 +// buildWaitTimeout is the longest wait for pending memory builds. +const buildWaitTimeout = time.Second + // buildQuotaLimit is the largest increase in used quota points of a run. const buildQuotaLimit = 15.0 -// buildCallLimit is the most model calls of a run. -const buildCallLimit = 660 - // BuildRun appends messages, builds their tree, and stops the run by the rules // of buildStop. type BuildRun struct { @@ -33,6 +33,13 @@ type BuildRun struct { usagePath string } +// DatedMessage is one message with an optional RFC 3339 date. +type DatedMessage struct { + Kind string `json:"kind"` + Text string `json:"text"` + Date string `json:"date,omitempty"` +} + // Run appends the entries. It waits for the builds only before a user message, // as a turn does, so up to buildMax builds run at once in between, and it waits // for all builds at the end. It returns the number of messages appended and why @@ -116,19 +123,12 @@ func (r *BuildRun) check() string { // waitBuilds waits up to one second without leaving a child context open. func (r *BuildRun) waitBuilds(ctx context.Context) error { - ctx, cancel := context.WithTimeout(ctx, time.Second) + ctx, cancel := context.WithTimeout(ctx, buildWaitTimeout) defer cancel() return r.memory.Wait(ctx) } -// DatedMessage is one message with an optional RFC 3339 date. -type DatedMessage struct { - Kind string `json:"kind"` - Text string `json:"text"` - Date string `json:"date,omitempty"` -} - // buildReadUsage reads the records of usage.jsonl at path, in the order of the // start of their calls. The file has them in the order of the end of their // calls, which differs when calls run at once. @@ -175,6 +175,60 @@ func buildReadUsage(path string) (records []ModelUsageRecord, err error) { return records, nil } +// buildStop returns why a build run must stop: a failed call, or a quota window +// whose used percent grew by more than buildQuotaLimit points since the first +// call. It returns "" when the run can go on. +func buildStop(records []ModelUsageRecord) string { + for _, record := range records { + if record.Error != "" { + return "call failed: " + record.Error + } + } + + if len(records) == 0 { + return "" + } + + first := buildUsedPercents(records[0]) + for name, used := range buildUsedPercents(records[len(records)-1]) { + start, found := first[name] + if found && used-start > buildQuotaLimit { + return fmt.Sprintf("%s grew from %g to %g", name, start, used) + } + } + + return "" +} + +// buildCallStart returns the start of the call of record, or the zero time when +// its date is not valid. +func buildCallStart(record ModelUsageRecord) time.Time { + start, err := time.Parse(time.RFC3339Nano, record.Date) + if err != nil { + return time.Time{} + } + + return start +} + +// buildUsedPercents returns the used percent of each quota window of record, by +// header name. +func buildUsedPercents(record ModelUsageRecord) map[string]float64 { + used := make(map[string]float64) + for name, value := range record.Quota { + if !strings.HasSuffix(name, "-used-percent") { + continue + } + + percent, err := strconv.ParseFloat(value, 64) + if err == nil { + used[name] = percent + } + } + + return used +} + // buildWriteReport writes the result of a build run. func buildWriteReport(out io.Writer, appended int, stop string, records []ModelUsageRecord, sizes []int) error { var input, cached, output, failed int @@ -224,42 +278,6 @@ func buildWriteReport(out io.Writer, appended int, stop string, records []ModelU return nil } -// buildStop returns why a build run must stop: a failed call, or a quota window -// whose used percent grew by more than buildQuotaLimit points since the first -// call. It returns "" when the run can go on. -func buildStop(records []ModelUsageRecord) string { - for _, record := range records { - if record.Error != "" { - return "call failed: " + record.Error - } - } - - if len(records) == 0 { - return "" - } - - first := buildUsedPercents(records[0]) - for name, used := range buildUsedPercents(records[len(records)-1]) { - start, found := first[name] - if found && used-start > buildQuotaLimit { - return fmt.Sprintf("%s grew from %g to %g", name, start, used) - } - } - - return "" -} - -// buildCallStart returns the start of the call of record, or the zero time when -// its date is not valid. -func buildCallStart(record ModelUsageRecord) time.Time { - start, err := time.Parse(time.RFC3339Nano, record.Date) - if err != nil { - return time.Time{} - } - - return start -} - // buildRatio returns a / b, or 0 when b is 0. func buildRatio(a, b int) float64 { if b == 0 { @@ -345,21 +363,3 @@ func buildQuotaText(record ModelUsageRecord) string { return strings.Join(parts, " ") } - -// buildUsedPercents returns the used percent of each quota window of record, by -// header name. -func buildUsedPercents(record ModelUsageRecord) map[string]float64 { - used := make(map[string]float64) - for name, value := range record.Quota { - if !strings.HasSuffix(name, "-used-percent") { - continue - } - - percent, err := strconv.ParseFloat(value, 64) - if err == nil { - used[name] = percent - } - } - - return used -}