bin/reflow wraps each changed paragraph again, so that no comment line
passes 80 columns with tabs as 8 columns, as the docs skill asks. Ten
lines were over, from edits that skipped the reflow. Only comments
change.
}
// addMessage builds the leaf of message when it needs no model call, or else
}
// addMessage builds the leaf of message when it needs no model call, or else
-// adds the leaf to the queue. Then it appends the leaf to the views. A crash can
-// stop an append after the leaf build and before the view save, so a leaf that
-// is built already stays as it is, and restoreQueue settles its parent.
+// adds the leaf to the queue. Then it appends the leaf to the views. A crash
+// can stop an append after the leaf build and before the view save, so a leaf
+// that is built already stays as it is, and restoreQueue settles its parent.
func (m *Memory) addMessage(message Message) error {
built, err := m.tree.Built(0, message.ID)
if err != nil {
func (m *Memory) addMessage(message Message) error {
built, err := m.tree.Built(0, message.ID)
if err != nil {
var errModelCallLimit = errors.New("call limit reached")
// modelEndpoint returns the URL and the authorizer of the endpoint in config.
var errModelCallLimit = errors.New("call limit reached")
// modelEndpoint returns the URL and the authorizer of the endpoint in config.
-// The ChatGPT backend uses the token file in dir. The OpenAI API uses the key in
-// OPENAI_API_KEY, and there is no fallback from one to the other. All clients
-// share the authorizer, so one refresh runs at a time.
+// The ChatGPT backend uses the token file in dir. The OpenAI API uses the key
+// in OPENAI_API_KEY, and there is no fallback from one to the other. All
+// clients share the authorizer, so one refresh runs at a time.
func modelEndpoint(config Config, dir string) (string, ModelAuthorizer, error) {
if config.Endpoint == configEndpointAPI {
key := os.Getenv("OPENAI_API_KEY")
func modelEndpoint(config Config, dir string) (string, ModelAuthorizer, error) {
if config.Endpoint == configEndpointAPI {
key := os.Getenv("OPENAI_API_KEY")
}
// run runs the chains of run and reports and logs its end with the length of
}
// run runs the chains of run and reports and logs its end with the length of
-// the run, unless Close ended it. A chain follows while messages wait after the final answer of the chain before
-// it, and no chain failed. A chain that Stop ends gives the reply "stopped".
+// the run, unless Close ended it. A chain follows while messages wait after the
+// final answer of the chain before it, and no chain failed. A chain that Stop
+// ends gives the reply "stopped".
func (r *SubagentRuns) run(ctx context.Context, run *SubagentRun) {
defer r.workers.Done()
defer run.cancel()
func (r *SubagentRuns) run(ctx context.Context, run *SubagentRun) {
defer r.workers.Done()
defer run.cancel()
// SubagentRun is one run of a subagent: the view that its requests get, its
// effort, the end of its context, the messages of Tell that wait for a request,
// SubagentRun is one run of a subagent: the view that its requests get, its
// effort, the end of its context, the messages of Tell that wait for a request,
-// whether Stop ended it, and the time it started. The mutex of SubagentRuns protects the messages
-// and the stop.
+// whether Stop ended it, and the time it started. The mutex of SubagentRuns
+// protects the messages and the stop.
type SubagentRun struct {
subagent *Subagent
view []string
type SubagentRun struct {
subagent *Subagent
view []string
last := subagentTestLastItem(call)
switch {
case subagentTestCall(call) && last["type"] == "function_call_output":
last := subagentTestLastItem(call)
switch {
case subagentTestCall(call) && last["type"] == "function_call_output":
- // The report comes after the reply of the turn of the spawn.
+ // The report comes after the reply of the turn of the
+ // spawn.
test.events.WaitFor(t, "reply", 1)
modelWriteEvents(w, modelCompletedEvent([]any{modelMessageItem("There are 3 files.")}, 100, 0, 5))
case subagentTestCall(call):
test.events.WaitFor(t, "reply", 1)
modelWriteEvents(w, modelCompletedEvent([]any{modelMessageItem("There are 3 files.")}, 100, 0, 5))
case subagentTestCall(call):
- // telegramTagEscaper writes the characters that rich Markdown reads as HTML
- // as HTML entities.
+ // telegramTagEscaper writes the characters that rich Markdown reads as
+ // HTML as HTML entities.
telegramTagEscaper = strings.NewReplacer("&", "&", "<", "<")
// telegramTagUnescaper reverses telegramTagEscaper.
telegramTagEscaper = strings.NewReplacer("&", "&", "<", "<")
// telegramTagUnescaper reverses telegramTagEscaper.
last := subagentTestLastItem(call)
switch {
case subagentTestCall(call):
last := subagentTestLastItem(call)
switch {
case subagentTestCall(call):
- // The report comes after the reply of the turn of the spawn.
+ // The report comes after the reply of the turn of the
+ // spawn.
require.Eventually(t, func() bool {
return slices.Contains(telegram.Sent(), "Started.")
}, 10*time.Second, time.Millisecond)
require.Eventually(t, func() bool {
return slices.Contains(telegram.Sent(), "Started.")
}, 10*time.Second, time.Millisecond)
require.Contains(t, logs.String(), "<6>receive back after=")
require.Contains(t, logs.String(), "<4>send failed retry=1s: 429")
require.Contains(t, logs.String(), "<6>receive back after=")
require.Contains(t, logs.String(), "<4>send failed retry=1s: 429")
- // The bot logs the end of the outage after the send returns, so the line
- // can come after the fake server has the message.
+ // The bot logs the end of the outage after the send returns, so the
+ // line can come after the fake server has the message.
require.Eventually(t, func() bool {
return strings.Contains(logs.String(), "<6>send back after=")
}, 10*time.Second, time.Millisecond)
require.Eventually(t, func() bool {
return strings.Contains(logs.String(), "<6>send back after=")
}, 10*time.Second, time.Millisecond)
return strings.ToLower(strings.TrimSpace(folded))
}
return strings.ToLower(strings.TrimSpace(folded))
}
-// whatsappFindAnswer returns the answer of whatsappFind for name with matches. Without
-// groups, the answer says that it has no groups.
+// whatsappFindAnswer returns the answer of whatsappFind for name with matches.
+// Without groups, the answer says that it has no groups.
func whatsappFindAnswer(name string, matches []WhatsAppMatch, groups bool) string {
slices.SortFunc(matches, func(a, b WhatsAppMatch) int {
return cmp.Or(strings.Compare(whatsappFold(a.name), whatsappFold(b.name)), strings.Compare(a.id, b.id))
func whatsappFindAnswer(name string, matches []WhatsAppMatch, groups bool) string {
slices.SortFunc(matches, func(a, b WhatsAppMatch) int {
return cmp.Or(strings.Compare(whatsappFold(a.name), whatsappFold(b.name)), strings.Compare(a.id, b.id))
// during the send gives an answer that the result is unknown, and not a second
// send. A disconnected WhatsApp sends nothing and makes no record. link gives
// the device, the client, and the own IDs, groups the names of the groups, and
// during the send gives an answer that the result is unknown, and not a second
// send. A disconnected WhatsApp sends nothing and makes no record. link gives
// the device, the client, and the own IDs, groups the names of the groups, and
-// state the send records, and logger gets one line for each send. The clock gives the times of the records and the time
-// zone of the answer. Image names are checked before the record is written, and
-// uploads start only after the record is durable. Text-only records keep their
-// text digest.
+// state the send records, and logger gets one line for each send. The clock
+// gives the times of the records and the time zone of the answer. Image names
+// are checked before the record is written, and uploads start only after the
+// record is durable. Text-only records keep their text digest.
func whatsappSend(ctx context.Context, link WhatsAppLink, groups *WhatsAppGroups, state *WhatsAppState, images *ImageStore, logger *slog.Logger, clock func() time.Time, id, chat, text, image string) (string, error) {
if !link.linked {
return whatsappNotLinked, nil
func whatsappSend(ctx context.Context, link WhatsAppLink, groups *WhatsAppGroups, state *WhatsAppState, images *ImageStore, logger *slog.Logger, clock func() time.Time, id, chat, text, image string) (string, error) {
if !link.linked {
return whatsappNotLinked, nil