Skip to content

feat(agent-server): add quest-helper and /logout endpoints#1774

Merged
chsami merged 4 commits into
chsami:developmentfrom
runsonmypc:feat/agent-server-questhelper-logout
May 13, 2026
Merged

feat(agent-server): add quest-helper and /logout endpoints#1774
chsami merged 4 commits into
chsami:developmentfrom
runsonmypc:feat/agent-server-questhelper-logout

Conversation

@runsonmypc
Copy link
Copy Markdown
Contributor

Summary

  • Expands the agent server to expose Quest Helper control + state introspection so external agents can drive and observe quest progress.
  • Adds a /logout endpoint mirroring the existing /login handler so an agent can end a session cleanly.

Endpoints added

/quest-helper (QuestHelperHandler)

  • /quest-helper/list — list available quests
  • /quest-helper/start — start a quest
  • /quest-helper/stop — stop the quest helper
  • /quest-helper/status — status of the current quest run
  • /quest-helper/states — bulk state read across all quests in a single response

/logout (LogoutHandler)

  • Mirrors LoginHandler semantics; registered alongside it in AgentServerPlugin.buildHandlers.

Other changes

  • QuestScript.java: 1-line whitespace fix on the line introduced by the recent clearWalkingRoute(...) migration. No behavior change; the fix is a side-effect of resolving the cherry-pick against the older Rs2Walker.setTarget(null) call this branch was built on.

Test plan

  • Start the client with the agent server enabled and a valid token
  • GET /quest-helper/list returns the available quests
  • POST /quest-helper/start with a known quest name starts the helper
  • GET /quest-helper/status reflects the running quest
  • POST /quest-helper/stop halts the helper cleanly
  • GET /quest-helper/states returns the full per-quest state map in one response
  • POST /logout ends the session in the same way /login begins it

Need programmatic quest selection from the ironman-guide skill; Quest Helper's
plugin panel was the only way to start a quest. Adds a handler that wraps
QuestHelperPlugin.getQuestManager().startUpQuest so the skill can pick a quest
over HTTP, plus fixes the crashes and wrong-click behavior that surfaced while
driving QH auto-play during the BRUHsailer run.

agent-server:
- QuestHelperHandler: /questhelper/start, /stop, /active, /list. Resolves quest
  by enum name or display name via QuestHelperQuest.valueOf / getByName.

QuestScript (reachability + action selection):
- Require line-of-sight in addition to canReach() before clicking an NPC or
  object — canReach pathfinds through closed doors, so a true return doesn't
  mean a direct click will land.
- When LOS fails, walk to the target (lets the walker open the door en route)
  instead of firing a click that will miss.
- Fallback to the object/NPC/inventory item's first non-empty action when no
  step text matches an action name, so QH doesn't emit an empty menu op.

Null-guards on MenuOptionClicked.getMenuOption() in:
- PouchScript, Rs2Gembag, QuestBankTabInterface, IncantationStep
  (all previously NPE'd on synthetic/agent-driven menu events where menuOption
  is null)
POST /logout calls Rs2Player.logout() on the script thread and polls
client.getGameState() == LOGIN_SCREEN; GET returns current login state.
Symmetric to LoginHandler. Used by ironguide to gate Microbot ↔ DreamBot
handoffs (logout via Microbot before launching DreamBot, log back in after).
Iterates QuestHelperQuest.values() on the client thread and returns
{enum, displayName, state} per quest where state ∈ {NOT_STARTED,
IN_PROGRESS, FINISHED} via QuestHelperQuest.getState(Client). Lets
external tooling bulk-audit per-quest completion without the side
effects of /quest-helper/start+stop (which set TurnOn=true).
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 12, 2026

Review Change Stack

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 3719c954-052a-43eb-b12c-f93102656b7e

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Walkthrough

This PR extends the microbot agent-server HTTP API with two independent handler groups. The /logout endpoint supports GET queries of login status and POST logout operations with optional deadline-bounded polling until the client reaches login screen. The /quest-helper handler gains three sub-endpoints: /stop to shut down quest execution, /list to enumerate all available quest helper quests, and /states to retrieve current state for each quest computed on the client thread. Both handlers are wired into the server infrastructure via AgentServerPlugin registration.

Possibly related PRs

  • chsami/Microbot#1736: Modifies AgentServerPlugin and other agent-server handlers for related endpoint changes.
  • chsami/Microbot#1744: Also changes AgentServerPlugin and AgentHandler implementations in the agent-server infrastructure.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main changes: adding quest-helper and /logout endpoints to the agent server.
