feat: register browser tools and skills for queen
This commit is contained in:
@@ -5,5 +5,12 @@
|
||||
"args": ["run", "python", "coder_tools_server.py", "--stdio"],
|
||||
"cwd": "../../../../tools",
|
||||
"description": "Unsandboxed file system tools for code generation and validation"
|
||||
},
|
||||
"gcu-tools": {
|
||||
"transport": "stdio",
|
||||
"command": "uv",
|
||||
"args": ["run", "python", "-m", "gcu.server", "--stdio", "--capabilities", "browser"],
|
||||
"cwd": "../../../../tools",
|
||||
"description": "Browser automation tools (Playwright-based)"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -737,21 +737,14 @@ _queen_tools_independent = """
|
||||
You are operating as a standalone agent — no worker graph. You do the work directly.
|
||||
|
||||
## File I/O (coder-tools MCP)
|
||||
- read_file(path, offset?, limit?, hashline?) — read with line numbers
|
||||
- write_file(path, content) — create/overwrite, auto-mkdir
|
||||
- edit_file(path, old_text, new_text, replace_all?) — fuzzy-match edit
|
||||
- hashline_edit(path, edits, auto_cleanup?, encoding?) — anchor-based edit
|
||||
- list_directory(path, recursive?) — list contents
|
||||
- search_files(pattern, path?, include?, hashline?) — regex search
|
||||
- run_command(command, cwd?, timeout?) — shell execution
|
||||
- undo_changes(path?) — restore from git snapshot
|
||||
- read_file, write_file, edit_file, hashline_edit, list_directory, \
|
||||
search_files, run_command, undo_changes
|
||||
|
||||
## Browser Automation (gcu-tools MCP)
|
||||
Full Playwright-based browser control: navigate, click, type, scroll, \
|
||||
screenshot, evaluate JS, handle tabs, intercept requests, and more.
|
||||
|
||||
Use these tools to interact with websites, fill forms, extract data, \
|
||||
and automate web workflows directly.
|
||||
All browser tools are prefixed with `browser_` (browser_start, browser_navigate, \
|
||||
browser_click, browser_fill, browser_snapshot, browser_screenshot, browser_scroll, \
|
||||
browser_tabs, browser_close, browser_evaluate, etc.).
|
||||
Follow the browser-automation skill protocol — activate it before using browser tools.
|
||||
"""
|
||||
|
||||
_queen_behavior_editing = """
|
||||
|
||||
@@ -13,7 +13,7 @@ export interface LiveSession {
|
||||
uptime_seconds: number;
|
||||
intro_message?: string;
|
||||
/** Queen operating phase — "planning", "building", "staging", or "running" */
|
||||
queen_phase?: "planning" | "building" | "staging" | "running";
|
||||
queen_phase?: "planning" | "building" | "staging" | "running" | "independent";
|
||||
/** Whether the queen's LLM supports image content in messages */
|
||||
queen_supports_images?: boolean;
|
||||
/** Selected queen identity ID (e.g. "queen_technology") */
|
||||
|
||||
@@ -47,7 +47,7 @@ export interface ChatMessage {
|
||||
/** Epoch ms when this message was first created — used for ordering queen/worker interleaving */
|
||||
createdAt?: number;
|
||||
/** Queen phase active when this message was created */
|
||||
phase?: "planning" | "building" | "staging" | "running";
|
||||
phase?: "planning" | "building" | "staging" | "running" | "independent";
|
||||
/** Images attached to a user message */
|
||||
images?: ImageContent[];
|
||||
/** Backend node_id that produced this message — used for subagent grouping */
|
||||
@@ -86,7 +86,7 @@ interface ChatPanelProps {
|
||||
/** Called when user dismisses the pending question without answering */
|
||||
onQuestionDismiss?: () => void;
|
||||
/** Queen operating phase — shown as a tag on queen messages */
|
||||
queenPhase?: "planning" | "building" | "staging" | "running";
|
||||
queenPhase?: "planning" | "building" | "staging" | "running" | "independent";
|
||||
/** Context window usage for queen and workers */
|
||||
contextUsage?: Record<string, ContextUsageEntry>;
|
||||
}
|
||||
@@ -210,7 +210,7 @@ const MessageBubble = memo(
|
||||
queenPhase,
|
||||
}: {
|
||||
msg: ChatMessage;
|
||||
queenPhase?: "planning" | "building" | "staging" | "running";
|
||||
queenPhase?: "planning" | "building" | "staging" | "running" | "independent";
|
||||
}) {
|
||||
const isUser = msg.type === "user";
|
||||
const isQueen = msg.role === "queen";
|
||||
@@ -300,13 +300,15 @@ const MessageBubble = memo(
|
||||
}`}
|
||||
>
|
||||
{isQueen
|
||||
? (msg.phase ?? queenPhase) === "running"
|
||||
? "running"
|
||||
: (msg.phase ?? queenPhase) === "staging"
|
||||
? "staging"
|
||||
: (msg.phase ?? queenPhase) === "planning"
|
||||
? "planning"
|
||||
: "building"
|
||||
? (msg.phase ?? queenPhase) === "independent"
|
||||
? "independent"
|
||||
: (msg.phase ?? queenPhase) === "running"
|
||||
? "running"
|
||||
: (msg.phase ?? queenPhase) === "staging"
|
||||
? "staging"
|
||||
: (msg.phase ?? queenPhase) === "planning"
|
||||
? "planning"
|
||||
: "building"
|
||||
: "Worker"}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -149,8 +149,8 @@ export function sseEventToChatMessage(
|
||||
}
|
||||
}
|
||||
|
||||
type QueenPhase = "planning" | "building" | "staging" | "running";
|
||||
const VALID_PHASES = new Set<string>(["planning", "building", "staging", "running"]);
|
||||
type QueenPhase = "planning" | "building" | "staging" | "running" | "independent";
|
||||
const VALID_PHASES = new Set<string>(["planning", "building", "staging", "running", "independent"]);
|
||||
|
||||
/**
|
||||
* Scan an array of persisted events and return the last queen phase seen,
|
||||
|
||||
@@ -47,7 +47,7 @@ function truncate(s: string, max: number): string {
|
||||
|
||||
type SessionRestoreResult = {
|
||||
messages: ChatMessage[];
|
||||
restoredPhase: "planning" | "building" | "staging" | "running" | null;
|
||||
restoredPhase: "planning" | "building" | "staging" | "running" | "independent" | null;
|
||||
flowchartMap: Record<string, string[]> | null;
|
||||
originalDraft: DraftGraphData | null;
|
||||
};
|
||||
@@ -112,7 +112,7 @@ interface AgentState {
|
||||
awaitingInput: boolean;
|
||||
workerInputMessageId: string | null;
|
||||
queenBuilding: boolean;
|
||||
queenPhase: "planning" | "building" | "staging" | "running";
|
||||
queenPhase: "planning" | "building" | "staging" | "running" | "independent";
|
||||
designingDraft: boolean;
|
||||
draftGraph: DraftGraphData | null;
|
||||
originalDraft: DraftGraphData | null;
|
||||
@@ -417,7 +417,7 @@ export default function ColonyChat() {
|
||||
}
|
||||
}
|
||||
|
||||
let restoredPhase: "planning" | "building" | "staging" | "running" | null = null;
|
||||
let restoredPhase: "planning" | "building" | "staging" | "running" | "independent" | null = null;
|
||||
let restoredFlowchartMap: Record<string, string[]> | null = null;
|
||||
let restoredOriginalDraft: DraftGraphData | null = null;
|
||||
|
||||
@@ -958,7 +958,9 @@ export default function ColonyChat() {
|
||||
const rawPhase = event.data?.phase as string;
|
||||
const eventAgentPath = (event.data?.agent_path as string) || null;
|
||||
const newPhase: AgentState["queenPhase"] =
|
||||
rawPhase === "running"
|
||||
rawPhase === "independent"
|
||||
? "independent"
|
||||
: rawPhase === "running"
|
||||
? "running"
|
||||
: rawPhase === "staging"
|
||||
? "staging"
|
||||
|
||||
@@ -35,6 +35,7 @@ export default function QueenDM() {
|
||||
|
||||
const turnCounterRef = useRef(0);
|
||||
const queenIterTextRef = useRef<Record<string, Record<number, string>>>({});
|
||||
const [queenPhase, setQueenPhase] = useState<"planning" | "building" | "staging" | "running" | "independent">("independent");
|
||||
|
||||
// Switch queen session when queenId changes
|
||||
useEffect(() => {
|
||||
@@ -195,6 +196,14 @@ export default function QueenDM() {
|
||||
break;
|
||||
}
|
||||
|
||||
case "queen_phase_changed": {
|
||||
const rawPhase = event.data?.phase as string;
|
||||
if (rawPhase === "independent" || rawPhase === "planning" || rawPhase === "building" || rawPhase === "staging" || rawPhase === "running") {
|
||||
setQueenPhase(rawPhase);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -298,7 +307,7 @@ export default function QueenDM() {
|
||||
isWaiting={isTyping && !isStreaming}
|
||||
isBusy={isTyping}
|
||||
disabled={loading || !queenReady}
|
||||
queenPhase="planning"
|
||||
queenPhase={queenPhase}
|
||||
pendingQuestion={awaitingInput ? pendingQuestion : null}
|
||||
pendingOptions={awaitingInput ? pendingOptions : null}
|
||||
pendingQuestions={awaitingInput ? pendingQuestions : null}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
from playwright.sync_api import sync_playwright
|
||||
|
||||
def main():
|
||||
with sync_playwright() as p:
|
||||
browser = p.chromium.launch(headless=False)
|
||||
page = browser.new_page()
|
||||
page.goto("https://www.linkedin.com/login")
|
||||
print("Please log in to LinkedIn in the opened browser window.")
|
||||
input("Press Enter here when you have logged in...")
|
||||
|
||||
# Now search connections
|
||||
print("Logged in. Ready to proceed.")
|
||||
browser.close()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user