Add run_on_client: agents run commands with files on the user's Macs

This commit is contained in:
Ian Gulliver
2026-10-17 14:41:04 -07:00
parent 14975d2ab8
commit fbc0699fdf
16 changed files with 928 additions and 249 deletions
+191
View File
@@ -0,0 +1,191 @@
package agents
import (
"context"
"encoding/json"
"errors"
"fmt"
"log/slog"
"os"
"os/exec"
"path/filepath"
"strings"
"time"
"g.fc.run/misc/byre/internal/api"
"g.fc.run/misc/byre/internal/mcp"
"g.fc.run/misc/byre/internal/store"
)
const (
bundleTimeout = 5 * time.Minute
MaxRunOutput = 64 << 10
)
type runOnClientArgs struct {
Paths []string `json:"paths"`
Command string `json:"command"`
Why string `json:"why"`
}
func (m *Manager) runOnClientTool(l *live) mcp.Tool {
return mcp.Tool{
Name: "run_on_client",
Description: "Ask the human to run a command on their own Mac, with files from your worktree, for example to install and launch an app you built. " +
"byre packs paths into a bundle now, so later changes to them aren't sent, and files a card in the human's inbox showing why, the command and the files. " +
"Every Mac the human has byre open on shows the card with Run and Dismiss; each Mac where they click Run downloads the bundle, unpacks it into a new empty directory, " +
"and runs command there with zsh as a login shell, as the human. The directory is deleted once the command finishes, so copy anything that must stay elsewhere first. " +
"The command keeps running if it quits byre's app, and the app reports it when it next starts. " +
"This call returns at once; you don't need to end your turn. Each Mac's run reaches you as a message with its host name, exit status and the last 64 KiB of its output. " +
"The card stays until the human dismisses it, so it can be run again or on another Mac.",
InputSchema: json.RawMessage(`{
"type": "object",
"properties": {
"paths": {"type": "array", "items": {"type": "string"}, "description": "Files or directories to send, relative to your worktree; each is unpacked at the same relative path. May be empty."},
"command": {"type": "string", "description": "The zsh command to run in the directory the bundle unpacks into, e.g. 'rm -rf ~/Applications/byre.app && ditto mac/.build/byre.app ~/Applications/byre.app && (pkill -x Byre; open ~/Applications/byre.app)'."},
"why": {"type": "string", "description": "One or two sentences for the human: what running it does and why."}
},
"required": ["paths", "command", "why"]
}`),
Handler: func(ctx context.Context, raw json.RawMessage) (string, error) {
return m.runOnClient(ctx, l, raw)
},
}
}
func (m *Manager) runOnClient(ctx context.Context, l *live, raw json.RawMessage) (string, error) {
args := runOnClientArgs{}
err := json.Unmarshal(raw, &args)
if err != nil {
return "", fmt.Errorf("malformed run_on_client call: %w", err)
}
if strings.TrimSpace(args.Command) == "" {
return "", errors.New("command is empty")
}
if strings.TrimSpace(args.Why) == "" {
return "", errors.New("why is empty: say what running it does and why")
}
paths, err := checkBundlePaths(l.dir, args.Paths)
if err != nil {
return "", err
}
id := store.NewID()
size, err := m.writeBundle(ctx, l.dir, paths, m.store.BundlePath(id))
if err != nil {
return "", err
}
payload := map[string]any{
"why": args.Why,
"command": args.Command,
"paths": paths,
"bytes": size,
}
err = m.store.CreateInboxItem(ctx, m.newItem(l, id, id, api.ClientRun, payload))
if err != nil {
os.Remove(m.store.BundlePath(id))
return "", err
}
return fmt.Sprintf("Run request %s filed in the human's inbox with a %d-byte bundle. Each Mac's run will reach you as a message.", id, size), nil
}
func checkBundlePaths(dir string, paths []string) ([]string, error) {
root, err := os.OpenRoot(dir)
if err != nil {
return nil, err
}
defer root.Close()
out := []string{}
for _, p := range paths {
clean := filepath.Clean(p)
if filepath.IsAbs(clean) || clean == "." || strings.HasPrefix(clean, "-") {
return nil, fmt.Errorf("path %q must be relative to your worktree and inside it", p)
}
_, err = root.Lstat(clean)
if err != nil {
return nil, fmt.Errorf("path %q: %w", p, err)
}
out = append(out, clean)
}
return out, nil
}
func (m *Manager) writeBundle(ctx context.Context, dir string, paths []string, dest string) (int64, error) {
err := os.MkdirAll(filepath.Dir(dest), 0o755)
if err != nil {
return 0, err
}
tmp := dest + ".tmp"
cctx, cancel := context.WithTimeout(ctx, bundleTimeout)
defer cancel()
// -T /dev/null lets tar write an empty archive when paths is empty.
cmd := exec.CommandContext(cctx, "tar", append([]string{"-czf", tmp, "-C", dir, "-T", "/dev/null", "--"}, paths...)...)
out, err := cmd.CombinedOutput()
if err != nil {
os.Remove(tmp)
return 0, fmt.Errorf("pack bundle: %w: %s", err, out)
}
err = os.Rename(tmp, dest)
if err != nil {
return 0, err
}
info, err := os.Stat(dest)
if err != nil {
return 0, err
}
return info.Size(), nil
}
func (m *Manager) ReportRun(ctx context.Context, user, itemID string, report api.RunReport) (api.InboxItem, error) {
item, err := m.store.GetInboxItem(ctx, itemID)
if err != nil {
return item, err
}
if item.Kind != api.ClientRun {
return item, fmt.Errorf("%w: item %s is a %s, not a client_run", ErrInvalid, itemID, item.Kind)
}
client := strings.TrimSpace(report.Client)
if client == "" {
return item, fmt.Errorf("%w: client is empty", ErrInvalid)
}
if strings.TrimSpace(report.RunId) == "" {
return item, fmt.Errorf("%w: run_id is empty", ErrInvalid)
}
output := report.Output
if len(output) > MaxRunOutput {
output = strings.ToValidUTF8(output[len(output)-MaxRunOutput:], "")
}
resp := api.InboxResponse{
Id: report.RunId,
ItemId: itemID,
User: user,
Type: api.Run,
Text: &output,
Client: &client,
ExitCode: &report.ExitCode,
CreatedAt: time.Now().UTC(),
}
added, err := m.store.AddRunResponse(ctx, resp)
if err != nil {
return item, err
}
if !added {
slog.Info("client run already reported", "item", itemID, "response", resp.Id, "client", client)
return m.store.GetInboxItem(ctx, itemID)
}
slog.Info("client run reported", "item", itemID, "response", resp.Id, "user", user, "client", client, "exit", report.ExitCode)
go func() {
err := m.Deliver(context.Background(), item.AgentSessionId)
if err != nil {
slog.Error("deliver run report", "session", item.AgentSessionId, "err", err)
}
}()
return m.store.GetInboxItem(ctx, itemID)
}
+7
View File
@@ -492,9 +492,16 @@ func deliveryMessage(pending []store.Pending) string {
fmt.Fprintf(b, "Your error %s: %s\n", p.Item.Id, p.Item.Payload["error"])
case api.RateLimited:
fmt.Fprintf(b, "Your rate-limited turn %s: %s\n", p.Item.Id, p.Item.Payload["error"])
case api.ClientRun:
fmt.Fprintf(b, "Your run request %s: %s\n", p.Item.Id, p.Item.Payload["command"])
}
switch r.Type {
case api.Run:
fmt.Fprintf(b, "%s ran it on %s: exit status %d\n", r.User, *r.Client, *r.ExitCode)
if r.Text != nil && *r.Text != "" {
fmt.Fprintf(b, "Output:\n```\n%s\n```\n", strings.TrimRight(*r.Text, "\n"))
}
case api.Option:
if p.Item.Payload["multiple"] == true {
fmt.Fprintf(b, "%s checked:\n", r.User)
+1 -1
View File
@@ -709,7 +709,7 @@ func (m *Manager) startLive(ctx context.Context, sess api.AgentSession, task api
if err != nil {
return nil, err
}
tools := append([]mcp.Tool{m.askTool(l), m.cancelQuestionTool(l), m.setMergeTitleTool(l), m.stopMergeTool(l), m.setTaskSummaryTool(l), m.searchClosedTool(l), m.exposePortTool(l), m.takeSnapshotTool(l)}, m.subtaskTools(l)...)
tools := append([]mcp.Tool{m.askTool(l), m.cancelQuestionTool(l), m.setMergeTitleTool(l), m.stopMergeTool(l), m.setTaskSummaryTool(l), m.searchClosedTool(l), m.exposePortTool(l), m.runOnClientTool(l), m.takeSnapshotTool(l)}, m.subtaskTools(l)...)
if sess.Role == api.Implementer {
g += longTitleGuidance(task)
notes, err := m.notesText(ctx, task.CreatedBy, task.ProjectId)
+4
View File
@@ -113,6 +113,10 @@ func CheckResponse(item api.InboxItem, c api.InboxResponseCreate) (api.InboxStat
return "", fmt.Errorf("%w: item %s: "+format, append([]any{ErrInvalid, item.Id}, args...)...)
}
if item.Kind == api.ClientRun && c.Type != api.Dismiss {
return bad("a run request is only dismissed here; runs are reported to /api/inbox/%s/runs", item.Id)
}
switch c.Type {
case api.Option:
if !question {
+325 -232
View File
@@ -203,6 +203,7 @@ func (e FindingState) Valid() bool {
// Defines values for InboxItemKind.
const (
ClientRun InboxItemKind = "client_run"
Question InboxItemKind = "question"
RateLimited InboxItemKind = "rate_limited"
SessionError InboxItemKind = "session_error"
@@ -211,6 +212,8 @@ const (
// Valid indicates whether the value is a known member of the InboxItemKind enum.
func (e InboxItemKind) Valid() bool {
switch e {
case ClientRun:
return true
case Question:
return true
case RateLimited:
@@ -227,6 +230,7 @@ const (
Dismiss InboxResponseType = "dismiss"
Option InboxResponseType = "option"
Other InboxResponseType = "other"
Run InboxResponseType = "run"
)
// Valid indicates whether the value is a known member of the InboxResponseType enum.
@@ -238,6 +242,8 @@ func (e InboxResponseType) Valid() bool {
return true
case Other:
return true
case Run:
return true
default:
return false
}
@@ -749,7 +755,7 @@ type InboxItem struct {
Id string `json:"id"`
Kind InboxItemKind `json:"kind"`
// Payload question: context (Markdown with the choices inline as `- ( ) text` / `- (*) text` pick-one or `- [ ] text` / `- [x] text` pick-any list items), question, why_blocked, options (each choice's text, in order), multiple (true for pick-any), recommended (the marked choices' text), attachments. session_error: error. rate_limited: vendor, rate_limit (the vendor's rate-limit status), error.
// Payload question: context (Markdown with the choices inline as `- ( ) text` / `- (*) text` pick-one or `- [ ] text` / `- [x] text` pick-any list items), question, why_blocked, options (each choice's text, in order), multiple (true for pick-any), recommended (the marked choices' text), attachments. session_error: error. rate_limited: vendor, rate_limit (the vendor's rate-limit status), error. client_run: why, command, paths (worktree paths in the bundle), bytes (the bundle's size).
Payload map[string]interface{} `json:"payload"`
ProjectId string `json:"project_id"`
ResolvedAt *time.Time `json:"resolved_at,omitempty"`
@@ -771,17 +777,25 @@ type InboxRespond struct {
// InboxResponse defines model for InboxResponse.
type InboxResponse struct {
Attachments []Attachment `json:"attachments"`
CreatedAt time.Time `json:"created_at"`
DeliveredAt *time.Time `json:"delivered_at,omitempty"`
Id string `json:"id"`
// Client run: the host name of the Mac that ran the command.
Client *string `json:"client,omitempty"`
CreatedAt time.Time `json:"created_at"`
DeliveredAt *time.Time `json:"delivered_at,omitempty"`
// ExitCode run: the command's exit status.
ExitCode *int `json:"exit_code,omitempty"`
Id string `json:"id"`
// Images Blob ids sent to the agent as images alongside the response.
Images []string `json:"images"`
ItemId string `json:"item_id"`
Options *[]string `json:"options,omitempty"`
Text *string `json:"text,omitempty"`
Type InboxResponseType `json:"type"`
User string `json:"user"`
Images []string `json:"images"`
ItemId string `json:"item_id"`
Options *[]string `json:"options,omitempty"`
// Text run: the command's output, at most its last 64 KiB.
Text *string `json:"text,omitempty"`
Type InboxResponseType `json:"type"`
User string `json:"user"`
}
// InboxResponseCreate defines model for InboxResponseCreate.
@@ -945,6 +959,16 @@ type Review struct {
// ReviewState skipped: the snapshot's step changed no files, so no reviewer ran.
type ReviewState string
// RunReport defines model for RunReport.
type RunReport struct {
Client string `json:"client"`
ExitCode int `json:"exit_code"`
Output string `json:"output"`
// RunId The Mac's id for this one run, used as the response's id; reporting it again records nothing new.
RunId string `json:"run_id"`
}
// SessionCreate defines model for SessionCreate.
type SessionCreate struct {
// Images Blob ids from uploadBlob, sent to the agent as images alongside the prompt.
@@ -1398,6 +1422,9 @@ type GetTaskTerminalParams struct {
// RespondInboxJSONRequestBody defines body for RespondInbox for application/json ContentType.
type RespondInboxJSONRequestBody = InboxRespond
// ReportRunJSONRequestBody defines body for ReportRun for application/json ContentType.
type ReportRunJSONRequestBody = RunReport
// UpdateMeJSONRequestBody defines body for UpdateMe for application/json ContentType.
type UpdateMeJSONRequestBody = UserUpdate
@@ -1461,6 +1488,12 @@ type ServerInterface interface {
// (GET /api/inbox/{itemId})
GetInboxItem(w http.ResponseWriter, r *http.Request, itemId string)
// (GET /api/inbox/{itemId}/bundle)
GetRunBundle(w http.ResponseWriter, r *http.Request, itemId string)
// (POST /api/inbox/{itemId}/runs)
ReportRun(w http.ResponseWriter, r *http.Request, itemId string)
// (GET /api/me)
GetMe(w http.ResponseWriter, r *http.Request)
@@ -1860,6 +1893,58 @@ func (siw *ServerInterfaceWrapper) GetInboxItem(w http.ResponseWriter, r *http.R
handler.ServeHTTP(w, r)
}
// GetRunBundle operation middleware
func (siw *ServerInterfaceWrapper) GetRunBundle(w http.ResponseWriter, r *http.Request) {
var err error
_ = err
// ------------- Path parameter "itemId" -------------
var itemId string
err = runtime.BindStyledParameterWithOptions("simple", "itemId", r.PathValue("itemId"), &itemId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true})
if err != nil {
siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "itemId", Err: err})
return
}
handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
siw.Handler.GetRunBundle(w, r, itemId)
}))
for _, middleware := range siw.HandlerMiddlewares {
handler = middleware(handler)
}
handler.ServeHTTP(w, r)
}
// ReportRun operation middleware
func (siw *ServerInterfaceWrapper) ReportRun(w http.ResponseWriter, r *http.Request) {
var err error
_ = err
// ------------- Path parameter "itemId" -------------
var itemId string
err = runtime.BindStyledParameterWithOptions("simple", "itemId", r.PathValue("itemId"), &itemId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true})
if err != nil {
siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "itemId", Err: err})
return
}
handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
siw.Handler.ReportRun(w, r, itemId)
}))
for _, middleware := range siw.HandlerMiddlewares {
handler = middleware(handler)
}
handler.ServeHTTP(w, r)
}
// GetMe operation middleware
func (siw *ServerInterfaceWrapper) GetMe(w http.ResponseWriter, r *http.Request) {
@@ -3469,6 +3554,8 @@ func HandlerWithOptions(si ServerInterface, options StdHTTPServerOptions) http.H
m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/api/blobs/{blobId}", wrapper.GetBlob)
m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/api/inbox", wrapper.ListInbox)
m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/api/inbox/{itemId}", wrapper.GetInboxItem)
m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/api/inbox/{itemId}/bundle", wrapper.GetRunBundle)
m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/api/inbox/{itemId}/runs", wrapper.ReportRun)
m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/api/inbox/responses", wrapper.RespondInbox)
m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/api/events", wrapper.StreamEvents)
m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/api/admin/status", wrapper.GetStatus)
@@ -3485,228 +3572,234 @@ func HandlerWithOptions(si ServerInterface, options StdHTTPServerOptions) http.H
// const string: with thousands of chunks the chained `+` fold is several
// times slower for the Go compiler than parsing a slice literal.
var swaggerSpec = []string{
"7H1/cxu3kuBXQfGuStbuiLLfy97dSnV/6NlO4r048VnKufbeS2lBDkjiaQiMAYwoxuXvfoXuBgYzxJAj",
"2bL9NvdPIg9ngEaj0ejf/WEy1+taK6GcnZx9mBhha62sgH+8NEYb/8dcKyeU83/yuq7knDup1enfrVb+",
"mZ2vxJr7v/6rEYvJ2eS/nLajnuKv9hRH+/jxYzEphZ0bWftBJmc4zXTif6B3/VAXS6HcG6PnwsK/a6Nr",
"YZxE0FaCV27l/+qOZV0zv2FrwZVlnLnGKCYtM41SUi0ZVyVTmllnBF8zcSuUYytuGTdG3oqSLbRhMMI1",
"Xzhhrq2Ya1XacybupBMljetWgtUImB98qZWYToqJUM16cvbXib6ZFAiHfwgfTn4rJm5bCwDQSLWcFJO7",
"E//ByS03iq/9ov46+REW9Yv/Dv+8pFHwXy9prI/FpOLWXQP819ztYuHdSqgOmP59tjHaCcZZJZVgTjPp",
"LKFiUkwW2qz9UJOSO3Hi5FpMiok2bOOHko5Zx40T5XRyppqq6i/nYzGpZekBoedSObEUxv9ghbVSq+vO",
"7+131nEngLIs04rBtl/iJ3Gy7uquVoLRoEd+Bf77DECO25uhSW+FKpG0ez99LCZGvG+kEaXfkQT2dsD4",
"OS46LKG/K0Ug0nbz9ezvYu48AOkyd6l7bgR3oqS9zW7NzpLCN7NtdsULbW7iiD1qkW7F6PeF0eszIB1c",
"45FlsmR6AY+AitzKnyT/T/8JuxGitgXjbC2s5Ut4yp5XvCkFe65LUYRjCM91Ke6mOeiT6XcBvICpjixb",
"SGOJFJkRtlkLfxqlJWADVRRs3jjGHYuLLlijSmEYZ0ps6O3rdnPPGZ9Zzww8kNqtRBzKZqEdoKq1LkW1",
"C/5b8b4RFviHf+GciXXttgkziaguxYI3lZuyizA/06raMruRbr4Sls2E2wg4kJbpjWq/hJHzwOqNEmYX",
"Kn+KKr2Uim1W2gpWCV4y7skSUSptANQjhTNP/f64haOZmcnoSuxOZMStFBthzhhn+Hc7DHtihWBv4enx",
"+c4sllXSOg/aLey0sILpxqXcVq7rSqyFcsKfR7+ISRGn3OW7KcOJQ5SVP1F0SUwKuBIrMZ5vp4f50o/+",
"Ckfcef42TrHz0/N2Tg9jM4OtsLvo/FFv2JqrbTiU8J5HWfiEcSPCjVewGZ/fLI1uVMm0EpZJNa+aUpQM",
"bjgYAY6nW/HI5P3TNVyMQpWe5xcZtp6w1951nhANENU+kmkZcXeQ73VV6Y1lniEAkEDg8FcgnQ23jJge",
"20i3OmPL2p38Ex0FjwF/nwDLKfxdb7Z0tHEo/1vLplKSmsNjoINS3GVpaIeD7K4gGTyhd1kWbO7Pm2Kz",
"LZttjThnGrcBIGVuZTzO/Ht4+hrlZGfhkQ/CvsGWWWAI+GkGzb1LrXeZIX9ILjVkY7lFtlcdHPXOpVOk",
"t1ZKwdnrzzk+X61JpuxdfpxQmOGwQpXXXnzJSxpyzZcZBgSPz1jJHWe/vv0pS4c3UpUpT1hIWF8pF4tJ",
"GNj/ky8NiEsefX6Vitd2pf2CG1NlSWUtzJrnCIQGO2Ov8Q1mdWPmIgtezXPCrgfyjBlR6xMjKu7krWD+",
"zSmjJXOFfzH/JpMoExKL3Whz44zwF/TM6qpxwhNiHAfkwzyX9yL+7mIWizO2lA5YPJC64WqZX03A2h6R",
"0Lg9+7xPsvPbcFCsg93O0eVfKj3LUCSqP9f4+odh2eszymvZ5eUOcge44ROZW+0LaV4qZ7a7K5ZLpWGS",
"/j77HcYfUXQR/vszNl1Kh49Bx/K/IK8Vd3DdAAFatuZuvvLaBFwOpTRi7rTZMj7Tt6JLbzOtK8GVB9Pf",
"s3k6kb+LoVMByo38Hah+tnUCZKO4M1K5//Zd9lqz23Ul1U0yXwJJIIC+tsVdiwwmbcEWcH2BysloxHjD",
"bm04ieEIThFZZ/2XW7knvuoxV2vpr3mlNythREHIFLdyLgpm9fxGAIJrWXeutVJ65k6MDSYcKd4EMrna",
"1uIFDJI++R4HTB/9goP3yRX2kWZsEU3bWESaG6DUn6R1HsQdWvVYD2TrxNoeskNEqo8bOuHG8O0wn/Wi",
"ciTWosMjO3tjtHap0Ox/9M+yTNCZRs396TwwH8hha3+yaKGeNhTbCC/lCS8DdCS0SK095MPKioisdP4c",
"wqPpp4trUvIOs6bwYnbs2+y9z/1ys+ccBInrA3aEh/DgcOuP1Zku/clSQa4Nkjdo/BYYH2eNFV4fW+h5",
"Y6dN7acvUaFGZcutxJbNRKW9Eq2n7Bev38Fp918y6UVFUMHEekAS2Faap1C3iK2N9n8OXqvifQc1w0xw",
"+ILdsY+8nxAaC9rAFsSD9w8Qwhuip96hvg3az6gzjSSVOdD+4GTtY3A7+f8I0JcEN5X09xXuJRwxUINr",
"3hFiho4XwUsT5hbr+eTzlZeJMqRfltKDZvPyzkwqbrb5K6kUldjzqa7K6zxTM8LzY6JN/wqbiYVnM8C1",
"4Me9omhWr25sKkTzshQlKhRyIeFPAFegjg7z0xTXc0BNRuMeYGQ0W5HgLkVGRNrgVrQm7e5etMjeZcoo",
"Rlt15NivV9+f/A/mxJ07h//6kwucPy/DDGONZJgxp1LcuewYe64SAG2lq9KiJQn0SLCfkfnAL2n89UFX",
"NeEonZnAG0L3C69I7eC69vJgdkkD+MpDhcPkp1alVMvLYPLpS4p3/gAgw9WpckR2MM0W8m5KAm95xkpp",
"19JaURbA7SuxcEw3EZevhVkKtuFGSbVMRS+YKCvi7JO7CPjv6WP656swRm95v8Jds4vjaO7axz87eNph",
"8vA0i15/y2W2tXMPJaZVBa6SQaM+fYccSC5XjtVcCWZXemPP0+0JL4Jzgi4rvDpd3hMwO4SAK25vrviM",
"3rb54+9/wavcX/9149AQU3h5XptSmCm7ipqPBwu/QGUgXumjLrQUnt6VNmh4uyIEDeBvZx8OcVpABGIv",
"t/mv1EzfvXJinbnPHktgGxiqb70Be7tHSut9EiDQFhPDnbiu5DrvlusKWF30hkHPGKjcd449ec3NTak3",
"CuyPgPb5Sss5mFnBy8Yt+48T9oQdwx3xH+wU/vlP4Z+1nN+caAVa3X+csL+y39L3/nr3W/oeV1s0hwMB",
"HRcsAFSwzWp7Pau85lcWTAPAlj0RfL4igI4sjNRS6nHB1k3lZF0J9sSZBv02YZ5jr+TM9XoN9l/2BAyw",
"3NyIMizwCMY7LhiPljw7ZR1knzH435SlKD8jl0WRPMXxoyvD/3CCP+Alf1zQSH9Tk+LeUq8RVle396Sz",
"+NGAdabjJh91oOG0vKXPcsd6FJ+GUYhL77eDoTH4erQZKcFiahzeOcnpyFHybyX+YB/u2IJbbA3yEcRM",
"uctKPhHTzwEO0ASkeoWfP+sjv4eP0eDanCjfnofRECfW8AxhPIRPlqKSt8J8Hu4KJuTMlfiXSs+YLG1H",
"gELJiVs0PFvGvaZrZRn0CsRb5x7cpd0eBvybQ3RO3K6D64MDDkvSZOAbTV9X/oOPxcQr7yNPWlgNfRQN",
"YoTmokNCB3XoHLV/AaIcogmQfcAkiRuD5pJ4f7V36CwQD3j4mtrzD09QxbdCTb111Qg23fFWqHDPnjNx",
"x+eu2jJ/kaPbM97r7RVNtzwY8pKXUqTcbxmBhjP4RzBBRNlBphcW5HzF1nzLZoKMlRjkQyg2gi3lrVDT",
"Q1uIP/MqmQn2J5WGhJdJAqrydtCHHbn+yYqHCsY7eFKuaNYYtFWTvIiG8WJCql5WRExu4c4Qwg/Ald14",
"ztuOAX/bphbGinJA6vxJ8PJnnTu7n1FM7kpK+/UvBbFidV2BxVl31AeOv4LVsn2FfOw0SH6vh/guGUrv",
"scisT9sP35M9kpFzRPEa7dRDjPPg1fcJ3MtDe78jPxBf9BriGdDhIC2GBYB5gjthIOpjyt5RGF8pFwth",
"kriKNqgARi86IRZJ3FE0DYY4L7JU793nHpyHWc5hnXTIyPSzdnJBgalvjFjYnNXXMz4lNkz6A4x6FGBq",
"IZW0K1EC7qynbrnYIjbRKg92e+kvNQjcMALswsDQenZrr6hk5u5oRjhz3lAY2GtmjP8dfpqyXyB8JISL",
"ZQdq9avMUKlKtg8aI2ptcgNcgZ0BsAVsQCgMwmGc2Wa95mbLnvifp6hBwk/0wxnz+ubxCKNji4sWkiKg",
"uLvCHEm84UoMWKhKwxfBm9hbmNeFNytZCcbxYgNSUX2jCtpUG4XnnY7yLgLBD5T18bXzAKuo6yPLNlKV",
"egMeP/gwOtNpGCYw1s0fPqlaOSiCNQKpAaKiRUIeecbJuax5zkZeSltXfHs96JlfSnct1lxWg7+GT3Ox",
"Y5sQvgyHb8XB4G6FYxwiTGQplJNue47ONOffXgrHlGbOcFkJk2VK4H87LKPja0V3jQnM6eKyiMPgw89z",
"kQ8i2B+GXKCsf94L9AHDkL+YzK0oGXds5Vxtz05P/9Y8ffrnuedmR5attHXwQJzhcz8SPjidfpqTsLUm",
"EAIB+IOazRsUJL5IdDRx0uuZ4WrAIzEgUw3ukBFrkucyP9X6epyHI0Vb+9kOwHG6+wUAEYqHpJ89axu9",
"gB3YB+Bweq6rgaiDe1nuOBy9eeNCigMGS37H/pf8yx7fQzDXGjEX8jb6JXvL5nYgMPFQkkM2UinMe2TZ",
"oqkqVgm1dKtOxNLusRubuhDDOTvGO7LHwToQWQTcwW2xubi4hiwKwQnLqzedN3bB7wVUYCaORwJ6VnjJ",
"ay+1znVTlZ7t19xY0JxLCf82Yq6XSlrBrFRzgcIYxS0X7EZsRelFI1z9NGcv9jusXH431trCFP6O9YJz",
"4cVFYcnRM9p706XnjwfsjYTGCFluK97GS6XH8RVpGW2+QJJSsOvSLLWA27SxoqBofKmWYJ0IUZlHlqEz",
"fle6zfl1dpEYou/bsOfzVOi3N7KuRTndx6bvc+JFYBo9566XBMoztllt8xkn6PK8Bov1XiIe7zgtMrH6",
"fgtWzZorxsvSCAtiHJ+vGAGQEK3nVlKVAuRNI6yX7ekte854+MLrJ+AJEuD09DpJltCDVvM5TAcDqufL",
"cduKa8lEDWslzsiU19JMM1tLd41PGDfLBgyXZ61iEdxux0F5AwwViFZUNcStMNJtCzbnTiwhbM9JV4mC",
"lcJxWRUY8gJqsuzIzS3+YpiyGkhsy0cVECJwXcmhsk7UdLIgCxFCYgtmtf9HWD8zXKWRA21SisfVpCCy",
"9lwbpxkZS4D8o5eEkjx8gaMnT74PEyXPLsOco9PrHkAu+7MVkk3Jeqd2shiCRyo4gDvWoR4TyHFeStL5",
"Ghai2uh1/VAbUc76t67diKAafC+Li5Du8ECPv177k21XPKe64K8QS2OE8G9RZlrNDem8abTtkWU/vrx4",
"ERNUN9wyx2+E+nwXyy2u6f1wqMWRBSubdZRMHDXXQKYAFoknZJY3IlgPMMTburgu1tRt4sWIiLAhnWQX",
"4Dfawt3W0w0DmLZAOn12Ttx4AWnTYmFPvYB16l+3px/oGH489d+dflAf76sZFpOwtwM/yuUyF3jrGqOu",
"hSrPKG2NlFahyhO9OAGLJ5LPlJmQbXnWphPiMSN5CGN37Q3le3vSAX8FvxHXAR/TaOZ80h5TzJ8GmxBC",
"kfp0nNYVm/OqsscF/OPa/6PwE13T9a9K5knNMF7XghsMyNOq3QSkXy8JhHDUWSOr0qYXQgisLiJO/J9h",
"Ps8Tw4T+uZ9ugscbcDLytgjn/Ar343Wcs/fDVWPUS4Cg/4PW1XOEp/fLhb35kaDrf0PA9h6/bWE/cDVk",
"bgM16XCdhPzS490S3kGN+dJlw5WBHvJswjrg7MjKdOPqxlHSMvzClsKfvtmWeeyfx1R7y7RXb3hVUXTh",
"mq34rYim6im7QIdMWpNA3ErdhIHppEPI0JOQjhAzqJeigDCw4246cjt99BDMjBQLjL0Zfw3NuM3HXZMX",
"ASA4shivhkYMgXNOA7+Hk0d2jmPyvOIVAdnPXl2HU4irjSZ87sD9jH4q/A3Ot19swTYRAs9vF5XepBya",
"AFhzSa5ecma1qdkE65S9FQuwyIJzNJkGmcGKqz6EwfHKqw3f2u6aWbLUMAMgPJx6RImXarhUYw+xn/Uv",
"3Io34eP45DWMMizWR7qNOQ7kHApLsBocwph3iiLXJ6ffDprWurD9oshYoxfsmb8tnz196sVqw+dOGFuw",
"Rsn3De5Gkmfltzofzx7FokM4kMo608yHXNl5w1cQQ/dJVX6WC+cEwdE3sniaH6jagPykczji6UqPRHbl",
"pbRzbspoFe1ndNKvcHHNK8GVKK+b2mvUmrW/SneORpjAYuDVpt43ZdbzEpIyOHuBb3VOZvCEAMPAEPx5",
"pf0J3IpB38uemhJJsKz0khhgH2bEz+BcdrzeKdtCNkpf5UtEKM/o8/PSd/1Loa2yApNjzEjtMdJyETAD",
"eElxxfHwYdLwkR1tmwJqe+Why/FthGUo+8HT0zUSF77YIsUSlNL5Gy0iDrPXpQvEmI8BGdCkSfnFZE6U",
"waRla1mCxDdlsqzEGeNzJ29FkThyCURyHKFSEE9D+wFcI7gMI+baU7OX+8zS/z8S+FlC6+QGx6GkWk47",
"5yI5MYCK+JqXAvGMlBpDJUDIbtSRTYLFbas9LKTiVfcU2+6F0NoFqHpFWN4EMs6XIf4EAfJyTQR0bFEL",
"JNJ+3YrkaahykTz6voUiffw6QJQ+fJFAlz5/jpD+Wh80M4BF5z7+J/ygtQkk7Cie2EEOjWcml1+xzHtJ",
"xmfROZLo6YMBEFzOk43EfA0ElDdToVhMlaBypoqXcDnj+QoFo4BavcZt+PwGSNjTWVuXJZQRGc12OuW8",
"MoynnF2D02NkLlRSaml8WmPlMTVUV+UiXb+wbN4YLzZV21BLJa/rkoQ4gPuaHAHXbVzIaL+BzURxHPCz",
"tOSScTShnWInuh6tpuQvwCiL0Z4URMw1xIFk7gwIDwm115TeFExXpQciOCvu51Xx470Vi2zwvBXX80qG",
"nc3aas197T+ZSnD5cjwQ9MjjSsEcseZbttQgherGgY6QFJ2ji0Q6hs4fBpJOM7/JE9nvej2TuaN7Gc4j",
"ZWcEEEjjYRWUBEGaxhuS98gcDroXJpRutwX3e9Sm/F8A7aCPK8F/ctZ3znFynooua+vucfcs9ymxe2x2",
"OWCL0Pwm757bLEdGd8RbwTNpC4NWQyveh3TBJD4qWA+9OBjcHCD9rvRGjTIGZhKzc0BfcXuTyXnlVlxT",
"XZedY7AnJgIl8P0lCEHI9mtBsQRduXTzT4cKD2ZMx1XOofCKvGUkUv36KpgUal4J57xUaK1cKgx8AdsO",
"hC5z5gdsjKd6JDP8DOyyGAPphW8ISoQMT3/EPefiS50/oo8RlPI4yhLVRiEqCyUyN1w6zzli3YqEmRVt",
"OTG/e2DY6M7AZsK/bMRa3+bLUTygAqEKByUa02VHQ+uotclW3EPv80vZp/Ml0vm9CgF6UiemYgY89+0O",
"UtowRE8mn+zbFXoj1mWEqz2iCfKWvSCe3wiEbsiugMeUvJfvG25X0TOjMnaqjmsf6yls4DahOpEaz30W",
"ewjI+0Y0+5hIyKq2rWk/BGiqJNVWqtRiFzmOVMu4o2BRxRhmP2Sws1KRU+WJQVq2EtU9GBOuIWoiGWLz",
"P0VK7iAUV7bmN8KetacJP2jLvoX4DigxggsmH7e7TmYfxPAB/tGiN+UepDu3SjMUmOuW0y2CRwWe40Xm",
"vw26Ay4WXqwb+INMSdqGEqJ+wcNE6m90z9uvyfy5ZxW4o4BlCSEERBMUA0Ym5S4RBR5GP9KS6ZqSbtiw",
"hB9cH07ExgsdNzCUKox8JxhwENZ7sR0vpF/nTexX0cgfpIwkCtQ/gzBq9iQO4Y9o/Mc//+txwWoOQSqE",
"OnJRe1wJswbDBLfszS9vr/YqRAfL/Q7U0AoXSqkpNqZ2XgtBOxPIzORg5WvhtVNlOVhkPVBoZcYQCwSf",
"PUEf4BSmJTFrzg3UUaL8aP/28VlOPEGGgTdnwURlBWvv5CKwlyIYwRwQYMRZ6xsGKTyWrURGyR1dzF6v",
"TkOxQuw5sXjTKBt+vq4FBgCFMrBYWhcdobBFQFBtyAmNAQcbwrwMXdQUfVHQ7FASAKXp6T4jUxeM+AD/",
"DrymZ1bJWqPCbCNtUV5q7Rmi4iOyQrWvAEhvIoi9H3oPX0eg46MXKfSdFwH0/nvdhz/rC1xXviAOiJp5",
"pNwPE429CGO1j3ZgbGwLJJaVBaHvepR20glv2NVVdjI6ztnTGIyBCiXGVY2pbDNgyCsmTpf6WlKRiQOX",
"69UvL36ZrjGfpat6pGb1ezHa4DnKz+53JUwe3Ylx4oXRv4tU7WBPlsL5rXkX3g1G/Lmut8e9FDsEnswH",
"+XodLXzXplEDYnV4BSUMWRKXhOH1Am4i8NX1lmFX3Ij9SLmOps+D06aYQrM2pqp5IDyHG5wH/PX3CJXv",
"ljEgc28qo0V9tj9+0WrB6QUbVM+k4tSeordkV97DCvsyTVZZ6J7UIT0eq4nZvDqfp9ggyRsMQ5rrtQcj",
"1E+OovEJCAYJIyBhP4pMXR2gwFjsKA+2gQjtVQR1LvNxuNU9ijskVdRyOdFG5BYOdTMX3VqN/uQt8Cyg",
"pgIFFYE2y7iQw/D3aJBIBuAISxvcvoGIwj0++Y43Hpkt+pWhD8VABuWwi/sSFaCdIHHK35Y2yKgoUFLo",
"UdERwUicnrKfNX2419s+zOnHsVrOLL/1BBvZrQb2JZV1gkOnAmS3FNQeuShYevzqzlDu60SGpB5Wy2Zi",
"rtfCxiL7fgwKHy7Z3yaYHgX/pIQpho/gc3z0t0nRZsHjJcVt4vXDmBp2lRQxCPGNifDulQe8m9LKN0Ne",
"LsDsELFdYQmsIIiA4Awo9iyM+Egg2GISJH3wis30XZT07CTZqMhtR8sus6t03is+ex6nvuKz72l2/14L",
"wBWfvSIYrvjsbQTjis/etZBc8VnIF/uNlvxuL0FFAuLpbZ0GkxJnL/AQYHzpCk9YLxtSeDU51CzfnSoA",
"8iK+54f894vXP03vkfOXDy9J5s5uPeHxkvKP+qElFXIcqeTaE8aznHBm9ObgWzsZLRVY4f2XWbB0qTM1",
"P++kdXZvtc7exYPNe6LgxzE0rFdyN1Hc4xUzzt+kSw31zQ45NwjwMP7QivO10ma63FL7m91yYn7AI0wK",
"UQ6FyGhjHUxlo48WjQG0QXJV1r8l5sNEC2GudGkq4WVBx1aCg/qJ5boDfBkLoLRDJeaSG2AYcOCAHuwi",
"CsB+XyGSERxdVOEkYIfygacjeWSBOG8RMLRhcD9ms5/njc05PEWVmuzazJ8Nh6KyGDbVWBuh91fpfMWj",
"Q5ArkkakhdjfAToeDvIfa4hEHUmjZjT9lMuFnLIZD9jeXIDH786Ug/ZXRZr3QJhdZlOf4w/B+p1Kw1gA",
"xQh1NGAcz1vIDpTsjQJxryMKVNCHKbGIR9IbBYyfQfbsDlhMGoVrc1C9D+7bJHwDuAjEq1mPjEGoklEy",
"2QXcrSxyrfxs3XL3kxEXyJp8t0EkSeDr1vlNActuOVXmerQKBqMLDRQTlRQpua5DlZJ9d9BuWZNPqVeQ",
"hWAIaUMFZR+MmR7goysq7MpPufShINDBBVLFcGvMtEn0vBndJn5qcoWC2E/pg16Z4F3Zv/UbkYIAYRvr",
"GPLYi8u/DPbyUJ0/Snsgxfdlx2QVHzJS9FKf+Icn9kbWJ6Hi1gm0gPB07Uwj0NS4vIcWjVkM9yqKSDPs",
"25+3TaaVHWg6QzUXku3cB26GAJL01v0CYyaUsgy0IVQZlbJ7th4he1vOvZFNB3wVrwdawZGlksFjA20S",
"LMft27F/jAuIDDUZGpUYyXCjOtvSiSodRwAPzo/pnqlEe+6gjK5XS2XHyvvlRoa462GPHV2whqvEVPkk",
"quUUZKzNjUVXz3EMabtfKFsn5D8D6XDLm7z7jOIEzqAGjmdZW+GmDPqwbKQVux4qMusnKQIAC1Zu7LwS",
"Q+OjjxzKEwV214lKJjA6zfQeKz4ZUAg+l3dx1vZZ6yhqn5GnqH2QRCu3D6MTpX2Uenrap904ZVr69ZA+",
"1bEwBbNTH/3B5TyWpPPnGg9ba41OQEvOwL6DTKFtGbFp33V1f9tFO1gOGgotzADhhqSPfiHwEBdIamSI",
"AcRr2P8VfyFdIl8S/IGtbUcHgFMZZVrYLi4+goC+AJsJ8fjJbGsEKDsGe8hOnk6fTp9iEVOheC0nZ5M/",
"T59O/4wNElaAulNey1NerqU6bb2TSwFKrkcxyIWvysnZ5AfhLoPDo1OD+U9Pn362ltA0Q6Yn9KUwt160",
"gg66wHUbC51YPsLLsI5ZpbFSf61t1roNXcraHnjasMZCAEHsVosm2Jkut8H8avgG3z/HkJdtDeaMUjgx",
"Dy5ETIvcOoEF2taN9Qo8e/PzDwX7tzcvfyjYD6++95z0nZi9mbILh3Vl/oW9ln9BhtnF9a+xOkCbq/sX",
"MgsleAawTpdy0UVw9K+2XTl2iA0//Xstlg/9tlYP/nQjZvV9v+0cEBJye2T47LORIWA+Q4RXIeikhHLF",
"U3+4vkPyzw0X4TuNdX++e/bn0W/3CPv0g//fq/LjviMaaWbvAf2DEc7uJnpMHlk8siRaotsdUASHnDb3",
"u3tsFwSC8bVwwniJ5MPEa/2hJw3ehBPcw0mfmotkTf0V/BbIoO2BRdufY5EnEDKAr07ZS6/Cwj+wcbek",
"GDPx/hz7nxKXg35ZXi/9t8tffp7iP4M6+xO37gSenLx6wZ6QKxR/e99Aid+w7GPsNSzqim/b9DgIdwoQ",
"vcPaCnARFqEHEXfB4Rh6pxkBdVHOcXMqwcv/CXhquxbRm2S/nPOqgmpBbSe2uAyMpFUMmrixpaYxdNtm",
"LceEsRTZy9DHK7e1K8FLkKxoczuYmhQ5Oh0O16cxAaPtkFF2+/Shkpo5g7Q28Cm10d75rq0p+ttBpuPE",
"nUMSPsHUl+5JPnhukUTx0wccznCI0H85dIZetYWAe5oc+15WfveZ4sZQWA9VdDdATDwpDpA2SL+VYpOj",
"r5+kdcGRmSOu3hZ0AlnuvYGfsPdBaxh3daYNSUYQxf47enx7jwG33A4RveZujv4UqPUcjArSRLe7nbIX",
"wajgNBZ4poLIfSo67SwuL3ReQPV32ykNg3NLrAgB1c2wHzoLLxuwPHbqQflXQwkaMD9KLPpbVph7AYo4",
"KeqxTDKw0UaFCvQ5KqQ+K6+iV39I2Hy4NNXp5zJKkvvaVOJFBKoTH/f+3pLePbiTf/tfH8rLTj94EA/I",
"he3yH1F7S3Ccxyk4GaO01Z64xxG1EC0PE7XQajGEzdfiMdEIDqoBDHoxx7MvEFoIEU0GSPTVEJyf/0gn",
"7qBHONAPRU44soSc+53Y9lStxekiVIkfogAsI/+I68QJMguNiREpKRzZnf5+XerojvEWqlvYJCABGzuE",
"LJx2rLa3YkGuL8Mcn013peUUJ5+f4BJ0fDlaG9yDxA6AfZ0f93rokKYXxQ9pgle75AFqEX7WFWwLL7hy",
"zJXarHSF2VuQfwa5SqDmhaQu+8/PjrzE1Ab/J41A6E8r3oOSmPyyWxIx5LtbinE/nrI3HGIW5jdstoWU",
"o0CNGP4TlFg/PA8NSIbk6p8EL/dqbj0ZF0f7TGoWpZy3Q635HQbK/cvTp8X+sLnfHpGc2+7aGZL+FQpN",
"UgMP+O+TELryL0+PC1ZX0H2C8oOtk1XVFhfI7eg0R7ckwe4z0oIPNtpjQ22cHDVT+6qYzERd2Ht5VWn4",
"GXsX+2vAq0nxoH4rm5WoMIPKhoKszjIl7ijzJUN3VBTxJ1SVH4MJdnsTjWKGf/psk0MaE5WXGOKJHfyn",
"CN1QiVttIm6hpsSn3NFAUEpTiZgsHxy6K1vyocQkyP6c6caxFar2Wwgf6ZsA4hpvhKgtFmFMxNm1WM+E",
"CS7hpXBQ99NOB1nUzxqLXjy++hPbiY3UfgCv00GMn37w/yOdA1u474pJL+B5nHlnmd/tbhh+Uj6SQoAw",
"P1QhwOWHgkf3vns7Vfl3jEsXmHqDmav+T48HSgv2TKhNzFDUWihPUaH+yxchqi5LGEdYAQF92krj0PB6",
"aLK3AxTJy7Xtij26uujf26orpzPtBtg9DjPPBfL9J9SkvBJxEtWpvdrIJonSQq1EWmDDYK/rN9zC0Jvk",
"my3G3SUduPD2T279LRjEkiGlK5IS0JiWzxVb61swsIGfgGaec0spQBbuCK0rhuuY5YjpUri23djjUFA7",
"/ijK+W4I85HfPnCLKTXxxAhe7o8faAskfTKDGip8Nia5eDeWohdZrQ3GfqaVgHYYywpqR3i6IZmYCujo",
"BdLUSi5XWNvsPbzX4XhplbgsujxDf9OWvnp8Zh6ypUbw8YuqClaBaGYgYb67CJRUw8iPdAo6Lau+cKBA",
"RNqAFCU2bfvTBx+xgOrTD/TXAVtviu9HujsOrLu75s8txkUsPEySy6HzNJbLHDyMV1R17vFPIpRkGylO",
"tS5HWEG/PdW3hP9iQOPHk9vJOk6Sy2N+doyzGirBTgKBV8coB5qk5liABYJZOynJRXiHtzUPuGtzQWFS",
"6XLqPoINe/U4jC1JCf/CXA0JcJilYZGmL2TyzB9Xyhcd1MBQJ9CLNBUU5EetYxbjMCFJBSkjbUD+Do+F",
"hNVHZLAw/h4vGnSZl9ZTt2ULXlnRFovOpMQqHRDxj8STdalbxvzV+FLIB4eYjrSkTEFVwoOdGrybZCmM",
"ZWqKVH9vy2d1EnpDKYBOVYW2o0S3tl2nOiV9CIUX/Ej5OCZuXEw3fiReFZNj/3is6qHOeyqgcPoB//AU",
"HzrXnX6Arn8fx9F9+P5eZF8MFPT38x9ZVvfaQ+EckEoXmuvB3fgUshMyvncP/xiAOq6PA85K7rLNE9s+",
"iFAPBMqRIrzQRsdSjTTZa7IGRTHvoATalsml0gbfyvs207aOj+TiTKb4Or516ik6cJwQpV/s3s8cD+t0",
"/YhHYvAmeIkuqW6t1VhNjyz+JvGph1aV/mqWlShbXt6oStjOS235zAzhOV2/DRWgvoVtf3yuGOzDpx/o",
"rwPKbjA/PyJ+xni+CNhHkq4iKh4mXeVwekr+hnHn6YEADB2oC0ysFJ0eErHaFEpaK65KvViwJ0vNq4KV",
"Yi7JcwIBqf4JLyFjt0DTfox6LLCT6vGUvYulNUNFWqrlHXyU0kZnC3p7OUgNvd7JWFrUC1yQ3QO1tkii",
"i3JcADdXICurPiL6B8n3yzpuA/SApqRA4lc99qeQ0m6a+usQ6cuQDE6NP9Dxv7ORrwKQ38hWRqTBPpai",
"krcQ+/tVd7IT9/GlN/IymHhAIQAKj/XsYoBC7NPacgbPnILziJTAllXtlL7uxY9gEXOSDDg09kviuakz",
"VogoCa1CwUDFWz/vAMldClW2LTj/kJEmgP7VDqP61nS8pE3uATkmGhIfy6C0R1FOlOTPLbngyh8mtnSR",
"dzpvq5tmzX4v25Iu3Z7G0YT8JBYGKmJhz0bhX5hSrKC9lX/u1yvmEFc2XUoH+qE4ZlBezg9WdGul3qNU",
"6rDZMVinoXgqsiSs4cmuun2u9UZBCbg7jGzzHKSZQ60ZyK4LVUqLtr+0JP05KWBKFTIPLwQzI6FO7FC5",
"1wD5vmKv1ObdiRr7iDVZuYiOQlsHskdjA03CnQ7LoICstvxnd0EFs43fDL+PEN0QeHaIL10JXmLxUl5V",
"ehPQEhtBB3tHP0vK79nkXhaXixRD6oziCgLVtEUmperuHTOcYh546Oh72y2mlQUwtGrfa4QpsrWbw7dn",
"XSRndxuro8R/4f4cxY4L3b7DWonjQYCdqD815/ATvS9EhBm2+UaYE3AReGXkW0sP+tKMWZ/wxq2ond2g",
"SwbMdrG/ZaBdzNulFN1WgOow8LY4LXsCwT1JG4q2CLE2bMVLKO8AYWGY9dZKwKxRJUYKSQPFvo7B0QM+",
"HuIT0vRt8Behlt42hdZzZWoXAQ2DEPildLH0JOPseUCLKE/854bLKp9p/INwz/UFofCLxHpw4+Rc1ly5",
"sY7mdpO/fUmhlIvFXlJslFxIUULdxFDzHk5z20cDLj+47qLzedm5mqZDV9cLP/u4rAMs0Hgvo3024wCr",
"i3/yOLQhnzyOrspQQn+vuvZ4iTuyErANQ1ET3M1Xf2ymXUozeER+UYKV0oi50xDPlhOmi/iGFDZkEjlI",
"BNkCd52yl8rBj/5fJUjREH5ZiYVjunHnLMrVJRP0LoeGPliLFK1t0MfSM2KPChSEKsFvSZ9uwXEro5vl",
"ik2nmH1vt+tKqpsClHS0vu+RN19Ic0jWvKy4XZ1Y4V9yqCJUHH2xuttKwGjtQhFkD0u3ZXioRr3nBH6d",
"U/NCmp+kdXvKpkSigA5DsGN/9FMEheDGmbUeMu+QTesHeSsyjRr8RVaK0u+/KNFI4jTbGOlEq1lQoGrR",
"9nejTnhU7N72jWCQzgdVslLjeL+1zzGcVx1LDHLLrMbS9v3+kWSJD1XvSCT0P/CSSgWvBVcQ+HDOSqNr",
"zD2DxCEQyM5D9Hffvs9WeiNuse88zoL10W3WIgDd6VA9D4XFqSdLZD7th0mbUnbVDoaOvyLG//oPqTaN",
"EWsuVT+SI+1qFluG8coIXm6pHVecicRaG8I+qDmcPWdaxZ5AkKgJ9RKbmjyOftnIUUFsxd9y/I9KGebN",
"T3/6YuanglIKQyt+XFO528p0+nVMd2MybnsVjMDGy5kV7/vJPpjp2k1yrTiFikMGLKfv84k+Hpn3yW79",
"jDWEoIVyPrn12dNHz24dpdwAZsaoNZjyiq3PadOSnNenx9++ouN1lkGSvGBGLJuKG1Rt8jbRKbsSdw5l",
"JCpO3dRYzcjK3wVi55xhdTX0q9KbnnHTxj26dObl+c8rnh0QwO51Qz+qGvOcBhrgnX5H/tgiGFQGHD4E",
"sdinPwMxhnxHmfHCeey2Al9gKU/8mDvH56s1FrADSsc0d101Dso6DdHaOV0DRlhd3UKjTSR8MO6GOqFS",
"WVmKbkuEXvHQAkqHAkiX/+eHgs39/Qi6lrhzQkHsyfD5ebVGV+GYMmOf/wD8o1abtLfLf75bV1+9WKUn",
"3VCs8kFn/c9/TM4AisKXV80gRzlhMkmzyVjNQquFNGuvovnHZDhJkrwh4ojCVEEtomFOpOq2QJLqVlIf",
"KKchVo+Ku2ML8FwEFFOeDKtqW2A2NHblHlCQoGG21yqDnw2b3rWt7HbXqNWhNB2yiveM6mRFz5vNgUGj",
"wb1jjmrN0thTHBsHQKUJufTIWnDrThbabHgIzmwBm6/E/MZjElpD0y6k6mJOT8zohVi/PoaK7GlCn2p8",
"baOeUBIjOC2f9PrgQ+904Y7TVAKqvt+OIKH149IIa/uzBq8t4ayn3eeKXOBOSssW8i7UuIZKKm0Xelge",
"tMK2O6kKg43hI7RB3YXe+qEmLJTMQD9hQVGAoXG7Vp5e4WjgkzZLjHAqyp3u7r33ELtnSYv3aDeBzpY3",
"2OOcYHTsCcXwyAUVWwy1Yo6LiNIAHyIintMy1GhMoQy7Eqb+8eXFi5CXJFQZHBEhOym8RtV4Mr1iiS7a",
"TVHHOVtDi7HetkA5FpduRzB+9DA5ZS8l0TTsUSu0900aGVNFCCHQG0U7nba2LZg/LiAZIWFvhTuj+GiI",
"a8LJME89nIx0gM7hWPNSFGhxkjYwlpgWSC2G/RKKNuKLhsl2uY5ubGrM0OnUQHkQXd+8hwYsGUndK6zP",
"2cf+eWIrw10oja7rwF156vZU2iUJQU++e/qvx20oOXeZWPJsgSKz/NSExXzaPSSgFbkWL6GB8c4tCcC0",
"jZS6sfVhM+6xC0nAh+q0mk275CVtn/OtZ+AqbGMW4NUzOJXYfZBT5f7//ic2X3HD516o8BuDUgPa+PGM",
"gOUv2+8Qft8FwH+AwRN0YR6fBYC0IsFh6FKd0kE9C9wrfpDhhOdY16LDYNMu/x4QVBbGN+Qn2vIre42f",
"J0/e0Egf88UXvlxk4T4rJCIusTQWcDnB1WWhlBP+kFTE+yIZMZ/JfoniI8B+kp7JULppN+qnNHxjGWd4",
"Ujd9xo2MJ7I76ikDVIXVsPxL55G7x1t616T5nKu5qGCaCz/B42e87KODcO14StgQGtS3bwoM6sGX13di",
"MkfHExUFqX1sq+VTSaBkkVhLuNqCslTJubMUTL0UCqhHLRn96RmvrLwceklTJ+CkKSZ4mEM4+JAj66A4",
"O3i5vvrq0f+E83waxzfOourQUnyfk6XW2Q714q7WNohO+I9r/2qRhCNwFMOtMLekfHJZ2TkH+jC3opPu",
"4z9mqoGCfnoBmvKRZSttXcH0rTDsx6urN5dFXyFqlRFtEn/hQJnSN20T9S9R4Ify/MZWFkHYvn3WN4Zs",
"oq8WXi1ApKuFSUKl+237dnfr7RfcrLf32qt/mK3KVE/cxfM3X8Oww3kGKjp+O1txKC1KdRcylDxBtXBL",
"NLDhpb6uXTfhMZ+vhGlEaX7c589YotG/TsGcMTdzEjrzj3EdB9Y4irHGl/vWxHDr8mBBJtW+pSvL5CLt",
"x7wRRsT0nBvhScwxIxb21F/COShPP6iP4y7ic4rA24TYnKjNcTd0SV9GPHwJfhRmG11PNUD3D8D8A6h+",
"v04X2tw8mrJS5Ov/3r8gyYHKQKHEDMUr5eqWodEgep6TlB88EEVsT4a9fDq8GHRsT2BSNeSTSAaggqVa",
"3Qpj0QmEWUPWaR1LXnUTc26FKrWhHLIwjd+LY7T8J2zqKOXqoVFcJz8Ci6ODqXhfkBsYx8vYK9mrXgGm",
"YMiLFl5cUxifO9Z2EsjXYftem5vLNrfp/1caOszYk3qtj2ouGFXNJ19TNc3+aYurSmEpPMmK91N2gc0g",
"iEaqpClb8GdEsqLk0WCOOmcc67MaeF2sIeoV8TI1kBWpN6p1UWId5B2dn5ubpKbtY0k2yQxfvNDvQ6v3",
"9EjOCbOWild7gtXeidmlnt8IR9E26IxL6YDGKBhnlV5KxexKVBWWcU5jeZKw5rmurN9DuPHlArukJYYc",
"hrVboLUwcjYUcTeBOsOkRJlzoVy1ZbXxt0RJHmNwbjWubkgYxr71BeNVBZ1KMHYulEDAOeeVRD4PArWi",
"b3uvksHLyt/RtQg1reOPK12V2PbiioC8lL+3Ln9B6BF3MgQV4DrJVQmcd65Lwb57+vRpdGj61xm2go6R",
"24LbveFFYf5xEUZ+T/aykr0hpANxqX6DHz5oP4bpGd4bPX0JWiS1ZNkSbG2003Nd/bED8RpFffwPduPo",
"q5aekulGAJ/zkLW41MKqI5fNvPs1zP6YFfPDHENV8+n3cNtM/5PtcCiLu1chjLVzowS4MPr3mFwCZuk5",
"CNBlkSS5e046ZT9xr42JUpK1H/1TNlUaYexSqyNHaB6QC4k3vQswP7I7Kc4zFMTnkaDiCr59bS1Aemoa",
"td8iH6KO+ptkGpX4dkSl1dIyp89CBQmpsMRkl1BaNQHCvcAQgElJjjsRsmvMNlTl5yAwiHWNzTqLNjaN",
"HltSzvCKTtK2g5zgdbMBCgq7+rZ51Apz6TRDJt5GYS8+wPU3SD5h2/fbdt/Ft76EMSXMRiL0GJsKVJGJ",
"NHyE2avEi+J7rVcplXkjBk4/+N9G9EYaZk57eiMxqESPlI+sVTpoSEUVDOa63j6IPoZKEz2MhW55P3R6",
"VLBzgvmFrMQZHP0AwYuWaXDL/v3i9U9whXCVROhTunEosfVYraT8/z6HPhxsSZBEUFd8noSepiXoER1e",
"9xlGBuRp/tvlLz8HWw6UhbYxfslz6GdefH329GknfimhqKA5I2V1IOnTWIZlvmm61DJGGx5FKF+uCO4O",
"z9jb/rN3n9+rvcfHj/8vAAD//w==",
"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",
}
// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+62
View File
@@ -1,7 +1,12 @@
package server
import (
"errors"
"fmt"
"io/fs"
"log/slog"
"net/http"
"os"
"g.fc.run/misc/byre/internal/api"
"g.fc.run/misc/byre/internal/store"
@@ -36,6 +41,63 @@ func (s *Server) GetInboxItem(w http.ResponseWriter, r *http.Request, itemID str
writeJSON(w, http.StatusOK, item)
}
func (s *Server) GetRunBundle(w http.ResponseWriter, r *http.Request, itemID string) {
item, err := s.store.GetInboxItem(r.Context(), itemID)
if err != nil {
writeStoreError(w, err)
return
}
if item.Kind != api.ClientRun {
writeError(w, http.StatusBadRequest, fmt.Errorf("item %s is a %s, not a client_run", itemID, item.Kind))
return
}
if item.State != api.Open {
writeError(w, http.StatusConflict, fmt.Errorf("run request %s is %s", itemID, item.State))
return
}
f, err := os.Open(s.store.BundlePath(itemID))
if err != nil {
writeError(w, http.StatusInternalServerError, err)
return
}
defer f.Close()
info, err := f.Stat()
if err != nil {
writeError(w, http.StatusInternalServerError, err)
return
}
w.Header().Set("Content-Type", "application/gzip")
http.ServeContent(w, r, "", info.ModTime(), f)
}
func (s *Server) ReportRun(w http.ResponseWriter, r *http.Request, itemID string) {
req := api.RunReport{}
if !readJSON(w, r, &req) {
return
}
item, err := s.agents.ReportRun(r.Context(), actor(r), itemID, req)
if err != nil {
writeAgentError(w, err)
return
}
writeJSON(w, http.StatusOK, item)
}
func (s *Server) removeClosedBundles(events []api.Event) {
for _, ev := range events {
if ev.Kind != "inbox.updated" || ev.Payload["kind"] != string(api.ClientRun) || ev.Payload["state"] == string(api.Open) {
continue
}
id, _ := ev.Payload["id"].(string)
err := os.Remove(s.store.BundlePath(id))
if err != nil && !errors.Is(err, fs.ErrNotExist) {
slog.Error("remove run bundle", "item", id, "err", err)
}
}
}
func (s *Server) RespondInbox(w http.ResponseWriter, r *http.Request) {
req := api.InboxRespond{}
if !readJSON(w, r, &req) {
+1
View File
@@ -81,6 +81,7 @@ func (s *Server) publish(events []api.Event) {
s.hub.publish(ev)
}
s.agents.Observe(events)
s.removeClosedBundles(events)
for _, ev := range events {
if (ev.Kind == "task.merged" || ev.Kind == "task.discarded") && ev.TaskId != nil {
s.terminals.close(*ev.TaskId)
+40 -5
View File
@@ -6,6 +6,7 @@ import (
"encoding/json"
"errors"
"fmt"
"path/filepath"
"strings"
"time"
@@ -14,7 +15,7 @@ import (
func DeliverableResponse(t api.InboxResponseType) bool {
switch t {
case api.Option, api.Other:
case api.Option, api.Other, api.Run:
return true
}
return false
@@ -167,6 +168,31 @@ func (s *Store) Respond(ctx context.Context, actor string, resolutions []Resolut
var ErrNotOpen = errors.New("inbox item is not open")
func (s *Store) AddRunResponse(ctx context.Context, resp api.InboxResponse) (bool, error) {
added := false
err := s.write(ctx, func(tx *sql.Tx, emit emitFunc) error {
res, err := tx.ExecContext(ctx, `
INSERT INTO inbox_responses (id, item_id, user_login, type, text, client, exit_code, images, attachments, created_at)
VALUES (?, ?, ?, ?, ?, ?, ?, '[]', '[]', ?)
ON CONFLICT (id) DO NOTHING
`, resp.Id, resp.ItemId, resp.User, string(api.Run), resp.Text, *resp.Client, *resp.ExitCode, formatTime(resp.CreatedAt))
if err != nil {
return err
}
n, err := res.RowsAffected()
if err != nil || n == 0 {
return err
}
added = true
return emitItem(ctx, tx, emit, "inbox.updated", resp.ItemId, resp.User)
})
return added, err
}
func (s *Store) BundlePath(itemID string) string {
return filepath.Join(s.dataDir(), "bundles", itemID+".tar.gz")
}
func (s *Store) WithdrawItem(ctx context.Context, id string) error {
return s.write(ctx, func(tx *sql.Tx, emit emitFunc) error {
res, err := tx.ExecContext(ctx, `UPDATE inbox_items SET state = ?, resolved_at = ? WHERE id = ? AND state = ?`,
@@ -235,9 +261,9 @@ type Pending struct {
func (s *Store) Undelivered(ctx context.Context, sessionID string) ([]Pending, error) {
rows, err := s.db.QueryContext(ctx, `
SELECT r.id, r.item_id FROM inbox_responses r JOIN inbox_items i ON i.id = r.item_id
WHERE i.agent_session_id = ? AND r.delivered_at IS NULL AND r.type IN (?, ?)
WHERE i.agent_session_id = ? AND r.delivered_at IS NULL AND r.type IN (?, ?, ?)
ORDER BY r.created_at
`, sessionID, string(api.Option), string(api.Other))
`, sessionID, string(api.Option), string(api.Other), string(api.Run))
if err != nil {
return nil, err
}
@@ -347,7 +373,7 @@ func getItem(ctx context.Context, q querier, id string) (api.InboxItem, error) {
func getResponses(ctx context.Context, q querier, itemID string) ([]api.InboxResponse, error) {
rows, err := q.QueryContext(ctx, `
SELECT id, item_id, user_login, type, options, text, images, attachments, created_at, delivered_at
SELECT id, item_id, user_login, type, options, text, client, exit_code, images, attachments, created_at, delivered_at
FROM inbox_responses WHERE item_id = ? ORDER BY created_at
`, itemID)
if err != nil {
@@ -361,15 +387,24 @@ func getResponses(ctx context.Context, q querier, itemID string) ([]api.InboxRes
typ := ""
options := sql.NullString{}
text := sql.NullString{}
client := ""
exitCode := sql.NullInt64{}
images := ""
attachments := ""
createdAt := ""
delivered := sql.NullString{}
err = rows.Scan(&r.Id, &r.ItemId, &r.User, &typ, &options, &text, &images, &attachments, &createdAt, &delivered)
err = rows.Scan(&r.Id, &r.ItemId, &r.User, &typ, &options, &text, &client, &exitCode, &images, &attachments, &createdAt, &delivered)
if err != nil {
return nil, err
}
if client != "" {
r.Client = &client
}
if exitCode.Valid {
code := int(exitCode.Int64)
r.ExitCode = &code
}
r.Type = api.InboxResponseType(typ)
if options.Valid {
+3
View File
@@ -466,6 +466,9 @@ ALTER TABLE inbox_responses ADD COLUMN images TEXT NOT NULL DEFAULT '[]';
ALTER TABLE lead_notes ADD COLUMN project_id TEXT NOT NULL DEFAULT '';
`}, {"add-session-subagents", `
ALTER TABLE agent_sessions ADD COLUMN subagents INTEGER NOT NULL DEFAULT 0;
`}, {"add-inbox-run-responses", `
ALTER TABLE inbox_responses ADD COLUMN client TEXT NOT NULL DEFAULT '';
ALTER TABLE inbox_responses ADD COLUMN exit_code INTEGER;
`}}
const (