Description check ✅ Passed The description is well-related to the changeset, detailing the new endpoints, their functionality, and providing a comprehensive test plan.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@runelite-client/src/main/java/net/runelite/client/plugins/microbot/agentserver/handler/LogoutHandler.java`:
- Around line 69-77: In LogoutHandler, validate the type of body.get("timeout")
before casting: check if body contains "timeout" and then if the value is an
instance of Number use ((Number) value).intValue(), else if it's a String try
parsing an integer with Integer.parseInt (handling NumberFormatException) or
ignore/ fallback; cap with MAX_TIMEOUT_SECONDS and apply DEFAULT_TIMEOUT_SECONDS
when <=0; ensure timeoutSeconds assignment uses these guarded conversions to
avoid ClassCastException.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 8db48ce1-93d1-4aa9-a4ec-49d4ca17bc97

📥 Commits

Reviewing files that changed from the base of the PR and between ddc6a2c and a75e82a.

📒 Files selected for processing (4)
  • runelite-client/src/main/java/net/runelite/client/plugins/microbot/agentserver/AgentServerPlugin.java
  • runelite-client/src/main/java/net/runelite/client/plugins/microbot/agentserver/handler/LogoutHandler.java
  • runelite-client/src/main/java/net/runelite/client/plugins/microbot/agentserver/handler/QuestHelperHandler.java
  • runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/QuestScript.java

Comment on lines +69 to +77
if (body != null) {
if (body.containsKey("wait")) {
wait = Boolean.TRUE.equals(body.get("wait"));
}
if (body.containsKey("timeout")) {
timeoutSeconds = Math.min(((Number) body.get("timeout")).intValue(), MAX_TIMEOUT_SECONDS);
if (timeoutSeconds <= 0) timeoutSeconds = DEFAULT_TIMEOUT_SECONDS;
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Validate type before casting to prevent ClassCastException.

Line 74 casts body.get("timeout") to Number without validating the type. If a caller sends {"timeout": "30"} (string) or another non-Number type, this will throw ClassCastException.

🛡️ Suggested fix
 		if (body.containsKey("timeout")) {
-			timeoutSeconds = Math.min(((Number) body.get("timeout")).intValue(), MAX_TIMEOUT_SECONDS);
-			if (timeoutSeconds <= 0) timeoutSeconds = DEFAULT_TIMEOUT_SECONDS;
+			Object timeoutObj = body.get("timeout");
+			if (timeoutObj instanceof Number) {
+				timeoutSeconds = Math.min(((Number) timeoutObj).intValue(), MAX_TIMEOUT_SECONDS);
+				if (timeoutSeconds <= 0) timeoutSeconds = DEFAULT_TIMEOUT_SECONDS;
+			}
 		}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (body != null) {
if (body.containsKey("wait")) {
wait = Boolean.TRUE.equals(body.get("wait"));
}
if (body.containsKey("timeout")) {
timeoutSeconds = Math.min(((Number) body.get("timeout")).intValue(), MAX_TIMEOUT_SECONDS);
if (timeoutSeconds <= 0) timeoutSeconds = DEFAULT_TIMEOUT_SECONDS;
}
}
if (body != null) {
if (body.containsKey("wait")) {
wait = Boolean.TRUE.equals(body.get("wait"));
}
if (body.containsKey("timeout")) {
Object timeoutObj = body.get("timeout");
if (timeoutObj instanceof Number) {
timeoutSeconds = Math.min(((Number) timeoutObj).intValue(), MAX_TIMEOUT_SECONDS);
if (timeoutSeconds <= 0) timeoutSeconds = DEFAULT_TIMEOUT_SECONDS;
}
}
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@runelite-client/src/main/java/net/runelite/client/plugins/microbot/agentserver/handler/LogoutHandler.java`
around lines 69 - 77, In LogoutHandler, validate the type of body.get("timeout")
before casting: check if body contains "timeout" and then if the value is an
instance of Number use ((Number) value).intValue(), else if it's a String try
parsing an integer with Integer.parseInt (handling NumberFormatException) or
ignore/ fallback; cap with MAX_TIMEOUT_SECONDS and apply DEFAULT_TIMEOUT_SECONDS
when <=0; ensure timeoutSeconds assignment uses these guarded conversions to
avoid ClassCastException.

Body values are parsed by Gson into native JSON types, so a client sending
{"timeout": "30"}, {"timeout": true}, or {"timeout": null} would crash the
handler on the (Number) cast. Accept Number or numeric String, fall back to
the default for anything else.
@chsami chsami merged commit 73d368c into chsami:development May 13, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants