Help making bots

Maybe you’d enjoy toying with the API some? Then I have a task for you!

Launch preparation requires some stress testing on the staging server (soon to come). For this, I was thinking “bots”. Lots of bots!

Wish to help create a bot for stress testing? Just tell me and I’ll gladly explain more about the API!

/Accipiter

Example

We will use nodejs for the bots. Let’s tease with an example.
Just change to your own username and the base64(sha256("mysecret")) of your password:

const ResClient = require('resclient').default;
const WebSocket = require('isomorphic-ws');

// Create the API client.
// See: https://resgate.io/docs/writing-clients/resclient/
let client = new ResClient(() => new WebSocket('wss://api.wolfery.com', {
  origin: 'https://wolfery.com'
}));

// Set the authentication to use when connecting to the API.
// Since we have no JWT token, we use password login.
// The password is sha256 hashed and base64 encoded.
client.setOnConnect(() => client.authenticate('auth', 'login', {
	name: 'myloginname',
	pass: 'ZSx9xofZjJiJME7S5AjHS2EehqQMqlHEtD8d1ZE8XNA=' // mysecret
}).catch(err => console.error("Failed to login: ", err)));

// Get the main player model.
client.call('core', 'getPlayer').then(player => {
	// Call on (empty listener) to keep ResClient subscribing to player events.
	player.on();

	// Promise to a controlled character
	let promise = null;
	if (player.controlled.length > 0) {
		// If we already control a character, we use that one first.
		promise = Promise.resolve(player.controlled.atIndex(0))
	} else if (player.chars.length > 0) {
		// If we have owned characters, we control one and wake 'em up
		promise = player.call('controlChar', { charId: player.chars.atIndex(0).id });
	} else {
		promise = Promise.reject("No owned characters");
	}

	// Ensure the controlled character is awake
	promise.then(char => {
		return (char.state == 'awake'
			? char
			: char.call('wakeup')
		).then(() => {
			// Say and repeat every 10 seconds
			sayAndRepeat(char, "I am a bot", 10000);
		});
	});
});

// sayAndRepeat makes a character repeat something over and over.
function sayAndRepeat(char, msg, duration) {
	// Say something
	char.call('say', { msg: msg });
	// Wait and say it again after a while
	setTimeout(() => sayAndRepeat(char, msg, duration), duration);
}

Note

To run the example above, you need nodejs and the npm packages: resclient, isomorphic-ws and ws

By the way, you do need to add the = if you generate the base64 sha256 from here.

And for those in the future that didn’t see Acci and my conversation in-world, the password is the base64 encoding of the bytes of the sha256 hash of your password, which the above linked generator does, but for those wanting to use an environment variable or the like, that’s how you get there.

Also, not to double bump so quickly but I had an issue with the example code, the lines:

// Ensure the controlled character is awake
	promise	.then(char => char.state == 'awake'
		? char
		: char.call('wakeup')
	).then(() => {
		// Say and repeat every 10 seconds
		sayAndRepeat(char, "I am a bot", 10000);
	});

lose the variable char before it reaches the scope of .then(); and should be passed in, making the call look like:

// Ensure the controlled character is awake
	promise	.then(char => char.state == 'awake'
		? char
		: char.call('wakeup')
	).then(char => {
		// Say and repeat every 10 seconds
		sayAndRepeat(char, "I am a bot", 10000);
	});

That got the example bot running for me.

Edit: I also see now that it used to be there in an earlier edit :joy:, at least for me, I still need it.

Sorry about that bug!
Yes, I missed keeping char within the closure. I’ve edited the example code.

But, now I have a first version of the “official” bot code :smiley:

Unlike my simple example above, this code can be used for all types of bot making.
My initial use is load testing, but it would be easy adapt it to make a bot that can listen for commands and act upon them:

Accipiter says to the receptionist ,"I need an apartment."

(Okay, that was not the best example. But you get the idea.)

If you need help in making a command-taking module, or to know which API calls you can use to list possible (vacant) rooms, or to transfer ownership, just ask!

Is there a reference document for the API itself somewhere? JS isn’t my forte, but if I’m interpreting this correctly, it looks like there’s some language-agnostic functionality for the calls, and I’d love to write a python wrapper for it. Most of my research is into AI systems, and I’d love to try and get some of them inserted into the world!

Yes and no.

WebSocket Protocol

