Pull requests show their tabs right under the title; agent panels move into Conversation
1 file+96−920/1 viewed
| 535 | 535 | </p> | |
| 536 | 536 | )} | |
| 537 | 537 | ||
| 538 | − | {lifecycle && <LifecyclePanel lifecycle={lifecycle} />} | |
| 539 | − | {/* The agent on it: who, doing what this minute, for how long, at what cost. */} | |
| 540 | − | <AgentPanel owner={params.owner} repo={params.repo} number={pull.number} stage={lifecycle?.stage ?? null} /> | |
| 541 | − | ||
| 542 | − | {/* Steering: while its agent works, people can tell it things. */} | |
| 543 | − | {canManage && | |
| 544 | − | pull.runtime === "hosted" && | |
| 545 | − | (working || ["working", "revising", "catching_up", "answering"].includes(lifecycle?.stage ?? "")) && ( | |
| 546 | − | <Form method="post" className="mt-4 rounded-2xl bg-surface p-4 ring-1 ring-merged/30"> | |
| 547 | − | <p className="flex items-center gap-2 text-sm font-medium"> | |
| 548 | − | <Sparkles size={15} className="text-merged" /> | |
| 549 | − | Message the agent | |
| 550 | − | </p> | |
| 551 | − | <p className="mt-1 text-xs text-muted"> | |
| 552 | − | A correction, a hint, a change of plan. It reads it at its next step, without | |
| 553 | − | starting over. | |
| 554 | − | </p> | |
| 555 | − | <div className="mt-3 flex gap-2"> | |
| 556 | − | <input type="hidden" name="action" value="message" /> | |
| 557 | − | <input | |
| 558 | − | name="body" | |
| 559 | − | required | |
| 560 | − | autoComplete="off" | |
| 561 | − | data-1p-ignore | |
| 562 | − | placeholder="Keep the old flag working too…" | |
| 563 | − | className="h-9 min-w-0 grow rounded-md bg-bg px-3 text-sm ring-1 ring-line outline-none placeholder:text-faint focus:ring-merged/60" | |
| 564 | − | /> | |
| 565 | − | <Button type="submit">Send</Button> | |
| 566 | − | </div> | |
| 567 | − | </Form> | |
| 568 | − | )} | |
| 569 | − | {messages.length > 0 && ( | |
| 570 | − | <ul className="mt-3 space-y-1.5"> | |
| 571 | − | {messages.map((message) => ( | |
| 572 | − | <li key={message.id} className="flex items-start gap-2 text-sm"> | |
| 573 | − | <Avatar name={message.author} size={18} /> | |
| 574 | − | <span className="min-w-0 grow"> | |
| 575 | − | <span className="font-medium"> | |
| 576 | − | {message.fromNumber != null ? `The agent on #${message.fromNumber}` : message.author} | |
| 577 | − | </span>{" "} | |
| 578 | − | <span className="text-muted"> | |
| 579 | − | {message.kind === "question" | |
| 580 | − | ? "asked:" | |
| 581 | − | : message.kind === "handoff" | |
| 582 | − | ? "handed over:" | |
| 583 | − | : message.kind === "answer" | |
| 584 | − | ? "answered:" | |
| 585 | − | : "to the agent:"} | |
| 586 | − | </span>{" "} | |
| 587 | − | {message.body} | |
| 588 | − | {message.answer && ( | |
| 589 | − | <span className="mt-1 block border-l-2 border-merged/40 pl-2 text-muted"> | |
| 590 | − | {message.declined ? "Declined: " : "Answer: "} | |
| 591 | − | {message.answer} | |
| 592 | − | </span> | |
| 593 | − | )} | |
| 594 | − | </span> | |
| 595 | − | <span className={`shrink-0 text-xs ${message.deliveredAt ? "text-accent" : "text-faint"}`}> | |
| 596 | − | {message.deliveredAt ? "read by the agent" : "waiting for its next step"} | |
| 597 | − | </span> | |
| 598 | − | </li> | |
| 599 | − | ))} | |
| 600 | − | </ul> | |
| 601 | − | )} | |
| 602 | − | ||
| 603 | 538 | {issue && ( | |
| 604 | 539 | <Link | |
| 605 | 540 | to={`${base}/issues/${issue.number}`} | |
| 620 | 555 | )} | |
| 621 | 556 | </Link> | |
| 622 | 557 | )} | |
| 623 | − | ||
| 624 | 558 | {pull.status === "merged" && ( | |
| 625 | 559 | <p className="mt-4 flex items-center gap-2.5 rounded-xl border border-merged/40 bg-merged/5 px-4 py-2.5 text-sm"> | |
| 626 | 560 | <GitMerge size={16} className="shrink-0 text-merged" /> | |
| 649 | 583 | </p> | |
| 650 | 584 | )} | |
| 651 | 585 | ||
| 652 | − | {collisions.length > 0 && active && ( | |
| 653 | − | <div className="mt-4 rounded-xl border border-line bg-surface px-4 py-3 text-sm"> | |
| 654 | − | <p className="flex items-center gap-2.5 font-medium"> | |
| 655 | − | <Radar size={16} className="shrink-0 text-info" /> | |
| 656 | − | Other work is changing the same files | |
| 657 | − | </p> | |
| 658 | − | <ul className="mt-2 space-y-1.5"> | |
| 659 | − | {collisions.map((other) => ( | |
| 660 | − | <li key={other.number} className="flex flex-wrap items-baseline gap-x-2 text-muted"> | |
| 661 | − | <Link | |
| 662 | − | to={`${base}/pull/${other.number}`} | |
| 663 | − | className="font-medium text-fg hover:underline" | |
| 664 | − | > | |
| 665 | − | {other.title} <span className="font-normal text-faint">#{other.number}</span> | |
| 666 | − | </Link> | |
| 667 | − | <span className="font-mono text-xs">{other.paths.join(", ")}</span> | |
| 668 | − | </li> | |
| 669 | − | ))} | |
| 670 | − | </ul> | |
| 671 | − | <p className="mt-2 text-xs text-faint"> | |
| 672 | − | Whichever merges second will have to catch up, and may conflict. | |
| 673 | − | </p> | |
| 674 | − | </div> | |
| 675 | − | )} | |
| 676 | − | ||
| 677 | − | <nav className="mt-8 flex gap-6 border-b border-line"> | |
| 586 | + | <nav className="mt-6 flex gap-6 border-b border-line"> | |
| 678 | 587 | <TabLink to={here} active={tab === "conversation"}> | |
| 679 | 588 | <MessageSquare size={15} /> | |
| 680 | 589 | Conversation | |
| 688 | 597 | Changes | |
| 689 | 598 | </TabLink> | |
| 690 | 599 | </nav> | |
| 600 | + | {/* What is happening on it now: its stage, its agent, what people told | |
| 601 | + | the agent, and what else touches the same files. On the conversation, | |
| 602 | + | so the tabs sit right under the title. */} | |
| 603 | + | {tab === "conversation" && ( | |
| 604 | + | <div> | |
| 605 | + | {lifecycle && <LifecyclePanel lifecycle={lifecycle} />} | |
| 606 | + | {/* The agent on it: who, doing what this minute, for how long, at what cost. */} | |
| 607 | + | <AgentPanel owner={params.owner} repo={params.repo} number={pull.number} stage={lifecycle?.stage ?? null} /> | |
| 608 | + | ||
| 609 | + | {/* Steering: while its agent works, people can tell it things. */} | |
| 610 | + | {canManage && | |
| 611 | + | pull.runtime === "hosted" && | |
| 612 | + | (working || ["working", "revising", "catching_up", "answering"].includes(lifecycle?.stage ?? "")) && ( | |
| 613 | + | <Form method="post" className="mt-4 rounded-2xl bg-surface p-4 ring-1 ring-merged/30"> | |
| 614 | + | <p className="flex items-center gap-2 text-sm font-medium"> | |
| 615 | + | <Sparkles size={15} className="text-merged" /> | |
| 616 | + | Message the agent | |
| 617 | + | </p> | |
| 618 | + | <p className="mt-1 text-xs text-muted"> | |
| 619 | + | A correction, a hint, a change of plan. It reads it at its next step, without | |
| 620 | + | starting over. | |
| 621 | + | </p> | |
| 622 | + | <div className="mt-3 flex gap-2"> | |
| 623 | + | <input type="hidden" name="action" value="message" /> | |
| 624 | + | <input | |
| 625 | + | name="body" | |
| 626 | + | required | |
| 627 | + | autoComplete="off" | |
| 628 | + | data-1p-ignore | |
| 629 | + | placeholder="Keep the old flag working too…" | |
| 630 | + | className="h-9 min-w-0 grow rounded-md bg-bg px-3 text-sm ring-1 ring-line outline-none placeholder:text-faint focus:ring-merged/60" | |
| 631 | + | /> | |
| 632 | + | <Button type="submit">Send</Button> | |
| 633 | + | </div> | |
| 634 | + | </Form> | |
| 635 | + | )} | |
| 636 | + | {messages.length > 0 && ( | |
| 637 | + | <ul className="mt-3 space-y-1.5"> | |
| 638 | + | {messages.map((message) => ( | |
| 639 | + | <li key={message.id} className="flex items-start gap-2 text-sm"> | |
| 640 | + | <Avatar name={message.author} size={18} /> | |
| 641 | + | <span className="min-w-0 grow"> | |
| 642 | + | <span className="font-medium"> | |
| 643 | + | {message.fromNumber != null ? `The agent on #${message.fromNumber}` : message.author} | |
| 644 | + | </span>{" "} | |
| 645 | + | <span className="text-muted"> | |
| 646 | + | {message.kind === "question" | |
| 647 | + | ? "asked:" | |
| 648 | + | : message.kind === "handoff" | |
| 649 | + | ? "handed over:" | |
| 650 | + | : message.kind === "answer" | |
| 651 | + | ? "answered:" | |
| 652 | + | : "to the agent:"} | |
| 653 | + | </span>{" "} | |
| 654 | + | {message.body} | |
| 655 | + | {message.answer && ( | |
| 656 | + | <span className="mt-1 block border-l-2 border-merged/40 pl-2 text-muted"> | |
| 657 | + | {message.declined ? "Declined: " : "Answer: "} | |
| 658 | + | {message.answer} | |
| 659 | + | </span> | |
| 660 | + | )} | |
| 661 | + | </span> | |
| 662 | + | <span className={`shrink-0 text-xs ${message.deliveredAt ? "text-accent" : "text-faint"}`}> | |
| 663 | + | {message.deliveredAt ? "read by the agent" : "waiting for its next step"} | |
| 664 | + | </span> | |
| 665 | + | </li> | |
| 666 | + | ))} | |
| 667 | + | </ul> | |
| 668 | + | )} | |
| 669 | + | {collisions.length > 0 && active && ( | |
| 670 | + | <div className="mt-4 rounded-xl border border-line bg-surface px-4 py-3 text-sm"> | |
| 671 | + | <p className="flex items-center gap-2.5 font-medium"> | |
| 672 | + | <Radar size={16} className="shrink-0 text-info" /> | |
| 673 | + | Other work is changing the same files | |
| 674 | + | </p> | |
| 675 | + | <ul className="mt-2 space-y-1.5"> | |
| 676 | + | {collisions.map((other) => ( | |
| 677 | + | <li key={other.number} className="flex flex-wrap items-baseline gap-x-2 text-muted"> | |
| 678 | + | <Link | |
| 679 | + | to={`${base}/pull/${other.number}`} | |
| 680 | + | className="font-medium text-fg hover:underline" | |
| 681 | + | > | |
| 682 | + | {other.title} <span className="font-normal text-faint">#{other.number}</span> | |
| 683 | + | </Link> | |
| 684 | + | <span className="font-mono text-xs">{other.paths.join(", ")}</span> | |
| 685 | + | </li> | |
| 686 | + | ))} | |
| 687 | + | </ul> | |
| 688 | + | <p className="mt-2 text-xs text-faint"> | |
| 689 | + | Whichever merges second will have to catch up, and may conflict. | |
| 690 | + | </p> | |
| 691 | + | </div> | |
| 692 | + | )} | |
| 693 | + | </div> | |
| 694 | + | )} | |
| 691 | 695 | <div className="mt-5"> | |
| 692 | 696 | {comparison ? ( | |
| 693 | 697 | <DiffView |