This project simulates a command-line operating system interface, designed to be called by agentic large language models (LLMs). It is exposed as an OpenAI-compatible API and is completely stateless. For an example of an LLM using it: https://dreams.infinitebackrooms.com/AndyAyrey/3Nir1p6x-c
- Features
- Getting Started
- Usage
- Adding New Environments
- Current Environments
- Future Improvements
- License
- Multiple App Environments: Add adapters for apps like Twitter, Perplexity, and other real world applications, transforming operations into an LLM-friendly command line syntax with ample 'help' extensions.
- Extensible Architecture: Easily add new environments by adding a new adapter and linking it in
environment-registry.js
- Command preprocessing gently corrects tool syntax using using any OpenAI compatible endpoint to allow your agent how to use the tools in-context
- OpenAI-compatible API endpoint - drop this in anywhere you're already handling a context window. (see
test.py
for an example of why this is useful)
Make sure you have Node.js installed.
- Clone the repository
- Install dependencies:
npm install
- Familarise yourself with the environments and adapters in
src/environments
. (n.b. some of them require other services to be running which I'm yet to release, sorry!) - Set up environment variables -
cp .env.example .env
and populate with your keys. Set yourWORLD_INTERFACE_KEY
to anything you like! - Start the server:
npm start
The server will start on port 3000 by default. Prompt it as you would any chatbot.
Send POST requests to /v1/chat/completions
with the following structure:
{
"messages": [{ "role": "user", "content": "twitter post Hello, world!" }]
}
Include the header Authorization: Bearer WHATEVER_YOU_SET_YOUR_WORLD_INTERFACE_KEY_TO
for authentication.
To add a new environment:
-
Create a New Environment File
Add your environment's JavaScript file in the
src/environments/
directory. For example, to add aweather
environment:const axios = require('axios'); class Weather { getCommands() { return [ { name: "current", description: "Get current weather for a location" }, { name: "forecast", description: "Get weather forecast for a location" }, ]; } async handleCommand(command, messages) { const [action, ...params] = command.split(" "); const location = params.join(" "); switch (action.toLowerCase()) { case "current": return await this.getCurrentWeather(location); case "forecast": return await this.getWeatherForecast(location); case "help": return this.help(); default: return { error: `Unknown action: ${action}` }; } } async getCurrentWeather(location) { try { const response = await axios.get(`https://api.weather.com/v3/weather/conditions`, { params: { location, apiKey: process.env.WEATHER_API_KEY }, }); return { title: `Current Weather for ${location}`, content: `Temperature: ${response.data.temperature}\nConditions: ${response.data.conditions}`, }; } catch (error) { return { title: "Error Fetching Weather", content: error.response ? error.response.data.error : error.message, }; } } async getWeatherForecast(location) { try { const response = await axios.get(`https://api.weather.com/v3/weather/forecast`, { params: { location, apiKey: process.env.WEATHER_API_KEY }, }); return { title: `Weather Forecast for ${location}`, content: `Tomorrow: ${response.data.forecast}`, }; } catch (error) { return { title: "Error Fetching Weather Forecast", content: error.response ? error.response.data.error : error.message, }; } } help() { return { title: "Weather Environment Help", content: `Available commands: - current <location> - Get current weather for a location - forecast <location> - Get weather forecast for a location`, }; } } module.exports = Weather;
-
Register the New Environment
Add your new environment to the
src/environment-registry.js
to make it available for use.const Twitter = require('./environments/twitter'); const Exo = require('./environments/exo'); const Sydney = require('./environments/sydney'); const MemeMagic = require('./environments/meme_magic'); const Search = require('./environments/search'); const Weather = require('./environments/weather'); // Newly added const environments = { twitter: new Twitter(), exo: new Exo(), sydney: new Sydney(), meme_magic: new MemeMagic(), search: new Search(), weather: new Weather(), // Registering the new environment }; module.exports = { getEnvironment: (name) => environments[name], getEnvironmentNames: () => Object.keys(environments), };
- Twitter: Connects to a Twitter proxy we're working on. Still to be released!
- Exo: A suite of tools for taking notes and running queries against Claude. Notes functionality to be branched off into a separate project as it depends on some stuff that's not ready for public consumption yet.
- Sydney: Connects to a simulacra of Sydney running on Llama 405b
- Search: Searches the internet using Perplexity
- Meme Magic: Generates memes using Glif. (Broken currently)
This is a toy model created to solve my own particular use case so there's looooots of stuff that needs to be added/improved to make it more generally useful as a basis for your own projects. Here's some ideas:
- Make pre-processing more sophisticated and easier to enable/disable/configure
- Expose a "hints" interface to enable individual apps to suggest next steps
- Expose an interface for widgets
- that show on session start (e.g. welcome message, notes from last session, etc)
- that show at the start/bottom of each output (e.g. the time, notifications, etc)
- Make environments self-registering (no need to edit the registry when you add a new one)
- Allow the agent to set environment variables for itself that are hydrated every session
- Better plugin architecture/extensibility
LMK on X @andyayrey if you'd like to share ideas or contribute!
MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.