assistme 0.3.0 → 0.3.1

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 CHANGED
@@ -3408,17 +3408,17 @@ ${content}`;
3408
3408
  response += `**Your task:** Analyze this job description and decompose it into 4-10 automatable skills.
3409
3409
 
3410
3410
  `;
3411
- response += `**IMPORTANT \u2014 You MUST use request_user_confirmation before creating skills:**
3411
+ response += `**IMPORTANT \u2014 You MUST use ask_user before creating skills:**
3412
3412
  `;
3413
3413
  response += `1. Analyze the job and draft a list of proposed skills (name, emoji, one-line description for each).
3414
3414
  `;
3415
- response += `2. Call \`request_user_confirmation\` with the formatted skill list as "message" and these options:
3415
+ response += `2. Call \`ask_user\` with the formatted skill list as "question" and these options:
3416
3416
  `;
3417
3417
  response += ` - options: [{label: "Approve All", action_key: "approve_all", description: "Create all proposed skills"}, {label: "Cancel", action_key: "cancel", description: "Do not create any skills"}]
3418
3418
  `;
3419
3419
  response += `3. WAIT for the response. If action_key is "approve_all", create all skills using \`skill_create\`. If "cancel", stop.
3420
3420
  `;
3421
- response += `4. Do NOT ask for confirmation in text. Do NOT create skills without calling request_user_confirmation first.
3421
+ response += `4. Do NOT ask for confirmation in text. Do NOT create skills without calling ask_user first.
3422
3422
 
3423
3423
  `;
3424
3424
  response += `For each skill, call \`skill_create\` with:
@@ -3585,92 +3585,34 @@ ${content}`;
3585
3585
  };
3586
3586
  }
3587
3587
  ),
