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.
@@ -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
- emitEvent(taskId, "user_action_request", actionData).catch(() => {});
586
- // Emit waiting_for_user status so the web UI can show a waiting indicator
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
- }).catch(() => {});
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
- while (Date.now() - startTime < timeout) {
596
- const response = await pollActionResponse(taskId);
597
- if (response && (!response.action_id || response.action_id === actionId)) {
598
- // Response can be either an option click or free-text input
599
- const actionKey = (response.action_key || "") as string;
600
- const text = (response.text || "") as string;
601
- const label = (response.label || actionKey || text) as string;
602
- log.info(`User responded: "${label}"`);
603
- return {
604
- content: [
605
- {
606
- type: "text",
607
- text: JSON.stringify({
608
- status: "responded",
609
- action_key: actionKey || "custom_input",
610
- label,
611
- text: text || label,
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
- await new Promise((resolve) => setTimeout(resolve, pollInterval));
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"),