Wolfery uses Resgate as the API gateway (https://resgate.io) to provide all the real-time updates in the game. This means, you can learn about the RES Client Protocol, which is what is used over the WebSocket connection. The protocol specifies how data (resources) is fetched, how updates and events looks like, and how calls are made.

Resgate’s protocols are designed to be quite easy to implement for the services. But it is quite a bit more complex to implement a client.

As references, you can look at client implementations in the Javascript resclient or the almost complete ResClient for .NET (C#).

Wolfery’s API

Wolfery’s API is not documented… yet.
But most of the resources the client uses can be found nested in the player resource that you can get for the currently logged in player by making the following call request:

call.core.getPlayer

(You can see that call in the code example in my initial post in this thread)

Check the Mucklet bot repository to see how login can be made in the Login.js file.

Python? I think @farcaller is also trying something similar. Maybe we can make a project for it? :slight_smile:

Fantastic- I’d taken a look at the bot example but some of the interface pieces didn’t quite make sense because I thought I was looking at another wrapped socket interface- with the Resgate gateway being what I was missing there. Between the C# service library and a python example for the clients, I think I should be able to manage.

A project sounds great- I happen to know @farcaller, who is much more familiar with web-based development than I am, so it’d be great to have multiple people working on it!

Great! :smiley:

Yeah, and I can personally recommend using the C# client as reference rather than the Javascript client. The C# client has a better structure and avoids some mistakes made in the Javascript implementation.

Also, since Javascript is inherently single threaded, the C# client is more suited as reference for any non-single threaded language.

But, it is much less tested (only one company using it AFAIK), so it can still contain its share of bugs.

The C# client is also strongly typed and lacks the typing guesses hell of its JS counterpart, which sure helps to reason with the code.

1 Like

I only did python for a quick prototype though. Focusing on dart here (because that gives me both mobiles, desktops and a cringe web via flutter—but I only care about the former) and I know someone around looking into the rust client.

Ok, so I’ve been fussing around with a python package which implements Websocket contact to resgate, and I’m getting an error “There was an error Handshake status 403 Forbidden” when I try to start the app.

Any idea what I’m doing wrong? I’ve tried lots of different ways of formatting the URL and putting in the authentication directly, but no luck.

Edit: Never mind, I’m a ding dong-
ws.run_forever(origin=“https://wolfrey.com”) isn’t a valid target.

I would personally be well up for trying to help with the python code side of things. Just ask :stuck_out_tongue:

So at this point I’m about 95% sure that the Python client/bot is pretty much ready to go. I’ve made up one demo and two utility bots thus far. The demo bot just moves between rooms, says some lines, sends a test message to a character, and announces its status variable. The utility bots are a notification system that messages a user when people enter the area it’s in, and a mapping agent that explores the world and saves a map (which I intend to use for a “give directions”/GOTO sort of command).

The goal is to have a single agent capable of doing the following through a priority based state machine/subsumption hierarchy: receiving direct diagnostic and control commands from a privileged user via messages (such as 'find ', 'goto ', ‘watch this space’, ‘be a bartender here’, etc.), engaging in conversations with (multiple) general users via address and serve specific requests (like ‘what time is it’, 'how do you get to ', 'make me a ', etc.).

My next steps are going to be * things:

  • Integrating a chat agent for a conversation mode (probably dumb AIML but if anyone has suggestions…)
  • Implementing the search & navigation algorithm (Dijkstra + a probability queue based traveling salesman heuristic, don’t worry about it), and making GOTO and ‘How to get to’ modules.
  • Adding a ‘Bartender’ mode to the ‘watch this space’ module to have two functional utilities.
  • Building a master state machine for command-based task execution for all the submodules I’ve designed (basically a task queue and set of completion conditions so you could say something like ‘goto Club Caribe and watch’, and it would navigate itself to the club and then send you a message whenever someone enters it)
  • Constructing a recommender system for a ‘did you mean?’ interface for commands (like for if someone wants directions to the hot springs and asks ‘where is the springs?’)

I’d like to spend another day or so finishing up my current command and interface system for it- right now I’m working on a chat agent for basic convos through addresses and also a demo version of a command function (basic stuff like ‘say the time’ or ‘go away’), but most of the other stuff is more high-level stuff for the AI goals I have, and isn’t really necessary for someone else to use (and actually might be more confusing, tbh). I do want to have non-trivial input, output, and monitoring all vetted first, though.

So basically, I’ve got the client and bot framework nearly done, and I think I can release that part in a day or so. My questions are: does it sound like that would be enough? If so what would be the ideal way to go about it? And are there any other ideas/features/objectives that would be good to either integrate first or just add to the main list for the AI-heavy version?

Huh. I wonder if the core of this could form the much-asked for CLI client.

There’s an ask for a cli client?

Where I’m at with it right now I could probably define 8-10 input functions and have a basic CLI up and running and then freeze it to an executable

As we talked about on Wolfery, there’s been frequent requests for a tinyfugue-like client from mostly older muck users - whom I suspect would find other excuses not to join anyway - and by people who want something more discreet than a full GUI.

Both needs would be served by some sort of minimum viable textmode client similar to the current state of the mobile app, and I wouldn’t consider it a huge feature, just a way to get sticks-in-the-MUCK out of their holes.

Alright, so I think it’s at a good place where people can start looking at it with a reasonable expectation that it should make sense and be useful, so here’s the python bot package:

I think it should have all the baseline stuff necessary to build interesting bots for Wolfery. I put in four demos and based on those working I think it’ll be good for making useful stuff. It has what all I need to make the more interesting stuff I want to make, in any case.

If you decide to take a look at it, do let me know if you have any questions, suggestions, requests, or run into any errors!

1 Like

Only two days later, ha! Here’s my package: res_client | Dart Package and github and the librarian bot source as a usage eaxmple.

1 Like