3588
- // ── User Interaction Tools ──────────────────────────────────
3588
+ // ── User Interaction Tool ───────────────────────────────────
3589
3589
  tool(
3590
- "request_user_input",
3591
- "Ask the user a clarifying question and wait for their free-text response. Use this when you need information that cannot be inferred from context, memory, or the workspace \u2014 e.g. which account to use, specific preferences, ambiguous instructions, or missing parameters for a skill. Do NOT use this for information you can discover yourself (git remote, file contents, etc.).",
3590
+ "ask_user",
3591
+ "Ask the user a question via the web UI and wait for their response. Shows a message with optional predefined option buttons PLUS a free-text input field \u2014 the user can either click a suggested option or type a custom answer. ALWAYS provide options when you can suggest likely answers. Do NOT use this for information you can discover yourself (git remote, file contents, etc.).",
3592
3592
  {
3593
- question: z.string().describe("The question to ask the user (supports markdown). Be specific about what you need and why."),
3594
- placeholder: z.string().optional().describe("Placeholder text for the input field (e.g. 'https://github.com/owner/repo')"),
3595
- timeout_seconds: z.number().optional().describe("How long to wait for response (default: 300)")
3596
- },
3597
- async (args) => {
3598
- const actionId = `input_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
3599
- const timeout = (args.timeout_seconds || 300) * 1e3;
3600
- const actionData = {
3601
- id: actionId,
3602
- type: "input",
3603
- message: args.question,
3604
- placeholder: args.placeholder || "",
3605
- created_at: (/* @__PURE__ */ new Date()).toISOString()
3606
- };
3607
- try {
3608
- await setActionRequest(taskId, actionData);
3609
- log.info(`Input request ${actionId}: "${args.question.slice(0, 80)}..."`);
3610
- emitEvent(taskId, "user_action_request", actionData).catch(() => {
3611
- });
3612
- const startTime = Date.now();
3613
- const pollInterval = 2e3;
3614
- while (Date.now() - startTime < timeout) {
3615
- const response = await pollActionResponse(taskId);
3616
- if (response && (!response.action_id || response.action_id === actionId)) {
3617
- const text = response.text || response.value || "";
3618
- log.info(`User input received: "${text.slice(0, 80)}"`);
3619
- return {
3620
- content: [{
3621
- type: "text",
3622
- text: JSON.stringify({ status: "responded", text })
3623
- }]
3624
- };
3625
- }
3626
- await new Promise((resolve2) => setTimeout(resolve2, pollInterval));
3627
- }
3628
- log.warn(`Input request ${actionId} timed out`);
3629
- return {
3630
- content: [{
3631
- type: "text",
3632
- text: JSON.stringify({
3633
- status: "timeout",
3634
- message: "User did not respond within the timeout period."
3635
- })
3636
- }]
3637
- };
3638
- } catch (err) {
3639
- log.error(`request_user_input failed: ${err}`);
3640
- return {
3641
- content: [{
3642
- type: "text",
3643
- text: `Failed to request user input: ${err instanceof Error ? err.message : err}`
3644
- }]
3645
- };
3646
- }
3647
- }
3648
- ),
3649
- tool(
3650
- "request_user_confirmation",
3651
- "Pause and ask the user for approval or input via the web UI. Returns the user's chosen action_key. Use this BEFORE creating skills, making irreversible changes, etc. The agent will block until the user responds or the timeout expires.",
3652
- {
3653
- message: z.string().describe("What to show the user (supports markdown)"),
3593
+ question: z.string().describe("The question to ask (supports markdown). Be specific about what you need and why."),
3654
3594
  options: z.array(z.object({
3655
3595
  label: z.string().describe("Button label shown to user"),
3656
3596
  action_key: z.string().describe("Machine-readable key returned when selected"),
3657
3597
  description: z.string().optional().describe("Tooltip/description for this option")
3658
- })).describe("Buttons/options to show the user"),
3598
+ })).optional().describe("Suggested options shown as buttons. The user can always type a custom answer instead."),
3599
+ placeholder: z.string().optional().describe("Placeholder text for the free-text input field"),
3659
3600
  timeout_seconds: z.number().optional().describe("How long to wait for response (default: 300)")
3660
3601
  },
3661
3602
  async (args) => {
3662
- const actionId = `action_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
3603
+ const actionId = `ask_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
3663
3604
  const timeout = (args.timeout_seconds || 300) * 1e3;
3664
3605
  const actionData = {
3665
3606
  id: actionId,
3666
- type: "confirmation",
3667
- message: args.message,
3668
- options: args.options,
3607
+ type: "ask_user",
3608
+ message: args.question,
3609
+ options: args.options || [],
3610
+ placeholder: args.placeholder || "",
3669
3611
  created_at: (/* @__PURE__ */ new Date()).toISOString()
3670
3612
  };
3671
3613
  try {
3672
3614
  await setActionRequest(taskId, actionData);
3673
- log.info(`Action request ${actionId} stored in metadata, waiting for user response...`);
3615
+ log.info(`Ask user ${actionId}: "${args.question.slice(0, 80)}..."`);
3674
3616
  emitEvent(taskId, "user_action_request", actionData).catch(() => {
3675
3617
  });
3676
3618
  const startTime = Date.now();
@@ -3678,23 +3620,25 @@ ${content}`;
3678
3620
  while (Date.now() - startTime < timeout) {
3679
3621
  const response = await pollActionResponse(taskId);
3680
3622
  if (response && (!response.action_id || response.action_id === actionId)) {
3681
- const actionKey = response.action_key || response.action || "";
3682
- const label = response.label || actionKey;
3683
- log.info(`User responded: ${label} (${actionKey})`);
3623
+ const actionKey = response.action_key || "";
3624
+ const text = response.text || "";
3625
+ const label = response.label || actionKey || text;
3626
+ log.info(`User responded: "${label}"`);
3684
3627
  return {
3685
3628
  content: [{
3686
3629
  type: "text",
3687
3630
  text: JSON.stringify({
3688
3631
  status: "responded",
3689
- action_key: actionKey,
3690
- label
3632
+ action_key: actionKey || "custom_input",
3633
+ label,
3634
+ text: text || label
3691
3635
  })
3692
3636
  }]
3693
3637
  };
3694
3638
  }
3695
3639
  await new Promise((resolve2) => setTimeout(resolve2, pollInterval));
3696
3640
  }
3697
- log.warn(`Action request ${actionId} timed out after ${args.timeout_seconds || 300}s`);
3641
+ log.warn(`Ask user ${actionId} timed out after ${args.timeout_seconds || 300}s`);
3698
3642
  return {
3699
3643
  content: [{
3700
3644
  type: "text",
@@ -3705,11 +3649,11 @@ ${content}`;
3705
3649
  }]
3706
3650
  };
3707
3651
  } catch (err) {
3708
- log.error(`request_user_confirmation failed: ${err}`);
3652
+ log.error(`ask_user failed: ${err}`);
3709
3653
  return {
3710
3654
  content: [{
3711
3655
  type: "text",
3712
- text: `Failed to request user confirmation: ${err instanceof Error ? err.message : err}`
3656
+ text: `Failed to ask user: ${err instanceof Error ? err.message : err}`
3713
3657
  }]
3714
3658
  };
3715
3659
  }
@@ -4021,7 +3965,7 @@ Available capabilities:
4021
3965
 
4022
3966
  5. JOB AUTOMATION:
4023
3967
  - When the user describes their job/role/daily work, use skill_generate to decompose it into automatable skills
4024
- - ALWAYS use request_user_confirmation to get user approval before creating skills \u2014 never create skills without approval
3968
+ - ALWAYS use ask_user to get user approval before creating skills \u2014 never create skills without approval
4025
3969
  - Use job_run to start a job \u2014 it gives you the job's goal and available skills as capabilities
4026
3970
  - When running a job, be AGENTIC: decide dynamically what to do based on what you discover
4027
3971
  - Do NOT follow a fixed sequence \u2014 if checking Slack reveals a task that needs GitHub, go do GitHub immediately
@@ -4055,9 +3999,10 @@ Guidelines:
4055
3999
  - When you learn something about the user (preferences, habits), use memory_store to remember it
4056
4000
 
4057
4001
  CRITICAL \u2014 Ask before you guess:
4058
- - Before executing a task, verify you have all required information. If anything is ambiguous or missing, use request_user_input to ask.
4002
+ - Before executing a task, verify you have all required information. If anything is ambiguous or missing, use ask_user to ask.
4059
4003
  - First try to resolve unknowns yourself: check memories, read workspace files (e.g. git remote, config files), or infer from conversation history.
4060
- - If you still lack a critical piece of information after self-resolution, ASK the user via request_user_input. Do NOT guess, assume defaults, or proceed with incomplete information.
4004
+ - If you still lack a critical piece of information after self-resolution, ASK the user via ask_user. Do NOT guess, assume defaults, or proceed with incomplete information.
4005
+ - When asking, provide suggested options as buttons whenever possible \u2014 the user can always type a custom answer instead.
4061
4006
  - Examples of when to ask: which account/repo/project to target, what format the user wants, which of multiple options to choose, credentials or URLs that cannot be inferred.
4062
4007
  - Keep questions specific and actionable. Explain what you already know and what exactly you need.
4063
4008
  - After receiving the answer, store it with memory_store if it is likely to be useful in future conversations.
@@ -4178,8 +4123,7 @@ var TaskProcessor = class {
4178
4123
  "mcp__assistme-agent__skill_add",
4179
4124
  "mcp__assistme-agent__skill_publish",
4180
4125
  // User interaction
4181
- "mcp__assistme-agent__request_user_input",
4182
- "mcp__assistme-agent__request_user_confirmation",
4126
+ "mcp__assistme-agent__ask_user",
4183
4127
  // Job automation tools
4184
4128
  "mcp__assistme-agent__job_run",
4185
4129
  "mcp__assistme-agent__job_schedule",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "assistme",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "AssistMe CLI Agent - AI-powered assistant that controls your real browser",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -453,12 +453,12 @@ export function createAgentToolsServer(deps: AgentToolsDeps): McpSdkServerConfig
453
453
  }
454
454
 
455
455
  response += `**Your task:** Analyze this job description and decompose it into 4-10 automatable skills.\n\n`;
456
- response += `**IMPORTANT — You MUST use request_user_confirmation before creating skills:**\n`;
456
+ response += `**IMPORTANT — You MUST use ask_user before creating skills:**\n`;
457
457
  response += `1. Analyze the job and draft a list of proposed skills (name, emoji, one-line description for each).\n`;
458
- response += `2. Call \`request_user_confirmation\` with the formatted skill list as "message" and these options:\n`;
458
+ response += `2. Call \`ask_user\` with the formatted skill list as "question" and these options:\n`;
459
459
  response += ` - options: [{label: "Approve All", action_key: "approve_all", description: "Create all proposed skills"}, {label: "Cancel", action_key: "cancel", description: "Do not create any skills"}]\n`;
460
460
  response += `3. WAIT for the response. If action_key is "approve_all", create all skills using \`skill_create\`. If "cancel", stop.\n`;
461
- response += `4. Do NOT ask for confirmation in text. Do NOT create skills without calling request_user_confirmation first.\n\n`;
461
+ response += `4. Do NOT ask for confirmation in text. Do NOT create skills without calling ask_user first.\n\n`;
462
462
  response += `For each skill, call \`skill_create\` with:\n`;
463
463
  response += `- name: kebab-case name (e.g. "slack-message-check")\n`;
464
464
  response += `- description: one-line description\n`;
@@ -616,131 +616,63 @@ export function createAgentToolsServer(deps: AgentToolsDeps): McpSdkServerConfig
616
616
  }
617
617
  ),
618
618
 
619
- // ── User Interaction Tools ──────────────────────────────────
619
+ // ── User Interaction Tool ───────────────────────────────────
620
620
 
621
621
  tool(
622
- "request_user_input",
623
- "Ask the user a clarifying question and wait for their free-text response. " +
624
- "Use this when you need information that cannot be inferred from context, memory, or the workspace — " +
625
- "e.g. which account to use, specific preferences, ambiguous instructions, or missing parameters for a skill. " +
622
+ "ask_user",
623
+ "Ask the user a question via the web UI and wait for their response. " +
624
+ "Shows a message with optional predefined option buttons PLUS a free-text input field — " +
625
+ "the user can either click a suggested option or type a custom answer. " +
626
+ "ALWAYS provide options when you can suggest likely answers. " +
626
627
  "Do NOT use this for information you can discover yourself (git remote, file contents, etc.).",
627
628
  {
628
- question: z.string().describe("The question to ask the user (supports markdown). Be specific about what you need and why."),
629
- placeholder: z.string().optional().describe("Placeholder text for the input field (e.g. 'https://github.com/owner/repo')"),
630
- timeout_seconds: z.number().optional().describe("How long to wait for response (default: 300)"),
631
- },
632
- async (args) => {
633
- const actionId = `input_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
634
- const timeout = (args.timeout_seconds || 300) * 1000;
635
-
636
- const actionData = {
637
- id: actionId,
638
- type: "input",
639
- message: args.question,
640
- placeholder: args.placeholder || "",
641
- created_at: new Date().toISOString(),
642
- };
643
-
644
- try {
645
- await setActionRequest(taskId, actionData);
646
- log.info(`Input request ${actionId}: "${args.question.slice(0, 80)}..."`);
647
-
648
- emitEvent(taskId, "user_action_request", actionData).catch(() => {});
649
-
650
- const startTime = Date.now();
651
- const pollInterval = 2000;
652
-
653
- while (Date.now() - startTime < timeout) {
654
- const response = await pollActionResponse(taskId);
655
- // Match response to this specific request by action_id
656
- if (response && (!response.action_id || response.action_id === actionId)) {
657
- const text = (response.text || response.value || "") as string;
658
- log.info(`User input received: "${text.slice(0, 80)}"`);
659
- return {
660
- content: [{
661
- type: "text",
662
- text: JSON.stringify({ status: "responded", text }),
663
- }],
664
- };
665
- }
666
-
667
- await new Promise((resolve) => setTimeout(resolve, pollInterval));
668
- }
669
-
670
- log.warn(`Input request ${actionId} timed out`);
671
- return {
672
- content: [{
673
- type: "text",
674
- text: JSON.stringify({
675
- status: "timeout",
676
- message: "User did not respond within the timeout period.",
677
- }),
678
- }],
679
- };
680
- } catch (err) {
681
- log.error(`request_user_input failed: ${err}`);
682
- return {
683
- content: [{
684
- type: "text",
685
- text: `Failed to request user input: ${err instanceof Error ? err.message : err}`,
686
- }],
687
- };
688
- }
689
- }
690
- ),
691
-
692
- tool(
693
- "request_user_confirmation",
694
- "Pause and ask the user for approval or input via the web UI. " +
695
- "Returns the user's chosen action_key. Use this BEFORE creating skills, making irreversible changes, etc. " +
696
- "The agent will block until the user responds or the timeout expires.",
697
- {
698
- message: z.string().describe("What to show the user (supports markdown)"),
629
+ question: z.string().describe("The question to ask (supports markdown). Be specific about what you need and why."),
699
630
  options: z.array(z.object({
700
631
  label: z.string().describe("Button label shown to user"),
701
632
  action_key: z.string().describe("Machine-readable key returned when selected"),
702
633
  description: z.string().optional().describe("Tooltip/description for this option"),
703
- })).describe("Buttons/options to show the user"),
634
+ })).optional().describe("Suggested options shown as buttons. The user can always type a custom answer instead."),
635
+ placeholder: z.string().optional().describe("Placeholder text for the free-text input field"),
704
636
  timeout_seconds: z.number().optional().describe("How long to wait for response (default: 300)"),
705
637
  },
706
638
  async (args) => {
707
- const actionId = `action_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
639
+ const actionId = `ask_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
708
640
  const timeout = (args.timeout_seconds || 300) * 1000;
709
641
 
710
642
  const actionData = {
711
643
  id: actionId,
712
- type: "confirmation",
713
- message: args.message,
714
- options: args.options,
644
+ type: "ask_user",
645
+ message: args.question,
646
+ options: args.options || [],
647
+ placeholder: args.placeholder || "",
715
648
  created_at: new Date().toISOString(),
716
649
  };
717
650
 
718
651
  try {
719
- // Store action request in message metadata via RPC — UI reads this
720
652
  await setActionRequest(taskId, actionData);
721
- log.info(`Action request ${actionId} stored in metadata, waiting for user response...`);
653
+ log.info(`Ask user ${actionId}: "${args.question.slice(0, 80)}..."`);
722
654
 
723
- // Also emit event for real-time notification (best-effort)
724
655
  emitEvent(taskId, "user_action_request", actionData).catch(() => {});
725
656
 
726
- // Poll for response
727
657
  const startTime = Date.now();
728
658
  const pollInterval = 2000;
729
659
 
730
660
  while (Date.now() - startTime < timeout) {
731
661
  const response = await pollActionResponse(taskId);
732
- // Match response to this specific request by action_id
733
662
  if (response && (!response.action_id || response.action_id === actionId)) {
734
- const actionKey = (response.action_key || response.action || "") as string;
735
- const label = (response.label || actionKey) as string;
736
- log.info(`User responded: ${label} (${actionKey})`);
663
+ // Response can be either an option click or free-text input
664
+ const actionKey = (response.action_key || "") as string;
665
+ const text = (response.text || "") as string;
666
+ const label = (response.label || actionKey || text) as string;
667
+ log.info(`User responded: "${label}"`);
737
668
  return {
738
669
  content: [{
739
670
  type: "text",
740
671
  text: JSON.stringify({
741
672
  status: "responded",
742
- action_key: actionKey,
673
+ action_key: actionKey || "custom_input",
743
674
  label,
675
+ text: text || label,
744
676
  }),
745
677
  }],
746
678
  };
@@ -749,7 +681,7 @@ export function createAgentToolsServer(deps: AgentToolsDeps): McpSdkServerConfig
749
681
  await new Promise((resolve) => setTimeout(resolve, pollInterval));
750
682
  }
751
683
 
752
- log.warn(`Action request ${actionId} timed out after ${args.timeout_seconds || 300}s`);
684
+ log.warn(`Ask user ${actionId} timed out after ${args.timeout_seconds || 300}s`);
753
685
  return {
754
686
  content: [{
755
687
  type: "text",
@@ -760,11 +692,11 @@ export function createAgentToolsServer(deps: AgentToolsDeps): McpSdkServerConfig
760
692
  }],
761
693
  };
762
694
  } catch (err) {
763
- log.error(`request_user_confirmation failed: ${err}`);
695
+ log.error(`ask_user failed: ${err}`);
764
696
  return {
765
697
  content: [{
766
698
  type: "text",
767
- text: `Failed to request user confirmation: ${err instanceof Error ? err.message : err}`,
699
+ text: `Failed to ask user: ${err instanceof Error ? err.message : err}`,
768
700
  }],
769
701
  };
770
702
  }
@@ -81,7 +81,7 @@ Available capabilities:
81
81
 
82
82
  5. JOB AUTOMATION:
83
83
  - When the user describes their job/role/daily work, use skill_generate to decompose it into automatable skills
84
- - ALWAYS use request_user_confirmation to get user approval before creating skills — never create skills without approval
84
+ - ALWAYS use ask_user to get user approval before creating skills — never create skills without approval
85
85
  - Use job_run to start a job — it gives you the job's goal and available skills as capabilities
86
86
  - When running a job, be AGENTIC: decide dynamically what to do based on what you discover
87
87
  - Do NOT follow a fixed sequence — if checking Slack reveals a task that needs GitHub, go do GitHub immediately
@@ -115,9 +115,10 @@ Guidelines:
115
115
  - When you learn something about the user (preferences, habits), use memory_store to remember it
116
116
 
117
117
  CRITICAL — Ask before you guess:
118
- - Before executing a task, verify you have all required information. If anything is ambiguous or missing, use request_user_input to ask.
118
+ - Before executing a task, verify you have all required information. If anything is ambiguous or missing, use ask_user to ask.
119
119
  - First try to resolve unknowns yourself: check memories, read workspace files (e.g. git remote, config files), or infer from conversation history.
120
- - If you still lack a critical piece of information after self-resolution, ASK the user via request_user_input. Do NOT guess, assume defaults, or proceed with incomplete information.
120
+ - If you still lack a critical piece of information after self-resolution, ASK the user via ask_user. Do NOT guess, assume defaults, or proceed with incomplete information.
121
+ - When asking, provide suggested options as buttons whenever possible — the user can always type a custom answer instead.
121
122
  - Examples of when to ask: which account/repo/project to target, what format the user wants, which of multiple options to choose, credentials or URLs that cannot be inferred.
122
123
  - Keep questions specific and actionable. Explain what you already know and what exactly you need.
123
124
  - After receiving the answer, store it with memory_store if it is likely to be useful in future conversations.
@@ -277,8 +278,7 @@ export class TaskProcessor {
277
278
  "mcp__assistme-agent__skill_add",
278
279
  "mcp__assistme-agent__skill_publish",
279
280
  // User interaction
280
- "mcp__assistme-agent__request_user_input",
281
- "mcp__assistme-agent__request_user_confirmation",
281
+ "mcp__assistme-agent__ask_user",
282
282
  // Job automation tools
283
283
  "mcp__assistme-agent__job_run",
284
284
  "mcp__assistme-agent__job_schedule",