Cut transcript noise: fold grey boxes, drop duplicate review rows
This commit is contained in:
@@ -24,7 +24,7 @@ const guidance = `You are running inside byre. The human reads your work in byre
|
||||
- TODO.md at the repo root is the project's list of work for byre; its format is the read_knowledge article todo-file.`
|
||||
|
||||
const proseQuestionNudge = "Your final message asks the human something in prose. Ask it with byre's ask_human tool " +
|
||||
"(context with the choices inline as `- ( ) choice` / `- (*) recommended` or `- [ ] choice` / `- [x] recommended` list items, question, why_blocked), " +
|
||||
"(context with the choices inline as `- ( ) choice` / `- (*) recommended` or `- [ ] choice` / `- [x] recommended` list items, and question)," +
|
||||
"then end your turn with a short summary."
|
||||
|
||||
var (
|
||||
|
||||
@@ -24,7 +24,6 @@ var attachmentKinds = []api.AttachmentKind{
|
||||
type askArgs struct {
|
||||
Context string `json:"context"`
|
||||
Question string `json:"question"`
|
||||
WhyBlocked string `json:"why_blocked"`
|
||||
Attachments []api.Attachment `json:"attachments"`
|
||||
ThreadID string `json:"thread_id"`
|
||||
}
|
||||
@@ -58,7 +57,6 @@ func (m *Manager) askTool(l *live) mcp.Tool {
|
||||
"properties": {
|
||||
"context": {"type": "string", "description": "Everything the human needs to answer well without reading your transcript: what you are working on, what you found, the relevant facts and data shared by all the choices, and then the choices. Markdown is rendered. Each choice is a list item, at least two, all of one kind: '- ( ) Merge now' / '- (*) Wait for review' (pick one; exactly one (*) marks your recommendation), or '- [ ] Fix the tests' / '- [x] Update the docs' (pick any; [x] marks the ones you recommend). The choice's first line, after the marker, is a short name that comes back verbatim as the answer. Everything about that one choice goes in lines indented two spaces beneath it, not in a paragraph above the list: what it would concretely do, its worked example, any code block, command or sub-list, and its trade-offs. For example:\n\n- ( ) Retry in the client\n Wraps ` + "`fetch` in `retry(3)`" + `; a 500 shows the spinner up to 6s longer.\n ` + "```" + `ts\n await retry(3, () => api.get(path));\n ` + "```" + `\n- (*) Queue on the server\n The request returns at once; the write lands within 1s.\n\nPut long supporting detail (logs, full data, per-option analysis) in collapsed sections the human expands on demand: a line '<details><summary>Title</summary>', the Markdown content, then a line '</details>'."},
|
||||
"question": {"type": "string", "description": "The question itself, in one or two sentences. Markdown is rendered."},
|
||||
"why_blocked": {"type": "string", "description": "What you can't do until this is answered, and why you can't decide it yourself."},
|
||||
"attachments": {"type": "array", "items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -77,7 +75,7 @@ func (m *Manager) askTool(l *live) mcp.Tool {
|
||||
}},
|
||||
"thread_id": {"type": "string"}
|
||||
},
|
||||
"required": ["context", "question", "why_blocked"]
|
||||
"required": ["context", "question"]
|
||||
}`),
|
||||
Handler: func(ctx context.Context, raw json.RawMessage) (string, error) {
|
||||
return m.ask(ctx, l, raw)
|
||||
@@ -121,7 +119,6 @@ func (m *Manager) ask(ctx context.Context, l *live, raw json.RawMessage) (string
|
||||
payload := map[string]any{
|
||||
"context": args.Context,
|
||||
"question": args.Question,
|
||||
"why_blocked": args.WhyBlocked,
|
||||
"options": options,
|
||||
"multiple": choices[0].checkbox,
|
||||
"recommended": recommended,
|
||||
@@ -259,9 +256,6 @@ func (m *Manager) validateAsk(ctx context.Context, l *live, args askArgs) error
|
||||
if strings.TrimSpace(args.Question) == "" {
|
||||
problems = append(problems, "question is empty")
|
||||
}
|
||||
if strings.TrimSpace(args.WhyBlocked) == "" {
|
||||
problems = append(problems, "why_blocked is empty: say what you can't do until this is answered and why you can't decide it yourself")
|
||||
}
|
||||
choices := parseChoices(args.Context)
|
||||
if len(choices) < 2 {
|
||||
problems = append(problems, "context needs at least two choices, each a list item on its own line: `- ( ) choice` (pick one) or `- [ ] choice` (pick any)")
|
||||
|
||||
@@ -641,7 +641,7 @@ func (m *Manager) itemText(ctx context.Context, item api.InboxItem) string {
|
||||
}
|
||||
fmt.Fprintf(b, "- %s%s\n", clip(o, 300), mark)
|
||||
}
|
||||
fmt.Fprintf(b, "Blocked on: %v\nThe full context is in read_inbox.", p["why_blocked"])
|
||||
b.WriteString("The full context is in read_inbox.")
|
||||
return b.String()
|
||||
}
|
||||
|
||||
|
||||
@@ -723,6 +723,9 @@ func (m *Manager) recordMessage(ctx context.Context, sess api.AgentSession, task
|
||||
if isContinuation(actor, text) {
|
||||
payload["continuation"] = true
|
||||
}
|
||||
if isFindingsMessage(actor, text) {
|
||||
payload["findings"] = true
|
||||
}
|
||||
err = m.store.RecordTurnMessage(ctx, sess.Id, newEvent(sess.Id, sess.Owner, task.ProjectId, task.Id, actor, "user.message", payload))
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
|
||||
@@ -256,7 +256,11 @@ func (m *Manager) recordQueued(ctx context.Context, l *live, msgs []queued) stri
|
||||
if l.implementer() && isMergeInPrompt(q.actor, q.text) {
|
||||
m.takeMergeTurn(l)
|
||||
}
|
||||
err := m.emit(ctx, l, q.actor, "user.message", map[string]any{"text": q.text, "mid_turn": true})
|
||||
payload := map[string]any{"text": q.text, "mid_turn": true}
|
||||
if isFindingsMessage(q.actor, q.text) {
|
||||
payload["findings"] = true
|
||||
}
|
||||
err := m.emit(ctx, l, q.actor, "user.message", payload)
|
||||
if err != nil {
|
||||
slog.Error("record mid-turn message", "session", l.id, "err", err)
|
||||
}
|
||||
|
||||
@@ -358,13 +358,19 @@ func (m *Manager) forwardFindings(taskID, reviewID string) {
|
||||
slog.Info("review findings forwarded", "review", reviewID, "session", s.Id)
|
||||
}
|
||||
|
||||
const findingsPreamble = "A reviewer looked at snapshot #"
|
||||
|
||||
func isFindingsMessage(actor, text string) bool {
|
||||
return actor == "byre" && strings.HasPrefix(text, findingsPreamble)
|
||||
}
|
||||
|
||||
func findingsMessage(r api.Review) string {
|
||||
res := map[string]any{}
|
||||
if r.Result != nil {
|
||||
res = *r.Result
|
||||
}
|
||||
b := &strings.Builder{}
|
||||
fmt.Fprintf(b, "A reviewer looked at snapshot #%d of your work and raised the findings below. Reviewers can be wrong or miss context: check each one against the code and your brief. "+
|
||||
fmt.Fprintf(b, findingsPreamble+"%d of your work and raised the findings below. Reviewers can be wrong or miss context: check each one against the code and your brief. "+
|
||||
"Before you change anything, answer each finding with respond_to_finding (snapshot %d and the finding's number): fixing if it holds up and you'll act on it, ignoring with your reason if you're leaving it. "+
|
||||
"The human sees your answers on the findings and can overrule an ignore.", r.SnapshotN, r.SnapshotN)
|
||||
findings, _ := res["findings"].([]any)
|
||||
|
||||
Reference in New Issue
Block a user