assistme 0.3.3 → 0.3.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +462 -65
- package/package.json +1 -1
- package/src/agent/processor.ts +55 -6
- package/src/agent/system-prompt.ts +5 -1
- package/src/browser/controller.ts +420 -10
- package/src/db/event.ts +32 -20
- package/src/mcp/agent-tools-server.ts +53 -40
- package/src/mcp/browser-server.ts +1 -1
|
@@ -25,10 +25,14 @@ export interface AgentToolsDeps {
|
|
|
25
25
|
skillManager: SkillManager;
|
|
26
26
|
taskId: string;
|
|
27
27
|
sessionId?: string;
|
|
28
|
+
/** Called when the agent starts waiting for user input (pauses task timeout). */
|
|
29
|
+
onUserWaitStart?: () => void;
|
|
30
|
+
/** Called when user input completes or times out (resumes task timeout). */
|
|
31
|
+
onUserWaitEnd?: () => void;
|
|
28
32
|
}
|
|
29
33
|
|
|
30
34
|
export function createAgentToolsServer(deps: AgentToolsDeps): McpSdkServerConfigWithInstance {
|
|
31
|
-
const { memoryManager, skillManager, taskId, sessionId } = deps;
|
|
35
|
+
const { memoryManager, skillManager, taskId, sessionId, onUserWaitStart, onUserWaitEnd } = deps;
|
|
32
36
|
|
|
33
37
|
return createSdkMcpServer({
|
|
34
38
|
name: "assistme-agent",
|
|
@@ -582,56 +586,65 @@ export function createAgentToolsServer(deps: AgentToolsDeps): McpSdkServerConfig
|
|
|
582
586
|
await setActionRequest(taskId, actionData);
|
|
583
587
|
log.info(`Ask user ${actionId}: "${args.question.slice(0, 80)}..."`);
|
|
584
588
|
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
emitEvent(taskId, "status_change", {
|
|
589
|
+
// Await event emissions to ensure they reach the DB before we start polling
|
|
590
|
+
await emitEvent(taskId, "user_action_request", actionData);
|
|
591
|
+
await emitEvent(taskId, "status_change", {
|
|
588
592
|
status: "waiting_for_user",
|
|
589
593
|
message: args.question,
|
|
590
|
-
})
|
|
594
|
+
});
|
|
595
|
+
|
|
596
|
+
// Pause the task wall-clock timeout while waiting for user
|
|
597
|
+
onUserWaitStart?.();
|
|
591
598
|
|
|
592
599
|
const startTime = Date.now();
|
|
593
600
|
const pollInterval = 2000;
|
|
594
601
|
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
602
|
+
try {
|
|
603
|
+
while (Date.now() - startTime < timeout) {
|
|
604
|
+
const response = await pollActionResponse(taskId);
|
|
605
|
+
if (response && (!response.action_id || response.action_id === actionId)) {
|
|
606
|
+
const actionKey = (response.action_key || "") as string;
|
|
607
|
+
const text = (response.text || "") as string;
|
|
608
|
+
const label = (response.label || actionKey || text) as string;
|
|
609
|
+
log.info(`User responded: "${label}"`);
|
|
610
|
+
return {
|
|
611
|
+
content: [
|
|
612
|
+
{
|
|
613
|
+
type: "text",
|
|
614
|
+
text: JSON.stringify({
|
|
615
|
+
status: "responded",
|
|
616
|
+
action_key: actionKey || "custom_input",
|
|
617
|
+
label,
|
|
618
|
+
text: text || label,
|
|
619
|
+
}),
|
|
620
|
+
},
|
|
621
|
+
],
|
|
622
|
+
};
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
await new Promise((resolve) => setTimeout(resolve, pollInterval));
|
|
616
626
|
}
|
|
617
627
|
|
|
618
|
-
|
|
628
|
+
log.warn(`Ask user ${actionId} timed out after ${args.timeout_seconds || 300}s`);
|
|
629
|
+
return {
|
|
630
|
+
content: [
|
|
631
|
+
{
|
|
632
|
+
type: "text",
|
|
633
|
+
text: JSON.stringify({
|
|
634
|
+
status: "timeout",
|
|
635
|
+
message:
|
|
636
|
+
"User did not respond within the timeout period. Continue the task with a reasonable default or skip the step that required user input.",
|
|
637
|
+
}),
|
|
638
|
+
},
|
|
639
|
+
],
|
|
640
|
+
};
|
|
641
|
+
} finally {
|
|
642
|
+
// Resume the task timeout regardless of outcome
|
|
643
|
+
onUserWaitEnd?.();
|
|
619
644
|
}
|
|
620
|
-
|
|
621
|
-
log.warn(`Ask user ${actionId} timed out after ${args.timeout_seconds || 300}s`);
|
|
622
|
-
return {
|
|
623
|
-
content: [
|
|
624
|
-
{
|
|
625
|
-
type: "text",
|
|
626
|
-
text: JSON.stringify({
|
|
627
|
-
status: "timeout",
|
|
628
|
-
message: "User did not respond within the timeout period.",
|
|
629
|
-
}),
|
|
630
|
-
},
|
|
631
|
-
],
|
|
632
|
-
};
|
|
633
645
|
} catch (err) {
|
|
634
646
|
log.error(`ask_user failed: ${err}`);
|
|
647
|
+
onUserWaitEnd?.();
|
|
635
648
|
return {
|
|
636
649
|
content: [
|
|
637
650
|
{
|
|
@@ -92,7 +92,7 @@ export function createBrowserMcpServer(): McpSdkServerConfigWithInstance {
|
|
|
92
92
|
),
|
|
93
93
|
tool(
|
|
94
94
|
"browser_type",
|
|
95
|
-
"Type text into an input field in the user's browser.",
|
|
95
|
+
"Type text into an input field in the user's browser. If the CSS selector fails, automatically falls back to typing into the currently focused element. Works with contenteditable elements (rich text editors) and cross-origin iframes.",
|
|
96
96
|
{
|
|
97
97
|
selector: z.string().describe("CSS selector of the input element"),
|
|
98
98
|
text: z.string().describe("Text to type"),
|